将现有的opengl纹理与Scenekit一起使用 [英] Using existing opengl texture with scenekit

查看:134
本文介绍了将现有的opengl纹理与Scenekit一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据Apple的文档,您可以使用NSColor,NSImage和CALayer为SCNMaterialProperty提供纹理. SCNMaterialProperty

According to Apple's documentation you can use NSColor, NSImage and CALayer to provide a texture to a SCNMaterialProperty. SCNMaterialProperty

但是,我想知道是否有一种方法可以提供现有的OpenGL纹理,该纹理是使用glGenTextures创建的,并且已分别渲染.

I am however wondering if there is a way to provide an existing OpenGL texture, which has been created with glGenTextures and rendered into separately.

我当然可以读取纹理的缓冲区,设置一个NSImage并将其提供给SCNMaterialProperty;但是出于性能原因,这显然不是最佳选择.

I can of course read the buffer of the texture, setup an NSImage, and provide that one to the SCNMaterialProperty; but for performance reasons that is obviously not optimal.

通过覆盖我猜测的材质的着色器程序来实现上述目的是很有意义的,但是执行此操作的文档似乎不存在.

It would make sense to implement the above by overriding the shader program(s) of the material I guess, but the documentation for doing this seems to be non-existent.

推荐答案

您可以通过创建将SCNProgram分配给材质来覆盖着色器程序.然后,在SCNProgramDelegate的委托方法之一中,您可以为纹理(和其他制服)绑定自己的值.但是,您必须编写自己的着色器.

You can override the shader programs by creating assigning a SCNProgram to the material. Then in one of the delegate methods for SCNProgramDelegate you can bind your own values for the texture (and other uniforms). You will however have do write your own shaders.

如果您习惯使用Objective-C,则需要进行一些设置,但是考虑到相应的OpenGL代码,实际上并不需要那么多.

There is a little bit of setup if you are used to Objective-C but it's really not that much when you think of the corresponding OpenGL code.

以下是一个示例着色器程序,该程序将纹理绑定到几何对象的表面.为简单起见,它不对法线和光源进行任何着色.

The following is an example shader program that binds a texture to the surface of a geometry object. For simplicity it doesn't do any shading with normals and light sources.

请注意,我不知道您想如何绑定特定的纹理,因此在下面的代码中,我使用GLKit读取了png并使用了该纹理.

Note that I don't know how you want to bind your specific texture so in the code below I read a png using GLKit and use that texture.

// 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 this example the shaders are written as

// 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"上.

Finally the implementation for the ...bindValueForSymbol:... method to bind a texture to the "yourTexture" uniform.

- (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:以打印出任何着色器编译错误非常有帮助


Also, for debugging purposes it's very helpful to implement program:handleError: to print out any shader compilation errors

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

这篇关于将现有的opengl纹理与Scenekit一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