3

所以我一直在尝试在我正在做的一个玩具项目中实现 Cook-Torrance 着色器模型,从正确的角度看它看起来相当不错: 普通的 但是当你从一个浅的角度看时,你的视觉效果会变得明亮工件和周围的截止。

发生截止是因为我正在检查 NdotL > 0,但如果我删除它,事情开始变得更加奇怪: 删除了 NdotL 检查 颜色反转,在 NdotL == 0 的地方出现某种线,并且 NdotH < 0 的每个片段都变成黑色,使得它有一个鸡蛋的形状。

这是着色器代码:

#version 330 core
in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoord;
in vec3 camPos;
in vec3 lightDir;

out vec4 color;

uniform sampler2D diffuseTexture;
uniform sampler2D glossTexture;
uniform sampler2D metalTexture;
uniform samplerCube cubemapTexture;
uniform vec3 lightPos;

float F(float ior, vec3 view, vec3 halfV) {
    float F0 = abs((1.0 - ior) / (1.0 + ior));
    F0 *= F0;
    float VoH = dot(view,halfV);
    float fresnel = F0+(1-F0) * pow(1 - VoH,5);
    return fresnel;
}

float chiGGX(float v) {
    return v > 0 ? 1 : 0;
}
float G(vec3 view, vec3 norm, vec3 halfV, float alpha) {
    float VoH2 = clamp(dot(view,halfV),0.0,1.0);
    float chi = chiGGX( VoH2 / clamp(dot(view,norm),0.0,1.0));
    VoH2 = VoH2 * VoH2;
    float tan2 = (1-VoH2) / VoH2;
    return (chi*2)/(1+sqrt(1+alpha*alpha*tan2));

}
float D(float roughness, vec3 norm, vec3 halfV) {
    float NdotH = max(dot(norm, halfV), 0.0);
    float r1 = 1.0 / ( 4.0 * roughness * roughness * pow(NdotH, 4.0));
    float r2 = (NdotH * NdotH - 1.0) / (roughness * roughness * NdotH * NdotH);
    return r1 * exp(r2);
}
void main()
{
    float gamma = 2.2f;
    float roughnessValue = texture(glossTexture, TexCoord).r;
    vec3 lightColor = vec3(1.0f, 0.8f, 1.0f)*4.0;

    vec3 norm = normalize(Normal);

    vec3 viewDir = normalize(camPos-FragPos);
    vec3 halfVector = normalize(lightDir + viewDir);
    float diff = max(dot(norm, lightDir), 0.0);

    float NdotL = dot(norm, lightDir);

    float spec = 0;
    if(NdotL > 0.0) {
        spec = ( F(1.45, viewDir, halfVector) * G(viewDir,norm,halfVector,roughnessValue) * D(roughnessValue,norm,halfVector)) / (3.14151828 * dot(norm, viewDir) * dot(norm, lightDir));
    }
    vec3 specular = spec * lightColor;
    vec3 ambient = vec3(0.05);
    vec3 diffuse = (1 - texture(metalTexture, TexCoord).r) * diff * lightColor + ambient;
    vec3 finalcolor = (diffuse * pow(texture(diffuseTexture, TexCoord).rgb, vec3(gamma))) + specular;

    color = vec4(finalcolor, 1.0f);
    color.rgb = pow(color.rgb, vec3(1.0/gamma));

}

我知道有一些未使用的值,但那是因为着色器尚未完成。

4

2 回答 2

2

我找到了出现这种暴力切断的原因。在这个线程中,我们三个人在各自独立的实现中都犯了同样的错误。我们忘记了面积投影项,在最终的光照公式中: 在此处输入图像描述

正确应用它可以解决这个问题:

在此处输入图像描述

进入这个:

在此处输入图像描述

所以就你的着色器而言,这意味着:

vec3 specular = spec * lightColor * NdotL;

漫反射也一样(环境不适用,因为它来自各个方向,所以将漫反射和漫反射环境分开)

来源: http ://www.trentreed.net/blog/physically-based-shading-and-image-based-lighting/

于 2017-08-28T08:42:16.650 回答
1

这是我基于贝克曼分布的 Cook-Torrance 独立实现:

layout(location = 0) in PerVertex
{
    special3 pos; // tangent to view
    vec2 texcoord;
    vec4 diffuse;
} IN;

layout(location = 0) out vec4 OUT;

layout(binding = 0) uniform sampler2D u_bump;
layout(binding = 1) uniform sampler2D u_raughness;

struct PerLight
{
    vec3 position;
    vec3 color;
};

layout(binding = 1) uniform lights_block
{
    int nlights;
    PerLight lights[4];
} LIGHTS;



float D(float m, float c) {
    float c2 = c*c, m2 = m*m, c2m2 = c2*m2;
    return exp((c2 - 1)/c2m2)/(3.14159*c2m2*c2);
}
float F(float R0, float NV) { return R0 + (1 - R0)*pow(1 - NV, 5); }
float G(float NL, float NV, float NH, float HV) { return min(1, 2*NH*min(NV, NL)/HV); }

void accumulate_light(special3 tangent, vec3 viewDir, float roughness, PerLight light, inout vec3 diffuse, inout vec3 specular)
{
    vec3 lightDir = quat_apply(tangent.q, light.position);

    if(lightDir.z > 0)
    {
        lightDir = normalize(lightDir);
        float NL = lightDir.z;
        diffuse += NL * light.color;

        float NV = viewDir.z;
        if(NV > 0)
        {
            vec3 halfDir = normalize(lightDir + viewDir);
            float NH = halfDir.z;
            float HV = dot(halfDir, viewDir);
            specular += D(roughness, NH)*F(0.034, NV)*G(NL, NV, NH, HV)/(4*NV*NL) * light.color;
        }
    }
}

void main()
{
    special3 tangent = {
        vec3(0),
        texture(u_bump, IN.texcoord.xy)
    };

    tangent = special_mul(IN.pos, tangent);
    tangent = special_inverse(tangent);

    const vec3 viewDir = normalize(tangent.v);

    vec3 diffuse = vec3(0.05);
    vec3 specular = vec3(0);
    float raughness = max(0.215 + texture(u_raughness, IN.texcoord.xy).r - .5, 0.001);
    for(int i = 0; i < LIGHTS.nlights; ++i)
        accumulate_light(tangent, viewDir, raughness, LIGHTS.lights[i], diffuse, specular);

    OUT = vec4(diffuse*IN.diffuse.rgb + specular, IN.diffuse.a);
}

这是我得到的图像:

垂直角

在掠射角上,您会看到硬截止,但显然这是高粗糙度值应该是这样的:

放牧角

如果我添加凹凸贴图,则效果不再可见:

在此处输入图像描述

于 2016-09-25T07:10:21.240 回答