OpenGL 3.3高角度视角下立方体渲染异常镜面高光问题
OpenGL 大型立方体阵列光照异常问题
问题背景
- 开发环境:OpenGL 3.3,Windows平台,C++语言,CMake构建系统
- 渲染目标:由大量独立立方体组成的方块阵列,当前阶段为光照功能调试期
异常现象
- 整体光照逻辑运行正常,但从特定高角度观察阵列时,会出现不符合物理逻辑的镜面高光。调试阶段已将镜面高光颜色修改为红色便于定位:按照光源方向设置,光线从立方体亮面方向入射,立方体侧面理论上不会产生该光源的反射高光。
- 特定视角下存在一处颜色跳变的棱边,成因暂未明确。
- 两处异常均在使用方向光源、特定观察角度下触发。
问题截图



问题排查结论
问题已解决,最终根因为纹理图片格式异常,并非C++业务逻辑或GLSL着色器代码逻辑错误。
核心代码
main.cpp 主渲染循环
// RENDER LOOP while (!glfwWindowShouldClose(window)) { // 输入处理:键盘、鼠标事件 processInput(window); defaultShader.use(); // 相机矩阵设置 // 模型矩阵为每个立方体单独动态设置 // 视图矩阵:世界空间转相机空间 glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); defaultShader.setMatrix4fv("view", view); // 投影矩阵:相机空间转裁剪空间设备坐标 glm::mat4 projection = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f); defaultShader.setMatrix4fv("projection", projection); // 绘制前缓冲清理 glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 绑定立方体VAO,设置光照通用参数 cube->use(); defaultShader.setVec3("viewPos", cameraPos.x, cameraPos.y, cameraPos.z); defaultShader.setVec3("material.specular", 0.0f, 1.0f, 0.0f); defaultShader.setFloat("material.shininess", 32.0f); defaultShader.setVec3("dirLight.direction", -1.0f, -0.0f, 0.0f); defaultShader.setVec3("dirLight.ambient", 0.2f, 0.2f, 0.2f); defaultShader.setVec3("dirLight.diffuse", 0.8f, 0.8f, 0.8f); defaultShader.setVec3("dirLight.specular", 1.0f, 1.0f, 1.0f); defaultShader.setVec3("pointLights[0].position", -1.0f, -1.0f, -1.0f); defaultShader.setVec3("pointLights[0].ambient", 0.2f, 0.2f, 0.2f); defaultShader.setVec3("pointLights[0].diffuse", 0.8f, 0.8f, 0.8f); defaultShader.setVec3("pointLights[0].specular", 1.0f, 1.0f, 1.0f); defaultShader.setFloat("pointLights[0].constant", 1.0f); defaultShader.setFloat("pointLights[0].linear", 0.045f); defaultShader.setFloat("pointLights[0].quadratic", 0.0075f); int cubesize = 30; // 逐立方体绘制30*30*30规格的阵列 for (float i = 0.0f; i < cubesize; i++) { for (float j = 0.0f; j < cubesize; j++) { for (float k = 0.0f; k < cubesize; k++) { glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(i, j, k)); defaultShader.setMatrix4fv("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); } } } // 绘制光源标记物体 light->use(); lightshader.use(); lightshader.setMatrix4fv("view", view); lightshader.setMatrix4fv("projection", projection); glm::mat4 model = glm::mat4(1.0f); lighty += 0.1f * deltaTime; model = glm::translate(model, glm::vec3(-1.0, -1.0, -1.0)); lightshader.setMatrix4fv("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); // 窗口交换缓冲、轮询事件 glfwSwapBuffers(window); glfwPollEvents(); }
片段着色器
#version 330 core in vec2 TexCoord; in vec3 Normal; in vec3 FragPos; struct DirLight { vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform DirLight dirLight; vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir); struct PointLight { vec3 position; float constant; float linear; float quadratic; vec3 ambient; vec3 diffuse; vec3 specular; }; #define NR_POINT_LIGHTS 1 uniform PointLight pointLights[NR_POINT_LIGHTS]; vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); struct Material { vec3 specular; float shininess; }; uniform Material material; uniform sampler2D texture0; uniform vec3 viewPos; out vec4 FragColor; void main() { // 计算基础插值变量 vec3 norm = normalize(Normal); vec3 viewDir = normalize(viewPos - FragPos); // 计算方向光光照贡献 vec3 result = CalcDirLight(dirLight, norm, viewDir); // 计算点光源光照贡献(当前注释未启用) for(int i = 0; i < NR_POINT_LIGHTS; i++) //result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); FragColor = texture2D(texture0, TexCoord) * vec4(result, 1.0); } vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir) { vec3 lightDir = normalize(-light.direction); // 漫反射分量 float diff = max(dot(normal, lightDir), 0.0); // 镜面高光分量 vec3 reflectDir = reflect(-lightDir, normal); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); // 合并分量输出 vec3 ambient = light.ambient * vec3(texture(texture0, TexCoord)); vec3 diffuse = light.diffuse * diff * vec3(texture(texture0, TexCoord)); vec3 specular = light.specular * spec * vec3(1.0f, 0.0f, 0.0f); // 调试专用:高光输出为红色 return (ambient + diffuse + specular); } vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) { vec3 lightDir = normalize(light.position - fragPos); // 漫反射分量 float diff = max(dot(normal, lightDir), 0.0); // 镜面高光分量 vec3 reflectDir = reflect(-lightDir, normal); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); // 距离衰减 float distance = length(light.position - fragPos); float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); // 合并分量输出 vec3 ambient = light.ambient * vec3(texture(texture0, TexCoord)); vec3 diffuse = light.diffuse * diff * vec3(texture(texture0, TexCoord)); vec3 specular = light.specular * spec * vec3(1.0f, 1.0f, 1.0f); ambient *= attenuation; diffuse *= attenuation; specular *= attenuation; return (ambient + diffuse + specular); }
顶点着色器
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoord; layout (location = 2) in vec3 aNormal; out vec2 TexCoord; out vec3 Normal; out vec3 FragPos; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main(){ gl_Position = projection * view * model * vec4(aPos, 1.0f); FragPos = vec3(model * vec4(aPos, 1.0)); TexCoord = vec2(aTexCoord.x, aTexCoord.y); Normal = aNormal; };
内容的提问来源于stack exchange,提问作者Redstonerayy
相关产品推荐
相关产品推荐

