2013-09-07 11 views
5

Ok, quindi sono in grado di caricare un modello di base con vertici, coordinate di trama e normali e renderlo senza problemi.Invio di dati ossei a glsl shader

Tuttavia, quando provo a lanciare alcune informazioni sull'osso, i dati ossei sembrano essere corrotti (o qualcosa del genere?) Quando provo a manipolarlo nello shader.

Ecco il mio codice per il caricamento e il rendering dei dati in opengl (impostando lo shader e inviare la matrice vista, matrice di mondo, ecc sono fatti in un'altra classe):

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

mio Shader reale è questo:

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

Se bug = 1.0, quindi i vertici sono di colore rosso, e se but = 2.0, quindi i vertici sono di colore verde. Vedo che tutti i vertici sono colorati in rosso in questo momento, il che significa che lo sum è maggiore di 1.5f.

Ho confermato che la somma di ciascun set di pesi è in effetti <= 1.0f ... quindi come mai nel mondo non è lo shader?

Qualcuno vede qualcosa di ovvio che mi manca?

EDIT: Sembra che ho trovato il problema - non mi stava chiamando glBindAttribLocation su uno dei miei in variabili - dopo l'aggiunta:

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

al mio codice dello shader di carico, funziona benissimo. La cosa strana è che non ho dovuto farlo per i primi 3 (posizione, consistenza e colore) e ha funzionato bene. Ma quando ho aggiunto le informazioni sull'osso, improvvisamente ho bisogno di questo ... perché?

risposta

3

È necessario utilizzare glVertexAttribIPointer (...) per fornire dati a un attributo vertice ivec<N>. Se pensavate di provare "corruzione" prima di impostare le posizioni degli attributi, aspettate solo che scriviate codice nello shader che ha effettivamente bisogno degli ID bone ... Questi valori saranno privi di significato perché state usando la chiamata API sbagliata per associare il vostro attributo dati con una particolare posizione vincolante.

La variante glVertexAttribPointer (...) non ha problemi nel prendere un tipo di dati GL_INT, ma lo converte in virgola mobile (e può normalizzare i valori in virgola fissa nel processo, quindi il parametro aggiuntivo). Pertanto, è previsto che questa variante fornisca i dati a un attributo vertice vec<N>, non a ivec<N>.

In modo più conciso, utilizzare glVertexAttribIPointer per gli attributi dei vertici interi e glVertexAttribPointer per virgola mobile.

+0

Questo è stato - dopo averlo fatto, ho potuto rimuovere anche le chiamate 'glBindAttribLocation'. Ora lavoro sull'animazione! (fino a un certo punto - sembra scomparire in alcuni punti, quindi penso che le normali potrebbero essere incasinate). Grazie a @ Andon! – Jarrett

Problemi correlati