自定义HLSL着色器在icosphere上制作奇怪的模式

时间:2014-10-07 20:47:43

标签: xna shader hlsl lighting

真的希望有人可以在这里帮助我 - 我很少能解决C#中的错误,因为我有相当多的经验,但我没有太多可以继续使用HLSL。

链接到下面的图片是相同的模型(在运行时以编程方式生成)两次,第一次(白色)时间使用BasicEffect,第二次使用我的自定义着色器,如下所示。它与BasicEffect一起工作的事实使我认为生成模型的法线或类似的东西不是问题。

我已经包含了不同级别的细分以更好地说明问题。值得一提的是,两种效果都使用相同的照明方向。

https://imagizer.imageshack.us/v2/801x721q90/673/qvXyBk.png

这是我的着色器代码(随意挑选它,任何提示都非常受欢迎):

float4x4 WorldViewProj;

float4x4 NormalRotation = float4x4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);

float4 ModelColor = float4(1, 1, 1, 1);
bool TextureEnabled = false;
Texture ModelTexture;
sampler ColoredTextureSampler = sampler_state
{
    texture = <ModelTexture>;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter = LINEAR;
    AddressU = mirror; AddressV = mirror;
};

float4 AmbientColor = float4(1, 1, 1, 1);
float AmbientIntensity = 0.1;
float3 DiffuseLightDirection = float3(1, 0, 0);
float4 DiffuseColor = float4(1, 1, 1, 1);
float DiffuseIntensity = 1.0;

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float4 Normal : NORMAL0;
    float2 TextureCoordinates : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float4 Color : COLOR0;
    float2 TextureCoordinates : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output = (VertexShaderOutput)0;

    output.Position = mul(input.Position, WorldViewProj);

    float4 normal = mul(input.Normal, NormalRotation);
    float lightIntensity = dot(normal, DiffuseLightDirection);
    output.Color = saturate(DiffuseColor * DiffuseIntensity * lightIntensity);

    output.TextureCoordinates = input.TextureCoordinates;

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    float4 pixBaseColor = ModelColor;
    if (TextureEnabled == true)
    {
        pixBaseColor = tex2D(ColoredTextureSampler, input.TextureCoordinates);
    }
    float4 lighting = saturate((input.Color + AmbientColor * AmbientIntensity) * pixBaseColor);
    return lighting;
}

technique BestCurrent
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

1 个答案:

答案 0 :(得分:0)

通常,在实施照明方程式时,需要确保一些事项:

  1. 在点积中使用法线,光线方向和其他方向矢量之前,应将其标准化。在您的情况下,您可以添加如下内容:

    normal = normalize(normal);

    如果DiffuseLightDirection已经未正常化,则应该这样做。它已经使用了您的默认值,但如果您的应用更改了它,则可能不再进行规范化。为此,最好在应用程序代码中进行规范化,因为它只需要在更改时执行一次,而不是每个顶点执行一次。

    还要记住,如果您将向量乘以包含比例的矩阵,则向量将不再被标准化,因此需要重新标准化。

  2. 光线方向和法线必须指向与表面相同的方向。您的默认指示灯是(1,0,0)。如果你想让光线指向+ x方向,那么你必须在使用法线执行点积之前实际否定向量,这样它就像法线一样指向表面。如果你已经考虑到这一点,那么这不是问题。

  3. 矢量无法翻译,因为它们只是一个方向而不是一个位置。因此,重要的是要确保何时使用矩阵转换它们,该矩阵要么向量的第四个分量(w)为0,要么转换它的矩阵没有转换。将w设置为0将在乘法期间将矩阵的任何平移归零。由于你的矩阵被称为NormalRotation,我假设它只包含一个轮换,所以这可能不是问题。