6

Apple のドキュメントによると、NSColor、NSImage、および CALayer を使用して、テクスチャを SCNMaterialProperty に提供できます。SCNMaterialProperty

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

もちろん、テクスチャのバッファを読み取り、NSImage をセットアップして、それを SCNMaterialProperty に提供できます。しかし、パフォーマンス上の理由から、これは明らかに最適ではありません。

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

4

2 に答える 2

9

マテリアルに SCNProgram を割り当てて作成することにより、シェーダー プログラムをオーバーライドできます。次に、デリゲート メソッドの 1 つで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;
}

// yourShader.frag
uniform sampler2D yourTexture;
varying vec2 texCoord;

void main(void) {
    gl_FragColor = texture2D(yourTexture, texCoord);
}

最後に...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);
}
于 2013-09-06T07:48:19.277 に答える
1

OpenGL を直接処理してカスタム テクスチャをバインドする必要がある場合は、SCNProgram または SCNNode のデリゲートが適しています (MountainLion 以上)。Apple 開発者アカウントをお持ちの場合は、http: //developer.apple.com/downloads/ の「WWDC 2013 サンプル コード」の下にサンプル コードがあります。「OS_X_SceneKit_Slides_WWDC2013」を探します

于 2013-09-05T19:49:04.103 に答える