Освещение ненормальное при расчете в касательном пространстве.Возможно, что-то не так с матрицей преобразования координат - PullRequest
3 голосов
/ 16 мая 2019

Я пытаюсь рассчитать освещение в касательном пространстве.Но я просто продолжаю получать ненормальные результаты.Я модифицировал демонстрационный код книги, и мне хотелось бы узнать, может быть, что-то не так с матрицей преобразования, которую я создал.

У меня проблемы с решением проблемы в Введение в программирование трехмерных игр с помощью DirectX 11 .Я пытался использовать матрицу TBN

Tx, Ty, Tz,Bx, By, 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?Моя тысяча спасибо!

...