why the drawn model is not centered in the screen - c++

I'm loading an Obj model and am trying to draw it like this :
void Game::Update()
{
glViewport(0, 0, 800, 600);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(Color::CornflowerBlue.R, Color::CornflowerBlue.G, Color::CornflowerBlue.B, Color::CornflowerBlue.A);
gluPerspective(45.0, 800.0 / 600.0, 1.0, 1000.0);
DrawModel(model);
}
void DrawModel(const Model &model)
{
for (size_t i = 0; i < model.Faces.size(); i++)
{
if (model.Materials.size() > 0)
{
float diffuse[] = { model.Materials[model.Faces[i].Material].Diffuse[0], model.Materials[model.Faces[i].Material].Diffuse[1], model.Materials[model.Faces[i].Material].Diffuse[2], 1.0 };
float ambient[] = { model.Materials[model.Faces[i].Material].Ambient[0], model.Materials[model.Faces[i].Material].Ambient[1], model.Materials[model.Faces[i].Material].Ambient[2], 1.0 };
float specular[] = { model.Materials[model.Faces[i].Material].Specular[0], model.Materials[model.Faces[i].Material].Specular[1], model.Materials[model.Faces[i].Material].Specular[2], 1.0 };
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialf(GL_FRONT, GL_SHININESS, model.Materials[model.Faces[i].Material].Ns);
glColor3f(diffuse[0], diffuse[1], diffuse[2]);
}
int loop = 3;
if (model.Faces[i].IsQuad){
loop = 4;
glBegin(GL_QUADS);
}
else
glBegin(GL_TRIANGLES);
if (model.NormalVertices.size() > 0)
glNormal3f(model.NormalVertices.at(model.Faces[i].Index).X, model.NormalVertices.at(model.Faces[i].Index).Y, model.NormalVertices.at(model.Faces[i].Index).Z);
for (int j = 0; j < loop; j++)
{
//TODO TEXTURE:
if (model.Vertices.size() > 0)
glVertex3f(model.Vertices[model.Faces[i].VerticesIndex[j]].X, model.Vertices[model.Faces[i].VerticesIndex[j]].Y, model.Vertices[model.Faces[i].VerticesIndex[j]].Z);
}
glEnd();
}
}
but I can't see it , because it's not centered in the screen , I know that I can translate it's coordinates , but I want it to show the model in the center without translating how is that possible?

Try gluLookAt() to place the "camera" and tell it where to look at.
You always translate the models to make them visible on screen because only the geometry rendered in the unit cube gets drawn to screen. Using gluLookAt() and gluPerspective() only generates fitting matrices to translate the geometry in the defined frustum to the unit cube.
It seems like you are learning OpenGL. If that is the case I would recommend not learning the old (<3.0) way with glBegin(GL_TRIANGLES) etc. but learn the new (>=3.0) OpenGL version, with VertexArrayObjects and the like, right away. For a start I can recommend this site: OpenGL Tutorials

Related

Adjusting light source size

I am currently trying to position a light starting from the bottom left of my screen and illuminating towards the center of my screen but my light source does not appear circular (light does not seem to be coming from a single point).
After moving the light source it shines on the entire object but the desired effect is for the lightsource to only shine (based on a point) towards the right.
void init()
{
camPos[0]= -(size/2)*.1;
camPos[1]= size*.1;
camPos[2]= -(size/2)*.1;
zoom = size/10;
glClearColor(0,0,0,0);
glColor3f(1, 1, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//Enable backface culling
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
//Enable Lighting
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
light_pos[0] = 1;
light_pos[1] = 10;
light_pos[2] = 1;
light_pos[3] = 1;
gluPerspective(45, 1, 1, 100);
};
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Camera
radians = float(pi*(angle-90.0f)/180.0f);
//initialize look
look[0] = (size/2)*.1;
look[1] = 1;
look[2] = (size/2)*.1;
camPos[0] = look[0] + sin(radians)*zoom;
camPos[1] = size/10;
camPos[2] = look[2] + cos(radians)*zoom;
gluLookAt(camPos[0], camPos[1], camPos[2], look[0],look[1],look[2], 0,1,0);
//lighting
//glColor3f(1,1,1);
float m_amb[] = {0.2, 0.2, 0.2, 1.0};
float m_dif[] = {1, 1, 1, 1.0};
float m_spec[] = {1, 1, 1, 1.0};
float shiny = 27;
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, m_amb);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m_dif);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m_spec);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shiny);
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
glShadeModel(GL_SMOOTH);
drawTerrain(terrainA, size);
glutSwapBuffers();
};
int main (int argc, char** argv)
{
srand(time(NULL));
//When program starts enter value
printf("Enter an int between 50 and 300: ");
scanf("%i",&size);
if ( size < 50 || size > 300){
printf("Invalid size! Please re-run \n");
return 0;
}
populateArray();
//Starts glut
glutInit(&argc, argv);
//Init display
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 800);
glutInitWindowPosition(600, 100);
glutCreateWindow("Terrain");glEnable(GL_DEPTH_TEST);
//Registering Callbacks
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutSpecialFunc(special);
glEnable(GL_DEPTH_TEST);
init();
glutMainLoop();
return 0;
};
The general practic is to define light attenuation factors as a coeficients of light equation.
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.5);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.5);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.2);
where kc is constant attenuation factor, kl - linear attenuation factor, kq - quadratic attenuation factor, d - distance to light source. You can modify this coeficients to achive the effect you want.
This example could not works correctly so I suggest to build your own light destribution function using shaders, it will be simple to achive desired effect and more effective (and will always work).

