C# OpenTK mouse picking incorrect? - c#

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

Related

how to calculate the formula for lenses to calculate the ray path?

I want to get a formula for creating rays in unity. specifically, I need a calculation for vector2.
if the ray falls from top to bottom on the lens - everything works, but how to make it possible to turn the lens?
Vector3 startingPosition = position;
RaycastHit2D hit = Physics2D.Raycast(position, direction, maxStepDistance);
if (hit.collider != null)
{
a = Vector2.SignedAngle(direction, hit.normal);
if (hit.collider.gameObject.name == "Circle")
{
float sin = Mathf.Sin(a * Mathf.Deg2Rad) * (koef1);
float cos = Mathf.Sqrt(1 - sin * sin);
direction = new Vector2(sin, -cos);
}
else if (hit.collider.gameObject.name == "Circleup")
{
a2 = a;
float sin = Mathf.Sin(a * Mathf.Deg2Rad) * (1 / koef1);
float cos = Mathf.Sqrt(1 - sin * sin);
direction = new Vector2(-sin, -cos);
}
else direction = Vector2.Reflect(direction, hit.normal);
position = new Vector2(hit.point.x -0.0001f, hit.point.y -0.0003f);
I tried to replace the formulas for the upper and lower collider, but again, it only works one way

OpenGL Unprojecting mouse cursor to find relative position to a certain object?

I have a player object that's moving around the screen. The camera is a fixed camera, looking down on the player (like in Diablo).
Now I want the player object to rotate towards the mouse cursor. The player is not always on the center of the screen (for this case I already have a solution).
In order to do this, I think I need to project the mouse cursor to the same height (y-axis) that my player is on (y-axis is "up" in my game) and then check compare player position with cursor position on the same height in world space.
So far, my unprojecting method looks like this:
private bool Unproject(float winX, float winY, float winZ, out Vector3 position)
{
position = Vector3.Zero;
Matrix4 transformMatrix = Matrix4.Invert(World.CurrentWindow.GetViewMatrix() * World.CurrentWindow.GetProjectionMatrix());
Vector4 inVector = new Vector4(
(winX - World.CurrentWindow.X) / World.CurrentWindow.Width * 2f - 1f,
(winY - World.CurrentWindow.Y) / World.CurrentWindow.Height * 2f - 1f,
2f * winZ - 1f,
1f
);
Matrix4 inMatrix = new Matrix4(inVector.X, 0, 0, 0, inVector.Y, 0, 0, 0, inVector.Z, 0, 0, 0, inVector.W, 0, 0, 0);
Matrix4 resultMtx = transformMatrix * inMatrix;
float[] resultVector = new float[] { resultMtx[0, 0], resultMtx[1, 0], resultMtx[2, 0], resultMtx[3, 0] };
if (resultVector[3] == 0)
{
return false;
}
resultVector[3] = 1f / resultVector[3];
position = new Vector3(resultVector[0] * resultVector[3], resultVector[1] * resultVector[3], resultVector[2] * resultVector[3]);
return true;
}
Now I unproject the mouse cursor once for the near plane (winZ = 0) and the far plane (winZ = 1).
protected Vector3 GetMouseRay(MouseState s)
{
Vector3 mouseposNear = new Vector3();
Vector3 mouseposFar = new Vector3();
bool near = Unproject(s.X, s.Y, 0f, out mouseposNear);
bool far = Unproject(s.X, s.Y, 1f, out mouseposFar);
Vector3 finalRay = mouseposFar - mouseposNear;
return finalRay;
}
My problem is:
How do I know if the values are correct. The values in the "finalRay" Vector are quite small - always. I would have thought that i would get much bigger z-values because my near plane (perspective projection) is 0.5f and my far plane is 1000f.
And how can I find out if the mouse cursor is left/right (-x, +x) or behind/in front of (-z, +z) the player? (I know the player's position)
Where is my error?
And how can I find out if the mouse cursor is left/right (-x, +x) or behind/in front of (-z, +z) the player?
Do it in the opposite direction. Project the postion of the player to the screen. So you can easily compare the position of the player with the mouse position:
// positon of the player in world coordinates
Vector3 p_ws ....;
// positon of the player in view space
Vector4 p_view = World.CurrentWindow.GetViewMatrix() * Vector4(p_ws.X, p_ws.Y, p_ws.Z, 1.0);
// postion of the player in clip space (Homogeneous coordinates)
Vector4 p_clip = World.CurrentWindow.GetProjectionMatrix() * p_view;
// positon of the player in normailzed device coordinates (perspective divide)
Vec3 posNDC = new Vector3(p_clip.X / p_clip.W, p_clip.Y / p_clip.W, p_clip.Z / p_clip.W);
// screen position in pixel
float p_screenX = (posNDC.X * 0.5 + 0.5) * World.CurrentWindow.Width;
float p_screenY = (posNDC.Y * 0.5 + 0.5) * World.CurrentWindow.Height;

Unproject MouseCoords ( OpenGL / OpenTK ).

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.

Updating the Y position aswell as the X position of the 2D camera

I'm trying to make a 2D camera that follows my player around both vertically and horizontally. The camera is only following my player horizontally atm. Ive been told to update the Y part aswell as the X part in my ScrollCamera() method, but I couldnt figure out how to do it (ended up making a big mess).
Heres the code:
private void ScrollCamera(Viewport viewport)
{
#if ZUNE
const float ViewMargin = 0.45f;
#else
const float ViewMargin = 0.5f;
#endif
// Calculate the edges of the screen.
float marginWidth = viewport.Width * ViewMargin;
float marginLeft = cameraPosition + marginWidth;
float marginRight = cameraPosition + viewport.Width - marginWidth;
// Calculate how far to scroll when the player is near the edges of the screen.
float cameraMovement = 0.0f;
if (Player.Position.X < marginLeft)
cameraMovement = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement = Player.Position.X - marginRight;
// Update the camera position, but prevent scrolling off the ends of the level.
float maxCameraPositionWidth = Tile.Width * Width - viewport.Width;
cameraPosition = MathHelper.Clamp(cameraPosition + cameraMovement, 0.0f, maxCameraPositionWidth);
}
This is the draw method in my level class:
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Begin();
for (int i = 0; i <= EntityLayer; ++i)
layers[i].Draw(spriteBatch, cameraPosition);
spriteBatch.End();
ScrollCamera(spriteBatch.GraphicsDevice.Viewport);
Matrix cameraTransform = Matrix.CreateTranslation(-cameraPosition, 0.0f, 0.0f);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default,
RasterizerState.CullCounterClockwise, null, cameraTransform);
DrawTiles(spriteBatch);
Player.Draw(gameTime, spriteBatch);
foreach (Enemy enemy in enemies)
enemy.Draw(gameTime, spriteBatch);
spriteBatch.End();
spriteBatch.Begin();
for (int i = EntityLayer + 1; i < layers.Length; ++i)
layers[i].Draw(spriteBatch, cameraPosition);
spriteBatch.End();
}
I'm pretty new to Xna and C# and Im doing this just for fun, but it would be great if someone could tell me how to do it :)
I have tried:
private void ScrollCamera(Viewport viewport)
{
#if ZUNE
const float ViewMargin = 0.45f;
#else
const float ViewMargin = 0.5f;
const float ViewHeight = 0.3f;
#endif
// Calculate the edges of the screen.
float marginHeight = viewport.Height * ViewHeight;
float marginTop = cameraPosition + marginHeight;
float marginBottom = cameraPosition + marginHeight;
float marginWidth = viewport.Width * ViewMargin;
float marginLeft = cameraPosition + marginWidth;
float marginRight = cameraPosition + viewport.Width - marginWidth;
// Calculate how far to scroll when the player is near the edges of the screen.
float cameraMovement = 0.0f;
if (Player.Position.X < marginLeft)
cameraMovement = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement = Player.Position.X - marginRight;
if (Player.Position.Y < marginTop)
cameraMovement = Player.Position.Y - marginTop;
else if (Player.Position.Y > marginBottom)
cameraMovement = Player.Position.X - marginBottom;
// Update the camera position, but prevent scrolling off the ends of the level.
float maxCameraPositionWidth = Tile.Width * Width - viewport.Width;
cameraPosition = MathHelper.Clamp(cameraPosition + cameraMovement, 0.0f, maxCameraPositionWidth);
}
Which was not right at all.
From the code you provided I conclude 'cameraPosition' is a float with which you only keep track of the X position. I would recommend using a Vector2 for this. This is technically two floats in one; one for the X position and one for Y. If you do this, you will have to repeat your calculation for the Y value. If you prefer not to use a Vector2, you could make a second variable for the Y position instead.
I am unable to see what you do with the cameraPosition, so I cannot help you with that part for Y.
Edit
The draw function you have made is not right, because you have only one variable for the camera position. You will need a variable for the X position, and a second one for the Y position. As I stated above, the typical way to do this in XNA, is via the Vector2 structure. If you are not familiar with structures(or classes), I recommend reading up about it as soon as possible, because they are very important in object oriented programming. A link to the microsoft Vector2 documentation: http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.vector2.aspx
What you would basically do is take the calculation you had at first.
float cameraMovement = 0.0f;
if (Player.Position.X < marginLeft)
cameraMovement = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement = Player.Position.X - marginRight;
// Update the camera position, but prevent scrolling off the ends of the level.
float maxCameraPositionWidth = Tile.Width * Width - viewport.Width;
cameraPosition = MathHelper.Clamp(cameraPosition + cameraMovement, 0.0f, maxCameraPositionWidth);
This is the calculation for the X position of your camera. Your code using Vector2 would be:
// Declare a Vector2 cameraPosition where you are now declaring a float cameraPosition right now.
Vector2 cameraMovement = new Vector2(0,0);
if (Player.Position.X < marginLeft)
cameraMovement.X = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement.X = Player.Position.X - marginRight;
float maxCameraPositionWidth = Tile.Width * Width - viewport.Width;
cameraPosition.X = MathHelper.Clamp(cameraPosition.X + cameraMovement.X, 0.0f, maxCameraPositionWidth);
You will have to do similar calculations for cameraMovement.Y and cameraPosition.Y.
When you have these, the only thing you will have to change in your draw function is the Y translation. Currently you have:
Matrix cameraTransform = Matrix.CreateTranslation(-cameraPosition, 0.0f, 0.0f);
As you see, you are only translating in the X axis. After adding the Y axis it looks like this:
Matrix cameraTransform = Matrix.CreateTranslation(-cameraPosition.X, -cameraPosition.Y, 0.0f);
I hope you figure it out now. Good luck!

