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 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 have a car moving around an elliptical track on OpenGL. The top-down view is pretty straight-forward, but I can't seem to figure out the driver's-eye view. Here are the equations that define the position and orientation of the car on the track:
const double M_PI = 4.0*atan(1.0);
carAngle += (M_PI/180.0);
if (carAngle > 2.0*M_PI) {
carAngle -= 2.0*M_PI;
}
carTwist = (180.0 * atan2(42.5*cos(carAngle), 102.5*sin(carAngle)) / M_PI)-90.0;
These calculations are kept in a Timer Func, and here is the code for the transformations:
// These are the inside/outside unit measurements
// of the track along the major/minor axes.
insideA = 100;
insideB = 40;
outsideA = 105;
outsideB = 45;
glPushMatrix();
glTranslated(cos(carAngle)*(outsideA+insideA)/2.0,
0.0,
sin(carAngle)*(outsideB+insideB)/2.0);
glScaled(10.0, 10.0, 10.0);
glRotated(carTwist, 0.0, 1.0, 0.0);
glCallList(vwListID1);
glPopMatrix();
This is viewed with gluLookAt, as follows:
gluLookAt(0.0, 20.0, 0.0,
0.0, 0.0, 0.0,
0.0, 0.0, 1.0);
This works just fine, and the car moves along the track and turns as expected. Now I want a "camera" view from the car. I am attempting this in a separate window, and I have everything with the second window working fine, except I can't get the view right.
I thought it would be something like:
double x, z, lx, lz;
x = cos(carAngle)*(outsideA+insideA)/2.0;
z = sin(carAngle)*(outsideB+insideB)/2.0;
lx = sin(carTwist);
lz = cos(carTwist);
gluLookAt(x, 1.0, z,
lx, 1.0, lz,
0.0, 1.0, 0.0);
The positioning, of course, works just fine, if I look top-down with gluLookAt using x, 20.0, z for the eye coordinates, and x, 0.0, z for the center coordinates, the car stays center screen. Since carTwist is the angle from the positive z-axis to the tangent line of the current car position on the track, the vector [sin(alpha),1,cos(alpha)] should provide a point 1 unit in front of the eye coordinates down the desired line of sight. But this doesn't work at all.
On another note, I tried using model transformations to achieve the same effect, but without luck. I would assume if I reverse the transformations without setting gluLookAt, I should get the desired view. i.e.:
glTranslated(-(cos(carAngle)*(outsideA+insideA)/2.0),
0.0,
-(sin(carAngle)*(outsideB+insideB)/2.0));
glRotated(-carTwist, 0.0, 1.0, 0.0);
According to this article, it should provide the same view.
Any help on either approach?
Your current lx and lz should be the look direction you want, however they are coordinates centered at the origin.
The 4th, 5th, and 6th arguments of gluLookAt specify a point in the scene to look at, not a look direction.
Therefore you will need to add the look direction to the camera position to get a point in the scene to direct your camera at.
Also, since carTwist is in degrees, you will need to convert it to radians for use with cos and sin functions.
double x, z, lx, lz;
x = cos(carAngle)*(outsideA+insideA)/2.0;
z = sin(carAngle)*(outsideB+insideB)/2.0;
lx = x + cos(carTwist * M_PI / 180.0);
lz = z + sin(carTwist * M_PI / 180.0);
I want to know how to draw a spiral.
I wrote this code:
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT);
GLfloat x,y,z = -50,angle;
glBegin(GL_POINTS);
for(angle = 0; angle < 360; angle += 1)
{
x = 50 * cos(angle);
y = 50 * sin(angle);
glVertex3f(x,y,z);
z+=1;
}
glEnd();
glutSwapBuffers();
}
If I don't include the z terms I get a perfect circle but when I include z, then I get 3 dots that's it. What might have happened?
I set the viewport using glviewport(0,0,w,h)
To include z should i do anything to set viewport in z direction?
You see points because you are drawing points with glBegin(GL_POINTS).
Try replacing it by glBegin(GL_LINE_STRIP).
NOTE: when you saw the circle you also drew only points, but drawn close enough to appear as a connected circle.
Also, you may have not setup the depth buffer to accept values in the range z = [-50, 310] that you use. These arguments should be provided as zNear and zFar clipping planes in your gluPerspective, glOrtho() or glFrustum() call.
NOTE: this would explain why with z value you only see a few points: the other points are clipped because they are outside the z-buffer range.
UPDATE AFTER YOU HAVE SHOWN YOUR CODE:
glOrtho(-100*aspectratio,100*aspectratio,-100,100,1,-1); would only allow z-values in the [-1, 1] range, which is why only the three points with z = -1, z = 0 and z = 1 will be drawn (thus 3 points).
Finally, you're probably viewing the spiral from the top, looking directly in the direction of the rotation axis. If you are not using a perspective projection (but an isometric one), the spiral will still show up as a circle. You might want to change your view with gluLookAt().
EXAMPLE OF SETTING UP PERSPECTIVE
The following code is taken from the excellent OpenGL tutorials by NeHe:
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
Then, in your draw loop would look something like this:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity();
glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
glBegin(GL_TRIANGLES); // Drawing Using Triangles
glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd();
Of course, you should alter this example code your needs.
catchmeifyoutry provides a perfectly capable method, but will not draw a spatially accurate 3D spiral, as any render call using a GL_LINE primitive type will rasterize to fixed pixel width. This means that as you change your perspective / view, the lines will not change width. In order to accomplish this, use a geometry shader in combination with GL_LINE_STRIP_ADJACENCY to create 3D geometry that can be rasterized like any other 3D geometry. (This does require that you use the post fixed-function pipeline however)
I recommended you to try catchmeifyoutry's method first as it will be much simpler. If you are not satisfied, try the method I described. You can use the following post as guidance:
http://prideout.net/blog/?tag=opengl-tron
Here is my Spiral function in C. The points are saved into a list which can be easily drawn by OpenGL (e.g. connect adjacent points in list with GL_LINES).
cx,cy ... spiral centre x and y coordinates
r ... max spiral radius
num_segments ... number of segments the spiral will have
SOME_LIST* UniformSpiralPoints(float cx, float cy, float r, int num_segments)
{
SOME_LIST *sl = newSomeList();
int i;
for(i = 0; i < num_segments; i++)
{
float theta = 2.0f * 3.1415926f * i / num_segments; //the current angle
float x = (r/num_segments)*i * cosf(theta); //the x component
float y = (r/num_segments)*i * sinf(theta); //the y component
//add (x + cx, y + cy) to list sl
}
return sl;
}
An example image with r = 1, num_segments = 1024:
P.S. There is difference in using cos(double) and cosf(float).
You use a float variable for a double function cos.