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 kevtsubasa · Feb 11, 2015 at 06:19 PM · rotationmeshbatchinggeometry

How to achieve a rotation on "batch quads" ?

Hello everyone,

Let's start with a simple illustration:

alt text

I have two plans. The plane on the left is the "target". The right plane is going to translate and rotate during a time, t. After the animation, the right plane will have the same position∨ientation than the left one.

Here is the code :

 public class Test : MonoBehaviour 
 {
     public float TranslateSpeed = 2.0f;
     public float RotateSpeed = 3.0f;
 
     public Transform Target;
 
     private Transform objectTransform;
 
     protected virtual void Awake () 
     {
              this.objectTransform = this.transform;
     }
 
     
     protected virtual void Update () 
     {
         if (Time.time < 1.5f)
         {
             return;
         }
 
         if (this.Target == null || this.objectTransform == null)
         {
             return;
         }
 
         float translateStep = this.TranslateSpeed * Time.deltaTime;
         float rotateStep = this.RotateSpeed * Time.deltaTime;
 
         this.objectTransform.position = Vector3.MoveTowards(this.objectTransform.position, this.Target.position, translateStep);
         this.objectTransform.rotation = Quaternion.RotateTowards(this.objectTransform.rotation, this.Target.rotation, rotateStep);
     }
 }


It works perfectly with the built-in unity functions.

Now, I would like to achieve this effect on many (maybe hundred, maybe thousands) quads batched inside one Unity.Mesh. So I create all the necessary buffers (vertices, triangles, etc...) and in the Update function, I want to get the same behaviour for all my quads, ie translate and rotate them to a given position and direction.

For the translation it's quite easy, but for the rotation it's tricky :/ I need to handle each quad one by one, and as the geometry is batched in one mesh, i don't have access to an "independant Transform variable"...

