Vertex buffers in open gl es 1.X - opengl-es

I am teaching myself about open gl es and vertex buffer (VBO) and I have written code and it is supposed to draw one red triangle but instead it colours the screen black:
- (void)drawRect:(CGRect)rect {
// Draw a red triangle in the middle of the screen:
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
// Setup the vertex data:
typedef struct {
float x;
float y;
} Vertex;
const Vertex vertices[] = {{50,50}, {50,150}, {150,50}};
const short indices[3] = {0,1,2};
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
NSLog(#"drawrect");
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
// The following line does the actual drawing to the render buffer:
glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_SHORT, indices);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, framebuffer);
[eAGLcontext presentRenderbuffer:GL_RENDERBUFFER_OES];
}
Here vertexBuffer is of type GLuint. What is going wrong? Thanks for your help.

Your vertices dont have a Z component, try {{50,50,-100}, {50,150,-100}, {150,50,-100}}; (your camera by default looks down the Z axis so putting it in the -Z should put it on screen) if you cant see it still try smaller numbers, im not sure what your near and far draw cutoff distance is, and if its not even set i dont know what the default is. This might not be the only issue but its the only one i can see by just looking quickly at it.

You need to add
glViewport(0, 0, 320, 480);
where you create the frame buffer and set up the context.
And replace your call to glDrawElements with
glDrawArrays(GL_TRIANGLE_STRIP, ...);

Related

GLFW simple triangle is lost?

