I've implemented an FPS style camera, with the camera consisting of a position vector, and Euler angles pitch and yaw (x and y rotations).
After setting up the projection matrix, I then translate to camera coordinates by rotating, then translating to the inverse of the camera position:
// Load projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set perspective
gluPerspective(m_fFOV, m_fWidth/m_fHeight, m_fNear, m_fFar);
// Load modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Position camera
glRotatef(m_fRotateX, 1.0, 0.0, 0.0);
glRotatef(m_fRotateY, 0.0, 1.0, 0.0);
glTranslatef(-m_vPosition.x, -m_vPosition.y, -m_vPosition.z);
Now I've got a few viewports set up, each with its own camera, and from every camera I render the position of the other cameras (as a simple box).
I'd like to also draw the view vector for these cameras, except I haven't a clue how to calculate the lookat vector from the position and Euler angles.
I've tried to multiply the original camera vector (0, 0, -1) by a matrix representing the camera rotations
then adding the camera position to the transformed vector, but that doesn't work at all (most probably because I'm way off base):
vector v1(0, 0, -1);
matrix m1 = matrix::IDENTITY;
m1.rotate(m_fRotateX, 0, 0);
m1.rotate(0, m_fRotateY, 0);
vector v2 = v1 * m1;
v2 = v2 + m_vPosition; // add camera position vector
glBegin(GL_LINES);
glVertex3fv(m_vPosition);
glVertex3fv(v2);
glEnd();
What I'd like is to draw a line segment from the camera towards the lookat direction.
I've looked all over the place for examples of this, but can't seem to find anything.
Thanks a lot!
I just figured it out. When I went back to add the answer, I saw that Ivan had just told me the same thing :)
Basically, to draw the camera vector, I do this:
glPushMatrix();
// Apply inverse camera transform
glTranslatef(m_vPosition.x, m_vPosition.y, m_vPosition.z);
glRotatef(-m_fRotateY, 0.0, 1.0, 0.0);
glRotatef(-m_fRotateX, 1.0, 0.0, 0.0);
// Then draw the vector representing the camera
glBegin(GL_LINES);
glVertex3f(0, 0, 0);
glVertex3f(0, 0, -10);
glEnd();
glPopMatrix();
This draws a line from the camera position for 10 units in the lookat direction.
Related
I'm trying to draw a little sphere in front of the camera, let's say 5 units away (C++, newby in openGL and not very confident in trigonometry!).
I expect that the sphere is always in the middle of my camera when I perform pan and tilt movements.
In my rendering loop, I calculated the coordinates of the sphere in the following way:
// 1) settimg my camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(camera_angle[1], 0, 1, 0);
glRotatef(camera_angle[0], 1, 0, 0);
glRotatef(camera_angle[2], 0, 0, 1);
glTranslatef(camera_pos[0],camera_pos[1],camera_pos[2]);
// 2) retrieving camera pan tilt angles in radians:
double phi = camera_angle[1] *(M_PI/180.0); //pan
double theta = camera_angle[0] *(M_PI/180.0); //tilt
//3) calculating xyz coordinates of the sphere, if 5 units away from camera
double dist = -5;
double ax = camera_pos[0] + (-1)*(dist*sin(phi)*cos(theta));
double ay = camera_pos[1] + dist*sin(theta);
double az = camera_pos[2] + dist*cos(theta)*cos(phi);
//4) draw sphere
float ndiv = 2.0;
GLfloat f[]={1.0,1.0,1.0,1};
glPushMatrix();
glTranslated(ax, ay, az);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, f);
glShadeModel(GL_FLAT);
glBegin(GL_TRIANGLES);
for (int i=0;i<20;i++)
makeTri(vdata[tindices[i][0]], vdata[tindices[i][1]], vdata[tindices[i][2]], ndiv, 0.2);
glEnd();
glPopMatrix();
I found the trigonometric formula here
spherical coordinate system
Note that I inverted some values like sin and cos, as I guess the correct order depends on reference system (I guess openGL has some inverted axis).
Now I have a strange result, that can be seen in this video:
sphere behaviour
Please, ignore the coloured spheres in the background and the green square in the middle of the camera, just look at the white sphere in front of the camera.
As you can see, if I perform only pan or only tilt (look at bottom left values showing the exact camera angles), the white sphere is always in the exact centre of the camera, as expected. Nevertheless, when pan and tilt are performed together, the sphere drifts:
the more pan and tilt values move away from 0 degree, the more the sphere drifts. Moreover, the shape of drift follow a circular trajectory, which is very suspicious for me.
Does anyone have an idea? Thanks
To draw something that doesn't move relative to the camera you simply start from an identity model-view matrix from scratch:
float ndiv = 2.0;
GLfloat f[]={1.0,1.0,1.0,1};
glPushMatrix();
glLoadIdentity(); // <------------- zero out transforms
glTranslated(0, 0, -5); // <------------- translate 5 units from the camera
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, f);
glShadeModel(GL_FLAT);
glBegin(GL_TRIANGLES);
for (int i=0;i<20;i++)
makeTri(vdata[tindices[i][0]], vdata[tindices[i][1]], vdata[tindices[i][2]], ndiv, 0.2);
glEnd();
glPopMatrix();
I am rather new to programming so I may not use the correct terminology. I am trying to create a dog out of only glutwirecubes, however I cannot figure out how to define a starting position for the back legs, nor can I figure out how to close the space between my 'shoulder' and 'elbows'. I have each body part assigned to rotate by key press. I also realize that my use of glPushMatrix and glPopMatrix may not be correct as I do not fully understand how the matrix stack is saved/loaded.
glPushMatrix();
glTranslatef(-1, 0, 0);
glRotatef((GLfloat)body,1, 0, 0);//sets rotations about x,y,z axis
glTranslatef(1, 0, 0);
glPushMatrix();
glScalef(2.0, 0.4, 0.5);//sets dimensions of cube
glutWireCube(2.0);//sets scale of wire cube
glPopMatrix();
glPopMatrix();
glPushMatrix();
glTranslatef(-1, 0, 0);
glRotatef((GLfloat)shoulder, 0, 0, 1);//sets rotations about x,y,z axis
glTranslatef(1, 0, 0);
glPushMatrix();
glScalef(1.5, 0.4, 0.5);//sets dimensions of cube
glutWireCube(.75);//sets scale of wire cube
glPopMatrix();
glTranslatef(1,0,0);
glRotatef((GLfloat)elbow,0,0,1);//sets rotations about x,y,z axis
glTranslatef(1,0,0);
glPushMatrix();
glScalef(1.5,0.4,0.5);//sets dimensions of cube
glutWireCube(.75);//sets scale of wire cube
glPopMatrix();
glPopMatrix();
glutSwapBuffers();
The picture is the position I am aiming for, however my cubes always start oriented horizontally.
with glTranslate right before, as for its friends !
For instance you might translate so that the center is now at the corner, so that your rotations rotate around this new handle.
I dont understand how this GluLookAt works in OpenGl.
I would like to know how to transform this two lines :
gluLookAt(5.0, 15.0, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0, -1.0);
gluLookAt(5.0, 0.0, 5.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0);
using glRotatef and glTranslatef.
After some searches, it seems to exist a way for making that thing :
glRotatef();
glRotatef();
glTranslatef(5.0,15.0,2.0);
glRotatef();
glRotatef();
glTranslatef(5.0,0.0,5.0);
So just by using two rotations and one translation.
But I dont understand how can i find the angles and the axes of these rotations.
I tried to explain how the functions work below. Hope it makes you understand the concept. For rotation and translation you can check this link to see how it is handled.
struct Triple
{
float x,y,z;
}
//CameraPosition
Triple Cp(a,b,c); //initialise your camera position
//LookatPosition
Triple Lp(e,f,g); //initialise your lookat position
//Up vector
Triple Up(k,l,m); //initialise your up vector
UpdateCamera()
{
//Update Cp, Lp here
//if you move your camera use translatef to update camera position
//if you want to change looking direction use correct rotation and translation to update your lookat position
//if you need to change up vector simply change it to
Up = Triple(knew,lnew,mnew);
}
display()
{
gluLookAt(Cp.x,Cp.y,Cp.z,Lp.x,Lp.y,Lp.z,Up.x,Up.y,Up.z);
//Your object drawings Here
}
I'd like to sidestep the glRotate and glTranslate and use glLoadMatrix instead (glLoadMatrix replaces the current matrix on the stack use glMultMatrix if you want to multiply): you would then use an array of floats containing the matrix in column major order:
xaxis.x yaxis.x zaxis.x 0
xaxis.y yaxis.y zaxis.y 0
xaxis.z yaxis.z zaxis.z 0
-dot(xaxis, camP) -dot(yaxis, camP) -dot(zaxis, camP) 1
where
zaxis = normal(At - camP)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)
and camP the position of the camera, At the point the camera is looking at and Up the up-vector.
So I draw an 'I' and use gluLookAt(0.f,0.f,3.f,0.f,0.f,0.f,0.f,1.f,0.f), and the I is moderate size. Then I add a drawScene() function which draw the background with gradient color, and then the 'I' becomes super big. I guess it is because I change matrix mode to GL_PROJECTION and GL_MODELVIEW in drawScene(), and those change the perspective maybe? I guess glPushMatrix() and glPopMatrix() are needed to reserve matrix status, but I have hard time finding where to put them. So how can I make the 'I' look normal size? Here are my drawI() and drawScene():
void drawI(int format)
{
glBegin(format);
glColor3f(0, 0, 1);
glVertex2f(point[3][0], point[3][1]);
glVertex2f(point[2][0], point[2][1]);
glVertex2f(point[1][0], point[1][1]);
glVertex2f(point[12][0], point[12][1]);
glVertex2f(point[10][0], point[10][1]);
glEnd();
glBegin(format);
glVertex2f(point[10][0], point[10][1]);
glVertex2f(point[11][0], point[11][1]);
glVertex2f(point[12][0], point[12][1]);
glEnd();
glBegin(format);
glVertex2f(point[9][0], point[9][1]);
glVertex2f(point[10][0], point[10][1]);
glVertex2f(point[3][0], point[3][1]);
glVertex2f(point[4][0], point[4][1]);
glVertex2f(point[6][0], point[6][1]);
glColor3f(1, 0.5, 0);
glVertex2f(point[7][0], point[7][1]);
glVertex2f(point[8][0], point[8][1]);
glEnd();
glBegin(format);
glColor3f(0, 0, 1);
glVertex2f(point[5][0], point[5][1]);
glVertex2f(point[6][0], point[6][1]);
glVertex2f(point[4][0], point[4][1]);
glEnd();
}
void drawScene()
{
glBegin(GL_QUADS);
//red color
glColor3f(1.0,0.0,0.0);
glVertex2f(-1.0,-1.0);
glVertex2f(1.0,-1.0);
//blue color
glColor3f(0.0,0.0,1.0);
glVertex2f(1.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();
}
Thanks a lot!
So I take glMatrixMode() and glLoadIdentity() out of drawScene() and drawI() and put them in display(). I changed drawScene() and drawI() above, and here is my display()
void display()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70.f,1.f,0.001f,30.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
drawScene();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.f,0.f,3.f,0.f,0.f,0.f,0.f,1.f,0.f);
drawI(GL_TRIANGLE_FAN);
glutSwapBuffers();
}
The normal way to do this (in a 3D mode) is in your code, before you call drawI or drawScene would be:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov, aspect, near, far); // fov is camera angle in degrees, aspect is width/height of your viewing area, near and far are your near and far clipping planes.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,3.0,0.0,0.0,0.0,0.0,1.0,0.0)
In your 2D rendering, you probably don't need the call to gluPerspective, but these calls should be done in your code before you call drawI or drawScene. Do this and delete the glMatrixMode() and glLoadIdentity() calls from drawI and drawScene.
Edit:
If your "I" is still too big, there are a number of things you could do, but you should probably be operating in 3D (giving a Z coordinate also).
You could scale the object:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,3.0,0.0,0.0,0.0,0.0,1.0,0.0)
glScalef(0.5, 0.5, 0.5);
You could move the camera further back (you'll need to include the gluPerspective() call as well):
gluLookAt(0.0,0.0,50.0,0.0,0.0,0.0,0.0,1.0,0.0);
Perhaps the easiest way to control the rendered image size in a 3D mode is to both move the camera (eye) back a way and then control the image size by changing the camera aperture angle (fov in the gluPerspective() call). A wider fov will shrink the rendered image; a smaller fov will enlarge it.
I don't know what the values for your coordinates are in drawI since they're variables, but a camera position of 3.0, an fov of 70.0 and an aspect of 1 should give you left, right, top and bottom clipping planes of about +/- 2.1 at Z = 0.
If you kept everything else the same and moved the camera to 50.0, the clipping planes would be at about +/- 35.0, so your "I" would occupy a much smaller portion of the viewing area.
If you then left the camera position at 50.0, but changed the fov to 40.0, the clipping planes would be at about +/- 18.2. Your "I" would fill a larger area than it did at cameraZ = 50.0, fov = 70.0, but a smaller area than cameraZ = 3.0, fov = 70.0.
You can play with camera position and fov to get the image size you want, or you could just scale the image. I like to keep camera position constant and change the fov. If I provide a function that changes the fov based on user input (maybe a mouse scroll), it's a good way to provide a zoom in/out effect.
BTW, in your original code, if you called:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,3.0,0.0,0.0,0.0,0.0,1.0,0.0)
Then later in DrawI or drawScene call:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
You've trashed the matrix loaded by your earlier call to gluLookAt().
I am trying to test gluLookAt using this code. But I can see only a black screen. What is wrong with this code ? Is there any basic concept about glulookAt (or opengl camera) that I need to understand.
glViewport(0,0,640,480);
glEnable(GL_DEPTH_TEST);
glClearColor(0,0,0,1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluLookAt(0,0,5,0,0,0,0,0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_POLYGON);
glColor3f(1, 0, 0);
glVertex2d(0.25, 0.25);
glVertex2d(-0.25, 0.25);
glVertex2d(-0.25, -0.25);
glVertex2d(0.25, -0.25);
glEnd();
One issue is the up vector of gluLookAt is in the same direction as the look direction.
All you need to do is set +Y up and it should work...
gluLookAt(0, 0, 0.5, //position is +0.5 along Z (NOTE: 0.5, not 5. see below),
0, 0, 0, //looking at a 0.5x0.5 X/Y quad at the origin
0, 1, 0 //rotated such that +Y is up
);
The other issue is that gluLookAt shouldn't be applied to the projection matrix. It'll work for now but will break lighting later. Move it to the modelview matrix:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(... as before ...);
Assuming the projection matrix hasn't been set, changing the from position of gluLookAt back to your 5 will make the quad disappear. This is because the default projection gives a viewing volume of an orthographic -1 to 1 cube. With the "camera" now too far away it won't see anything. This is where you'll want to investigate changing the projection matrix. Maybe increase the size of the orthographic projection with glOrtho(), or look into the more complex but natural gluPerspective().