I copy my code here:

 using UnityEngine;
 using System.Collections;
 
 /*   **** INFORMATIONS ***
 *
 *   The name "leave" refers to a simple quad.
 *   A PATCH contains leaves geometry.
 ***/
  
 public class LeavesPatch : MonoBehaviour {
     public int NumberOfLeaves = 10;
     public float LeaveSize = 0.1f;
     public float Radius = 2.0f; // Used to spread leaves position in a circle.
     public float AnimationLength = 3.0f;
     public float TranslationSpeed = 3.0f;
     public float RotationSpeed = 3.0f;
 
     public Transform TargetToReach;
     public Material LeaveMaterial;
 
     private const int IndicesPerQuad = 6;
 
     private Mesh patchMesh;
     private bool playAnimation = false;
 
     private Vector3[] updateVertices;
 
     protected virtual void Awake() {
         // Create buffers
         Vector3[] quadVertices = new Vector3[] { 
             new Vector3(-0.5f * this.LeaveSize, 0.0f, 0.5f * this.LeaveSize),
             new Vector3(0.5f * this.LeaveSize, 0.0f, 0.5f * this.LeaveSize),
             new Vector3(0.5f * this.LeaveSize, 0.0f, -0.5f * this.LeaveSize),
             new Vector3(-0.5f * this.LeaveSize, 0.0f, -0.5f * this.LeaveSize),
         };
 
         Vector3[] quadNormals = new Vector3[] {
             Vector3.up,
             Vector3.up,
             Vector3.up,
             Vector3.up
         };
 
         int[] quadIndices = new int[] {
             0, 1, 2,
             0, 2, 3
         };
 
         Vector2[] quadUV = new Vector2[] {
             new Vector2(0.0f, 0.0f),
             new Vector2(1.0f, 0.0f),
             new Vector2(1.0f, 1.0f),
             new Vector2(0.0f, 1.0f)
         };
 
         // Create patch and fill buffers.
         Vector3[] patchVertices = new Vector3[quadVertices.Length * this.NumberOfLeaves];
         Vector3[] patchNormals = new Vector3[quadNormals.Length * this.NumberOfLeaves];
         int[] patchIndices = new int[quadIndices.Length * this.NumberOfLeaves];
         Vector2[] patchUVs = new Vector2[quadUV.Length * this.NumberOfLeaves];
 
 
         for (int i = 0; i < this.NumberOfLeaves; ++i) {
             // Create vertices and random position in a circle (plan XZ).
             Vector3[] newVertices = new Vector3[quadVertices.Length];
             float randRadius = Random.Range(0.0f, this.Radius);
             float randRadian = Mathf.Deg2Rad * Random.Range(0.0f, 360.0f);
             Vector3 randCirclePos = new Vector3(
                                                 randRadius * Mathf.Cos(randRadian),
                                                 0.0f,
                                                 randRadius * Mathf.Sin(randRadian));
 
             for (int j = 0; j < quadVertices.Length; ++j) {
                 newVertices[j] = quadVertices[j] + randCirclePos;
             }
 
             // Create new array of indices.
             int[] newIndices = new int[IndicesPerQuad];
             for (int j = 0; j < IndicesPerQuad; ++j) {
                 newIndices[j] = quadIndices[j] + (i * 4);
             }
 
             System.Array.Copy(newVertices, 0, patchVertices, i * 4, 4);
             System.Array.Copy(quadNormals, 0, patchNormals, i * 4, 4);
             System.Array.Copy(newIndices, 0, patchIndices, i * IndicesPerQuad, IndicesPerQuad);
             System.Array.ConstrainedCopy(quadUV, 0, patchUVs, i * 4, 4);
         }
 
         // Create the Patch GameObject and we add essentials Component.
         this.patch = new GameObject("Patch");
         MeshRenderer mr = this.patch.AddComponent<MeshRenderer>();
         mr.material = this.LeaveMaterial;
         MeshFilter patchMeshFilter = this.patch.AddComponent<MeshFilter>();
 
         patchMeshFilter.mesh.MarkDynamic();
         patchMeshFilter.mesh.vertices = patchVertices;
         patchMeshFilter.mesh.normals = patchNormals;
         patchMeshFilter.mesh.triangles = patchIndices;
         patchMeshFilter.mesh.uv = patchUVs;
         patchMeshFilter.mesh.Optimize();
 
         this.patchMesh = patchMeshFilter.mesh;
     }
 
 
 
     protected virtual void Update() {
         // Press SPACE to launch the animation.
         if (Input.GetKeyDown(KeyCode.Space)) {
             this.playAnimation = !this.playAnimation;
 
 
             if (this.playAnimation)
                 Debug.Log("PLAY");
         }
 
         if (!this.playAnimation) {
             return;
         }
 
 
         this.updateVertices = this.patchMesh.vertices;
 
 
         // I work in the patch space.
         Vector3 targetPositionInPatchLocalSpace = this.patch.transform.worldToLocalMatrix.MultiplyPoint3x4(this.TargetToReach.position);
         Vector3 targetDirectionInPatchLocalSpace = this.patch.transform.InverseTransformDirection(this.TargetToReach.up);
 
         Vector3 currentPatchNormal = Vector3.zero;
 
         float translationStep = this.TranslationSpeed * Time.deltaTime;
         float rotationStep = this.RotationSpeed * Time.deltaTime;
 
         for (int i = 0; i < this.patchMesh.vertexCount; ++i) {
 
             // MOVE TOWARDS  Built-in unity function
             Vector3 newPos = Vector3.MoveTowards(this.updateVertices[i], targetPositionInPatchLocalSpace, translationStep);
 
 
             // ROTATE TOWARDS
             // I only compute the normal of the quad only one time per quad.
             if ((i % 4) == 0) {
                 Vector3 p0 = (this.updateVertices[i + 3] - this.updateVertices[i]);
                 Vector3 p1 = (this.updateVertices[i + 1] - this.updateVertices[i]);
 
                 currentPatchNormal = Vector3.Cross(p0, p1).normalized;
 
                 // Debug : Draw Normal.
                 Vector3 startPoint = this.transform.TransformPoint((this.updateVertices[i] + this.updateVertices[i + 1] + this.updateVertices[i + 2]) / 3.0f);
                 Vector3 worldSpaceNormal = this.transform.TransformDirection(currentPatchNormal);
 
                 Debug.DrawRay(startPoint, worldSpaceNormal, Color.red, float.MaxValue, true);
             }
 
             // TODO : I thought it would worked...
             Vector3 newDir = Vector3.RotateTowards(currentPatchNormal, targetDirectionInPatchLocalSpace, rotationStep, 0.0f);
             Quaternion currentRotation = Quaternion.LookRotation(newDir);
 
             //Matrix4x4 m = Matrix4x4.TRS(newPos - this.updateVertices[i], Quaternion.identity, Vector3.one); // This line works, only translation !
             Matrix4x4 m = Matrix4x4.TRS(newPos - this.updateVertices[i], currentRotation, Vector3.one);  // and this line doesn't work ...
 
             Vector3 pt = m.MultiplyPoint3x4(this.updateVertices[i]);
             this.updateVertices[i] = pt;
         }
 
         this.patchMesh.vertices = this.updateVertices;
         this.patchMesh.RecalculateNormals();
         this.patchMesh.RecalculateBounds();
     }
 }


