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 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
Add comment · 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

· Add your reply
  • Sort: 
avatar image
1

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
Add comment · 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 $$anonymous$$eshFilters' 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 ins$$anonymous$$d of in-game. :/

In-editor, $$anonymous$$eshFilter.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. Ins$$anonymous$$d 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 $$anonymous$$eshFilter.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: ins$$anonymous$$d 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
0

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

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

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

Updating UV in imported mesh without having to re-material 0 Answers

Combine Mesh but Keep UV Offset & Scale 0 Answers

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

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