• Create Account

# Direct3D 9 and 360 degrees

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

32 replies to this topic

### #1theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 16 April 2012 - 01:21 PM

Hey,

I'm new here and I have a silly question to start off.

I have a simple program that draws a cube. You can rotate the cube with arrow keys and look around on one spot with the camera.
Now I've been messing around with it, thinking wouldn't it be fun to make a 360 degree turn and get back to my cube.
What the program instead does, is keep going infinitely in the direction I choose and it will take the same amount of moving the mouse to get back to the object (hence, it never makes a 360 degree turn).

So, the impression this left me is that direct3D thinks that there is an infinite amount of space or something along those lines.
Almost like every 360 turn is on a next level and to get back to the object, you need to turn around enough times to get to the level the object is at.

Anyway, enough fantasy, here's the code:
D3DXMATRIX matView;	// the view transform matrix
static float LookX = 0.0f; LookX -= mousestate.lX * 0.0075f;
static float LookY = 0.0f; LookY -= mousestate.lY * 0.0075f;
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (0.0f, 0.0f, 15.0f),	// the camera position
&D3DXVECTOR3 (LookX, LookY, 0.0f),	// the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f));	// the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView);	// set the view transform to matView


What should I do to fix this problem? I'd rather not start guessing on my own this time, but if I should stay vague, then I think I would probably need to do some checks on the LookX and LookY values??
------------------------------

I'm using directX 9 and Visual studio 2008

Cheers,
Theo

### #2ApochPiQ  Moderators   -  Reputation: 21060

Like
0Likes
Like

Posted 16 April 2012 - 01:25 PM

You're moving your look position along an infinite line through space, not a circle.
Wielder of the Sacred Wands

### #3theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 16 April 2012 - 01:37 PM

You're moving your look position along an infinite line through space, not a circle.

Yes, it seems like so. I dont exactly understand why the program does that. I seem to be lacking some knowledge on how the API works.
Could you fill me in on the information?

### #4ApochPiQ  Moderators   -  Reputation: 21060

Like
1Likes
Like

Posted 16 April 2012 - 02:20 PM

What you want is something like this:

horizontal_angle += mouse.deltaX * some_factor;
lookat.x = sin(horizontal_angle) * some_distance_value;
lookat.y = cos(horizontal_angle) * some_distance_value;

I may have swapped the sin/cos and you may want z instead of y (I can never remember offhand which axis is which in D3D), so experiment a bit :-)
Wielder of the Sacred Wands

### #5Bacterius  Crossbones+   -  Reputation: 13028

Like
0Likes
Like

Posted 16 April 2012 - 03:22 PM

In D3D Y is the "up" axis, and XZ is the "horizontal" plane.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

### #6theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 17 April 2012 - 08:00 AM

What you want is something like this:

horizontal_angle += mouse.deltaX * some_factor;
lookat.x = sin(horizontal_angle) * some_distance_value;
lookat.y = cos(horizontal_angle) * some_distance_value;

I may have swapped the sin/cos and you may want z instead of y (I can never remember offhand which axis is which in D3D), so experiment a bit :-)

Based on what you wrote, I tried this and even some experimenting
D3DXMATRIX matView;	// the view transform matrix
static float horizontal_angle = 0.0f; horizontal_angle += mousestate.lX * 0.0075f; //what is this one_factor??
static float vertical_angle = 0.0f; vertical_angle += mousestate.lY * 0.0075;
static float LookX = 0.0f;	 LookX = sin(horizontal_angle) * 0.0075f;
static float LookY = 0.0f;	 LookY = cos(vertical_angle) * 0.0075f;
static float MoveX = 0.0f;
static float MoveY = 0.0f;
if(keystate[DIK_A] & 0x80)
{
MoveX += 0.3f;
//LookX = MoveX;
}
if(keystate[DIK_D] & 0x80)
{
MoveX -= 0.3f;
//LookX = MoveX;
}
if(keystate[DIK_S] & 0x80)
{
MoveY -= 0.3f;
//LookY = MoveY;
}
if(keystate[DIK_W] & 0x80)
{
MoveY += 0.3f;
//LookY = MoveY;
}
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (MoveX, MoveY, 15.0f),	// the camera position
&D3DXVECTOR3 (LookX, LookY, 0.0f),	// the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f));	// the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView);	// set the view transform to matView


I did add some movement code, but it has nothing to do with the mouse movement right now.
The thing is, the camera now doesn't budge at all ( Y ) or desperately tries and stays put ( X ).

I do know my math, but I am learning programming independently and so I do not know how to use such geometry math
in my programs.