The quads just turn themselves and with the Debug.Draw(normals) I get a nice effect :p

alt text

I really would appreciate your mathematics tricks ;)

Thanks in advance !

C.Tsubasa

problem.jpg (150.4 kB)
planes.jpg (186.8 kB)
Comment
Add comment · Show 5
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 VesuvianPrime · Feb 11, 2015 at 06:26 PM 0
Share

I'm having trouble seeing exactly what the problem is. Perhaps a video would help.

I'm wondering if your line:

 Quaternion currentRotation = Quaternion.LookRotation(newDir);

Should be:

 Quaternion currentRotation = Quaternion.LookRotation(newDir, transform.up);
avatar image kevtsubasa · Feb 12, 2015 at 02:59 AM 0
Share

Look at my loop line 48. I handle my vertices independently of each other. So I cannot use any transform as you suggest in your answer

 Quaternion currentRotation = Quaternion.LookRotation(newDir, transform.up);

I'm going to update a video asap !

avatar image Baste · Feb 12, 2015 at 10:27 AM 0
Share

I took the liberty of formatting your code a bit - the array initializations in awake required a lot of horizontal scrolling.

To get the rotation going, shouldn't it be enough to just move the corners of each quad in the mesh? The tris are only based on the corners, so you shouldn't actually have to rotate anything.

avatar image kevtsubasa · Feb 13, 2015 at 03:29 PM 0
Share

Baste, you're right !! I didn't think about it :)

""To get the rotation going, shouldn't it be enough to just move the corners of each quad in the mesh? The tris are only based on the corners, so you shouldn't actually have to rotate anything." -> Thank you ;

But ok it will work for my quads, but if I handle a plane with hole(s) inside ? How I can manage this ? I forgot my basics mathematics knowledge :/

avatar image Baste · Feb 13, 2015 at 04:06 PM 0
Share

Every mesh is based on the same two structures - the corner points, and the triangles formed from those corners. If it works with a quad, it should definitely work with a plane.

0 Replies

· Add your reply
  • Sort: 

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

4 People are following this question.

avatar image avatar image avatar image avatar image

Related Questions

Use Unity's transform API to manipulate points? 0 Answers

Change Pivot Point- Maya 3 Answers

How to find the closest 4 verts/corners ( along with their orientation ) of a rectangular object in relationship with another object? 1 Answer

How to find the lookat Position of this Mesh Collider? 1 Answer

3rd Person Camera Geometry Navigation 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