将骨骼数据发送到GLSL着色器

5

好的,我能够翻译基础模型的顶点、纹理坐标和法线,并且能够顺利地渲染出来。

然而,当我尝试加入一些骨骼信息时,在着色器中尝试操纵骨骼数据时,骨骼数据似乎被损坏了(或其他什么问题?)。

以下是我的代码,用于将数据加载并渲染到OpenGL中(设置着色器并发送视图矩阵、世界矩阵等操作在另一个类中完成):

/*
 * Mesh.cpp
 *
 *  Created on: 2011-05-08
 *      Author: jarrett
 */

#include <boost/log/trivial.hpp>

#include "../common/utilities/AssImpUtilities.h"

#include "Mesh.h"

namespace glr {
namespace glw {
Mesh::Mesh(IOpenGlDevice* openGlDevice,
        const std::string path, 
        std::vector< glm::vec3 > vertices, 
        std::vector< glm::vec3 > normals,
        std::vector< glm::vec2 > textureCoordinates,
        std::vector< glm::vec4 > colors,
        std::vector<VertexBoneData > bones,
        BoneData boneData)
    : openGlDevice_(openGlDevice), vertices_(vertices), normals_(normals), textureCoordinates_(textureCoordinates), colors_(colors), bones_(bones), boneData_(boneData)
{
    BOOST_LOG_TRIVIAL(debug) << "loading mesh into video memory...";

    // create our vao
    glGenVertexArrays(1, &vaoId_);
    glBindVertexArray(vaoId_);

    // create our vbos
    glGenBuffers(5, &vboIds_[0]);

    glBindBuffer(GL_ARRAY_BUFFER, vboIds_[0]);
    glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(glm::vec3), &vertices_[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vboIds_[1]);
    glBufferData(GL_ARRAY_BUFFER, textureCoordinates_.size() * sizeof(glm::vec2), &textureCoordinates_[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vboIds_[2]);
    glBufferData(GL_ARRAY_BUFFER, normals_.size() * sizeof(glm::vec3), &normals_[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);

    std::cout << "SIZE: " << vertices_.size() << " " << sizeof(glm::ivec4) << " " << bones_.size() << " " << sizeof(VertexBoneData) << std::endl;

    // Convert data into simple vectors, then send to OpenGL
    std::vector< glm::ivec4 > boneIds = std::vector< glm::ivec4 >();
    std::vector< glm::vec4 > weights = std::vector< glm::vec4 >();

    for ( VertexBoneData& d : bones_ )
    {
        boneIds.push_back( d.boneIds );
        weights.push_back( d.weights );
    }

    glBindBuffer(GL_ARRAY_BUFFER, vboIds_[3]);
    glBufferData(GL_ARRAY_BUFFER, boneIds.size() * sizeof(glm::ivec4), &boneIds[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 4, GL_INT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vboIds_[4]);
    glBufferData(GL_ARRAY_BUFFER, weights.size() * sizeof(glm::vec4), &weights[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(4);
    glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 0, 0);

    // Disable our Vertex Array Object
    //glEnableVertexAttribArray(0);
    // Disable our Vertex Buffer Object
    glBindVertexArray(0);

    GlError err = openGlDevice_->getGlError();
    if (err.type != GL_NONE)
    {
        // TODO: throw error
        BOOST_LOG_TRIVIAL(error) << "Error loading mesh in opengl";
        BOOST_LOG_TRIVIAL(error) << "OpenGL error: " << err.name;
    }
    else
    {
        BOOST_LOG_TRIVIAL(debug) << "Successfully loaded mesh.";
    }
}

Mesh::~Mesh()
{
}

void Mesh::render()
{
    glBindVertexArray(vaoId_);

    glDrawArrays(GL_TRIANGLES, 0, vertices_.size());

    glBindVertexArray(0);
}

BoneData& Mesh::getBoneData()
{
    return boneData_;
}
}
}

我实际使用的着色器代码是这样的:

#version 150 core

struct Light {
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    vec4 position;
    vec4 direction;
};


in vec3 in_Position;
in vec2 in_Texture;
in vec3 in_Normal;
in ivec4 in_BoneIds;
in vec4 in_BoneWeights;

out vec2 textureCoord;
out vec3 normalDirection;
out vec3 lightDirection;
out float bug;

layout(std140) uniform Lights 
{
    Light lights[ 1 ];
};

void main() {        
    gl_Position = pvmMatrix * vec4(in_Position, 1.0);

    vec4 lightDirTemp = viewMatrix * lights[0].direction;

    textureCoord = in_Texture;

    //vec4 normalDirTemp = boneTransform * vec4(in_Normal, 1.0);
    //normalDirection = normalize(normalMatrix * normalDirTemp.xyz);
    normalDirection = normalize(normalMatrix * in_Normal);

    lightDirection = normalize(vec3(lightDirTemp));



    // If we have any bugs, should highlight the vertex red or green
    bug = 0.0;
    float sum = in_BoneWeights[0] + in_BoneWeights[1] + in_BoneWeights[2] + in_BoneWeights[3];
    if (sum > 1.5f)
        bug = 1.0;
    else if (sum < 0.95f)
        bug = 2.0;
    // disable bug highlighting
    //bug = 0.0;        
}

如果bug = 1.0,则顶点将被着为红色,如果but = 2.0,则顶点将被着为绿色。我现在看到所有的顶点都是红色的,这意味着sum大于1.5f
我已经确认每组权重的总和实际上小于或等于<= 1.0f...那么在着色器中为什么不是这种情况?
有人发现我漏掉了什么明显的东西吗?
编辑:看起来我找到了问题-我没有在任何一个in变量上调用glBindAttribLocation-在添加之后:
glBindAttribLocation(programId_, 0, "in_Position");
    glBindAttribLocation(programId_, 1, "in_Texture");
    glBindAttribLocation(programId_, 2, "in_Color");
    glBindAttribLocation(programId_, 3, "in_BoneIds");
    glBindAttribLocation(programId_, 4, "in_BoneWeights");

对于我的着色器加载代码,它运行良好。奇怪的是-对于前三个(位置、纹理和颜色),我不需要这样做,它也可以正常工作。但是当我添加骨骼信息时,突然就需要这样做了……为什么呢?

1个回答

3
你需要使用 glVertexAttribIPointer (...) 来提供数据给一个 ivec<N> 顶点属性。如果你认为在设置属性位置之前已经遇到了“损坏”,那么请等待,直到您编写了实际需要骨骼ID的着色器代码...这些值将是毫无意义的,因为您正在使用错误的API调用来将属性数据与特定绑定位置相关联。 glVertexAttribPointer (...) 变量没有问题地接受 GL_INT 数据类型,但它将转换为浮点数(并可能在此过程中规范化定点值,因此有额外的参数)。因此,这个变量应该为 vec<N> 顶点属性提供数据,而不是 ivec<N>
更简洁地说,对于整数顶点属性,请使用 glVertexAttribIPointer,对于浮点型则请使用 glVertexAttribPointer

就是这样 - 在做完这个之后,我可以删除glBindAttribLocation调用。现在我的动画已经可以工作了!(在某种程度上 - 它似乎在某些地方消失了,所以我认为法线可能会出问题)。谢谢@Andon! - Jarrett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接