将顶点属性绑定到常量值的 InputLayout?
InputLayout which binds vertex attributes to a constant value?
我正在尝试将一些代码从 OpenGL 移植到 DirectX - 在 OpenGL 中,可以禁用某个顶点属性并将其设置为常量值。
const GLfloat data[] = { 1.0f, 0.0f, 0.0f, 1.0f };
GLuint location = glGetAttribLocation(program, name);
glDisableVertexAttribArray(location);
glVertexAttrib4fv(location, data);
这非常有用,即如果着色器需要颜色的顶点属性,我可以通过这种方式传递一个常量值,而不是将相同的颜色复制到顶点缓冲区中的每个顶点。
在 DirectX 中,需要创建一个与着色器匹配的 ID3D11InputLayout
,例如:
ID3D11InputLayout* layout = nullptr;
D3D11_INPUT_ELEMENT_DESC ied[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
device->CreateInputLayout(ied, 2, vertexShader.data(), vertexShader.size(), &layout);
但是如果InputLayout没有覆盖着色器期望的所有顶点属性,就会出现运行时异常。
基本上我想在输入布局中省略某个顶点属性并将着色器中的属性值设置为常量值。
我目前只能看到以下解决方案(每个都有很大的缺点):
- 为常量颜色(来自
常量 buffer/uniform 而不是属性)→ 但这将导致额外的着色器对象和额外的着色器代码需要维护
- 为每个顶点复制相同颜色的顶点属性 → 但这会浪费大量内存
还有其他解决办法吗? DirectX 中处理此类情况的最佳做法是什么?
考虑在着色器中使用 #if 预处理器指令。这种方法不排除具有额外着色器对象的问题。尽管如此,它通过避免代码复制粘贴来简化代码维护。
示例:
struct VertexInputType
{
float4 inPosition : POSITION;
#ifdef USE_COLOR
float4 inColor : COLOR;
#endif
};
#ifndef USE_COLOR
static const float4 inColor = { 1.0, 0.0f, 0.0f, 1.0f };
#endif
Direct3D 中没有等效项 - 解决问题的方法是创建多个着色器对象,并使用每个着色器对象及其关联的输入布局来渲染场景中的对象。
但是请注意,以上指的是着色器对象,而不是着色器源。由于 D3D 着色器编译器与图形驱动程序完全分开,您可以使用 HLSL 预处理器更改着色器源,并将着色器编译为两个不同的着色器对象。此外,输入布局仅适用于顶点着色器,因此如果您的两个顶点着色器输出相同的信息,您的下一个着色器(外壳、几何或像素)可以在顶点着色器更改时保持不变。
我正在尝试将一些代码从 OpenGL 移植到 DirectX - 在 OpenGL 中,可以禁用某个顶点属性并将其设置为常量值。
const GLfloat data[] = { 1.0f, 0.0f, 0.0f, 1.0f };
GLuint location = glGetAttribLocation(program, name);
glDisableVertexAttribArray(location);
glVertexAttrib4fv(location, data);
这非常有用,即如果着色器需要颜色的顶点属性,我可以通过这种方式传递一个常量值,而不是将相同的颜色复制到顶点缓冲区中的每个顶点。
在 DirectX 中,需要创建一个与着色器匹配的 ID3D11InputLayout
,例如:
ID3D11InputLayout* layout = nullptr;
D3D11_INPUT_ELEMENT_DESC ied[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
device->CreateInputLayout(ied, 2, vertexShader.data(), vertexShader.size(), &layout);
但是如果InputLayout没有覆盖着色器期望的所有顶点属性,就会出现运行时异常。
基本上我想在输入布局中省略某个顶点属性并将着色器中的属性值设置为常量值。 我目前只能看到以下解决方案(每个都有很大的缺点):
- 为常量颜色(来自 常量 buffer/uniform 而不是属性)→ 但这将导致额外的着色器对象和额外的着色器代码需要维护
- 为每个顶点复制相同颜色的顶点属性 → 但这会浪费大量内存
还有其他解决办法吗? DirectX 中处理此类情况的最佳做法是什么?
考虑在着色器中使用 #if 预处理器指令。这种方法不排除具有额外着色器对象的问题。尽管如此,它通过避免代码复制粘贴来简化代码维护。
示例:
struct VertexInputType
{
float4 inPosition : POSITION;
#ifdef USE_COLOR
float4 inColor : COLOR;
#endif
};
#ifndef USE_COLOR
static const float4 inColor = { 1.0, 0.0f, 0.0f, 1.0f };
#endif
Direct3D 中没有等效项 - 解决问题的方法是创建多个着色器对象,并使用每个着色器对象及其关联的输入布局来渲染场景中的对象。
但是请注意,以上指的是着色器对象,而不是着色器源。由于 D3D 着色器编译器与图形驱动程序完全分开,您可以使用 HLSL 预处理器更改着色器源,并将着色器编译为两个不同的着色器对象。此外,输入布局仅适用于顶点着色器,因此如果您的两个顶点着色器输出相同的信息,您的下一个着色器(外壳、几何或像素)可以在顶点着色器更改时保持不变。