Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by developer_arni · Oct 23, 2013 at 10:12 PM · rotationmeshvector3quaternion

Rotating direction vectors

I have two 3d objects A and B which collide at a single point P (they could collide at several points at once, but I am only interested in a specific point at a time), this collision point P, hits a mesh triangle T1 on A and a mesh triangle T2 on B. I am trying to rotate B so that T1 and T2 are parallel, i.e. align their rotations so that T2 lies 'flat' on T1.

P is determined by two raycasts, one for each hit, which provides me with information of the meshes, collision point and triangles.

I am stuck rotating B with the correct amount.

I have tried calculating the normal vectors from the T1 and T2 (as they can simply be considered as planes in the world) and used Quaternion.FromToRotation/2 like this:

 B.transform.rotation = Quaternion.FromToRotation(T2.normalVector,T1.normalVector);

Note that the code is slightly pseudo-like. This produces almost! the correct answer, although B is still rotating slightly wrong, taking the inverse of the result from FromToRotation, produces an even better result, but still not there.

Then I read somewhere that FromToRotation actually returns the amount of rotation that needs to be done before being hitting the target direction, but trying to work with this new information, just messes the rotation completely up!

I have also tried using many of the other Quaternion functions, even tried manually to calculate the axis and angle needed to rotate to the wanted direction (T1) and then use Quaternion.AngleAxis, although this doesn't change the rotation at all.

I thought at first that this problem would be rather straight forward; I have two directions D1 and D2 and a object Obj, and I want to rotate Obj with the same rotation that it would take to align D1 with D2. But I am stuck! Endless of Quaternion tutorials, unityAnswer post and google searches later, and I am still stuck.

I appreciate any help or guidens, thanks in advance.

The following is the script that, at least tries to accomplish the above. In the script A is referred to as primary and B is referred to as secondary.

 #pragma strict
 
 public var primary:GameObject;
 public var secondary:GameObject;
 private var attachmentHit : RaycastHit;


 function Start () {

 // - Find the hit of the initial attachmentment point on the secondary item
 // Note this is the bottom 
     
 // Get the position of the core of the secondary
 var secCorePos : Vector3 = secondary.transform.Find("SecCore").gameObject.transform.position;
 
 // Create the ray
 var origin : Vector3 = secCorePos+Vector3.down;
 var direction : Vector3 = secCorePos - origin;
 
 // Cast the ray and fill the attachmentHit value
 Physics.Raycast(origin, direction, attachmentHit, 100.0f, 1 << 9);
 }

The following function is called when the secondary item is being dragged, it rotates and positions the secondary item based on the mouse position and primary item.

   function OnMouseDrag()
 {
 // - Calculate the next position and rotation of the secondary item
 
 // Get the screen position of the mouse
 var mpos : Vector2 = Input.mousePosition;
 // Get the position of the core of the primary item
 var primCorePos : Vector3 = primary.transform.Find("PrimCore").gameObject.transform.position;
 // Translate the mouse screen position to a world position
 var mposworld : Vector3 = GetWorldPosFromMousePoint(mpos,Vector3.Distance(primCorePos,
                                                     Camera.main.transform.position));
 
 // Create a ray from the mouse position to the primary core
 var dis : float = Vector3.Distance(mposworld, primCorePos);
 var dir : Vector3 = (primCorePos - mposworld).normalized;
 
 // Cast the ray
 var hits : RaycastHit[] = Physics.RaycastAll(mposworld, dir, dis, 1 << 8);
 DebugUtils.Assert(hits.length > 0, "OnMouseDrag: There has to be atleast one hit!");
 
 // Find the collision that was the furthest away from the core
 // ie. shortest distance as the ray starts at mouse position
 var outmosthit : RaycastHit = hits[0];
 var prevdis : float = outmosthit.distance;
 for (var i:int = 1; i < hits.length; i++)
 {
     var nextdis : float = hits[i].distance;
     if (nextdis < prevdis)
     {
         outmosthit = hits[i];
         prevdis = nextdis;
     }
 }
     
 // Returns self + all children (all levels)
 var allChildren = secondary.GetComponentsInChildren(Transform);
 for (var child : Component in allChildren) {
     // Move all children, including self
     child.transform.position = outmosthit.point; 
 }

 // Get the normal vector from the collision triangle on the primary object
 var normalPrim : Vector3 = GetNormalVectorFromHit(outmosthit);
 // Get the normal vector from the attachment triangle on the secondary object
 var normalSec : Vector3 = GetNormalVectorFromHit(attachmentHit);

 // Rotate the secondary object so its hit-triangle aligns with the hit-triangle of the primary object
 secondary.transform.rotation = Quaternion.FromToRotation(normalSec,-normalPrim) * secondary.transform.rotation;
 }

