C++ OpenGL渲染器类设计:灵活和简单?
我正在为OpenGL3.1设计一个渲染系统(目前仅限于2D)。我想做的是真正考虑优雅的设计模式,这样我就不必担心一些乱七八糟的东西,这是一种维护和调试的痛苦 起初,我在考虑使用一个模板基类,该基类包含接受不同类型名称作为参数的函数。然后,子类将从基类继承,并在派生时发送它们将用作模板参数的类型 所以,我有点困惑,我应该如何正确地设计它,而不只是把东西砍掉。问题是,我正在使用自己的顶点结构,它环绕C++ OpenGL渲染器类设计:灵活和简单?,c++,renderer,opengl-3,C++,Renderer,Opengl 3,我正在为OpenGL3.1设计一个渲染系统(目前仅限于2D)。我想做的是真正考虑优雅的设计模式,这样我就不必担心一些乱七八糟的东西,这是一种维护和调试的痛苦 起初,我在考虑使用一个模板基类,该基类包含接受不同类型名称作为参数的函数。然后,子类将从基类继承,并在派生时发送它们将用作模板参数的类型 所以,我有点困惑,我应该如何正确地设计它,而不只是把东西砍掉。问题是,我正在使用自己的顶点结构,它环绕glm向量类,因此我可以在结构中拥有顶点对,并在调用glvertexattributepointer
glm
向量类,因此我可以在结构中拥有顶点对,并在调用glvertexattributepointer()
时使用内存偏移量跨越它们
换句话说,
typedef struct colorVertex_d
{
glm::vec3 Position;
glm::vec4 Color;
}
colorVertex_t;
typedef struct textureVertex_d
{
glm::vec3 Position;
glm::vec2 UV;
}
textureVertex_t;
理想情况下,我想做的是将此渲染器中可用的实际类型限制为已定义的顶点类型
我认为这样做的一种方法是,按照的思路做一些事情,然后在发送到类的类型无效时调用Shutdown方法(有点像异常,只是不是异常…)
不过,我甚至不确定在这种情况下这是否是一个好的实现
我真正想要的是一种方法,我可以支持多种缓冲区类型(例如顶点、索引、法线、颜色等),它们符合上面所示的顶点结构类型
原始来源
/**
* Is an abstract class to inherit from for defining custom buffer handler classes,
* the type name specified is the type of data stored in the buffer specifically, e.g. textureVertex_t or colorVertex_t
*/
template < typename DataT, typename ContainerT >
class RenderBuffer
{
public:
enum RenderMethod
{
Stream, // used for writing data into the buffer once per render
Dynamic, // values in the buffer are changed from time to time
Static // data is set only once, then rendered as many times as it needs to be
};
enum DrawMode
{
Triangle,
TriangleStrip,
Line,
LineStrip
};
enum BufSetType
{
Alloc,
Update
};
RenderBuffer( RenderMethod rm, DrawMode dm )
{
switch( rm )
{
case Stream: mRenderMethod = GL_STREAM_DRAW; break;
case Dynamic: mRenderMethod = GL_DYNAMIC_DRAW; break;
case Static: mRenderMethod = GL_STATIC_DRAW; break;
}
switch( dm )
{
case Triangle: mDrawMode = GL_TRIANGLES; break;
case TriangleStrip: mDrawMode = GL_TRIANGLE_STRIP; break;
case Line: mDrawMode = GL_LINES; break;
case LineStrip: mDrawMode = GL_LINE_STRIP; break;
}
}
virtual ~RenderBuffer( void )
{
}
virtual void Reserve( size_t sz ) = 0; // Reserve space for whatever container used to store the buffer data.
virtual void Bind( void ) const = 0;
virtual void UnBind( void ) const = 0;
template < typename DataT, ContainerT >
virtual void SetBufferData( const ShaderProgram& program, const ContainerT& data, BufSetType m )
{
}
template < typename DataT, ContainerT >
virtual void SetBufferData( const ShaderProgram& program, const DataT* data, const size_t len, BufSetType m )
{
}
virtual void Render( void ) const = 0;
size_t VertexCount;
protected:
GLenum mDrawMode, mRenderMethod;
};
/**
*是从中继承的抽象类,用于定义自定义缓冲区处理程序类,
*指定的类型名称是存储在缓冲区中的数据类型,例如textureVertex\u t或colorVertex\u t
*/
模板
类RenderBuffer
{
公众:
枚举渲染方法
{
流,//用于在每次渲染时将数据写入缓冲区一次
动态,//缓冲区中的值会不时更改
静态//数据只设置一次,然后根据需要进行多次渲染
};
枚举模式
{
三角形,
三角帆,
行,,
线带
};
枚举BufSetType
{
Alloc,
更新
};
RenderBuffer(RenderMethod rm、DrawMode dm)
{
交换机(rm)
{
案例流:mRenderMethod=GL\u Stream\u DRAW;break;
案例动态:mRenderMethod=GL\u Dynamic\u DRAW;break;
案例静态:mRenderMethod=GL\u Static\u DRAW;break;
}
开关(dm)
{
案例三角形:mDrawMode=GL_三角形;中断;
案例三角形TRIP:mDrawMode=GL_三角形_条;中断;
案例行:mDrawMode=GL_行;中断;
案例线条带:mDrawMode=GL_线条带;中断;
}
}
虚拟渲染缓冲区(无效)
{
}
虚拟空保留(size_t sz)=0;//为用于存储缓冲区数据的任何容器保留空间。
虚空绑定(void)常量=0;
虚拟void UnBind(void)const=0;
模板
虚拟void SetBufferData(常量着色器程序和程序、常量容器和数据、BufSetType m)
{
}
模板
虚拟void SetBufferData(常量着色器程序和程序、常量数据*数据、常量大小、BufSetType m)
{
}
虚拟虚空渲染(虚空)常量=0;
尺寸/垂直计数;
受保护的:
GLenum-mDrawMode,mRenderMethod;
};
我打了很多东西,但我仍然不确定你的目标或问题是什么。您似乎试图创建一个对象来封装OpenGL所能做的一切。我的第一个建议是不要那样做
我建议使用一个Mesh类,它包含一个VAO和一个程序,并且知道如何渲染自己:
glUseProgram(mProgramID);
glBindVertexArray(mVAO);
glDrawArrays(mDrawMode, 0, mNumPrimitives);
我想这就是你想要实现的
我建议使用子类,而不是所有的模板。设置一个需要做很多工作(可能有不同的子类、参数化函数或重载),但一旦设置好,渲染就很简单了
如果您死心塌地地使用模板,那么模板专门化可能会帮助您缩小差距。但我并不认为模板在这里有什么用处;这感觉就像是你在试图把他们塞进监狱。我打了一大堆东西,但我仍然不确定你的目标或问题是什么。您似乎试图创建一个对象来封装OpenGL所能做的一切。我的第一个建议是不要那样做 我建议使用一个Mesh类,它包含一个VAO和一个程序,并且知道如何渲染自己:
glUseProgram(mProgramID);
glBindVertexArray(mVAO);
glDrawArrays(mDrawMode, 0, mNumPrimitives);
我想这就是你想要实现的
我建议使用子类,而不是所有的模板。设置一个需要做很多工作(可能有不同的子类、参数化函数或重载),但一旦设置好,渲染就很简单了
如果您死心塌地地使用模板,那么模板专门化可能会帮助您缩小差距。但我并不认为模板在这里有什么用处;这感觉就像是你想把他们塞进监狱。我发现“RenderBuffer”这个名字有点让人困惑,因为它通常指的是FBO中的只写附件:)是的,我刚刚读到了这些。肯定会改变的…不过你还有其他的建议吗?说到这一点,我仍然觉得有点卡住了。关于顶点格式:由于您限制了顶点格式,我假设您也将依赖于在顶点着色器中指定属性位置?我走了另一个方向,让所有的东西都转到着色器,当使用不同的格式或属性顺序时,只需快速生成VAO。不过我需要在顶点格式上有很大的灵活性。属性名称和形式