Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 stadlernicolas26 · Jun 27, 2020 at 03:16 PM · rotationvector3anglescalculatehexagon

How to calculate the rotation of a hexagon based on its six vertices position

I have given a hexagon with the position of its six vertices given. My question is, how to calculate the rotation of the hexagon in all three dimensions. If anyone could come up with a general function with these six vertices as arguments I would be soo thankful, because I by myself am not able to do that. I already tried it with Vector3.Angle, but I always got wrong results and now I gave up.

Comment
Add comment · Show 1
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 stadlernicolas26 · Jun 28, 2020 at 09:47 AM 0
Share

I also tried it with trigonometry but i couldnt figure out which vertices to use because i dont know how to deter$$anonymous$$e the two vertices on the top and the bottom

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by UnityedWeStand · Jul 01, 2020 at 12:27 AM

The solution to your problem is actually quite involved (I had to write something similar for a game I'm working on, in the context of aligning the faces of polyhedra with each other). I'll try to walk you through as best as I can, but it may take some time to understand what is going on.

From what I can tell, your question is: given the location of the vertices of an arbitrarily rotated hexagon in 3D spaceVector3[] rotatedHexagonVerts = new Vector3[] {v1, v2, v3, v4, v5, v6}, you want to be able to calculate some rotation Quaternion hexagonRotation that defines the rotation of rotatedHexagonVerts relative to some neutral position (X, Y, Z rotation all equal to zero) given by Vector3[] neutralHexagonVerts = new Vector3[] {n1, n2, n3, n4, n5, n6}

As will all thing rotational, Quaternions will be your best friend. I will not assume your hexagon is symmetrical (or even flat for that matter), so this solution will work in all cases.

 private Quaternion GetHexagonRotation(Vector3[] rotatedHexagonVerts, Vector3[] neutralHexagonVerts)
 {
     Vector3 neutralRefVector1 = neutralHexagonVerts[1] - neutralHexagonVerts[0];
     Vector3 neutralRefVector2 = neutralHexagonVerts[2] - neutralHexagonVerts[0];
     Vector3 rotatedRefVector1 = rotatedHexagonVerts[1] - rotatedHexagonVerts[0];
     Vector3 rotatedRefVector2 = rotatedHexagonVerts[2] - rotatedHexagonVerts[0];
 
     Quaternion rotation1 = Quaternion.FromToRotation(neutralRefVector1, rotatedRefVector1);
     Vector3 newNeutralRefVector2 = rotation1 * neutralRefVector2;
 
     Vector3 rotatedRefVector2Perp = rotatedRefVector2 - Vector3.Project(rotatedRefVector2, rotatedRefVector1);
     Vector3 newNeutralRefVector2Perp = newNeutralRefVector2 - Vector3.Project(newNeutralRefVector2, rotatedRefVector1);
 
     float angle = Vector3.Angle(newNeutralRefVector2Perp, newRotatedRefVector2Perp);
     Quaternion rotation2 = Quaternion.AngleAxis(angle, rotatedRefVector1);
 
    return rotation2 * rotation1;
 }


There's a lot of vector math going on, so you might need to take some time to dissect each operation. Feel free to reach out for questions.

Comment
Add comment · Show 7 · 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 stadlernicolas26 · Jul 01, 2020 at 05:07 AM 0
Share

Imma try it out when Im at home again, but I already got one question: Is the order of the vertices of rotatedHexagonVerts and neutralHexagonVerts important? Because I dont know the order Im given by uniy when I assign rotatedHexagonVerts to the hexagonmesh.vertices array

avatar image UnityedWeStand stadlernicolas26 · Jul 01, 2020 at 08:25 AM 1
Share

The order for a particular hexagon doesn't matter (i.e. v1, v2, v3, v4, v5, v6 could be the vertices in clockwise order, counter clockwise order, or some completely random order). However, it is very important that there is correspondence between the vertices of rotatedHexagonVerts and neutralHexagonVerts. What this means is that v1 and n1 need to be the same vertex on the hexagon, v2 and n2 need to be the same vertex, and so on for the other vertices.

avatar image stadlernicolas26 · Jul 01, 2020 at 12:30 PM 0
Share

I tried it now and I guess you made a typo, i think at Vector3.Angle it should be newNeutralRefVector2Perp and rotatedRefVector2Perp. Also I am getting values for the rotation around 0.5, is this supposed to be like that? $$anonymous$$aybe I messed up the order, but I would not know how to sort both vertices arrays to be the same. Or does the reference object has to be same size and same position?

avatar image UnityedWeStand stadlernicolas26 · Jul 02, 2020 at 04:58 AM 0
Share

Oh, good catch on the typo.

The return type of the function is a Quaternion, so you can't really read the values directly. You could see the Euler Angles equivalent by accessing someQuaterion.eulerAngles, which would be more useful.

Regarding the order of the vertices, may I ask how you know in the first place that the 6 random points definitely make up something resembling a hexagon, that they're not just a random cloud of points?

avatar image stadlernicolas26 UnityedWeStand · Jul 02, 2020 at 10:13 AM 0
Share

To your question how I know that the vertices make up a hexagon: Basically what I did was I made a hexsphere in Blender, a 3d modeling software. In order to then access every hexagon in Unity, I separated them in blender to different objects. But the problem in Blender is, that after a seperate you are able to get the position of the object relative to the wolrd, but not the rotation. And now, when I want to place something on the hexagonal tiles, I need to know how much I have to rotate it in order to fit nicely on the hexagon. quaternion.eulerAngles works fine, I am getting good rotation values, bit I am a bit hesitant of how to use them correctly, because when I apply them to the object that has to be rotated, it is not correctly. $$anonymous$$aybe I can figure out, how to use the eulerAngles.

Show more comments
avatar image
0

Answer by exploringunity · Jul 02, 2020 at 03:37 AM

Hey @stadlernicolas26 ,

First, read @UnityedWeStand 's answer -- it's more concise, and probably has better performance than my solution below :)

