How to calculate Rayintersection 3D for Picking - c#

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

Related

Converting Calculating To Movement Overtime?

I am moving an object in a parabolic arc this way:
public IEnumerator ParabolicMovement()
{
Vector3 startPos;
Vector3 targetPos;
float speed = 6;
float arcHeight = 3;
Vector3 nextPos = Vector3.zero;
while (transform.position != targetPos)
{
// Compute the next position, with arc added in
float x0 = startPos.x;
float x1 = targetPos.x;
float dist = x1 - x0;
float nextX = Mathf.MoveTowards(transform.position.x, x1, (speed) * Time.deltaTime);
float baseY = Mathf.Lerp(startPos.y, targetPos.y, (nextX - x0) / dist);
float arc = arcHeight * (nextX - x0) * (nextX - x1) / (-0.25f * dist * dist);
nextPos = new Vector3(nextX, baseY + arc, transform.position.z);
transform.position = nextPos;
yield return null;
}
}
This works, but I now want to take this and make it happen over a specific amount of time. I removed the loop from the original method and broke it up into two separate methods to accomplish this:
public IEnumerator BeginJumpOverTime()
{
float duration = 1f;
float startTime = Time.time;
float endTime = startTime + duration;
while (Time.time <= endTime)
{
float tNormalized = Mathf.Clamp((Time.time - startTime) / duration, 0f, 1f);
Vector2 newXAndY = CalculateXAndY(tNormalized);
transform.position = newXAndY;
yield return null;
}
}
public Vector2 CalculateXAndY(float t)
{
Vector3 startPos = GameEngine.Instance.battleManager.TurnHero.transform.position;
Vector3 targetPos = GameEngine.Instance.battleManager.TargetEnemy.transform.position;
float speed = 6;
float arcHeight = 3;
Vector3 nextPos = Vector3.zero;
// Compute the next position to make the parabola
float x0 = startPos.x;
float x1 = targetPos.x;
float dist = x1 - x0;
float nextX = Mathf.MoveTowards(transform.position.x, x1, (speed) * (Time.deltaTime) );
float baseY = Mathf.Lerp(startPos.y, targetPos.y, (nextX - x0) / dist);
float arc = arcHeight * (nextX - x0) * (nextX - x1) / (-0.25f * dist * dist);
nextPos = new Vector3(nextX, baseY + arc, transform.position.z);
return (nextPos);
}
I'm pretty certain this concept should work, I just can't seem to figure out where to factor tNormalized when it's passed into CalculateXandY(). Is anyone math savvy able to assist me with this? Thanks a ton!
Kind regards,

Transformation from Screen Coordinates to World Coordinates in Opentk

