Unproject MouseCoords ( OpenGL / OpenTK ). - c#

Hey I am trying to convert 2d mouse coords to a 3d direction vector to world space. The problem is that the direction vector of the ray is only fully working if the camera is not turning in Y-axis. For example: Camera looking down. Y is -0.999 thats perfect, but now I turn the camera 90° in Y-axis and the result is that X is now -0.999 and Y very small ( but still looking down ). The only direction thats working is Z.
This is the code for getting the mouse ray.
public Vector3 get3DMouseCoords(int mousex, int mousey)
{
Vector2 normalizedCoords = getNormalizedMouseCoords(mousex, mousey);
Vector4 clipCoords = new Vector4(normalizedCoords.X, normalizedCoords.Y, -1f, 1f);
Vector4 eyeRay = getEyeRay(clipCoords);
return getWorldRay(eyeRay);
}
private Vector3 getWorldRay(Vector4 eyeRay)
{
Matrix4 invertertedView = Matrix4.Invert(Camera.Transformation);
Vector3 worldRay = Vector4.Transform(invertertedView, eyeRay).Xyz;
return worldRay.Normalized();
}
private Vector4 getEyeRay(Vector4 clipCoords)
{
Matrix4 invertertedProj = Matrix4.Invert(Camera.PerspectiveProjection);
Vector4 eyeRay = Vector4.Transform(invertertedProj, clipCoords);
return new Vector4(eyeRay.X, eyeRay.Y, -1f, 0f);
}
private Vector2 getNormalizedMouseCoords(int mousex, int mousey)
{
float x = 2.0f * mousex / (float)screenWidth - 1;
float y = -(2.0f * mousey / (float)screenHeight - 1);
return new Vector2(x, y);
}
This is the view matrix code:
Vector3 lookat = new Vector3();
lookat.X = (float)(Math.Sin((float)orientation.X) * Math.Cos((float)orientation.Y));
lookat.Y = (float)Math.Sin((float)orientation.Y);
lookat.Z = (float)(Math.Cos((float)orientation.X) * Math.Cos((float)orientation.Y));
view = Matrix4.LookAt(Position, Position + lookat, Vector3.UnitY);
Thanks in Advance.

Related

C# OpenTK mouse picking incorrect?

This is my code of generate a ray
float x = (2.0f * e.X) / Width - 1f;
float y = (1.0f - (2.0f * e.Y) / Height);
float z = 1.0f;
Vector3 ray_nds = new Vector3(x, y, z);
Vector4 ray_clip = new Vector4(ray_nds.X, ray_nds.Y, -1.0f, 1.0f);
Vector4 ray_eye = Matrix4.Invert(Projection) * ray_clip;
ray_eye = new Vector4(ray_eye.X, ray_eye.Y, -1.0f, 0.0f);
Vector3 ray_wor = (Matrix4.Invert(View) * ray_eye).Xyz;
ray_wor = Vector3.Normalize(ray_wor);
ray.Origin = CameraPosition;
ray.Direction = ray_wor;
And I draw the ray into the scene.
When I look at -Z axis, it working perfect like this (I click plane center)
But when my camera front is not -Z axis or +Z axis
ray's direction was incorect like this (I click plane center)
I have no idea what's wrong with it for a week
Can anyone help me ?
If you need other info of my code, please tell me, thank you :)
Update 1:
This is my view :
public Matrix4 View { get => Matrix4.LookAt(CameraPosition, CameraPosition + CameraFront, CameraUp); }
and this is my rotate code :
(rotate the scene is change camera position and look to view center actually)
lookX += (lastMouseLoc.X - e.X) * RotateSensitive;
lookY += (e.Y - lastMouseLoc.Y) * RotateSensitive;
lookY = Math.Max(lookY, -MathHelper.DegreesToRadians(89));
lookY = Math.Min(lookY, MathHelper.DegreesToRadians(89));
Vector3 v = new Vector3((float)Math.Sin(lookX) * (float)Math.Cos(lookY), (float)Math.Sin(lookY), (float)Math.Cos(lookX) * (float)Math.Cos(lookY));
CameraPosition = ViewCenter + v * lastDistOfCenter;
CameraFront = Vector3.Normalize(ViewCenter - CameraPosition);
lastMouseLoc = e.Location;
You forgot the z-coordinate after converting from the normalized device space to the viewing space:
ray_eye = new Vector4(ray_eye.X, ray_eye.Y, -1.0f, 0.0f);
ray_eye = new Vector4(ray_eye.X, ray_eye.Y, ray_eye.Z, 0.0f);

