Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 11 Next capture
2021 2022 2023
1 capture
11 Jun 22 - 11 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
4
Question by Chris12345 · Jul 14, 2015 at 11:46 PM · c#unity 4.6

Round Procedural Mesh Corners? C#

Good Afternoon, I have a script to build a procedural 2d square mesh but cannot figure out how to round the corners with a variable slider to increases roundness of the square mesh. Please see image and code bellow.

alt text

Thanks Again for all your help :)

Current Code:

  using UnityEngine;
  using UnityEditor;
  using System.Collections;
  
  public class Generate : MonoBehaviour
  {
  
   private Mesh s;

  public int RoundEdges; // Rounds all edges //
  public int RoundTopLeft; // Rounds Top Left Edge //
  public int RoundTopRight; // Rounds Top Right Edge //
  public int RoundBottomLeft; //Rounds Bottom Left Edge //
  public int RoundBottomRight; //Rounds Bottom Right Edge //
  
   private Vector3[] vertices = {
       new Vector2(0,0),
       new Vector2(0,1),
       new Vector2(1,1),
       new Vector2(1,0)
   };
  
   private int[] triangles = {
       0,1,2,
       2,3,0
   };   
  
   public void Create()
   {
       s = new Mesh();
       GetComponent<MeshFilter>().sharedMesh = s;
       s.name = "S";
   }
  
   void Start()
   {
       Create();
   }
  void Update(){
  // Round Edges //
  s.vertices = vertices;
  s.triangles = triangles;
 }

 }


image.jpg (19.8 kB)
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

2 Replies

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

Answer by Bunny83 · Jul 30, 2015 at 03:40 AM

I usually don't create scripts for others here on UA since that's not what this site is good for. @fafase and @_Gkxd gave you more than enough information to implement it yourself. I just want to make it clear that this is an exception. I though that i could use something like that for myself the other day...

So i've just written a rounded quad generator and made almost everything adjustable. You can specify:

  • the size of the quad

  • If it's double sided or single sided. Single sided mesh will face the "-z-axis" so it's compatible with 2d.

  • If the script should generate UV coordinates.

  • How many vertices should be generated for one corner [2,16000]. If 2 is used you get a "beveled" corner.

  • the base radius of all corners. (*1)

  • each radius independently from the others.(*1)

  • if the mesh should be updated each frame (AutoUpdate). Keep in mind that it's quite demanding to recreate the mesh each frame, so you might want to turn it off and update the mesh when you changed something.

