How to find a position, knowing a direction, angle and distance? - c#

Using the diagram provided, I know:
Character at position A, facing B (posA)
Object at position B (posB), facing a random direction.
desired angle (20) for C (desiredAngle), based in the direction A to B.
distance from B to C
How would I go about finding the position of C?
In the code below, I managed to get the vector BC, now how can define a point along that vector using the distance from A to B?
//The angle of the hand in relation to the object
public float angleFromPlayer = -60f;
//Get the direction vector from the selectedObject to the actor
Vector3 objectDirectionToActor = actorParent.position - selectedObjectCenter;
//Make it horizontal (Flatten the y)
objectDirectionToActor.y = 0;
//Get the rotated vector using the desiredAngle
Vector3 rotatedVector = Quaternion.Euler(0, angleFromPlayer, 0) * objectDirectionToActor;

Figured it out, here is the solution for posterity:
//How high the hand will be from the dropSurface/selectedObjectPivot
public float handOffsetFromDropSurface = 0.15f;
//The angle of the hand in relation to the object
public float targetAngleFromPlayer = -80f;
//Extra distance between selectedObjectCenter and wristBone (since the handDistance is a bit too short)
public float extraHandDistance = 0f;
Vector3 GetHandBonePositionForDropSurface(Vector3 selectedObjectCenter) {
//Get the direction vector from the selectedObject to the actor
Vector3 objectDirectionToActor = actorParent.position - selectedObjectCenter;
//Make it horizontal (Flatten the y)
objectDirectionToActor.y = 0;
//Change vector size to 1 for multiplication
objectDirectionToActor.Normalize();
//Get the rotated vector using the desiredAngle
Vector3 rotatedVector = Quaternion.Euler(0, targetAngleFromPlayer, 0) * objectDirectionToActor;
//Get the distance we want the point to be from the center of the selectedObject
float handDistance =
Vector3.Distance(playerProperties.boneRightIndexProximal.position,
playerProperties.boneRightHand.position) + extraHandDistance;
//Resize vector to match the hand distance
rotatedVector *= handDistance;
//Get finalPosition, adding the handOffsetFromDropSurface
Vector3 wristTargetPosition = selectedObjectCenter + rotatedVector + (Vector3.up * handOffsetFromDropSurface);
return wristTargetPosition;
}

Related

Rotate faces so normals align with an axis in C#

I have an array of faces, each face has an array of points in 3d space. I want to fill an array of unfolded faces that contains the faces with their normals all pointing along the z axis. DirectionA is the z axis, DirectionB is the normal of the face. I work out the angle and axis then apply it. As I have points, myPoint is a point not a vector could that be a problem? My logic is not right somewhere....
Here is my current code:
public void UnfoldAll()
{
Vector3d directionA = new Vector3d(0, 0, 1);//z axis
int iii = 0;
foreach (Face f in faces)
{
Vector3d directionB = normals[f.normal - 1]; //normal from face
float rotationAngle = (float)Math.Acos(directionA.DotProduct(directionB));
Vector3d rotationAxis = directionA.CrossProduct(directionB);
//rotate all points around axis by angle
for (int i = 0; i < f.Corners3D.Length; i++)
{
Vector3d myPoint;
myPoint.X = f.Corners3D[i].X;
myPoint.Y = f.Corners3D[i].Y;
myPoint.Z = f.Corners3D[i].Z;
myPoint = Vector3d.Normalize(myPoint);
Vector3d vxp = Vector3d.CrossProduct(rotationAxis, myPoint);
Vector3d vxvxp = Vector3d.CrossProduct(rotationAxis, vxp);
Vector3d final = directionB;
var angle = Math.Sin(rotationAngle);
var angle2 = 1 - Math.Cos(rotationAngle);
final.X += (angle * vxp.X) + (angle2 * vxvxp.X);
final.Y += (angle * vxp.Y) + (angle2 * vxvxp.Y);
final.Z += (angle * vxp.Z) + (angle2 * vxvxp.Z);
unfoldedFaces[iii].Corners3D[i].X = final.X;
unfoldedFaces[iii].Corners3D[i].Y = final.Y;
unfoldedFaces[iii].Corners3D[i].Z = final.Z;
}
}
iii++;
}
Any suggestions would be great. Thank you.
When doing any kind of 3D transformation, it is usually a good idea to stay away from angles if you can. Things tend to be easier if you stick to matrices, quaternions and vectors as much as possible.
If you want to rotate a face you should find a transform that describes the rotation, and then simply apply this transform to each of the vertices to get the rotated triangle. You could use either a matrix or a quaternion to describe a rotational transform.
The exact method will depend a bit on what library you are using for transforms. For Unity3D you have the Quaternion.FromToRotation that should do what you want, just input the current normal as the from vector, and the desired normal as the toDirection.
If you are using System.Numerics you can use Quaternion.FromAxisAngle. Just take the cross product your two normals to get the axis, and take the arc cos of the dot-product to get the angle. Don't forget to ensure the normals are normalized.
Thank you that was helpful, here is my code if anyone else needs help:
public void UnfoldAll()
{
Vector3d directionA = new Vector3d(0, 0, 1);//z axis
unfoldedFaces = new UnfoldedFace[faces.Length];
int iii = 0;
foreach (Face f in faces)
{
unfoldedFaces[iii].Corners3D = f.Corners3D;
Vector3d directionB = normals[f.normal - 1]; //normal from face
directionB = Vector3d.Normalize(directionB);
Vector3d vxp = Vector3d.CrossProduct(directionA, directionB);
float rotationAngle = (float)Math.Acos(directionA.DotProduct(directionB));
Quaternion q = Quaternion.FromAxisAngleQ(vxp, rotationAngle);
q.Rotate(unfoldedFaces[iii].Corners3D);
iii++;
}
}

