i'm trying to get the tangent vector for each point on the circle , i tried to use the derivative for the circle equation, but the result looks off in the viewport, so i'm wondering if i can find some help here
the code
public void OnDrawGizmos(){
step = (360.0f * Mathf.Deg2Rad) / numberOfPoints ;
CreateVertices();
}
void CreateVertices()
{
Points.Clear();
Normals.Clear();
Tangents.Clear();
float dynamicAngle = 0.0f;
for (int i = 0; i <= numberOfPoints; i++)
{
Vector3 point;
point.x = transform.position.x + Radius * Mathf.Cos(dynamicAngle);
point.y = transform.position.y + Radius * Mathf.Sin(dynamicAngle);
point.z = transform.position.z;
dynamicAngle = dynamicAngle + step;
if (i >= 1)
{
Gizmos.color = Color.red;
Gizmos.DrawLine(Points[i - 1], point);
Gizmos.color = Color.white;
}
Points.Add(point);
CalculateNormals(dynamicAngle ,point);
CalculateTangents(dynamicAngle,i , point);
}
}
void CalculateNormals(float dynamicAngle , Vector3 point)
{
Vector3 Normal = (point - transform.position).normalized;
Gizmos.color = Color.magenta;
Gizmos.DrawLine(Normal, point);
Gizmos.color = Color.white;
Normals.Add(Normal);
}
void CalculateTangents(float dynamicAngle,int i ,Vector3 point)
{
Vector3 tangent;
tangent = new Vector3(-Normals[i].y, Normals[i].x, 0);
tangent.Normalize();
Gizmos.color = Color.blue;
Gizmos.DrawLine( point, tangent);
Gizmos.color = Color.white;
Tangents.Add(tangent);
}
Blue is the tangents purple is the normals, as you can see they are not perpendicular:
To understand my issue better here is a gif from unity viewport:
Since you already calculated the normals you can use the cross product to get the corresponding tangents
Vector3 up = new Vector3(0, 0, 1); // up side of your circle
Vector3 tangent = Vector3.Cross(normal, up);
If you only need to use circles on a specific plane you can also use this simplification
Vector3 tangent = new Vector3(-normal.y, normal.x, 0);
Edit:
The normals and tangents are direction vectors. They point from point in the direction the normal / tangent whould point. To draw the tangent, you have to pass the correct start and end points of the line by using
Gizmos.DrawLine(point, point + tangent);
If you move the GameObject away from the origin you will notice that the normals also get deformed, this has the same reason.
You are using 2D parametric equations:
x = x0 + r*cos(a)
y = y0 + r*sin(a)
z = z0
a = <0,2*Pi>
Tangent is unit circle coordinate with center (0,0,0) but shifted by 90 degrees:
tx = cos(a (+/-) pi/4)
ty = sin(a (+/-) pi/4)
tz = 0
Similarly bi-tangent is:
bx = (+/-) cos(a)
by = (+/-) sin(a)
bz = 0
and finally normal is
nx = 0
ny = 0
nz = (+/-) 1
The signs depends on your coordinate system conventions and movement direction.
Related
I am working on a 3D project, in Unity.
I have an object moving in a confined space. The object have a fixed velocity, and it bounces back once they reach the space limit.
I want it to change direction once every n seconds.
The problem I am facing is: How to rotate a 3D vector by a given angle.
In 2D is pretty easy, while in 3D I am not sure how to handle it.
Can someone help me with that?
In 2D this is simple...
In three 3 as well.
You can e.g. simply rotate a Vector3 about any given Euler angles via
var newVector = Quaternion.Euler(x, y, z) * oldVector;
question remains where you get those angles from and whether those are random or you are rather looking for Reflect the vector once the objects reach your defined area constraints.
You can as well simply invert the individual components like e.g.
// Note for simplicity reasons this is not an actual "distance"
// but rather the maximum of each individual axis
public float maxDistance;
private Rigidbody _rigidbody;
private void Start ()
{
_rigidbody = GetComponent<Rigidbody>();
_rigidbody.velocity = Random.insideUnitSphere.normalized;
}
private void FixedUpdate()
{
var vel = _rigidbody.velocity;
var pos = _rigidbody.position;
if(Mathf.Abs(pos.x) >= maxDistance)
{
vel.x *= -1;
}
if(Mathf.Abs(pos.y) >= maxDistance)
{
vel.y *= -1;
}
if(Mathf.Abs(pos.z) >= maxDistance)
{
vel.z *= -1;
}
_rigidbody.velocity = vel;
}
You can change directions by a certain angle on a certain axis, making it similar to 2D.
If you are moving the object with its transform you can easily rotate an object with the Rotate method on the game object transform.
//in a script attached to the game object you want to rotate
transform.Rotate(Vector3.up, Random.Range(90,270), Space.self);
You can now use transform.forward to move the object.
If you want to go deeper into 3D rotation have a look at Quaternions
You can use the Quaternion.operator * to rotate one rotation by another, or to rotate a vector by a rotation.
Consider also looking at the Vector3 class methods such as Reflect and RotateTowards.
Tip: To keep a consistent speed across all directions, consider normalizing the direction vector, (0,1,1) will travel faster than (0,0,1).
You can normalize any vector as follows:
Vector3 direction = Vector3.up + Vector3.forward; //(0,1,1)
direction = direction.normalized; //(0,0.71,0.71)
I managed to do the thing I wanted. Firstly, I computed a Vector3 that was orthogonal to the current transform.forward; then I rotate that angle around itself of a random angle between 0 and 360 degrees, and finally I used that generated vector as axis for the rotation to apply to the velocity of my object.
Here is the code:
public static void ChangeObjectDirection(Rigidbody rb, int angle, float velocity)
{
// get the transform of rb
var t = rb.gameObject.transform;
// get the current velocity direction
var direction = t.forward;
// generate a normalized orthogonal vector wrt the current velocity direction
var orth = OrthogonalVector(direction);
// rotate the orthogonal vector around himself of a random angle between 0 and 360
orth = Quaternion.AngleAxis(Random.Range(0, 360), direction) * orth;
// generate random rotational angle in degrees
var randomAngle = Random.Range(-angle, angle);
// rotate the current velocity direction of randomAngle around the orth vector
direction = Quaternion.AngleAxis(randomAngle, orth) * direction;
// update the velocity direction
t.forward = direction;
rb.velocity = direction * velocity;
}
private static Vector3 OrthogonalVector(Vector3 u)
{
var a = u.x;
var b = u.y;
var c = u.z;
Vector3 v;
if (b == 0 && c == 0)
{
v = new Vector3(0f, 1f, 1f);
}
else if (a == 0 && c == 0)
{
v = new Vector3(1f, 0f, 1f);
}
else if (a == 0 && b == 0)
{
v = new Vector3(1f, 1f, 0f);
}
else
{
if (c != 0)
{
// ax + bx + cz == 0 with x == 1 and y == 1 => z = (-a - b) / c
v = new Vector3(1f, 1f, (-a - b) / c);
}
else
{
// ax + bx + cz == 0 with y == 1 and z == 1 => c = (-b - c) / a
v = new Vector3((-b - c) / a, 1f, 1f);
}
}
v = v.normalized;
return v;
}
I want to proceduraly generate meshes. I created a method to supply the vertices of a circle. The idea is that it creates a shape in 2d and then rotates it in 3d assuming that "rotation" is the vector of the shapes normal axis.
public List<Vector3> Loop (Vector3 center, Vector3 rotation, float radius, int divisions)
{
List<Vector3> loop = new List<Vector3>();
for(int p = 0; p < divisions; p++)
{
float u = (float)Math.Cos(2 * Math.PI * p / divisions) * radius;
float v = (float)Math.Sin(2 * Math.PI * p / divisions) * radius;
float x = 0;
float y = 0;
float z = 0;
// Apply rotation to u & v to get x, y, z
loop.Add(new Vector3(x, y, z));
}
return loop;
}
Creating the circle in 2d (u & v) was super easy but when I looked into applying 3d rotations, it seemed to be a complete rabbit hole completely beyond my comprehension.
Is there a way to use existing API to do this?
I would pass in an axis parameter that you are rotating rotation around, then use Cross products to find the "up" direction for the "forward" that is the normal of the circle.
Use Quaternion.LookRotation, then Quaternion * Vector3 to apply the rotation to the position:
public List<Vector3> Loop (Vector3 center, Vector3 rotation, Vector3 axis, float radius, int divisions)
{
List<Vector3> loop = new List<Vector3>();
for(int p = 0; p < divisions; p++)
{
float u = (float)Math.Cos(2 * Math.PI * p / divisions) * radius;
float v = (float)Math.Sin(2 * Math.PI * p / divisions) * radius;
Vector3 fromPosition = new Vector3(u, v, 0f);
Vector3 up = Vector3.Cross(rotation.normalized, axis.normalized);
Quaternion rot = Quaternion.LookRotation(rotation, up);
loop.Add(rot * fromPosition);
}
return loop;
}
So you could do something like: List<Vector3> res = Loop(Vector3.zero, Vector3.up, Vector3.right, 10f, 20);
In the function below, The distance between ball and target is
known(R). Also, the angle between the resultant vector and the x-axis is
known(LaunchAngle). Thanks to these parameters(R, LaunchAngle), I
calculate the initial velocity of a ball. I checked all the values.
According to physics, they are all correct. Although all calculations
are correct, the ball does not hit the target.
void LaunchFromTargetPositionWithoutFrictionForce()
{
Vector3 projectileXZPos = new Vector3(transform.position.x, 0.0f, transform.position.z);
Vector3 targetXZPos = new Vector3(TargetObjectTF.position.x, 0.0f, TargetObjectTF.position.z);
transform.LookAt(targetXZPos);
float R = Vector3.Distance(projectileXZPos, targetXZPos);
float G = -Physics.gravity.y;
float Vz = Mathf.Sqrt(G * R / Mathf.Sin((2.0f * LaunchAngle) * Mathf.Deg2Rad));
float Vy = Vz * Mathf.Sin(LaunchAngle * Mathf.Deg2Rad);
float Vx = Vz * Mathf.Cos(LaunchAngle * Mathf.Deg2Rad);
text2.text = "vz: " + Vz.ToString() + " vy: " + Vy.ToString() + " vx: " + Vx.ToString();
Vector3 localVelocity = new Vector3(0f, Vy, Vx);
Vector3 globalVelocity = transform.TransformDirection(localVelocity);
rigid.velocity = globalVelocity;
bTargetReady = true;
if (isSlowMotion) timeManager.slowMotion();
}
First location of the ball
And after 2-dimensional motion it is hit before target
I changed first 3 line with below codes. And problem solved.
Vector3 projectileXZPos = transform.position;
Vector3 targetXZPos = TargetObjectTF.position;
float dist = Vector3.Distance(projectileXZPos, targetXZPos);
transform.LookAt(targetXZPos);
I am making the Bouncing Ball using Processing. It works fine when I use the ball object once, but when I use it twice like ball1 & ball2, the balls appear on top of each other making the delusion that it is just one ball bouncing, although I'm setting their primary location and velocity a random number. So, where is the problem? (first argument is for velocity and the second is for x Coordinate)
Main class:
Ball ball1 = new Ball(int(random(0, 2)),int(random(width)));
Ball ball2 = new Ball(int(random(0, 2)),int(random(width)));
void setup() {
// Windows configurations
size(640, 360);
background(50);
}
void draw() {
// Draw the circle
ball1.display();
// Circle movements
ball1.movements();
// Movement limits
ball1.movementLimits();
// Draw the circle
ball2.display();
// Circle movements
ball2.movements();
// Movement limits
ball2.movementLimits();
}
Ball class:
float xCoordinates;
float yCoordinates;
float xVelocity;
float yVelocity;
final float gravity = 0.1;
class Ball {
Ball(int Velocity, int Coordinates) {
xCoordinates = Coordinates;
yCoordinates = height / 6;
if (Velocity == 0)
xVelocity = 2;
else
xVelocity = -2;
if (Velocity == 0)
yVelocity = 2;
else
yVelocity = -2;
}
void movementLimits() {
if (xCoordinates - 10 <= 0 || xCoordinates + 10 >= width)
xVelocity *= -1;
if (yCoordinates + 10 >= height)
yVelocity *= -0.9;
if (yCoordinates - 10 <= 0)
yVelocity *= -1;
}
void movements() {
xCoordinates += xVelocity;
yCoordinates += yVelocity;
yVelocity += gravity;
}
void display() {
background(50);
fill(255);
stroke(255);
circle(xCoordinates, yCoordinates, 20);
}
}
Problem 1:
Both of your objects are shaing the same cooridinates and velocity. They are stored globally so when one object changes it, the change is used by the other object as well. To fix this you should give your Ball class properties to hold the coordinates and velocities.
class Ball{
float x;
float y;
float dx;
float dy
public Ball(float x, float y, float dx, float dy){
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
}
}
Problem 2:
In the display function in Ball, you call background(50);. This will basicly cover the entire screan with the new background; over any previous balls which includes ball1. However, if you remove this line you'll get a kind of cool effect cause by all previous ball drawing sticking around. You should move the background(50); line to the beginning of the draw function. This way, you draw the two balls, draw over them with gray, then redraw the two balls in their new positions.
I'd like to draw the trajectory of an object that is moving circularly, but I do not know how to do it.
Could you tell me a good way?
I've not done a orbiting around something, but I am using Cos and Sin to generate static items around the object.
If you use TrailRenderer with the use of MathF cos and sin to rotate around an object.
var y = amplitude * MathF.cos(Time.timeSinceLevelLoaded * speed) + currentPosY
var x = amplitude * MathF.sin(Time.timeSinceLevelLoaded * speed) + currentPosX
I've not watched it, but "Board to bits" on youtube has a tutorial on the matter. of space orbiting for a planet playlist.
Hope this is the right direction for you.
Thank you for a lot of response.
I found it works with below...
void drawLine()
{
Vector3[] points = new Vector3[segments+1];
for (int i = 0; i< segments; i++)
{
float angle = ((float)i / (float)segments) * 360 * Mathf.Deg2Rad;
float x = Mathf.Sin(angle) * radius;
float z = Mathf.Cos(angle) * radius;
points[i] = new Vector3(x, 0f, z);
}
points[segments] = points[0];
lr.positionCount = segments + 1;
lr.SetPositions(points);
}