However, I still think there is some educational value in seeing a different approach to the same problem, so with that said, let's do some math!


The goal is to calculate the rotation required to align an arbitrarily rotated hexagon to some given up and forward vectors. We'll calculate 2 rotations -- first aligning with the up axis, and then aligning with the forward axis. After that, we'll combine the two rotations into one that aligns with both axes in a single motion.

We can break down the problem into several smaller steps:

0) Decide what is "WORLD UP" and what is "WORLD FORWARD" -- These are the axes that you will be aligning your hexagon to.

1) Find the plane ("LOCAL UP" and "LOCAL FORWARD" vectors) that the hexagon is aligned with using the 3-point method.

2) Use the Axis-Angle method to align the plane with the WORLD UP axis.

2.A) Find the axis of rotation to align the LOCAL UP axis with the WORLD UP axis using the Cross Product.

2.B) Find the angle of rotation to align the plane with the WORLD UP axis using the Dot Product.

2.C) Create a Quaternion describing the rotation to align the plane with the WORLD UP axis.

3) Rotate the LOCAL FORWARD axis of the plane to be aligned with the WORLD UP axis using the Quaternion created in step 2.C. This produces a WORLD-UP-ALIGNED LOCAL FORWARD axis.

4) Use the Axis-Angle method again to align the WORLD-UP-ALIGNED LOCAL FORWARD axis of the plane with the WORLD FORWARD axis.

4.A) Find the axis of rotation -- No work to do here :) The first rotation aligns the plane with the WORLD UP axis. The second rotation, to align the plane with the WORLD FORWARD axis, will be around the WORLD UP axis.

4.B) Find the angle of rotation to align the WORLD-UP-ALIGNED LOCAL FORWARD axis with the WORLD FORWARD axis using the Dot Product, also using the Cross Product to check the direction of rotation required.

4.C) Create a Quaternion describing the rotation to align the WORLD-UP-ALIGNED LOCAL FORWARD axis to the WORLD-FORWARD axis.

5) Combine the two rotations created above to create a Quaternion describing a single rotation to align the plane to both axes simultaneously.


Here's a screenshot with a demo of the visualization for several hexes with different rotations and reference up/forward vectors:

demo showing various hex rotations


