您可以通過創建分配SCNProgram的材料覆蓋着色器程序。然後在SCNProgramDelegate
的其中一個代理方法中,您可以綁定自己的紋理值(和其他制服)。然而,你會寫自己的着色器。
有設置的一點點,如果你使用的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];
在這個例子中的着色器被寫成
// 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;
}
而且
最後爲...bindValueForSymbol:...
方法執行綁定一個紋理的 「yourTexture」 均勻。
- (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.
}
此外,爲了調試的目的是實現program:handleError:
打印出任何着色器編譯錯誤
- (void)program:(SCNProgram*)program handleError:(NSError*)error {
// Log the shader compilation error
NSLog(@"%@", error);
}
哇,非常感謝! – simonfi
終於有一段時間來玩這個了,只想再說一聲謝謝!除少量錯字(a_textureCoordinate在頂點着色器),這非常完美,比我以前的實現,它不停地更換使用新NSImage中所有的時間紋理快得多。 只是一個小問題;你怎麼解決這個問題? SceneKit的文檔到目前爲止似乎非常有限。 – simonfi