Archived

This topic is now archived and is closed to further replies.

snisarenko

Implementing mouse look in my 3D Engine

Recommended Posts

Ok those people who have done this please give me a clue what i am doing wrong. And propose an alternative on how to do this. Heres what I do when i get a message WM_MOUSEMOVE case WM_MOUSEMOVE: { mouseRotY+=(LOWORD(lParam)-mouseCenter.x)*mouseSpeed; mouseRotX+=(HIWORD(lParam)-mouseCenter.y)*mouseSpeed; SetCursorPos(mouseCenter.x,mouseCenter.y); return 0; } When i run the program it doesn''t Swap Buffers. I figured out why. When I call SetCursorPos It automaticly sends a WM_MOUSEMOVE message which causes it to send it again and again recursivly. So those of you who have done this point me in the right direction. Tell me how you implemented this.

Share this post


Link to post
Share on other sites
ok first of all every time the mouse is moved 1 pixel you will get a WM_MOUSEMOVE message. so what you must do is record the old rotation and the place that the mouse was pressed. then use them to opdate the rotation like this.


case WM_LBUTTONDOWN:
{
mouseCenter.x = LOWORD(lParam);
mouseCenter.y = HIWORD(lParam);

mouseRotYold = mouseRotY;
mouseRotXold = mouseRotX;

return 0;
}

case WM_MOUSEMOVE:
{
mouseRotY = mouseRotYold + (LOWORD(lParam)-mouseCenter.x) * mouseSpeed;
mouseRotX = mouseRotXold + (HIWORD(lParam)-mouseCenter.y) * mouseSpeed;

return 0;
}


this will set the rotation to equal the rotation before the drag pluss a bit based on the distance draged. have a thing about what happens when and the exact values that are passed.

eg. assumeing the mouse was pressed in the middel of your screen:

MOUSEMOVE: x=321 y=240 rotY=1 rotX=0 rotYold=0 rotXold=0
MOUSEMOVE: x=322 y=240 rotY=2 rotX=0 rotYold=0 rotXold=0
MOUSEMOVE: x=334 y=241 rotY=4 rotX=1 rotYold=0 rotXold=0


the above is a good eg of the output you should get in a detailed debug log. youll need to have a globally opened file that a buggy function can write is call paramiters and intermediate values to. just remember to write some text and new lines to the file as well or it will be useless. writeing to a file will slow your program down a lot but can help a lot with some bugs.

-Jono AH

[edited by - jonox on December 26, 2002 12:48:08 AM]

Share this post


Link to post
Share on other sites
I don't think u understood me.

First of all I am not dragging.
I just want the camera to move with the mouse.

mouseCenter is the center of my screen.

the only reason i am putting the mouse in the center of the screen is because if I wouldn't then the cursor would collide with an edge of the screen and wont be able to move anymore.

What I looking for is somehow to get mouse displacement no matter where the cursor is. But there is no function (as far as I know) that will give me that. So I have to place the mouse in the center after each movement. But SetCursorPos sends another mouse move message ang goes into recursion infinetly.

Get it now ?

Basicaly I am trying to get the mouse movement no matter where the cursor is on the screen.

This is just my way of doing mouse-camera movement. I am doing this for the first time.

Somebody please post yours if you can.

[edited by - snisarenko on December 27, 2002 2:06:01 AM]

Share this post


Link to post
Share on other sites