GluPerspective acting strange

I'm trying to change the field of view in my scene when touching F2 and F3.
For this I have in my specialKey function this:
void specialKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_F2:
changeFOV = true;
fovScale = 0.05;
break;
case GLUT_KEY_F3:
changeFOV = true;
fovScale = -0.05;
break;
}
I have a timed function that call myDisplay each milisecond and in that function I do:
if(changeFOV){
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
fovAngle += fovScale;
gluPerspective(fovAngle, screenWidth/screenHeight, 2, 200);
glTranslatef(camera.x, camera.y, camera.z);
glMatrixMode(GL_MODELVIEW);
changeFOV = false;
}
Now the first time I press F2 or F3, the scene gets small to the size of one pixel (aprox) but if I keep pressing F3 the scene gets closer and closer and then it works correctly (F2 and F3).
fovAngle is 60.0f at the beginning (The scene looks good without pressing F2 or F3).
This is my init() function:
void init() {
glInitNames();
gluPerspective(fovAngle, screenWidth/screenHeight, 2, 200);
glTranslatef(camera.x, camera.y, camera.z);
glClearColor(0, 0, 0, 1);
glViewport(0.0, 0.0, screenWidth, screenHeight);
glutInitWindowSize(screenWidth, screenHeight);
string windowName = "AMAZING 3D MODELING - ";
windowName += (sceneMode ? "Scene" : "Camera");
glutCreateWindow(windowName.c_str());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glMaterialfv(GL_FRONT, GL_AMBIENT, object_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, object_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, object_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, object_shine);
glutDisplayFunc(displayFunc);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutSpecialFunc(specialKey);
glutKeyboardFunc(keyboard);
glutTimerFunc(2, idle, 1);
glutMainLoop();
}
Any thoughts?
(if more code is needed please ask and I will edit the question)
The main problem is that you're calling GL functions before you have an OpenGL context. The context is created as part of glutCreateWindow(), so all your OpenGL calls, like your whole initial projection setup, need to be moved after glutCreateWindow().
You also seem to be missing a call to glutInit(), which should be at the very start. I'm surprised that your code works at all without it.
The camera translation should normally be in modelview matrix mode. It won't change the resulting position of your geometry, but the lighting will be wrong otherwise.
The reason this behaves the way it does is most likely that your camera is very far away. Since the projection/camera is not set up on the initial rendering, it is not applied, and the geometry appears. Then the first time the projection/camera are applied, everything gets very small because you're looking at it from very far away. Then, as you make the FOV smaller, the size of the geometry increases.
So what you need to do is:
Add call to glutInit() at the start.
Move all initialization calls after glutCreateWindow().
Set camera translation in modelview mode.
Move camera closer.
I would put the transformation setup in a function that you can call both at init time, and when it changes. The function would contain something like this:
void setTransformations() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fovAngle, screenWidth/screenHeight, 2, 200);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(camera.x, camera.y, camera.z);
}
Then you call it during init:
glutCreateWindow(...);
setTransformations();
and when the FOV changes:
if (changeFOV) {
fovAngle += fovScale;
changeFOV = false;
setTransformations();
}

Bad lighting behaviour (fixed pipeline)

