在切线空间中计算时,照明异常。坐标转换矩阵可能有问题

时间:2019-05-16 07:48:46

标签: c++ directx-11 hlsl

我正在尝试计算切线空间中的光照。但是我一直在得到异常结果。我正在修改本书的演示代码,如果创建的转换矩阵可能有问题,我会徘徊。

我无法解决 DirectX 11 3D游戏编程简介中的问题。我尝试使用TBN矩阵

Tx,Ty,Tz,
Bx,作者,Bz,
Nx,Ny,Nz

正如书中提供的那样,但是我发现光矢量被错误地转换为切线空间,现在我不知道如何调试此着色器。

这是我的像素着色器:

float4 PS1(VertexOut pin,
uniform int gLightCount,
uniform bool gUseTexure,
uniform bool gAlphaClip,
uniform bool gFogEnabled,
uniform bool gReflectionEnabled) : SV_Target{
// Interpolating normal can unnormalize it, so normalize it.
pin.NormalW = normalize(pin.NormalW);
pin.TangentW = normalize(pin.TangentW);

// The toEye vector is used in lighting.
float3 toEye = gEyePosW - pin.PosW;

// Cache the distance to the eye from this surface point.
float distToEye = length(toEye);

// Calculate normalMapSample
float3 normalMapSample = 
normalize(SampledNormal2Normal(gNormalMap.Sample(samLinear, pin.Tex).rgb));

// normalize toEye
toEye = normalize(toEye);

// Default to multiplicative identity.
float4 texColor = float4(1, 1, 1, 1);
if (gUseTexure)
{
    // Sample texture.
    texColor = gDiffuseMap.Sample(samLinear, pin.Tex);

    if (gAlphaClip)
    {
        // Discard pixel if texture alpha < 0.1.  Note that we do this
        // test as soon as possible so that we can potentially exit the shader 
        // early, thereby skipping the rest of the shader code.
        clip(texColor.a - 0.1f);
    }
}

//
// Lighting.
//

float4 litColor = texColor;
if (gLightCount > 0)
{
    // Start with a sum of zero. 
    float4 ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
    float4 diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
    float4 spec = float4(0.0f, 0.0f, 0.0f, 0.0f);

    // Sum the light contribution from each light source.  
    [unroll]
    for (int i = 0; i < gLightCount; ++i)
    {
        float4 A, D, S;
        ComputeDirectionalLightInTangent(gMaterial, gDirLights[i], 
            normalMapSample, World2TangentSpace(pin.NormalW, pin.TangentW, gTexTransform), toEye,
            A, D, S);

        ambient += A;
        diffuse += D;
        spec += S;
    }

    litColor = texColor*(ambient + diffuse) + spec;

    if (gReflectionEnabled)
    {
        float3 incident = -toEye;
        float3 reflectionVector = reflect(incident, normalMapSample);
        float4 reflectionColor = gCubeMap.Sample(samLinear, reflectionVector);

        litColor += gMaterial.Reflect*reflectionColor;
    }
}

//
// Fogging
//

if (gFogEnabled)
{
    float fogLerp = saturate((distToEye - gFogStart) / gFogRange);

    // Blend the fog color and the lit color.
    litColor = lerp(litColor, gFogColor, fogLerp);
}

// Common to take alpha from diffuse material and texture.
litColor.a = gMaterial.Diffuse.a * texColor.a;

return litColor;
}  

这是函数 SampledNormal2Normal World2TangentSpace ComputeDirectionalLightInTangent

float3 SampledNormal2Normal(float3 sampledNormal)
{
float3 normalT = 2.0f*sampledNormal - 1.0f;
return normalT;
}

float3x3 World2TangentSpace(float3 unitNormalW, float3 tangentW, float4x4 texTransform)
{
// Build orthonormal basis.
float3 N = unitNormalW;
float3 T = normalize(tangentW - dot(tangentW, N)*N);
float3 B = cross(N, T);

float3x3 TBN = float3x3(T, B, N);
/*float3x3 invTBN = float3x3(T.x, T.y, T.z, B.x, B.y, B.z, N.x, N.y, N.z);
return invTBN;*/


float3 T_ = T - dot(N, T)*N;
float3 B_ = B - dot(N, B)*N - (dot(T_, B)*T_) / dot(T_, T_);
float3x3 invT_B_N = float3x3(T_.x, T_.y, T_.z, B_.x, B_.y, B_.z, N.x, N.y, N.z);
return invT_B_N;
}

void ComputeDirectionalLightInTangent(Material mat, DirectionalLight L,
float3 normalT, float3x3 toTS, float3 toEye,
out float4 ambient,
out float4 diffuse,
out float4 spec)
{
// Initialize outputs.
ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
spec = float4(0.0f, 0.0f, 0.0f, 0.0f);

// The light vector aims opposite the direction the light rays travel.
float3 lightVec = -L.Direction;
lightVec = mul(lightVec, toTS);
lightVec = normalize(lightVec);

// toEye to Tangent Space
toEye = mul(toEye, toTS);
toEye = normalize(toEye);

// Add ambient term.
ambient = mat.Ambient * L.Ambient;

// Add diffuse and specular term, provided the surface is in 
// the line of site of the light.

float diffuseFactor = dot(lightVec, normalT);

// Flatten to avoid dynamic branching.
[flatten]
if (diffuseFactor > 0.0f)
{
    float3 v = reflect(-lightVec, normalT);
    float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w);

    diffuse = diffuseFactor * mat.Diffuse * L.Diffuse;
    spec = specFactor * mat.Specular * L.Specular;
}
}

在大多数地方,我得到的结果似乎要暗得多,而在几个突出显示区域中,结果却太亮。我想知道是否有人可以帮助我编写代码或就如何调试hlsl着色器提供建议。我的万分感谢!

0 个答案:

没有答案