Page 1 of 1

Problems creating a Google Earth interface

Posted: Sun Jun 24, 2007 6:50 pm
by itzjac
Hi working friends, I am developing a game which needs a node rotation exactly as Google Earth interface does with the earth model. I have solved the 2D-3D transforming by interacting with the mouse as well as to distinguish the bounding area for that node in order to avoid clicking on empty areas or other nodes. The problem comes with the rotation.

If you check the Google Earth interface you can see if your mouse move [up-down] your earth rotate downwards, or [right-left] your earth rotate leftwards, it doesn't matter the 3D model position. Oposite on my irrlicht project the rotation is exactly as Google Earth interface, but when I reach some "limits" the rotation becomes non-intuitive, I want to solve that problem.

I thing that I can make the RelativeTransformation becomes the AbsoluteTransformation every time I stop rotating the model but I don't know how can that be done. :D [/url]

Posted: Mon Jun 25, 2007 8:13 am
by Robert Y.
What you are describing is Gimbal Lock, which occurs when you try to rotate with Euler angles.

Search the net for Gimbal Lock, Trackball Rotation and Quaternions to find a solution.

Posted: Mon Jun 25, 2007 11:28 am
by LLDD
This basic quaternion tutorial may help you: http://sacredsoftware.net/tutorials/Qua ... ions.xhtml
________
Gm Foods

Posted: Mon Jun 25, 2007 5:54 pm
by itzjac
Surely I will need a lot of math understanding that topics, could you please send more tutorials for understanding that maths and later usign it with irrlicht, I remember when I began my project usign GLUT the behavior of the rotation was very similar to Google Earth and there was a very few algorith besides, why is so dificult with Irrlicht?

This algorith received the x,y mouse position

Code: Select all


void AreaMateria::moverModelo(int x, int y){
      if(!false){
     alfa = (alfa + (y - y0));
     beta = (beta + (x - x0));
     x0 = x; y0 = y;
    }
    else
         if(false){
            gama = (gama - (x - xz0));
            xz0 = x;
            gama= (gama - (y - yz0));
            yz0=y;
         }

     glutPostRedisplay();
}

This algorith use the alfa, beta and gama angles for the rotation :

Code: Select all

void AreaMateria::despliega(){


        glPushMatrix();
               despliegaModelo(fondo,activarnormales);
    glPopMatrix();
        glPushMatrix();
    glBlendFunc		( GL_SRC_ALPHA, GL_ONE );
    glEnable(GL_BLEND );

           
            glRotatef(alfa, 1.0f, 0.0f, 0.0f);
            glRotatef(beta, 0.0f, 1.0f, 0.0f);
            glRotatef(gama, 0.0f, 0.0f, 1.0f);
            

    despliegaModelo(modelo1,activarnormales);
    glDisable(GL_BLEND );
        glPopMatrix();
}
It will be very useful to undestand quatenions with code examples, thanks :lol:

Posted: Mon Jun 25, 2007 11:30 pm
by Andrey
I had the same problem. I've tried to figure out, how to make the same camera motions like in the game Lineage2. The basic principles are almost the same like in GoogleEarth. But I didn't know about any of these quaternions, Euler angles etc..
So, I took the paper sheet and began to draw my camera in 3d-coordinates :)

So, thats the code from my camera wrapper class(just a few trigonometry...) :

Code: Select all

void CameraWrapper::UpdateData()
{
	*curr_pos = this->camera_node->getPosition();
	*targ_pos = this->camera_node->getTarget();
    R = this->camera_node->getPosition().getDistanceFrom(*targ_pos);
			
	D->X = curr_pos->X - targ_pos->X;
	D->Y = curr_pos->Y - targ_pos->Y;
	D->Z = curr_pos->Z - targ_pos->Z;

	xr = atan(D->Z / D->Y) * 180.0f / PI;
	yr = atan(D->Z / D->X) * 180.0f / PI;
	zr = atan(D->Y / D->X) * 180.0f / PI;
	
	curr_angle = acos(D->Y / R) * 180.0f / PI;
	xangle = atan(D->Z / D->X) * 180.0f / PI;
	zangle = atan(D->X / D->Z) * 180.0f / PI;
}

void CameraWrapper::SetNewPos()
{
	newD->X = curr_pos->X - targ_pos->X;
	newD->Y = curr_pos->Y - targ_pos->Y;
    newD->Z = curr_pos->Z - targ_pos->Z;

	if((D->X > 0) ^ (newD->X > 0))
		if(newD->X > 0)
			curr_pos->X -= 2*newD->X;
		else
			curr_pos->X += 2*newD->X;

	if((D->Z > 0) ^ (newD->Z > 0))
		if(newD->Z > 0)
			curr_pos->Z -= 2*newD->Z;
		else
			curr_pos->Z += 2*newD->Z;

	camera_node->setPosition(*curr_pos);
}
void CameraWrapper::TurnRight(f32 angle)
{
	this->UpdateCurrPos();
	curr_pos->rotateXZBy(angle, *targ_pos);
	camera_node->setPosition(*curr_pos);
}

