灯带,这个与float3 worldPos有关 由于某种原因它不会沿 x 轴改变
根据 worldPos 为像素着色 worldPos 取决于对象坐标而不是像素坐标
顶点着色器:
cbuffer rot : register(b0)
{
matrix modelViewProj;
matrix model;
};
struct Output
{
float3 worldPos : Position;
float3 n : Normal;
float4 pos : SV_Position;
float2 tc : Texcoord;
};
Output main(float3 pos : Position, float3 n : Normal, float2 tc : Texcoord)
{
Output vertexOut;
vertexOut.worldPos = (float3)mul(float4(pos, 1.0f), model);
vertexOut.pos = mul(float4(pos, 1.0f), modelViewProj);
vertexOut.n = mul(n, (float3x3) model);
vertexOut.tc = tc;
return vertexOut;
}
像素着色器:
struct ObjectCBuf
{
float3 materialColor;
};
cbuffer LightCBuf : register(b1)
{
float3 lightPos;
float3 ambient;
float3 diffuseColor;
float diffuseIntensity;
float attConst;
float attLin;
float attQuad;
ObjectCBuf object;
};
float4 main(float3 worldPos : Position, float3 n : Normal, float4 pos : SV_Position) : SV_TARGET
{
const float3 vToL = lightPos - worldPos;
const float distToL = length(vToL);
const float3 dirToL = vToL / distToL;
// diffuse attenuation
const float att = 1.0f / (attConst + attLin * distToL + attQuad * (distToL * distToL));
// diffuse intensity
const float3 diffuse = diffuseColor * diffuseIntensity * att * max(0.0f, dot(dirToL, n));
// final color
//return float4(object.materialColor, 1.0);
return float4(saturate((diffuse + ambient) * object.materialColor), 1.0f);
}
当我不在 C++ 代码中添加常量缓冲区时,worldPos 表现良好
存在内存对齐问题。对于常量缓冲区的
float2
到 float4
向量,您需要确保它们与 float4
边界对齐,否则它会被“撕裂”。 D3D11 也是如此。 (但此外,对于 D3D12,常量缓冲区需要具有与 256 字节对齐的总大小,即 64 float
,或 16 float4
)
在您的情况下,您有
float3 lightPos
和 float3 ambient
彼此相邻,这就是它们在内存中的放置方式:
0 | 1 | 2 | 3 |
---|---|---|---|
lightPos.x | lightPos.y | lightPos.z | 环境.x |
环境.y | 环境.z | 漫反射颜色.x | 漫反射颜色.y |
你看到这里的问题了吗?
float3 ambient
(以及float3 diffuseColor
)的元素“位于不同行”,float*
向量必须在 hlsl 中作为一个整体读取,而 hlsl 只能读取每个向量的“同一行”。值 ambient.x
(可能)读取正确,但值 ambient.y
和 ambient.z
丢失,并且它们最终可能会变成 0.0f
。我说“可能”是因为这是未定义的行为,不能保证这最终会在每个硬件上发生。
这就是我更改代码的方式:
cbuffer LightCBuf : register(b1)
{
// row 0
float3 lightPos;
float diffuseIntensity;
// row 1
float3 ambient;
float attConst;
// row 2
float3 diffuseColor;
float attLin;
// row 3
float attQuad;
ObjectCBuf object;
};
从上面的代码中注意到,我在每个 float3 旁边放置了一个 float,在移动到下一个元素之前填充了整个 4 个 float 长度的内存,这样每个 float3 最终都会“在同一行”。