2015-10-21 4 views
1

В настоящее время я пытаюсь реализовать затенение Фонга & Освещение на текстурированном кубе с использованием HLSL и DirectX 11. Я считаю, что мои вычисления окружающего и диффузного освещения являются правильными и визуально они дают ожидаемый результат. Однако, когда я применяю зеркальное освещение я получаю странные результаты (см ссылки)Почему мой шейдер производит неправильные зеркальные результаты? [DX11]

Диффузный, Ambient & Зеркальные: https://i.gyazo.com/f7700d758e05227e27be91ab0cfdf64e.png

Зеркальные только: https://i.gyazo.com/27bbfa0efce5c60748f61f54365cc042.png

Мой .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; 
} 

Пожалуйста извините любые беспорядочные коды или имена переменных, я попытался заставить это работать, используя различные учебники и учебники, каждый со своими собственными соглашениями об именах, так что мой немного перепутался с мамой Ent.

EDIT: Используя ответ и некоторые другие источники информации, я переработал свой шейдер и получил его работу. По моим проблемам было неправильное заполнение в постоянном буфере. Я также добавил космические вычисления касательных и правильно преобразованы мои рельефности нормалей в -1 до +1 диапазона в

//-------------------------------------------------------------------------------------- 
// 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); 
} 

ответ

2

Первый:

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

хранилище данных в текстуре, как правило, формат RGBA с 8 битами для каждого канала. , если вы не читаете текстуру поплавка. , когда текстура хранит каждый канал с 8 бит. вам нужно отобразить значение формы от 0 ~ 1 до -1 ~ 1 в шейдере.

второй:

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

добавить неверен, вы должны заменить нормальный с шишка нормально.

третий:

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

Если вы хотите протестировать зеркальное отображение, вы можете использовать оригинал.