2013-09-05 15 views
6

Appleのドキュメントによれば、NSColor、NSImage、CALayerを使用してSCNMaterialPropertyにテクスチャを提供することができます。 SCNMaterialPropertyシーンキットで既存のOpenGLテクスチャを使用する

ただし、既存のOpenGLテクスチャを提供する方法があるかどうかは疑問です。これはglGenTexturesで作成され、別々にレンダリングされています。

もちろん、テクスチャのバッファを読み込み、NSImageを設定して、SCNMaterialPropertyにその値を渡すことができます。パフォーマンス上の理由から、明らかに最適ではありません。

これは私が推測する材料のシェーダプログラムをオーバーライドすることで上記を実装するのが理にかなっていますが、これを行うためのドキュメントは存在しないようです。

答えて

8

マテリアルにSCNプログラムを割り当てることによってシェーダプログラムをオーバーライドすることができます。次に、SCNProgramDelegateのデリゲートメソッドの1つで、テクスチャ(と他のユニフォーム)のために独自の値をバインドすることができます。しかし、あなたは自分のシェイダーを書く必要があります。

Objective-Cに慣れていれば少しセットアップがありますが、対応するOpenGLコードを考えるとそれほど多くはありません。

以下は、テクスチャをジオメトリオブジェクトのサーフェスにバインドするシェーダプログラムの例です。簡単にするため、法線や光源には影を付けません。

特定のテクスチャをどのようにバインドしたいのか分からないので、下のコードでGLKitを使用してpngを読み、そのテクスチャを使用します。

// Create a material 
SCNMaterial *material = [SCNMaterial material]; 

// Create a program 
SCNProgram *program = [SCNProgram program]; 

// Read the shader files from your bundle 
NSURL *vertexShaderURL = [[NSBundle mainBundle] URLForResource:@"yourShader" withExtension:@"vert"]; 
NSURL *fragmentShaderURL = [[NSBundle mainBundle] URLForResource:@"yourShader" withExtension:@"frag"]; 
NSString *vertexShader = [[NSString alloc] initWithContentsOfURL:vertexShaderURL 
                 encoding:NSUTF8StringEncoding 
                  error:NULL]; 
NSString *fragmentShader = [[NSString alloc] initWithContentsOfURL:fragmentShaderURL 
                  encoding:NSUTF8StringEncoding 
                  error:NULL]; 
// Assign the shades 
program.vertexShader = vertexShader; 
program.fragmentShader = fragmentShader; 

// Bind the position of the geometry and the model view projection 
// you would do the same for other geometry properties like normals 
// and other geometry properties/transforms. 
// 
// The attributes and uniforms in the shaders are defined as: 
// attribute vec4 position; 
// attribute vec2 textureCoordinate; 
// uniform mat4 modelViewProjection;  
[program setSemantic:SCNGeometrySourceSemanticVertex 
      forSymbol:@"position" 
      options:nil]; 
[program setSemantic:SCNGeometrySourceSemanticTexcoord 
      forSymbol:@"textureCoordinate" 
      options:nil]; 
[program setSemantic:SCNModelViewProjectionTransform 
      forSymbol:@"modelViewProjection" 
      options:nil]; 


// Become the program delegate so that you get the binding callback 
program.delegate = self; 

// Set program on geometry 
material.program = program; 
yourGeometry.materials = @[material]; 

は、この例ではシェーダ最後...bindValueForSymbol:...メソッドの実装は、 "yourTexture" 均一にテクスチャを結合すること

// yourShader.vert 
attribute vec4 position; 
attribute vec2 textureCoordinate; 
uniform mat4 modelViewProjection; 

varying vec2 texCoord; 

void main(void) { 
    // Pass along to the fragment shader 
    texCoord = textureCoordinate; 

    // output the projected position 
    gl_Position = modelViewProjection * position; 
} 

そして

​​

として書かれています。

- (BOOL) program:(SCNProgram *)program 
bindValueForSymbol:(NSString *)symbol 
     atLocation:(unsigned int)location 
      programID:(unsigned int)programID 
      renderer:(SCNRenderer *)renderer 
{ 
    if ([symbol isEqualToString:@"yourTexture"]) { 
     // I'm loading a png with GLKit but you can do your very own thing 
     // here to bind your own texture. 
     NSError *error = nil; 
     NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"sampleImage" ofType:@"png"]; 
     GLKTextureInfo *texture = [GLKTextureLoader textureWithContentsOfFile:imagePath options:nil error:&error]; 
     if(!texture) { 
      NSLog(@"Error loading file: %@", [error localizedDescription]); 
     } 

     glBindTexture(GL_TEXTURE_2D, texture.name); 

     return YES; // indicate that the symbol was bound successfully. 
    } 

    return NO; // no symbol was bound. 
} 

また、デバッグ目的のためには、残念ながら、あなたがあなた自身のシェーダを供給する必要があります

- (void)program:(SCNProgram*)program handleError:(NSError*)error { 
    // Log the shader compilation error 
    NSLog(@"%@", error); 
} 
+0

うわー、ありがとう! – simonfi

+2

最後にこれで遊ぶ時間がありましたが、もう一度お返事を言いたいだけです!小さなタイプミス(頂点シェーダのa_textureCoordinate)を除いて、これは完全に機能し、新しいNSImageを使用してテクスチャを常に置き換えた以前の実装よりもはるかに高速です。 小さな質問です。どのようにこれを把握しましたか?これまでのところ、SceneKitのドキュメントは極端に限られています。 – simonfi

1

OpenGLを直接処理して独自のテクスチャをバインドする必要がある場合は、SCNProgramまたはSCNNodeのデリゲートを使用してください(MountainLion以上)。アップルのデベロッパーアカウントをお持ちの場合、サンプルコードは http://developer.apple.com/downloads/ "WWDC 2013 Sample Code"にあります。 "OS_X_SceneKit_Slides_WWDC2013"を参照

+0

任意のシェーダコンパイルエラーをプリントアウトするprogram:handleError:を実装するのに非常に便利です。また、SceneKit自体はMountain Lion以上です) –

+0

@Toyosあなたのメールアドレスは何ですか?あなたが気にしない場合は、プロジェクトについてのメールをお送りしますか? – Crashalot