I am reading the screen coordinates through the UnProject function and they are read correctly when it is in an XY plane, however when I change to another plane the reading is not done correctly, the "Y" component is read as the "X" component of the point and the "X" component is completely wrong. Here my code.
void VistaEnElevacionYZ()
{
posicion = new Vector3(5, 0, 0);
direccion = new Vector3(0f, 0f, 0f);
upZ = new Vector3(0, 0, 1);
trX = -2.5f;
trY = -2.5f;
trZ = -1.0f;
Escala3D = 0.35f;
}
void SetupCamera()
{
Matrix4 lookAt = Matrix4.LookAt(posicion, direccion, upZ);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.LoadMatrix(ref lookAt);
}
public static PointF convertScreenToWorldCoords(float x, float y)
{
int[] viewport = new int[4];
Matrix4 modelViewMatrix, projectionMatrix;
GL.GetFloat(GetPName.ModelviewMatrix, out modelViewMatrix);
GL.GetFloat(GetPName.ProjectionMatrix, out projectionMatrix);
GL.GetInteger(GetPName.Viewport, viewport);
Vector2 mouse;
mouse.X = x;
mouse.Y = viewport[3] - y;
Vector4 vector = UnProject(ref projectionMatrix, modelViewMatrix, new Size(viewport[2], viewport[3]), mouse);
PointF coords = new PointF(vector.X, vector.Y);
return coords;
}
public static Vector4 UnProject(ref Matrix4 projection, Matrix4 view, Size viewport, Vector2 mouse)
{
Vector4 vec;
vec.X = 2.0f * mouse.X / (float)viewport.Width - 1;
vec.Y = (2.0f * mouse.Y / (float)viewport.Height - 1);
vec.Z = 0;
vec.W = 1.0f;
Matrix4 viewInv = Matrix4.Invert(view);
Matrix4 projInv = Matrix4.Invert(projection);
Vector4.Transform(ref vec, ref projInv, out vec);
Vector4.Transform(ref vec, ref viewInv, out vec);
if (vec.W > float.Epsilon || vec.W < float.Epsilon)
{
vec.X /= vec.W;
vec.Y /= vec.W;
vec.Z /= vec.W;
}
return vec;
}
I call the method convertScreenToWorldCoords () from the MouseClick event and the VistaEnElevacionYZ method with the click event of a button.
I was finally able to solve the problem that was the subject of my question. I did the calculation of my model matrix by direct multiplication of the transformations. I was also applying the translation before the scaling, for that reason my function did not work.
PointF convertScreenToWorldCoords(float x, float y)
{
Vector2 mouse;
int[] viewport = new int[4];
GL.GetInteger(GetPName.Viewport, viewport);
Matrix4 modelViewMatrix = (Matrix4.CreateTranslation(trX, trY, trZ) * Matrix4.CreateScale(Escala3D));
Matrix4 projectionMatrix = Matrix4.CreateOrthographic(7.89f, 9.5f, 1.0f, 200f);
mouse.X = x;
mouse.Y = viewport[3] - y;
Vector4 vector = UnProject(ref projectionMatrix, modelViewMatrix, new Size(viewport[2], viewport[3]), mouse);
PointF coords = new PointF(vector.X, vector.Y);
return coords;
}

How to subtract two Vector3 ?I want to measure the distance between two Object

I want to measure the distance of two objects(only in the Z-axis) and if the distance of these objects is = 50 then do something...But I can't subtract two Vector3.
something like this:
Vector3 Bullet;
Vector3 player;
public Vector3 distance;
Bullet = new Vector3(0f, 0f, transform.position.z);
Player = new Vector3(0f, 0f, player.position.z);
if (distance = Bullet - Player)
{
Debug.Log("out of range");
}
Use Vector3.Distance.
Vector3 bullet = new Vector3(0f, 0f, player.position.z);;
Vector3 player = new Vector3(0f, 0f, transform.position.z);
public float distance;
if (distance >= Vector3.Distance(other.position, transform.position))
{
print("out of range: " + dist);
}
source: https://docs.unity3d.com/ScriptReference/Vector3.Distance.html
Or you could minus the z values directly. There's no need to use vector functions if you're only calculating the z values.
If you need and use only Z axis, you don't need extra vectors at all.
You can calculate your distance in one axis just like that:
Mathf.Abs(transform.position.z - player.position.z);
And also to check for "out of range" you need to use ">=" instead of "==" to avoid bugs when, for example, in one frame your distance could jump from 49.9 to 51.1, and code with "==" will fail in this case.
So the final code should be:
public Vector3 distance;
if (Mathf.Abs(transform.position.z - player.position.z) >= distance)
{
Debug.Log("out of range");
}
this is not a subtraction you need, just calculate a distance between 2 vector3
const v3Obj1 = { x: 10, y: 10, z: 75 }
const v3Obj2 = { x: -10, y: 15, z: 75 }
function distance(x0, y0, z0, x1, y1, z1) {
let deltaX = x1 - x0
let deltaY = y1 - y0
let deltaZ = z1 - z0
let distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ)
return parseFloat(distance)
}
console.log(
distance(v3Obj1.x, v3Obj1.y, v3Obj1.z, v3Obj2.x, v3Obj2.y, v3Obj2.z)
) // return {Float} 20.615528128088304
// code tested

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.

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