繁体   English   中英

OpenGL VBO绘图问题

[英]OpenGL VBO drawing problems

我正在制作的粒子引擎目前有问题。 使用引擎,您可以在引擎中添加多个发射器,其思想是每个粒子系统都可以发射自己的粒子。

但是,我遇到的问题是,当我添加第二个粒子系统时,第一个粒子系统似乎受到影响,这意味着它根本没有被绘制。 正确调用了每个粒子系统的绘制调用。

我想的问题是,尽管创建了多个VBO,但实际上只使用了一个。

我将展示影响VBO的功能的重要部分。 我的着色器使用统一的位置存储WVP矩阵。 我还应该提到每个粒子系统都应使用其自己的着色器程序。

这是我在创建粒子系统时调用的initializeBuffers函数:

void ParticleSystem::InitializeBuffers()
{
    glGenVertexArrays(1, &VaoId);   
    glBindVertexArray(VaoId);

    //glGenBuffers(1, &VboId);
    glGenBuffers(1, &PositionBufferId);
    glGenBuffers(1, &IndexBufferId);
    glGenBuffers(1, &WVPId);

    std::list<Particle>::iterator iterator = particles.begin();
    //positions.reserve(5);

    for (std::list<Particle>::iterator iterator = particles.begin(), end = particles.end(); iterator != end; ++iterator) 
    {
        positions.push_back(iterator->GetPosition());
        //verticesToDraw.insert(verticesToDraw.end(), iterator->GetVertices()->begin(), iterator->GetVertices()->end());
        indicesToDraw.insert(indicesToDraw.end(), iterator->GetIndices()->begin(), iterator->GetIndices()->end());
    }


    //glBindBuffer(GL_ARRAY_BUFFER, VboId);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indicesToDraw[0]) * indicesToDraw.size(), &indicesToDraw[0], GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, WVPId);

    for (unsigned int i = 0; i < 4 ; i++) {
        glEnableVertexAttribArray(WVP_LOCATION + i);
        glVertexAttribPointer(WVP_LOCATION + i, 4, GL_FLOAT, GL_FALSE, sizeof(Matrix4f), (const GLvoid*)(sizeof(GLfloat) * i * 4));
        glVertexAttribDivisor(WVP_LOCATION + i, 1);
    }

    for(std::list<BaseBuildingBlock*>::iterator iterator =  buildingBlocks.begin(), end = buildingBlocks.end(); iterator != end; ++iterator)
    {
        (*iterator)->InitializeBuffer(programId);
    }

    /*
    glBindBuffer(GL_ARRAY_BUFFER, WorldId);

    for (unsigned int i = 0; i < 4 ; i++) {
    glEnableVertexAttribArray(WORLD_LOCATION + i);
    glVertexAttribPointer(WORLD_LOCATION + i, 4, GL_FLOAT, GL_FALSE, sizeof(Matrix4f), (const GLvoid*)(sizeof(GLfloat) * i * 4));
    glVertexAttribDivisor(WORLD_LOCATION + i, 1);
    }
    */
    //return GLCheckError();
}

这是绘制函数,是实际绘制实例元素的代码,wvp矩阵由该函数中较早的粒子系统形成。

