How to get transformed coordinate in OpenGL? - opengl

I draw a solid sphere like the followings:
glPushMatrix();
glScalef(0.015, 0.015, 0.015);
glRotatef(90, 1.0, 0.0, 0.0);
glTranslatef(0.0, 200, 0.0);
glRotatef(-20, 0.0, 0.0, 1.0);
glRotatef(-20, 1.0, 0.0, 0.0);
glTranslatef(78.75, -110.74, -13.53);
glutSolidSphere(4.0f,15,15);
glPopMatrix();
How can I get the transformed coordinates of this solid sphere?

You can get the state variables GL_MODELVIEW_MATRIX by the function glget.
It returns the current matrix from ModelView stack. I think that is what you need.

Put the translated coordinates in variables, then you won't have to retrieve the transformed coordinates of the shape.
float solidSphereX = whatever;
float solidSphereY = whatever;
float solidSphereZ = whatever;
float solidSphereRotationX = whatever in radians;
float solidSphereRotationY = whatever in radians;
float solidSphereRotationZ = whatever in radians;
...
glPushMatrix();
glRotatef(solidSphereRotationX, solidSphereRotationY, solidSphereRotationZ);
glTranslatef(solidSphereX, solidSphereY, solidSphereZ);
glPopMatrix();

Related

OpenGL object distortion in perspective view

Do you guys have any idea what is the cause of this problem? It looks fine in orthographic view.
Orthographic View:
Perspective View:
Code that might be related:
//Global variable
float tx = 0, tz = 0, tSpeed = 1.0;
bool isOrtho = true;
float ONear = -20.0, OFar = 20.0;
float PNear = 1.0, PFar = 41.0;
float ptx = 0, pty = 0, ptSpeed = 0.1;
float pry = 0, prSpeed = 1.0;
void projection() {
glMatrixMode(GL_PROJECTION); //refer to projection matrix
glLoadIdentity(); //reset projection matrix
glTranslatef(ptx, pty, 0.0); //translation for projection
glRotatef(pry, 0.0, 1.0, 0.0); //rotate for projection
if (isOrtho) {
//Ortho View
glOrtho(-20.0, 20.0, -20.0, 20.0, ONear, OFar); //Ortho view
}
else {
//Perspective view
gluPerspective(45, 1.0, -1.0, 1.0);
glFrustum(-20.0, 20.0, -20.0, 20.0, PNear, PFar);
}
}
void display(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
projection();
glMatrixMode(GL_MODELVIEW);
lighting();
drawRobot();
}
The glu docs for gluPerspective state:
zNear
Specifies the distance from the viewer to the near clipping plane (always positive).
(emphasis mine).
Your code gluPerspective(45, 1.0, -1.0, 1.0); passes -1.0 for zNear, which is not in the allowed range of values.

Rotate object around constantly rotating object

I'm trying to simulate the solar system and need to get the moon to orbit a planet orbiting the sun
i am currently using the following code to rotate the planets
glPushMatrix();
glRotated((GLdouble)(spin*earth.speed), 0.0, 0.0, 1.0);
glTranslated(earth.xPos, earth.yPos, earth.zPos);
earth.draw();
glPopMatrix();
i'm trying to use the code below to make my moon orbit the earth however at the moment all i can do is rotate around a specific point.
glPushMatrix();
//define one time only start location
bool start = true;
if (start)
{
glTranslated(earthMoon.xPos, earthMoon.yPos, earthMoon.zPos);
start = false;
}
//orbit earths start point
//perfectly fits around earth
glTranslatef(-0.1, -0.1, 0);
glRotatef(spin*10, 0, 0, 1);
glTranslatef(0.1, 0.1, 0);
// need translation vector to follow earth
//glTranslated(earthMoon.xPos, earthMoon.yPos, earthMoon.zPos);
earthMoon.draw();
glPopMatrix();
i think what i need to do is find some way of knowing earths position from the rotatef function.
I have a class for the planets with the following attributes and methods:
float radius;
float xPos;
float yPos;
float zPos;
float speed;
planet(float r, float x, float y, float z, float speed);
~planet();
void draw(void)
{
glPushMatrix();
glColor3f(0.0, 1.0, 1.0);
glutSolidSphere(radius, 20, 10);
glPopMatrix();
}
the class' coordinates do not get updated when the planet rotates
Does anyone know how to get this to work?
Don't pop your matrix once you drew earth,
then your new referential will be the earth position,
you just have to call the moon drawing code and it will rotate around your earth.
Found a fix that works as intended in case anyone else is struggling with this concept
//earth
glPushMatrix();
//earth orbit
glRotated((GLdouble)(spin*earth.speed), 0.0, 0.0, 1.0);
glTranslated(earth.xPos, earth.yPos, earth.zPos);
//earth mooon
glPushMatrix();
//orbit around earth
glRotatef(spin * 5, 0, 0, 1);
glTranslatef(0.1, 0.1, 0.0);
//rotate around self
glRotated((GLdouble)spin, 0.0, 1.0, 0.0);
//draw moon
earthMoon.draw();
glPopMatrix();
//rotate around self
glRotated((GLdouble)spin, 0.0, 1.0, 0.0);
//draw earth
earth.draw();
glPopMatrix();
//
Hope this helps anyone else

