One of the ways to view a scene is to either use gluLookAt or to create your own custom viewing routine. I came across this custom viewing routine in a flight simulator in a book.
void pilotView(GLdouble planex, GLdouble planey,
GLdouble planez, GLdouble roll,
GLdouble pitch, GLdouble heading)
{
glRotated(roll, 0.0, 0.0, 1.0);
glRotated(pitch, 0.0, 1.0, 0.0);
glRotated(heading, 1.0, 0.0, 0.0);
glTranslated(-planex, -planey, -planez);
}
Rotating the camera by x degrees clockwise is equivalent to rotating the target object by x degrees counterclockwise. Thus, when we specify the "roll" angle for example, shouldn't we be writing "glRotated(-roll, 0.0, 0.0, 1.0)" instead of "glRotated(roll, 0.0, 0.0, 1.0)"?
No, we should not, in OpenGL triangles are transformed not camera OpenGL does not have notion of camera; so when you add a rotation to the transform your object will be rotated by this updated transform.
gluLookAt just sets up transformation of the objects as if you are looking at it, but still what is transformed is the object.
As for this function my guess is that it sets transformation to set it so that view would be aligned with plane instead of being aligned with horizontal and hang in the center instead of behind that is why we have + sign on rotations and - sign on translations. Note that calls do not set transformation, but update it.
Related
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.
I am creating the solar system and I keep running into problems with the lighting. The first problem is that the moon casts no shadows on the earth and the earth casts no shadows on the moon.
The other problem is that the light that is shining on the the earth and the moon are not coming from my sun, but from the center point of the orbit. I added the red lines in the picture below to show what I mean.
the picture below should illustrate what my two problems are.
Here is the code that is dealing with the lights and the planets.
glDisable(GL_LIGHTING);
drawCircle(800, 720, 1, 50);
//SUN
//Picture location, major radius, minor radius, major orbit, minor orbit, angle
Planet Sun ("/home/rodrtu/Desktop/SolarSystem/images/Sun.png",
100, 99, 200.0, 0.0, 0.0);
double sunOrbS = 0;
double sunRotS = rotatSpeed/10;
cout << sunRotS << " Sun Rotation" << endl;
//orbit speed, rotation speed, moon reference coordinates (Parent planet's major and minor Axis)
Sun.displayPlanet(sunOrbS, sunRotS, 0.0, 0.0);
//Orbit path
//EARTH
GLfloat light_diffuse[] = { 1.5, 1.5, 1.5, 1.5 };
GLfloat pos[] = { 0.0, 0.0, 0.0, 200.0 };
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, pos);
Planet Earth ("/home/rodrtu/Desktop/SolarSystem/images/EarthTopography.png",
50, 49, 500.0, 450.0, 23.5);
double eaOrbS = orbitSpeed;
double eaRotS = rotatSpeed*3;
Earth.displayPlanet(eaOrbS, eaRotS, 0.0, 0.0);
//EARTH'S MOON
Planet Moon ("/home/rodrtu/Desktop/SolarSystem/images/moonTest.png",
25, 23, 100.0, 100.0, 15);
double moOrbS = rotatSpeed*4;
double moRotS = eaOrbS;
Moon.displayPlanet(moOrbS, moRotS, Earth.getMajorAxis(), Earth.getMinorAxis());
orbitSpeed+=.9;
if (orbitSpeed > 359.0)
orbitSpeed = 0.0;
rotatSpeed+=2.0;
if (rotatSpeed > 7190.0)
rotatSpeed = 0.0;
This next functions are used to determine the orbit coordinate and location of each planet
void Planet::setOrbit(double orbitSpeed, double rotationSpeed,
double moonOrbitX, double moonOrbitY)
{
majorAxis = orbitSemiMajor * cos(orbitSpeed / 180.0 * Math::Constants<double>::pi);
minorAxis = orbitSemiMinor * sin(orbitSpeed / 180.0 * Math::Constants<double>::pi);
glTranslate(majorAxis+moonOrbitX, minorAxis+moonOrbitY, 0.0);
glRotatef(orbitAngle, 0.0, 1.0, 1.0);
glRotatef(rotationSpeed, 0.0, 0.0, 1.0);
}
void Planet::displayPlanet(double orbitSpeed,double rotationSpeed,
double moonOrbitX, double moonOrbitY)
{
GLuint surf;
Images::RGBImage surfaceImage;
surfaceImage=Images::readImageFile(texture);
glEnable(GL_TEXTURE_2D);
glGenTextures(0, &surf);
glBindTexture(GL_TEXTURE_2D, surf);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
surfaceImage.glTexImage2D(GL_TEXTURE_2D,0,GL_RGB);
glPushMatrix();
setOrbit(orbitSpeed,rotationSpeed, moonOrbitX, moonOrbitY);
drawSolidPlanet(equatRadius, polarRadius, 1, 40, 40);
glPopMatrix();
}
What am I doing wrong? I read up on the w component of GL_POSITION and I changed my position to be 200 (where the sun is centered), but the light source is still coming from the center of the orbit.
To make a proper reply for the light position issue..
[X, Y, Z, W] is called homogenous coordinates
A coordinate [X, Y, Z, W] in homogenous space is will be [X/W, Y/W, Z/W] in 3D space.
Now, consider the following W values :
W=1.0 : [1.0, 1.0, 1.0, 1.0] is [1.0, 1.0, 1.0] in 3D place.
W=0.1 : [1.0, 1.0, 1.0, 0.1] is [10.0, 10.0, 10.0] in 3D place.
W=0.001 : [1.0, 1.0, 1.0, 0.001] is [1000.0, 1000.0, 1000.0] in 3D place.
When we keep moving towards W=0 the [X/W, Y/W, Z/W] values approaches a point at infinity. It's actually no longer a point, but a direction from [0,0,0] to [X,Y,Z].
So when defining the light position we need to make sure to get this right.
W=0 defines a directional light, so x,y,z is a directional vector
W=1 defined a positional light, so x,y,z is a position in 3D space
You'll get to play around with this a lot once you dig deeper into matrix math. If you try to transform a direction (W=0) with a translation matrix for example, it will not have any effect. This is very relevant here as well since the light position will be affected by the modelview matrix.
Some easy to understand information here for further reading :
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
If OpenGL doesn't have a "cast shadow" function, how could I acomplish this then?
What you must understand is, that OpenGL has no concept of a "scene". All OpenGL does is drawing points, lines or triangles to the screen, one at a time. After it's drawn, it has no influence on the following drawing operations.
So to do something fancy like shadows, you must get, well, artistic. By that I mean, like an artist who paints a plastic picture which has depth with "just" a brush and a palette of colours, you must use OpenGL in a artistic way to recreate with it the effects you desire. Drawing a shadow can be done in various ways. But the most popular one is known by the term Shadow Mapping.
Shadow Mapping is a two step process. In the first step the scene is rendered into a "grayscale" picture "seen" from the points of view of the light, where the distance from the light is drawn as the "gray" value. This is called a Shadow Depth Map.
In the second step the scene is drawn as usual, where the lights' shadow depth map(s) are projected into the scene, as if the lights were a slide projector (where everything receives that image, as OpenGL doesn't shadow). In a shader the depth value in the shadow depth map is compared with the actual distance to the light source for each processed fragments; if the distance to the light is farther than the corresponding pixel in the shadow map this means that while rendering the shadow map something got in front of the currently processed geometry fragment, which hence lies in the shadow, so it's drawn in a shadow color (usually the ambient illumination color); you might want to combine this with an Ambient Occlusion effect to simulate soft, self shadowing ambient illumination.
I'm having problems in OpenGL getting my object (a planet) to rotate relative to the current camera rotation. It seems to work at first, but then after rotating a bit, the rotations are no longer correct/relative to the camera.
I'm calculating a delta (difference) in mouseX and mouseY movements on the screen. The rotation is stored in a Vector3D called 'planetRotation'.
Here is my code to calculate the rotation relative to the planetRotation:
Vector3D rotateAmount;
rotateAmount.x = deltaY;
rotateAmount.y = deltaX;
rotateAmount.z = 0.0;
glPushMatrix();
glLoadIdentity();
glRotatef(-planetRotation.z, 0.0, 0.0, 1.0);
glRotatef(-planetRotation.y, 0.0, 1.0, 0.0);
glRotatef(-planetRotation.x, 1.0, 0.0, 0.0);
GLfloat rotMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, rotMatrix);
glPopMatrix();
Vector3D transformedRot = vectorMultiplyWithMatrix(rotateAmount, rotMatrix);
planetRotation = vectorAdd(planetRotation, transformedRot);
In theory - what this does is, sets up a rotation in the 'rotateAmount' variable. It then gets this into model space, by multiplying this vector with the inverse model transform matrix (rotMatrix).
This transformed rotation is then added to the current rotation.
To render this is the transform being setup:
glPushMatrix();
glRotatef(planetRotation.x, 1.0, 0.0, 0.0);
glRotatef(planetRotation.y, 0.0, 1.0, 0.0);
glRotatef(planetRotation.z, 0.0, 0.0, 1.0);
//render stuff here
glPopMatrix();
The camera sort of wobbles around, the rotation I'm trying to perform, doesn't seem relative to the current transform.
What am I doing wrong?
GAH! Don't do that:
glPushMatrix();
glLoadIdentity();
glRotatef(-planetRotation.z, 0.0, 0.0, 1.0);
glRotatef(-planetRotation.y, 0.0, 1.0, 0.0);
glRotatef(-planetRotation.x, 1.0, 0.0, 0.0);
GLfloat rotMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, rotMatrix);
glPopMatrix();
OpenGL is not a math library. There are proper linear algebra libraries for that kind of job.
As for your problems. A vector is not fit to store a rotation. You need at least a Vector (axis of rotation) and the angle itself, or better yet a Quaternion.
Also rotations don't add. They're no commutative, however addition is a commutative operation. Rotations in fact multiply.
How to fix your code: Rewrite it from scratch using the proper mathematical methods. For this please read up the topics of "Rotation matrices" and "Quaternions" (Wikipedia has them).
I just want to create a perspective where the eye of the camera would be, at, say: (2, 2, -2), looking right at the origin. I'm trying to use a combination of gluLookAt() and glFrustum(), but for some reason, though it is rendering, my objects look very distorted:
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum (-1.0, 1.0, -1.0, 1.0, 1.0, 500.0);
...
gluLookAt (-2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0);
What am I doing wrong?
EDIT: Here is a screenshot. The left side defines a profile curve to be swept around the y-axis. It should be a cylinder in the perspective view, but it's... warped.
EDIT 2: Also, those axis in the perspective view are set up as followed, which I know isn't correct:
// draw the axis
glBegin(GL_LINES);
// x
glVertex3f(500.0, 0.0, 0.0);
glVertex3f(-500.0, 0.0, 0.0);
// y
glVertex3f(0.0, -500.0, 0.0);
glVertex3f(0.0, 500.0, 0.0);
// z
glVertex3f(0.0, 0.0, -500.0);
glVertex3f(0.0, 0.0, 500.0);
glEnd();
EDIT 3: Also, none of the vertices of that shape have an x, y, or z value greater than 1.0..
What am I doing wrong?
I don't thing you're doing wrong anything. The kind of view you want to have in your left pane is usually done using a orthographic projection. The distortion you see is just a perspective distortion; you're not looking perpendicular onto the curve (the curve lies in the XY plane, and you're looking at the XY plane from some angle).
Side note:
The projection matrix only defines the "lens" of OpenGL. It must not be used to place the "camera". Any eyepoint positioning (the view) is defined as part of the modelview transformation. Thus gluLookAt is meant to be used on the modelview matrix.
Your frustum is set up as if the screen is square. If your screen isn't square this will distort the objects badly.
Also, if the objects are close to your camera, the near and far distances can affect the image.
And one more thing, your up axis in gluLookAt is pointing down.
Posting a screenshot would help identify the problem.
Suppose I have a point at (250,125,-20).
After the following transformation,
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(100.0, 50.0, 0.0);
glRotatef(-25.0, 0.0, 1.0, 0.0);
How can I get the value of current coordinates of that point?
Need I write a subroutine to multiply a matrix to a vector?
Are there any built-in solutions?
You can't get the coordinates for a specific vertex (point) after a transformation, however for this particular case you can get the ModelViewMatrix after the translate/rotate is applied.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(100.0, 50.0, 0.0);
glRotatef(-25.0, 0.0, 1.0, 0.0);
glGetFloatv(GL_MODELVIEW_MATRIX , *your_matrix*);
//print your matrix to check if that is the desired transformation coordinates
There is no magic tape in OpenGL, you will have to write your own framework e.g: for every objects in your world a class where you hold the vertices and what data you find relevant.