OpenGL ES 2.0纹理无法显示

时间:2015-03-04 22:38:46

标签: ios objective-c opengl-es opengl-es-2.0

因此,我正在学习使用iOS的OpenGL ES 2.0并开发迷宫游戏。迷宫是随机生成的(所以不是一个装载的模型),我的斗争是在迷宫的墙壁和地板上纹理化。我的方法是将迷宫视为一系列立方体,并且我有单独绘制立方体各个面的代码(所以我可以通过简单地留下一些面来创建路径)。

使用捕获GPU帧,我已经确认纹理确实正确加载,帧缓冲区中的数据是正确的,并且我没有得到任何错误。我可以看到我的其他灯光效果(因此脸部不是完全黑色),但没有纹理出现。

以下是我如何定义我的立方体面孔

 GLfloat rightCubeVertexData[] =
{
    0.5f, -0.5f, -0.5f,
    0.5f, -0.5f, 0.5f,
    0.5f, 0.5f, -0.5f,
    0.5f, 0.5f, -0.5f,
    0.5f, -0.5f, 0.5f,
    0.5f, 0.5f, 0.5f,
};

GLfloat rightCubeNormalData[] =
{
    -1.0f, 0.0f, 0.0f,
    -1.0f, 0.0f, 0.0f,
    -1.0f, 0.0f, 0.0f,
    -1.0f, 0.0f, 0.0f,
    -1.0f, 0.0f, 0.0f,
    -1.0f, 0.0f, 0.0f,
};

GLfloat rightCubeTexCoords[] =
{
    0.0, 0.0,
    1.0, 0.0,
    0.0, 1.0,
    0.0, 1.0,
    1.0, 0.0,
    1.0, 1.0,
};

其他面的定义方式基本相同(除了它们各自在一个阵列中,分割位置,法线和tex坐标只是我尝试的东西;我只是想让一个面对纹理然后我会扩展到其余部分。

以下是我如何将数据加载到缓冲区

glGenVertexArraysOES(1, &_rightVertexArray);
glBindVertexArrayOES(_rightVertexArray);

glGenBuffers(3, _rightVertexBuffer);

glBindBuffer(GL_ARRAY_BUFFER, _rightVertexBuffer[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(rightCubeVertexData), rightCubeVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0));

glBindBuffer(GL_ARRAY_BUFFER, _rightVertexBuffer[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(rightCubeNormalData), rightCubeNormalData, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0));

glBindBuffer(GL_ARRAY_BUFFER, _rightVertexBuffer[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(rightCubeTexCoords), rightCubeTexCoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0));

同样,使用三个缓冲区是一个实验,其余的是在一个缓冲区中定义的。

以下是我加载纹理的方法

crateTexture = [self setupTexture:@"crate.jpg"];
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, crateTexture);
glUniform1i(uniforms[UNIFORM_TEXTURE], 0);

// Load in and set up texture image (adapted from Ray Wenderlich)
- (GLuint)setupTexture:(NSString *)fileName
{
    CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
    if (!spriteImage) {
        NSLog(@"Failed to load image %@", fileName);
        exit(1);
    }

    size_t width = CGImageGetWidth(spriteImage);
    size_t height = CGImageGetHeight(spriteImage);

    GLubyte *spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));

    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);

    CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);

    CGContextRelease(spriteContext);

    GLuint texName;
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);

    free(spriteData);
    return texName;
}

然后,在适当的时候,我只需要调用glDrawArrays来绘制面部。我对此完全感到困惑,这可能是一个非常愚蠢的错误,但任何人都能提供的任何帮助都会非常感激。

P.S。这是我的片段着色器

varying vec3 eyeNormal;
varying vec4 eyePos;
varying vec2 texCoordOut;

uniform sampler2D texture;

uniform vec3 flashlightPosition;
uniform vec3 diffuseLightPosition;
uniform vec4 diffuseComponent;
uniform float shininess;
uniform vec4 specularComponent;
uniform vec4 ambientComponent;

void main()
{
    vec4 ambient = ambientComponent;

    vec3 N = normalize(eyeNormal);
    float nDotVP = max(0.0, dot(N, normalize(diffuseLightPosition)));
    vec4 diffuse = diffuseComponent * nDotVP;

    vec3 E = normalize(-eyePos.xyz);
    vec3 L = normalize(flashlightPosition - eyePos.xyz);
    vec3 H = normalize(L+E);
    float Ks = pow(max(dot(N, H), 0.0), shininess);
    vec4 specular = Ks*specularComponent;
    if( dot(L, N) < 0.0 ) {
        specular = vec4(0.0, 0.0, 0.0, 1.0);
    }

    gl_FragColor = (ambient + diffuse + specular) * texture2D(texture, texCoordOut);
    //gl_FragColor = ambient + diffuse + specular;
    gl_FragColor.a = 1.0;
}

是的,所有统一名称都是正确的,并且与主代码中的内容相对应。

编辑:这是顶点着色器

precision mediump float;

attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoordIn;

varying vec3 eyeNormal;
varying vec4 eyePos;
varying vec2 texCoordOut;

uniform mat4 modelViewProjectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 normalMatrix;

void main()
{
    eyeNormal = (normalMatrix * normal);
    eyePos = modelViewMatrix * position;
    texCoordOut = texCoordIn;
    gl_Position = modelViewProjectionMatrix * position;
}

2 个答案:

答案 0 :(得分:0)

原来我在编译着色器时忘记了绑定属性位置。需要添加行

glBindAttribLocation(_program, GLKVertexAttribTexCoord0, "texCoordIn");

加载着色器方法。

答案 1 :(得分:0)

总结从评论中完成的程序......

在处理纹理时可能会出现很多问题,并且知道如何确定问题的位置是很好的。

纹理本身需要注意什么:

  • 检查您是否设置了

    等参数
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    
  • 检查将制服设置为glUniform1i(uniformName, 0),其中最后一个参数对应于活动纹理而不是纹理ID。
  • 其他包括检查统一名称是否正确,纹理是否已绑定..如果可能,请检查调试器是否正确加载了纹理。

除此之外,您的纹理坐标很可能会混乱,这似乎是一个非常常见的问题。要调试,最好使用纹理坐标本身替换片段着色器中纹理所获得的颜色。例如。将texture2D(texture, texCoordOut)替换为vec4(texCoordOut.x, texCoordOut.y, .0, 1.0)。由于纹理坐标应在[0,1]范围内,因此您应该在场景中看到红色和绿色之间的漂亮渐变。如果你没有看到它们,那么你的纹理坐标会搞砸:如果全部是黑色的,你的坐标都是零,如果大多数是黄色,那么你的坐标很可能太大了。

在你的情况下,纹理坐标都是黑色的,这意味着你总是从纹理中获得第一个像素,因此在场景中是一个恒定的颜色。在这一点上要检查的是:

  • 您推送到GPU的坐标是否正确
  • 指针是否设置为glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0))(检查所有参数)
  • 属性是否已启用glEnableVertexAttribArray(GLKVertexAttribTexCoord0)
  • 属性是否已绑定到正在编译的着色器。

在你的情况下,你忘了绑定纹理坐标属性,这很容易错过。

根据您提供给我们的信息,我们无法找到这个错误,但您应该注意我给您的程序,以确定问题的确切位置。它在将来也可能很方便。

相关问题