为什么我的着色器产生不正确的镜面反射结果?[DX11]

斯蒂芬·摩尔

我目前正在尝试使用HLSL和DirectX 11在带纹理的立方体上实施Phong阴影和照明。我相信我的环境和漫反射光照计算是正确的,并且在视觉上它们可以产生预期的结果。但是,当我使用镜面照明时,会得到奇怪的结果(请参阅链接)

漫反射,环境光和镜面光: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;
}

请原谅任何混乱的代码或变量名,我已经尝试使用各种教程和教科书来实现此目的,每种教程和教科书都具有自己的命名约定,因此我的想法目前有些混乱。

编辑:使用答案和其他一些信息源,我重新制作了着色器并使其正常工作。我的问题之一是常量缓冲区中的填充不正确。我还添加了切线空间计算并将正确的凹凸法线转换为-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);
}
疯子子

第一的:

 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)

添加不正确,应该用凹凸法线代替法线。

第三:

我不确定法线存储在哪个空间中,通常法线将存储在切线空间中,这意味着您还应该从顶点着色器传递切线或双法线。

如果只想测试镜面反射,则可以使用原始法线。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么我对象的ArrayList循环的结果是不正确的?

为什么我对象的ArrayList循环的结果是不正确的?

HLSL中的镜面反射

为什么我的GLSL着色器呈现裂痕?

使用SharpDX运行DX11计算着色器-无法获得结果

为什么OpenGL着色器无法正确编译?

从DX9到DX11的顶点着色器编译错误(Unity 5.6到2017.4)

为什么此函数产生不正确的值?

为什么我的几何着色器“过载”?

为什么我的程序返回的结果不正确?

计算着色器均匀优化不正确吗?

对象旋转时,对象上的自定义着色器不正确

顶点着色器中属性的位置不正确

为什么此哈希表产生不正确的结果?

为什么我的Hovertool(来自bokeh)显示不正确的结果?

为什么我的Ray March片段着色器反射纹理查找减慢了帧速率?

为什么我会收到“单变量”警告和不正确的结果?

为什么我的代码获得平均结果似乎不正确?

GLSL phong着色器产生的奇怪的镜面反射结果

为什么我的图像不正确?

IIf语句和If语句的评估方式不同。IIf语句产生不正确的结果。为什么?

基本镜面反射底纹

我的弹射器游戏产生的距离不正确

为什么我的顶点动画着色器在场景和游戏视图中产生不同的结果?

为什么我的数学不正确

为什么我的测验结果显示不正确?

为什么 R 产生不正确的 AIC 和 BIC

为什么我的 Rust StackDFS 实现会产生不正确的结果?

为什么 VPMOVMSKB 似乎产生了不正确的结果?