1

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

起初,我的想法类似于有一个模板化的基类,它带有接受不同类型名作为参数的函数。然后子类将从基类继承,在派生时发送它们将使用的类型作为模板参数。

然后我发现这基本上是不可能的。

所以,我有点卡住了,我应该如何正确地设计这个而不只是把东西弄掉。问题是我正在使用我自己的顶点结构,它围绕glm向量类,所以我可以在一个结构中拥有顶点对,并在调用glVertexAttribPointer().

换句话说,

typedef struct colorVertex_d
{
    glm::vec3 Position;
    glm::vec4 Color;
}
colorVertex_t;

typedef struct textureVertex_d
{
    glm::vec3 Position;
    glm::vec2 UV;
}
textureVertex_t;

理想情况下,我想做的是将可用于此渲染器的实际类型限制为已定义的顶点类型。

我认为这样做的一种方法是按照 this 的方式做一些事情然后如果发送给类的类型无效,则调用 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;
};
4

1 回答 1

1

我打了一堆东西,但我仍然不确定你的目标或问题是什么。您似乎正在尝试创建一个对象来封装 OpenGL 可以做的所有事情。我的第一个建议是不要这样做。

我建议一个 Mesh 类,它包含一个 VAO 和一个程序并且知道如何渲染自己:

glUseProgram(mProgramID);
glBindVertexArray(mVAO);
glDrawArrays(mDrawMode, 0, mNumPrimitives);

我认为这就是你想要达到的目标。

我建议使用子类,而不是所有东西的模板。设置一个有很多工作(以及可能的不同子类、参数化函数或重载),但是一旦设置好,渲​​染就很简单了。

如果您对使用模板一无所知,那么模板专业化可能会帮助您弥合差距。但是我在这里并没有真正看到模板的好用处。感觉就像你正试图把它们硬塞进去。

于 2013-10-08T20:25:18.700 回答