【问题标题】:Custom HLSL shader making weird patterns across icosphere自定义 HLSL 着色器在 icosphere 上制作奇怪的图案
【发布时间】:2014-10-09 07:31:09
【问题描述】:

真的希望有人可以在这里帮助我 - 我很少无法解决 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) 确保在点积中使用法线之前对其进行规范化。 2)法线和光的方向向量需要指向相同的点积方向(从表面出来)。如果您对光的意图是 +x 方向,那么您需要在进行点积之前将其否定为 -x 方向。 3) 可能不是问题,但要确保input.Normal 的第四个分量为0 或NormalRotation 矩阵不包含任何翻译。
  • 在点积中使用之前还要确保光的方向是标准化的
  • 第一句话立即解决了我的问题,将法线归一化。可以花几天时间俯瞰它!非常感谢您的快速回复。如果您将其作为答案发送,我会标记它。

标签: xna shader hlsl lighting


【解决方案1】:

一般来说,在实现光照方程时,需要确保以下几点:

  1. 在将法线、光线方向和其他方向向量用于点积之前,应先对其进行归一化处理。在您的情况下,您可以添加如下内容:

    normal = normalize(normal);

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

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

  2. 光线方向和法线必须指向从表面向外的同一方向。您的默认灯光方向是(1,0,0)。如果您希望光线指向 +x 方向,那么您必须在与法线进行点积之前实际取反向量,以便它像法线一样从表面指向。如果您已经考虑到这一点,那么这不是问题。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-16
    相关资源
    最近更新 更多