(*1) The base radius is added to the independent one for each edge. You can also specify negative values. The resulting value is clamped between [0,1]

 //RoundedQuadMesh.cs
 using UnityEngine;
 using System.Collections;
 
 public class RoundedQuadMesh : MonoBehaviour
 {
     public float RoundEdges = 0.5f;
     public float RoundTopLeft = 0.0f;
     public float RoundTopRight = 0.0f;
     public float RoundBottomLeft = 0.0f;
     public float RoundBottomRight = 0.0f;
     public float Size = 1f;
     public int CornerVertexCount = 8;
     public bool CreateUV = true;
     public bool DoubleSided = false;
     public bool AutoUpdate = true;
 
     private MeshFilter m_MeshFilter;
     private Mesh m_Mesh;
     private Vector3[] m_Vertices;
     private Vector3[] m_Normals;
     private Vector2[] m_UV;
     private int[] m_Triangles;
 
     void Start ()
     {
         m_MeshFilter = GetComponent<MeshFilter>();
         if (m_MeshFilter == null)
             m_MeshFilter = gameObject.AddComponent<MeshFilter>();
         if (GetComponent<MeshRenderer>() == null)
             gameObject.AddComponent<MeshRenderer>();
         m_Mesh = new Mesh();
         m_MeshFilter.sharedMesh = m_Mesh;
         UpdateMesh();
     }
 
     public Mesh UpdateMesh()
     {
         if (CornerVertexCount<2)
             CornerVertexCount = 2;
         int sides = DoubleSided ? 2 : 1;
         int vCount = CornerVertexCount * 4 * sides + sides;
         int triCount = (CornerVertexCount * 4) * sides;
         if (m_Vertices == null || m_Vertices.Length != vCount)
         {
             m_Vertices = new Vector3[vCount];
             m_Normals = new Vector3[vCount];
         }
         if (m_Triangles == null || m_Triangles.Length != triCount * 3)
             m_Triangles = new int[triCount * 3];
         if (CreateUV && (m_UV == null || m_UV.Length != vCount))
         { 
             m_UV = new Vector2[vCount];
         }
         float f = 1f / (CornerVertexCount-1);
         m_Vertices[0] = Vector3.zero;
         int count = CornerVertexCount * 4;
         if (CreateUV)
         {
             m_UV[0] = Vector2.one *0.5f;
             if (DoubleSided)
                 m_UV[count + 1] = m_UV[0];
         }
         
         for (int i = 0; i < CornerVertexCount; i++ )
         {
             float s = Mathf.Sin((float)i * Mathf.PI * 0.5f*f);
             float c = Mathf.Cos((float)i * Mathf.PI * 0.5f*f);
             float tl = Mathf.Clamp01(RoundTopLeft + RoundEdges);
             float tr = Mathf.Clamp01(RoundTopRight + RoundEdges);
             float bl = Mathf.Clamp01(RoundBottomLeft + RoundEdges);
             float br = Mathf.Clamp01(RoundBottomRight + RoundEdges);
             Vector2 v1 = new Vector3(-1f + tl - c * tl, 1 - tl + s * tl);
             Vector2 v2 = new Vector3(1f - tr + s * tr, 1f - tr + c * tr);
             Vector2 v3 = new Vector3(1f - br + c * br, -1f + br - s * br);
             Vector2 v4 = new Vector3(-1f + bl - s * bl, -1f + bl - c * bl);
 
             m_Vertices[1 + i] = v1 * Size;
             m_Vertices[1 + CornerVertexCount + i] = v2 * Size;
             m_Vertices[1 + CornerVertexCount * 2 + i] = v3 * Size;
             m_Vertices[1 + CornerVertexCount * 3 + i] = v4 * Size;
             if (CreateUV)
             {
                 m_UV[1 + i] = v1 * 0.5f + Vector2.one * 0.5f;
                 m_UV[1 + CornerVertexCount * 1 + i] = v2 * 0.5f + Vector2.one * 0.5f;
                 m_UV[1 + CornerVertexCount * 2 + i] = v3 * 0.5f + Vector2.one * 0.5f;
                 m_UV[1 + CornerVertexCount * 3 + i] = v4 * 0.5f + Vector2.one * 0.5f;
             }
             if (DoubleSided)
             {
                 // The backside vertices are in reverse order
                 m_Vertices[1 + CornerVertexCount * 7 + CornerVertexCount - i] = v1 * Size;
                 m_Vertices[1 + CornerVertexCount * 6 + CornerVertexCount - i] = v2 * Size;
                 m_Vertices[1 + CornerVertexCount * 5 + CornerVertexCount - i] = v3 * Size;
                 m_Vertices[1 + CornerVertexCount * 4 + CornerVertexCount - i] = v4 * Size;
                 if (CreateUV)
                 {
                     m_UV[1 + CornerVertexCount * 7 + CornerVertexCount - i] = v1 * 0.5f + Vector2.one * 0.5f;
                     m_UV[1 + CornerVertexCount * 6 + CornerVertexCount - i] = v2 * 0.5f + Vector2.one * 0.5f;
                     m_UV[1 + CornerVertexCount * 5 + CornerVertexCount - i] = v3 * 0.5f + Vector2.one * 0.5f;
                     m_UV[1 + CornerVertexCount * 4 + CornerVertexCount - i] = v4 * 0.5f + Vector2.one * 0.5f;
                 }
             }
         }
         for (int i = 0; i < count + 1;i++ )
         {
             m_Normals[i] = -Vector3.forward;
             if (DoubleSided)
                 m_Normals[count + 1 + i] = Vector3.forward;
         }
         
         for (int i = 0; i < count; i++)
         {
             m_Triangles[i*3    ] = 0;
             m_Triangles[i*3 + 1] = i + 1;
             m_Triangles[i*3 + 2] = i + 2;
             if (DoubleSided)
             {
                 m_Triangles[(count + i) * 3] = count+1;
                 m_Triangles[(count + i) * 3 + 1] = count+1 +i + 1;
                 m_Triangles[(count + i) * 3 + 2] = count+1 +i + 2;
             }
         }
         m_Triangles[count * 3 - 1] = 1;
         if (DoubleSided)
             m_Triangles[m_Triangles.Length - 1] = count + 1 + 1;
 
         m_Mesh.Clear();
         m_Mesh.vertices = m_Vertices;
         m_Mesh.normals = m_Normals;
         if (CreateUV)
             m_Mesh.uv = m_UV;
         m_Mesh.triangles = m_Triangles;
         
         return m_Mesh;
     }
 
     void Update ()
     {
         if (AutoUpdate)
             UpdateMesh();
     }
 }

