Example with camera glm / OpenGL immediate mode - opengl

I can't get the camera transforms to work with glm...
Probably just a silly thing I missed but I just can't find it... help?
glViewport(0, 0, m_width, m_height);
glClearColor(0.5f, 0.5f, 1.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float fovy = 60.0f;
float aspect = m_width / float(m_height);
float znear = 0.1f;
float zfar = 100.0f;
glm::mat4 Mp = glm::perspective(fovy, aspect, znear, zfar);
glMultMatrixf(&Mp[0][0]);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glm::vec3 eye = glm::vec3(5, 5, 5);
glm::vec3 lookat = glm::vec3(0, 0, 0);
glm::vec3 up = glm::vec3(0, 1, 0);
glm::mat4 M = glm::lookAt(eye, lookat, up);
glMultMatrixf(&M[0][0]);
glBegin(GL_TRIANGLES);
glColor3f(1, 1, 1);
glVertex3f(-10,-10,-10);
glVertex3f(10,-10,-10);
glVertex3f(10, 10,-10);
glColor3f(1, 1, 0);
glVertex3f(-10,-10,-10);
glVertex3f(10, 10,-10);
glVertex3f(-10, 10,-10);
glEnd();
This gives the following output:
m_width = 1024, m_heigth = 768

Compared to gluPerspective, the unit of the angle argument of glm::perspective is Radian. Use glm::radians o convert from degrees to radians:
glm::perspective(fovy, aspect, znear, zfar);
glm::perspective(glm::radians(fovy), aspect, znear, zfar);
Instead of glLoadIdentity followed by glMultMatrixf you can use glLoadMatrixf.
In addition, you can use glm::value_ptr to get a pointer to the matrix fields:
float fovy = 60.0f;
float aspect = m_width / float(m_height);
float znear = 0.1f;
float zfar = 100.0f;
glm::mat4 Mp = glm::perspective(glm::radians(fovy), aspect, znear, zfar);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(glm::value_ptr(Mp));
glm::vec3 eye = glm::vec3(5, 5, 5);
glm::vec3 lookat = glm::vec3(0, 0, 0);
glm::vec3 up = glm::vec3(0, 1, 0);
glm::mat4 M = glm::lookAt(eye, lookat, up);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(glm::value_ptr(M));

Related

Using GLM with GTK to make simple 3D drawing

I am jus trying to draw a 3D Cartesian axis to see if I can get 3D to work. I am using GTK with Cairo to do the drawing. Here is my code...
glm::vec3 camera_pos(0, 0, -10);
glm::vec3 camera_target(0, 0, 0);
glm::vec3 up(0, 1, 0);
gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data)
{
guint width, height;
width = gtk_widget_get_allocated_width(widget);
height = gtk_widget_get_allocated_height(widget);
glm::mat4 model = glm::translate(glm::vec3(width / 2.0f, height / 2.0f, 0.0f)) *
glm::scale(glm::vec3(100.0f, 100.0f, 100.0f));
glm::mat4 camera = glm::lookAt(camera_pos, camera_target, up);
glm::mat4 perspective = glm::perspective(45.0f, (float)width / (float)height, 0.1f, 100.0f);
glm::mat4 transform = perspective * camera * model;
glm::vec4 xaxis = transform * glm::vec4(1, 0, 0, 1);
glm::vec4 yaxis = transform * glm::vec4(0, 1, 0, 1);
glm::vec4 zaxis = transform * glm::vec4(0, 0, 1, 1);
glm::vec4 orig = transform * glm::vec4(0, 0, 0, 1);
cout << orig.x << " " << orig.y << endl;
cairo_set_source_rgb(cr, 1.0, 0, 0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, xaxis.x, -xaxis.y);
cairo_stroke(cr);
cairo_set_source_rgb(cr, 0, 1.0, 0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, yaxis.x, -yaxis.y);
cairo_stroke(cr);
cairo_set_source_rgb(cr, 0, 0, 1.0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, zaxis.x, -zaxis.y);
cairo_stroke(cr);
return FALSE;
}
Can someone check the math here because I am getting a lot of negative coordinates. Nothing appears on my screen when I run this.
Edit:
I just modified my camera vectors like this.
gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data)
{
guint width, height;
width = gtk_widget_get_allocated_width(widget);
height = gtk_widget_get_allocated_height(widget);
glm::vec3 camera_pos(0, 0, 1000);
glm::vec3 camera_target(width / 2.0f, height / 2.0f, 0);
glm::vec3 up(0, 1, 0);
glm::mat4 model = glm::translate(glm::vec3(width / 2.0f, height / 2.0f, 0.0f));// *
//glm::scale(glm::vec3(100.0f, 100.0f, 100.0f));
glm::mat4 camera = glm::lookAt(camera_pos, camera_target, up);
glm::mat4 perspective = glm::perspective(45.0f, (float)width / (float)height, 0.1f, 100.0f);
glm::mat4 transform = perspective * camera * model;
glm::vec4 xaxis = transform * glm::vec4(100, 0, 0, 1);
glm::vec4 yaxis = transform * glm::vec4(0, 100, 0, 1);
glm::vec4 zaxis = transform * glm::vec4(0, 0, 100, 1);
glm::vec4 orig = transform * glm::vec4(0, 0, 0, 1);
cout << xaxis.x << " " << xaxis.y << endl;
cairo_set_source_rgb(cr, 1.0, 0, 0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, xaxis.x, -xaxis.y);
cairo_stroke(cr);
cairo_set_source_rgb(cr, 0, 1.0, 0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, yaxis.x, -yaxis.y);
cairo_stroke(cr);
cairo_set_source_rgb(cr, 0, 0, 1.0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, zaxis.x, -zaxis.y);
cairo_stroke(cr);
return FALSE;
}
Now I can see a blue line from the corner of my screen but it is still wrong.
You are using a perspective projection, but you do not carry out the persepctive divide, which will totally screw up your results. glm::perspective will create a matrix which maps the viewing frustum with the given angle and apsect ratio along the negative z axis to a [-w,w]^3 "cube" in clip space. After the perspective divide by the w coordinate, the viewing frustum will be [-1,1]^3 in normalized device coords. Usually at this stage, the coordinates are further converted into window space, where the actual pixels come into play.
In your case, you seem to try to incorporate the window resolution in the model transform at the start of the transform chain, which is totally weird if you later apply a standard GL projection matrix.