opengl rotate an object around fixed axes

Hi I'm trying to implement a opengl program with rotation&translation. But I got this problem that, the world axes will rotating along with my object(a cube). It's like, first I rotate cube along Z-axis, it works fine, then I middle-click the mouse and want to rotate the cube along the original Y-axis. At the moment I click, the cube will stop rotating along Z and start to rotate along Y. But it turns out it will rotate along a "new and invisible" Y-axis. I figure out that's because when I rotate the cube along Z with glRotatef(), the other two axis:X,Y also rotate. How can I fix the axes when I'm rotating the cube. I know the glRotatef() will multiply all matrix in screen with a rotation axis, so I tried added a glLoadIdentity() in each rotation but it still not work. can anyone give me the solution?
the code is here for reference:
#include <stdlib.h>
#include <GL/glut.h>
#include <iostream>
GLfloat vertices[8][3] =
{ { -1.0, -1.0, -1.0 }, { 1.0, -1.0, -1.0 },
{ 1.0, 1.0, -1.0 }, { -1.0, 1.0, -1.0 }, { -1.0, -1.0, 1.0 },
{ 1.0, -1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { -1.0, 1.0, 1.0 } };
GLuint listName;
GLfloat theta[3] = { 0.0, 0.0, 0.0 };
GLint axis = 2;
GLfloat delta = 0.02;
GLint stop = 0;
GLfloat distance = 0;
void face(int a, int b, int c, int d)
{
glBegin(GL_POLYGON);
//glColor3fv(colors[a]);
glVertex3fv(vertices[a]);
//glColor3fv(colors[b]);
glVertex3fv(vertices[b]);
//glColor3fv(colors[c]);
glVertex3fv(vertices[c]);
//glColor3fv(colors[d]);
glVertex3fv(vertices[d]);
glEnd();
}
void cube(void)
{
glColor3f(1.0f,1.0f,1.0f);
face(0, 3, 2, 1);
face(2, 3, 7, 6);
face(0, 4, 7, 3);
face(1, 2, 6, 5);
face(4, 5, 6, 7);
face(0, 1, 5, 4);
glutWireCube(2.5f);
glutPostRedisplay();
}
void drawAxis(void){
// save previous matrix
glPushMatrix();
// clear matrix
glLoadIdentity();
// draw our axes
glRotatef(45.0, 1.0, 0.0, 0.0);
glRotatef(45.0, 0.0, -1.0, 0.0);
glBegin(GL_LINES);
// draw line for x axis
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(10.0, 0.0, 0.0);
// draw line for y axis
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 10.0, 0.0);
// draw line for Z axis
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 10.0);
glEnd();
// load the previous matrix
glPopMatrix();
glutPostRedisplay();
}
void spinCube()
{
theta[axis] += delta;
if (theta[axis] > 360.0) theta[axis] -= 360.0;
glutPostRedisplay();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef(45.0, 1.0, 0.0, 0.0);
glRotatef(45.0, 0.0, -1.0, 0.0);
drawAxis();
glPushMatrix();
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
glTranslatef(0.0, 0.0, distance + 2.0);
glCallList(listName);
glPopMatrix();
glutSwapBuffers();
}
void myReshape(int w, int h)
{
GLfloat aspect = (GLfloat) w / (GLfloat) h;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-10.0, 10.0, -10.0 / aspect, 10.0 / aspect, -50.0, 50.0);
else
glOrtho(-10.0*aspect, 10.0*aspect, -10.0, 10.0, -50.0, 50.0);
glMatrixMode(GL_MODELVIEW);
}
void mouse(int btn, int state, int x, int y)
{
if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { axis = 0;
}
if (btn == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) { axis = 1;
}
if (btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { axis = 2;
}
}
void keyboard(unsigned char key, int x, int y)
{
if (key == 'q' || key == 'Q') exit(0);
if (key == ' ') { stop = !stop; }
if (stop)
glutIdleFunc(NULL);
else
glutIdleFunc(spinCube);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);
glutInitWindowSize(600, 600);
glutCreateWindow("cube");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutIdleFunc(spinCube);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
//creating a display list:
listName = glGenLists(1);
glNewList(listName, GL_COMPILE);
cube();
glEndList();
glEnable(GL_DEPTH_TEST);
glutMainLoop();
return 0;
}
What you're after might be accumulating arbitrary rotations. This can't be done with euler angles, which gimbal lock. It's pretty common to have euler angle rotations and in most cases the issue is simply to do with the order they're applied in. The first thing I'd suggest is to reverse the order of your x/y/z rotations.
Next, if you want to accumulate rotations you'll really want to get into quaternions. This can be done with matrices but can easily become numerically unstable. Quaternions can be normalized which solves this issue.
If you rotate around X, the first call is of course, glRotatef(a, 1, 0, 0); draw(). Then you want to rotate the object and its current rotation around y. Note that the object and current rotation are grouped in this line of thinking. So you glRotatef(b, 0, 1, 0); glRotatef(a, 1, 0, 0); draw();. Each time you rotate, you add the rotation behind the existing list of transforms. If you added in front, it'd transform the object in its local space and not global. What you could do is this (near-pseudo-code with an imaginary matrix implementation):
Keep a current object transform matrix M
In spinCube, M = rotationMatrix(delta, axis==0?1:0, axis==1?1:0, axis==2?1:0) * M (note it's rotation * M and not M * rotation.
Before you draw the cube, glMultMatrixf(M.data)
The problem is floating point error will build up over time and the matrix will start to skew/scale your object in weird ways. Instead, you'll want a quaternion implementation (again near-pseudo-code):
Q = rotationQuaternion(delta, axis==0?1:0, axis==1?1:0, axis==2?1:0) * Q
Q.normalize()
...
glMultMatrixf(Q.toMatrix().data)

Sun as a light source using opengl and c++

I am working on the solar system and I am trying to get the sun to be the central light source of this program but it's not working the way I thought it would.
Here is a picture of what I have without lighting.
Here is the same program with lighting.
A different angle here so you can see that the Earth has no shadow as it is supposed to (ignore the red on the moon, that's for my reference)
I don't know if you can tell, but it looks like the light is centered in each sphere, and not in the Sun.
The shadow on the Earth is as if the light was coming from the top. Same with the Sun. The Sun here is not a light source, it's just a sphere that is also being lit by some some source. There is no shadow from the Earth on the moon or from the moon on the Earth.
This here is the code that draws the system
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat pos[] = { 0.0, 0.0, 1.0, 0.0 };
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightf(GL_LIGHT0, GL_POSITION, pos);
//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;
//orbit speed, rotation speed, moon reference coordinates (Parent planet's major and minor Axis)
Sun.displayPlanet(sunOrbS, sunRotS, 0.0, 0.0);
//EARTH
Planet Earth ("/home/rodrtu/Desktop/SolarSystem/images/EarthTopography.png",
50, 49, 500.0, 450.0, 23.5);
double eaOrbS = orbitSpeed*2;
double eaRotS = rotatSpeed*5;
Earth.displayPlanet(eaOrbS, eaRotS, 0.0, 0.0);
//Orbit path
drawCircle(800, 720, 1, 50);
//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 > 719.0)
rotatSpeed = 0.0;
These next two functions are responsible for coordinates and drawing the spheres
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();
}
If I'm way off on what I am doing could you point me to a good tutorial? I have read a few but I guess I didn't understand them as I thought I did.
If I'm on track, could you show me where I'm wrong and what I need to do right?
You need to call glLightfv(GL_LIGHT0, GL_POSITION, pos); and set the position of the light source to the center of the sun.

rotating object relative to camera in OpenGL

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).