My earth needs camera help!

Started by
6 comments, last by MasterWorks_Software 20 years, 3 months ago
Hi all, I''ve got a DX8 game that uses textured quads for sprites. This is a game where you defend the earth from asteroids, and everything except the earth is done in 2-D. This is a question about the 3D part. The earth is a polygon sphere. After each level, I''d like the camera to rotate around the earth to a new viewpoint. This is for cosmetic effect and has nothing to do with the game; just to keep things interesting, basically. Until now I''ve been using D3DXMatrixLookAtLH, and when I need a new orientation, I choose a new camera position, a new look_at point, and a new up vector, then linearly interpolate from the old values to the new values. Needless to say this looks terrible. I understand that I might be better off using yaw/pitch/roll and then assembling my own view matrix. I could even use quats to interpolate the motion. The problem here is that because this is a 2D game, I need to control the eventual 2D position of the earth. By not using Euler angles, I can first choose a random destination camera location and a random destination up vector and based on that I can (using some math) calculate a destination look_at point such that the center of the Earth ends up, for example, at pixel coordinates (640, 240). Concisely stated, my goal is to move the earth on the 2D screen (by moving the camera) from (xOld,yOld) to (xNew, yNew) but with some sort of pleasing, fluid motion and a new view of the planet (looking at Asia to begin with and South America to end with, for instance, with the ''up'' vectors being anything imaginable). Anybody got any ideas on this? This has turned out to be far more complicated than I envisioned... the look_at description of camera orientation is very convenient for my 2D purposes but so horrendous for interpolating motion that I don''t know what to do. Many thanks, Jay
Advertisement
Consider not moving the view matrix at all, but the sphere''s world matrix. You can specify the rotation about the y axis, and the sphere will turn. You can then apply a transform to get it anywhere you want, within the [-1,-1][1,1] bounds of the view space, to offset it from the camera. After, that, rotate the planet along the z axis to change its ''up'' vector around.

In other words, your game doesn''t have to revolve around the world; the world can rotate under the game. You may have to move lights around too, if you''re using any, but it''s similar.

I like pie.
[sub]My spoon is too big.[/sub]
This is not a bad idea, I had avoided trying to move the Earth itself because then the lighting on the earth would shift, but I guess I could update the lights also.

Given a directional light and the earth''s rotation , how do I find the new direction for the light so that the sun is still property oriented to the earth?
If you rotate the earth around it's model origin, then rotate the sun around that same origin (after it has been translated), that should do the trick. Typically, one would rotate a model, then translate it to it's new position. In the case of the earth, it's rotated, but there is no need for translation.

So, if you did the opposite with the sun, first translate it from it's origin (also the earth's origin) in some arbitrary direction, then rotate it about that origin the same number of degrees that the earth rotated...there you have it. The only requirement I can think of is that the earth's origin and sun's origin will have to be the WORLD space origin.

One question is which arbitrary direction do you translate the sun in? Well, if Asia is your starting point, and Asia is facing the player, pointing in the negative z direction, I you would probably want to translate the sun into the -z direction, and maybe a smaller distance either way in the x direction, just to have an offset.

Pseudo Code:
SetTransform(WORLD, Zero);
EarthTransform = Rotate(Degrees);
SetTransform(WORLD, EarthTransform);
DrawEarth();
SunTransform = Translate(VectorFromEarth);
SunTransform = SunTransform*Rotate(Degrees);
SetTransform(WORLD, SunTransform);
DrawSun;

This assumes you have a sun that is visible on the screen. If not, I think you can still create a matrix to symbolize the sun, operate on it, then take the light's position and assign the positional components from the matrix to it...I think... Or you could calculate it with sines and cosines.

EDIT: Oops, you're using directional lights, I was thinking point source. For a directional vector, you could use sines and cosines to calculate the position on the unit circle where the light would lie, then inverse the position (assuming your earth is at origin) to get the direction.

Assuming CCW rotation:
EarthTheta = 0;
SunOffset = 300;
This makes the "Sun" begin at a position to the right of the player.
Distance = 100;
SunTheta = SunOffset + EarthTheta;
SunPosX = sin(SunTheta);
SunPosZ = cos(SunTheta);
SunDirection = (-SunPosX, -SunPosZ)*Distance;

