• 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 leedotjohnson · Apr 10, 2013 at 04:23 PM · texturemeshuvvector2mapping

Procedural Uniform UVs On a Plane

I have a script that procedurally generates a plane (rectangular) via width and height input. The plane is composed of a lattice across a grid of 1.0f spacing. For example, a plane of 4x5 has 20 quads, or 40 triangles. I understand how UVs work but I'm having some trouble 'building' the UV Vector2's procedurally. Basically, I want to have a UV mapping: 0,0 / 1,0 / 0,1 / 1,1 for each quad on the mesh. T$$anonymous$$s is for an experiment in dynamic UV mapping so simply setting a UV for the whole plane and tiling the texture does not apply here. Many thanks in advance.

Comment
Add comment · Show 4
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 Fattie · Apr 10, 2013 at 04:29 PM 0
Share
avatar image Huacanacha · May 22, 2014 at 09:55 PM 0
Share
avatar image Fattie · May 24, 2014 at 06:37 AM 0
Share
avatar image Huacanacha · May 24, 2014 at 07:24 AM 0
Share

2 Replies

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

Answer by Huacanacha · May 22, 2014 at 09:54 PM

Here's a modified version of the CreatePlane script (linked by Fattie in a comment above) that supports two-sided planes/quads. It has correctly reversed UV mapping and minimal vertices (4 certs, 4 tris for a two sided quad). Very useful for collision detection and t$$anonymous$$n transparent objects with transparency (or not).

Original source (now updated to support two-sided planes): http://wiki.unity3d.com/index.php?title=CreatePlane

