镜面高光故障 OpenGL

Posted

技术标签:

【中文标题】镜面高光故障 OpenGL【英文标题】:Specular Highlight Glitch OpenGL 【发布时间】:2014-03-07 22:39:15 【问题描述】:

我在渲染 Phong 或其他高光 BRDF 时遇到了这个问题。

我从搅拌机导入 OBJ。只有顶点。在我这样重新计算法线之后:

    Vertex& v1 = _vertices[id1];
    Vertex& v2 = _vertices[id2];
    Vertex& v3 = _vertices[id3];

    glm::vec3 edge1 = v2.position - v1.position;
    glm::normalize(edge1);
    glm::vec3 edge2 = v3.position - v1.position;
    glm::normalize(edge2);

    glm::vec3 normal = glm::cross(edge1, edge2);
    if (normal != glm::vec3(0.0))
        glm::normalize(normal);
            
            TrianglePtr triangle(new Triangle);
    triangle->normal = normal;

之后,我将顶点三角形中的所有法线相加。当我显示法线时,它们看起来还不错。

我在几何着色器阶段计算所有内容

VS:

layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec3 normal;
layout (location = 3) in vec3 tangent;
layout (location = 4) in vec2 uv;

layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outTangent;
layout (location = 2) out vec3 outBitangent;
layout (location = 3) out vec3 outColor;
layout (location = 4) out vec2 outUV;

out gl_PerVertex

    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
;

void main()
   
    outNormal = normalize(normal);
    outTangent = normalize(tangent);
    outBitangent = normalize(cross(normal, tangent));
    outColor = color;
    outUV = uv;
    gl_Position =  vec4(position, 1.0);

GS:

#version 430 core

layout(triangles, invocations = 1) in;
layout (triangle_strip, max_vertices = 3) out;

layout (location = 0) in vec3 normal[];
layout (location = 1) in vec3 tangent[];
layout (location = 2) in vec3 bitangent[];
layout (location = 3) in vec3 color[];
layout (location = 4) in vec2 uv[];

layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outTangent;
layout (location = 2) out vec3 outBitangent;
layout (location = 3) out vec3 outColor;
layout (location = 4) out vec2 outUv;
layout (location = 5) out vec3 lightDir;
layout (location = 6) out vec3 viewDir;

layout (std140, binding = 0) uniform WorldDataBlock

    mat4 modelMatrix;
    mat4 viewMatrix;
    mat4 projectionMatrix;
    mat4 normalMatrix;
worldData;

uniform vec3 lightPosition = vec3(100.0, 100.0, 100.0);

in gl_PerVertex

    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
gl_in[];

out gl_PerVertex

    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
;

void main()

    mat4 MV = worldData.viewMatrix * worldData.modelMatrix;
    mat4 MVP =  worldData.projectionMatrix * MV;

    for(int idx = 0; idx < gl_in.length(); ++idx)
           
        outNormal = normalize(worldData.normalMatrix * vec4(normal[idx], 0.0)).xyz;
        outTangent = normalize(mat3(worldData.normalMatrix) * tangent[idx]);
        outBitangent = normalize(mat3(worldData.normalMatrix) * bitangent[idx]);
        
        vec3 pos = (MV * gl_in[idx].gl_Position).xyz;
        vec3 lightPos = (worldData.viewMatrix * vec4(lightPosition, 1.0)).xyz;
        
        lightDir = normalize(lightPos - pos);       
        viewDir = normalize(-pos);

        gl_Position = MVP *  gl_in[idx].gl_Position;
        EmitVertex();
    

    EndPrimitive();

FS:(尝试 Dysney 材质着色器),与标准 Phong 的结果相同

    float roughness = clamp(materialData.roughness, 0.0, 1.0);
float alpha = roughness * roughness;
float k = pow((roughness + 1.0), 2) / 8.0;
vec3 H = normalize(lightDir + viewDir);

float NdotV = max(dot(normal, viewDir), 0.0);
float NdotL = max(dot(normal, lightDir), 0.0);
float NdotH = max(dot(normal, H), 0.0);
float VdotH = max(dot(viewDir, H), 0.0);
float LdotH = max(dot(lightDir, H), 0.0);

float D = alpha * alpha / ( PI * pow((pow(NdotH, 2) * ( alpha * alpha - 1.0) + 1), 2));

float Gv = NdotV / (NdotV * (1.0 - k) + k);
float Gl = NdotL / (NdotL * (1.0 - k) + k);
float G = Gv * Gl;

float F0 = 0.5 + 2 * VdotH * VdotH * roughness;
float exponent = -5.55473 * VdotH - 6.98316 * VdotH;
float F = F0 + (1.0 - F0) * pow(2.0, exponent);

float denum = clamp(4.0 * NdotL * NdotV, EPSILON, 1.0);

return max(D * G * F / denum, 0.0);

有什么想法吗?

【问题讨论】:

【参考方案1】:

故障是由于我的正常计算造成的。我只从 OBJ 导入顶点。我基本上使用叉积来计算法线以对三角形进行加权,但这还不够。所以我改进了在公式中添加角权重的微积分。 对于基本形状,我在我的程序中创建它而不是导入它们。所以我可以直接计算给定形状的法线。

【讨论】:

以上是关于镜面高光故障 OpenGL的主要内容,如果未能解决你的问题,请参考以下文章

Vertex中实现每顶点光照的镜面高光效果

Unity-Shader-镜面高光Phong&BlinnPhong-油腻的师姐在哪里

浅墨Unity3D Shader编程之十三 单色透明Shader & 标准镜面高光Shader

UnityShader镜面反射计算与反射光向量推导

三维模型反射光照射实现物体表面高光实现(WebGL进阶04)

highlight是啥意思