C# Vector2 How to move an object toward an angle

I want to move an object to the given angle, But it moves only up, and down, only Y axis.
Vector2 unitV = new Vector2((float)Math.Sin(player.angle), (float)Math.Cos(player.angle));
unitV.Normalize();
player.model.Position += Vector2.Multiply(unitV,player.model.Speed) * (float)gameTime.ElapsedGameTime.TotalSeconds;
I just met this problem while practicing, but here is the solution i found. I hope this will work for you. Used XNA 4 C sharp.
Declaration:
Texture2D sprite;
Vector2 spritePosition = Vector2.Zero;
Vector2 spriteOriginalPos;
float spriterotation = 0;
float anglecorrection = (Math.PI * 90 / 180.0);
float speed = 1;
Note that the anglecorrection is needed to move the object toward its "up" angle.
Load:
//Load basic texture to make it recognizable :)
sprite= Content.Load<Texture2D>("spritetexture");
//Default position in middle
spritePosition = new Vector2(
(graphics.GraphicsDevice.Viewport.Width / 2) - (sprite.Width / 2),
(graphics.GraphicsDevice.Viewport.Height / 2) - (sprite.Height / 2));
//Sprite centering
spriteOriginalPos.X = sprite.Width / 2;
spriteOriginalPos.Y = sprite.Height / 2;
Update:
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Up))
{
spritePosition.X += speed * (float)Math.Cos(spriterotation - anglecorrection);
spritePosition.Y += speed * (float)Math.Sin(spriterotation - anglecorrection);
}
Draw:
spriteBatch.Draw(sprite, spritePosition, null, Color.Black, spriterotation, spriteOriginalPos, 1.0f, SpriteEffects.None, 0f);

Categories