c++ - 程序特定的 OpenGL 运行时错误 : Multiple Input Buffers For Skinned Animation

标签 c++ opengl animation runtime shader

问题:

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

更新: 所以问题一定出在我尝试将数据输入到着色器时。我重写了代码(旧代码仍在下方)以对 index 参数使用 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
};

(第一个数组包含顶点,第二个数组包含相应的 boneID。)奇怪的是,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);
}

在过去的几个小时里,我一直在用头撞 table ,看看似乎是正确的代码。无论如何,这可能是我错过的愚蠢的事情。感谢您的帮助。

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

蒙皮模型.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;
};

蒙皮模型.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;
}

游戏.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 不采用标准化参数)

关于c++ - 程序特定的 OpenGL 运行时错误 : Multiple Input Buffers For Skinned Animation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22470545/

相关文章:

c++ - 多线程文件读取

c++ - [仅等于运算符]在集合中查找重复元素并将它们分组的快速算法是什么?

java - GL20.glCompileShader 使用 OpenGL 的 Java 程序崩溃

iphone - UIImageView 动画图像无法更改?

python - 在 Python 中缩放和显示图像的最快方法是什么?

javascript - 像电影一样滚动时的页面动画

python - 存储空间数组 SQLite3

c++ - 旋转时立方体未按预期呈现

c# - 将 OpenGL 用于桌面应用程序是否合理?

java - 乔格。 OpenGL。如何更新VBO?