使用 HLSL 和 D3D11 进行 Blinn-Phong 着色:点光源

Posted

技术标签:

【中文标题】使用 HLSL 和 D3D11 进行 Blinn-Phong 着色:点光源【英文标题】:Blinn-Phong shading with HLSL and D3D11: point light 【发布时间】:2015-12-30 10:18:57 【问题描述】:

我目前正在尝试使用 HLSL 中的 Blinn-Phong 着色在我的游戏中实现点光源。我遵循的教程链接here。 我现在的代码是:

struct VS_INPUT

    float4 Position : POSITION;
    float3 Normal : NORMAL;
    float2 TexCoord : TEXCOORD;
;

struct VS_OUTPUT

    float4 Position : SV_POSITION;
    float4 WorldPosition : POSITION;
    float3 Normal : NORMAL;
    float2 TexCoord : TEXCOORD;
;

struct NF3D_LIGHT_OMNIDIRECTIONAL

    float4 Diffuse;
    float4 Ambient;
    float3 Position;
    float3 Attitude;
    float Range;
    int BindSlot;
;


//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
cbuffer CB_PROJECTION : register(b0)

    matrix Projection;


cbuffer CB_VIEW : register(b1)

    matrix View;
    float4 CameraPosition;


cbuffer CB_WORLD : register(b2)

    matrix World;


cbuffer Light : register(b5)

    NF3D_LIGHT_OMNIDIRECTIONAL light;
;


//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_OUTPUT VS(VS_INPUT Input)

    VS_OUTPUT Output = (VS_OUTPUT)0;

    // Change the position vector to be 4 units for proper matrix calculations.
    Input.Position.w = 1.0f;

    // Aply the perspective to every vertex.
    Output.Position = mul(Input.Position, World);
    Output.WorldPosition = Output.Position;
    Output.Position = mul(Output.Position, View);
    Output.Position = mul(Output.Position, Projection);

    // Normalise the normal vector.
    Output.Normal = mul(Input.Normal, (float3x3)World);
    Output.Normal = normalize(Output.Normal);

    // Transfer the texture coordinates.
    Output.TexCoord = Input.TexCoord;

    return Output;



//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS(VS_OUTPUT Input) : SV_Target

    // https://***novak.wordpress.com/2008/11/13/hlsl-per-pixel-point-light-using-phong-blinn-lighting-model/
    // Phong relfection is ambient + light-diffuse + spec highlights.
    // I = Ia*ka*Oda + fatt*Ip[kd*Od(N.L) + ks(R.V)^n]
    // Ref: http://www.whisqu.se/per/docs/graphics8.htm
    // and http://en.wikipedia.org/wiki/Phong_shading

    // Get light direction for this fragment
    float3 lightDir = normalize(light.Position - Input.WorldPosition);

    // Note: Non-uniform scaling not supported
    float diffuseLighting = saturate(dot(Input.Normal, -lightDir)); // per pixel diffuse lighting

    // Introduce fall-off of light intensity
    diffuseLighting *= ((length(lightDir) * length(lightDir)) / dot(light.Position - Input.WorldPosition, light.Position - Input.WorldPosition));

    // Using Blinn half angle modification for perofrmance over correctness
    float3 h = normalize(normalize(CameraPosition.xyz - Input.WorldPosition) - lightDir);
    float specLighting = pow(saturate(dot(h, Input.Normal)), 2.0f);

    return saturate(light.Ambient + (light.Diffuse * diffuseLighting * 0.6f) + (specLighting * 0.5f));

在这张照片中可以看到问题: 请注意,这些帧是故意不按顺序排列的,我尝试捕获它们以便可以非常清楚地理解错误。

小行星是一个简单的模型,它围绕点光源的原点运行。镜面光在所有面和像素上应该是均匀的,但正如您所见,如果网格位于相机前面,反射光会在其上形成锐利的形状。 我也意识到我的代码是错误的,如果我从方程中删除镜面光,问题就会消失。谁能解释一下这里发生了什么,我该如何解决这个问题?提前谢谢你。

【问题讨论】:

【参考方案1】:

我解决了!问题是:

CameraPosition.xyz - Input.WorldPosition

它们都是float4 类型,删除.xyz 消除了这个烦人的错误。

【讨论】:

为什么WorldPositionCameraPosition float4s 呢?真正的解决方案可能是让他们float3s。照原样,您的修复可能使它看起来更正确,但它仍然可能不完全正确。 我不知道,从我的测试看来,它似乎有效。感谢您的回复。

以上是关于使用 HLSL 和 D3D11 进行 Blinn-Phong 着色:点光源的主要内容,如果未能解决你的问题,请参考以下文章

在 HLSL 中进行 64 位加法,为啥我的一种实现会产生不正确的结果?

OBS Studio 窗口采集game-capture注入之OpenGL与D3D11的GPU资源进行互操作

OpenGL学习脚印:Blinn-Phong光照模型

球体在渲染纹理时会显示多边形

[Unity] Shader - CG语言 和 HLSL语言

blinn phong 照明产生奇怪的结果