• 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
Question by theRaddRedd · Nov 20, 2012 at 04:07 AM · editormeshuvoffsetatlas

Moving Mesh Instance UVs in Editor? (code provided)

Hey,

So I made this script that edits the UV coordinates of a model to slide it along a texture atlas for a semi 2D game. This function in itself works, but in the editor, I used MeshFilter.sharedMesh (like the docs said to) to prevent leaking; as an unintended side-effect, all meshes in the scene with this script change their uvs to the selected coords in the script since they all share a model. I don't want that to happen because I can't tell what type of sprite is where without running the game.

TL;DR: How can I make this script ONLY affect the mesh it's attached to?

*feel free to use this if you like

     #pragma strict
     @script ExecuteInEditMode()
     
     var myMesh:MeshFilter;
         var myTex:Texture2D;
     
     var uvs:Vector2[] =new Vector2[4];
     
     //Use these like coordinates to access the UVs. 
     //These are controlled via editor script
     var rowNum:int = 0; //On which row is the sprite located?
     var columnNum:int = 0;//In which column is the sprite located;
     var isAnimated:boolean;
         var framerate:int = 10;
         var animCoords : Vector2[] = new Vector2[10];    
         
     private var padding:float=0.00390625;//Whatever padding space you use between sprites
     private var width:float = 0.0625;//either direction, because I only use square textures.
     
     private var _myMesh:Mesh;
         
     function getObjectMesh (){
             var mf:MeshFilter= GetComponent(MeshFilter);
             var mesh:Mesh;
             if (Application.isEditor){
                 mesh=mf.sharedMesh;
             } else {
                 mesh=mf.mesh;    
             }
             return mesh;
     }
         
     function Offset(){
             //Get the current mesh to edit 
         myMesh=GetComponent(MeshFilter);
         _myMesh = myMesh.sharedMesh;
         
         var mesh:Mesh = getObjectMesh();
         
         //Current texture, in case you need it;
             myTex =renderer.sharedMaterial.mainTexture;//don't want to generate an instance
         
         //Assign uvs, maintain square aspect ratio
             //bottom left
         uvs[0] = Vector2(/*x value*/    (padding*(columnNum))+(((columnNum)-1)*width),
             /*y value*/     (1-(  (padding*(rowNum))+ (width*(rowNum-1)))  ));
             
             //bottom right
         uvs[1] = Vector2(uvs[0].x+width, uvs[0].y);
         
             //top left
         uvs[2] = Vector2(uvs[1].x,1-(    (padding*(rowNum)) + (width*(rowNum)) )  );
         
             //top right. 
         uvs[3] = Vector2(uvs[0].x, uvs[2].y); // pretty easy, huh?
         
         mesh.uv = uvs;
         
         return;
     }
         
     function Start () {
             rowNum = Mathf.Clamp (rowNum,1,15);
             columnNum = Mathf.Clamp (columnNum,1,15);
             Offset();
     }
     
     function Update () {
         getObjectMesh ();
         
         if(!Application.isPlaying)
             Offset();
     }
Comment

People who like this

0 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 theRaddRedd · Nov 23, 2012 at 03:08 PM 0
Share

lol, why are my problems always too hard to solve...

3 Replies

  • Sort: 
avatar image

Answer by invicticide · Nov 30, 2012 at 02:25 AM

You have to use MeshFilter.mesh for this, as opposed to MeshFilter.sharedMesh. It does mean you'll have many instances of the mesh, but when the mesh is just a quad that cost isn't prohibitive.

Comment
karl_

People who like this

1 Show 2 · 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 theRaddRedd · Nov 30, 2012 at 02:04 PM 0
Share

Thanks for the reply! I actually tried that, but I couldn't make prefabs of the result because all of the MeshFilters' mesh variables were assigned to an in-scene clone :\ Is there any way around that?

avatar image invicticide · Dec 02, 2012 at 08:54 PM 0
Share

Oh, somehow I missed the part where this was happening in-editor instead of in-game. :/

In-editor, MeshFilter.mesh will cause leakage and other problems, as you've correctly noted. If you want a bunch of prefabs that are each the same quad with different UVs, then unfortunately the only way I know to handle that is to have each prefab actually reference a completely unique mesh asset.

For example, say you've got a texture atlas with four sprites in it: A, B, C, and D. Instead of having a single quad.mb mesh and modifying the UVs programmatically, you'd need to have four separate meshes: a.mb, b.mb, c.mb, and d.mb. Each mesh is the same quad geometry but different UVs, and you've setup those UVs in your modeling package, not in Unity.

It's kind of a sucky workflow when all you're trying to do is have a sprite atlas, but I haven't yet found a better way to do it.

As a sidebar: in my game "Fail-Deadly" I set all my UVs at runtime, not in-editor. By doing it at runtime I was able to set the UVs programmatically, using MeshFilter.mesh, and not have to worry about editor leakage. Those auto-instanced meshes went away when the game was shutdown, but that's okay in this case because they only needed to exist during the game session anyway. The tradeoff for this easy implementation is that I can't view my sprites in-editor using their correct UVs: instead I see a quad with the entire sprite atlas on it. Fortunately for that game that's okay, because I didn't need to lay out levels or anything that required viewing the assets in the editor: everything is procedurally laid out at runtime. This probably isn't at all equivalent to your case, but it might lend some useful context to my previous answer. ;)