I certainly dont know how cinus and cosinus fits in there.
------------------

I would still say that it's the API that has no sense of space.
What I would do is think for a week and come up with an algorithm for D3D to understand
where the objects are relative to the camera.

But like you already pointed out, I am wrong about that aspect and need to learn some geometry.

So what did I do wrong in my program?

Theo

### #7theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 17 April 2012 - 11:10 AM

Okay, after I put back my original code, I experimented a bit and found out that direct3D does not let me look away from the object too far. Or rather, after a certain point,
the camera looking movement slows extremely down. So how would I go about fixing that?

### #8ApochPiQ  Moderators   -  Reputation: 21060

Like
0Likes
Like

Posted 17 April 2012 - 11:28 AM

Try multiplying the sin/cos by something large, not something small. Chances are you're providing numbers which are too small.

Also, you might try increasing the factor you use to scale the angle; try larger and larger numbers until you can see results, then narrow it down to a range that gives you a good feel.
Wielder of the Sacred Wands

### #9theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 17 April 2012 - 11:48 AM

Try multiplying the sin/cos by something large, not something small. Chances are you're providing numbers which are too small.

Also, you might try increasing the factor you use to scale the angle; try larger and larger numbers until you can see results, then narrow it down to a range that gives you a good feel.

Okay, this actually works, but not the way I wanted it to.
What it does is that it goes to a certain degree and then comes back the same way.
I wanted a full 360 degree turn, while now it only goes to a certain point and comes back.

### #10theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 17 April 2012 - 11:54 AM

So back to the real problem..Why does the mouse movement become almost unmovable after a certain point away from the object?

### #11ApochPiQ  Moderators   -  Reputation: 21060

Like
0Likes
Like

Posted 17 April 2012 - 12:16 PM

Add MoveX and MoveY to LookAtX and LookAtY. As it stands you're positioned a ways away from the world origin and looking at a point that revolves around the origin.

Try this thought experiment: draw a circle on the floor. Now stand 10 feet away, and watch an ant walk around the circle. The effect should resemble what you're seeing in your code.
Wielder of the Sacred Wands

### #12theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 17 April 2012 - 01:33 PM

Add MoveX and MoveY to LookAtX and LookAtY. As it stands you're positioned a ways away from the world origin and looking at a point that revolves around the origin.

Try this thought experiment: draw a circle on the floor. Now stand 10 feet away, and watch an ant walk around the circle. The effect should resemble what you're seeing in your code.

Wow, that actually fixed the movement problem that I didn't even mention here. But the mouse problem -- it goes back and forth when I turn away from the object. If I turn left, it will go left and after a certain point it will start going back until it reaches that certain point on the right side. So it keeps going like this:

oooooooXoooooooo
<--------------------->o
oooooooooooooooo

X being the object and the line the point where the camera looks at. The point is that it will never see the X that would be on the other side of the line, let alone make a 360 turn and see the object first from the other side.
('o' dont have any meaning here, I couldn't get the X to be in the middle)

### #13ApochPiQ  Moderators   -  Reputation: 21060

Like
0Likes
Like

Posted 17 April 2012 - 06:16 PM

Can you post your current code? I have a feeling I miscommunicated the correct fix for the problem.

Anyways, you really should do my thought experiment. I think it'll help you understand what you're seeing.
Wielder of the Sacred Wands

### #14theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 17 April 2012 - 11:59 PM

D3DXMATRIX matView;	// the view transform matrix

static float horizontal_angle = 0.0f; horizontal_angle -= mousestate.lX * 0.075f;
static float vertical_angle = 0.0f;   vertical_angle -= mousestate.lY * 0.075f;
static float LookX = 0.0f;			LookX = sin(horizontal_angle) * 20.0f;
static float LookY = 0.0f;			LookY = cos(vertical_angle) * 20.0f;
/*static float LookX = 0.0f; LookX -= mousestate.lX * 0.003f;
static float LookY = 0.0f; LookY -= mousestate.lY * 0.003f; */
static float MoveX = 0.0f;
static float MoveY = 0.0f;
LookX += MoveX;
LookY += MoveY;
if(keystate[DIK_A] & 0x80)
{
MoveX += 0.3f;
//LookX += MoveX;
}
if(keystate[DIK_D] & 0x80)
{
MoveX -= 0.3f;
//LookX -= MoveX;
}
if(keystate[DIK_S] & 0x80)
{
MoveY += 0.3f;
//LookY += MoveY;
}
if(keystate[DIK_W] & 0x80)
{
MoveY -= 0.3f;
//LookY -= MoveY;
}
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (MoveX, MoveY, 15.0f),	// the camera position
&D3DXVECTOR3 (LookX, LookY, 0.0f),	// the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f));	// the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView);	// set the view transform to matView


Oh, I think I finally understood what you meant by the ant.

I need the camera to look around and along the circle, is that what you meant?
It came to me because I was looking at how other people were making the camera move.
I'm supposed to rotate the axes or something along those lines? (instead of making the camera look left or right)
But that wouldn't work either if the object is indeed the center of the world. It would just make the object rotate.
So if I had to guess, then perhaps I need a way to make the camera be in the center of the world instead.
But even so.. some calculations would probably be off the moment I move from there..

### #15ApochPiQ  Moderators   -  Reputation: 21060

Like
0Likes
Like

Posted 18 April 2012 - 12:50 PM

OK, I see what's going on.

You're never changing the Z coordinate of your look-at position, meaning that you never move in the horizontal plane. You just slide the X coordinate back and forth along a sinusoidal curve.

The formula should look like this:

LookAtX = MovePositionX + sin(horizontal_angle);
LookAtZ = MovePositionZ + cos(horizontal_angle);

Get horizontal movement working first, and then we can complicate things by throwing in the additional rotation to do vertical movement :-)
Wielder of the Sacred Wands