Here's a code sample that implements the algorithm above to calculate the rotation and visualize the results -- Attach it to an empty GameObject and try playing around with the parameters in the inspector. GetAxisAlignmentRotation is the key function:

 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
 
 public class HexVisualizer : MonoBehaviour
 {
     public float outerRadius = 1f;
     // Pythagorean theorem -- equilateral triangle
     float innerRadius => outerRadius * 0.866025404f;
 
     [Header("INPUT: Initial hex Rotation (degrees)")]
     [Range(-360, 360)] public float rotX;
     [Range(-360, 360)] public float rotY;
     [Range(-360, 360)] public float rotZ;
 
     [Header("INPUT: Vectors to align hex to (not normalized)")]
     public Vector3 upVectorDenorm = Vector3.up;
     Vector3 referenceUp => upVectorDenorm.normalized;
     public Vector3 forwardVectorDenorm = Vector3.forward;
     Vector3 referenceForward => forwardVectorDenorm.normalized;
 
     [Header("OUTPUT: Rotation required to align hex with reference vectors")]
     public Vector3 calculatedAntirotation;
 
     Quaternion hexRot => Quaternion.Euler(rotX, rotY, rotZ);
 
     const float referenceVectorScale = 3.0f;
 
     Vector3[] GetCornersUntranslated()
     {
         // These are the corners for a pointy-top hex centered at the origin aligned with the XZ plane
         return new[] {
             new Vector3(0f, 0f, outerRadius),                   // Top
             new Vector3(innerRadius, 0f, 0.5f * outerRadius),   // Top-Right
             new Vector3(innerRadius, 0f, -0.5f * outerRadius),  // Bottom-Right
             new Vector3(0f, 0f, -outerRadius),                  // Bottom
             new Vector3(-innerRadius, 0f, -0.5f * outerRadius), // Bottom-Left
             new Vector3(-innerRadius, 0f, 0.5f * outerRadius)   // Bottom-Right
         };
     }
 
     Vector3[] GetCornersTranslated() { return GetCornersUntranslated().Select(x => transform.position + hexRot * x).ToArray(); }
 
     Quaternion GetAxisAlignmentRotation(Vector3 localUp, Vector3 localForward, Vector3 worldUp, Vector3 worldForward)
     {
         // Align hex with the UP vector provided by the user via the Axis-Angle method
         var upRotationAxis = Vector3.Cross(worldUp, localUp).normalized;
         var upAngle = Mathf.Acos(Vector3.Dot(worldUp, localUp));
         var alignUpRot = AxisAngleToQuaternion(upRotationAxis, upAngle);
 
         // Align hex with the FORWARD vector provided by the user
         // Find which way the hex thinks is "forward" after aligning with the UP vector...
         var upAlignedLocalForward = (Quaternion.Inverse(alignUpRot) * localForward).normalized;
         // ... and compare it to the reference forward vector
         var forwardAngle = Mathf.Acos(Vector3.Dot(worldForward, upAlignedLocalForward));
         // If the cross-product is negative, invert the rotation direction
         var flip = Vector3.Cross(worldForward, upAlignedLocalForward).y < 0f;
         if (flip) { forwardAngle = -forwardAngle; }
         var alignForwardRot = AxisAngleToQuaternion(worldUp, forwardAngle);
 
         // Multiply the two rotations to get a single rotation that aligns to both axes simultaneously
         return Quaternion.Inverse(alignForwardRot) * Quaternion.Inverse(alignUpRot);
     }
 
     public Quaternion AxisAngleToQuaternion(Vector3 axis, float radians)
     {
         var s = Mathf.Sin(radians / 2);
         var x = axis.x * s;
         var y = axis.y * s;
         var z = axis.z * s;
         var w = Mathf.Cos(radians / 2);
         return new Quaternion(x, y, z, w);
     }
 
     // A hexagon's center is directly between any two opposite points
     Vector3 CalculateCenter(Vector3[] corners) { return (corners[0] + corners[3]) / 2f; }
 
     // Find the plane the hex lies on using the 3-point method
     Vector3 CalculateNormal(Vector3[] corners)
     {
         var (a, b, c) = (corners[0], corners[1], corners[2]);
         var ab = b - a;
         var ac = c - a;
         return Vector3.Cross(ab, ac).normalized;
     }
 
     // Assumes pointy-top hexes, with the top vertex first, where "forward" is bottom -> top
     Vector3 CalculateForward(Vector3[] corners)
     {
         return (corners[0] - corners[3]).normalized;
     }
 
     void OnDrawGizmos()
     {
         // Calculate the rotation to align with the reference axes
         var corners = GetCornersTranslated();
         var hexCenter = CalculateCenter(corners);
         var hexUp = CalculateNormal(corners);
         var hexForward = CalculateForward(corners);
         var antiRotation = GetAxisAlignmentRotation(hexUp, hexForward, referenceUp, referenceForward);
 
         // Draw the world up/forward vectors that we want to align to
         DrawReferenceVectors();
 
         // Draw the original hex based on input params; also draw the up-alignment axis of rotation
         var upRotationAxis = Vector3.Cross(referenceUp, hexUp).normalized;
         DrawHex(corners, Color.red);
         DrawRotationAxis(upRotationAxis);
         DrawNormals(hexCenter, corners, hexUp, Color.green);
 
         // Draw the corrected hex after rotating to align with the reference axes
         var alignedCorners = corners.Select(x => antiRotation * (x - hexCenter) + hexCenter).ToArray();
         var alignedNormal = antiRotation * hexUp;
         DrawHex(alignedCorners, Color.magenta);
         DrawNormals(hexCenter, alignedCorners, alignedNormal, Color.cyan);
 
         // Output the calculated rotation to the inspector
         calculatedAntirotation = antiRotation.eulerAngles;
     }
 
     void DrawHex(Vector3[] corners, Color col)
     {
         Gizmos.color = col;
         int numCorners = corners.Length;
         if (numCorners == 0) { return; }
 
         Gizmos.DrawLine(transform.position, corners[0]);
         for (var i = 0; i < numCorners; i++)
         {
             var j = (i + 1) % (numCorners);
             var p1 = corners[i];
             var p2 = corners[j];
             Gizmos.DrawLine(p1, p2);
         }
     }
 
     void DrawNormals(Vector3 center, Vector3[] corners, Vector3 normal, Color col)
     {
         Gizmos.color = col;
         var points = new List<Vector3>(corners) { center };
         foreach (var point in points) { Gizmos.DrawRay(point, normal); }
     }
 
     void DrawReferenceVectors()
     {
         Gizmos.color = Color.green;
         Gizmos.DrawRay(transform.position, referenceUp * referenceVectorScale);
         Gizmos.color = Color.blue;
         Gizmos.DrawRay(transform.position, referenceForward * referenceVectorScale);
     }
 
     void DrawRotationAxis(Vector3 rotationAxis)
     {
         Gizmos.color = Color.yellow;
         Gizmos.DrawRay(transform.position, rotationAxis * referenceVectorScale);
     }
 }