void ParticleSystem::Draw(Matrix4f perspectiveCameraMatrix)
{
    // scale TEST
    //GLint gScaleLocation = glGetUniformLocation(program, "gScale");
    //assert(gScaleLocation != 0xFFFFFFFF);
    //glUniform1f(gScaleLocation, scale);

    //Pipeline p;
    //Matrix4f* WVPMatrices = new Matrix4f[particles.size()];
    //Matrix4f* WorldMatrices = new Matrix4f[particles.size()];

    WVPMatrices.clear(); 
    WorldMatrices.clear(); 

    glUseProgram(0);

    glUseProgram(programId);

    //Matrix4f perspectiveMatrix;
    //perspectiveMatrix.BuildPerspProjMat(90,1, 0.01, 200, 100 - 0 /*getWidth() / 32*/, 100 - 0  /*getHeight() / 32*/);


    //********************************************************************************************************
    // Method 1

    // Think I need to next define a camera position.

    if(particles.size() == 0)
    {
        return;
    }

    verticesToDraw.clear();


    Matrix4f scaleMatrix;
    Matrix4f worldMatrix;
    Matrix4f rotateMatrix;
    Matrix4f finalMatrix;

    //ColourId = glGetUniformLocation(programId, "UniformColour");


    int i = 0;



    for (std::list<Particle>::iterator iterator = particles.begin(), end = particles.end(); iterator != end; ++iterator) 
    {

        verticesToDraw = *iterator->GetVertices();
        indicesToDraw = *iterator->GetIndices();
        //positions.push_back(iterator->GetPosition());
        worldMatrix.InitTranslationTransform(iterator->GetPosition().x, iterator->GetPosition().y, iterator->GetPosition().z);
        rotateMatrix.InitRotateTransform(iterator->GetRotation().x, iterator->GetRotation().y, iterator->GetRotation().z);
        scaleMatrix.InitScaleTransform(iterator->GetScale().x, iterator->GetScale().y, iterator->GetScale().z);
        finalMatrix = perspectiveCameraMatrix * worldMatrix * rotateMatrix * scaleMatrix;
        //p.WorldPos(iterator->GetPosition());
        //p.Rotate(iterator->GetRotation());
        WVPMatrices.push_back(finalMatrix.Transpose());

        /*glUniform4f(ColourId, iterator->GetColour().r, iterator->GetColour().g, iterator->GetColour().b,
        iterator->GetColour().a);*/
        //WorldMatrices[i] = p.GetWorldTrans();
        i++;

        //iterator->Draw();
    }


    //glEnableVertexAttribArray(0);

    if(colourOverLifeBuildingBlock != NULL)
    {
        colourOverLifeBuildingBlock->Test();
    }

    glBindBuffer(GL_ARRAY_BUFFER, VboId);
    glBufferData(GL_ARRAY_BUFFER, verticesToDraw.size() * sizeof(verticesToDraw[0]), &verticesToDraw.front(), GL_STATIC_DRAW);
    glEnableVertexAttribArray(POSITION_LOCATION);
    glVertexAttribPointer(POSITION_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0);

    int size = particles.size();

    glBindBuffer(GL_ARRAY_BUFFER, WVPId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Matrix4f) * size, &WVPMatrices.front(), GL_DYNAMIC_DRAW);

    glDrawElementsInstanced(GL_TRIANGLES, indicesToDraw.size(), GL_UNSIGNED_BYTE, 0, particles.size());

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    //glDisableVertexAttribArray(0);
    //glFlush();

}

粒子系统的整个标题如下:

#include <gl\glew.h>
#include <array>
#include <vector>

class ParticleSystem
{

public:
    ParticleSystem(Vector3 pos, Quaternion rot, float spawnRate, int particlesToSpawn); // Constructs a particle system.
    ~ParticleSystem(); // Destructor.
    void Update(float elapsedTime); // Updates the particle system.
    void Draw(Matrix4f perspectiveMatrix); // Draw the particle system
    void CreateShaders();
    void InitializeBuffers();

    // Long amount of get sets.
    /*float* GetMinLifeTime();
    void SetMinLifeTime(float lt);
    float* GetMaxLifeTime();
    void SetMaxLifeTime(float lt);*/
    int* GetParticlesToSpawnAtATime();
    void SetParticlesToSpawnAtATime(int particlesToSpawn);
    float* GetSpawnRate();
    void SetSpawnRate(float spawnRate);
    Vector3* GetPosition();
    void SetPosition(Vector3 newPosition);
    Quaternion* GetRotation();
    void SetRotation(Quaternion rotation);
    std::list<BaseBuildingBlock*> GetBuildingBlocks();

    VelocityBuildingBlock* GetVelocityBuilding();
    ColourOverLifeBuildingBlock* GetColourOverLifeBuildingBlock();
    LifeTimeBuildingBlock* GetLifeTimeBuildingBlock();
    UniformColourBuildingBlock* GetUniformColourBuildingBlock();
    ScaleBuildingBlock* GetScaleBuildingBlock();
    /*Vector3* GetMinVelocity();
    void SetMinVelocity(Vector3 min);
    Vector3* GetMaxVelocity();
    void SetMaxVelocity(Vector3 maxVelocity);*/
    Vector3 GetMinParticleStartPoint();
    void SetMinParticleStartPoint(Vector3 minParticleStartPoint);
    Vector3 GetMaxParticleStartPoint();
    void SetMaxParticleStartPoint(Vector3 maxParticleStartPoint);
    bool CreateColourOverLifeBuildingBlock();
    bool DeleteColourOverLifeBuildingBlock();
    bool CreateUniformColourBuildingBlock();
    bool DeleteUniformColourBuildingBlock();
    bool CreateScaleBuildingBlock();
    bool DeleteScaleBuildingBlock();


