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