程序特定的OpenGL运行时错误:多个输入缓冲区蒙皮动画

Program Specific OpenGL Runtime Bug: Multiple Input Buffers For Skinned Animation

本文关键字:输入 缓冲区 动画 OpenGL 运行时错误 程序      更新时间:2023-10-16

问题:

似乎第二个GLuint缓冲区没有被正确地读入。

Update:所以问题必须是当我尝试输入数据到着色器。我重新编写了代码(旧代码仍在下面),以便对索引参数使用swizzling。这是我唯一能让它工作的方法。我想使用多个glVertexAttribPointer的,但每次我试图给我相同的未定义的结果。

我想做什么:

我正在用一个非常简化的着色器测试非常简单的蒙皮动画,

#version 330 core
in vec2 model;
in uint jointID;
const int MAX_JOINTS = 10;
uniform mat4 joints[MAX_JOINTS];
void main()
{
    gl_Position = joints[jointID] * vec4(model, 0.0f, 1.0f);
}

我输入一些简单的数据,

const GLfloat vertices[] =
{
    // upper arm
    0.0f, 0.0f,
    0.4f, 0.0f,
    0.4f, 0.2f,
    0.0f, 0.0f,
    0.4f, 0.2f,
    0.0f, 0.2f,
    // lower arm
    0.4f, 0.0f,
    0.8f, 0.0f,
    0.8f, 0.2f,
    0.4f, 0.0f,
    0.8f, 0.2f,
    0.4f, 0.2f
};
const GLuint indices[] =
{
    // upper arm
    0,
    1,
    1,
    0,
    1,
    0,
    // lower arm
    1,
    1,
    1,
    1,
    1,
    1
};

(第一个数组包含顶点,第二个数组包含相应的bonid)奇怪的是,boneID似乎从来都不太等于1因为当我让矩阵的下标为1时,这些顶点保持不变。这让我相信,这是一个问题,我设置我的glVertexAttribPointer的方式,

void SkinnedModel::draw()
{
    shaderProgram.use();
    glEnableVertexAttribArray(modelLoc);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexAttribPointer(modelLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(jointIDLoc);
    glBindBuffer(GL_ARRAY_BUFFER, indexBuffer);
    glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);
    glUniformMatrix4fv(jointsLoc, 10, GL_FALSE, (GLfloat*)&poseMatrices);
    glDrawArrays(GL_TRIANGLES, 0, numVertices); 
    glDisableVertexAttribArray(modelLoc);
    glDisableVertexAttribArray(jointIDLoc);
}

在过去的几个小时里,我一直在用头撞桌子,看那些似乎是正确的代码。总之,可能是我漏掉了什么蠢事。如有任何帮助,不胜感激。

以下是所有相关的源代码(以防万一):

SkinnedModel.h

#pragma once
#include "stl/DataTypes.h"
#include "Shader.h"
#include <Dense>
using namespace Eigen;
struct Joint
{
    Joint** children;
    Joint* parent;
    U32 index;
};
class SkinnedModel
{
public:
    static void init();
    static void destroy();
    SkinnedModel();
    ~SkinnedModel();
    void create(const GLfloat* vertices, const GLuint* jointIndices, GLint numVertices, Joint* rootJoint);
    void draw();
    void rotate(Joint* joint, F32 angle, F32 x, F32 y);
    GLuint vertexBuffer;
    GLuint indexBuffer;
    GLint numVertices;
    //GLint numJoints;
    Joint* root;
    Matrix<GLfloat,4,4> poseMatrices[10];
    static ShaderProgram shaderProgram;
    static GLuint modelLoc;
    static GLuint jointIDLoc;
    static GLuint modelViewMatrixLoc;
    static GLuint jointsLoc;
};

SkinnedModel.cpp

