I use OpenGL + OpenMesh to render a 3d mesh
My mesh reading and processing code:
void read(MyMesh &model, const string &path) {
model.request_vertex_colors();
model.request_face_normals();
OpenMesh::IO::Options opt;
opt += OpenMesh::IO::Options::VertexColor;
opt += OpenMesh::IO::Options::FaceNormals;
if (!OpenMesh::IO::read_mesh(model, path, opt)) {
cerr << "read error\n";
exit(1);
}
// fill the vertices and normals array
for (auto f : model.faces())
for (auto v : model.fv_range(f)){ // how can I get vertex texcoords based on face?
vertices.push_back(model.point(v));
normals.push_back(model.normal(f));
colors.push_back(model.color(v));
}
model.release_vertex_colors();
model.release_face_normals();
}
But I find that I can't get vertex texcoords based on the face in OpenMesh.
It seems there isn't a function called model.texcoords(face_handle, vertex_handle) to let me get the vertex texcoords on this face.
Or can I get the texcoords index of each face like these in obj file:
f 481/1/1 480/2/1 24/3/1 25/4/1
f 477/5/2 7/6/2 17/7/2 18/8/2
f 1/9/3 326/10/3 11/11/3
f 482/12/4 481/1/4 25/4/4
f 478/13/5 477/5/5 18/8/5 19/14/5
f 2/15/6 1/9/6 11/11/6 12/16/6
f 479/17/7 478/13/7 19/14/7 20/18/7
f 3/19/8 2/15/8 12/16/8 13/20/8
f 8/21/9 479/17/9 20/18/9 21/22/9
I use glDrawArrays(...) to draw mesh.
Declarations
vector<MyMesh::Point> vertices; // `MyMesh::Point` is like float3 struct which has 3 float numbers in it
vector<MyMesh::Point> normals;
vector<MyMesh::Point> colors;
unsigned int model_vbo[3], model_vao;
Data bind
glGenBuffers(3, model_vbo);
glGenVertexArrays(1, &model_vao);
glBindBuffer(GL_ARRAY_BUFFER, model_vbo[0]);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * 3 * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, model_vbo[1]);
glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(float), colors.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, model_vbo[2]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(float), normals.data(), GL_DYNAMIC_DRAW);
glBindVertexArray(model_vao);
glBindBuffer(GL_ARRAY_BUFFER, model_vbo[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glBindBuffer(GL_ARRAY_BUFFER, model_vbo[1]);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glBindBuffer(GL_ARRAY_BUFFER, model_vbo[2]);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Draw loop
s.use();
s.setMat4("model", Rotate * Scale);
s.setMat4("projection", cam.projection());
s.setMat4("view", cam.view());
glBindVertexArray(model_vao);
glDrawArray(GL_TRIANGLES, 0, vertices.size() / 3);
vertex shader
#version 450 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec3 normal;
uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;
out vec3 Color;
out vec3 Normal;
void main(){
Normal = normal;
Color = color;
gl_Position = projection * view * model * vec4(position, 1.0);
}
fragment shader
#version 450 core
out vec4 scene_color;
in vec3 Color; // vertex color
in vec3 Normal;
void main(){
scene_color = vec4(Color,1.0);
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I want to draw points using opengl shader.
Now my code using glvertex3f(pos.x, pos.y, pos.z) but when too many point to draw using it, it slow. So I want to using shader and glDrawarrays. But its not work. please check my code.
original code :
for (const auto lm : landmarks) {
const openvslam::Vec3_t pos_w = lm->get_pos_in_world();
glColor3ub(lm->color_[0], lm->color_[1], lm->color_[2]);
glVertex3f(pos_w.cast<float>().eval().x(),pos_w.cast<float>().eval().y(), pos_w.cast<float>().eval().z());
}
my code :
for (const auto lm : landmarks) {
const openvslam::Vec3_t pos_w = lm->get_pos_in_world();
int buffer_size = local_landmarks.size();
glGenBuffers(2, buffers_);
glBindBuffer(GL_ARRAY_BUFFER, buffers_[0]);
glm::vec3 pos_pt = glm::vec3(pos_w.cast<float>().eval().x(),pos_w.cast<float>().eval().y(), pos_w.cast<float>().eval().z());
glBufferData(GL_ARRAY_BUFFER, 3*buffer_size*sizeof(float), &pos_pt , GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, buffers_[1]);
glm::vec3 color_pt = glm::vec3(lm->color_[0], lm->color_[1], lm->color_[2]);
glBufferData(GL_ARRAY_BUFFER, buffer_size*3*sizeof(float), &color_pt, GL_DYNAMIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
Eigen::Matrix4f mvp = s_cam_shader_opengl->GetProjectionModelViewMatrix();
//Eigen::Matrix4f mvp = s_cam_shader_opengl->GetProjectionMatrix() * s_cam_shader_opengl->GetModelViewMatrix();
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, mvp.data());
glPointSize(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_POINTS, 0, 3*num);
}
vertex shader
#version 460
uniform mat4 mvpMat;
layout (location = 0) in vec3 test_position;
layout (location = 1) in vec3 test_color;
out vec3 colorr;
void main(void){
colorr = test_color;
gl_Position = vec4(test_position,1.0);
}
fragment shader
#version 460
uniform mat4 mvpMat;
in vec3 colorr;
out vec4 frag_color;
void main(void) {
frag_color = vec4(colorr, 1.0);
}
////////////////////////////////////////////////////////////////////////
+edit
I update code but it said segmentation error.
Whats problem?
struct TLandmarkData
{
glm::vec3 pos;
glm::vec3 color;
};
using TLandmarks = std::vector<TLandmarkData>;
TLandmarks landmarks_;
...
code
...
glUseProgram(points_program_);
while(){
...
for (const auto lm : landmarks) {
TLandmarkData aaa;
glm::vec3 pos_pt = glm::vec3(pos_w.cast<float>().eval().x(),pos_w.cast<float>().eval().y(), pos_w.cast<float>().eval().z());
glm::vec3 color_pt = glm::vec3(lm->color_[0], lm->color_[1], lm->color_[2]);
aaa.pos = pos_pt;
aaa.color = color_pt;
landmarks_.push_back(aaa);
}
...
GLuint vbo_;
GLuint vao_;
glGenBuffers(1, &vbo_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, landmarks_.size()*sizeof(*landmarks_.data()), landmarks_.data(), GL_STATIC_DRAW);
glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TLandmarkData), 0);
glEnableVertexAttribArray( 0 );
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(TLandmarkData), (void*)(sizeof(glm::vec3)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_POINTS, 0, landmarks_.size());
}
vertex shader
#version 460
layout (location = 0) in vec3 test_position;
layout (location = 1) in vec3 test_color;
out vec3 colorr;
void main(void){
colorr = test_color;
gl_Position = vec4(test_position,1.0);
}
fragment shader
#version 460
in vec3 colorr;
out vec4 frag_color;
void main(void) {
frag_color = vec4(colorr, 1.0);
}
+
What you actually do is to create landmarks.size() buffers rather than 1 buffer. You have to create one single buffer. For the best performance gain you have to create tha buffer once (respectively when it changes only) and to do the world transformation in the shader.
Use the following data structure to represent a point (or a similar aggregate):
struct TLandmarkData
{
glm::vec3 pos;
glm::vec3 color;
};
using TLandmarks = std::vector<TLandmarkData>;
Create a Vertex Array Object and a Vertex Buffer Object (once at initialization):
(See also Vertex Specification)
TLandmarks landmarks;
GLuint vbo_;
GLuint vao_;
glGenBuffers(1, &vbo_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, landmarks.size()*sizeof(*landmarks.data()), landmarks.data(), GL_STATIC_DRAW);
glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TLandmarkData), 0);
glEnableVertexAttribArray( 0 );
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(TLandmarkData), (void*)(sizeof(glm::vec3)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
As you can see, you don't need any loop. If the data changes, the buffer (vbo_) can be updated (e.g. glBufferSubData).
When you want to draw the points, then it is sufficient to bind the vertex array object. The count argument to glDrawArrays has to be the number of vertices:
glBindVertexArray(vao_);
glDrawArrays(GL_POINTS, 0, landmarks.size());
Use a Uniform of type mat4, to transform the points to world coordinates in the vertex shader:
#version 460
uniform mat4 mvpMat;
layout (location = 0) in vec3 test_position;
layout (location = 1) in vec3 test_color;
layout (location=0) uniform mat4 worldtransform;
out vec3 colorr;
void main(void){
colorr = test_color;
gl_Position = worldtransform * vec4(test_position,1.0);
}
Set the uniform (update it per frame) by glUniformMatrix4fv after the program is installed by glUseProgram:
glm::mat4 toworld(1.0f);
// set toworld
// [...]
glUseProgram(myProgram);
glUniformMatrix4fv(0, 1, GL_FALSE, glm::value_ptr(toworld));
I have filled VBO with my vertices (2x position, 2x size, 4x uv, 2x texture data(1 float sets correct texture array and 2. sets index of texture in array), still not rendering, what am i missing?
I tried setting geometry shader to render simple quad, nothing showed up, i tried just rendering color in fragment, nothing showed up, I checked OPENGL debug message, nothing there, in vertex shader i checked calculation for my matrix, everything should be fine
Data is being loaded every frame using glBufferData to same buffer, because of resizing, this code is for entities and amount of them on screen can change easily.
Fragment shader:
void main()
{
texColor = vec4(1.0,0.0,0.0,1.0); //Red fillment
FragColor = texColor;
}
Vertex shader:
layout:
layout(location = 0) in vec2 position;
layout(location = 1) in vec2 size;
layout(location = 2) in vec4 uv;
layout(location = 3) in vec2 textureData; //1. data is to pick correct atlas, 2. is index of texture in atlas
interface:
out VS_OUT
{
mat4 screenMatrix;
vec2 position;
vec4 uv;
vec2 textureData;
vec2 size;
} vs_out;
matrix:
mat4 screenMatrix = mat4((2.0/screenRatio.x),0.0,0.0,0.0,0.0,(2.0/screenRatio.y),0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0);
Geometry Shader:
Layout:
layout (points) in;
layout(triangle_strip,max_vertices = 4) out;
out:
out vec2 TexData;
out vec2 TexCoord;
code:
void renderPlayer(mat4 screenMatrix, vec4 position,vec2 textureData,vec2 size,vec4 uv)
{
gl_Position = nullPos+((position+vec4(0.0,0.0,0.0,0.0))*screenMatrix); // 1:bottom-left
TexData = textureData;
TexCoord = vec2(uv.xy);
EmitVertex();
gl_Position = nullPos+((position+vec4(size.x,0.0,0.0,0.0))*screenMatrix); // 2:bottom-right
TexData = textureData;
TexCoord = vec2(uv.zy);
EmitVertex();
gl_Position = nullPos+((position+vec4(0.0,size.y,0.0,0.0))*screenMatrix); // 3:top-left
TexData = textureData;
TexCoord = vec2(uv.xw);
EmitVertex();
gl_Position = nullPos+((position+vec4(size.x,size.y,0.0,0.0))*screenMatrix); // 4:top-right
TexData = textureData;
TexCoord = vec2(uv.zw);
EmitVertex();
EndPrimitive();
}
main:
void main() {
renderPlayer(gs_in[0].screenMatrix,vec4(gs_in[0].position,0.0,0.0),gs_in[0].textureData,gs_in[0].size,gs_in[0].uv);
}
C++ code:
VBO data inicialization:
float* vertices = new float[totalVertices];
for (EntityRenderData renderDataCurrent : renderData)
{
for (int layerI = 0; layerI < renderDataCurrent.getLayerCount(); layerI++)
{
int i = 0;
vertices[layerI * 10 + i++] = renderDataCurrent.getLayer(layerI).xPos;
vertices[layerI * 10 + i++] = renderDataCurrent.getLayer(layerI).yPos;
vertices[layerI * 10 + i++] = renderDataCurrent.getLayer(layerI).xSize;
vertices[layerI * 10 + i++] = renderDataCurrent.getLayer(layerI).ySize;
vertices[layerI * 10 + i++] = renderDataCurrent.getLayer(layerI).U0;
vertices[layerI * 10 + i++] = renderDataCurrent.getLayer(layerI).V0;
vertices[layerI * 10 + i++] = renderDataCurrent.getLayer(layerI).U1;
vertices[layerI * 10 + i++] = renderDataCurrent.getLayer(layerI).V1;
vertices[layerI * 10 + i++] = (float)renderDataCurrent.getLayer(layerI).textureAtlasId;
vertices[layerI * 10 + i++] = (float)renderDataCurrent.getLayer(layerI).textureIndex;
drawCount++;
}
}
Render Part:
glBindVertexArray(playerVAO);
glBindBuffer(GL_ARRAY_BUFFER, playerVBO);
glBufferData(GL_ARRAY_BUFFER, totalVertices * sizeof(float), vertices, GL_STREAM_DRAW);
game->renderer->entityShader->use();
glDrawArrays(GL_POINTS, 0, drawCount);
Inicialization Part:
glGenVertexArrays(1, &playerVAO);
glGenBuffers(1, &playerVBO);
glBindVertexArray(playerVAO);
// position
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// size
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(1);
// uv
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)(4 * sizeof(float)));
glEnableVertexAttribArray(2);
// texture data
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)(8 * sizeof(float)));
glEnableVertexAttribArray(3);
If a non-zero named array buffer object is bound, then the last parameter of glVertexAttribPointer is treated as a byte offset into the buffer object's data store.
The definition of the generic vertex attribute data and the referenced buffer is stated in the Vertex Array Object.
It is not sufficient to generate a buffer object, the array buffer object has to be the currently bound buffer object, when using glVertexAttribPointer:
glGenVertexArrays(1, &playerVAO);
glGenBuffers(1, &playerVBO);
glBindVertexArray(playerVAO);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, playerVBO); // <--- bind the buffer object
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)(2 * sizeof(float)));
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)(4 * sizeof(float)));
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)(8 * sizeof(float)));
I'm using SIFT algorithm and I want to draw lines between keypoints in differents image. I made it, but actually, all my lines have the same color so it's unreadable.
What I want to achieve is to set a random color to each line, but 1 and only 1 color to a line.
I have to use shaders to do that, and so I send LINES and POINTS (that is the color) to the same shader, and I don't know what's wrong in my code (I have a crash when trying to execute my code. EDIT : It is not that something is wrong in my code (well, obviously yes...) but the error cause a crash, like if I had a segmentation fault. So I think my errors is due to a wrong place allocation for my color array (because it worked without this array))
my code :
std::vector<GLfloat> points;
std::vector<glm::vec3> colors;
GLuint VAO, VBO[2];
void setupLines() {
glGenVertexArrays(1, &VAO);
glGenBuffers(2, &VBO[0]);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, points.size() * sizeof(GLfloat), &points[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), &colors[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
void draw() {
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glDrawArrays(GL_LINES, 0, points.size());
//The error occurs here, it seems...
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glDrawArrays(GL_POINTS, 0, colors.size());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
//for each points, we create the same colors 2by 2 so lines (that are 2 points) have the same colors
void addColor() {
for (int i = 0; i < points.size()/2; ++i) {
float a = rand() / (float)RAND_MAX;
float b = rand() / (float)RAND_MAX;
float c = rand() / (float)RAND_MAX;
colors.push_back(glm::vec3(a, b, c));
colors.push_back(glm::vec3(a, b, c));
}
}
and my vertex Shader :
#version 330 core
layout (location = 0) in vec2 aTexCoord;
layout (location = 1) in vec3 color;
out vec2 TexCoord;
out vec3 Col;
void main()
{
TexCoord = vec2(aTexCoord.xy);
Col = color;
}
and then I use Col in fragment shader to color.
Is it how I have to do this?
You have to set the current position gl_Position in the vertex shader.
The vertex coordinate has to be an attribute:
in vec3 aVertCoord;
and you have to assigne the coordinate to gl_Position:
gl_Position = vec4(aVertCoord.xyz, 1.0);
Note, for 2D coordinates it is should be something like:
in vec2 aVertCoord;
void main()
{
.....
gl_Position = vec4(aVertCoord.xy, 0.0, 1.0);
}
In final you have 2 vertex attributes. The vertex coordinates and the color. You do not need any texture coordinates, because you draw lines (GL_LINES). But I guess what you call aTexCoord is the vertex position, so you have to do it like this:
#version 330 core
layout (location = 0) in vec2 aTexCoord;
layout (location = 1) in vec3 color;
out vec3 TexCoord;
out vec3 Col;
void main()
{
gl_Position = vec4(aTexCoord.xy, 0.0, 1.0);
TexCoord = aTexCoord.xy;
Col = color;
}
The vertex array object VAO stores the states of the generic vertex attributes (glVertexAttribPointer, glEnableVertexAttribArray). The vertex attribute state may refer to a vertex array buffer. You have to bind the vertex array object VAO only, when you draw the object (lines):
void draw() {
glBindVertexArray(VAO);
int numberOfPoints = points.size() / 2; // Number of points, not the number of floats
glDrawArrays(GL_LINES, 0, numberOfPoints );
glBindVertexArray(0);
}
Note, it sufficient to call glDrawArrays one time.
Further, the 1st paramter of glVertexAttribPointer is the attribute index:
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), &colors[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(
1, // <---------------------------- attribute index
3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
Since you need one color per vertex coordinate, but you want every line to be drawn in a single color, you have to do it like this:
void addColor()
{
int numberOfPoints = points.size() / 2;
for (int i = 0; i < numberOfPoints/2; ++i)
{
glm::vec3 col(
rand() / (float)RAND_MAX,
rand() / (float)RAND_MAX,
rand() / (float)RAND_MAX);
colors.push_back(col);
colors.push_back(col);
}
}
I wanted to load a model into OpenGL with Assimp.
I am using QT as my framework that provides me with the functions needed.
Baiscally, my program crashes at Mesh::DrawMesh at gl.glDrawElements()...
I bet it has to do with one of my allocations but I don't know.
I am sure the model is loaded correctly because I compared the loaded results ;)
So here I post the initialize function that basically sets up the buffers etc. for that mesh. I think that maybe something went wrong there:
void Mesh::initialize()
{
vao->create();
vbo->create();
ebo->create();
vao->bind();
vbo->bind(); //glBindBuffer(GL_ARRAY_BUFFER, vbo); // Bind vbo
vbo->setUsagePattern(QOpenGLBuffer::StaticDraw);
vbo->allocate(vertices.data(),vertices.size() * sizeof(Vertex)); //glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW); //Allocates space in bytes
ebo->bind(); //glBindBuffer(GL_ARRAY_BUFFER, ebo);
ebo->setUsagePattern(QOpenGLBuffer::StaticDraw);
ebo->allocate(indices.data(),indices.size()*sizeof(GLuint)); //glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW); //Allocates space in bytes
program->enableAttributeArray(0); //glEnableVertexAttribArray(0); //On layout = 0
program->setAttributeBuffer(0,GL_FLOAT,0,sizeof(Vertex));//glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),0); // Stride is sizeof(Vertex) ofc, offset is 0 because we want to access Position
program->enableAttributeArray(1); //glEnableVertexAttribArray(1);
program->setAttributeBuffer(1,GL_FLOAT,offsetof(Vertex,Normal),3,sizeof(Vertex)); //glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,sizeof(Vertex), (GLvoid*) offsetof(Vertex, Normal));
program->enableAttributeArray(2);
program->setAttributeBuffer(2,GL_FLOAT,offsetof(Vertex,TextCoords),2,sizeof(Vertex));//glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,sizeof(Vertex), (GLvoid*) offsetof(Vertex, TextCoords));
vao->release();
}
This is my Draw method that gets called when the program is bound:
void Mesh::DrawMesh(QOpenGLFunctions_3_3_Core& gl)
{
vao->bind();
qDebug() << vertices.size();
gl.glDrawElements(GL_TRIANGLES, indices.size(),GL_UNSIGNED_INT,0);
vao->release();
}
Vertex Shader:
#version 330 core
layout(location=0) in vec3 position;
layout(location=1) in vec3 normal;
layout(location=2) in vec2 textCoords;
uniform mat4 MVP;
out vec4 color;
void main(void)
{
gl_Position= MVP*vec4(position,1);
color = vec4(0.5,0.5,0.5,0.5);
}
InitializeGL function of my QOpenGLWidget:
void RenderingWindow::initializeGL()
{
this->initializeOpenGLFunctions();
program.create();
program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/testvert.vert" );
program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/testfrag.frag");
program.link();
program.bind();
this->glEnable(GL_DEPTH_TEST);
Camera::instance().LookAt(0,0,10, 0,0,0 ,0,1,0);
model.SetProgram(&program);
model.LoadModel(*this, "C:/Users/TestCube.fbx");
program.release();
}
This is my Vertex struct:
struct Vertex
{
QVector3D Position;
QVector3D Normal;
QVector2D TextCoords;
};
I'm currently trying to set up a GPU skinning (with glsl) but it's not working the way I would :) Actually it's not working at all. My mesh disappear when I try this glsl code :
layout(location = 0) in vec3 vertexPos;
layout(location = 1) in vec2 vertexUv;
layout(location = 2) in vec3 vertexNor;
layout(location = 5) in ivec4 joints_influences;
layout(location = 6) in vec4 weights_influences;
uniform mat4 ViewProj, View, Proj, Model;
out vec3 vertexPosEye;
out vec3 vertexNorEye;
const int MAX_INFLUENCES = 4;
const int MAX_BONES = 50;
uniform mat4 animation_matrices[MAX_BONES];
uniform mat4 inv_bind_matrices[MAX_BONES];
void main()
{
vertexPosEye = (View * Model * vec4(vertexPos, 1)).xyz; // Position
vertexNorEye = (View * Model * vec4(vertexNor, 0)).xyz; // Normal matrix
vec4 final_v = vec4(0, 0, 0, 0);
for (int i = 0; i < MAX_INFLUENCES; i++)
{
vec4 v = vec4(vertexPos, 1)
* inv_bind_matrices[joints_influences[i]]
* animation_matrices[joints_influences[i]]
* weights_influences[i];
final_v += v;
}
gl_Position = ViewProj * Model * final_v;
}
when I try this :
gl_Position = ViewProj * Model * vertexPos;
My mesh is back :) but no animations anymore of course...
Here's my application (c++) code when I set VBO attributes :
// Vertex position
glGenBuffers(1, &buffer[0]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
glBufferData(GL_ARRAY_BUFFER, vertices.pos.size() * sizeof(bVector3), &vertices.pos[0], GL_STATIC_DRAW);
// Ibid for uv, normals, tangents and bitangents.
// Skinning : joints index
glGenBuffers(1, &buffer[5]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[5]);
glBufferData(GL_ARRAY_BUFFER, vertices.joints.size() * sizeof(SkinningJoints), &vertices.joints[0], GL_STATIC_DRAW);
// Skinning : weights
glGenBuffers(1, &buffer[6]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[6]);
glBufferData(GL_ARRAY_BUFFER, vertices.weights.size() * sizeof(SkinningWeights), &vertices.weights[0], GL_STATIC_DRAW);
// Indices
glGenBuffers(1, &buffer[7]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[7]);
glBufferData(GL_ARRAY_BUFFER, vertices.indices.size() * sizeof(bUshort), &vertices.indices[0], GL_STATIC_DRAW);
In the main loop :
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(0));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(for uv, normals, tangents and bitangents)...
glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(5));
glVertexAttribPointer(5, 4, GL_INT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(6);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(6));
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->GetBuffer(7));
glDrawElements(GL_TRIANGLES, m->vertices.indices.size(), GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
Here is my RenderingVertices struct (after Barr's recomendations):
struct RenderingVertices
{
// std::vector<Vec3>
vVec3 pos, nor, tang, btan;
vVec2 uv;
vUshort indices;
vector<SkinningJoints> joints;
vector<SkinningWeights> weights;
};
And here is my SkinningJoints struct :
struct SkinningJoints
{
int j[MAX_BONES_PER_VERT];
SkinningJoints(Vertex::Weights weights[MAX_BONES_PER_VERT])
{
for (bUint i = 0; i < MAX_BONES_PER_VERT; i++)
j[i] = weights[i].jid;
}
};
My SkinningWeights struct is almost the same, with an array of float instead of int.
Now when I try to debug the joints index, weights values and final vertex as colors, here is what I get :
// Shader
color_debug = joints_influences;
http://www.images-host.fr/view.php?img=00021800pop.jpg
color_debug = weights_influences;
http://www.images-host.fr/view.php?img=00021800pop2.jpg
Another interesting thing, when I try this :
vec4 pop = vec4(vertexPos, 1) * animation_matrices[1] * inv_bind_matrices[1] * 1.0;
gl_Position = ViewProj * Model * pop;
My all mesh is actually rotating, which means that my uniform animation_matrices is good.
Anyone can see what i'm doing wrong here ?
I finally got it working. For those who may be interested, here is what I was doing wrong :
When I send joints indices array to Glsl, instead of doing this:
glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(5));
glVertexAttribPointer(5, 4, GL_INT, GL_FALSE, 0, BUFFER_OFFSET(0));
I needed to do this:
glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(5));
glVertexAttribIPointer(5, 4, GL_INT, 0, BUFFER_OFFSET(0));
You have to look closely to find the difference. Instead of calling glVertexAttribPointer(), I needed to call glVertexAttribIPointer() because joints indices are int.
Hope this will help someone someday.
Did you try debugging your skinning attributes? Output the vertex weight as colors so that you can confirm you have meaningful values? If everything is black you'll know where to look.
From a quick glance at your RenderingVertices I can spot a first problem. You are passing a Vector of pointers to GL which I don't think is what you want to do.
Most of the time you will limit skinning influences to 4 joint/weight pairs per vertex. So you can get away with a simple array (ie. SkinningJoints joints[4];).