    /*Colour GetStartColour();
    void SetStartColour(Colour startColour);
    Colour GetEndColour();
    void SetEndColour(Colour endColour);*/
    Vector3* GetMinParticleRotationAmountPerFrame();
    void SetMinParticleRotationAmountPerFrame(Vector3 minParticleRotationAmount);
    Vector3* GetMaxParticleRotationAmountPerFrame();
    void SetMaxParticleRotationAmountPerFrame(Vector3 maxParticleRotationAmount);
    void Save(TiXmlElement* element);

private:
    // Spawns a particle.
    void SpawnParticle();

    GLuint VaoId;
    GLuint VboId;
    GLuint IndexBufferId;
    GLuint PositionBufferId;
    GLuint WVPId;
    GLenum programId;

    std::vector<GLfloat> verticesToDraw;
    std::vector<GLubyte> indicesToDraw; 
    std::vector<Vector3> positions;
    std::vector<Matrix4f> WVPMatrices; 
    std::vector<Matrix4f> WorldMatrices; 

    std::list<Particle> particles; // List of particles
    Vector3 position; // position of the emitter
    Quaternion rotation; // rotation of the emitter.
    float spawnRate; // spawnrate of the emitter.
    int particlesToSpawnAtATime; // The amount of particles to spawn at a time.
    float minLifeTime; // The minimum time a particle can live for.
    float maxLifeTime; // The maximum time a particle can live for.
    float timer; // Timer
    ShaderCreator* shaderCreator;

    //Vector3 minVelocity; // The minimum velocity a particle can have.
    //Vector3 maxVelocity; // The maximum velocity a particle can have/



    //std::list<BaseBuildingBlock> buildingBlocks;

    // I'm thinking of eventually making a list of baseBuildingBlocks. 
    std::list<BaseBuildingBlock*> buildingBlocks; 
    VelocityBuildingBlock* velocityBuildingBlock;
    ColourOverLifeBuildingBlock* colourOverLifeBuildingBlock;
    LifeTimeBuildingBlock* lifeTimeBuildingBlock;
    UniformColourBuildingBlock* uniformColourBuildingBlock;
    ScaleBuildingBlock* scaleBuildingBlock;

    Vector3 minParticleStartPoint; // The minimum position a particle can start at.
    Vector3 maxParticleStartPoint; // The maximum position a particle can start at.
    Vector3 minParticleRotationAmountPerFrame; // The minimum amount of rotation that a particle can rotate every frame.
    Vector3 maxParticleRotationAmountPerFrame; // The maximum amount of rotation that a particle can rotate every frame.
    Colour startColour; // StartColour is the colour that a particle will start with.
    Colour endColour; // EndColour is the colour that a particle will end with.

    //TEST
    float scale;

};

#endif

现在我想知道,是否有某种方法必须切换活动的VBO? 还是我完全走错了路。 我使用了着色器调试器,两个VBO都存在。

您需要在每次绘制调用之前正确设置顶点属性-即,您必须在每次绘制调用之前为每个属性调用glBindBuffer,然后调用glEnableVertexArrayglVertexAttribPointer 在您发布的代码中,这仅发生在粒子位置,而不发生在显然包含转换矩阵的“ WVP_LOCATION”属性中(您确实通过glBufferData将数据上传到GPU,但未设置该属性)-这意味着一旦拥有多个粒子系统,就只能访问第二个粒子系统的转换矩阵进行渲染。

一方面,您要在此处执行的操作似乎效率很低-实际上,您是在每帧将每个粒子的一个转换矩阵推入GPU。 根据所需的粒子数量,这会降低性能-您应该考虑使用变换反馈来更新粒子的位置等。

编辑:刚刚意识到opengl wiki链接并没有真正解释很多。 变换反馈是一种记录顶点着色器输出的方法(或者,如果存在几何/细分着色器,则将记录该输出)。 输出变量被写入VBO-之后,它们可以像其他任何顶点属性一样用于渲染。 整个概念与使用帧缓冲区对象记录片段着色器输出极为相似。 它允许完全存在于GPU上的粒子系统,并带有顶点着色器,用于计算每帧中更新的位置,寿命和其他属性。 可以在此处找到一个非常不错的教程,其中显示了此类转换反馈的基本设置。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM