You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL 3.3高角度视角下立方体渲染异常镜面高光问题

OpenGL 大型立方体阵列光照异常问题

问题背景

  • 开发环境:OpenGL 3.3,Windows平台,C++语言,CMake构建系统
  • 渲染目标:由大量独立立方体组成的方块阵列,当前阶段为光照功能调试期

异常现象

  • 整体光照逻辑运行正常,但从特定高角度观察阵列时,会出现不符合物理逻辑的镜面高光。调试阶段已将镜面高光颜色修改为红色便于定位:按照光源方向设置,光线从立方体亮面方向入射,立方体侧面理论上不会产生该光源的反射高光。
  • 特定视角下存在一处颜色跳变的棱边,成因暂未明确。
  • 两处异常均在使用方向光源、特定观察角度下触发。

问题截图

异常红色高光现象1
棱边颜色跳变现象2
异常红色高光现象3

问题排查结论

问题已解决,最终根因为纹理图片格式异常,并非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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 00:51:26