HLSL 如何将常量缓冲区作为一个整体传递给函数,而不是每个成员
HLSL how to pass constant buffer as a whole to functions, instead of per member
假设我有多个使用相同功能的着色器,我想将它移到一个单独的函数中。例如,我有多个共享相同矩阵乘法的顶点着色器:
PS_INPUT main(VERTEX_INPUT vertex)
{
PS_INPUT output = (PS_INPUT)0;
output.Position = mul(vertex.Position, World);
output.Position = mul(output.Position, View);
output.Position = mul(output.Position, Projection);
// other uncommon functionality...
return output;
}
并且数据来自常量缓冲区。
cbuffer Object : register(b0)
{
float4x4 World;
}
cbuffer Camera : register(b1)
{
float4x4 View;
float4x4 Projection;
}
如果我想将矩阵乘法移动到单独的函数中,我通常会这样写:
float4 process_position(float4 inputPosition, float4x4 world, float4x4 view, float4x4 projection)
{
float4 outPosition = mul(inputPosition, world);
outPosition = mul(outPosition, view);
outPosition = mul(outPosition, projection);
return outPosition;
}
这很容易失控,并随着更多的争论变得异常混乱。参数可以分组在一个结构中,但如果我更改常量缓冲区中的某些内容,仍然需要维护。 有没有办法自动将绑定到当前着色器的整个 cbuffer 传递给一个函数,而不是它的单个成员?像这样的东西会很棒:
float4 process_position(float4 inputPosition, Object objBuf, Camera camBuf) // errors...
{
float4 outPosition = mul(inputPosition, objBuf.World);
outPosition = mul(outPosition, camBuf.View);
outPosition = mul(outPosition, camBuf.Projection);
return outPosition;
}
PS_INPUT main(VERTEX_INPUT vertex)
{
PS_INPUT output = (PS_INPUT)0;
output.Position = process_output(vertex.Position, Object, Camera); // errors...
// other uncommon functionality...
return output;
}
注意:使用着色器模型5_0
在着色器模型 5 中,常量缓冲区不是对象或变量,因此不能将 then 作为参数传递给函数。
最接近的方法确实是使用结构(并确保在 cbuffer 声明和函数输入中都使用结构。
struct sObjectData
{
float4x4 World;
};
struct sCameraData
{
float4x4 View;
float4x4 Projection;
};
cbuffer cbObject : register(b0)
{
sObjectData objectData;
}
cbuffer Camera : register(b1)
{
sCameraData cameraData;
}
float4 process_position(float4 inputPosition, sObjectData objBuf, sCameraData
camBuf)
{
float4 outPosition = mul(inputPosition, objBuf.World);
outPosition = mul(outPosition, camBuf.View);
outPosition = mul(outPosition, camBuf.Projection);
return outPosition;
}
float4 test = process_position(input.pos, objectData, cameraData);
当然可以进行一些维护(如果您重命名一个字段或删除一个字段,但如果无论如何都允许传递整个 cbuffer 也会出现这种情况),但至少添加新字段或重新排序字段会成功不受影响。
假设我有多个使用相同功能的着色器,我想将它移到一个单独的函数中。例如,我有多个共享相同矩阵乘法的顶点着色器:
PS_INPUT main(VERTEX_INPUT vertex)
{
PS_INPUT output = (PS_INPUT)0;
output.Position = mul(vertex.Position, World);
output.Position = mul(output.Position, View);
output.Position = mul(output.Position, Projection);
// other uncommon functionality...
return output;
}
并且数据来自常量缓冲区。
cbuffer Object : register(b0)
{
float4x4 World;
}
cbuffer Camera : register(b1)
{
float4x4 View;
float4x4 Projection;
}
如果我想将矩阵乘法移动到单独的函数中,我通常会这样写:
float4 process_position(float4 inputPosition, float4x4 world, float4x4 view, float4x4 projection)
{
float4 outPosition = mul(inputPosition, world);
outPosition = mul(outPosition, view);
outPosition = mul(outPosition, projection);
return outPosition;
}
这很容易失控,并随着更多的争论变得异常混乱。参数可以分组在一个结构中,但如果我更改常量缓冲区中的某些内容,仍然需要维护。 有没有办法自动将绑定到当前着色器的整个 cbuffer 传递给一个函数,而不是它的单个成员?像这样的东西会很棒:
float4 process_position(float4 inputPosition, Object objBuf, Camera camBuf) // errors...
{
float4 outPosition = mul(inputPosition, objBuf.World);
outPosition = mul(outPosition, camBuf.View);
outPosition = mul(outPosition, camBuf.Projection);
return outPosition;
}
PS_INPUT main(VERTEX_INPUT vertex)
{
PS_INPUT output = (PS_INPUT)0;
output.Position = process_output(vertex.Position, Object, Camera); // errors...
// other uncommon functionality...
return output;
}
注意:使用着色器模型5_0
在着色器模型 5 中,常量缓冲区不是对象或变量,因此不能将 then 作为参数传递给函数。
最接近的方法确实是使用结构(并确保在 cbuffer 声明和函数输入中都使用结构。
struct sObjectData
{
float4x4 World;
};
struct sCameraData
{
float4x4 View;
float4x4 Projection;
};
cbuffer cbObject : register(b0)
{
sObjectData objectData;
}
cbuffer Camera : register(b1)
{
sCameraData cameraData;
}
float4 process_position(float4 inputPosition, sObjectData objBuf, sCameraData
camBuf)
{
float4 outPosition = mul(inputPosition, objBuf.World);
outPosition = mul(outPosition, camBuf.View);
outPosition = mul(outPosition, camBuf.Projection);
return outPosition;
}
float4 test = process_position(input.pos, objectData, cameraData);
当然可以进行一些维护(如果您重命名一个字段或删除一个字段,但如果无论如何都允许传递整个 cbuffer 也会出现这种情况),但至少添加新字段或重新排序字段会成功不受影响。