Rotate object in Unity 2D

Help to understand the management of objects. At the moment, there is a rotation of the object. I want the arrow to rotate, and the angle of rotation depends on the current X and Y coordinates. Unity2D.
Now it is left (does not rotate), but it needs to be right (it always rotates and looks in one direction), but I don’t know how to calculate the degrees for rotation.
`
public float angle = 0; // угол
public float radius = 0.5f; // радиус
public bool isCircle = false; // условие движения по кругу
public float speed = 5f;
// Update is called once per frame
void Update()
{
angle += Time.deltaTime; // меняется значение угла
var x = Mathf.Cos(angle * speed) * radius + parent.position.x;
var y = Mathf.Sin(angle * speed) * radius + parent.position.y;
transform.position = new Vector3(x, y,0);
//transform.Rotate(0, 0, a);
}
`
Help me, how to calculate angle?
You need Mathf.Atan2, it will return a radian, then you need to multiply a Mathf.Rad2Deg to get the Euler angle.

Given world position and normalized world space compute 2D canvas location

I am trying to create a F1 2021 Radar like shown in the repository here: https://github.com/ryry6/f1-radar-releases
Or in the image here
I have computed the delta X and Z coordinates to each of the cars, however I am struggling to get the cars to appear as intended on a 2D Canvas (C#, WPF).
The following is the data provided by the game:
public float m_worldPositionX; // World space X position
public float m_worldPositionY; // World space Y position
public float m_worldPositionZ; // World space Z position
public float m_worldVelocityX; // Velocity in world space X
public float m_worldVelocityY; // Velocity in world space Y
public float m_worldVelocityZ; // Velocity in world space Z
public short m_worldForwardDirX; // World space forward X direction (normalised)
public short m_worldForwardDirY; // World space forward Y direction (normalised)
public short m_worldForwardDirZ; // World space forward Z direction (normalised)
public short m_worldRightDirX; // World space right X direction (normalised)
public short m_worldRightDirY; // World space right Y direction (normalised)
public short m_worldRightDirZ; // World space right Z direction (normalised)
public float m_gForceLateral; // Lateral G-Force component
public float m_gForceLongitudinal; // Longitudinal G-Force component
public float m_gForceVertical; // Vertical G-Force component
public float m_yaw; // Yaw angle in radians
public float m_pitch; // Pitch angle in radians
public float m_roll; // Roll angle in radians
The following is the code I am unsure about...
var deltaX = PlayerCar.m_worldPositionX - OtherCar.m_worldPositionX;
var deltaZ = PlayerCar.m_worldPositionZ - OtherCar.m_worldPositionZ;
var deltaYawRad = PlayerCar.m_yaw - OtherCar.m_yaw;
// Convert from RAD to DEG
double deltaYaw = (180 / Math.PI) * deltaYawRad;
// This is the part I need help with
var moveUp = deltaZ * worldRightDirZ + deltaX * worldForwardDirX;
var moveLeft = deltaX * worldRightDirX + deltaZ * worldForwardDirZ;
// Set the rectangle to a position on the canvas and scale it accordingly
Canvas.SetTop(rec, RadarModel.PlayerCarTop + moveUp * RadarModel.Scale);
Canvas.SetLeft(rec, RadarModel.PlayerCarLeft + moveLeft * RadarModel.Scale);

How to randomly find one of the vectors from point P tangent to a sphere

I would like to randomly select a vector originating at point P, such that the line formed alongside this vector is tangent to the surface of some sphere. To do this, I need a collection of all points S forming a circle on the sphere, such that the line SP is tangent to the sphere at point S. Then, given this information, I can select one point S', and create a direction vector from point P to point S'.
I would like to do this in Unity. I don't have much preference over how the vector is created itself, as long as it can be randomised and points to a point on the abovementioned circle. I believe an ideal solution would consider an angle θ ∈ [0, 2π] which can be randomised to give a vector from the origin of the circle (not the sphere) to the associated S' point.
I would appreciate a solution in C#, but I am happy with other languages too. Please do note that while the mathematical solutions are appreciated, I am specifically looking for implementation details, as I am not very fluent with Unity engine, their coordinate system and vector operations yet.
Visualisation below:
The solution in Unity is as follows:
Compute the circle's center point
Compute the circle's radius
Create a projection using a randomly selected point in 3D coordinates and point P
Use the center point and the radius to position the point, which results in finding S', such that PS' is tangent to the sphere
using UnityEngine;
public class Script : MonoBehaviour
{
private readonly float _accuracy = 0.1f;
private readonly int _vectorsCount = 1000;
private readonly Vector3 _point = new Vector3(600, 600, 600);
private readonly float _sphereRadius = 500f;
private void Start()
{
// This value will be used to calculate both the circle coordinates and its radius.
var quadraticSum = Mathf.Pow(_point.x, 2) + Mathf.Pow(_point.y, 2) + Mathf.Pow(_point.z, 2);
// Find out coordinates of the circle created by the intersection of the plane with the sphere
Vector3 circleCenter;
circleCenter.x = _point.x * Mathf.Pow(_sphereRadius, 2) / quadraticSum;
circleCenter.y = _point.y * Mathf.Pow(_sphereRadius, 2) / quadraticSum;
circleCenter.z = _point.z * Mathf.Pow(_sphereRadius, 2) / quadraticSum;
// Find out radius of the above circle
var circleRadius = _sphereRadius * Mathf.Sqrt(quadraticSum - Mathf.Pow(_sphereRadius, 2)) /
Mathf.Sqrt(quadraticSum);
/*
* At this point, we can start drawing - let's draw:
*
* - the point using red colour
* - the sphere using blue colour
* - the circle using green colour
*
* Below assumes center of the sphere is at (0, 0, 0)
*/
Debug.DrawLine(Vector3.zero, _point, Color.red, 1000);
DrawSphere();
DrawCircle(circleCenter, circleRadius);
}
private void DrawSphere()
{
for (var theta = -Mathf.PI; theta < Mathf.PI; theta += _accuracy)
{
for (var phi = -Mathf.PI; phi < Mathf.PI; phi += _accuracy)
{
var ray = new Vector3(
_sphereRadius * Mathf.Sin(theta) * Mathf.Cos(phi),
_sphereRadius * Mathf.Sin(theta) * Mathf.Sin(phi),
_sphereRadius * Mathf.Cos(theta)
);
Debug.DrawLine(Vector3.zero, ray, Color.blue, 1000);
}
}
}
private void DrawCircle(Vector3 center, float radius)
{
for (int i = 0; i < _vectorsCount; i++)
{
// Since I wanted random vectors, I am repeatedly drawing a random vector on the circle
var tangentPoint = Vector3.ProjectOnPlane(Random.insideUnitSphere, _point).normalized * radius + center;
Debug.DrawLine(Vector3.zero, tangentPoint, Color.green, 1000);
//Debug.DrawLine(_point, tangentPoint, Color.cyan, 1000);
}
}
}
See the screenshots for visualisation:
Here is an angle with the red line drawn after the sphere and the circle are drawn, to see the center of the sphere:

Projectile trajectory based on angle

In my 3D game (top down shooter), I try to do this:
When you click the mouse button (raycast on point) on a specific area on the map -> a shot was fired from the gun -> the projectile flies in the direction of the barrel with a certain path and at the same distance as the mouse pointer (but not the direction).
I already have the source code for calculating the projectile trajectory.
Help make the projectile fly in the direction of the barrel, BUT with the distance shown by the mouseposition raycast, NOT the mouseposition direction.
```private void FireCannonAtPoint(Vector3 point)
{
var velocity = BallisticVelocity(point, _angle);
GameObject projectile = Instantiate(_projectile, _shootPoint.transform.position, Quaternion.identity) as GameObject;
projectile.GetComponent<Rigidbody>().velocity = velocity;
}
private Vector3 BallisticVelocity(Vector3 destination, float angle)
{
Vector3 dir = destination - _shootPoint.transform.position;
float height = dir.y;
dir.y = 0;
float dist = dir.magnitude;
float a = angle * Mathf.Deg2Rad;
dir.y = dist * Mathf.Tan(a);
dist += height / Mathf.Tan(a);
float velocity = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 * a));
return velocity * dir.normalized;
}```
Barrel: segment [turret_end_1, turret_end2] in 3D, where turret_end_1 the point on the turret where the bullet leaves it.
Screen: the focal point F and the plane of the screen, named screen_plane.
# From 3D to 2D: projection from 3D space on the screen_plane:
Mouse = [mouse_x, mouse_y] # given on the screen_plane
B1 = project_on_screen_plane(turret_end_1)
B2 = project_on_screen_plane(turret_end_2)
# Calculations in 2D, i.e. on the screen_plane
U = B1-B2
U = ( dot_product(Mouse-B1, U) / dot_product(U, U) ) * U
U = B1 + U # this is the point you are looking for on the screen
# From 2D back to 3D: connect the focal point with the point U on the screen plane
# to form a line and find its intersection point in 3D with the line B1 B2
# aligned with the turret.
# line through F with directing vector Vector_from_F_to(U)
# line through B1 with directing vector B1-B2
V = intersect( F, Vector_from_F_to(U), B1, B1-B2 ) # the point you are looking for in 3D

Categories