如何将纹理数据从 Objective C 客户端传递到此 openGL 顶点着色器?

How do I pass texture data to this openGL vertex shader from an Objective C client?

我正在尝试遵循 Cozzi 和 Ring 的“虚拟地球仪的 3D 引擎设计”中的示例。

我正在尝试使用他们的顶点着色器(11.2.2,第 319 页),因为它似乎为我需要完成的工作提供了准确的起点(从基于数组的密集地形数据渲染地形) ):

in vec2 position;
uniform mat4 og_modelViewPerspectiveMatrix;
uniform sampler2DRect u_heightMap;

void main()
{
    gl_Position = og_modelViewPerspectiveMatrix * vec4(position, texture(u_heightMap,    position).r, 1.0);
}

问题是我不清楚如何在Objective C客户端代码中设置必要的数据。 构建输出显示

TerrainShaderTest[10429:607] Shader compile log:
ERROR: 0:31: Invalid qualifiers 'in' in global variable context
ERROR: 0:33: 'sampler2DRect' : declaration must include a precision qualifier for type
ERROR: 0:37: Use of undeclared identifier 'position'
ERROR: 0:37: Use of undeclared identifier 'u_heightMap'
ERROR: 0:37: Use of undeclared identifier 'position'
2015-01-08 10:33:30.532 TerrainShaderTest[10429:607] Failed to compile vertex shader
2015-01-08 10:33:30.545 TerrainShaderTest[10429:607] GL ERROR: 0x0500

如果我改用不同的顶点着色器(如下),我会得到一个基本但有效的结果,在客户端使用相同的位置设置(但显然不是 heightmap/texture。)

// WORKS - very simple case
attribute vec4 position;
varying lowp vec4 colorVarying;
uniform mat4 modelViewProjectionMatrix;

void main()
{
    colorVarying = (position + vec4(0.5,0.5,0.0,0));
    gl_Position = modelViewProjectionMatrix * position;
}

来自客户端 (Objective C) 的代码片段:

...
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
...

#pragma mark -  OpenGL ES 2 shader compilation

- (BOOL)loadShaders
{
    GLuint vertShader, fragShader;
    NSString *vertShaderPathname, *fragShaderPathname;

    // Create shader program.
    _program = glCreateProgram();

    // Create and compile vertex shader.
    vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
    if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
        NSLog(@"Failed to compile vertex shader");
        return NO;
    }

    // Create and compile fragment shader.
    fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
    if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
        NSLog(@"Failed to compile fragment shader");
        return NO;
    }

    // Attach vertex shader to program.
    glAttachShader(_program, vertShader);

    // Attach fragment shader to program.
    glAttachShader(_program, fragShader);

    // Bind attribute locations.
    // This needs to be done prior to linking.
    glBindAttribLocation(_program, GLKVertexAttribPosition, "position");

    // Link program.
    if (![self linkProgram:_program]) {
        NSLog(@"Failed to link program: %d", _program);

        if (vertShader) {
            glDeleteShader(vertShader);
            vertShader = 0;
        }
        if (fragShader) {
            glDeleteShader(fragShader);
            fragShader = 0;
        }
        if (_program) {
            glDeleteProgram(_program);
            _program = 0;
        }

        return NO;
    }

    // Get uniform locations.
    uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix");
    uniforms[UNIFORM_TEXTURE] = glGetUniformLocation(_program, "u_heightMap");
    glProgramUniform1fvEXT (_program, uniforms[UNIFORM_TEXTURE], nTerrainElements, _pTerrainScaled);

    // Release vertex and fragment shaders.
    if (vertShader) {
        glDetachShader(_program, vertShader);
        glDeleteShader(vertShader);
    }
    if (fragShader) {
        glDetachShader(_program, fragShader);
        glDeleteShader(fragShader);
    }

    return YES;
}

对设置客户端数据有帮助吗?

在 iOS,您将使用 OpenGL ES。最常用的版本是 ES 2.0。 2013 年开始发布的设备也支持 ES 3.0。

您的着色器代码与 ES 2.0 不兼容:

in vec2 position;
uniform mat4 og_modelViewPerspectiveMatrix;
uniform sampler2DRect u_heightMap;

void main()
{
    gl_Position = og_modelViewPerspectiveMatrix *
                  vec4(position, texture(u_heightMap, position).r, 1.0);
}

要使其与 ES 2.0 兼容:

  • ES 2.0 仍然使用 attribute 作为顶点属性,而不是像当前版本的完整 OpenGL 和 ES 3.0+ 那样使用 in
  • 没有ES版本支持RECT纹理,所以类型sampler2DRect无效。使用常规 2D 纹理,在着色器代码中使用相应的 sampler2D
  • ES 2.0 使用 texture2D() 作为纹理采样函数的名称,而不是新版本中的 texture()

着色器应该如下所示:

attribute vec2 position;
uniform mat4 og_modelViewPerspectiveMatrix;
uniform sampler2D u_heightMap;

void main()
{
    gl_Position = og_modelViewPerspectiveMatrix *
                  vec4(position, texture2D(u_heightMap, position).r, 1.0);
}