object drawing order in OpenGL

I created a sphere floating above a ground. The sphere is centered around (0,0,0). I have set up a camera with a twist, elevation, azimuth as well as moving in closer and farther from the sphere. The problem I have is that the sphere is always drawn on top of the ground. For example, if I move the camera below the ground I should see the ground be drawn on top of the sphere but that's not the case. Here are my ground and draw functions.
void init_ground()
{
GLfloat x = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
GLfloat z = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
for(int i=0; i<NUM_GROUND_LINES*2; i += 2)
{
GLfloat x = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(-x, -4.0, z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
z += 1.0;
}
for(int i=NUM_GROUND_LINES*2; i<NUM_GROUND_LINES*4; i += 2)
{
GLfloat z = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(x, -4.0, -z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
x += 1.0;
}
}
glm::vec3 cameraPos = glm::vec3(0.0, 0.0, 3.0);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
void draw()
{
glm::mat4 view;
glm::mat4 projection;
glm::mat4 model;
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
view = glm::rotate(view, glm::radians(GLfloat(twist)), glm::vec3(0.0, 0.0, 1.0));
view = glm::rotate(view, glm::radians(GLfloat(elevation)), glm::vec3(1.0, 0.0, 0.0));
view = glm::rotate(view, glm::radians(GLfloat(azimuth)), glm::vec3(0.0, 0.0, 1.0));
projection = glm::perspective(45.0f, (GLfloat)WIDTH/(GLfloat)HEIGHT, 0.1f, 100.0f);
glUseProgram(program_ground);
GLint ground_proj_loc = glGetUniformLocation(program_ground, "projection");
GLint ground_view_loc = glGetUniformLocation(program_ground, "view");
GLint ground_model_loc = glGetUniformLocation(program_ground, "model");
glUniformMatrix4fv(ground_proj_loc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(ground_view_loc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(ground_model_loc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(vao_ground);
glDrawArrays(GL_LINES, 0, NUM_GROUND_LINES*2*4);
glBindVertexArray(0);
glUseProgram(program_sphere);
GLint sphere_model_loc = glGetUniformLocation(program_sphere, "model");
GLint sphere_view_loc = glGetUniformLocation(program_sphere, "view");
GLint sphere_proj_loc = glGetUniformLocation(program_sphere, "projection");
glUniformMatrix4fv(sphere_view_loc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(sphere_proj_loc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(sphere_model_loc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(vao_sphere);
glDrawArrays(GL_LINE_LOOP, 0, 342);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
To be able to remove hidden superficies, you need to enable the Depth Test.
To do that, first you must ask, at the context creation time, a buffer to store the relative z positional value of a vertex, in relation to the camera. If you are using GLFW library, this creation is done automatically.
The second step is to enable the depth test itself. To do that, you need to call:
glEnable(GL_DEPTH_TEST);
somewhere before you call your draw functions.
And, at last, at every frame draw, you must clear you depth buffer, calling:
glClear(GL_DEPTH_BUFFER_BIT);
but usually it is called as:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
to clear the color buffer as well.

OpenGL: Fish-eyes effect and how to avoid this

I'm trying to model the Solar System and I'm experiencing the Fish-eyes effects.
As you can see from the picture, the sun is at the centre, the Earth is translated 20 units to the x-axis and it doesn't look like a sphere anymore.
In glm::lookAt function, I set the field of view (is this FoVx?, I read from wiki, this is horizontal field of view so I think this is FoVx.) to be 80 degree, aspect ratio is 5.4f / 3.0f (most of application set the aspect ratio to be 4/3 but if I use this ratio, these planets look exactly like an ellipse!).
So how can I solve this problem? As the Earth would be orbiting around the Sun, and it should be always be a sphere at any angle and distance of view. Maybe I haven't completely understand the perspective, view matrix etc. Really need some help.
Here is the code which I used to render the Sun and the Earth:
void renderSun(int i){
glPushMatrix();
glLoadIdentity();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_ID[0]);
glUniform1i(texture_Location, 0);
glm::mat4 Projection = glm::perspective(90.0f, 5.4f / 3.0f, 1.0f, 100.0f);
glm::mat4 View = glm::lookAt(
glm::vec3(0, 30, 1),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
/* Animations */
GLfloat angle = (GLfloat) (i);
//View = glm::translate(View, glm::vec3(-2.0f, 0.0f, 0.0f));
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f));
/* ******* */
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
glDrawElements(GL_TRIANGLES, numsToDraw, GL_UNSIGNED_INT, NULL);
glPopMatrix();
}
void renderEarth(int i){
glPushMatrix();
glLoadIdentity();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_ID[3]);
glUniform1i(texture_Location, 0);
//glm::mat4 Projection = glm::ortho(0.f, 800.f, 0.f, 400.f, -5.f, 5.f );
glm::mat4 Projection = glm::perspective(80.0f, 5.4f / 3.0f, 1.0f, 100.0f);
glm::mat4 View = glm::lookAt(
glm::vec3(0, 30, 2),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
/* Animations */
GLfloat angle = (GLfloat) (i);
View = glm::translate(View, glm::vec3(30.0f, 0.0f, 0.0f));
//View = glm::scale(View, glm::vec3(4.0f, 5.0f, 4.0f));
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f));
/* ******* */
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
glDrawElements(GL_TRIANGLES, numsToDraw, GL_UNSIGNED_INT, NULL);
glPopMatrix();
}

OpenGL: Orbiting with Orthogonal projection

I'm modelling the solar system and testing the orbit of the Earth around the Sun, using orthogonal projection.
The starting point of the Earth is to the right of the Sun, direction of moving is to the left hand side. But the Earth is not completely rendered when it is in front of the Sun and when go further behind the Sun, as you can see from 3 images below:
Starting point:
Next frame:
Final frame:
Can some one explain what exactly happening here? I think this is the cull face problem, I tried:
glEnable(GL_CULL_FACES);
glCullFace(GL_FRONT);
It doesn't work actually.
This is my code:
// global vars
int width = 1820, height = 960;
#define CENTRE_X static_cast<float>(width/2)
#define CENTRE_Z static_cast<float>(-height/2)
#define EARTH_SIZE glm::vec3(30.0f, 40.0f, 30.0f)
#define SUN_SIZE EARTH_SIZE*3.0f
void renderSun(int i){
glPushMatrix();
glLoadIdentity();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_ID[0]);
glUniform1i(texture_Location, 0);
glm::mat4 Projection = glm::ortho(0.0f, static_cast<float>(width), 0.0f, static_cast<float>(height), 0.0f, 100.0f);
glm::mat4 View = glm::lookAt(
glm::vec3(0, 120, 1),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
/* Animations */
GLfloat angle = (GLfloat) (i);
View = glm::translate(View, glm::vec3(static_cast<float>(width/2), 0.0f, static_cast<float>(-height/2)));
View = glm::scale(View, SUN_SIZE);
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f));
/* ******* */
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
glDrawElements(GL_TRIANGLES, numsToDraw, GL_UNSIGNED_INT, NULL);
glPopMatrix();
}
void renderEarth(int i){
glPushMatrix();
glLoadIdentity();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_ID[3]);
glUniform1i(texture_Location, 0);
glm::mat4 Projection = glm::ortho(0.0f, static_cast<float>(width), 0.0f, static_cast<float>(height), 0.0f, 100.0f);
glm::mat4 View = glm::lookAt(
glm::vec3(0, 150, 1),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
/* Animations */
GLfloat angle = (GLfloat) (i);
View = glm::translate(View, glm::vec3(cos(orbitPos)*150, sin(orbitPos)*150, 0.0f));
View = glm::translate(View, glm::vec3(CENTRE_X, 0.0f, CENTRE_Z));
View = glm::scale(View, EARTH_SIZE);
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f));
/* ******* */
glm::mat4 Model = glm::mat4(1.0f);
orbitPos += 0.005;
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
glDrawElements(GL_TRIANGLES, numsToDraw, GL_UNSIGNED_INT, NULL);
glPopMatrix();
}
You are using inconsistent View matrices, your code is essentially rotating the view of the earth, which causes it to move relative to the sun. This is very unusual way to do things, and is probably the cause of your problems. It is (presumably) causing the models to collide in clip space, and intersect with one another. You should instead use the same View matrix for both, and modify the Model matrix for the earth model. Keeping the renderSun method the same, you could do this by modifying renderEarth:
void renderEarth(int i){
//...
/* Animations */
GLfloat angle = (GLfloat) (i);
glm::mat4 M0 = glm::translate(View, glm::vec3(cos(orbitPos)*150, sin(orbitPos)*150, 0.0f));
glm::mat4 M1 = glm::translate(View, glm::vec3(CENTRE_X, 0.0f, CENTRE_Z));
glm::mat4 M2 = glm::scale(View, EARTH_SIZE);
glm::mat4 M3 = glm::rotate(View, angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f));
/* ******* */
orbitPos += 0.005;
glm::mat4 MVP = Projection * View * M3 * M2 * M1 * M0;
// ...

OpenGL texture not displayed (solid color instead texture) or displayed with artifacts

I'm using code to draw text as textures in OpenGL (Qt4.8.3 + Linux (debian-like)).
Code was ported from 2D project, where it is working good.
2D project was using gluOrtho2D, now I use gluLookAt for 3D.
The issue is that instead of text I'm seing colored rectangle.
If I turn on GL_DEPTH_TEST I see artifacts instead of text. BTW artifacts change if I move camera, which is quite strange.
Here's the code:
void GLWidget::paintGL() {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //Set blending function.
glEnable(GL_BLEND); //Enable blending.
glShadeModel(GL_SMOOTH);
glEnable(GL_MULTISAMPLE);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60.0f, (GLdouble) width() / (GLdouble) height(), 0.001f, 10000.0f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
// Set up current camera
gluLookAt( cameraDistance * sin(cameraTheta * M_PI / 180) * cos(cameraPhi * M_PI / 180),
cameraDistance * sin(cameraTheta * M_PI / 180) * sin(cameraPhi * M_PI / 180),
cameraDistance * cos(cameraTheta * M_PI / 180),
0.0, 0.0, 0.0,
0.0, 0.0, 1.0);
glTranslatef(-4.5355, -4.5355, 0.0);
glPushMatrix();
// draw text labels
drawLabel(1, 0, 90, "1");
drawLabel(2, 0, 90, "2");
drawLabel(3, 0, 90, "3");
drawLabel(4, 0, 90, "4");
drawLabel(5, 0, 90, "5");
glPopMatrix();
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glPopMatrix();
}
void GLWidget::drawLabel(float xpos, float ypos, float angle, char *txt) {
float labelHeight = 0.3;
float labelWidth = labelHeight / 2;
float margin = labelWidth / 10;
float len = (float) strlen(txt);
glPushMatrix();
glRotatef(-angle, 0, 0, -1);
glTranslatef(xpos, ypos, 0.0f);
glRotatef(angle, 0, 0, -1);
glScalef(1.0, -1.0, 1.0);
glTranslatef(- len * labelWidth / 2, -labelHeight / 2 + margin, 0.0f);
// background
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_QUADS);
glVertex3f(-margin, -margin, 0);
glVertex3f(len * labelWidth + margin, -margin, 0);
glVertex3f(len * labelWidth + margin, labelHeight + margin, 0);
glVertex3f(-margin, labelHeight + margin, 0);
glEnd();
// text
glColor3f(0.5f, 0.5f, 0.5f);
glEnable(GL_TEXTURE_2D);
glBindTexture( GL_TEXTURE_2D, glFont->getTextureID() );
glFont->drawText(labelWidth, labelHeight, txt);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
void oglFont::drawText(GLfloat cw, GLfloat ch, char *txt)
{
glBegin(GL_QUADS);
//character location and dimensions
GLfloat cx = 0.0f;
GLfloat cy = 0.0f;
//calculate how wide each character is in term of texture coords
GLfloat dtx = float(c_width) / float(m_width);
GLfloat dty = float(c_height) / float(m_height);
for (char * c = txt; *c != 0; c++, cx += cw) {
int index = getCharIndex(c);
int row = index / c_per_row;
int col = index % c_per_row;
if (index < 0) {
//qDebug() << "glFont: Character outside of font! char: " << c;
}
// find the texture coords
GLfloat tx = float(col * c_width) / float(m_width);
GLfloat ty = float(row * c_height) / float(m_height);
glTexCoord2f(0, 0);
glVertex2f(cx, cy);
glTexCoord2f(1, 0);
glVertex2f(cx + cw, cy);
glTexCoord2f(1, 1);
glVertex2f(cx + cw, cy + ch);
glTexCoord2f(0, 1);
glVertex2f(cx, cy + ch);
}
glEnd();
}
The reason for the artifacts is Z fighting.
This problem can be solved by increasing the depth buffer precision OR by making the different objects further apart from each-other (the ones from drawlable ).
Also make sure that your generated text doesn't get culled by the far plane / near plane (maybe you generate the geometry very near the edges ? ).
It turns out that because texture was loaded in QGLWidget constructor, context was either not created or not set.
I moved texture loading in initializeGL() method and it works great.