d3d12:添加常量缓冲区时,输出结构发生变化

问题描述 投票:0回答:1

灯带,这个与float3 worldPos有关 由于某种原因它不会沿 x 轴改变 enter image description here

根据 worldPos 为像素着色 enter image description here worldPos 取决于对象坐标而不是像素坐标

基于 worldPos 的颜色应该是什么样子 enter image description here

顶点着色器:

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 表现良好

c++ directx fragment-shader vertex-shader directx-12
1个回答
0
投票

存在内存对齐问题。对于常量缓冲区的

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 最终都会“在同一行”。

© www.soinside.com 2019 - 2024. All rights reserved.