开启深度测试后未生效?附相关OpenGL/Cocos2d-x代码片段
嘿,看你给出的代码片段,首先最明显的问题是完全没看到开启深度测试的关键代码,这大概率就是根源。下面我给你拆解几个必须检查的点,结合你的代码来补全:
1. 先把深度测试开关打开!
OpenGL默认是关闭深度测试的,你得在初始化阶段(比如启动渲染前)加上这句:
glEnable(GL_DEPTH_TEST);
另外,每帧渲染前一定要记得同时清除颜色缓冲和深度缓冲,不然上一帧的深度数据会干扰当前帧:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
要是只清颜色不清深度,深度测试的结果肯定乱套。
2. 确认帧缓冲区有深度附件(针对Cocos2d-x)
从你用Director来看,应该是在Cocos2d-x环境下。默认帧缓冲区一般会带深度缓冲,但保险起见,初始化GLView的时候可以明确设置:
GLViewImpl* glView = GLViewImpl::createWithRect("GLDemo", Rect(0, 0, 800, 600)); glView->setDepthBufferFormat(GL_DEPTH_COMPONENT24); // 指定24位深度缓冲格式 Director::getInstance()->setOpenGLView(glView);
如果是自定义FBO的话,那必须手动绑定深度纹理/渲染缓冲作为附件,这个得额外注意。
3. 检查Shader里的Z坐标处理
你的顶点数据里有Z值(比如0.5、0.8),但得确保顶点着色器把Z坐标正确转换到裁剪空间啊!比如必须用MVP矩阵(模型视图投影矩阵)来变换顶点位置,不然Z值的范围不符合OpenGL的要求(裁剪空间Z是[-1,1]),深度测试根本没法正确判断。举个顶点着色器的例子:
attribute vec3 a_position; uniform mat4 u_MVPMatrix; // 这个矩阵要在代码里传进去 void main() { gl_Position = u_MVPMatrix * vec4(a_position, 1.0); }
要是你直接把顶点位置赋值给gl_Position,没做投影变换,那Z值等于白给。
4. 顶点数据绑定要完整
你的代码里创建了VAO和VBO,但没看到设置顶点属性指针的代码!比如glVertexAttribPointer和glEnableVertexAttribArray这俩关键调用。如果Z坐标的属性没正确绑定到着色器,那着色器拿到的Z值可能是默认值,深度测试自然失效。给你补一段:
// 先把顶点数据传入VBO glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 获取着色器中a_position的属性位置 GLint posLoc = m_Program->getAttribLocation("a_position"); // 设置顶点属性指针:每个顶点3个float,步长是3*sizeof(float) glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // 启用这个属性数组 glEnableVertexAttribArray(posLoc);
5. 深度测试函数的设置(可选)
默认的深度测试函数是GL_LESS(新像素Z值小于缓冲区里的就通过),一般够用。但如果你之前改过这个设置,可以重置回默认:
glDepthFunc(GL_LESS);
给你的代码补全示例
把这些步骤整合到你的代码里,大概是这样:
// 初始化阶段先开深度测试 glEnable(GL_DEPTH_TEST); glClearDepthf(1.0f); // 深度缓冲清除值默认是1.0,可省略 m_Program = new GLProgram; m_Program->initWithFilenames("shader/gldemo.vsh", "shader/gldemo.fsh"); m_Program->link(); m_Program->updateUniforms(); glGenVertexArrays(1, &vao); glBindVertexArray(vao); // 创建VBO并传入顶点数据 glGenBuffers(1, &vertexVBO); glBindBuffer(GL_ARRAY_BUFFER, vertexVBO); auto size = Director::getInstance()->getVisibleSize(); float vertices[] = { 0,0,0.5, // first point -1, 1,0.5, -1, -1,0.5, -0.3,0,0.8, 1, 1,0.8, 1, -1,0.8 }; glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 绑定顶点属性 GLint posLoc = m_Program->getAttribLocation("a_position"); glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(posLoc); // 解绑VAO和VBO glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0);
然后每帧渲染的时候:
// 先清除缓冲 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 使用着色器程序 m_Program->use(); // 计算并设置MVP矩阵(关键!根据你的相机来) Mat4 projMat = Director::getInstance()->getMatrix(MATRIX_STACK_PROJECTION); Mat4 modelViewMat = Director::getInstance()->getMatrix(MATRIX_STACK_MODELVIEW); Mat4 mvp = projMat * modelViewMat; m_Program->setUniformMatrix4fv("u_MVPMatrix", 1, GL_FALSE, mvp.m); // 绑定VAO并绘制 glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES, 0, 6); // 画两个三角形(6个顶点) glBindVertexArray(0);
按照这些步骤调整后,深度测试应该就能正常工作了~
内容的提问来源于stack exchange,提问作者jerryln