The following function (should) retrieve the normal vector from a triangle-hit

 function GetNormalVectorFromHit(hit:RaycastHit) : Vector3
 {
 // See link for details and this is partly taken from there
 // http://docs.unity3d.com/Documentation/ScriptReference/RaycastHit-barycentricCoordinate.html
 DebugUtils.Assert(hit != null, "GetNormalVectorFromHit: hit cannot be null");

 // Just in case, also make sure the collider also has a renderer 
 // material and texture 
 var meshCollider = hit.collider as MeshCollider;
 DebugUtils.Assert(meshCollider != null, "GetNormalVectorFromHit: meshCollider cannot be null");
 DebugUtils.Assert(meshCollider.sharedMesh != null, "GetNormalVectorFromHit: sharedMesh cannot be null");
 
 var mesh : Mesh = meshCollider.sharedMesh;
 var vertices = mesh.vertices;
 var triangles = mesh.triangles;
 var p1 = vertices[triangles[hit.triangleIndex * 3 + 0]]; 
 var p2 = vertices[triangles[hit.triangleIndex * 3 + 1]];    
 var p3 = vertices[triangles[hit.triangleIndex * 3 + 2]];
 var u : Vector3 = p2 - p1;
 var v : Vector3 = p3 - p1;
 var normalVector : Vector3 = Vector3.Cross(u,v);
 
 return normalVector.normalized;
 }

The following function converts a screen position to a world position

 function GetWorldPosFromMousePoint(pos:Vector2,distance:float)
 {
 var hit : RaycastHit;
 var point : Vector3;
 var ray : Ray = Camera.main.ScreenPointToRay(pos);

 // http://answers.unity3d.com/questions/376735/get-world-coordinates-from-mouse-click.html
 point = ray.origin + (ray.direction * distance);     

 return point;
 }
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by robertbu · Oct 24, 2013 at 04:05 AM

I believe what you are looking for is in terms of aligning the two normals is:

 B.transform.rotation = Quaternion.FromToRotation(T2.normalVector,-T1.normalVector) * B.transform.rotation;

Note this will align the two rotations, but since the rotation is around the pivot point of 'B', this means that the points of contact may be pulled apart by the rotation. If you need code to bring them back into alignment, let me know.

Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image developer_arni · Oct 25, 2013 at 07:15 PM 0
Share

Thanks for the reply! This resembles my intuition very much, although this makes B rotate like crazy (although in a pattern). There must be something else wrong, so I ran through my code again, line by line, but maybe I just don't get it. I edited my question with the code; if you or anyone else would like to try and help me further.

avatar image robertbu · Oct 25, 2013 at 08:26 PM 1
Share

I'll be gald to continue to work with you on this issue. I like figuring out rotation problems. Usually I'll test a solution, but I'm mostly away from my desktop for the couple of days. I'm pretty sure the line of code I provided will do what you want given accurate normals. I'll review your code further when I get a bit more time, but one thing jumps out at me. Why are you going to all the trouble of calculating the normals when the RaycastHit struct provides normal for you? I'd start by replacing your normal calculating code with the RaycastHit.normal and go from there.

avatar image robertbu · Oct 25, 2013 at 08:29 PM 1
Share

Taking another quick look, your normal code has an issue. The vertices in a mesh are local coordinates. You want a world space normal. You need to convert these vertices into world space to your your code. See Transform.TransformPoint() or Transform.TransformDirection().

avatar image developer_arni · Oct 26, 2013 at 05:47 PM 0
Share

Unbelievable! I had not considered that the vertices were in local space! Taking this into account and using your rotation line makes it work just perfect!

And I am rather new to working with meshes and raycasthits in unity, and had not considered much about all the fields in a raycasthit. Thanks for the tip, although simply using the normal field does not work? Is this still in local space? As using Transform.TransformPoint() or Transform.TransformDirection() on these values does not work either?

avatar image robertbu · Oct 26, 2013 at 06:38 PM 0
Share

The normal in RaycastHit is in world space and does not require conversion.. You should compare your normal after converting it into world space to the Raycast normal to see how/if they are different. They should be the same.

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

14 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

3D nested Turret Prefab Rotation 1 Answer

Game Object rotation sometimes doesn't match defined quaternion 0 Answers

Perpendicular Vector3 0 Answers

Rotate object based on hit normal + matching camera direction 0 Answers

Rotating sprite through touch (storing current rotation) 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges