【问题标题】:Can't render different meshes with different VAO on OpenGL无法在 OpenGL 上使用不同的 VAO 渲染不同的网格
【发布时间】:2019-01-20 11:46:10
【问题描述】:

由于某种奇怪的原因,我似乎无法渲染不同的生成网格。我有一个类可以为每个实例生成适当的缓冲区和 vaos。这个类的想法是让我生成原语。我将这个类的一个成员添加到 BoxGeometry 和 SphereGeometry 中。如果我只渲染一种类型,那没有问题,但如果我渲染两种不同的类型,它只会渲染一种原始类型并且不正确。

这是基本几何生成器:

#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的问题。

【问题讨论】:

  • 你有截图吗?您的程序的行为是什么,它与您的期望/期望有何不同?
  • 编辑并添加了显示问题的图片相册。
  • 所有对象都使用相同的着色器吗?但主要问题是,函数背后隐藏了太多代码。例如,哪个着色器方法会调用glUseProgram?我怀疑use 这意味着着色器在 设置unforms 之后被绑定。由于统一设置始终适用于当前着色器,因此您可能将统一设置在错误的着色器中。
  • 你的硬件平台是什么?英特尔?英伟达? AMD ?
  • NVIDIA,毕竟制服像其他人提到的那样被损坏了,而不是真正的驱动问题。

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


【解决方案1】:

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

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

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

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

这是 OpenGL 的有状态 API 困扰您的又一个案例,这种问题可以通过直接状态访问、其他各种无绑定函数以及 Vulkan 等更新的 API 解决。

简单的解决方案

只需将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 上不起作用,猜对的人没有奖品),但它确实为您节省了大量调试时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多