I modified the "Simple example" example in GLFW3.0.4 in Mac OSX 10.8 as an XCode 4.6 project (runs fine when unchanged). I am having a (2D) rectangle drawn with an external library (which draws via shaders). I can see the rectangle but If I draw the sample triangle (immediate drawn) before it, the triangle is seen in the first splash (frame) and then it is lost. If I try to draw it after, the triangle is never seen. I can only see the rectangle and I don't know what settings/states the library is changing!
I tried to inspect the application with OpenGL Profiler. Stopped before CGLFlushDrawable and could not find the triangle in any of the buffers (front, back, depth, stencil).
Am I doing something (prominently) wrong? The profiler allows only gl-function breakpoints. How can I debug this (more efficiently) and find the problem.
Here is (much of the changed parts of) the code:
void glfw2DViewport(GLFWwindow * window) {
float ratio;
int width, height;
glfwGetFramebufferSize(window, &width, &height);
ratio = width / (float) height;
glViewport(0, 0, width, height);
glClearColor(0.8, 0.8, 0.8, 1.0); // Lets see if something black is drawn!!
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// eye is at 0,0,0 looking to positive Z, -1(behind) to 1 are clipping planes:
// https://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml
glOrtho(ratio, -ratio, -1.f, 1.f, 1.0f, -1.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// ----- 2D settings -----
glfwSwapInterval(1);
glEnable(GL_SMOOTH);
glDisable(GL_DEPTH_TEST);
//glDisable(GL_STENCIL_TEST); // Disabling changed nothing!!
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(5.0f);
glEnable(GL_LINE_SMOOTH);
glPointSize(5.0f);
glEnable(GL_POINT_SMOOTH);
}
int main(void) {
GLFWwindow* window;
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
if (!window) {
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
glfw2DViewport(window);
//...
while (!glfwWindowShouldClose(window)) {
glMatrixMode(GL_MODELVIEW_MATRIX);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
//drawUnitTriangle(); // can be seen just in the first frame!
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); // A vain attempt?
glPushAttrib(GL_ALL_ATTRIB_BITS); // Another vain attempt??
external_library_identity_matrix();
external_library_rectangle(POS,RED);
external_library_flush();
glPopAttrib();
glPopClientAttrib();
// Other vain attempts:
glfwMakeContextCurrent(window);
glMatrixMode(GL_MODELVIEW_MATRIX);
glLoadIdentity();
drawUnitTriangle(); // Nothing is Drawn!!
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
Are you sure the posted code is exactly what you are building with? If that's true, please check the argument of glMatrixMode() it should be GL_MODELVIEW, not GL_MODELVIEW_MATRIX. There are two places where you set it like this.
Since you already have glfw2DViewport(), why don't you put it in the while loop and delete other model view setting codes?

I need to minimize the number of glDraw* calls

I'm working on a little 2D graphics/game library for personal use and currently I'm trying to think of a way to improve performance when drawing tiled maps. Currently I am creating a static GL_QUADS VBO for each tile in the map and then drawing it to the screen. Each VBO is referencing a texture loaded into memory which is sub-imaged and mapped to the VBO.
Currently, I have a 20 x 20 tile map that I am testing with. With my current implementation, since I have to draw each individual tile, that is 400 glDraw* calls every frame.
Is there any way to, for example, make each row of the tile map ONE VBO? This would reduce the glDraw* calls to 20, for this example. How would I map the sub-images? Individual tiles can be rotated.
I have seen some references to using a Texture Atlas. Would that be a good alternative? Any useful links on how to implement this in opengl?
CODE:
Current render method:
public void render() {
texture.bind();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
for (SpriteSheet spriteSheet : spriteSheets) {
VBO vbo = spriteSheet.getVBO();
float angle = spriteSheet.getAngle();
vbo.bind();
if (angle != 0) {
glPushMatrix();
Vector2f position = spriteSheet.getPosition();
glTranslatef(position.x, position.y, 0);
glRotatef(angle, 0.0f, 0.0f, 1);
glTranslatef(-position.x, -position.y, 0);
glVertexPointer(Vertex.positionElementCount, GL_FLOAT, Vertex.stride, Vertex.positionByteOffset);
glColorPointer(Vertex.colorElementCount, GL_FLOAT, Vertex.stride, Vertex.colorByteOffset);
glTexCoordPointer(Vertex.textureElementCount, GL_FLOAT, Vertex.stride, Vertex.textureByteOffset);
glDrawArrays(vbo.getMode(), 0, Vertex.elementCount);
glPopMatrix();
}
else {
glVertexPointer(Vertex.positionElementCount, GL_FLOAT, Vertex.stride, Vertex.positionByteOffset);
glColorPointer(Vertex.colorElementCount, GL_FLOAT, Vertex.stride, Vertex.colorByteOffset);
glTexCoordPointer(Vertex.textureElementCount, GL_FLOAT, Vertex.stride, Vertex.textureByteOffset);
glDrawArrays(vbo.getMode(), 0, Vertex.elementCount);
}
vbo.unbind();
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
texture.unbind();
}
There are several things you can do.
A texture atlas one option, but you could use a GL_TEXTURE_2D_ARRAY as well, using the 3rd texture coordinate to select which layer to use.
The next thing to think about is instancing: Have a single quad in the buffer and make OpenGL draw it several times, using an additional buffer to select texture layer and rotation based on the drawn instance.

My triangle doesn't render when I use OpenGL Core Profile 3.2

I have a Cocoa (OSX) project that is currently very simple, I'm just trying to grasp the general concepts behind using OpenGL. I was able to get a triangle to display in my view, but when I went to write my vertex shaders and fragment shaders, I realized I was running the legacy OpenGL core profile. So I switched to the OpenGL 3.2 profile by setting the properties in the pixel format of the view in question before generating the context, but now the triangle doesn't render, even without my vertex or fragment shaders.
I have a controller class for the view that's instantiated in the nib. On -awakeFromNib it sets up the pixel format and the context:
NSOpenGLPixelFormatAttribute attr[] =
{
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
0
};
NSOpenGLPixelFormat *glPixForm = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
[self.mainView setPixelFormat:glPixForm];
self.glContext = [self.mainView openGLContext];
Then I generate the VAO:
glGenVertexArrays(1, &vertexArrayID);
glBindVertexArray(vertexArrayID);
Then the VBO:
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
g_vertex_buffer_data, the actual data for that buffer is defined as follows:
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
Here's the code for actually drawing:
[_glContext setView:self.mainView];
[_glContext makeCurrentContext];
glViewport(0, 0, [self.mainView frame].size.width, [self.mainView frame].size.height);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle
glDisableVertexAttribArray(0);
glFlush();
This code draws the triangle fine if I comment out the NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, in the NSOpenGLPixelFormatAttribute array, but as soon as I enable OpenGL Core Profile 3.2, it just displays black. Can anyone tell me what I'm doing wrong here?
EDIT: This issue still happens whether I turn my vertex and fragment shaders on or not, but here are my shaders in case it is helpful:
Vertex shader:
#version 150
in vec3 position;
void main() {
gl_Position.xyz = position;
}
Fragment shader:
#version 150
out vec3 color;
void main() {
color = vec3(1,0,0);
}
And right before linking the program, I make this call to bind the attribute location:
glBindAttribLocation(programID, 0, "position");
EDIT 2:
I don't know if this helps at all, but I just stepped through my program, running glGetError() and it looks like everything is fine until I actually call glDrawArrays(), then it returns GL_INVALID_OPERATION. I'm trying to figure out why this could be occurring, but still having no luck.
I figured this out, and it's sadly a very stupid mistake on my part.
I think the issue is that you need a vertex shader and a fragment shader when using 3.2 core profile, you can't just render without them. The reason it wasn't working with my shaders was...wait for it...after linking my shader program, I forgot to store the programID in the ivar in my class, so later when I call glUseProgram() I'm just calling it with a zero parameter.
I guess one of the main sources of confusion was the fact that I expected the 3.2 core profile to work without any vertex or fragment shaders.

Rendering 2D sprites in a 3D world?

How do I render 2D sprites in OpenGL given that I have a png of the sprite? See images as an example of the effect I'd like to achieve. Also I would like to overlay weapons on the screen like the rifle in the bottom image. Does anyone know how I would achieve the two effects? Any help is greatly appreciated.
In 3D terms, this is called a "billboard". A billboard is completely flat 2D plane with a texture on it and it always faces the camera.
See here for a pure OpenGL implementation: http://nehe.gamedev.net/data/articles/article.asp?article=19
Just about any 3D engine should be able to do them by default. Ogre3D can do it, for instance.
a) For the first case:
That's not really 2D sprites. Those men seem to be rendered as single quads with a texture with some kind of transparency (either alpha test or alpha blending).
Anyway, even a single quad can still be considered a 3D object, so for such situation you might want to treat it as one: track its translation and rotation and render it in the same way as any other 3D object.
b) For the second case:
If you want the gun (a 2D picture, I pressume) to be rendered in the same place without any perspective transformation, then you can use the same technique one uses for drawing the GUI (etc). Have a look at my post here:
2D overlay on a 3D scene
For the overlaying of the 2D weapon, you can use glOrtho for the camera view.
You create a 3d quad and map the .png-based texture to it. You can make the quad face whatever direction you want, as in the first picture, or make it always facing the camera (like a billboard, mentioned by Svenstaro) as in your second picture. Though, to be fair, I am sure that second picture just blitted the image (with some scaling) directly in the software-created framebuffer (that looks like Wolf3d tech, software rendering).
Take a look at OpenGL Point Sprites:
http://www.informit.com/articles/article.aspx?p=770639&seqNum=7
Especially useful for partical systems but may do the trick for your purposes.
Check this tutorial about billboards. I think you'll find useful.
http://www.lighthouse3d.com/opengl/billboarding/
opengl-tutorial has:
a tutorial http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/ focused on energy bars
OpenGL 3.3+ WTF licensed code that just works: https://github.com/opengl-tutorials/ogl/blob/71cad106cefef671907ba7791b28b19fa2cc034d/tutorial18_billboards_and_particles/tutorial18_billboards.cpp
Screenshot:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <GL/glew.h>
#include <glfw3.h>
GLFWwindow* window;
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/norm.hpp>
using namespace glm;
#include <common/shader.hpp>
#include <common/texture.hpp>
#include <common/controls.hpp>
#define DRAW_CUBE // Comment or uncomment this to simplify the code
int main( void )
{
// Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW\n" );
getchar();
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_RESIZABLE,GL_FALSE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
window = glfwCreateWindow( 1024, 768, "Tutorial 18 - Billboards", NULL, NULL);
if( window == NULL ){
fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Hide the mouse and enable unlimited mouvement
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Set the mouse at the center of the screen
glfwPollEvents();
glfwSetCursorPos(window, 1024/2, 768/2);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders( "Billboard.vertexshader", "Billboard.fragmentshader" );
// Vertex shader
GLuint CameraRight_worldspace_ID = glGetUniformLocation(programID, "CameraRight_worldspace");
GLuint CameraUp_worldspace_ID = glGetUniformLocation(programID, "CameraUp_worldspace");
GLuint ViewProjMatrixID = glGetUniformLocation(programID, "VP");
GLuint BillboardPosID = glGetUniformLocation(programID, "BillboardPos");
GLuint BillboardSizeID = glGetUniformLocation(programID, "BillboardSize");
GLuint LifeLevelID = glGetUniformLocation(programID, "LifeLevel");
GLuint TextureID = glGetUniformLocation(programID, "myTextureSampler");
GLuint Texture = loadDDS("ExampleBillboard.DDS");
// The VBO containing the 4 vertices of the particles.
static const GLfloat g_vertex_buffer_data[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
};
GLuint billboard_vertex_buffer;
glGenBuffers(1, &billboard_vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, billboard_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_DYNAMIC_DRAW);
#ifdef DRAW_CUBE
// Everything here comes from Tutorial 4
GLuint cubeProgramID = LoadShaders( "../tutorial04_colored_cube/TransformVertexShader.vertexshader", "../tutorial04_colored_cube/ColorFragmentShader.fragmentshader" );
GLuint cubeMatrixID = glGetUniformLocation(cubeProgramID, "MVP");
static const GLfloat g_cube_vertex_buffer_data[] = { -1.0f,-1.0f,-1.0f,-1.0f,-1.0f, 1.0f,-1.0f, 1.0f, 1.0f,1.0f, 1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f, 1.0f,-1.0f,1.0f,-1.0f, 1.0f,-1.0f,-1.0f,-1.0f,1.0f,-1.0f,-1.0f,1.0f, 1.0f,-1.0f,1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f,-1.0f,-1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f,-1.0f, 1.0f,1.0f,-1.0f, 1.0f,1.0f, 1.0f, 1.0f,1.0f,-1.0f,-1.0f,1.0f, 1.0f,-1.0f,1.0f,-1.0f,-1.0f,1.0f, 1.0f, 1.0f,1.0f,-1.0f, 1.0f,1.0f, 1.0f, 1.0f,1.0f, 1.0f,-1.0f,-1.0f, 1.0f,-1.0f,1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f,1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f,1.0f,-1.0f, 1.0f};
static const GLfloat g_cube_color_buffer_data[] = { 0.583f, 0.771f, 0.014f,0.609f, 0.115f, 0.436f,0.327f, 0.483f, 0.844f,0.822f, 0.569f, 0.201f,0.435f, 0.602f, 0.223f,0.310f, 0.747f, 0.185f,0.597f, 0.770f, 0.761f,0.559f, 0.436f, 0.730f,0.359f, 0.583f, 0.152f,0.483f, 0.596f, 0.789f,0.559f, 0.861f, 0.639f,0.195f, 0.548f, 0.859f,0.014f, 0.184f, 0.576f,0.771f, 0.328f, 0.970f,0.406f, 0.615f, 0.116f,0.676f, 0.977f, 0.133f,0.971f, 0.572f, 0.833f,0.140f, 0.616f, 0.489f,0.997f, 0.513f, 0.064f,0.945f, 0.719f, 0.592f,0.543f, 0.021f, 0.978f,0.279f, 0.317f, 0.505f,0.167f, 0.620f, 0.077f,0.347f, 0.857f, 0.137f,0.055f, 0.953f, 0.042f,0.714f, 0.505f, 0.345f,0.783f, 0.290f, 0.734f,0.722f, 0.645f, 0.174f,0.302f, 0.455f, 0.848f,0.225f, 0.587f, 0.040f,0.517f, 0.713f, 0.338f,0.053f, 0.959f, 0.120f,0.393f, 0.621f, 0.362f,0.673f, 0.211f, 0.457f,0.820f, 0.883f, 0.371f,0.982f, 0.099f, 0.879f};
GLuint cubevertexbuffer;
glGenBuffers(1, &cubevertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, cubevertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_cube_vertex_buffer_data), g_cube_vertex_buffer_data, GL_DYNAMIC_DRAW);
GLuint cubecolorbuffer;
glGenBuffers(1, &cubecolorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, cubecolorbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_cube_color_buffer_data), g_cube_color_buffer_data, GL_DYNAMIC_DRAW);
#endif
double lastTime = glfwGetTime();
do
{
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
double currentTime = glfwGetTime();
double delta = currentTime - lastTime;
lastTime = currentTime;
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
#ifdef DRAW_CUBE
// Again : this is just Tutorial 4 !
glDisable(GL_BLEND);
glUseProgram(cubeProgramID);
glm::mat4 cubeModelMatrix(1.0f);
cubeModelMatrix = glm::scale(cubeModelMatrix, glm::vec3(0.2f, 0.2f, 0.2f));
glm::mat4 cubeMVP = ProjectionMatrix * ViewMatrix * cubeModelMatrix;
glUniformMatrix4fv(cubeMatrixID, 1, GL_FALSE, &cubeMVP[0][0]);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, cubevertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, cubecolorbuffer);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );
glDrawArrays(GL_TRIANGLES, 0, 12*3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
#endif
// We will need the camera's position in order to sort the particles
// w.r.t the camera's distance.
// There should be a getCameraPosition() function in common/controls.cpp,
// but this works too.
glm::vec3 CameraPosition(glm::inverse(ViewMatrix)[3]);
glm::mat4 ViewProjectionMatrix = ProjectionMatrix * ViewMatrix;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Use our shader
glUseProgram(programID);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
// Set our "myTextureSampler" sampler to user Texture Unit 0
glUniform1i(TextureID, 0);
// This is the only interesting part of the tutorial.
// This is equivalent to mlutiplying (1,0,0) and (0,1,0) by inverse(ViewMatrix).
// ViewMatrix is orthogonal (it was made this way),
// so its inverse is also its transpose,
// and transposing a matrix is "free" (inversing is slooow)
glUniform3f(CameraRight_worldspace_ID, ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
glUniform3f(CameraUp_worldspace_ID , ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
glUniform3f(BillboardPosID, 0.0f, 0.5f, 0.0f); // The billboard will be just above the cube
glUniform2f(BillboardSizeID, 1.0f, 0.125f); // and 1m*12cm, because it matches its 256*32 resolution =)
// Generate some fake life level and send it to glsl
float LifeLevel = sin(currentTime)*0.1f + 0.7f;
glUniform1f(LifeLevelID, LifeLevel);
glUniformMatrix4fv(ViewProjMatrixID, 1, GL_FALSE, &ViewProjectionMatrix[0][0]);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, billboard_vertex_buffer);
glVertexAttribPointer(
0, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the billboard !
// This draws a triangle_strip which looks like a quad.
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
// Cleanup VBO and shader
glDeleteBuffers(1, &billboard_vertex_buffer);
glDeleteProgram(programID);
glDeleteTextures(1, &TextureID);
glDeleteVertexArrays(1, &VertexArrayID);
#ifdef DRAW_CUBE
glDeleteProgram(cubeProgramID);
glDeleteVertexArrays(1, &cubevertexbuffer);
glDeleteVertexArrays(1, &cubecolorbuffer);
#endif
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
Tested on Ubuntu 15.10.
Axis oriented version of this question: https://gamedev.stackexchange.com/questions/35946/how-do-i-implement-camera-axis-aligned-billboards Here we have done a viewpoint oriented billboard.

How to rotate an object and but leaving the lighting fixed? (OpenGL)

I have a cube which I want to rotate. I also have a light source GL_LIGHT0. I want to rotate the cube and leave the light source fixed in its location. But the light source is rotating together with my cube. I use OpenGL ES 1.1
Here's a snippet of my code to make my question more clear.
GLfloat glfarr[] = {...} //cube points
GLubyte glubFaces[] = {...}
Vertex3D normals[] = {...} //normals to surfaces
const GLfloat light0Position[] = {0.0, 0.0, 3.0, 0.0};
glLightfv(GL_LIGHT0, GL_POSITION, light0Position);
glEnable(GL_LIGHT0);
for(i = 0; i < 8000; ++i)
{
if (g_bDemoDone) break;
glLoadIdentity();
glTranslatef(0.0,0.0, -12);
glRotatef(rot, 0.0, 1.0,1.0);
rot += 0.8;
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals);
glVertexPointer(3, GL_FLOAT, 0, glfarr);
glDrawElements(GL_TRIANGLES, 3*12, GL_UNSIGNED_BYTE, glubFaces);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
eglSwapBuffers(eglDisplay, eglSurface);
}
Thanks.
Fixed in relation to what? The light position is transformed by the current MODELVIEW matrix when you do glLightfv(GL_LIGHT0, GL_POSITION, light0Position);
If you want it to move with with the cube you'll have to move glLightfv(GL_LIGHT0, GL_POSITION, light0Position); to after the translation and rotation calls.
The problem seems to be that you're rotating the modelview matrix, not the cube itself. Essentially, you're moving the camera.
In order to rotate just the cube, you'll need to rotate the vertices that make up the cube. Generally that's done using a library (GLUT or some such) or simple trig. You'll be operating on the vertex data stored in the array, before the glDrawElements call. You may/may not have to or want to modify the normals or texture coordinates, it depends on your effects and how it ends up looking.

Resources