Also note, that you can make the sun slowly move around the earth at a different rate than the earth moves, just by changing the SunOffset on a frame by frame basis (or every 10 seconds adjusting it).

I'm a little rusty, if I messed up, please someone correct me! It's also late.

Chris

[edited by - Supernat02 on January 13, 2004 11:52:10 PM]

[edited by - Supernat02 on January 13, 2004 11:56:22 PM]
Chris ByersMicrosoft DirectX MVP - 2005
Chris,

Thanks for your help, but I''m not sure I understand your code regarding the directional light.

Right now I have been using:

x = 0
y = 0
z = -1
myLight.direction = vec3(x, y, z)

Your suggestion only has X and Z in it which makes me think there must be some flaw. If the earth can be freely rotated (x, then y, then z) then it seems the light direction will just correspond to a point on the unit sphere. (This is close to what you said regarding a unit circle but I''m not sure how to extend the other dimension: (sin x, cos y, ??? z) I''m familiar with spherical coordinates but we have 3 angles to work with here, not 2 angles and a distance...

Can I quickly calculate this position (or vector, however you want to look at it) using the world matrix that I used to transform the earth? Or some other way? This seems like a ridiculously easy problem but my linear-algebra brain isn''t functioning properly.

I have to make sure the light direction is consistent, we wouldn''t want the sun shining on the north or south pole!!

-Jay

I'm sorry about that. That was just psuedo code. I assumed y = 0 in all calculations, forgot to write that down though. I also assumed the earth only rotating in one direction, around the y axis. Making y always equal 0 for the earth, sun, and light will help reduce the calculations and keep them centered at the origin. However, I think y is independent, so you can set it to 10, -10, whatever you want. Just always use that for y in the calcs.

void DrawStuff(int Theta){int   LightDistance = 10  LightY = 0,  LightX,  LightZ;  LightX = sin(Theta)*LightDistance;  LightZ = cos(Theta)*LightDistance;D3DXMATRIX World;D3DXMatrixTranslation(0, 0, 0);D3DDevice->SetTransform(D3DTS_WORLD, &World);D3DLIGHT9 Light;// Initialize a D3DLIGHT9 structure here.Light.Direction = D3DXVECTOR3(-LightX, -LightY, -LightZ);// Draw the Earth here with SetStream, FVF, DrawPrimitive, etc.}


Hope this is more clear.

Now, for rotating the earth in the other two axis, it gets a little more complex. I'm sorry I didn't catch that in your first post. I would suggest first just doing the above, unless you already have, and then working further from there. You can try the stuff below, but I don't know if it will work for what you need. You first need to know theta and phi.

r = distance from earth
theta = angle rotated in x-z plane.
phi = angle from x-z plane to the y axis AFTER the angle theta rotation has occured.

So, first you would rotate the earth around the y axis, then rotate a number of degrees up from the x-z plane...if that makes sense.

x = r*cos(theta)*sin(phi);
z = r*sin(theta)*sin(phi);
y = r*cos(phi);

Light.Direction = D3DXVECTOR3(-x, -y, -z);

At least this will allow you to rotate the earth using 2 angles, to any position, then calculate where the light should be.

Chris



[edited by - Supernat02 on January 14, 2004 1:52:57 PM]
Chris ByersMicrosoft DirectX MVP - 2005
Chris,

Thanks again but I''m still a little bit unclear on how to do this.

There is no ''theta'' or ''phi'', that''s what I''ve been getting away from (before I was using a moving CAMERA on a theta/phi/radius track but the interpolation, up vector, and lookat point are all tricky in that orientation.) To make the earth look like it''s rotating I use texture transforms, ie. spin the land and cloud maps around the Earth. This transformation isn''t relevent to the lighting problem.

I''m using D3DXMatrixRotationX/Y/Z (then multiplied together) to create my world matrix that rotates the earth. The perceived effect needs to be that the CAMERA is moving, not the Earth; therefore I need some formula that takes these rotX, rotY, and rotZ values and gives me a new light direction.

I tried setting up a basic vector, myVector = (0,0,1) for instance, and then D3DXVec3TransformCoord vOut, myVector, mWorldMatrix and use the results from vOut as the direction for the light but that doesn''t seem to work.

Any suggestions?
Also, I am open to using point lights if that will help!

This topic is closed to new replies.

Advertisement