#include "SkinnedModel.h"
ShaderProgram SkinnedModel::shaderProgram;
GLuint SkinnedModel::modelLoc = -1;
GLuint SkinnedModel::jointIDLoc = -1;
GLuint SkinnedModel::modelViewMatrixLoc = -1;
GLuint SkinnedModel::jointsLoc = -1;
void SkinnedModel::init()
{
    ShaderProgramSettings shaderPS;
    shaderPS.loadShader("Skinned.v.glsl", ShaderType::VERTEX);
    shaderPS.loadShader("Skinned.f.glsl", ShaderType::FRAGMENT);
    shaderProgram = shaderPS.create();
    shaderProgram.use();
    modelLoc = shaderProgram.getAttrib("model");
    jointIDLoc = shaderProgram.getAttrib("jointID");
    //modelViewMatrixLoc = shaderProgram.getUniform("modelViewMatrix");
    jointsLoc = shaderProgram.getUniform("joints");
}
void SkinnedModel::destroy()
{
    shaderProgram.destroy();
}
SkinnedModel::SkinnedModel()
{
}
SkinnedModel::~SkinnedModel()
{
    glDeleteBuffers(1, &vertexBuffer);
    glDeleteBuffers(1, &indexBuffer);
}
void SkinnedModel::create(const GLfloat* vertices, const GLuint* jointIndices, GLint numVertices, Joint* rootJoint)
{
    this->numVertices = numVertices;
    this->root = rootJoint;
    for(U32 i=0;i<10;++i)
    {
        poseMatrices[i] = Matrix<GLfloat,4,4>::Identity();
    }
    poseMatrices[1] = Matrix<GLfloat,4,4>::Zero(); // <--- This should mess it up!
    // Creating buffers
    glDeleteBuffers(1, &vertexBuffer);
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, numVertices*2*sizeof(GLfloat), vertices, GL_STATIC_DRAW);
    glDeleteBuffers(1, &indexBuffer);
    glGenBuffers(1, &indexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(GLuint), jointIndices, GL_STATIC_DRAW);
}
void SkinnedModel::draw()
{
    shaderProgram.use();
    glEnableVertexAttribArray(modelLoc);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexAttribPointer(modelLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(jointIDLoc);
    glBindBuffer(GL_ARRAY_BUFFER, indexBuffer);
    glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);
    glUniformMatrix4fv(jointsLoc, 10, GL_FALSE, (GLfloat*)&poseMatrices);
    glDrawArrays(GL_TRIANGLES, 0, numVertices); 
    glDisableVertexAttribArray(modelLoc);
    glDisableVertexAttribArray(jointIDLoc);
}
void SkinnedModel::rotate(Joint* joint, F32 angle, F32 x, F32 y)
{
    F32 rcos = cos(angle);
    F32 rsin = sin(angle);
    Matrix<GLfloat, 4, 4> rotMatrix = Matrix<GLfloat, 4, 4>::Identity();
    rotMatrix(0,0) = rcos;
    rotMatrix(0,1) = -rsin;
    rotMatrix(1,0) = rsin;
    rotMatrix(1,1) = rcos;
    rotMatrix(0,3) = x-rcos*x+rsin*y;
    rotMatrix(1,3) = y-rsin*x-rcos*y;
    poseMatrices[joint->index] *= rotMatrix;
}

Game.cpp

void Game::init()
{
    GUI::init();
    SkinnedModel::init();
    getScreen()->setBackgroundColor(1.0f, 1.0f, 1.0f);
    const GLfloat vertices[] =
    {
        // upper arm
        0.0f, 0.0f,
        0.4f, 0.0f,
        0.4f, 0.2f,
        0.0f, 0.0f,
        0.4f, 0.2f,
        0.0f, 0.2f,
        // lower arm
        0.4f, 0.0f,
        0.8f, 0.0f,
        0.8f, 0.2f,
        0.4f, 0.0f,
        0.8f, 0.2f,
        0.4f, 0.2f
    };
    const GLuint indices[] =
    {
        // upper arm
        0,
        1,
        1,
        0,
        1,
        0,
        // lower arm
        1,
        1,
        1,
        1,
        1,
        1
    };

    upperArm.parent = 0;
    upperArm.children = new Joint*[1];
    upperArm.children[0] = &lowerArm;
    upperArm.index = 0;
    lowerArm.parent = &upperArm;
    lowerArm.children = 0;
    lowerArm.index = 1;
    m.create(vertices, indices, 12, &upperArm);
    //m.rotate(&lowerArm, PI/4, 0.4f, 0.1f);
    //DEBUG("SIZE %i", sizeof(Eigen::Matrix<GLfloat,4,4>));
}
void Game::loop(double dt)
{
    m.draw();
}

更新:显然,如果boneID的所有值都设置为1,它永远不会在着色器中使用1 @.@.所以第二个数组甚至没有被读取,或者它没有被正确读取

如果你正在使用整数顶点属性(即你在顶点着色器中声明的in uintin int等),则需要使用glVertexAttribIPointer

代替

glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);

glVertexAttribIPointer(jointIDLoc, 1, GL_UNSIGNED_INT, 0, NULL);

(注意glVertexAttribIPointer不取规范化参数)