Ok, so that was a lot of math! How do we use the above to solve the original problem statement: "Given the points of 2 hexes, find the rotation required to align them"?

For clarity, let's rename GetAxisAlignmentRotation and its parameters for your use-case -- we're not making any logic changes, just hopefully this helps make the function make more sense for working with aligning hexagons specifically:

OLD: Quaternion GetAxisAlignmentRotation(Vector3 localUp, Vector3 localForward, Vector3 worldUp, Vector3 worldForward)

NEW: Quaternion FindRotationToAlignHexes(Vector3 hex1Up, Vector3 hex1Forward, Vector3 hex2Up, Vector3 hex2Forward)

The function signature now indicates that if you know the up and forward vectors for both hexes, it will return the rotation needed to align them.

So the remaining problem is, how do we get the up and forward vectors for the hexes given only the points?

We have functions to find these, but the names may not be intuitive. Let's rename them to be more clear what they do for hexagons:

To find "up":

OLD: Vector3 CalculateNormal(Vector3[] corners)

NEW: Vector3 FindHexUp(Vector3[] corners)

And to find "forward":

OLD: Vector3 CalculateForward(Vector3[] corners)

NEW: Vector3 FindHexForward(Vector3[] corners)

With the functions renamed, the code to solve your problem should look something like this:

 // Given the following:
 // Vector3[] hex1Corners = [the vertices for hex1]
 // Vector3[] hex2Corners = [the vertices for hex2]
 
 // We want to find the rotation to align hex1 to hex2
 var hex1Up = FindHexUp(hex1Corners);
 var hex1Forward = FindHexForward(hex1Corners);
 var hex2Up = FindHexUp(hex2Corners);
 var hex2Forward = FindHexForward(hex2Corners);
 var alignmentRotation = GetAxisAlignmentRotation(hex1Up, hex1Forward, hex2Up, hex2Forward);

Hope this helps!


hex-demo.png (157.2 kB)
Comment
Add comment · Show 3 · 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 stadlernicolas26 · Jul 02, 2020 at 10:10 AM 0
Share

Thank you very much for your detailed explanation. But I am a bit confused. As an input theres the rotation of the hexagon needed, but I dont know that value. $$anonymous$$y problem is to find out how much i have to rotate a hexagon to fit another hexagon with unknown rotation, only calculated by the vertices of the two hexagons. $$anonymous$$aybe I missed something and if thats so feel free to correct me, but thank you for dealing with my problem

avatar image exploringunity stadlernicolas26 · Jul 02, 2020 at 09:10 PM 0
Share

The "INPUT/OUTPUT" stuff in the inspector is just for testing visually. I updated the answer, adding some extra info at the end that hopefully makes it more clear how to use the code to solve your problem. Let me know if there's still any confusion.

avatar image stadlernicolas26 exploringunity · Jul 04, 2020 at 12:29 PM 0
Share

But I get 0.x as a rotation. Is that supposed to be right?

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

194 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 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 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 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 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 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 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 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 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 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 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 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 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 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

Trying to get the angle of a camera object based on players forward, is not distance independent 0 Answers

Quick Angles Question 2 Answers

Vector3.SignedAngle wrong direction when crossing the 0 point 1 Answer

How Do I accurately rotate a player 180 degrees about the Z axis? 1 Answer

Change a property based on angle? 1 Answer


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