edit
I created a modified version of the script (which you can find on my dropbox here)and added those features:

  • You can specify a "Rect" in local space to define the quad. So it isn't limited to squares anymore

  • The rounding feature can be toggled between percentage mode (the old one) and absolute mode. Note: In absolute mode it might still make the radius smaller when the over-all width (or height) is exceeded. However if the rect is large enough the radius of all edges should be constant even when you change the width / height. In percentage mode it always uses the smaller edge as reference. So the corners don't get a streched circle. They will always be a quarter circle.

  • "Size" has been replaced with "Scale" which simply scales the endresult around the origin just like Unity's scale would like but it scales the actual vertices in localspace.

  • Added a "FlipBackFaceUV" flag to flip the uv horizontally (u = 1f-u)

edit
If someone's interested in how it looks like, here's a Unity webplayer build

Comment
Add comment · Show 9 · 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 Chris12345 · Jul 30, 2015 at 01:22 PM 0
Share

Wow, thanks a lot I really appreciate this :), Checking it out now.

avatar image Bunny83 · Jul 30, 2015 at 03:36 PM 0
Share

Just found a little problem with the "absolute" mode ^^. The UV coordinates are acaled as well so a rect with size 2 will look like it has a tiling of 2. Well, that's the problem when you reuse values for multiple things ^^. I replaced the version in my dropbox with a fixed version ^^.

avatar image Chris12345 · Jul 30, 2015 at 04:50 PM 0
Share

Thanks Again, It works great :)

avatar image Chris12345 · Aug 20, 2015 at 02:00 AM 0
Share

How Can I add a outer boarder? I have tried to add more vertices but i am having problems.

avatar image crookookoo · Jan 28, 2018 at 06:02 PM 0
Share

@Bunny83 your modified script sounds great! Could you please reupload it here as a code block? The dropbox link is dead and everyone will happy to still access it in the future.

@Chris12345 if you still have the script, please share.

Thanks!

avatar image Bunny83 crookookoo · Jan 29, 2018 at 01:38 AM 0
Share

Of course I still have the script. However I'm not home for the next few days so I don't have access to my files and Dropbox account. You can blame Dropbox for removing the public folder support. If I'm back home I'll update the link. Unfortunate over the years I've posted literally hundreds of public folder links.

avatar image Bunny83 crookookoo · Feb 01, 2018 at 04:27 PM 1
Share

I just came back home ^^. I've updated the dropbox link.

Show more comments
avatar image
1

Answer by fafase · Jul 18, 2015 at 09:35 PM

Beziers or Catmull-Rom curve.

Here below is Catmull-Rom equation from https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline

 public static Vector2 CatmullRomTangent(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t) {
         return 0.5f * ((-p1 + p3) + 2f * (2f * p1 - 5f * p2 + 4f * p3 - p4) * t + 3f * (-p1 + 3f * p2 - 3f * p3 + p4) * Mathf.Pow(t, 2f));
 }

You can control the t value to make it smoother when the slider moves.

EDIT: So you have point on your object, for instance a triangle and you want to smooth the corners.

Your triangle has vertex array {A,B,C}. You start iterating with A and in this case you can use C as previous. If the curve is not closed then you use Vector2.zero. And you start iterating the ratio t. So consider you want 5 points between, you have t = 0, 0.25, 0.5, 0.75 ,1.0.

so you get:

  for(int t = 0; t <= 1.0f; t = t + precision)
     Vector2 position = CatmullRomTangent(C, A, B, C, t);

Then you move the content so that B - C is the middle part and iterate t again.

Your job is to get the position value to place a new vertex in the scene. precision is the value taken from the slider and the smaller it is, the more iteration you get and the more expensive it gets.

Comment
Add comment · Show 8 · 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 Chris12345 · Jul 18, 2015 at 09:43 PM 0
Share

Could you apply this to the code listed? Thanks for the response. It looks like I would have to set each vector to the according P1-P4.

avatar image Chris12345 · Jul 19, 2015 at 03:14 AM 0
Share

Can you explain more?

avatar image fafase · Jul 20, 2015 at 08:38 AM 0
Share

Unfortunately, I do not have time right now to do a detailed version so I updated the answer with a little bit more info. $$anonymous$$aybe someone will come with a ready to paste code version.

avatar image Chris12345 · Jul 20, 2015 at 02:09 PM 0
Share

Thanks for explaining, but I am still struggling, hopefully someone will help :)

avatar image _Gkxd · Jul 28, 2015 at 12:59 AM 1
Share

The particular operation that you're interested is called "fillet." Searching for that term might get you some results. I have also found a Stack Overflow answer explains the process pretty well. (This doesn't use splines.)

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

25 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

Related Questions

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

Retrieve Variable's [Tooltip()] Property From a Custom Inspector (C#) 2 Answers

Unity 4.6 Text Misbehaves During Gameplay 1 Answer

Scoring System Unity 6.4 C# 2D Game 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