I'm trying to render an object (say cube) with OpenGL 1.1 (I know that doesn't makes sense nowadays, but I've to use this). Everything works fine until I try some lighting.
Here's the problem:
The Global variable set are:
static GLfloat light_position[] = {1.0, 1.0, 2*cZ.x , 0.0};
// cZ.x is the minimum z of the mesh. I know
// this is at infinity, but don't work also with w=1.0
In the main function:
...
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
....
Drawing a mesh k
// While drawing mesh k
GLfloat light_ambient[] = {COLOUR[k][0], COLOUR[k][1], COLOUR[k][2], 1.0};
GLfloat light_diffuse[] = {COLOUR[k][0], COLOUR[k][1], COLOUR[k][2], 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
....
//This is a mesh, so will be drawn using triangles
glBegin(GL_TRIANGLES);
//Triangles will be defined by vertex indices in faces
for (unsigned int i = 0; i<mesh->faces.size(); i++){
int index1 = mesh->faces.at(i).x;
int index2 = mesh->faces.at(i).y;
int index3 = mesh->faces.at(i).z;
glNormal3f(mesh->normals.at(i).x,mesh->normals.at(i).y,mesh->normals.at(i).z);
glVertex3f(mesh->vertices.at(index1).x, mesh->vertices.at(index1).y, mesh->vertices.at(index1).z);
glVertex3f(mesh->vertices.at(index2).x, mesh->vertices.at(index2).y, mesh->vertices.at(index2).z);
glVertex3f(mesh->vertices.at(index3).x, mesh->vertices.at(index3).y, mesh->vertices.at(index3).z);
}
glEnd();
....
Whereas the normal are computed as:
glm::vec3 currFace = m->faces.at(faceIndex);
glm::vec3 vert1 = m->vertices.at(currFace.x);
glm::vec3 vert2 = m->vertices.at(currFace.y);
glm::vec3 vert3 = m->vertices.at(currFace.z);
glm::vec3 side1 = (vert2 - vert1);
glm::vec3 side2 = (vert3 - vert1);
glm::vec3 normal = glm::cross(side1, side2);
normal = glm::normalize(normal);
I'm really struggling to understand what's wrong, can you point me in the right direction?
EDIT: This happens similarly with the standford bunny (taken from standford repo, so it's well formed)
http://imgur.com/Z6225QG
Looking at your normals picture it looks like that more than not being shaded, some of your object faces are transparent.
I used to have a similar problem while learning OpenGL, in my case I forgot to enable DEPTH_TEST. You can do it simply adding this line to your GL init function function:
glEnable(GL_DEPTH_TEST);
Give it a try

How do I exactly update an objects position in OpenGL using Qt's QGLWidget?

I'm trying to move a cube drawn wit OpenGL in a QGLWidget. Here is part of the code:
void Hologram::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawBox();
}
void Hologram::drawBox() {
for (int i = 0; i < 6; i++) {
glBegin(GL_QUADS);
glNormal3fv(&n[i][0]);
glVertex3fv(&v[faces[i][0]][0]);
glVertex3fv(&v[faces[i][1]][0]);
glVertex3fv(&v[faces[i][2]][0]);
glVertex3fv(&v[faces[i][3]][0]);
glEnd();
}
qDebug() << "drawing box";
}
void Hologram::initializeGL() {
/* Enable a single OpenGL light. */
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
/* Use depth buffering for hidden surface elimination. */
glEnable(GL_DEPTH_TEST);
/* Setup the view of the cube. */
glMatrixMode(GL_PROJECTION);
gluPerspective( /* field of view in degree */ 40.0,
/* aspect ratio */ 1.0,
/* Z near */ 1.0, /* Z far */ 10.0);
glMatrixMode(GL_MODELVIEW);
// qDebug() << "vx:" << vx << "vy:" << vy << "vz:" << vz;
gluLookAt(0.0, 0.0, 5.0, // eye position
0.0, 0.0, 0.0, // center
0.0, 1.0, 0.); // up vector
// Adjust cube position
glTranslatef(0.0, 0.0, -1.0);
}
void Hologram::animate() {
glTranslatef(0.0, 0.0, -0.1);
updateGL();
}
I've implemented a timer that periodically calls animate() via a signal&slot connection. Shouldn't it add -0.1 to the z-coordinate every time when animate() is executed and therefore move the cube in z-direction? Depending on the value I choose, the cube is either not moving (for values approx. <-0.3) or I cannot see it at all (values approx. >0.4). First I thought it either might move very fast and disappear or it moves very slow and therefore I couldn't see any changes. But playing around with z value always ended up in one of the above mentioned cases... Isn't that strange? What am I doing wrong?
Problem solved: The correct way to do it is
void Hologram::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0, 0.0, -dz);
drawBox();
}
The reason why I got the strange behaviour described above is due to the fact that the object was clipped by the near/far planes of the perspective set with gluPerspective()...

