Why am I getting an incorrect vector when trying to find HingeJoint2D.anchor in world space? - unity3d

In the scene, I have a long chain of children that are connected via hinge to their parent. For my code, I need the position of the hinge anchors in world space, so I use:
public Vector2 hingeVector => hinge.anchor + (Vector2)gameObject.transform.position;
For the first hinge, that code gives the correct position. But for the second hinge this happens:
The red point is the vector I get, the blue point is the actual position. As you can see, it's a somewhat small but still problematic difference.
Is there any way I can fix this? I couldn't find anything like this online.

You need to add the object's rotation
The anchor values are axis aligned and aren't affected by rotation, but in order to calculate the anchor point in world space, knowing the transform's position, you need to rotate the anchor point values by the object's rotation then add it to the position:
Vector2 p = hinge.anchor.Rotate(gameObject.transform.rotation.eulerAngles.z)
+ (Vector2)gameObject.transform.position;

Related

What's the difference between ScreenToWorldPoint and ScreenPointToWorldPointInRectangle?

What's the difference between ScreenToWorldPoint and ScreenPointToWorldPointInRectangle? And when should we use which one?
Senario:
I'm using UI system creating my card game similar to Hearthstone. I want to transform my mouse drag positions to world position. RectTransformUtility.ScreenPointToWorldPointInRectangle(UIObjectBeingDragged.transform.parent as RectTransform, Input.mousePosition, Camera.main, out resultV3) works fine. But I also tried Camera.main.ScreenToWorldPoint(Input.mousePosition), and it give a different and "wrong" result.
ScreenToWorldPoint
Gives you a world position (the return value) that is along a ray shot through the near plane of the camera (the Camera whose method is being called) at some given point (the x and y components of the position parameter) and a given distance from that near plane (the z component of the position parameter).
You should use this when you:
have a specific distance from the near plane of the camera you are interested in and
don't need to know if it hit inside some rectangle or not
You could think of this as a shortcut for Ray.GetPoint that uses the x and y of position and various info of the Camera to make the Ray, and the z component of position is the distance parameter.
ScreenPointToWorldPointInRectangle
Also gives you a world position (worldPoint) along a ray shot through the near plane of a camera (cam) at a given point (screenPoint). Only this time instead of giving you the point a given distance along the ray, it gives you the intersection point between that ray and a given rectangle (rect) if it exists, and tells you if such an intersection exists or not (the return value).
You should use this when you:
have a specific rectangle you are interested in the intersection with a camera ray,
You don't know the distance between the camera or its near plane and the intersection point
Want to know if that rectangle is hit by the ray or not.
You could think of this as a shortcut for Plane.Raycast which uses cam and screenPoint to make the Ray, and rect to make the Plane, and also gives some more information of if it would intersect outside the boundaries of the rect.

Rotate a wheel with camber angle

I'm new to 3D design, so this might be a silly question.
I have trouble simulating wheel camber using rotation with Quaternion.
What I understand is that the rotation of the WheelCollider occurs along the X axis, whereas in my case the "visual wheel" is rotated 80 ° along the Z axis so the rotation occurs along the Y axis.
This code works well with the FL wheel because its axis is aligned with the collider axis, while it doesn't work with the FR wheel.
collider.GetWorldPose(out Vector3 position, out Quaternion rotation);
visual.transform.position = position;
// initialVisualRotation is the wuaternion rotation of the visual at Startup
// in this case: X=0 Y=0 Z=80
visual.transform.rotation = initialVisualRotation * rotation;
These are my local and global rotation axes for the right front wheel (FR).
How can I "adjust" the wheel rotation without change initial axes (as I did for the FL wheel)?
Are there some quaternion operations to adopt in these cases?
A bit of workaround for not having to deal with messed up transforms is to make object a child of another empty object.This way you can make parent object rotated to make wheel tilted but Child( actual wheel) will have its original axis always not messed with and so you can use simple script to always rotate it around same axis that is always going to be the same despite whole system(hierarchy of objects) being " tilted".
Parent is responsible on rotating around one axis and child around another.
I think you need to take a step back and arrange your prefabs this way as it seesm you did not.

Find the offset between the rotation of a bone in Unity and in the original rig

