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
Related
In OpenGL's fixed pipeline, by default, specifying vertex coordinates using glVertex3f is equivalent to specifying a location between -1.0 and +1.0 in screen space. Therefore, given a set of 4 perfectly adjacent screen-space vertices using GL_TRIANGLE_STRIP (or even GL_QUADS), and unless your window is already perfectly square, you will always render a rectangle instead of a perfect square...
Knowing the width, height and aspect ratio of a window, is there some way to correct this?
I have tried multiplying the vertex coordinates by the aspect ratio, which unfortunately seemed to achieve the same visual effect.
Here's the full source code I'm currently using:
#include "main.h"
#pragma comment(lib, "glut32.lib")
int g_width = 800;
int g_height = 600;
int g_aspectRatio = double(g_width) / double(g_height);
bool g_bInitialized = false;
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0, 0);
glutInitWindowSize(g_width, g_height);
glutCreateWindow("OpenGL Test App");
glutDisplayFunc(onRender);
glutReshapeFunc(onSize);
glutIdleFunc(onRender);
glutMainLoop();
return 0;
}
void onInit()
{
glFrontFace(GL_CW);
}
void onRender()
{
if(!g_bInitialized)
onInit();
static float angle = 0.0f;
const float p = 0.5f * g_aspectRatio;
glLoadIdentity();
gluLookAt(
0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f
);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glScalef(1, -1, 1); // Flip the Y-axis
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLE_STRIP);
{
glColor4f(1.0, 0.0, 0.0, 1.0); // Red
glVertex3f(-p, -p, 0.0); // Top-Left
glColor4f(0.0, 1.0, 0.0, 1.0); // Green
glVertex3f(p, -p, 0.0); // Top-Right
glColor4f(0.0, 0.0, 1.0, 1.0); // Blue
glVertex3f(-p, p, 0.0); // Bottom-Left
glColor4f(1.0, 1.0, 0.0, 1.0); // Yellow
glVertex3f(p, p, 0.0); // Bottom-Left
}
glEnd();
angle += 0.6f;
glutSwapBuffers();
}
void onSize(int w, int h)
{
g_width = max(w, 1);
g_height = max(h, 1);
g_aspectRatio = double(g_width) / double(g_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(45, g_aspectRatio, 1, 1000);
glMatrixMode(GL_MODELVIEW);
}
EDIT:
This has been solved... In the above code, I had defined g_aspectRatio as an int instead of a floating-point value. Therefore, it's value was always 1...
In my (old) experience, that's just why you have an aspect ratio argument to gluPerspective().
The manual page says:
In general, the aspect ratio in gluPerspective should match
the aspect ratio of the associated viewport. For example, aspect = 2.0
means the viewer's angle of view is twice as wide in x as it is in y.
If the viewport is twice as wide as it is tall, it displays the image
without distortion.
Check your g_aspectRatio value.
by default, specifying vertex coordinates using glVertex3f is equivalent to specifying a location between -1.0 and +1.0 in screen space
Wrong. Coordinates passed to OpenGL through glVertex or a glVertexPointer vertex array are in model space. The transformation to screen space happens by transforming into view space by the modelview matrix and from view space to clip space by the projection matrix. Then clipping is applied and the perspective divide applied to reach normalized coordinate space.
Hence the value range for glVertex can be whatever you like it to be. By applying the right projection matrix you get your view space to be in [-aspect; aspect]×[-1, 1] if you like that.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-aspect, aspect, -1, 1, -1, 1);
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
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()...
anyone can teach me how to draw 2 objects, for example a cube and a sphere, in origin (0, 0, 0) and when i move the cube, the sphere just remains in the origin. same with moving the sphere, the cube remains..
using keyboardfunc.
if (!LightSwitch)
{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glPushMatrix();
glTranslatef(CubeX, CubeY, CubeZ);
glColor3f(1.0, 0.0, 0.0);
glPushAttrib(GL_LIGHTING_BIT | GL_CURRENT_BIT);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Green);
glutSolidCube(2.0);
glPopAttrib();
glPopMatrix();
glEnd();
}
if (!LightSwitch1)
{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT1);
glPushMatrix();
glTranslatef(AxisX, AxisY, AxisZ);
glColor3f(1.0, 0.0, 0.0);
glPushAttrib(GL_LIGHTING_BIT | GL_CURRENT_BIT);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Blue);
glutSolidSphere(2.0, 10.0, 5.0);
glPopAttrib();
glPopMatrix();
}
glEnd();
I'm no expert, but I believe that by having separate glPushMatrix() / glPopMatrix() blocks for the sphere and the cube, you are giving each object its own local coordinate system. This is why they transform independent of each other.
If you want to move them together, you need to specify glTranslate() outside your glPushMatrix() / glPopMatrix() first:
glTranslatef(translation....); // Translates the whole scene
glPushMatrix();
glTranslatef(the sphere); // Sphere & cube locations changeable via keyb.
glTranslatef(the cube);
glPopMatrix();
If you want to, say, rotate the cube with respect to the sphere (ie., make the center of the sphere the origin of the cube's coordinate system), make a new glPushMatrix()/glPopMatrix() block nested within the first block:
glPushMatrix();
glTranslatef(the sphere);
glPushMatrix();
glRotatef(the cube); // Rotate about specific axis of the sphere
glPopMatrix();
glPopMatrix();
I believe your code is correct for drawing the sphere at location Axis and the cube at location Cube. You say you are using a keyboard func and it is moving them both together when you want to move just one. I believe you are updating both sets of variables in your keyboard function. Try printing out CubeXYZ and AxisXYZ and make sure you're getting the right thing.
I have put all the necessary files[temp link removed] if you need to have a look.
mavStar.exe is my program.
The function currently I‘m trying to debug is :
void drawOG()
{
int curr,right,back,bottom;
//Does NOT draw the right most,back most,bottom most layer at the moment
//Does NOT draw face between state 1 & 2
for(int z=0;z+1 < occupancyGrid->Nz; z++){
glPushMatrix();
for(int y=0;y+1 < occupancyGrid->Ny; y++){
glPushMatrix();
for(int x=0;x+1 < occupancyGrid->Nx; x++){
curr = occupancyGrid->M[x][y][z];
right = occupancyGrid->M[x+1][y][z];
back = occupancyGrid->M[x][y][z+1];
bottom = occupancyGrid->M[x][y+1][z];
drawCube(RIGHT_FACE,colorBetween(curr,right));
drawCube(BACK_FACE,colorBetween(curr,back));
drawCube(BOTTOM_FACE,colorBetween(curr,bottom));
glTranslatef (HALF_VOXEL_SIZE*2, 0.0, 0.0);
}
glPopMatrix();
glTranslatef (0.0, -HALF_VOXEL_SIZE*2, 0.0);
}
glPopMatrix();
glTranslatef (0.0, 0.0, -HALF_VOXEL_SIZE*2);
}
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//mouse tracking
glRotatef(fYDiff, 1,0,0);
glRotatef(fXDiff, 0,1,0);
glRotatef(fZDiff, 0,0,1);
glScalef(fScale, fScale, fScale);
//draw model
glMatrixMode(GL_MODELVIEW);
drawOG();
printOpenGLError(); // Check for OpenGL errors
glutSwapBuffers();
}
There is a much easier way to draw the faces you want by using:
glPushMatrix();
glBegin(GL_QUADS);
//Draw the 16 vertices with their normals.
glEnd();
glPopMatrix();
For example if you want the front:
glPushMatrix();
glBegin(GL_QUADS);
glColor3f(1.0f,1.0f,1.0f);
glNormal3f(0.0,0.0,1.0);
glVertex3f( position[0], position[1], position[2]);
glNormal3f(0.0,0.0,1.0);
glVertex3f( position1[0], position1[1], position1[2]);
glNormal3f(0.0,0.0,1.0);
glVertex3f(position2[0], position2[1], position2[2]);
glNormal3f(0.0,0.0,1.0);
glVertex3f(position3[0], position3[1], position3[2]);
glEnd();
glPopMatrix();
Draw the faces on a piece of paper to figure out what values you need for position,position1,position2,position3,etc. Named them so for general purpose, it should be fairly easy to determine their coordinates.
If you want to give it a touch of flexibility you can create a Cube class and render only the faces for witch you have set a flag to be on. By using a class you gain lots of control on how you want your render-able object to be displayed (color,position,scale, etc).