C++ 在hlsl着色器中设置全局参数的正确方法是什么?

C++ 在hlsl着色器中设置全局参数的正确方法是什么?,c++,3d,hlsl,direct3d11,C++,3d,Hlsl,Direct3d11,在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 : CO

在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;
}
m_deviceContext->VSSetConstantBuffers( 0, 1, &cameraCbuffer );
< >如何在摄像机移动时从C++代码F.E中设置这些全局值?我应该创建另一个着色器,它只设置我可以像这样作为缓冲区访问的这些值吗

void SetProjectionMatrix(float4x4 inputMatrix : MATRIX){
    Projection = inputMatrix;
}

请告诉我实现此目的的正确方法。

首先,在着色器中,您需要将矩阵放入恒定缓冲区:

cbuffer CameraBuffer : register( b0 ) {
    float4x4 World;
    float4x4 View;
    float4x4 Projection;
}
如果不声明常量缓冲区,则会为您创建它们,但最好显式声明它们并按更新频率对它们进行分组。例如,将每帧更新的所有常量和仅设置一次的所有常量组合在一起。这允许您只更新需要更新的常量,而不向GPU发送额外数据

即使它们位于此cbuffer结构中,在着色器中仍以相同的方式访问它们

在C++代码中,你将声明一个类似的结构来存储你的矩阵:

struct CameraConstants {
    XMFLOAT4X4 world;
    XMFLOAT4X4 view;
    XMFLOAT4X4 projection;
};
照顾好孩子是非常重要的。这种结构不会有问题,但在某些情况下,您可能需要向C++结构添加额外的填充,以说明着色器缓冲区打包数据,使其不会因为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 );
现在只需将常量缓冲区绑定到顶点着色器:

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;
}
m_deviceContext->VSSetConstantBuffers( 0, 1, &cameraCbuffer );
请注意,第一个参数映射到着色器cbuffer声明中使用的寄存器(本例中为
b0

还有一件事,hlsl中的矩阵默认为列主矩阵。如果你的矩阵是C++中的行主要元素,那么你需要在发送到GPU之前把它们转置或在着色器中声明你的矩阵为<代码> RooMealEng/<代码>
查看DirectX示例以获取所有这些的一些源代码:

首先,在着色器中,您需要将矩阵放入常量缓冲区:

cbuffer CameraBuffer : register( b0 ) {
    float4x4 World;
    float4x4 View;
    float4x4 Projection;
}
如果不声明常量缓冲区,则会为您创建它们,但最好显式声明它们并按更新频率对它们进行分组。例如,将每帧更新的所有常量和仅设置一次的所有常量组合在一起。这允许您只更新需要更新的常量,而不向GPU发送额外数据

即使它们位于此cbuffer结构中,在着色器中仍以相同的方式访问它们

在C++代码中,你将声明一个类似的结构来存储你的矩阵:

struct CameraConstants {
    XMFLOAT4X4 world;
    XMFLOAT4X4 view;
    XMFLOAT4X4 projection;
};
照顾好孩子是非常重要的。这种结构不会有问题,但在某些情况下,您可能需要向C++结构添加额外的填充,以说明着色器缓冲区打包数据,使其不会因为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 );
现在只需将常量缓冲区绑定到顶点着色器:

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;
}
m_deviceContext->VSSetConstantBuffers( 0, 1, &cameraCbuffer );
请注意,第一个参数映射到着色器cbuffer声明中使用的寄存器(本例中为
b0

还有一件事,hlsl中的矩阵默认为列主矩阵。如果你的矩阵是C++中的行主要元素,那么你需要在发送到GPU之前把它们转置或在着色器中声明你的矩阵为<代码> RooMealEng/<代码>
查看DirectX示例以获取所有这些的一些源代码:

您是否已经在internet上搜索过这些源代码?这是一个非常基本的问题,应该由许多教程来解决。(即使是快速搜索也会导致类似的结果。)@Gnietschow我想我不知道正确的术语。@Gnietschow还有一个问题,您提供的链接使用效果而不是缓冲区。我正在使用缓冲区,并将它们绑定到输入汇编阶段。虽然我的示例不适合这里,但很高兴看到,您甚至为您的问题在google上投入了一点精力。如果您不知道术语,我建议您先阅读一些教程。此外,您还可以阅读hlsl参考资料,该参考资料有点重,但大部分都有示例:您是否已经在互联网上搜索过该参考资料?这是一个非常基本的问题,应该由许多教程来解决。(即使是快速搜索也会导致类似的结果。)@Gnietschow我想我不知道正确的术语。@Gnietschow还有一个问题,您提供的链接使用效果而不是缓冲区。我正在使用缓冲区,并将它们绑定到输入汇编阶段。虽然我的示例不适合这里,但很高兴看到,您甚至为您的问题在google上投入了一点精力。如果您不知道术语,我建议您先阅读一些教程。此外,您还可以阅读hlsl引用,该引用有点重,但主要是通过示例:我是否必须仅在初始化常量缓冲区时或每次更改常量缓冲区中的值时调用
VSSetConstantBuffers()
?您只需要在希望将不同的常量缓冲区绑定到特定插槽时调用它。所以现在,如果您只有一个常量缓冲区,那么您只需要调用它一次,不管m