C++ OpenGL渲染器类设计:灵活和简单?

C++ OpenGL渲染器类设计:灵活和简单?,c++,renderer,opengl-3,C++,Renderer,Opengl 3,我正在为OpenGL3.1设计一个渲染系统(目前仅限于2D)。我想做的是真正考虑优雅的设计模式,这样我就不必担心一些乱七八糟的东西,这是一种维护和调试的痛苦 起初,我在考虑使用一个模板基类,该基类包含接受不同类型名称作为参数的函数。然后,子类将从基类继承,并在派生时发送它们将用作模板参数的类型 所以,我有点困惑,我应该如何正确地设计它,而不只是把东西砍掉。问题是,我正在使用自己的顶点结构,它环绕glm向量类,因此我可以在结构中拥有顶点对,并在调用glvertexattributepointer

我正在为OpenGL3.1设计一个渲染系统(目前仅限于2D)。我想做的是真正考虑优雅的设计模式,这样我就不必担心一些乱七八糟的东西,这是一种维护和调试的痛苦

起初,我在考虑使用一个模板基类,该基类包含接受不同类型名称作为参数的函数。然后,子类将从基类继承,并在派生时发送它们将用作模板参数的类型

所以,我有点困惑,我应该如何正确地设计它,而不只是把东西砍掉。问题是,我正在使用自己的顶点结构,它环绕
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。不过我需要在顶点格式上有很大的灵活性。属性名称和形式