无法在OpenGL上使用不同的VAO渲染不同的网格物体

时间:2018-08-13 17:18:34

标签: c++ c++11 opengl opengl-3

出于某些奇怪的原因,我似乎无法渲染不同的生成网格。我有一个为每个实例生成适当的缓冲区和值的类。类的想法是让我生成基元。我分别向BoxGeometry和SphereGeometry添加此类的成员。如果仅渲染1种类型,就没有问题,但是如果渲染两种不同的类型,则它仅渲染1种基本类型,并且错误地呈现。

这是基本几何图形生成器:

#pragma once

// GLAD
#include <vector>
#include <glad/glad.h>
#include <cstddef>
#include <cstdint>

class GeometryGenerator {

public:
    GeometryGenerator() : buffer(64), ibuffer(192) {
        buffer.clear();
        ibuffer.clear();
        generated = false;
    }

    void emitVertex() {
        buffer.push_back(currentVertex);
    }

    void emitTriangle() {
        ibuffer.push_back(currentTriangle[0]);
        ibuffer.push_back(currentTriangle[1]);
        ibuffer.push_back(currentTriangle[2]);
    }

    void declareVertexPosition(float x, float y, float z) {
        currentVertex.position[0] = x;
        currentVertex.position[1] = y;
        currentVertex.position[2] = z;
    }

    void declareVertexNormal(float x, float y, float z) {
        currentVertex.normal[0] = x;
        currentVertex.normal[1] = y;
        currentVertex.normal[2] = z;
    }

    void declareTriangle(std::uint32_t x, std::uint32_t y, std::uint32_t z) {
        currentTriangle[0] = x;
        currentTriangle[1] = y;
        currentTriangle[2] = z;
        emitTriangle();
    }

    void generate() {
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glGenBuffers(1, &EBO);

        glBindVertexArray(VAO);

        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * buffer.size(), buffer.data(),
                     GL_STATIC_DRAW);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(std::uint32_t) * ibuffer.size(), ibuffer.data(),
                     GL_STATIC_DRAW);

        // position attribute
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);

        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
                              (void*)offsetof(Vertex, normal));

        glBindVertexArray(0);
        generated = true;
    }

    void draw() {
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, ibuffer.size(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
    }

private:
    struct alignas(1) Vertex {
        float position[3];
        float normal[3];
    };

    Vertex currentVertex;
    std::uint32_t currentTriangle[3];
    std::vector<struct Vertex> buffer;
    std::vector<std::uint32_t> ibuffer;
    bool generated;
    unsigned int VAO, VBO, EBO;
};

这是我的BoxClass:     #pragma一次

#include <memory>
#include "GeometryGenerator.h"
#include "shader.h"
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/string_cast.hpp>
#include "Light.h"

class BoxGeometry {
public:
    static BoxGeometry& getInstance() {
        static BoxGeometry instance;
        return instance;
    }

    void render(const glm::mat4& projection, const glm::mat4& view, const Light& light,
                const Kepler3D::Matrix44& modelMatrix, const Kepler3D::Matrix44& shapeMatrix,
                float length, float width, float height, const glm::vec4& baseColor) {
        glm::mat4 mv;
        std::memcpy(glm::value_ptr(mv), &modelMatrix, sizeof(float)*4*4);
        glm::mat4 sv;
        std::memcpy(glm::value_ptr(sv), &shapeMatrix, sizeof(float)*4*4);
        mainShader->setFloat("boxLength", length);
        mainShader->setFloat("boxWidth", width);
        mainShader->setFloat("boxHeight", height);
        mainShader->setVec3("light.direction", light.direction);
        mainShader->setVec3("light.ambient", light.ambient);
        mainShader->setVec3("light.diffuse", light.diffuse);
        mainShader->setVec3("light.specular", light.specular);
        mainShader->setMat4("ProjectionMatrix", projection);
        mainShader->setMat4("ViewMatrix", view);
        mainShader->setMat4("ModelMatrix", glm::transpose(mv));
        mainShader->setMat4("ShapeMatrix", glm::transpose(sv));
        mainShader->setVec4("baseColor", baseColor);
        mainShader->use();
        geometry.draw();
    }

    BoxGeometry(BoxGeometry const&) = delete;
    void operator=(BoxGeometry const&) = delete;

private:
    void generateGeometry() {
        geometry.declareVertexPosition(0.5f, 0.5f, 0.5f);
        geometry.declareVertexNormal(0.0f, 1.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(0.5f, 0.5f, -0.5f);
        geometry.declareVertexNormal(0.0f, 1.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, 0.5f, -0.5f);
        geometry.declareVertexNormal(0.0f, 1.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, 0.5f, 0.5f);
        geometry.declareVertexNormal(0.0f, 1.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareTriangle(0, 1, 2);
        geometry.declareTriangle(2, 3, 0);

        // bottom

        geometry.declareVertexPosition(0.5f, -0.5f, 0.5f);
        geometry.declareVertexNormal(0.0f, -1.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(0.5f, -0.5f, -0.5f);
        geometry.declareVertexNormal(0.0f, -1.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, -0.5f, -0.5f);
        geometry.declareVertexNormal(0.0f, -1.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, -0.5f, 0.5f);
        geometry.declareVertexNormal(0.0f, -1.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareTriangle(4, 5, 6);
        geometry.declareTriangle(6, 7, 4);

        //left

        geometry.declareVertexPosition(0.5f, -0.5f, 0.5f);
        geometry.declareVertexNormal(1.0f, 0.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(0.5f, -0.5f, -0.5f);
        geometry.declareVertexNormal(1.0f, 0.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(0.5f, 0.5f, -0.5f);
        geometry.declareVertexNormal(1.0f, 0.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(0.5f, 0.5f, 0.5f);
        geometry.declareVertexNormal(1.0f, 0.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareTriangle(8, 9, 10);
        geometry.declareTriangle(10, 11, 8);

        //Right

        geometry.declareVertexPosition(-0.5f, -0.5f, 0.5f);
        geometry.declareVertexNormal(-1.0f, 0.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, -0.5f, -0.5f);
        geometry.declareVertexNormal(-1.0f, 0.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, 0.5f, -0.5f);
        geometry.declareVertexNormal(-1.0f, 0.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, 0.5f, 0.5f);
        geometry.declareVertexNormal(-1.0f, 0.0f, 0.0f);
        geometry.emitVertex();

        geometry.declareTriangle(12, 13, 14);
        geometry.declareTriangle(14, 15, 12);

        //Front

        geometry.declareVertexPosition(0.5f, -0.5f, 0.5f);
        geometry.declareVertexNormal(0.0f, 0.0f, 1.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, -0.5f, 0.5f);
        geometry.declareVertexNormal(0.0f, 0.0f, 1.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, 0.5f, 0.5f);
        geometry.declareVertexNormal(0.0f, 0.0f, 1.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(0.5f, 0.5f, 0.5f);
        geometry.declareVertexNormal(0.0f, 0.0f, 1.0f);
        geometry.emitVertex();

        geometry.declareTriangle(16, 17, 18);
        geometry.declareTriangle(18, 19, 16);

        //Back

        geometry.declareVertexPosition(0.5f, -0.5f, -0.5f);
        geometry.declareVertexNormal(0.0f, 0.0f, 1.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, -0.5f, -0.5f);
        geometry.declareVertexNormal(0.0f, 0.0f, 1.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(-0.5f, 0.5f, -0.5f);
        geometry.declareVertexNormal(0.0f, 0.0f, 1.0f);
        geometry.emitVertex();

        geometry.declareVertexPosition(0.5f, 0.5f, -0.5f);
        geometry.declareVertexNormal(0.0f, 0.0f, 1.0f);
        geometry.emitVertex();

        geometry.declareTriangle(20, 21, 22);
        geometry.declareTriangle(22, 23, 20);

        geometry.generate();
    }
    void initShader() {
        mainShader = std::make_unique<Shader>("shaders/VSBox.glsl", "shaders/PSPhong.glsl");
    }
    BoxGeometry() : geometry() {
        generateGeometry();
        initShader();
    }
    std::unique_ptr<Shader> mainShader;
    GeometryGenerator geometry;
};

和sphere类:     #pragma一次

#include <memory>
#include "GeometryGenerator.h"
#include "shader.h"
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/string_cast.hpp>
#include "Light.h"
#include <math.h>

class SphereGeometry {
public:
    static SphereGeometry& getInstance() {
        static SphereGeometry instance;
        return instance;
    }

    void render(const glm::mat4& projection, const glm::mat4& view, const Light& light,
                const Kepler3D::Matrix44& modelMatrix, const Kepler3D::Matrix44& shapeMatrix,
                float radius, const glm::vec4& baseColor) {
        glm::mat4 mv;
        std::memcpy(glm::value_ptr(mv), &modelMatrix, sizeof(float)*4*4);
        glm::mat4 sv;
        std::memcpy(glm::value_ptr(sv), &shapeMatrix, sizeof(float)*4*4);
        mainShader->setFloat("radius", radius);
        mainShader->setVec3("light.direction", light.direction);
        mainShader->setVec3("light.ambient", light.ambient);
        mainShader->setVec3("light.diffuse", light.diffuse);
        mainShader->setVec3("light.specular", light.specular);
        mainShader->setMat4("ProjectionMatrix", projection);
        mainShader->setMat4("ViewMatrix", view);
        mainShader->setMat4("ModelMatrix", glm::transpose(mv));
        mainShader->setMat4("ShapeMatrix", glm::transpose(sv));
        mainShader->setVec4("baseColor", baseColor);
        mainShader->use();
        geometry.draw();
    }

    SphereGeometry(SphereGeometry const&) = delete;
    void operator=(SphereGeometry const&) = delete;

private:
    void generateGeometry() {
        glm::vec3 top(0.0f, 0.5f, 0.0f);
        glm::vec3 bottom(0.0f, -0.5f, 0.0f);
        float radius = 0.5f;
        float angleA = 0.f;
        const float pi = 3.14159265f;
        float angleB = pi * 0.5f;
        unsigned int sides = 16;
        unsigned int laterals = 16;
        float advanceX = 2.f*pi / sides;
        float advanceY = pi / laterals;

        unsigned int faceIndex = 0;

        angleB -= advanceY;
        laterals--;
        // Top
        for (unsigned int i = 0; i < sides; i++) {
            geometry.declareVertexPosition(top.x, top.y, top.z);
            geometry.declareVertexNormal(0.0f, 1.0f, 0.0f);
            geometry.emitVertex();

            geometry.declareVertexPosition(cos(angleA)*cos(angleB)*radius, sin(angleB)*radius, sin(angleA)*cos(angleB)*radius);
            geometry.declareVertexNormal(cos(angleA)*cos(angleB), sin(angleB), sin(angleA)*cos(angleB));
            geometry.emitVertex();

            angleA += advanceX;

            geometry.declareVertexPosition(cos(angleA)*cos(angleB)*radius, sin(angleB)*radius, sin(angleA)*cos(angleB)*radius);
            geometry.declareVertexNormal(cos(angleA)*cos(angleB), sin(angleB), sin(angleA)*cos(angleB));
            geometry.emitVertex();

            geometry.declareTriangle(faceIndex, faceIndex+1, faceIndex+2);
            faceIndex += 3;
        }

        for(; laterals > 1; laterals--) {
            float cachedB = angleB;
            angleB -= advanceY;
            angleA = 0.f;
            for (unsigned int i = 0; i < sides; i++) {

                geometry.declareVertexPosition(cos(angleA)*cos(cachedB)*radius, sin(cachedB)*radius, sin(angleA)*cos(cachedB)*radius);
                geometry.declareVertexNormal(cos(angleA)*cos(cachedB), sin(cachedB), sin(angleA)*cos(cachedB));
                geometry.emitVertex();

                geometry.declareVertexPosition(cos(angleA)*cos(angleB)*radius, sin(angleB)*radius, sin(angleA)*cos(angleB)*radius);
                geometry.declareVertexNormal(cos(angleA)*cos(angleB), sin(angleB), sin(angleA)*cos(angleB));
                geometry.emitVertex();

                angleA += advanceX;

                geometry.declareVertexPosition(cos(angleA)*cos(cachedB)*radius, sin(cachedB)*radius, sin(angleA)*cos(cachedB)*radius);
                geometry.declareVertexNormal(cos(angleA)*cos(cachedB), sin(cachedB), sin(angleA)*cos(cachedB));
                geometry.emitVertex();

                geometry.declareVertexPosition(cos(angleA)*cos(angleB)*radius, sin(angleB)*radius, sin(angleA)*cos(angleB)*radius);
                geometry.declareVertexNormal(cos(angleA)*cos(angleB), sin(angleB), sin(angleA)*cos(angleB));
                geometry.emitVertex();

                geometry.declareTriangle(faceIndex, faceIndex+1, faceIndex+2);
                geometry.declareTriangle(faceIndex+1, faceIndex+3, faceIndex+2);
                faceIndex += 4;
            }
        }

        angleA = 0.f;
        // Bottom
        for (unsigned int i = 0; i < sides; i++) {

            geometry.declareVertexPosition(cos(angleA)*cos(angleB)*radius, sin(angleB)*radius, sin(angleA)*cos(angleB)*radius);
            geometry.declareVertexNormal(cos(angleA)*cos(angleB), sin(angleB), sin(angleA)*cos(angleB));
            geometry.emitVertex();

            angleA += advanceX;

            geometry.declareVertexPosition(cos(angleA)*cos(angleB)*radius, sin(angleB)*radius, sin(angleA)*cos(angleB)*radius);
            geometry.declareVertexNormal(cos(angleA)*cos(angleB), sin(angleB), sin(angleA)*cos(angleB));
            geometry.emitVertex();

            geometry.declareVertexPosition(bottom.x, bottom.y, bottom.z);
            geometry.declareVertexNormal(0.0f, -1.0f, 0.0f);
            geometry.emitVertex();

            geometry.declareTriangle(faceIndex, faceIndex+2, faceIndex+1);
            faceIndex += 3;
        }

        geometry.generate();
    }
    void initShader() {
        mainShader = std::make_unique<Shader>("shaders/VSSphere.glsl", "shaders/PSPhong.glsl");
    }
    SphereGeometry() : geometry() {
        generateGeometry();
        initShader();
    }
    std::unique_ptr<Shader> mainShader;
    GeometryGenerator geometry;
};

现在,我不确定我是否忘记正确设置某些内容,但是从理论上讲,我应该能够毫无问题地呈现每个基元的实例,但是VAO似乎存在问题。我正在使用OpenGL 3.3,glfw,glm和我尝试测试的物理引擎。我不是ogl的业余爱好者,对此我感到有些惊讶,但是我一无是处编写了这段代码,所以我不确定自己忘记了什么。

编辑: 图片: Album of images showing different instances

我检查了一下,没有内存损坏问题,这似乎表明ogl有问题。

1 个答案:

答案 0 :(得分:2)

我看不到所有代码,但这对我来说可疑:

mainShader->setFloat("boxLength", length);
mainShader->...;
mainShader->use();

在不同的着色器程序中,统一的位置并不是唯一的。如果setFloat只是glUniform1f或类似名称的包装,而useglUseProgram,则意味着代码在错误的程序上设置了统一的样式!

  

glUniform —为当前程序对象指定一个统一变量的值

这是OpenGL有状态API困扰您的另一种情况,这种问题是通过直接状态访问,其他各种无绑定功能以及更新的API(如Vulkan)解决的。

便捷解决方案

只需将use放在顶部:

mainShader->use();
mainShader->setFloat("boxLength", length);
mainShader->...;

替代解决方案

如果可以选择OpenGL 4.1,则您的glProgramUniform操作不受当前绑定程序的影响。这来自GL_ARB_separate_shader_objects扩展名。

调试和检测问题

您可能未使用KHR_debug或未致电glGetError。错误的统一访问应该会产生INVALID_OPERATION错误。看到这些错误的最佳方法是创建调试上下文并启用KHR_debug扩展名。这需要实施一些工作,并且不能在所有地方都可以使用(嗯,它不能在macOS上运行,对于猜对了的人来说没有任何奖励),但是它确实为您节省了很多调试时间。