创建几何数据的结构

时间:2016-02-21 20:12:07

标签: c++ opengl vbo vao

我想在一个缓冲区中绘制多个多边形,这是我认为它应该如何工作的概念,但事实并非如此。 这就是我所拥有的:

GLuint VertexArrayID; 
GLuint vao;
GLuint program;

typedef struct object{
    GLuint vao;
    GLuint numVertices;
} object;

object objects[MAX_VERTEX_COUNT];

我在这里创建VBO:

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, VertexArrayID);
    glBufferData(GL_ARRAY_BUFFER, 2 * vertex_count * sizeof(float), data, GL_STATIC_DRAW);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(data), data);
    glUseProgram(program);
    GLuint vPosition = glGetAttribLocation(program, "vPosition");
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glVertexPointer(2, GL_FLOAT, 0, NULL);
    glEnableClientState(GL_VERTEX_ARRAY);

    //glDrawArrays(GL_TRIANGLE_FAN, 0, vertex_count);

我做了这样的循环,但是我想,当我把vao放在对象[i] .vao中时,每次当我通过那个循环时,它都没有这个循环,但我不确定。 / p>

    for (int i = 0; i < 5; i++)
    {
        objects[i].vao = vao;
        glBindVertexArray(objects[i].vao);
        objects[i].numVertices = vertex_count;
        glDrawArrays(GL_TRIANGLE_FAN, 0, objects[i].numVertices);
    }

    glDisableClientState(GL_VERTEX_ARRAY);

也许你有一些想法?

1 个答案:

答案 0 :(得分:0)

这里我有一个Image2D类对象,用于渲染与我的GUI层次结构一起使用的基本2D图像。我的Shader引擎非常大,因为我有一个使用模板类型管理着色器的系统。它还使用批处理,并且加载到内存中的所有资产都保存到Storage类中,用于处理内存占用的清理。它是一个太大的项目,无法显示编译工作程序所需的所有内容,但这是一个从我的ShaderEngine中生成的可渲染对象的示例。

<强> Image2d.h

class Image2d : public VisualMko {
private:
    TextureInfo m_textureInfo;

    // --- Only For Version 1.0 ---
    // VBO                       //
    unsigned m_vboTexture;       //
    unsigned m_vboPosition;      //
    unsigned m_vboIndices;       //
    //                           //
    // VAO                       //
    unsigned m_vao;              //
    // ------------------------- //

    // version 2.0 variables below
    glm::vec2   m_offsetPosition;

public:
    Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId );
    Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId = std::string() );
    virtual ~Image2d();

    void    setOffsetPosition( const glm::vec2& offset );

    virtual void clearTextureInfos() override;

    void render() override;

    TextureInfo getTextureInfo() const;
    void        setTextureInfo( const TextureInfo& textureInfo );

private:
    Image2d( const Image2d& c ); // Not Implemented
    Image2d& operator=( const Image2d& c );

}; // Image2d    

} // namespace vmk

#endif // IMAGE2D_H

<强> Image2d.cpp

#include "stdafx.h"
#include "Image2d.h"

#include "AssetStorage.h"
#include "ShaderManager.h" // Only Needed For Version 1.0
#include "TextureFileReader.h"

