# Direct3D 9 and 360 degrees

This topic is 2096 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

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:
[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
[/CODE]

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

##### Share on other sites
You're moving your look position along an infinite line through space, not a circle.

##### Share on other sites
[quote name='ApochPiQ' timestamp='1334604357' post='4931825']
You're moving your look position along an infinite line through space, not a circle.
[/quote]

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?

##### Share on other sites

What you want is something like this:

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

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

##### Share on other sites
In D3D Y is the "up" axis, and XZ is the "horizontal" plane.

##### Share on other sites
[quote name='ApochPiQ' timestamp='1334607607' post='4931848']

What you want is something like this:

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

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 :-)
[/quote]

Based on what you wrote, I tried this and even some experimenting
[CODE]
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
[/CODE]

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

##### Share on other sites
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?

##### Share on other sites
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.

##### Share on other sites
[quote name='ApochPiQ' timestamp='1334683718' post='4932198']
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.
[/quote]

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.

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

##### Share on other sites
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.

##### Share on other sites
[quote name='ApochPiQ' timestamp='1334686574' post='4932219']
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.
[/quote]

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)

##### Share on other sites
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.

##### Share on other sites
[CODE]
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
[/CODE]

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

##### Share on other sites
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 [i]plane[/i]. 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 :-)

##### Share on other sites
[CODE]
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
[/CODE]

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..
[CODE]
LookY = (cos(vertical_angle) * 20.0f) - 20.0f;
[/CODE]

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:

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

##### Share on other sites
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.

##### Share on other sites
[quote name='ApochPiQ' timestamp='1334862328' post='4932902']
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.
[/quote]

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.

##### Share on other sites
You can get the basic formulas from [url="http://www.fastgraph.com/makegames/3drotation/"]here[/url], 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 :-)

##### Share on other sites
[quote]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).[/quote]
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). [color=#ff0000]You need to use spherical coordinates for this[/color], (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:

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

MoveX, MoveY, MoveZ as usual (keyboard is used to move around)
[/CODE]

And:

[CODE]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[/CODE]

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

##### Share on other sites
Apoch and Bacterius, thank you

The code Apoch gave me did indeed seem to work, but even so, as I moved away from the object, strange things seemed to arise.
The magical constant 20.0f seemed to work the best with no twiching at the location I was at, but as I moved farther away from the object,
something fishy was happening anyway. And the curve that the Y rotated by .. it was fishy as well.

Question about your code Bacterius, the Sin with the capital S does not work in the program.
I searched google and it seemed that the domain (whatever that is) is different for sin and Sin.
So what would be the function for Sin in directX?

Cheers,
Theo

##### Share on other sites
Sorry, it was obviously a typo. I was typing pseudocode quickly. It's just the standard sin function.

##### Share on other sites

I can't see my object... why?? (cannot find it)

Here's the whole code (related to transformations):

[CODE]
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 AngleX = 0.0f; AngleX += mousestate.lX * MouseSpeed;
static float AngleY = 0.0f; AngleY += mousestate.lY * MouseSpeed;

static float LookX = 0.0f;
static float LookY = 0.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;
}
LookX = cos(AngleX) * sin(AngleY);
LookY = sin(AngleY);
LookZ = sin(AngleX) * sin(AngleY);
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (MoveX, MoveY, MoveZ), // the camera position
&D3DXVECTOR3 (LookX + MoveX, LookY + MoveY, LookZ + MoveZ), // the look-at position + to go along with movement
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView); // set the view transform to matView
D3DXMATRIX matProjection; // the projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(45), // the horizontal field of view
(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
1.0f, // the near view-plane
1000.0f); // the far view-plane
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection
// ----------------------------------------------------------- CAMERA SETUP <END> --------------------------------------------------------------------------//

// select the vertex buffer to display
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->SetIndices(i_buffer); //select the index buffer
D3DXMATRIX matTranslateA; // a matrix to store the translation for triangle A
D3DXMATRIX matRotateX; // a matrix to store the rotation for each triangle
D3DXMATRIX matRotateY;
static float indexX = 0.0f; // index+=0.03f;
static float indexY = 0.0f;
if(keystate[DIK_LEFT] & 0x80)
{
indexY += 0.03f;
}
if(keystate[DIK_RIGHT] & 0x80)
{
indexY -= 0.03f;
}
if(keystate[DIK_DOWN] & 0x80)
{
indexX += 0.03f;
}
if(keystate[DIK_UP] & 0x80)
{
indexX -= 0.03f;
}
//building matrices
D3DXMatrixTranslation(&matTranslateA, 0.0f, 0.0f, 15.0f); //15.0f away from the camera
D3DXMatrixRotationX(&matRotateX, indexX);
D3DXMatrixRotationY(&matRotateY, indexY);
// tell Direct3D about each world transform, and then draw another triangle
d3ddev->SetTransform(D3DTS_WORLD, &(matRotateX * matRotateY * matTranslateA));
d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
//single primitive: d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
[/CODE]

Also, even tho it was a typo, Sin actually means arcussinus or sin^-1. (asked the math teacher and only one search result on google)

##### Share on other sites
[quote]Also, even tho it was a typo, Sin actually means arcussinus or sin^-1. (asked the math teacher and only one search result on google)[/quote]
Really... that's just stupid. What a messed up convention. Anyway.

Can you make your program print out the values of AngleX, and AngleY each frame (to the console preferably) as well as the values of LookX/Y/Z? Then we'll see if the camera setup code is actually working properly.

I also don't understand something in your code. Is the camera setup executed every frame? Because it should if you want to be able to move around. And if so, why do you reset the values of MoveX, MoveY, MoveZ to zero each frame?