### #16theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 19 April 2012 - 10:20 AM

D3DXMATRIX matView;	// the view transform matrix

static float MouseSpeed = 0.0075f;

if (keystate[DIK_F1])
{
MouseSpeed += 0.0001f;
}
else if (keystate[DIK_F2])
{
if (MouseSpeed > 0.0001f)
{
MouseSpeed -= 0.0001f;
}
}
static float horizontal_angle = 0.0f; horizontal_angle += mousestate.lX * MouseSpeed;
static float vertical_angle = 0.0f;   vertical_angle += mousestate.lY * MouseSpeed;

static float LookX = 0.0f;			LookX = (sin(horizontal_angle) * 20.0f);
static float LookY = 0.0f;			LookY = (cos(vertical_angle) * 20.0f) - 20.0f;
static float LookZ = 0.0f;

static float MoveX = 0.0f;
static float MoveY = 0.0f;
static float MoveZ = 0.0f;
if(keystate[DIK_A] & 0x80)
{
MoveX -= 0.3f;
}
if(keystate[DIK_D] & 0x80)
{
MoveX += 0.3f;
}
if(keystate[DIK_S] & 0x80)
{
MoveY -= 0.3f;
}
if(keystate[DIK_W] & 0x80)
{
MoveY += 0.3f;
}
//in order for the camera to keep looking in the same direction
LookX += MoveX;
LookY += MoveY;
LookZ = MoveZ + (cos(horizontal_angle) * 20.0f); //this one has something to do with turning around 360*
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (MoveX, MoveY, MoveZ),	// the camera position
&D3DXVECTOR3 (LookX, LookY, LookZ),	// the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f));	// the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView);	// set the view transform to matView


So there it is, I did not believe it, but the horizontal movement works now.

I also tried to get vertical movement to work INSTEAD, and it did work, but after moving away from the object,
I noticed that what it did was move like around the orbit...

In any case, how to get vertical movement to work as well?

I still don't understand what the Z coordinates do in terms of the camera.
At first I thought that it's like zoom in or zoom out, but that's not it.
X and Y points at where the camera should look, but Z never seemed to do anything,
except in terms of moving in and out.

Oh and..
LookY = (cos(vertical_angle) * 20.0f) - 20.0f;


For some reason, the camera looked down in terms of the object, so I had to substract 20.0f for it to look perfectly at the object. Why is that?
The object is positioned at:

D3DXMatrixTranslation(&matTranslateA, 0.0f, 0.0f, 15.0f); //15.0f away from the camera


### #17ApochPiQ  Moderators   -  Reputation: 21060

Like
0Likes
Like

Posted 19 April 2012 - 01:05 PM

I would strongly suggest you get a refresher in basic 3-space Cartesian geometry. This is pretty elementary mathematics and you'll need a very solid grasp of it to do 3D graphics programming.
Wielder of the Sacred Wands

### #18theo2005  Members   -  Reputation: 114

Like
0Likes
Like

Posted 19 April 2012 - 01:50 PM

I would strongly suggest you get a refresher in basic 3-space Cartesian geometry. This is pretty elementary mathematics and you'll need a very solid grasp of it to do 3D graphics programming.

I'm really sorry, but I, nor anybody else in my class (or even the next class) has learned 3D Cartesian geometry/analytic geometry.
Everything we have been doing so far is only 2D (with the exception of formulas for cubes and pyramids).

