C++ 可变模板和顶点缓冲区属性

C++ 可变模板和顶点缓冲区属性,c++,templates,opengl,variadic-templates,vbo,C++,Templates,Opengl,Variadic Templates,Vbo,在OpenGL中,创建VBO时,必须执行以下三项操作: 创建缓冲区 无符号整数vboId; glGenBuffers(1,&vboId); glBindBuffer(GL_数组_BUFFER,vboId); glBufferData(GLU数组缓冲区、大小、数据、GLU静态图); 确保缓冲区已绑定 glBindBuffer(GL_数组_BUFFER,vboId); 启用并定义属性 glvertexattributepointer(0,3,GL_FLOAT,GL_FALSE,3*s

在OpenGL中,创建VBO时,必须执行以下三项操作:

  • 创建缓冲区
无符号整数vboId;
glGenBuffers(1,&vboId);
glBindBuffer(GL_数组_BUFFER,vboId);
glBufferData(GLU数组缓冲区、大小、数据、GLU静态图);
  • 确保缓冲区已绑定
glBindBuffer(GL_数组_BUFFER,vboId);
  • 启用并定义属性
glvertexattributepointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(FLOAT),(void*)0);
GlenableVertexAttributeArray(0);
在原始OpenGL中执行此操作虽然简单,但如果要为单个缓冲区设置多个属性,则可能会失控。我在想,我可以通过如下API使用可变模板简化调用属性函数的过程:

//3个浮动位置,2个浮动uv纹理坐标。
浮点数据[]{
0.f,0.f,0.f,0.f,0.f,
0.f,1.f,0.f,0.f,1.f,
1.f,0.f,0.f,1.f,0.f,
1.f,1.f,0.f,1.f,1.f,
};
auto-vboId=createVbo(数据,sizeof(数据));
bindVbo(vboId);
setVboLayout(vboId);

然而,这是不可行的,因为模板参数(AFAIK)实际上不能是可变的,而只能使参数可变。我不想使用函数参数的原因是因为我想输入C++关键字<代码>浮点< /COD>和<代码> int >代码>,不能用作参数。我当前的解决方案是将参数与复制基本类型的枚举一起使用,例如
Float32
Int32
。我想知道是否可以使用可变模板来做类似的事情

您可以很好地创建可变模板参数,而无需从函数参数中扣除它们。但是,不能声明所需的交替类型和值参数的类型(

一种解决方案是使用复合类型来存储这两种信息,而数组类型非常适合。因此,您将声明并致电:

template <class... Attributes>
void setVboLayout(VboId vboId);

setVboLayout<float[3], float[2]>(vboId);
这里,
bindAttribute
重载每个属性返回刚注册的属性之后的偏移量


您可以很好地创建可变模板参数,而无需从函数参数中扣除它们。但是,不能声明所需的交替类型和值参数的类型(

一种解决方案是使用复合类型来存储这两种信息,而数组类型非常适合。因此,您将声明并致电:

template <class... Attributes>
void setVboLayout(VboId vboId);

setVboLayout<float[3], float[2]>(vboId);
这里,
bindAttribute
重载每个属性返回刚注册的属性之后的偏移量


一般不能混合使用非类型模板参数(
3
)和类型模板参数(
float
)。我建议创建一个包装器,将
float
3
float
2
进行分组,这似乎是相关的。(
setVboLayout(vboId);
)@Jarod42,我会尝试一下,因为我没有想到它,但我最初希望能够使用基本类型,以及能够指定类型counts@GabeRundlett:“
setVboLayout(vboId);
”为什么要这样做?这与设置vbolayout(GL_FLOAT,3,GL_FLOAT,2,vboId)有什么区别?您是否计划对这些值进行编译时检查?如果是,为什么?为什么使用C++关键字是重要的,即使OpenGL不使用那些关键字;它使用自己定义的类型,如
GLfloat
GLuint
,等等。总的来说,这似乎是一个毫无意义的想法。@GabeRundlett:“我当前的解决方案是使用参数和枚举来复制基本类型”OpenGL已经有这样的类型。@GabeRundlett:“我想让API与OpenGL无关。”这不是这样做的正确抽象。像这里描述的那些低级调用永远不应该直接暴露于抽象的代码中。它应该处理更抽象的概念,如对象和模型。这使您可以在用户背后自由地更改API的性质。例如,Vulkan使顶点格式成为管道状态的一部分,因此不能独立于着色器对其进行更改。此外,编译时硬编码使网格文件无法指定其自身的格式。通常无法混合使用非类型模板参数(
3
)和类型模板参数(
float
)。我建议创建一个包装器,将
float
3
float
2
进行分组,这似乎是相关的。(
setVboLayout(vboId);
)@Jarod42,我会尝试一下,因为我没有想到它,但我最初希望能够使用基本类型,以及能够指定类型counts@GabeRundlett:“
setVboLayout(vboId);
”为什么要这样做?这与设置vbolayout(GL_FLOAT,3,GL_FLOAT,2,vboId)有什么区别?您是否计划对这些值进行编译时检查?如果是,为什么?为什么使用C++关键字是重要的,即使OpenGL不使用那些关键字;它使用自己定义的类型,如
GLfloat
GLuint
,等等。总的来说,这似乎是一个毫无意义的想法。@GabeRundlett:“我当前的解决方案是使用参数和枚举来复制基本类型”OpenGL已经有这样的类型。@GabeRundlett:“我想让API与OpenGL无关。”这不是这样做的正确抽象。像这里描述的那些低级调用永远不应该直接暴露于抽象的代码中。它应该处理更抽象的概念,如对象和模型。这使您可以在用户背后自由地更改API的性质。例如,Vulkan使顶点格式成为管道状态的一部分,因此不能独立于着色器对其进行更改。此外,编译时硬编码使得不可能有