2015-10-21 1 views
1

J'essaie actuellement de mettre en œuvre l'éclairage Phong & sur un cube texturé en utilisant HLSL et DirectX 11. Je crois que mes calculs d'éclairage ambiant et diffus sont corrects et visuellement ils produisent un résultat attendu. Toutefois, lorsque je demande l'éclairage spéculaires j'obtenir des résultats étranges (voir les liens)Pourquoi mon shader produit-il des résultats spéculaires incorrects? [DX11]

Diffuse, ambiante & spéculaires: https://i.gyazo.com/f7700d758e05227e27be91ab0cfdf64e.png

spéculaires Seulement: https://i.gyazo.com/27bbfa0efce5c60748f61f54365cc042.png

Mon fichier .fx:

//Texture Variables 
Texture2D txDiffuse[2] : register(t0); 
SamplerState anisoSampler : register(s0); 

//-------------------------------------------------------------------------------------- 
// Constant Buffer Variables 
//-------------------------------------------------------------------------------------- 
cbuffer ConstantBuffer : register(b0) 
{ 
    matrix World; 
    matrix View; 
    matrix Projection; 

    float4 DiffuseMtrl; 
    float4 DiffuseLight; 

    float3 LightPosition; 

    float4 AmbientMaterial; 
    float4 AmbientLight; 

    float4 specularMaterial; 
    float4 specularLight; 
    float specularPower; 

    float3 eyePosW; 
} 
//-------------------------------------------------------------------------------------- 
struct VS_INPUT 
{ 
    float4 Pos : POSITION; 
    float3 Normal : NORMAL; 
    float2 Tex : TEXCOORD0; 
}; 

//-------------------------------------------------------------------------------------- 
struct VS_OUTPUT 
{ 
    float4 Pos : SV_POSITION; 
    float3 Norm : NORMAL; 
    float3 PosW : POSITION; //Eye Vector 
    float3 LPos : LIGHTPOS; //Position of light 
    float2 Tex : TEXCOORD0; 
}; 

//-------------------------------------------------------------------------------------- 
// Vertex Shader 
//-------------------------------------------------------------------------------------- 

VS_OUTPUT VS(VS_INPUT vIn) 
{ 
    VS_OUTPUT output = (VS_OUTPUT)0; 
    float4 worldPosition; 

    output.Tex = vIn.Tex; 
    vIn.Pos.w = 1.0f; 
    output.Pos = mul(vIn.Pos, World); 


    output.Pos = mul(output.Pos, View); 
    output.Pos = mul(output.Pos, Projection); 

    worldPosition = mul(vIn.Pos, World); 

    output.LPos = normalize(worldPosition - LightPosition); 
    output.PosW = normalize(eyePosW.xyz - worldPosition.xyz); 
    float3 normalW = mul(float4(vIn.Normal, 0.0f), World).xyz; 
    normalW = normalize(normalW); 


    output.Norm = normalW; 
    return output; 
} 


//-------------------------------------------------------------------------------------- 
// Pixel Shader 
//-------------------------------------------------------------------------------------- 
float4 PS(VS_OUTPUT input) : SV_Target 
{ 
    float4 textureColor = txDiffuse[0].Sample(anisoSampler, input.Tex); 
    float4 bumpNormal = txDiffuse[1].Sample(anisoSampler, input.Tex); 
    float4 output; 
    float lightIntensity; 
    float specularAmount; 

    input.Norm = normalize(input.Norm); 
    bumpNormal = normalize(bumpNormal); 

    //Invert LDir for calculations 
    float3 LDir = -input.LPos; 

    lightIntensity = saturate(dot((input.Norm + bumpNormal.rgb), LDir)); 

    float3 r = reflect(LDir, (input.Norm + bumpNormal.rgb)); 
    specularAmount = pow(max(dot(r, input.PosW), 0.0f), specularPower); 


    // Compute Colour using Diffuse ambient and texture 
    float diffuseAmount = max(dot(LDir, (input.Norm + bumpNormal.rgb)), 0.0f); 

    float3 diffuse = (diffuseAmount * (DiffuseMtrl * DiffuseLight).rgb) * lightIntensity; 
    float3 ambient = AmbientLight * AmbientMaterial; 
    float3 specular = specularAmount * (specularMaterial * specularLight).rgb * lightIntensity; 

    output.rgb = ((ambient + diffuse) * textureColor) + specular; 
    output.a = textureColor.a; 

    return output; 
} 

S'il vous plaît excusez tout code désordonné ou noms de variables, j'ai essayé de faire fonctionner cela en utilisant divers tutoriels et manuels, chacun avec leurs propres conventions de nommage, donc le mien est un peu foiré à la maman ent.

EDIT: En utilisant la réponse et d'autres sources d'information, j'ai retravaillé mon shader et je l'ai fait fonctionner. Sur mes problèmes était un remplissage incorrect dans le tampon constant. J'ai également ajouté des calculs de l'espace tangentes et converti correctement mes Normales bosse dans un -1 à +1 plage

//-------------------------------------------------------------------------------------- 
// Constant Buffer Variables 
//-------------------------------------------------------------------------------------- 
cbuffer ConstantBuffer 
{ 
    matrix World; 
    matrix View; 
    matrix Projection; 

} 