void CameraWrapper::TurnLeft(f32 angle)
{
	this->TurnRight(-angle);
}

void CameraWrapper::TurnDown(f32 angle)
{
	this->UpdateData();
	if(curr_angle <= 88.9f)
	{
		curr_angle += angle;			
		curr_pos->Y = cos(curr_angle*PI/180.0f)*R + targ_pos->Y;
		vSum = R * sin(curr_angle*PI/180.0f);
		curr_pos->X = vSum * cos(xangle*PI/180.0f) + targ_pos->X;
		curr_pos->Z = vSum * cos(zangle*PI/180.0f) + targ_pos->Z;
		this->SetNewPos();
	}
}

void CameraWrapper::TurnUp(f32 angle)
{
	this->UpdateData();
	if(curr_angle >= 1.1f)
	{
		curr_angle -= angle;			
		curr_pos->Y = cos(curr_angle*PI/180.0f)*R + targ_pos->Y;
		vSum = R * sin(curr_angle*PI/180.0f);
		curr_pos->X = vSum * cos(xangle*PI/180.0f) + targ_pos->X;
		curr_pos->Z = vSum * cos(zangle*PI/180.0f) + targ_pos->Z;
		this->SetNewPos();
	}
}
I hope, it will help...

Posted: Tue Jun 26, 2007 4:41 pm
by itzjac
Thanks Andrey it seems to be a posible answer to my problem, searching about quaternions I found some code to rotate with a quaternion variable, I don't undernstand very well but I think this is another solution, I hope some one can explain me this:

My original code

Code: Select all

   
alfa = (alfa+ (event.MouseInput.Y - y));
beta = (beta + (event.MouseInput.X - x));

x = event.MouseInput.X; y = event.MouseInput.Y;
                      

 node-> setRotation(core::vector3df( -0.5*alfa,
                                                -0.5*beta,0 ));

quaternion code

Code: Select all

 /*get the actual rotation and covert it to quaternion*/
core::vector3df euler = node->getRotation();
core::quaternion current(euler.X, euler.Y, euler.Z);

/*get angles because mouse movement*/
alfa = (alfa+ (event.MouseInput.Y - y));
beta = (beta + (event.MouseInput.X - x));

x= event.MouseInput.X; y = event.MouseInput.Y;


axis = core::vector3df(-0.5*alfa, -0.5*beta, 0.0f);
axis.normalize();
core::quaternion rotation;
rotation.fromAngleAxis(0.1*PI, axis);
rotation = current*rotation;


rotation.toEuler(euler);
/*conversion between radians and euler angles*/
node->setRotation(euler*57.2957795);

Posted: Sat Jul 07, 2007 7:09 pm
by itzjac
Hi again!! I have been working with those quaternions and I have made my project to work exactly as when I was using the simple setRotation (..)instruction, here is my code running correctly:

Code: Select all

          /*reference to obtain the actual rotation I haven't found the use of
          current yet but in other post they used it*/
          core::vector3df euler1 = node->getRotation();

          core::quaternion current(euler1.X,euler1.Y,euler1.Z);

          /*angles produced by mouse movement*/
         alfa = (alfa+ (event.MouseInput.Y - y));
         beta = (beta+ (event.MouseInput.X - x));

         x = event.MouseInput.X;y = event.MouseInput.Y;


         /*x-arounn rotation, y-around rotation and rotation*/
         core::quaternion rotationX;
         core::quaternion rotationY;
         core::quaternion rotation;

         /*the vectors where the rotations are made don't foget t
         normalize*/
         core::vector3df axisX(1.0f,0.0f,0.0f);
         core::vector3df axisY(0.0f,1.0f,0.0f);
         axisX.normalize();
         axisY.normalize();

         /*
         angle/axis rotation for quaternions receive only
         radians we have to convert it
         radians = degrees *(PI/180)
        */
          rotationX.fromAngleAxis(alfa*PI/180.0f,axisX);

          rotationY.fromAngleAxis(-beta*PI/180.0f,axisY);

         /*it doesn't matter the order rotationY*rotationX here because the
         effect is the same 
         concatenate the X rotation with Y rotation*/
         rotation = rotationX*rotationY;
 
         /*convert the concatenated rotation to Euler angles on radians*/
         rotation.toEuler(euler1);

        /*set the rotation of auler angles  converting radians to degrees*/
        node->setRotation(euler1* 57.2957795);
The end effect is the same as with the simple setRotation(..) instruction, remember what I need is simple end soft rotation interface as
Google Earth
if you move your mouse left-rigth you need to rotate the node to rigth, it doesn't matter the relative or absolute rotation, if you move your mouse top-down you rotate down, thanks again the quaternions tutorial from Ogre Wiki was perfect!!! :D