2013-09-07 19 views
5

Ok, więc jestem w stanie wczytać podstawowy model z wierzchołkami, współrzędnymi tekstury i normalnymi i renderować go bez problemu.Wysyłanie danych kostnych do modułu cieniującego glsl

Jednak kiedy próbuję rzucić jakieś informacje o kości, dane kości wydają się być uszkodzone (lub coś?), Kiedy próbuję manipulować nimi w module cieniującym.

Oto mój kod do załadunku i renderowania danych do OpenGL (ustawienie shader i wysyłanie macierz widoku, macierz świata, etc są wykonywane w innej klasie):

/* 
* 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_; 
} 
} 
} 

Mój rzeczywisty shader to:

#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;   
} 

Jeśli bug = 1.0, to wierzchołki są w kolorze czerwonym, a jeśli but = 2.0, to wierzchołki są w kolorze zielonym. Widzę teraz wszystkie wierzchołki w kolorze czerwonym, co oznacza, że ​​sum jest większa niż 1.5f.

Potwierdziłem, że suma każdego zestawu wag jest w rzeczywistości <= 1.0f ... więc jak na świecie nie jest tak w przypadku modułu cieniującego?

Ktoś widzi coś oczywistego, czego mi brakuje?

EDIT: Wygląda na to, że znalazłem problem - ja nie dzwoni glBindAttribLocation na żadnym z moich in zmiennych - po dodaniu:

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

do mojego kodu shader ładunkowej, to działa dobrze. Dziwne jest to - nie musiałem tego robić przez pierwsze 3 (pozycja, tekstura i kolor) i działało dobrze. Ale kiedy dodałem informację o kości, nagle potrzebuję tego ... dlaczego?

Odpowiedz

3

Musisz użyć glVertexAttribIPointer (...), aby przekazać dane do atrybutu wierzchołka ivec<N>. Jeśli uważasz, że doświadczasz "zepsucia" przed ustawieniem lokalizacji atrybutów, po prostu poczekaj, aż napiszesz kod w module cieniującym, który faktycznie potrzebuje identyfikatorów kości ... Te wartości będą bez znaczenia, ponieważ używasz niewłaściwego wywołania API do powiązania atrybutu dane z określoną lokalizacją wiązania.

Wariant glVertexAttribPointer (...) nie ma problemów ze zrobieniem typ GL_INT danych, ale to się dzieje, aby przekształcić go zmiennoprzecinkowych (a może znormalizować wartości stałoprzecinkowych w procesie, stąd dodatkowy parametr). Tak więc ten wariant ma dostarczać dane do atrybutu wierzchołków vec<N>, a nie ivec<N>.

Bardziej zwięźle, użyj glVertexAttribIPointer dla atrybutów liczb całkowitych i glVertexAttribPointer dla zmiennoprzecinkowych.

+0

To było to - po wykonaniu tego mogłem usunąć również wywołania 'glBindAttribLocation'. Teraz mam animację działającą! (do pewnego stopnia - zdaje się zanikać w pewnych miejscach, więc myślę, że normalni mogą się popsuć.). Dzięki @Andon! – Jarrett

Powiązane problemy