avatar image

Answer by Bunny83 · Dec 02, 2012 at 10:02 PM

Like invicticide said you have to use individual assets. Everything at edit time has to be an asset, otherwise it's lost when you reload Unity / open another scene / ...

You can use the AssetDatabase to save a clone of your mesh as new asset. However it's up to you how you trigger the cloning & saving process since it only has to be done once. That's usually a good example for an EditorWindow or wizard.

However, beside modifying the mesh, wouldn't be enough in your case to just adjust the Materials uv-offset and scaling?

Comment

People who like this

0 Show 0 · 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

Answer by theRaddRedd · Dec 03, 2012 at 03:23 PM

Appreciate all the answers guys.

I scripted a pretty good solution to this over the past couple of days. Feel free to use/modify (I grant no warranties/assume no liabilities/etc.)

WHAT IT DOES:

-Slide quad uvs in the editor along an atlas

-Linearly Animate uv placements via an array of Row/column pairs

-Batched Draw Calls (for the most part)

-You can remove when done sliding, and changes hold.

-Prefab-able!

KNOWN PROBLEMS:

-QUADS ONLY. I hard-coded the the uv sliding to work with vertex indexes, so you may need to tweak the vertex numbers in the script.

  • used this on a 15x15 sprite atlas on a 256 X 256 image, so you'll have to adjust rowPadding etc. for your needs

  • used .mesh for this, so meshes DO leak. Sorry, no better way it seems :\ Since you'll be using quads, though, this isn't that bad a problem :)

PoorMan's SpriteManager:

 #pragma strict
 @script ExecuteInEditMode()
 
 var myMesh:MeshFilter;
     var myTex:Texture2D;
 
 var uvs:Vector2[] =new Vector2[4];
 
 //Use these like coordinates to access the UVs. 
 //These are controlled via editor script
 var rowNum:int = 0; //On which row is the sprite located?
 var columnNum:int = 0;//In which column is the sprite located;
 var isAnimated:boolean;
     var framerate:int = 10;
     var animCoords : Vector2[] = new Vector2[10];    
     
 private var padding:float=0.00390625;//Whatever padding space you use between sprites
 private var width:float = 0.0625;//either direction, because I only use square textures.
     
 
     var index:int = 0;
     var waitTime:float = 0.01;
 function Animate():IEnumerator{
     rowNum=animCoords[index].x;
     columnNum =animCoords[index].y;
     
     //ready next frame
     if(index<(animCoords.length-1))
         index++;
     else{
         index = 0;
     }
     
     yield WaitForSeconds(waitTime);
     Animate();
     return;
 }
     
 function Offset(){
         //Get the current mesh to edit 
     myMesh=gameObject.GetComponent(MeshFilter);    
 
 
     
     //var mesh:Mesh = getObjectMesh();
     
     //Current texture, in case you need it;
         myTex =renderer.sharedMaterial.mainTexture;//don't want to generate an instance
     
     //Assign uvs, maintain square aspect ratio
         //bottom left
     uvs[0] = Vector2(/*x value*/    (padding*(columnNum))+(((columnNum)-1)*width),
         /*y value*/     (1-(  (padding*(rowNum))+ (width*(rowNum-1)))  ));
         
         //bottom right
     uvs[1] = Vector2(uvs[0].x+width, uvs[0].y);
     
         //top left
     uvs[2] = Vector2(uvs[1].x,1-(    (padding*(rowNum)) + (width*(rowNum)) )  );
     
         //top right. 
     uvs[3] = Vector2(uvs[0].x, uvs[2].y); // pretty easy, huh?
     
     myMesh.mesh.uv = uvs;
     return;
 }
     
 function CreateNewMesh(){
         var newMesh:Mesh;
         var temp:GameObject = (Instantiate(Resources.Load("Prefabs/Blocks/basePlane"))as GameObject);
         var tempF:MeshFilter = temp.GetComponent(MeshFilter);
         
         newMesh = tempF.sharedMesh;    
         
         DestroyImmediate(temp);
         DestroyImmediate(tempF);
         
         return newMesh;
 }    
 
 function Start () {
         if(!Application.isPlaying)
             myMesh.mesh = CreateNewMesh();
         
         rowNum = Mathf.Clamp (rowNum,1,15);
         columnNum = Mathf.Clamp (columnNum,1,15);
         Offset();
         if(isAnimated){
             Animate();
         }
 }
 
 function Update () {
     if(!Application.isPlaying||isAnimated)
         Offset();
 }




Comment

People who like this

0 Show 0 · 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

Unity Answers is in Read-Only mode

Unity Answers content will be migrated to a new Community platform and we are aiming to launch a public beta by June 9. Please note, Unity Answers is now in read-only so we can prepare for the final data migration.

For more information and updates, please read our full announcement thread in the Unity Forum.

Follow this Question

Answers Answers and Comments

12 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

Related Questions

Mesh UVs won't change positions 1 Answer

How to set up UV for lightmaps for generated meshes? 4 Answers

Combine Mesh but Keep UV Offset & Scale 0 Answers

SkinnedMeshRenderer offset UVs to match texture atlas? 1 Answer

Automatic mesh combine and texture atlasing 4 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