struct PointLight 
{ 
    float4 ambient; 
    float4 diffuse; 
    float4 specular; 

    float3 pos; 
    float range; 

    float3 att; 
    float pad; 

}; 

cbuffer CbPerFrame 
{ 
    PointLight light; 
    float3 eyePosW; 
    float pad; 
    float4 SpecularMaterial; 
    float SpecularPower; 
    float3 pad2; 
}; 

Texture2D ObjTexture[2]; 
SamplerState ObjSamplerState; 

//-------------------------------------------------------------------------------------- 
struct VS_OUTPUT 
{ 
    float4 Pos : SV_POSITION; 
    float4 worldPos : POSITION; 
    float2 TexCoord : TEXCOORD; 
    float3 normal : NORMAL; 
    float3 tangent : TANGENT; 
    float3 biTangent : BITANGENT; 
}; 

void CalcTanBiTan(float3 norm, out float3 tan, out float3 biTan) 
{ 

    float3 c1 = cross(norm, float3(0.0f, 0.0f, 1.0f)); 
    float3 c2 = cross(norm, float3(0.0f, 1.0f, 0.0f)); 

    if (length(c1) > length(c2)) 
    { 
     tan = c1; 
    } 
    else 
    { 
     tan = c2; 
    } 
    tan = normalize(tan); 

    biTan = cross(norm, tan); 
    biTan = normalize(biTan); 
} 

//-------------------------------------------------------------------------------------- 
// Vertex Shader 
//-------------------------------------------------------------------------------------- 

VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL) 
{ 
    VS_OUTPUT output = (VS_OUTPUT)0; 

    output.Pos = mul(inPos, World); 
    output.worldPos = mul(inPos, World); 
    output.Pos = mul(output.Pos, View); 
    output.Pos = mul(output.Pos, Projection); 
    output.normal = mul(normal, World); 
    output.TexCoord = inTexCoord; 

    float3 tangent, biTangent; 
    CalcTanBiTan(normal, tangent, biTangent); 

    output.tangent = mul(tangent, (float3x3)World); 
    output.tangent = normalize(output.tangent); 
    output.biTangent = mul(biTangent, (float3x3)World); 
    output.biTangent = normalize(output.biTangent); 

    return output; 
} 


//-------------------------------------------------------------------------------------- 
// Pixel Shader 
//-------------------------------------------------------------------------------------- 
float4 PS(VS_OUTPUT input) : SV_Target 
{ 
    input.normal = normalize(input.normal); 
    float4 diffuse = ObjTexture[0].Sample(ObjSamplerState, input.TexCoord); 
    float4 bumpMap = ObjTexture[1].Sample(ObjSamplerState, input.TexCoord); 

    bumpMap = (bumpMap * 2.0f) - 1.0f; 

    float3 bumpNormal = (bumpMap.x * input.tangent) + (bumpMap.y * input.biTangent) + (bumpMap.z * input.normal); 
    bumpNormal = normalize(bumpNormal); 

    float3 finalColor = float3(0.0f, 0.0f, 0.0f); 

    //Create vector between light and pixel 
    float3 lightToPixelVec = light.pos - input.worldPos; 

    //find distance between light pos and pixel pos 
    float d = length(lightToPixelVec); 

    float3 finalAmbient = diffuse * light.ambient; 
    if (d > light.range) 
     return float4(finalAmbient, diffuse.a); 

    //Turn lightToPixelVec into a unit vector describing pixel direction from the light position 
    lightToPixelVec /= d; 

    float howMuchLight = dot(lightToPixelVec, bumpNormal); 

    float3 toEye = normalize(eyePosW - input.worldPos); 
    float3 spec; 
    [flatten] 
    if (howMuchLight > 0.0f) 
    { 
     float3 v = reflect(-lightToPixelVec, bumpNormal); 
     float specFactor = pow(max(dot(v, toEye), 0.0f), SpecularPower); 
     spec = specFactor * SpecularMaterial * light.specular; 
     finalColor += howMuchLight * diffuse * light.diffuse; 

     finalColor /= light.att[0] + (light.att[1] * d) + light.att[2] * (d*d); 
    } 

    finalColor = saturate(finalColor + finalAmbient + spec); 

    return float4(finalColor, diffuse.a); 
} 

Répondre

2

Première:

float4 bumpNormal = txDiffuse[1].Sample(anisoSampler, input.Tex); 
bumpNormal = normalize(bumpNormal); 

le magasin de données dans une texture est généralement un format RGBA avec 8 bits pour chaque canal. sauf si vous lisez à partir d'une texture flottante. lorsque la texture stocke chaque canal avec 8 bits. vous avez besoin de mapper le formulaire de valeur 0 ~ 1 à -1 ~ 1 dans le shader.

seconde:

input.Norm = normalize(input.Norm); 
bumpNormal = normalize(bumpNormal); 
(input.Norm + bumpNormal.rgb) 

add est incorrect, vous devez remplacer la normale avec bosse normale.

troisième:

Je ne sais pas dans quel espace de votre normale stocké, habituellement normale sera magasin dans l'espace tangent, cela signifie que vous devez également passer tangente ou binormale de vertex shader.

Si vous voulez seulement tester le spéculaire, vous pouvez utiliser la normale d'origine.