Converting FPS ground camera to FPS free flying camera

I have implemented a camera in my OpenGL(openTk) project
//Move(0f, 0.1f, 0f); } Forward
//Move(-0.1f, 0f, 0f); } Left
//Move(0f, -0.1f, 0f); } Back
//Move(0.1f, 0f, 0f); } Right
//Move(0f, 0f, 0.1f); } Up
//Move(0f, 0f, -0.1f); } Down
public static void Move(float x, float y, float z)
{
Vector3 offset = new Vector3();
Vector3 forward = new Vector3((float)Math.Sin((float)Orientation.X), 0, (float)Math.Cos((float)Orientation.X));
Vector3 right = new Vector3(-forward.Z,0,forward.X);
offset += x * right;
offset += y * forward;
offset.Y += z;
offset.NormalizeFast();
offset = Vector3.Multiply(offset, MoveSpeed);
Position += offset;
}
Where "Orientation" is the x,y of the direction the camera is facing. "Position" is the position of the Camera in the world, and "MoveSpeed" is float.
This camera works great. But it is ground based. By this I mean that only the x value of the camera orientation affects movement direction. The y value does not. I want to make a free flying camera so if you look up and press forward the camera will fly into the air.
I tried changing the forward declation to:
Vector3 forward = new Vector3((float)Math.Sin((float)Orientation.X), (float)Math.Sin((float)Orientation.Y), (float)Math.Cos((float)Orientation.X));
This partially works, the camera now can fly into the air. But its not right, the camera is moving the same forward amount no matter how far "up" you tilt it. The up is not replacing some of the forward, its being added onto it.
I hope this explanation makes sense.
Thanks
You can do something like this:
First get the forward vector from Orientation (you can use this for your Camera.LookAt as well)
public Vector3 getForward(Vector2 Orientation)
{
Vector3 forward = new Vector3(0, 1, 0);
//X axis rotation
forward.Z = (float)Math.Sin((float)Orientation.Y);
forward.Y = (float)Math.Cos((float)Orientation.Y);
//Z axis rotation
forward.X = forward.Y*(float)Math.Sin((float)Orientation.X);
forward.Y = forward.Y*(float)Math.Cos((float)Orientation.X);
return forward;
}
And then move your camera with:
public void Move(float horizontal, float strafe)
{
Vector3 forward=getForward(Orientation);
//forward vector projected on XoY plane and rotated 90 degrees
Vector3 leftXoY = new Vector3(-forward.y ,forward.x,0);
Vector3 moveDirection = Vector3.Multiply(forward,horizontal)+Vector3.Multiply(leftXoY,strafe);
moveDirection.Normalize();
Position += Vector3.Multiply(moveDirection,MoveSpeed);
}
So if you call move(1,-1); will move the camera forward (along the forward vector) and strafe right.
I have found the solution after fiddling with it for a long time. I do not know if this is an efficient way to do it or not but it does work.
public static void Move(float x, float y, float z)
{
Vector3 CameraTargetVector;
CameraTargetVector.X = (float)(Math.Sin((float)Orientation.X) * Math.Cos((float)Orientation.Y));
CameraTargetVector.Y = (float)Math.Sin((float)Orientation.Y);
CameraTargetVector.Z = (float)(Math.Cos((float)Orientation.X) * Math.Cos((float)Orientation.Y));
Vector3 offset = new Vector3();
offset += x * new Vector3(-CameraTargetVector.Z, 0, CameraTargetVector.X);
offset += y * CameraTargetVector;
offset.Y += z;
offset.NormalizeFast();
Position += Vector3.Multiply(offset, MoveSpeed);
}

