I implemented simple OBJ-parser and using parallelepiped as example model. I added rotation feature based on quaternions. Next goal - adding light. I parsed normals and decided drawing normals as "debug" feature (for further better understanding light). But I stuck after that:
Here my parallelepiped with small rotation.
Look at the right further bottom vertice and normal. I can't understand why it rendered through my parallelepiped. It should be hidden.
I use depth buffer (because without it parallelepiped looking weird while I rotate it). So I initialize it:
glGenRenderbuffers(1, &_depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _frameBufferWidth, _frameBufferHeight);
and enable it:
glEnable(GL_DEPTH_TEST);
I generate 4 VBOs: vertex and index buffers for parallelepiped, vertex and index buffers for lines(normals).
I use one simple shader for both models(if it will be needed - I can add code later but I think everything is ok with it).
At first I draw parallelepiped, after that - normals.
Here my code:
// _field variable - parallelepiped
glClearColor(0.3, 0.3, 0.4, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int vertexSize = Vertex::size();
int colorSize = Color::size();
int normalSize = Normal::size();
int totalSize = vertexSize + colorSize + normalSize;
GLvoid *offset = (GLvoid *)(sizeof(Vertex));
glBindBuffer(GL_ARRAY_BUFFER, _geomBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indicesBufferID);
glVertexAttribPointer(_shaderAtributePosition, vertexSize, GL_FLOAT, GL_FALSE, sizeof(Vertex::oneElement()) * totalSize, 0);
glVertexAttribPointer(_shaderAttributeColor, colorSize, GL_FLOAT, GL_FALSE, sizeof(Color::oneElement()) * totalSize, offset);
glDrawElements(GL_TRIANGLES, _field->getIndicesCount(), GL_UNSIGNED_SHORT, 0);
#ifdef NORMALS_DEBUG_DRAWING
glBindBuffer(GL_ARRAY_BUFFER, _normalGeomBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _normalIndexBufferID);
totalSize = vertexSize + colorSize;
glVertexAttribPointer(_shaderAtributePosition, vertexSize, GL_FLOAT, GL_FALSE, sizeof(Vertex::oneElement()) * totalSize, 0);
glVertexAttribPointer(_shaderAttributeColor, colorSize, GL_FLOAT, GL_FALSE, sizeof(Color::oneElement()) * totalSize, offset);
glDrawElements(GL_LINES, 2 * _field->getVertexCount(), GL_UNSIGNED_SHORT, 0);
#endif
I understand for example if I merge this two draw calls in one (And use same VBOs for parallelepiped and normals - everything will be fine).
But it will be uncomfortable because I use lines and triangles.
There are should be another way for fixing Z order. I can't believe that complex scene (for example sky, land and buildings) draws via one draw call.
So, what I am missing?
Thanks in advance.
If you are rendering into a window surface you need to request depth as part of your EGL configuration request. The depth renderbuffer you have allocated is only useful if you attach it to a Framebuffer Object (FBO) for off-screen rendering.
Related
I am trying to render two different vertex collections on top of one another. Right now, my main loop renders one correctly when it's by itself, and the other correctly when it's by itself, but when I call both of my draw functions, I see a blank window. Why might this be happening?
The first draw call uses one shader, while the second draw call uses a different one. I don't clear the screen in between.
If it makes the code more clear, my shader programs are stored as class variables, as are the texture IDs after they're loaded elsehwere in my program.
This is my main loop:
while (true)
{
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawModel1(); // This works when drawModel2() is commented out
drawModel2(); // This works when drawModel1() is commented out
// Unbind buffer
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Swap the screen buffers
glfwSwapBuffers(_window);
}
My drawModel1() function renders points:
void drawModel1()
{
// Use the image shader
_img_shader.use();
// Feed the position data to the shader
glBindBuffer(GL_ARRAY_BUFFER, _img_pos_VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Feed the color data to the shader
glBindBuffer(GL_ARRAY_BUFFER, _img_color_VBO);
glVertexAttribPointer(1, 3, GL_UNSIGNED_BYTE, GL_TRUE, 3 * sizeof(GLubyte), (GLvoid*)0);
glEnableVertexAttribArray(1);
// Set the projection matrix in the vertex shader
GLuint projM = glGetUniformLocation(_img_shader.program(), "proj");
glm::mat4 proj = _ndc * _persMat;
glUniformMatrix4fv(projM, 1, GL_TRUE, glm::value_ptr(proj));
// Set the view matrix in the vertex shader
GLuint viewM = glGetUniformLocation(_img_shader.program(), "view");
glUniformMatrix4fv(viewM, 1, GL_TRUE, glm::value_ptr(_viewMat));
// Draw the points
glBindVertexArray(_img_VAO);
glDrawArrays(GL_POINTS, 0, _numImageVertices);
// Disable attributes
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
And my drawModel2() function renders indexed triangles:
void drawModel2()
{
_model_shader.use();
// Load the mesh texture
GLuint texID = _loaded_textures.at(mesh.tex_file());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texID);
glUniform1i(glGetUniformLocation(_model_shader.program(), "texture_img"), 0);
// Set the proj matrix in the vertex shader
GLuint nvpmM = glGetUniformLocation(_model_shader.program(), "npvm");
glm::mat4 npvm = _ndc * _persMat * _viewMat * mat;
glUniformMatrix4fv(nvpmM, 1, GL_FALSE, glm::value_ptr(npvm));
// Feed the position data to the shader
glBindBuffer(GL_ARRAY_BUFFER, mesh.pos_VBO());
GLuint pos_att = glGetAttribLocation(_model_shader.program(), "position");
glEnableVertexAttribArray(pos_att);
glVertexAttribPointer(pos_att, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
// Feed the texture coordinate data to the shader
glBindBuffer(GL_ARRAY_BUFFER, mesh.tex_VBO());
GLuint tex_coord_att = glGetAttribLocation(_model_shader.program(), "texCoords");
glEnableVertexAttribArray(tex_coord_att);
glVertexAttribPointer(tex_coord_att, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
// Draw mesh
glBindVertexArray(mesh.VAO());
glDrawElements(GL_TRIANGLES, mesh.numIndices(), GL_UNSIGNED_SHORT, (void*)0);
// Disable attributes
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
// Release resources
glBindTexture(GL_TEXTURE_2D, 0);
}
You need to bind your vertex arrays at the start of your function, not right before the draw call itself. The Vertex Array is responsible for maintaining the state associated with a given object[-type] and any calls made that will setup state (like glVertexAttribPointer or glEnableVertexAttribArray) will be maintained on that Vertex Array. What you were essentially doing with your old code is that you were setting up state for your object, then switching to an entirely different VAO, then drawing, which meant model1 was using model2's bindings and setup, and vice-versa. Unless they have identical rules and setups, it's extremely unlikely that they'll both draw.
Incidentally, because VAO's store state, the only things that need to be in your draw calls are the draw call itself, and any data that changed that frame. So you'll want to consider spending some time refactoring your code, as it looks like most of those settings (like buffer binding) don't change on a frame-by-frame basis.
So I had a quick question about a homework assignment I was assigned for my OpenGL class. In class, we made two triangles transform (get bigger and smaller) as they follow a sine wave, and our homework is to make it so that only one transforms while the other stays static, all while only using one vertex shader, one fragment shader, and uniform variables. When I tried it, my mindset was to somehow return the value of 1 to a Scale variable to keep one of the triangles from moving. I was able to make it so that one of the triangles was stationary, but no shader was attached to it, so it was solid white. I have a feeling I have to use some OOP to create another instance of the triangle, but I really can't wrap my head around how I'm supposed to distinguish between the two triangles while only using one vertex shader. Can anyone shed some light onto this? This is the hardest class of the curriculum, so even a hint would be lovely! Thank you! I can post my code if you all want, but I made some changes to it that made my program cry, so I'll try to retrace my steps and post it tomorrow! Thank you all!
[EDIT] Okay here's my code. Trying to make it so that only the red triangle is static. I have a feeling the answer is in the provided class in the form of an "if statement", though I could be wrong about the complexity of this problem. Thank you all again for helping me.
#include "Triangle.h"
Triangle::Triangle(vec3 points[], vec4 color[], GLuint pID)
{
ProgramID = pID;
memcpy(Points, points, sizeof(Points));
memcpy(Colors, color, sizeof(Colors));
glUseProgram(ProgramID);
glGenVertexArrays(1, &VBO);
glBindVertexArray(VBO);
glGenBuffers(1, &VB);
glBindBuffer(GL_ARRAY_BUFFER, VB);
glBufferData(GL_ARRAY_BUFFER, sizeof(Points), Points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glGenBuffers(1, &CB);
glBindBuffer(GL_ARRAY_BUFFER, CB);
glBufferData(GL_ARRAY_BUFFER, sizeof(Colors), Colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(1);
Scale = 90.0f;
gScaleLocation = glGetUniformLocation(ProgramID, "Scale");
}
void Triangle::Draw()
{
glUseProgram(ProgramID);
glBindVertexArray(VBO);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
if ()
{
Scale += 0.0f;
}
else
{
Scale += 0.01f;
}
glUniform1f(gScaleLocation, sinf(Scale));
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
Rather than putting the animation logic into the Triangle class, move it to the caller. So first extract the scaling factor as a parameter:
void Triangle::Draw(double scale)
{
glUseProgram(ProgramID);
glBindVertexArray(VBO);
glUniform1f(gScaleLocation, scale);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
Next call Draw with different parameters on different triangle instances:
// your triangles. I assume you have two instances based on the little code you provided.
Triangle tri0, tri1;
// add this to some context, initialized to 0
int frame;
// Your rendering function, you didn't post it.
void render()
{
tri0.Draw(1); // triangle 0 is not animating
tri1.Draw(sin(frame*0.01)); // triangle 1 follows a sine wave
frame++;
}
Right now it seems to me that my interleaved VBO is strictly ' read-only ' but I want to update it every frame (preferrably from GLSL).
I have a planet that moves around in an orbit, the code below is for rendering points of the orbit.
Problem outline:
I want each point on that orbit to have its own "lifetime", logic:
when the planet passes each consecutive point? update lifetime to 1.0 and reduce with time!
This will be used to create a fading orbitpath of each moving object. Right now Im just looking for ways to manipulate the vbo...
How can I read AND write within GLSL to and from a VBO ? Can anyone post example please?
Update: I modified the code above to work with transform feedback (suggested by user Andon M. Coleman) but I think I might be doing something wrong (I get glError):
Setup:
// Initialize and upload to graphics card
glGenVertexArrays(1, &_vaoID);
glGenBuffers(1, &_vBufferID);
glGenBuffers(1, &_iBufferID);
glGenBuffers(1, &_tboID);
// First VAO setup
glBindVertexArray(_vaoID);
glBindBuffer(GL_ARRAY_BUFFER, _vBufferID);
glBufferData(GL_ARRAY_BUFFER, _vsize * sizeof(Vertex), _varray, GL_DYNAMIC_DRAW);
// TRANSFORM FEEDBACK
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, _tboID); // Specify buffer
// Allocate space without specifying data
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
_vsize*sizeof(Vertex), NULL, GL_DYNAMIC_COPY);
// Tell OGL which object to store the results of transform feedback
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, _vBufferID); //correct?
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), reinterpret_cast<const GLvoid*>(offsetof(Vertex, location)));
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), reinterpret_cast<const GLvoid*>(offsetof(Vertex, velocity)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _isize * sizeof(int), _iarray, GL_STREAM_DRAW);
render method():
//disable fragment, so that we do a first run with feedback
glEnable(GL_RASTERIZER_DISCARD);
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iBufferID);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, _tboID);
glBeginTransformFeedback(_mode);
glDrawElements(_mode, _isize, GL_UNSIGNED_INT, 0);
glEndTransformFeedback();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glBindVertexArray(0);
glDisable(GL_RASTERIZER_DISCARD);
// then i attempt to do the actual draw
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iBufferID);
glDrawElements(_mode, _isize, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
And - right before linking:
const GLchar* feedbackVaryings[] = { "point_position" };
glTransformFeedbackVaryings(_ephemerisProgram->getProgramID(), 1, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);
you can not change the content of your VBO from the rendering pipline of Opengl, but you can use tricks to update them depending on the time, also if you are using Opengl 4.4 you can use ComputeShaders but it's a little bit complicated to explain it in here, hust google for it, good luck.
How can I read AND write within GLSL to and from a VBO?
You can't. VBOs are strictly readonly from the normal rendering shaders. Modification is not possible at all (because that would open an infathomable deep barrel of worms) but using transformation feedback the results of the shader stages can be written into a buffer.
Or you use compute shaders.
Problem outline: I want each point on that orbit to have its own "lifetime", logic: When the planet passes each consecutive point? update lifetime to 1.0 and reduce with time!
Sound like a task for a compute shader. But honestly I don't think there's much to gain from processing this on a GPU.
I have an OpenGL 1.1 ES 2D sprite engine that's based on one GL_TRIANGLE_FAN per sprite. The main rendering code that gets called per-sprite, per-frame is as follows:
void drawTexture(BitmapImage* aImage, short* vertices, float* texCoords,
ColorMap &colorMap, TInt xDest, TInt yDest, TInt aAlpha)
{
glPushMatrix();
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, textureId);
glVertexPointer(3, GL_SHORT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glColorPointer(RGBA_BYTES, GL_UNSIGNED_BYTE, 0, colorMap.GetMap());
TFloat scaleX, scaleY;
aImage->getScale(scaleX, scaleY);
glTranslatef((float)xDest, (float)yDest, 0.0f);
glScalef(scaleX, scaleY, 1.0f);
glRotatef(aImage->getRotAngle(), 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glPopMatrix();
}
I've been told that switching to Vertex Buffer Objects (VBOs) will significantly increase the performance of rendering, so I'd like to do that. My research thus far has lead me to several examples showing how to set up individual vertex, color, and texture offset buffers, but good examples of how to interleave this data have been more elusive.
For example, I'm pretty sure this is how I'd set up to render with my vertex data in a VBO:
glGenBuffers(1, &batchBufferHandle);
glBindBuffer(GL_ARRAY_BUFFER, batchBufferHandle);
glBufferData(GL_ARRAY_BUFFER, dataSize, data, GL_STATIC_DRAW);
glVertextPointer(3, GL_SHORT, 0, 0);
glDrawElements(..., 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &batchBufferHandle);
Apparently I'd generate and bind similar buffers for texture coordinates and vertex color data, though I'm not 100% clear on how setting those up would differ.
My understanding is that the speed boost would come from rendering a bunch of these triangle fans in one "draw call", but what is a "draw call" in this context? DrawElements() gets called multiple times using this methodology, so that can't be it...?
Whatever the case, it would mean that I'd have to generate a VBO (or three) that contain all the data in series for a bunch of sprites. That can be difficult enough on its own given the legacy code I'm dealing with, but I also need to translate, scale, and rotate each individual sprite. Where does that data go in the VBO(s)?
My conclusion thus far is using VBOs is only helpful in the case of a SINGLE, but complex object. It would appear what I want to do is not possible -- provide OpenGL with a list of sprites to render (including all vertex, color, texture map, scale, rotation, and translation information for each).
Is my assessment correct or is there a way to do this (using OpenGL ES 1.1)?
I decided to import Wavefront .OBJ format to a test-scene that I'm working on. I get the model (vertices) to be in the right place and it displays fine. When I then apply a texture a lot of things looks distorted. I checked my Maya scene (there it looks good), and the object has many more uv-coordinates than vertex positions (this is what makes the scene looks weird in OpenGL, is my guess).
How would I go about loading a scene like that. Do I need to duplicate vertices and how do I store it in the vertex-buffer object?
You are right that you have to duplicate the vertices.
In addition to that you have to sort them in draw order, meaning that you have to order the vertices with the same offsets as the texture coordinates and normals.
basically you'll need this kind of structure:
float *verts = {v1_x,v1_y,v1_z,v1_w,v2_x,v2_y,v2_z,v2_w,...};
float *normals = {n1_x,n1_y,n1_z,n2_x,n2_y,n2_z,...};
float *texcoords = {t1_u,t1_v,t1_w,t2_u,t2_v,t2_w,...};
This however would mean that you have at least 108bytes per Triangle.
3(vert,norm,tex)
*3(xyz/uvw)
*3(points in tri)
*4(bytes in a float))
-----------------------
= 108
You can significantly reduce that number by only duplicating the vertices that actually are duplicate (have identical texture coordinate,vertices and normals meaning: smoothed normals and no UV borders) and using an Index Buffer Object to set the draw order.
I faced the same problem recently in a small project and I just split the models along the hard-edges and UV-Shell borders therefore creating only the necessary duplicate Vertices. Then I used the glm.h and glm.cpp from Nate Robins and copied/sorted the normals and texture coordinates in the same order as the vertices.
Then setup the VBO and IBO:
//this is for Data that does not change dynamically
//GL_DYNAMIC_DRAW and others are available
GLuint mDrawMode = GL_STATIC_DRAW;
//////////////////////////////////////////////////////////
//Setup the VBO
//////////////////////////////////////////////////////////
GLuint mId;
glGenBuffers(1, &mId);
glBindBuffer(GL_ARRAY_BUFFER, mId);
glBufferData(GL_ARRAY_BUFFER,
mMaxNumberOfVertices * (mVertexBlockSize + mNormalBlockSize + mColorBlockSize + mTexCoordBlockSize),
0,
mDrawMode);
glBufferSubData(GL_ARRAY_BUFFER, mVertexOffset, numberOfVertsToStore * mVertexBlockSize, vertices);
glBufferSubData(GL_ARRAY_BUFFER, mNormalOffset, numberOfVertsToStore * mNormalBlockSize, normals);
glBufferSubData(GL_ARRAY_BUFFER, mColorOffset, numberOfVertsToStore * mColorBlockSize, colors);
glBufferSubData(GL_ARRAY_BUFFER, mTexCoordOffset, numberOfVertsToStore * mTexCoordBlockSize, texCoords);
//////////////////////////////////////////////////////////
//Setup the IBO
//////////////////////////////////////////////////////////
GLuint IBOId;
glGenBuffers(1, &IBOId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mMaxNumberOfIndices * sizeof(GLuint), 0, mDrawMode);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numberOfIndicesToStore * sizeof(GLuint), indices);
//////////////////////////////////////////////////////////
//This is how to draw the object
//////////////////////////////////////////////////////////
glBindBuffer(GL_ARRAY_BUFFER, mId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOId);
//Enables and Disables are only necessary each draw
//when they change between objects
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(mVertexComponents, GL_FLOAT, 0, (void*)mVertexOffset);
if(mNormalBlockSize){
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, (void*)mNormalOffset);
}
if(mColorBlockSize){
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(mColorComponents, GL_FLOAT, 0, (void*)mColorOffset);
}
if(mTexCoordBlockSize){
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(mTexCoordComponents, GL_FLOAT, 0, (void*)mTexCoordOffset);
}
glDrawRangeElements(primMode,
idFirstVertex,
idLastVertex,
idLastVertex - idFirstVertex + 1,
mAttachedIndexBuffer->getDataType(),
0);
if(mTexCoordBlockSize)
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if(mColorBlockSize)
glDisableClientState(GL_COLOR_ARRAY);
if(mNormalBlockSize)
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);