DirectX 11 漫反射照明实现

DirectX 11 Diffuse Lighting Implementation

以下:https://www.gamasutra.com/view/feature/131275/implementing_lighting_models_with_.php?page=2

我正在尝试实施漫反射照明,但我认为我不理解某些东西......,我不知道我是否正确计算它。

立方体的顶点信息为:

SimpleVertex vertices[] =
        {
            { DirectX::XMFLOAT3(-1.0f, 1.0f, -1.0f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 0.0f) },
            { DirectX::XMFLOAT3(1.0f, 1.0f, -1.0f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 0.0f) },
            { DirectX::XMFLOAT3(1.0f, 1.0f, 1.0f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 1.0f) },
            { DirectX::XMFLOAT3(-1.0f, 1.0f, 1.0f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 1.0f) },

            { DirectX::XMFLOAT3(-1.0f, -1.0f, -1.0f), DirectX::XMFLOAT3(0.0f, -1.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 0.0f) },
            { DirectX::XMFLOAT3(1.0f, -1.0f, -1.0f), DirectX::XMFLOAT3(0.0f, -1.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 0.0f) },
            { DirectX::XMFLOAT3(1.0f, -1.0f, 1.0f), DirectX::XMFLOAT3(0.0f, -1.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 1.0f) },
            { DirectX::XMFLOAT3(-1.0f, -1.0f, 1.0f), DirectX::XMFLOAT3(0.0f, -1.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 1.0f) },

            { DirectX::XMFLOAT3(-1.0f, -1.0f, 1.0f), DirectX::XMFLOAT3(-1.0f, 0.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 1.0f) },
            { DirectX::XMFLOAT3(-1.0f, -1.0f, -1.0f), DirectX::XMFLOAT3(-1.0f, 0.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 1.0f) },
            { DirectX::XMFLOAT3(-1.0f, 1.0f, -1.0f), DirectX::XMFLOAT3(-1.0f, 0.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 0.0f) },
            { DirectX::XMFLOAT3(-1.0f, 1.0f, 1.0f), DirectX::XMFLOAT3(-1.0f, 0.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 0.0f) },

            { DirectX::XMFLOAT3(1.0f, -1.0f, 1.0f), DirectX::XMFLOAT3(1.0f, 0.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 1.0f) },
            { DirectX::XMFLOAT3(1.0f, -1.0f, -1.0f), DirectX::XMFLOAT3(1.0f, 0.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 1.0f) },
            { DirectX::XMFLOAT3(1.0f, 1.0f, -1.0f), DirectX::XMFLOAT3(1.0f, 0.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 0.0f) },
            { DirectX::XMFLOAT3(1.0f, 1.0f, 1.0f), DirectX::XMFLOAT3(1.0f, 0.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 0.0f) },

            { DirectX::XMFLOAT3(-1.0f, -1.0f, -1.0f), DirectX::XMFLOAT3(0.0f, 0.0f, -1.0f), DirectX::XMFLOAT2(0.0f, 1.0f) },
            { DirectX::XMFLOAT3(1.0f, -1.0f, -1.0f), DirectX::XMFLOAT3(0.0f, 0.0f, -1.0f), DirectX::XMFLOAT2(1.0f, 1.0f) },
            { DirectX::XMFLOAT3(1.0f, 1.0f, -1.0f), DirectX::XMFLOAT3(0.0f, 0.0f, -1.0f), DirectX::XMFLOAT2(1.0f, 0.0f) },
            { DirectX::XMFLOAT3(-1.0f, 1.0f, -1.0f), DirectX::XMFLOAT3(0.0f, 0.0f, -1.0f), DirectX::XMFLOAT2(0.0f, 0.0f) },

            { DirectX::XMFLOAT3(-1.0f, -1.0f, 1.0f), DirectX::XMFLOAT3(0.0f, 0.0f, 1.0f), DirectX::XMFLOAT2(1.0f, 1.0f) },
            { DirectX::XMFLOAT3(1.0f, -1.0f, 1.0f), DirectX::XMFLOAT3(0.0f, 0.0f, 1.0f), DirectX::XMFLOAT2(0.0f, 1.0f) },
            { DirectX::XMFLOAT3(1.0f, 1.0f, 1.0f), DirectX::XMFLOAT3(0.0f, 0.0f, 1.0f), DirectX::XMFLOAT2(0.0f, 0.0f) },
            { DirectX::XMFLOAT3(-1.0f, 1.0f, 1.0f), DirectX::XMFLOAT3(0.0f, 0.0f, 1.0f), DirectX::XMFLOAT2(1.0f, 0.0f) },
        };

顶点着色器是:

cbuffer ConstantBuffer : register( b0 )
{
    matrix World;
    matrix View;
    matrix Projection;
    float4 vMeshColor;
};

struct VS_INPUT
{
    float4 Position : POSITION;
    float3 Normal : NORMAL;
    float2 Texture : TEXCOORD0;
};

struct PS_INPUT
{
    float4 Position : SV_POSITION;
    float3 Normal : TEXCOORD0;
    float2 Texture : TEXCOORD1;
};

PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;

    output.Position = mul( input.Position, World );
    output.Position = mul( output.Position, View );
    output.Position = mul( output.Position, Projection );

    output.Normal = mul( input.Normal, World );
    output.Normal = mul( output.Normal, View );
    output.Normal = mul( output.Normal, Projection );
    output.Normal = normalize( output.Normal );

    output.Texture = input.Texture;

    return output;
}

像素为:

PS_OUTPUT PS( PS_INPUT input )
{
    PS_OUTPUT output;
    float4 ambient = {0.1, 0.0, 0.0, 1.0};
    float4 lightColor = { 1.0f, 1.0f, 1.0f, 1.0f};

    float3 lightPosition = ( 1.0f, 1.0f, 0.0f );
    float3 lightDirection = normalize(lightPosition - input.Position);

    float1 diffuse = saturate( dot( lightDirection, input.Normal )) * lightColor;

    output.color = diffuse;

    //float4 solidColor = float4( 1.0f, 1.0f, 0.0f, 1.0f );
    //output.color = solidColor;
    return output;
}

结果(立方体旋转50度时):

菲律宾共产党:https://github.com/walbourn/directx-sdk-samples/blob/master/Direct3D11Tutorials/Tutorial06/Tutorial06.cpp

HLSL:https://github.com/walbourn/directx-sdk-samples/blob/master/Direct3D11Tutorials/Tutorial06/Tutorial06.fx

这里没有太多的信息可以继续,但是法线是一个方向向量(一个方向)从一个顶点(一个点)指向某个方向。当您计算漫射照明时,您所做的是获得光的位置,获得顶点的位置(点,在本例中我从立方体假设),然后找到两个向量之间的角度。把它想象成一个三角形,你从光的位置到立方体的顶点画一条线,然后计算光的这条线和法向量(垂直、正交或直出的线)之间的角度立方体表面。这两个向量之间的角度越大,它就会越暗,因为你取 "dot product"。当角度成直角时,点积将为零,这意味着没有光。当"normal"方向直接指向光线的方向时,点积的值为1,表示全光。当您将此点积(基本上是光强度)与另一种颜色相乘时,您正在调整顶点(或立方体)所具有的原始颜色的亮度。这调节了你看到的颜色。希望能解释一些事情。

至于为什么换个数字会看到你看到的,我就不知道了。

我只是补充一点,关于你的问题,如果你改变法线和位置,为什么你会看到不同的东西,法线向量几乎总是一个单位向量(长度为一)。当你进行光照计算时,如果两个向量都被归一化(都是单位向量,或者都是长度为 1 的向量),你只能得到介于 0 和 1 之间的所需值。否则你会得到很大或很小的负数。如果你使用像 45 这样的大数字作为你的照明倍增系数,那么事情就不对了。着色器中的颜色值介于 0 和 1 之间。

更新:好吧,这个解释起来有点复杂,我不知道能不能画个图来说明一下。这段代码中发生的事情是,您获取立方体的每个角顶点,并将其乘以所谓的 world/view/projection 矩阵。基本上它获取立方体的顶点,将它移动到它在世界中的位置,然后将它移动到与相机位置相反的位置,这通常意味着靠近原点 (0, 0, 0) 在前面相机。然后投影矩阵将这些点转换到屏幕上。这里要记住的重要一点是,将顶点着色器中的传入顶点乘以这个神奇的 WVP 矩阵,最终结果是顶点最终出现在相机前面,然后投影到屏幕上。

现在正在进行第二部分,即光照计算。它可以在世界 space 中完成,或者在世界 x 视图转换完成后完成。在这种情况下,代码会在世界 space 中进行光照计算,这意味着无论立方体的顶点在其局部 space 中的哪个位置,它都会转换到其世界位置。它可以在世界任何地方,它可以是 (150, 20, 60)。您需要将它转换到这个世界位置,因为灯光位置也在这个 space 中的世界某个地方。法向量通常是单位向量(长度为 1 的向量)。想象法向量从 (0, 0, 0) 开始并指向一个方向。

在您将法向量乘以世界矩阵的第一个实例中,这是错误的。理想情况下应该发生的是法向量应该 'follow' 顶点位置的变换,然后从变换后的世界位置以长度为 1 的方式指出。我希望我能画出一些东西来更好地解释它。第一个肯定是错误的,第二个位置乘以世界矩阵我认为也是错误的。

编辑:我浏览了教程代码,它工作正常。您指定 (1, 1, 0) 的光点,然后在着色器中使用它。另一方面,在教程中,两个亮点是:

XMFLOAT4( -0.577f, 0.577f, -0.577f, 1.0f ),
XMFLOAT4( 0.0f, 0.0f, -1.0f, 1.0f ),

你会看到的第二个是单位向量,只有 Z 是 -1。第一个也是单位向量(长度为 1),因为 A 平方 + B 平方 + C 平方 = 长度。这就是为什么这两个都是单位向量并且点积会正确产生的原因。另一方面,您的 (1, 1, 0) 向量不是单位向量。我不确定这是否有区别,尽管在任何情况下您的代码和教程的代码都不相同,但我不确定这些更改是否是您的代码不起作用的原因。另请注意,查克的灯光代码之所以有效,是因为立方体位于中心,如果将其移动到其他任何地方,您到处都会遇到灯光错误。我猜他这样做只是为了演示。