Unity 2D Raycasting from a Rotating Transform

I'm trying to create a vision field in Unity 2d. I'm projecting raycasts from a rotating gameobject which rotates according to where the character is looking. However this character moves back and forth so when they are moving left I set the transform.scale to -1. The problem is when I do this the raycasts don't change direction along with the character and stay pointing right! Here is the code, I'm probably missing something obvious! Any help would be appreciated!
Transform parent;
float vision_angle_ = 50;
float direction;
Vector3 angle;
Vector2 position;
Quaternion q;
int x = 10;
void Start ()
{
parent = transform.parent;
}
void Update ()
{
direction = parent.GetComponent<Behaviour>().direction;
angle = new Vector2 (x, Mathf.Tan ((vision_angle_) * .5f * Mathf.Deg2Rad) * x);
q = Quaternion.AngleAxis (1, -transform.forward);
position = new Vector2 (transform.position.x, transform.position.y);
for (float i = 0; i < 50; i++) {
angle = q * angle;
RaycastHit2D tile_hit = Physics2D.Raycast (position, transform.TransformDirection (angle), 10);
Debug.DrawRay (position, transform.TransformDirection (angle), Color.green);
}
}
TransformDirection doesn't take the scale of your transform into account. You can adjust to compensate:
Vector2 direction = transform.TransformDirection(angle);
if (transform.localScale.x < 0f) {
direction.x = -direction.x;
}
RaycastHit2D tile_hit = Physics2D.Raycast(position, direction, 10);

I tried to make the camera to move the same way in first person game but its not moving why?

This is my Game1.cs code i marked the areas of the camera movement code parts:
Added the camera code in my Game1.cs i used the riemers tutorials camera code here:
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series4/Mouse_camera.php
I also tried the code in the bottom by user31911 but same results the camera pointer/cursor is dancing/shaking in the middle and not responding.
Im trying to use the Camera class to move the camera around using the mouse.
http://pastebin.com/SF3iiftq
In the constructor i have this line:
viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraRotatedUpVector);
If i use this line instead assign the viewMatrix variable later in my code then i dont see the terrain at all.
And the big main problem is that the mouse is not responding at all what i get is the mouse pointer dancing/shaking in the middle.
The only thing that responding is my ProcessInput method i did the keys there are working but the method ProcessInputCamera the kkeys and mouse there are not resopnding when im moving the camera the mouse cursor is shaking/dancing in the middle.
I can't figure out why it happen.
But the mouse is not moving the camera.
Pls edit your Question! There are to many unnecessary informations...
here is my camera (1st person) class
class Camera
{ // up in here normal needed vars
public Vector3 cameraPosition;
public float moveSpeed, rotateSpeed;
public bool playing = true;
public GraphicsDevice device;
public Matrix view, projection;
Matrix rotation;
float yaw = 0;
float pitch = 0;
int oldX, oldY;
public Camera(Vector3 cameraPosition, float moveSpeed, float rotateSpeed, float filedOfView, GraphicsDevice device, float PerspectiveFieldOfView)
{
this.cameraPosition = cameraPosition;
this.moveSpeed = moveSpeed;
this.rotateSpeed = rotateSpeed;
this.device = device;
view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up);
projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(PerspectiveFieldOfView), device.Viewport.AspectRatio, 0.1f, filedOfView);
ResetMouseCursor();
}
public void Update()
{
KeyboardState kState = Keyboard.GetState(); // make is able to use your keys
Vector3 v = new Vector3(0, 0, -50) * moveSpeed; // let you permanent walk
move(v); // isnt essential could be deleted if you wont that
}
if (kState.IsKeyDown(Keys.W))
{
Vector3 v = new Vector3(0, 0, -100) * moveSpeed;
move(v);
}
if (kState.IsKeyDown(Keys.S))
{
Vector3 v = new Vector3(0, 0, 50) * moveSpeed;
move(v);
}
if (kState.IsKeyDown(Keys.A))
{
Vector3 v = new Vector3(-50, 0, 0) * moveSpeed;
move(v);
projection = Matrix.
}
if (kState.IsKeyDown(Keys.D))
{
Vector3 v = new Vector3(50, 0, 0) * moveSpeed;
move(v);
}
pitch = MathHelper.Clamp(pitch, -1.5f, 1.5f);
MouseState mState = Mouse.GetState();
int dx = mState.X - oldX; /* is for turning you objekt / camera
yaw -= rotateSpeed * dx; *
*
int dy = mState.Y - oldY; *
pitch -= rotateSpeed * dy; */
ResetMouseCursor(); // this makes your mouse "dancing" in the middle
UpdateMatrices();
}
private void ResetMouseCursor() // mouse settings for the camera
{
int centerX = device.Viewport.Width / 2;
int centerY = device.Viewport.Height / 2;
Mouse.SetPosition(centerX, centerY);
oldX = centerX;
oldY = centerY;
}
private void UpdateMatrices() //standart camera things
{
rotation = Matrix.CreateRotationY(yaw) * Matrix.CreateRotationX(pitch);
Vector3 transformedReference = Vector3.Transform(new Vector3(0, 0, -1), rotation);
Vector3 lookAt = cameraPosition + transformedReference;
view = Matrix.CreateLookAt(cameraPosition, lookAt, Vector3.Up);
}
public void move(Vector3 v) // is the self programmed method to let you move
{
Matrix yRotation = Matrix.CreateRotationY(yaw);
v = Vector3.Transform(v, yRotation);
cameraPosition += v;
}
}
It's pretty standart, but good.
In most cases this class is all you need for the Camera and it's configuration.
Rewrite/Fix it, like however you need it...
Tipp: You could also consider a Arc-Ball-Cam..

How to calculate Rayintersection 3D for Picking

Im struggeling to implement a Function which basically tells me, if a Ray "gets close enough" to an object
Basically I implemented Implementing Ray Picking
#nornagon soloution to create the Ray. My object on screen is centered around a Point. I assume that if the Ray is within a certain distance to this point, the object is selected.
I call those 3 Points(X,Y,Z) : _pickFrom, _pickTo and pO
For a start, this is my method to calculate the Ray depending on Mouseposition on screen:
public static void Pick(int x, int y)
{
float nx = 2.0f * ((float)x) / ((float)_width) - 1.0f;
float ny = 1.0f - 2.0f * ((float)y) / ((float)_height);
Matrix4 unview = Matrix4.Invert(Matrix4.Mult(_projectionMatrix, _modelviewMatrix));
Vector4 nearPoint = Vector4.Transform(new Vector4(nx, ny, 0, 1), unview);
_pickTo = nearPoint - _pickFrom;
}
_pickFrom is the position of the camera in the Scene.
_pickTo is the direction of the pickray.
_width and _height are the rendercontext sizes.
How would I now implement a function which gives me the distance of a point to the pickray?
I figured it out myself now:
public void SetMouse(int x, int y)
{
float xpos = 2.0f * ((float)x / (float)_width) - 1.0f;
float ypos = 2.0f* (1.0f - (float)y / (float)_height) - 1.0f;
Vector4 startRay = new Vector4(xpos, ypos, -1, 1);
Vector4 endRay = new Vector4(xpos, ypos, 1, 1);
Matrix4 trans = _modelView.Data * _projection.Data;
trans.Invert();
startRay = Vector4.Transform(startRay, trans);
endRay = Vector4.Transform(endRay, trans);
_pickFrom = startRay.Xyz / startRay.W;
_pickTo = endRay.Xyz / endRay.W;
}
....
public float Distance(Vector3 p)
{
Vector3 x1 = _pickFrom;
Vector3 x2 = _pickTo;
return Vector3.Cross
(Vector3.Subtract(p, x1),
Vector3.Subtract(p, x2)
).Length / Vector3.Subtract(x2, x1).Length;
}

Categories