Usage: add script to an Editor folder in your project, then select Game Object -> Create Other -> Custom Plane...

 using UnityEngine;
 using UnityEditor;
 using System.Collections;
 
 
 public class CreatePlane : ScriptableWizard
 {
     
     public enum Orientation
     {
         Horizontal,
         Vertical
     }
     
     public enum AnchorPoint
     {
         TopLeft,
         TopHalf,
         TopRight,
         RightHalf,
         BottomRight,
         BottomHalf,
         BottomLeft,
         LeftHalf,
         Center
     }
     
     public int widthSegments = 1;
     public int lengthSegments = 1;
     public float width = 1.0f;
     public float length = 1.0f;
     public Orientation orientation = Orientation.Horizontal;
     public AnchorPoint anchor = AnchorPoint.Center;
     public bool addCollider = false;
     public bool createAtOrigin = true;
     public bool twoSided = false;
     public string optionalName;
     
     static Camera cam;
     static Camera lastUsedCam;
     
     
     [MenuItem("GameObject/Create Other/Custom Plane...")]
     static void CreateWizard()
     {
         cam = Camera.current;
         // Hack because camera.current doesn't return editor camera if scene view doesn't have focus
         if (!cam)
             cam = lastUsedCam;
         else
             lastUsedCam = cam;
         ScriptableWizard.DisplayWizard("Create Plane",typeof(CreatePlane));
     }
     
     
     void OnWizardUpdate()
     {
         widthSegments = Mathf.Clamp(widthSegments, 1, 254);
         lengthSegments = Mathf.Clamp(lengthSegments, 1, 254);
     }
     
     
     void OnWizardCreate()
     {
         GameObject plane = new GameObject();
         
         if (!string.IsNullOrEmpty(optionalName))
             plane.name = optionalName;
         else
             plane.name = "Plane";
         
         if (!createAtOrigin && cam)
             plane.transform.position = cam.transform.position + cam.transform.forward*5.0f;
         else
             plane.transform.position = Vector3.zero;
         
         Vector2 anchorOffset;
         string anchorId;
         switch (anchor)
         {
         case AnchorPoint.TopLeft:
             anchorOffset = new Vector2(-width/2.0f,length/2.0f);
             anchorId = "TL";
             break;
         case AnchorPoint.TopHalf:
             anchorOffset = new Vector2(0.0f,length/2.0f);
             anchorId = "TH";
             break;
         case AnchorPoint.TopRight:
             anchorOffset = new Vector2(width/2.0f,length/2.0f);
             anchorId = "TR";
             break;
         case AnchorPoint.RightHalf:
             anchorOffset = new Vector2(width/2.0f,0.0f);
             anchorId = "RH";
             break;
         case AnchorPoint.BottomRight:
             anchorOffset = new Vector2(width/2.0f,-length/2.0f);
             anchorId = "BR";
             break;
         case AnchorPoint.BottomHalf:
             anchorOffset = new Vector2(0.0f,-length/2.0f);
             anchorId = "BH";
             break;
         case AnchorPoint.BottomLeft:
             anchorOffset = new Vector2(-width/2.0f,-length/2.0f);
             anchorId = "BL";
             break;            
         case AnchorPoint.LeftHalf:
             anchorOffset = new Vector2(-width/2.0f,0.0f);
             anchorId = "LH";
             break;            
         case AnchorPoint.Center:
         default:
             anchorOffset = Vector2.zero;
             anchorId = "C";
             break;
         }
         
         MeshFilter meshFilter = (MeshFilter)plane.AddComponent(typeof(MeshFilter));
         plane.AddComponent(typeof(MeshRenderer));
         
         string planeAssetName = plane.name + widthSegments + "x" + lengthSegments + "W" + width + "L" + length + (orientation == Orientation.Horizontal? "H" : "V") + anchorId + ".asset";
         Mesh m = (Mesh)AssetDatabase.LoadAssetAtPath("Assets/Editor/" + planeAssetName,typeof(Mesh));
         
         if (m == null)
         {
             m = new Mesh();
             m.name = plane.name;
             
             int hCount2 = widthSegments+1;
             int vCount2 = lengthSegments+1;
             int numTriangleVertices = widthSegments * lengthSegments * 6;
             if (twoSided) {
                 numTriangleVertices *= 2;
             }
             int numVertices = hCount2 * vCount2;
             
             Vector3[] vertices = new Vector3[numVertices];
             Vector2[] uvs = new Vector2[numVertices];
             int[] triangleVertices = new int[numTriangleVertices];
             
             int index = 0;
             float uvFactorX = 1.0f/widthSegments;
             float uvFactorY = 1.0f/lengthSegments;
             float scaleX = width/widthSegments;
             float scaleY = length/lengthSegments;
             for (float y = 0.0f; y < vCount2; y++)
             {
                 for (float x = 0.0f; x < hCount2; x++)
                 {
                     if (orientation == Orientation.Horizontal)
                     {
                         vertices[index] = new Vector3(x*scaleX - width/2f - anchorOffset.x, 0.0f, y*scaleY - length/2f - anchorOffset.y);
                     }
                     else
                     {
                         vertices[index] = new Vector3(x*scaleX - width/2f - anchorOffset.x, y*scaleY - length/2f - anchorOffset.y, 0.0f);
                     }
                     uvs[index++] = new Vector2(x*uvFactorX, y*uvFactorY);
                 }
             }
             
             index = 0;
             for (int y = 0; y < lengthSegments; y++)
             {
                 for (int x = 0; x < widthSegments; x++)
                 {
                     triangleVertices[index]   = (y     * hCount2) + x;
                     triangleVertices[index+1] = ((y+1) * hCount2) + x;
                     triangleVertices[index+2] = (y     * hCount2) + x + 1;
                     
                     triangleVertices[index+3] = ((y+1) * hCount2) + x;
                     triangleVertices[index+4] = ((y+1) * hCount2) + x + 1;
                     triangleVertices[index+5] = (y     * hCount2) + x + 1;
                     index += 6;
                 }
                 if (twoSided) {
                     // Same tri vertices, different order so normals are reversed
                     for (int x = 0; x < widthSegments; x++)
                     {
                         triangleVertices[index]   = (y     * hCount2) + x;
                         triangleVertices[index+1] = (y     * hCount2) + x + 1;
                         triangleVertices[index+2] = ((y+1) * hCount2) + x;
                         
                         triangleVertices[index+3] = ((y+1) * hCount2) + x;
                         triangleVertices[index+4] = (y     * hCount2) + x + 1;
                         triangleVertices[index+5] = ((y+1) * hCount2) + x + 1;
                         index += 6;
                     }
                 }
             }
             
             m.vertices = vertices;
             m.uv = uvs;
             m.triangles = triangleVertices;
             m.RecalculateNormals();
             
             AssetDatabase.CreateAsset(m, "Assets/Editor/" + planeAssetName);
             AssetDatabase.SaveAssets();
         }
         
         meshFilter.sharedMesh = m;
         m.RecalculateBounds();
         
         if (addCollider)
             plane.AddComponent(typeof(BoxCollider));
         
         Selection.activeObject = plane;
     }
 }
Comment
Add comment · 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
0

Answer by Owen-Reynolds · Apr 10, 2013 at 05:14 PM

You didn't say what part you were having touble with, but...

"for each QUAD on the mesh": the trick is the verts have UVs -- faces and quads don't, they guess them from surrounding verts. Two side-by-side quads normally share the middle two verts, so the bottom middle vert can't have (1,0) for the left quad and also (0,0) for the right quad.

One solution is not to share verts. T$$anonymous$$s is what a modelling program does whenever you make a seam (invisibly splits those verts.)

The other is to use the grap$$anonymous$$cs-card's built-in love of UV-tiling. Set x's in the "two adjacent quads" example as 0,1,2. The two quads still share that x=1 middle vert. But quad #2 shows a full tile, from 1 to 2. T$$anonymous$$s is what setting tiling secretly does.

But, if you wanted each quad to show 3/4ths of the image, it can't be done w/o splitting verts (well, unless you want x=0, 0.75, 0, 0.75 for alternating reverse directions.)

Comment
Add comment · Show 1 · 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 Fattie · Apr 10, 2013 at 05:22 PM 0
Share

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

13 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

Related Questions

Assigning UV Map to model at runtime 0 Answers

using script to fill the uv array 0 Answers

Mesh building changes in Unity 3.5.6 0 Answers

Split a mesh while using same UVs and texture position. 0 Answers

Distortion of Texture from some Angles 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