程序特定的OpenGL运行时错误:多个输入缓冲区蒙皮动画
Program Specific OpenGL Runtime Bug: Multiple Input Buffers For Skinned Animation
问题:
似乎第二个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 uint
或in int
等),则需要使用glVertexAttribIPointer
。
glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);
glVertexAttribIPointer(jointIDLoc, 1, GL_UNSIGNED_INT, 0, NULL);
(注意glVertexAttribIPointer
不取规范化参数)
相关文章:
- 清除输入缓冲区后未提取字符串流
- 快速读取标准输入缓冲区,无需检查
- C++ 为什么还剩下输入缓冲区?
- 如果输入缓冲区不为空,请使用getchar.()检测Ctrl+d
- 如果我在 C++ 中为 int 提供双精度,输入缓冲区中存储了什么?
- 如何重复使用原始输入缓冲区内存?
- 从输入缓冲区读取
- 安全操作以清除C++中的空输入缓冲区
- 如何检查输入缓冲区是否为空
- 我可以做一个循环,直到“std::cin”在输入缓冲区中看到“”字符
- 是否可以在键盘输入缓冲区中向前看并在MFC/Win32中检测条形码条目
- fftwf_execute_dft_c2r写入输入缓冲区
- 如何在C 中清除输入缓冲区
- cin.clear() 如何清除输入缓冲区
- C++清除输入缓冲区(最后没有换行符)
- 输入缓冲区错误或其他原因
- Linux 串行端口读取 - 我可以更改输入缓冲区的大小吗?
- 清除输入缓冲区中的所有其他字符
- 如何在获得下一个字符后正确刷新输入缓冲区,而无需按两次回车键!C++
- 清除包括换行符在内的输入缓冲区