Xna 自定义HLSL着色器在icosphere上创建奇怪图案

Xna 自定义HLSL着色器在icosphere上创建奇怪图案,xna,shader,hlsl,lighting,Xna,Shader,Hlsl,Lighting,真的希望有人能在这里帮助我-我很少不能解决C#中的错误,因为我在这方面有相当多的经验,但我没有太多的HLSL可以继续 链接到下面的图片是同一个模型(运行时以编程方式生成)两次,第一次(白色)使用BasicFect,第二次使用我的自定义着色器,如下所示。它与BasicFect一起工作的事实让我认为,为模型生成法线或诸如此类的东西不是问题 为了更好地说明这个问题,我加入了不同层次的细分。值得一提的是,两种效果使用相同的照明方向 以下是我的着色器代码(请随意挑选,欢迎提供任何提示): float4x

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

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

为了更好地说明这个问题,我加入了不同层次的细分。值得一提的是,两种效果使用相同的照明方向

以下是我的着色器代码(请随意挑选,欢迎提供任何提示):

float4x4世界视图项目;
float4x4法线旋转=float4x4(1,0,0,0,1,0,0,0,1,0,0,0,0,1);
float4 ModelColor=float4(1,1,1,1);
bool TextureEnabled=false;
纹理模型纹理;
采样器颜色文本采样器=采样器\状态
{
纹理=;
magfilter=线性;minfilter=线性;mipfilter=线性;
AddressU=镜像;AddressV=镜像;
};
float4-AmbientColor=float4(1,1,1,1);
浮动环境强度=0.1;
float3 DiffuseLightDirection=float3(1,0,0);
float4 DiffuseColor=float4(1,1,1,1);
浮子扩散强度=1.0;
结构VertexShaderInput
{
浮动4位置:位置0;
float4 Normal:NORMAL0;
float2纹理坐标:TEXCOORD0;
};
结构VertexShaderOutput
{
浮动4位置:位置0;
float4颜色:COLOR0;
float2纹理坐标:TEXCOORD0;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput输入)
{
VertexShaderOutput输出=(VertexShaderOutput)0;
output.Position=mul(input.Position,WorldViewProj);
float4 normal=mul(input.normal,NormalRotation);
浮动光强度=点(法线、漫射光方向);
输出颜色=饱和(漫射颜色*漫射强度*光强度);
output.TextureCoordinates=input.TextureCoordinates;
返回输出;
}
float4 PixelShaderFunction(VertexShaderOutput输入):COLOR0
{
float4 pixBaseColor=ModelColor;
如果(TextureEnabled==true)
{
pixBaseColor=tex2D(彩色纹理采样器,输入纹理坐标);
}
float4照明=饱和((input.Color+AmbientColor*AmbientIntensity)*pixBaseColor);
返回照明;
}
技术最佳电流
{
通行证1
{
VertexShader=编译vs_2_0 VertexShaderFunction();
PixelShader=编译ps_2_0 PixelShaderFunction();
}
}

通常,在实施照明等式时,需要确保以下几点:

  • 法线、灯光方向和其他方向向量在点积中使用之前应进行规格化。在您的情况下,您可以添加如下内容:

    normal=正常化(normal)

    如果漫反射光方向尚未标准化,则应对其执行相同的操作。它已经是您的默认值,但如果您的应用程序更改了它,它可能不再正常化。因此,最好在应用程序代码中进行规范化,因为它只需要在更改时执行一次,而不是逐顶点执行

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

  • 灯光方向和法线必须指向曲面外的同一方向。默认灯光方向为
    (1,0,0)
    。如果希望灯光指向+x方向,则必须在对法线执行点积之前对向量求反,使其与法线一样从曲面指向。如果你已经考虑到了这一点,那么这就不是问题

  • 向量不能平移,因为它们只是一个方向而不是一个位置。因此,当你用矩阵变换它们时,确保向量的第四个分量(w)为0或者你用矩阵变换它时没有平移是很重要的。将w设置为0将使乘法过程中矩阵的任何平移为零。由于您的矩阵称为
    NormalRotation
    ,我假设它只包含一个旋转,所以这可能不是问题


  • 有几件事需要尝试:1)在将法线用于点积之前,请确保法线已标准化。2) 法线和光线方向向量需要指向点积的同一方向(从曲面向外)。如果你对光的意图是+x方向,那么在做点积之前,你需要将它否定为-x方向。3) 可能不是问题,但请确保
    输入的第四个分量。Normal
    为0,或者
    Normal rotation
    矩阵不包含平移。另外,在点状产品中使用之前,请确保灯光方向已规范化。第一句话通过规范化法线立即解决了我的问题。可能花了好几天的时间忽略了这一点!非常感谢您的快速回复。如果你把它作为答复寄过来,我会记下来的。
    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();
        }
    }