openGL - how to rotate an object without rotating lights

i want to draw a rotating cube in the middle of the screen, and i want it to be lit by a light above it (i want it to look as if the cube was being lit from a fixed screen position). my problem is that i don't know how to prevent the light from rotating with the cube.
here's the code:
(SUMMARY: initGL, paintGL, and resizeGl are the functions that you always have to implement. in paintGL i use makeCube(). in makeCube() i use glBegin(GL_QUADS) to make a cube,and i use calcNormals() to calculate the normals of the cube )
-------------initGL--------------------------
angle=0.0;
glEnable (GL_DEPTH_TEST);
glEnable (GL_LIGHTING);
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 0.0f, 1.5f,1.5f, 1.0f };
glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT0, GL_POSITION,LightPosition);
glEnable (GL_LIGHT0);
--------------paintGL------------------
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -13.0);
glRotatef(angle,0.0f,1.0f,0.0f);
makeCube();
angle+=0.3;
--------------void makeCube()-------------------
float P[8][3]={ {-1,-1, 1},{1,-1, 1},{1,1, 1},{-1,1, 1},
{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1}};
float * planes[6][4] ={ {P[0],P[1],P[2],P[3]},
{P[1],P[5],P[6],P[2]},
{P[4],P[7],P[6],P[5]},
{P[0],P[3],P[7],P[4]},
{P[3],P[2],P[6],P[7]},
{P[0],P[4],P[5],P[1]}};
int i;
for(i=0;i<6;i++){
float *normal;
normal = calcNormal(planes[i][0],planes[i][1],planes[i][2]);
glBegin(GL_QUADS);
glNormal3f(normal[0], normal[1], normal[2]);
glVertex3f(planes[i][0][0],planes[i][0][1],planes[i][0][2]);
glVertex3f(planes[i][1][0],planes[i][1][1],planes[i][1][2]);
glVertex3f(planes[i][2][0],planes[i][2][1],planes[i][2][2]);
glVertex3f(planes[i][3][0],planes[i][3][1],planes[i][3][2]);
glEnd();
}
----------------float* calcNormal()----------------------
float vec1[3] = {P2[0]-P1[0],P2[1]-P1[1],P2[2]-P1[2]};
float vec2[3] = {P3[0]-P2[0],P3[1]-P2[1],P3[2]-P2[2]};
float cross[3] = {vec1[1]*vec2[2]-vec2[1]*vec1[2],
vec1[2]*vec2[0]-vec2[2]*vec1[0],
vec1[0]*vec2[1]-vec2[0]*vec1[1]};
float modCross = sqrt(cross[0]*cross[0]+cross[1]*cross[1]+cross[2]*cross[2]);
cross[0]/=modCross;
cross[1]/=modCross;
cross[2]/=modCross;
return cross;
-------------resizeGL--------------------------
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLfloat x = GLfloat(width) / height;
glFrustum(-x, +x, -1.0, +1.0, 4.0, 15.0);
glMatrixMode(GL_MODELVIEW);
It seems that you're transforming the position of the light in your paintGL section.
Looking over old code, I found an app in my code directory that loads and rotates .OBJ meshes, while allowing the light to be moved.
I think that the solution is to set the position of the light each frame. (Can't remember it's been over 18 months since I touched the project)
void idleFunc()
{
light(); /// *** I think you need to replicate this functionality ****
glPushMatrix();
myGluLookAt(0.0, -.50, -6.0, /* eye is at (0,0,5) */
0.0, 0.0, 0.0, /* center is at (0,0,0) */
0.0, 1.0, 0.); /* up is in positive Y direction */
transformFunc();
displayFunc();
glPopMatrix();
}
void displayFunc()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (useDrawList)
glCallList(DLid);
else
drawObj(loadedObj);
drawLight0(); // *** just displays an unlit sphere at the position of the light **
glutSwapBuffers();
frameCount++;
}
/* set the poition of each of the lights */
void light()
{
glLightfv(GL_LIGHT0, GL_POSITION, lightPos1);
glLightfv(GL_LIGHT1, GL_POSITION, lightPos2);
}
i solved this problem drawing the cube with VERTEX ARRAYS rather than DIRECT MODE, it seems that rotations or lights affect the object in a different way with each method, which is quite weird