It seems like the kind of stuff you learn in the university.

If you are only willing to share formulas (which will help me temporarily) without an explanation (and I'm not expecting to get a math course from you or anybody else on this forum), then I suppose I have no choice but to bother the physics teacher at my school (again).

I actually tried to explain my problem to the math teacher (without getting into the programming), but she just redirected me to the physics teacher, who needed more information to help me anyway.

### #19ApochPiQ  Moderators   -  Reputation: 21060

Like
1Likes
Like

Posted 19 April 2012 - 02:47 PM

You can get the basic formulas from here, or general Google searches for "3D Euler angle rotations." It should help you get started even if you don't have the foundations in the maths yet.

By the way, I have to say it's impressive that you're willing to forge ahead with this and learn on your own ahead of the "normal pace." Good on ya, and keep it up.

Good luck :-)
Wielder of the Sacred Wands

### #20Bacterius  Crossbones+   -  Reputation: 13028

Like
0Likes
Like

Posted 19 April 2012 - 02:54 PM

I'm really sorry, but I, nor anybody else in my class (or even the next class) has learned 3D Cartesian geometry/analytic geometry.
Everything we have been doing so far is only 2D (with the exception of formulas for cubes and pyramids).

But if you don't know anything about 3D geometry how do you expect to understand 3D matrix transformations/projections, sense of ordinary space, all that stuff? Not that I'm saying it's impossible but it will be difficult without a knowledge of the basics. Otherwise magic constants (such as the 20's in your code) start appearing and you have no idea why.

Anyway. The D3DXMatrixLookAtLH function takes as an input a 3D coordinate which specifies the location (in "world" space) of the camera, and a 3D coordinate which specifies the location of the target (thus the direction in which the camera is looking can be obtained by a subtraction). The third parameter is the up vector but it can be kept to (0, 1, 0) until you want to perform "roll" rotation (i.e. rotation along the Z axis).

In your code the camera's target is derived from the mouse position in an incorrect manner. What happens is that your camera's target (what the camera is looking at) is rotating along a non-obvious curve centered on the origin (because you messed up with the angle calculation). I suspect you want the camera target to rotate in a graceful curve as you move the mouse around (like a spherical magnet would slide all around another). You need to use spherical coordinates for this, (this is why you need to know 3D geometry) which map two angles and a radius onto a sphere's surface. The formulas are not obvious to the beginner but work (more on wikipedia):

For a horizontal angle Phi and a vertical angle Theta (both in radians), and a radius R, the corresponding point on the sphere (centered on the origin, translate if needed):

X = R * cos(Phi) * sin(Theta)
Y = R * Sin(Theta)
Z = R * sin(Phi) * Sin(Theta)

(assuming the Y axis goes upwards).

Now if you put this in your code, instead of the "ant around a circle" result Apoch described earlier, you will get an "ant around a sphere" result. Now if you add MoveX to LookX and MoveY to LookY and MoveZ to LookZ, then you will have translated the rotation center onto the camera's position, which means you will be able to look around in every direction by moving the mouse around (like in FPS shooters, for instance). Finally, the radius of the rotation does not matter because it will not change the direction the camera is facing (in the LookAt function, the direction ends up being normalized, so any scaling factor is cancelled out).

As for the the magic constant in the code which "sorta kinda worked", I suspect it simply happened to reduce the visible error to a minimum (while still being completely wrong).

So the final correct code would be:

LookX = cos(angleX) * sin(angleY)
LookY = Sin(angleY)
LookZ = sin(angleX) * Sin(angleY)

MoveX, MoveY, MoveZ as usual (keyboard is used to move around)


And:

D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (MoveX, MoveY, MoveZ), // the camera position
&D3DXVECTOR3 (LookX + MoveX, LookY + MoveY, LookZ + MoveZ), // the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction

And there you have it, you reinvented camera rotation in its simplest form. With this code you should be able to use the keyboard to move around the world, and use the mouse to naturally look around (which is what you wanted, right?)

Also, make sure you put bounds on the Theta (angleY) angle so that the camera cannot "flip vertically" because then everything will be inverted. In real life this would correspond to looking forward, then looking upwards, until you bend your neck backwards (and same for looking downwards), which results in an extremely unintuitive sense of direction, so for player sanity we usually ensure -pi/2 < angleY < pi/2, although this may depend on the API (conventions and stuff). But that's just a minor detail.

-------------------

I may have made mistakes in the post above, but I think this is what you were looking for. If not, then I did not understand your problem so if it is so can you reformulate it in the simplest way possible (what do you want to achieve?)

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

PARTNERS