2013-09-07 2 views
5

Итак, я могу загрузить базовую модель с вершинами, координатами текстуры и нормалями и сделать ее без проблем.Отправка данных о костях в glsl shader

Однако, когда я пытаюсь бросить какую-то информацию о костях, данные о костях, кажется, повреждаются (или что-то?), Когда я пытаюсь манипулировать им в шейдере.

Вот мой код для загрузки и визуализации данных в 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 ... так как в мире это не так в шейдере?

Кто-нибудь видит что-то очевидное, что мне не хватает?

EDIT: Похоже, я нашел эту проблему - я не звонил glBindAttribLocation на любом из моих in переменных - после добавления:

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"); 

моей шейдер загрузки коды, он отлично работает. Нечеткое дело - мне не приходилось делать это для первых 3 (положение, текстура и цвет), и он работал нормально. Но когда я добавил информацию о костях, мне вдруг это нужно ... почему?

ответ

3

Чтобы предоставить данные атрибуту вершины ivec<N>, необходимо использовать glVertexAttribIPointer (...). Если вы считали, что испытываете «коррупцию» перед установкой местоположений атрибутов, просто подождите, пока вы не напишете код в вашем шейдере, который действительно нуждается в идентификаторах костей ... Эти значения будут бессмысленными, потому что вы используете неправильный вызов API для связывания своего атрибута данные с определенным местом привязки.

Вариант glVertexAttribPointer (...) не имеет проблем с получением типа данных GL_INT, но он собирается преобразовать его в плавающую точку (и он может нормализовать значения фиксированной точки в процессе, следовательно, дополнительный параметр). Таким образом, ожидается, что этот вариант предоставит данные в атрибут вершины vec<N>, а не ivec<N>.

Более кратко, используйте glVertexAttribIPointer для атрибутов целочисленных вершин и glVertexAttribPointer для с плавающей запятой.

+0

Так оно и было - после этого я мог также удалить вызовы 'glBindAttribLocation'. У меня теперь есть анимация! (в какой-то степени, кажется, исчезает в местах, поэтому я думаю, что нормали могут быть испорчены). Спасибо @ Эндон! – Jarrett