Sie können die Shader-Programme überschreiben, indem Sie dem Material ein SCNProgram zuweisen. Dann können Sie in einer der Delegate-Methoden für SCNProgramDelegate
Ihre eigenen Werte für die Textur (und andere Uniformen) binden. Sie werden jedoch Ihre eigenen Shader schreiben müssen.
Es gibt ein wenig Setup, wenn Sie an Objective-C gewöhnt sind, aber es ist wirklich nicht so viel, wenn Sie an den entsprechenden OpenGL-Code denken.
Das folgende Beispiel zeigt ein Shaderprogramm, das eine Textur an die Oberfläche eines Geometrieobjekts bindet. Der Einfachheit halber erfolgt keine Schattierung mit Normalen und Lichtquellen.
Beachten Sie, dass ich nicht weiß, wie Sie Ihre spezifische Textur binden möchten, so dass ich im folgenden Code ein PNG mit GLKit lesen und diese Textur verwenden.
// 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];
In diesem Beispiel werden die Shadern geschrieben werden als
// 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;
}
Und
// yourShader.frag
uniform sampler2D yourTexture;
varying vec2 texCoord;
void main(void) {
gl_FragColor = texture2D(yourTexture, texCoord);
}
Schließlich wird die Implementierung für die ...bindValueForSymbol:...
Verfahren eine Textur auf die "yourTexture" Uniform zu binden.
- (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.
}
Auch für Debugging-Zwecke ist es sehr hilfreich program:handleError:
zu implementieren alle Shader Kompilierungsfehlern auszudrucken
- (void)program:(SCNProgram*)program handleError:(NSError*)error {
// Log the shader compilation error
NSLog(@"%@", error);
}
wow, vielen Dank! – simonfi
Endlich hatte ich etwas Zeit, um damit zu spielen, und wollte nur nochmal Danke sagen! Abgesehen von einem kleinen Tippfehler (a_textureCoordinate im Vertex-Shader) funktionierte das perfekt und ist viel schneller als meine vorherige Implementierung, die die Textur immer mit einem neuen NSMageitor ersetzte. Nur eine kleine Frage; Wie hast du das herausgefunden? Die Dokumentation für SceneKit scheint bisher sehr begrenzt zu sein. – simonfi