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;
};
Related
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);
}
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'm trying to get some basic shaders working in OpenGL, and I seem to have hit a roadblock at the first barrier. I'm trying to enable some vertex attributes, but I'm getting weird results. I've brought up the draw call in RenderDoc, and only vertex attribute 0 is being enabled. Here is my VAO making code, and my render loop. I'm probably overlooking something really obvious. Thanks!
std::vector<float> positions;
std::vector<float> normals;
std::vector<float> texCoords;
for (auto x : model->positions)
{
positions.push_back(x.x);
positions.push_back(x.y);
positions.push_back(x.z);
}
for (auto x : model->normals)
{
normals.push_back(x.x);
normals.push_back(x.y);
normals.push_back(x.z);
}
for (auto x : model->texCoords)
{
texCoords.push_back(x.x);
texCoords.push_back(x.y);
}
GLuint indicesVBO = 0;
GLuint texCoordsVBO = 0;
GLuint vertsVBO = 0;
GLuint normsVBO = 0;
glGenVertexArrays(1, &model->vao);
glBindVertexArray(model->vao);
glGenBuffers(1, &vertsVBO);
glBindBuffer(GL_ARRAY_BUFFER, vertsVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * positions.size(), positions.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
glEnableVertexAttribArray(0);
glGenBuffers(1, &normsVBO);
glBindBuffer(GL_ARRAY_BUFFER, normsVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * normals.size(), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
glEnableVertexAttribArray(1);
glGenBuffers(1, &texCoordsVBO);
glBindBuffer(GL_ARRAY_BUFFER, texCoordsVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * texCoords.size(), texCoords.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
glEnableVertexAttribArray(2);
glGenBuffers(1, &indicesVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->indices.size() * sizeof(uint32_t), model->indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
My Render Loop is this:
//I'm aware this isn't usually needed but I'm just trying to make sure
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
for (GamePiece * x : gamePieces)
{
glUseProgram(x->program->programID);
glBindVertexArray(x->model->vao);
glBindTexture(GL_TEXTURE_2D, x->texture->texID);
glDrawElements(GL_TRIANGLES, x->model->indices.size(), GL_UNSIGNED_INT,(void*)0);
}
And my vertex shader:
#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 texCoord;
out vec2 outUV;
out vec3 outNormal;
void main()
{
outUV = texCoord;
outNormal = normal;
gl_Position = vec4(position, 1.0f);
}
#version 330
in vec2 inUV;
in vec3 normal;
out vec4 outFragcolor;
uniform sampler2D colourTexture;
void main()
{
outFragcolor = texture2D(colourTexture, inUV);
}
See OpenGL 4.5 Core Profile Specification - 7.3.1 Program Interfaces, page 96:
[...] When a program is linked, the GL builds a list of active resources for each interface. [...] For example, variables might be considered inactive if they are declared but not used in executable code, [...] The set of active resources for any interface is implementation-dependent because it depends on various analysis and optimizations performed by the compiler and linker
This means that, if the compiler and linker determine that the an attribute variable is "not used", when the executable code is executed, then the attribute is inactive.
Inactive attributes are no active program resources and thus not visible in RenderDoc.
Furthermore the output variables of a shader stage are linked to the input variables of the next shader stage by its name.
texCoord is not an active program resource, because it is assigned to the output variable outUV. The fragment shader has no input variable outUV.
Vertex shader:
out vec2 outUV;
out vec3 outNormal;
Fragment shader:
in vec2 inUV;
in vec3 normal;
See Program separation linkage:
Either use the same names for the outputs of the vertex shader and inputs of the fragment shader, or use layout locations to linke the interface variables:
Vertex shader:
layout(location = 0) out vec2 outUV;
layout(location = 1) out vec3 outNormal;
Fragment shader:
layout(location = 0) in vec2 inUV;
layout(location = 1) in vec3 normal;
I am currently trying to render the value of an integer using a bitmap (think scoreboard for invaders) but I'm having trouble changing texture coordinates while the game is running.
I link the shader and data like so:
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE,
4 * sizeof(float), (void*)(2 * sizeof(float)));
And in my shaders I do the following:
Vertex Shader:
#version 150
uniform mat4 mvp;
in vec2 position;
in vec2 texcoord;
out vec2 Texcoord;
void main() {
Texcoord = texcoord;
gl_Position = mvp * vec4(position, 0.0, 1.0) ;
}
FragmentShader:
#version 150 core
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D tex;
void main() {
outColor = texture2D(tex, Texcoord);
}
How would I change this code/implement a function to be able to change the texcoord variable?
If you need to modify the texture coordinates frequently, but the other vertex attributes remain unchanged, it can be beneficial to keep the texture coordinates in a separate VBO. While it's generally preferable to use interleaved attributes, this is one case where that's not necessarily the most efficient solution.
So you would have two VBOs, one for the positions, and one for the texture coordinates. Your setup code will look something like this:
GLuint vboIds[2];
glGenBuffers(2, vboIds);
// Load positions.
glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
// Load texture coordinates.
glBindBuffer(GL_ARRAY_BUFFER, vboIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_DYNAMIC_DRAW);
Note the different last argument to glBufferData(), which is a usage hint. GL_STATIC_DRAW suggests to the OpenGL implementation that the data will not be modified on a regular basis, while GL_DYNAMIC_DRAW suggests that it will be modified frequently.
Then, anytime your texture data changes, you can modify it with glBufferSubData():
glBindBuffer(GL_ARRAY_BUFFER, vboIds[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(texCoords), texCoords);
Of course if only part of them change, you would only make the call for the part that changes.
You did not specify how exactly the texture coordinates change. If it's just something like a simple transformation, it would be much more efficient to apply that transformation in the shader code, instead of modifying the original texture coordinates.
For example, say you only wanted to shift the texture coordinates. You could have a uniform variable for the shift in your vertex shader, and then add it to the incoming texture coordinate attribute:
uniform vec2 TexCoordShift;
in vec2 TexCoord;
out vec2 FragTexCoord;
...
FragTexCoord = TexCoord + TexCoordShift;
and then in your C++ code:
// Once during setup, after linking program.
TexCoordShiftLoc = glGetUniformLocation(program, "TexCoordShift");
// To change transformation, after glUseProgram(), before glDraw*().
glUniform2f(TexCoordShiftLoc, xShift, yShift);
So I make no promises on the efficiency of this technique, but it's what I do and I'll be damned if text rendering is what slows down my program.
I have a dedicated class to store mesh, which consists of a few vectors of data, and a few GLuints to store pointers to my uploaded data. I upload data to openGL like this:
glBindBuffer(GL_ARRAY_BUFFER, position);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * data.position.size(), &data.position[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, normal);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * data.normal.size(), &data.normal[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, uv);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec2) * data.uv.size(), &data.uv[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * data.index.size(), &data.index[0], GL_DYNAMIC_DRAW);
Then, to draw it I go like this:
glEnableVertexAttribArray(positionBinding);
glBindBuffer(GL_ARRAY_BUFFER, position);
glVertexAttribPointer(positionBinding, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(normalBinding);
glBindBuffer(GL_ARRAY_BUFFER, normal);
glVertexAttribPointer(normalBinding, 3, GL_FLOAT, GL_TRUE, 0, NULL);
glEnableVertexAttribArray(uvBinding);
glBindBuffer(GL_ARRAY_BUFFER, uv);
glVertexAttribPointer(uvBinding, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, NULL);
glDisableVertexAttribArray(positionBinding);
glDisableVertexAttribArray(normalBinding);
glDisableVertexAttribArray(uvBinding);
This setup is designed for a full fledged 3D engine, so you can definitely tone it down a little. Basically, I have 4 buffers, position, uv, normal, and index. You probably only need the first two, so just ignore the others.
Anyway, each time I want to draw some text, I upload my data using the first code chunk I showed, then draw it using the second chunk. It works pretty well, and it's very elegant. This is my code to draw text using it:
vbo(genTextMesh("some string")).draw(); //vbo is my mesh containing class
I hope this helps, if you have any questions feel free to ask.
I use a uniform vec2 to pass the texture offset into the vertex shader.
I am not sure how efficient that is, but if your texture coordinates are the same shape, and just moved around, then this is an option.
#version 150
uniform mat4 mvp;
uniform vec2 texOffset;
in vec2 position;
in vec2 texcoord;
out vec2 Texcoord;
void main() {
Texcoord = texcoord + texOffset;
gl_Position = mvp * vec4(position, 0.0, 1.0) ;
}
I have been successful in rendering primitives with a colour component via the shader and also translating them. However, upon attempting to load a texture and render it for the primitive via the shader, the primitives glitch, they should be squares:
As you can see, it successfully loads and applies the texture with the colour component to the single primitive in the scene.
If I then remove the color component, I again have primitives, but oddly, they are scaled by changing the uvs - this should not be the case, only the uvs should scale! (also their origin is offset)
My shader init code:
void renderer::initRendererGfx()
{
shader->compilerShaders();
shader->loadAttribute(#"Position");
shader->loadAttribute(#"SourceColor");
shader->loadAttribute(#"TexCoordIn");
}
Here is my object handler rendering function code:
void renderer::drawRender(glm::mat4 &view, glm::mat4 &projection)
{
//Loop through all objects of base type OBJECT
for(int i=0;i<SceneObjects.size();i++){
if(SceneObjects.size()>0){
shader->bind();//Bind the shader for the rendering of this object
SceneObjects[i]->mv = view * SceneObjects[i]->model;
shader->setUniform(#"modelViewMatrix", SceneObjects[i]->mv);//Calculate object model view
shader->setUniform(#"MVP", projection * SceneObjects[i]->mv);//apply projection transforms to object
glActiveTexture(GL_TEXTURE0); // unneccc in practice
glBindTexture(GL_TEXTURE_2D, SceneObjects[i]->_texture);
shader->setUniform(#"Texture", 0);//Apply the uniform for this instance
SceneObjects[i]->draw();//Draw this object
shader->unbind();//Release the shader for the next object
}
}
}
Here is my sprite buffer initialisation and draw code:
void spriteObject::draw()
{
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), NULL);
glVertexAttribPointer((GLuint)1, 4, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex) , (GLvoid*) (sizeof(GL_FLOAT) * 3));
glVertexAttribPointer((GLuint)2, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex) , (GLvoid*)(sizeof(GL_FLOAT) * 7));
glDrawElements(GL_TRIANGLE_STRIP, sizeof(SpriteIndices)/sizeof(SpriteIndices[0]), GL_UNSIGNED_BYTE, 0);
}
void spriteObject::initBuffers()
{
glGenBuffers(1, &vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(SpriteVertices), SpriteVertices, GL_STATIC_DRAW);
glGenBuffers(1, &indexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(SpriteIndices), SpriteIndices, GL_STATIC_DRAW);
}
Here is the vertex shader:
attribute vec3 Position;
attribute vec4 SourceColor;
varying vec4 DestinationColor;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 MVP;
attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;
void main(void) {
DestinationColor = SourceColor;
gl_Position = MVP * vec4(Position,1.0);
TexCoordOut = TexCoordIn;
}
And finally the fragment shader:
varying lowp vec4 DestinationColor;
varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;
void main(void) {
gl_FragColor = DestinationColor * texture2D(Texture, TexCoordOut);
}
If you want to see any more specifics of certain elements, just ask.
Many thanks.
Are you sure your triangles have the same winding? The winding is the order in which the triangle points are listed ( either clockwise or counter-clockwise ). The winding is used in face culling to determine if the triangle is facing or back-facing.
You can easily check if your triangle are wrongly winded by disabling face culling.
glDisable( GL_CULL_FACE );
More information here ( http://db-in.com/blog/2011/02/all-about-opengl-es-2-x-part-23/#face_culling )