Goal:
Calculate a rotation, that can be used, to correct the Transform of the bones, so they get rotated as expected when manually rotated.
In Detial:
Character's bone Transform is not imported to Unity correctily, ie. the left hand's Z axis does not looks towards the top of the hand, but backwards, while the right hand's Z axis looks forward.
The bones default rotation is not the same as you would expect if you have seen the rig in another application before.
I had the idea to create a class, that puts the character in T-Pose, then maps the bones rotation.
(I would assume that Unity does something similiar under the hood, that's how I got the idea.)
So the class would be used with an API like this:
/// This should return the rotation, where the bone pointing forward rotated by rotation.
/// Ie. when rotation = Quaternion.Identity the left hand should look forward.
Quaternion CorrectRotation(HumanBodyBones bone, Quaternion rotation)
{
return Quaternion.Inverse(tPoseRotations[bone]) * rotation;
}
The problem is, that I can't seem to find a good way to map theese rotations.
My last attempt was this:
Vector3 boneDirection = (boneTransform.position - parentTransform.position).normalized;
Quaternion mappedRotation = Quaternion.LookRotation(boneDirection, parentTransform.up);
As you can see in this image, with this method the hands look in the same direction, forward, but still not rotated correctly, they have an offset from the desired result. (The correct rotation is shown by the purple hands.)
When given other rotations, the hands follow with the same offset, so other then this unwanted offset they work correctly.
So basically, I would appriciate any help to fix my problem, either this way, or with a different solution, that works with different rigs.

Unity3D - Get Mathematical Plane from Primitive Plane in same world position

I have a GameObject.Plane in a given position for visual purposes.
From that, given the plane's rotation and position in world space, I have to make a mathematical plane to use in the next calculations, but something's off.
I've tried doing
new Plane(go.transform.InverseTransformDirection(-go.transform.right), go.transform.InverseTransformPoint(go.transform.position));
where go is the primitive plane object.
Its position in world space seems fine, judging from the later results, but the rotation is not.
The Primitive plane(go) is rotated 90 degrees so instead of facing upwards it's facing the side.
What's going wrong here?
Edit: Current setup is
go.transform.InverseTransformDirection(-go.transform.right);
return new Plane(go.transform.up, go.transform.position);
void OnDrawGizmos()
{
Gizmos.color = Color.magenta;
Gizmos.DrawLine(planePrimitive.transform.position, planePrimitive.transform.position + plane.normal * 3f);
}
This
go.transform.InverseTransformDirection(-go.transform.right)
returns a vector facing to the side and you are using it as the Plane's normal.
A primitive Plane object's normal is simply it's local transform.up vector.
Then note that a Plane takes world space coordinates so it makes no sense to use InverseTransformDirection and InverseTransformPoint since transform.up and transform.position already are in world space.
new Plane(go.transform.up, go.transform.position);
If you are rather talking about a primitive Quad object then the vector you want is -transform.forward instead.
new Plane(-go.transform.forward, go.transform.position);
To your Gizmos:
You are using the testPlane.normal like it was a position. It is not! The normal is a direction and doesn't tell anything about the position.
What you want to do would be e.g. (without using local space gizmos)
Gizmos.DrawLine(go.transform.position, go.transform.position + testPlane.normal * 3f);
or if you can depend only on the plane itself use
Gizmos.DrawLine(plane.distance, plane.distance + testPlane.normal * 3f);
In this second plane the plane.distance is the vector from 0,0,0 to the closest point on the plane. It will therefore still not be exactly in the position of the given plane object.

Unity3D angle between vectors/directions on specific axis

I have two directions and i am trying to calculate the angle on a specific axis. The object from which the directions are derived is not a static object so i'm struggling to get my head round the maths to work out what i need to do.
FYI, I have the start and end points that i have used to calculate the directions if they are needed.
Here's a diagram to show what i am looking for:
The above image is from a top-down view in unity and it shows the angle i want.
The problem can be seen from the above image, which is that the directions are not on the same height so i can't use the vector3.angle function as it won't give me the correct angle value.
In essence i want to know how much would i have to rotate the red line to the left (top view) so that it would line up with the blue (top-view).
The reason i need this is as i am trying to find a way of getting the side-to-side angles of fingers from my leap motion sensor.
This a generic version of my other question:
Leap Motion - Angle of proximal bone to metacarpal (side to side movement)
It will provide more specific information as to the problem if you need it and it has more specific screenshots.
**UPDATE:
After re-reading my question i can see it wasn't particularly clear so here i will hopefully make it clearer. I am trying to calculate the angle of a finger from the leap motion tracking data. Specifically the angle of the finger relative to the metacarpal bone (bone is back of hand). An easy way to demonstrate what i mean would be for you to move your index finger side-to-side (i.e. towards your thumb and then far away from your thumb).
I have put two diagrams below to hopefully illustrate this.
The blue line follows the metacarpal bone which your finger would line up with in a resting position. What i want to calculate is the angle between the blue and red lines (marked with a green line). I am unable to use Vector3.Angle as this value also takes into account the bending of the finger. I need someway of 'flattening' the finger direction out, thus essentially ignoring the bending and just looking at the side to side angle. The second diagram will hopefully show what i mean.
In this diagram:
The blue line represents the actual direction of the finger (taken from the proximal bone - knuckle to first joint)
The green line represents the metacarpal bone direction (the direction to compare to)
The red line represents what i would like to 'convert' the blue line to, whilst keeping it's side to side angle (as seen in the first hand diagram).
It is also worth mentioning that i can't just always look at the x and z axis as this hand will be moving at rotating.
I hope this helps clear things up and truly appreciate the help received thus far.
If I understand your problem correctly, you need to project your two vectors onto a plane. The vectors might not be in that plane currently (your "bent finger" problem) and thus you need to "project" them onto the plane (think of a tree casting a shadow onto the ground; the tree is the vector and the shadow is the projection onto the "plane" of the ground).
Luckily Unity3D provides a method for projection (though the math is not that hard). Vector3.ProjectOnPlane https://docs.unity3d.com/ScriptReference/Vector3.ProjectOnPlane.html
Vector3 a = ...;
Vector3 b = ...;
Vector3 planeNormal = ...;
Vector3 projectionA = Vector3.ProjectOnPlane(a, planeNormal);
Vector3 projectionB = Vector3.ProjectOnPlane(b, planeNormal);
float angle = Vector3.Angle(projectionA, projectionB);
What is unclear in your problem description is what plane you need to project onto? The horizontal plane? If so planeNormal is simply the vertical. But if it is in reference to some other transform, you will need to define that first.