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 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. This 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

Here's a superb asset, free, that does this ...

http://wiki.unity3d.com/index.php?title=CreatePlane

I love that script - it's priceless. The example code may help.

the specific answer to your questions is just set the UV like that.

Regarding your specific question:

Here's my classic answer on the topic :)

http://answers.unity3d.com/questions/293607/tiling-uv-mapping.html

note the hand drawn diagrams. If you are gonna weave mesh

YOU $$anonymous$$UST DRAW DIAGRA$$anonymous$$S ON PAPER !!!!

I hope it helps. Be sure to up-thumb my other famous answer ok :)

avatar image Huacanacha · May 22, 2014 at 09:55 PM 0
Share

@Fattie Thank you for the link to that CreatePlane script! I modified it to support two sided planes (with identically mapped UV's on both sides) which can be useful for collision detection or rendering very thin flat objects.

I can't update the community Wiki (yet) but perhaps you can on my behalf? Code is in my answer below as it's too big for a comment.

avatar image Fattie · May 24, 2014 at 06:37 AM 0
Share

Right, it's a great script. I don't bother with wikis but I'm certain someone will take care of that. Cheers !!

avatar image Huacanacha · May 24, 2014 at 07:24 AM 0
Share

They gave me access so it's updated now, for all to benefit ;)

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 thin 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. This is what a modelling program does whenever you make a seam (invisibly splits those verts.)

The other is to use the graphics-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. This 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

i guess it's all totally flat, so the normals don't matter (I suppose - they are all just "up")

with vert sharing, I'd suggest he simply not share any verts at all. theres never any need to. performance/size is irrelevant and it's always easier to make mesh when you simply don't share verts ! the two arrays just line up 1:1, super-simple.

also you can just let the uv value increase to 20 or whatever, it will do it, I suppose .. NP

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

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

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

Distortion of Texture from some Angles 0 Answers

A way to "fold" a texture on a mesh? 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