DX12) 部分常量缓冲区被截断
DX12) Part of the Constants buffer is cut off
这是我的对象绘图常量缓冲区。
实际上,gWorld 和 gOldWorld 的值是正确的,但是 gCubemapOn、gMotionBlurOn、gRimLightOn 的值是错误的。
gCubemapOn 必须为 TRUE,它看起来像,但实际上该值是 65537。
gRimLightOn 必须为 TRUE,但如您所见,实际值为 FALSE。
下面的代码是我如何使用常量缓冲区的。
template<typename Cnst>
class ConstantBuffer
{
public:
ConstantBuffer(ID3D12Device* device, UINT count, bool isConstant=true)
{
if (isConstant)
mByteSize = (sizeof(Cnst) + 255) & ~255;
else
mByteSize = sizeof(Cnst);
ThrowIfFailed(device->CreateCommittedResource(
&Extension::HeapProperties(D3D12_HEAP_TYPE_UPLOAD),
D3D12_HEAP_FLAG_NONE,
&Extension::BufferResourceDesc(D3D12_RESOURCE_DIMENSION_BUFFER, mByteSize * count),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr, IID_PPV_ARGS(&mUploadBuffer)));
ThrowIfFailed(mUploadBuffer->Map(0, nullptr, (void**)(&mData)));
}
ConstantBuffer(const ConstantBuffer& rhs) = delete;
ConstantBuffer& operator=(const ConstantBuffer& rhs) = delete;
virtual ~ConstantBuffer()
{
if (mUploadBuffer)
mUploadBuffer->Unmap(0, nullptr);
mData = nullptr;
}
D3D12_GPU_VIRTUAL_ADDRESS GetGPUVirtualAddress(int idx) const
{
return mUploadBuffer->GetGPUVirtualAddress() + idx * mByteSize;
}
void CopyData(int index, const Cnst& data)
{
memcpy(&mData[index * mByteSize], &data, sizeof(Cnst));
}
UINT GetByteSize() const
{
return mByteSize;
}
private:
ComPtr<ID3D12Resource> mUploadBuffer = nullptr;
BYTE* mData = nullptr;
UINT mByteSize = 0;
};
这就是我更新常量缓冲区的方式
void Pipeline::UpdateConstants()
{
UINT matOffset = 0;
for (int i = 0; i < mRenderObjects.size(); i++)
{
mObjectCB->CopyData(i, mRenderObjects[i]->GetObjectConstants());
mRenderObjects[i]->UpdateMatConstants(mMaterialCB.get(), matOffset);
matOffset += mRenderObjects[i]->GetMeshCount();
}
}
ObjectConstants GameObject::GetObjectConstants()
{
ObjectConstants objCnst = {};
if (mReflected)
{
objCnst.World = Matrix4x4::Transpose(Matrix4x4::Multiply(mWorld, mReflectMatrix));
objCnst.oldWorld = Matrix4x4::Transpose(Matrix4x4::Multiply(mOldWorld, mReflectMatrix));
}
else
{
objCnst.World = Matrix4x4::Transpose(mWorld);
objCnst.oldWorld = Matrix4x4::Transpose(mOldWorld);
}
objCnst.cubemapOn = mCubemapOn;
objCnst.motionBlurOn = mMotionBlurOn;
objCnst.rimLightOn = mRimLightOn;
return objCnst;
}
struct ObjectConstants
{
XMFLOAT4X4 World;
XMFLOAT4X4 oldWorld;
bool cubemapOn;
bool motionBlurOn;
bool rimLightOn;
};
我相信这与看到的问题相同 。 HLSL bool 是 4 个字节,C++ bool 是 1 个字节。如果您将 CPU 结构声明为
struct ObjectConstants
{
XMFLOAT4X4 World;
XMFLOAT4X4 oldWorld;
int32_t cubemapOn;
int32_t motionBlurOn;
int32_t rimLightOn;
};
应该可以。
这是我的对象绘图常量缓冲区。 实际上,gWorld 和 gOldWorld 的值是正确的,但是 gCubemapOn、gMotionBlurOn、gRimLightOn 的值是错误的。
gCubemapOn 必须为 TRUE,它看起来像,但实际上该值是 65537。 gRimLightOn 必须为 TRUE,但如您所见,实际值为 FALSE。
下面的代码是我如何使用常量缓冲区的。
template<typename Cnst>
class ConstantBuffer
{
public:
ConstantBuffer(ID3D12Device* device, UINT count, bool isConstant=true)
{
if (isConstant)
mByteSize = (sizeof(Cnst) + 255) & ~255;
else
mByteSize = sizeof(Cnst);
ThrowIfFailed(device->CreateCommittedResource(
&Extension::HeapProperties(D3D12_HEAP_TYPE_UPLOAD),
D3D12_HEAP_FLAG_NONE,
&Extension::BufferResourceDesc(D3D12_RESOURCE_DIMENSION_BUFFER, mByteSize * count),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr, IID_PPV_ARGS(&mUploadBuffer)));
ThrowIfFailed(mUploadBuffer->Map(0, nullptr, (void**)(&mData)));
}
ConstantBuffer(const ConstantBuffer& rhs) = delete;
ConstantBuffer& operator=(const ConstantBuffer& rhs) = delete;
virtual ~ConstantBuffer()
{
if (mUploadBuffer)
mUploadBuffer->Unmap(0, nullptr);
mData = nullptr;
}
D3D12_GPU_VIRTUAL_ADDRESS GetGPUVirtualAddress(int idx) const
{
return mUploadBuffer->GetGPUVirtualAddress() + idx * mByteSize;
}
void CopyData(int index, const Cnst& data)
{
memcpy(&mData[index * mByteSize], &data, sizeof(Cnst));
}
UINT GetByteSize() const
{
return mByteSize;
}
private:
ComPtr<ID3D12Resource> mUploadBuffer = nullptr;
BYTE* mData = nullptr;
UINT mByteSize = 0;
};
这就是我更新常量缓冲区的方式
void Pipeline::UpdateConstants()
{
UINT matOffset = 0;
for (int i = 0; i < mRenderObjects.size(); i++)
{
mObjectCB->CopyData(i, mRenderObjects[i]->GetObjectConstants());
mRenderObjects[i]->UpdateMatConstants(mMaterialCB.get(), matOffset);
matOffset += mRenderObjects[i]->GetMeshCount();
}
}
ObjectConstants GameObject::GetObjectConstants()
{
ObjectConstants objCnst = {};
if (mReflected)
{
objCnst.World = Matrix4x4::Transpose(Matrix4x4::Multiply(mWorld, mReflectMatrix));
objCnst.oldWorld = Matrix4x4::Transpose(Matrix4x4::Multiply(mOldWorld, mReflectMatrix));
}
else
{
objCnst.World = Matrix4x4::Transpose(mWorld);
objCnst.oldWorld = Matrix4x4::Transpose(mOldWorld);
}
objCnst.cubemapOn = mCubemapOn;
objCnst.motionBlurOn = mMotionBlurOn;
objCnst.rimLightOn = mRimLightOn;
return objCnst;
}
struct ObjectConstants
{
XMFLOAT4X4 World;
XMFLOAT4X4 oldWorld;
bool cubemapOn;
bool motionBlurOn;
bool rimLightOn;
};
我相信这与看到的问题相同
struct ObjectConstants
{
XMFLOAT4X4 World;
XMFLOAT4X4 oldWorld;
int32_t cubemapOn;
int32_t motionBlurOn;
int32_t rimLightOn;
};
应该可以。