在hlsl着色器中设置全局参数的正确方法是什么?如果我有以下的全球对撞机:
float4x4 World;
float4x4 View;
float4x4 Projection;我在一个顶点着色器里使用它们:
void VertexShaderFunction( in float4 inputPosition : POSITION, in float4 colorIn : COLOR, out float4 posOut : SV_POSITION, out float4 colorOut : COLOUR)
{
//Set values for output
float4 worldPosition = mul(inputPosition, World);
float4 viewPosition = mul(worldPosition, View);
float4 position = mul(viewPosition, Projection);
posOut = position;
colorOut = colorIn;
}然后如何从c++代码f.e中设置这些全局值。相机什么时候动的?我是否应该创建另一个着色器,它将这些值设置为这样的缓冲区?
void SetProjectionMatrix(float4x4 inputMatrix : MATRIX){
Projection = inputMatrix;
}请告诉我实现这一目标的正确方法是什么。
发布于 2014-10-27 05:03:57
首先,在您的着色器中,您需要将矩阵放入一个常量缓冲区中:
cbuffer CameraBuffer : register( b0 ) {
float4x4 World;
float4x4 View;
float4x4 Projection;
}如果不声明常量缓冲区,则会为您创建常量缓冲区,但更好的方法是显式声明它们并按更新频率对它们进行分组。例如,将每帧一起更新的所有常量和仅在一起设置一次的所有常量分组。这允许您只更新需要更新的常量,而不向GPU发送额外的数据。
即使它们在这个cbuffer结构中,它们仍然在您的着色器中以相同的方式访问。
在C++代码中,您需要声明一个类似的结构来存储矩阵:
struct CameraConstants {
XMFLOAT4X4 world;
XMFLOAT4X4 view;
XMFLOAT4X4 projection;
};照顾好常量变量的填充规则是非常重要的。这种结构没有任何问题,但在某些情况下,您可能需要在C++结构中添加额外的填充,以说明着色器cbuffers打包数据的事实,这样由于GPU寄存器的16字节性质,它不会跨越16字节的边界。
在初始化过程中,还需要创建一个常量缓冲区。该过程与顶点缓冲区相同,但您需要使用以下标志来声明CPU可写的常量缓冲区:
cbDesc.Usage = D3D11_USAGE_DYNAMIC;
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;无论何时更新矩阵,都需要将它们上传到GPU。为此,您可以将常量缓冲区映射到CPU,并复制您的CameraConstants结构:
D3D11_MAPPED_SUBRESOURCE resource;
m_deviceContext->Map( cameraCbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource );
memcpy( resource.pData, cameraConstants, sizeof( CameraConstants ) );
m_deviceContext->Unmap( cameraCbuffer, 0 );现在,只需将常量缓冲区绑定到顶点着色器:
m_deviceContext->VSSetConstantBuffers( 0, 1, &cameraCbuffer );注意,第一个参数映射到您在着色器cbuffer声明中使用的寄存器(本例中为b0)。
另外,默认情况下,hlsl中的矩阵是主要列。如果您的矩阵是C++中的主要行(可能),那么您需要在发送到GPU之前转换它们,或者在着色器中将矩阵声明为row_major。
查看DirectX示例,获取所有这些的一些源代码:https://code.msdn.microsoft.com/windowsdesktop/Direct3D-Tutorial-Win32-829979ef
https://stackoverflow.com/questions/26571743
复制相似问题