namespace vmk {

// ----------------------------------------------------------------------------
// Image2d()
// Creates A Rectangular 2D Imgae Of The Size Specified And Stores It In A
// Vertex Array Object For Rendering. The Surface Verts Are Defined Like:
//        width
//      <------->
//      v0 --- v2  ^
//      :    /  :  | height
//      :  /    :  |
//      v1 --- v3  v
//
Image2d::Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( glm::uvec2(), strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
    if ( fWidth <= 0 || fHeight <= 0 ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Invalid image size (" << fWidth << "," << fHeight << ") must be more then 0 in each dimension.";
        throw ExceptionHandler( strStream );
    }

    // Save TextureID
    TextureFileReader textureFileReader( strTextureFilename );
    m_textureInfo = textureFileReader.getOrCreateTextureInfo( filterQuality, generateMipMap, false );

    // Define Texture Coordinates
    std::vector<float> vTextureCoordinates;
    vTextureCoordinates.push_back( 0.0f );
    vTextureCoordinates.push_back( 1.0f );

    vTextureCoordinates.push_back( 0.0f );
    vTextureCoordinates.push_back( 0.0f );

    vTextureCoordinates.push_back( 1.0f );
    vTextureCoordinates.push_back( 1.0f );

    vTextureCoordinates.push_back( 1.0f );
    vTextureCoordinates.push_back( 0.0f );

    // Define Vertex Positions (x,y,z)
    std::vector<float> vVertexPositions;
    vVertexPositions.push_back( 0.0f );
    vVertexPositions.push_back( fHeight );
    vVertexPositions.push_back( 0.0f );

    vVertexPositions.push_back( 0.0f );
    vVertexPositions.push_back( 0.0f );
    vVertexPositions.push_back( 0.0f );

    vVertexPositions.push_back( fWidth );
    vVertexPositions.push_back( fHeight );
    vVertexPositions.push_back( 0.0f );

    vVertexPositions.push_back( fWidth );
    vVertexPositions.push_back( 0.0f );
    vVertexPositions.push_back( 0.0f );

    // Define 2 Triangle Faces
    std::vector<unsigned char> vIndices;
    vIndices.push_back( 0 );
    vIndices.push_back( 1 );
    vIndices.push_back( 2 );
    vIndices.push_back( 3 );

    // Create Vertex Array Object
    glGenVertexArrays( 1, &m_vao );
    glBindVertexArray( m_vao ); // Start Array

    m_pShaderManager->setAttribute( A_COLOR, COLOR_WHITE );

    // Create Position Buffer And Store On Video Card
    glGenBuffers( 1, &m_vboPosition );
    glBindBuffer( GL_ARRAY_BUFFER, m_vboPosition );
    glBufferData( GL_ARRAY_BUFFER, vVertexPositions.size() * sizeof( vVertexPositions[0] ), &vVertexPositions[0], GL_STATIC_DRAW );
    m_pShaderManager->enableAttribute( A_POSITION );

    // Create Texture Coordinate Buffer
    glGenBuffers( 1, &m_vboTexture );
    glBindBuffer( GL_ARRAY_BUFFER, m_vboTexture );
    glBufferData( GL_ARRAY_BUFFER, vTextureCoordinates.size() * sizeof( vTextureCoordinates[0] ), &vTextureCoordinates[0], GL_STATIC_DRAW );
    m_pShaderManager->enableAttribute( A_TEXTURE_COORD0 );

    // Create Index Buffer
    glGenBuffers( 1, &m_vboIndices );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_vboIndices );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, vIndices.size() * sizeof( vIndices[0] ), &vIndices[0], GL_STATIC_DRAW );

    glBindVertexArray( 0 ); // Stop Array

    // Disable Attribute Pointers
    m_pShaderManager->disableAttribute( A_POSITION );
    m_pShaderManager->disableAttribute( A_TEXTURE_COORD0 );

    // THIS MUST BE AFTER: Vertex Array Buffer Is Unbound!
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); // Stop Buffer Index
    glBindBuffer( GL_ARRAY_BUFFER, 0 ); // Stop Buffer

} // Image2d - v1.0

// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( size, strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
    m_version = 2;

    TextureFileReader textureFileReader( strTextureFilename );
    m_textureInfo = textureFileReader.getOrCreateTextureInfo( TextureInfo::FILTER_NONE, false, false );
    m_config.uTextureId = m_textureInfo.uTextureId;

    if ( 0 == m_textureInfo.size.x || 0 == m_textureInfo.size.y ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " size of " << strTextureFilename << " is invalid " << m_textureInfo.size;
        throw ExceptionHandler( strStream );
    }

    // Verify Image Fits Inside Texture
    if ( m_textureInfo.size.x < size.x + origin.x || m_textureInfo.size.y < size.y + origin.y ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " " << strTextureFilename << " size is " << m_textureInfo.size
            << " which is too small for an image that is " << size
            << " pixels in size, with an origin point set at " << origin ;
        throw ExceptionHandler( strStream );
    }

    glm::vec2 textureCoordScaleFactor( 1.0f / static_cast<float>( m_textureInfo.size.x ),
        1.0f / static_cast<float>( m_textureInfo.size.y ) );

    glm::vec2 texCoordBottomLeft = glm::vec2( textureCoordScaleFactor.x * origin.x,
                                              textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y - size.y ) );
    glm::vec2 texCoordTopRight   = glm::vec2( textureCoordScaleFactor.x * ( origin.x + size.x ),
                                              textureCoordScaleFactor.y * (m_textureInfo.size.y - origin.y ) );

    // Set Colors And Texture Coordinates (Position Will Be Updated In Render Function
    m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordBottomLeft.x, texCoordTopRight.y ) ) );
    m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordBottomLeft.x, texCoordBottomLeft.y ) ) );
    m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordTopRight.x,   texCoordTopRight.y ) ) );
    m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordTopRight.x,   texCoordBottomLeft.y ) ) );

} // Image2d() - v2.0

// ----------------------------------------------------------------------------
// ~Image2d()
Image2d::~Image2d() {
    if ( 1 == m_version ) {
        // Destroy Objects
        if ( m_vboTexture != 0 ) {
            glBindBuffer( GL_ARRAY_BUFFER, 0 );
            glDeleteBuffers( 1, &m_vboTexture );
            m_vboTexture = 0;
        }
        if ( m_vboPosition != 0 ) {
            glBindBuffer( GL_ARRAY_BUFFER, 0 );
            glDeleteBuffers( 1, &m_vboPosition );
            m_vboPosition = 0;
        }
        if ( m_vboIndices != 0 ) {
            glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
            glDeleteBuffers( 1, &m_vboIndices );
            m_vboIndices = 0;
        }
        if ( m_vao != 0 ) {
            glBindVertexArray( 0 );
            glDeleteVertexArrays( 1, &m_vao );
            m_vao = 0;
        }
    }
} // Image2d