case WM_MOUSEMOVE:
{
MouseX = HIWORD(lParam);
MouseY = LOWORD(lParam);

if(MouseX != MouseCenter.x && MouseY != MouseCenterY)
{
MouseRotX += (MouseX - MouseCenter.y) * MouseSpeed;
MouseRotY += (MouseY - MouseCenter.x) * MouseSpeed;

SetCursorPos(MouseCenter.x, MouseCenter.y);
return 0;
}


can you do that?

Share this post


Link to post
Share on other sites
I think you should simply use a global bool variable to avoid the recursion.

case WM_MOUSEMOVE
if (!g_bRotated) {
...
g_bRotated=true;
}

And after you swapped the buffers you set the variable to false again.

Share this post


Link to post
Share on other sites
1°/ Put the cursor in the center of the screen only if it''s not already there. There''s no point moving it to where it is already. So before doing any modifications, check if the mouse has moved away from the center, and if it is still there, don''t SetCursorPos. (This part will also solve your problem).

2°/ As an optional optimization, instead of re-setting the mouse each time it moves, only re-set it when it exits a certain rectangle (for instance, 200 pixels wide, at the center of the screen). Use a variable to track the previous position of the mouse, and use it to calculate by how much it moved.

3°/ Smoothing advice : by using your method, if the mouse moves 3.5 pixels, you''ll only get 3 pixels. That is going to make your looking around quite sharp (moving by 0.1° on a frame, then 0.2° on the next one). To smooth out the mouse, keep track of the average mouse velocity, and average it (instead of sudden changes). The formula I like to use is :

Velocity = Velocity / kappa + MouseMoveThisFrame;
Angles = Angles + Velocity;

Where kappa is a constant you choose (I use 8). The smaller it is, the smoother the movement.

Good luck!

ToohrVyk
-------------
Extatica - a free 3d game engine
Available soon!
Click here to learn more

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
[qoute]
2°/ As an optional optimization, instead of re-setting the mouse each time it moves, only re-set it when it exits a certain rectangle (for instance, 200 pixels wide, at the center of the screen). Use a variable to track the previous position of the mouse, and use it to calculate by how much it moved.


Is it really an optimisation? Now you not only have to move mouse, but also check whether it is in the rectangle?

Share this post


Link to post
Share on other sites
GUYS YOU ALL MISSED A VERY IMPORTANT THING. SetCursorPos Sends antoher WM_MOUSEMOVE Message Before it exits handling the first. Going into an infinite recursion.

Ximmer: Your solution might work. But I am doubtfull.

George2: Thats exactly what i am trying to do, but I am having the problem with SetCursorPos, like i said above. Please post your code.

Emin3m: I tried that, but my rotation for some reason becomes supper fast, weird, and only goes into one direction.

ToohVyk: I am not even gonna go into what u said.


[edited by - snisarenko on December 27, 2002 12:19:14 PM]

[edited by - snisarenko on December 27, 2002 12:22:51 PM]

Share this post


Link to post
Share on other sites
do yourself a favor, get the camera tutorials from gametutorials.com and use the class that is used in those tutorials, i use them and they are flawless. You get FP and over the shoulder views

IT Administrator / Software Engineere
http://drdsoftware.cjb.net

Share this post


Link to post
Share on other sites
Ximmer''s code doesn''t work for some reason. It still goes into a recursion. His method is similiar to the method I tried to solve the recursion.

I have a few ideas, but its too late in the evening and i am tired. I will try them tommorow.

Oh, by the way thanks for reminding me about gametutorials camera tutorials. If my ideas don''t work they will be my last resort.

Well thank u all for replying, and helping me out.

Share this post


Link to post
Share on other sites
snis--

what i would reccomend you do is to make another set of variables which store the mouse position last frame, as well as those this frame. then all you have to do is subtract the new one and the old one to find out how far the mouse has moved since the last frame. I am not sure why exactly you are using SetCursorPos(), but if its cause you are worried about the cursor going out of the bounds of the window, i am not sure whether or not that is actually a problem. i have never run into it, but i havent done all that much with mouse either. now, what I would recommend to handle the rotation would be something like this:

case WM_MOUSEMOVE:
{
MouseXold = MouseX;
MouseYold = MouseY;

MouseX = LOWORD(lParam);
MouseY = HIWORD(lParam); //dont forget, this is the TOTAL position of the cursor, not how many pixels it was moved

MouseMoveX = MouseX-MouseXold; //how many pixels moved
MouseMoveY = MouseY-MouseYold;
}

then, somewhere else, like in a main loop function:

CameraRotationX += MouseMoveX*Sensitivity;
CameraRotationY += MouseMoveY*Sensitivity;

Or, you can just do what I like to do:

CameraRotationX = MouseX * Sensitivity;
CameraRotationY = MouseY * Sensitivity;

I am not sure this is what you are looking for, but i hope it helps either way!

--Steve132


Share this post


Link to post
Share on other sites
//first just get the position of the mouse and save it
case WM_MOUSEMOVE:
{
mouseY = LOWORD(lParam);
mouseX = HIWORD(lParam);
return 0;
}

//now in your actual code use this

rotX+=100-mouseX; //find x distance from 100
rotY+=100-mouseY; //find y distance from 100
SetCursorPos(100,100); //reset the mouse to point 100,100

//now use rotX and rotY as needed (glRotatef()). They will not be limited by the mouse reaching the edge of the screen because it never does.


[edited by - xiros on December 27, 2002 10:50:15 PM]

Share this post


Link to post
Share on other sites
if you are not draging then you have no need to use WM_MOUSEMOVE. use the following:


SwapBuffers(hDC); // Swap Buffers (Double Buffering)

GetCursorPos(&mpos); // Get The Current Mouse Position
SetCursorPos(mouseCenter.x,mouseCenter.y); // Set Mouse Position To Center Of The Window

mouseRotY += (mpos.x-mouseCenter.x)*mouseSpeed;
mouseRotX += (mpos.y-mouseCenter.y)*mouseSpeed;

.. key stuff ..


that should fix it.



- Jono AH

Share this post


Link to post
Share on other sites
Stop discarding solutions mindlessly.<\FLAME>

Here is what your problem looks like, doesn''t it?

Receive WM_MOUSEMOVE
Compute Rotation.
Move Mouse
[Mouse is now in the center of the screen]
Receive WM_MOUSEMOVE (from setcursorpos)
Compute Rotation
Move Mouse again...
[Mouse is now in the center of the screen]
Receive WM_MOUSEMOVE (from setcursorpos)
Compute Rotation
Move Mouse again...

etc...

This is what I understood. If I am mistaken, ok, burn me away.

I gave you one solution : only move mouse if it is NOT at the center of the screen. Now think about it for a minute instead of complaining. What would happen?

Receive WM_MOUSEMOVE
Compute Rotation
Move Mouse
[Mouse is now in the center of the screen]
Receive WM_MOUSEMOVE (from setcursorpos)
Mouse is in the center of the screen, so do nothing
>>>The mouse is not moved!!!<<<
>>>NO WM_MOUSEMOVE message posted<<<
>>>Your problem is SOLVED<<<

So like you said, you missed an important point too : yes, SetCursorPos DOES send a WM_MOUSEMOVE message. But if you don''t call it, it won''t send that message, will it?
Nope, it won''t.

Next time you come chiming in, looking for an answer or a solution, don''t say "that''s not gonna work" before you think it through...And if you still believe it''s wrong, explain me why. <\FLAME>

ToohrVyk
-------------
Extatica - a free 3d game engine
Available soon!
Click here to learn more

Share this post


Link to post
Share on other sites
quote:
Original post by snisarenko


George2: Thats exactly what i am trying to do, but I am having the problem with SetCursorPos, like i said above. Please post your code.




Well I use SDL and Linux, but the principles are the same :

  
float tr = (float)(cfg.width/2 - mouse.posX())* 0.1f;
float l = (float)(cfg.height/2 - mouse.posY())* 0.1f;
cam.Rotate(l,true,false,false); // rotate cam about the X-axis

cam.Rotate(tr,false,true,false); // rotate cam about the Y-axis

SDL_WarpMouse(cfg.width/2,cfg.height/2);


This code get''s called once every frame (not when I recieve a message when the mouse has moved).
Note : SDL_WarpMouse and SetCursorPos do the same thing

Share this post


Link to post
Share on other sites
xiros: I will try your method

wild_pointer, JonoX, and George2: That was my Plan B if the first plan didn't work. I think I will have to do that if i won't be able to get it to work.

ToohrVyk: Dude don't flip out on me. I wasn't wining. I any case I am sorry. Anyways, I think I posted above that I actually tried your method. (yes i actually put it in my program). It does get rid of the recursion, but the rotation becomes very fast and weird. It goes only into one direction and doesn't stop.

[edited by - snisarenko on December 28, 2002 4:23:06 PM]

Share this post


Link to post
Share on other sites
Its Time to solve a mystery ..........
Ok so to get down to the bottom of this problem i did something simple.

Here is my code:

case WM_MOUSEMOVE:
{
mouseRotY+=(LOWORD(lParam)-mouseCenter.x)*mouseSpeed;
mouseRotX+=(HIWORD(lParam)-mouseCenter.y)*mouseSpeed;
return 0;
}

.... in my main program

SwapBuffers(hDC);
RenderSkyBox();
SetCursorPos(mouseCenter.x, mouseCenter.y);


Ok so what would you expect this program to do? Nothing, Right ?
Since I am allways reseting it to single position. But wait if i move the mouse maybe somewhere between case WM_MOUSEMOVE and SetCursorPos I could move my mouse and maybe in a little millisecond mouse motion will get to RenderSkyBox(); and rotate it a little, Right ? So if I run my programm and I don''t touch my mouse we are garanteed that the no rotation will happen, right?

Well ........ I run my program and I don''t touch my mouse.... gues what happens?......
For some weird reason my skybox is spining uppwards and only upwars and at very high speed.

Now could somebody explain why the hell this is happening ?

Share this post


Link to post
Share on other sites
like i said before forget about WM_MOUSEMOVE. dellete it! all you need is this:


POINT mousepPosition;
...

SwapBuffers(hDC); // Swap Buffers (Double Buffering)

RenderSkyBox();

GetCursorPos(&mousepPosition); // save mouse position
SetCursorPos(mouseCenter.x,mouseCenter.y); // then move it to center

mouseRotY += (mousepPosition.x-mouseCenter.x)*mouseSpeed;
mouseRotX += (mousepPosition.y-mouseCenter.y)*mouseSpeed;
.. key stuff ..



just try it. is''t not that hard.

Share this post


Link to post
Share on other sites
Thanks, I used your code and it worked perfectly.

But see i am still restless. I want to find out why my previous way didn't work

I just can't abandon it ........ it is stuck in my mind

[edited by - snisarenko on December 28, 2002 6:51:47 PM]

Share this post


Link to post
Share on other sites
Didn''t read everything, but I have a question. How can a WndProc be called recursively when it''s necessary to call DispatchMessage to forward a message to the WndProc? Or do non-window specific messages get sent straight to the WndProc? That seems really suspicious, but perhaps it''s just me.

Also, GetCursorPos is lovely for things like this, as some suggested.

Peace,
ZE.

//email me.//zealouselixir software.//msdn.//n00biez.//
miscellaneous links

Share this post


Link to post
Share on other sites
ok. lets see if we can make some sense out of all this!

first things firat.

case WM_MOUSEMOVE:
{
mouseRotY+=(LOWORD(lParam)-mouseCenter.x)*mouseSpeed;
mouseRotX+=(HIWORD(lParam)-mouseCenter.y)*mouseSpeed;
SetCursorPos(mouseCenter.x,mouseCenter.y);

return 0;
}


this will be called recusively blocking the rest of the program from running. that is, every time SetCursorPos() is called a WM_MOUSEMOVE message is generated.


case WM_MOUSEMOVE:
{
MouseX = HIWORD(lParam);
MouseY = LOWORD(lParam);

if(MouseX != MouseCenter.x || MouseY != MouseCenterY)
{
MouseRotX += (MouseX - MouseCenter.y) * MouseSpeed;
MouseRotY += (MouseY - MouseCenter.x) * MouseSpeed;
SetCursorPos(MouseCenter.x, MouseCenter.y);
}
return 0;
}


this will stop the recursion as SetCursorPos() is only called if the mouse has moved from where it was put. however a WM_MOUSEMOVE message is sent every time the mouse is moved one pixel which can slow down things a bit if the mouse is moving fast.

the code by Steve132 will not work because there is no SetCursorPos() call made.

xiros code sould work but why use:

case WM_MOUSEMOVE:
{
mouseY = LOWORD(lParam);
mouseX = HIWORD(lParam);

return 0;
}


when you could just call GetCursorPos() ???

this has all been very confusing as there has been a lot of small misunderstandings and assumptions.

its good that everyone tried to help but i think maby a bit more detail in explanations and a bit more related code would realy help at times.</lecture>


- Jono AH

Share this post


Link to post
Share on other sites