// ----------------------------------------------------------------------------
// setOffsetPosition()
void Image2d::setOffsetPosition( const glm::vec2& offset ) {
    if ( offset.x != m_offsetPosition.x || offset.y != m_offsetPosition.y ) {
        m_offsetPosition = offset;
        m_transformMatrix.updateTranslation = true;
    }
} // setOffsetPosition

// ----------------------------------------------------------------------------
// clearTextureInfos()
void Image2d::clearTextureInfos() {
    if ( m_pAssetStorage->removeTextureInfo( m_textureInfo.uTextureId ) ) {
        m_textureInfo = TextureInfo();
    }
} // clearTextureInfos

// ----------------------------------------------------------------------------
// render()
void Image2d::render() {
    if ( 1 == m_version ) {
        m_pShaderManager->setTexture( 0, U_TEXTURE0_SAMPLER_2D, m_textureInfo.uTextureId );

        glBindVertexArray( m_vao );
        glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr );
        glBindVertexArray( 0 );
    } else {
        // Version 2.0
        // Update Vertices
        if ( m_transformMatrix.updateTranslation || m_transformMatrix.updateScale || m_transformMatrix.updateRotation ) {
            m_transformMatrix.updateTranslation = m_transformMatrix.updateScale = m_transformMatrix.updateRotation = false;

            // Order Of Operations Matter Here!
            glm::mat4 matrix; // identity

            if ( m_transformMatrix.hasTranslation ) {
                matrix[3][0] = m_transformMatrix.translation.x;
                matrix[3][1] = m_transformMatrix.translation.y;
            }

            if ( m_transformMatrix.hasRotation ) {
                matrix = glm::rotate( matrix, m_transformMatrix.fRotationAngleDegrees, glm::vec3( 0.0f, 0.0f, -1.0f ) );
            }

            if ( m_transformMatrix.hasScale ) {
                matrix = matrix * glm::mat4( m_transformMatrix.scale.x,                       0.0f, 0.0f, 0.0f,
                                                                   0.0f, m_transformMatrix.scale.y, 0.0f, 0.0f,
                                                                   0.0f,                      0.0f, 1.0f, 0.0f,
                                                                   0.0f,                      0.0f, 0.0f, 1.0f );
            }

            // Center Offset
            if ( m_offsetPosition.x != 0 || m_offsetPosition.y != 0 ) {
                matrix = glm::translate( matrix, glm::vec3( -m_offsetPosition.x, -m_offsetPosition.y, 0.0f ) );
            }

            // Apply Transformation To All 4 Vertices
            m_vVertices[0].position = glm::vec2( matrix * glm::vec4(        0,        0, 0, 1.0f ) );
            m_vVertices[1].position = glm::vec2( matrix * glm::vec4(        0, m_size.y, 0, 1.0f ) );
            m_vVertices[2].position = glm::vec2( matrix * glm::vec4( m_size.x,        0, 0, 1.0f ) );
            m_vVertices[3].position = glm::vec2( matrix * glm::vec4( m_size.x, m_size.y, 0, 1.0f ) );
        }
        renderBatch();
    }
} // render

// ----------------------------------------------------------------------------
// getTextureInfos()
TextureInfo Image2d::getTextureInfo() const {
    return m_textureInfo;
} // getTextureInfo

// ----------------------------------------------------------------------------
// setTextureInfo()
void Image2d::setTextureInfo( const TextureInfo& textureInfo ) {
    m_textureInfo = textureInfo;
} // setTextureInfo

} // namespace vmk

现在这个类有两个构造函数,它们将根据正在使用的Image2d版本进行调用。如果我没记错的话,版本1在版本2的情况下不使用BatchManager或Batch Process。如果你看第一个构造函数。调用glBindVertexArray( 0 );glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); glBindBuffer( GL_ARRAY_BUFFER, 0 );方法来停止数组和缓冲区。在再次调用if语句的第一部分中,我们调用glBindVertexArray( 0 );来停止数组。

如果你看一下析构函数版本2没有得到清理,因为它是通过BatchManager使用的,而且通过BatchManager使用的所有内容都会被我的AssetStorage类自动清理和处理。但是,由于此类的第1版不使用BatchManager,因此它必须自行清理,您可以看到对glBindBuffer( BUFFER_ENUMERATED_TYPE, 0 );的调用,然后调用glDeleteBuffers(...);,然后将VBO和VAO设置为0。 / p>

如果您想了解更多有关此内容以及如何使用现代OpenGL成功构建3D Graphics ShaderEngine,请访问http://www.marekknows.com,这是我学习如何成功使用OpenGL的地方。这些作品不是我自己设计的,但是这个引擎中的所有东西都是按照Marek的视频教程手动输入和调试的。