CROSS POST FROM UNITY ANSWERS. (I appear to have stumped them )
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 (I grant no warranties/ assume no liabilities, etc.)
#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();
}
Don’t use sharedMesh. It’s shared. It’s in the name.
To prevent leaking, you’ll have to do more work. So the first time you edit it, you’ll need to use the regular mesh variable. After that, use sharedMesh to prevent leaks.
I know that sharedMesh is shared (thankfully, I can read) and I tried using MeshFilter.mesh initially, which almost worked except that I couldn’t save prefabs that kept the settings in the script. If you don’t mind, would you mind elaborating a bit more on your method?
Instead of changing the shared mesh, you have to create a new mesh and say “Hey, selected game object? You use THIS mesh as your sharedmesh now, please.”
I copied your function into my code and it works for my mesh filter with no changes :?
if ( GUILayout.Button("Make Attach") ) {
if ( !sgo.GetComponent.<MeshFilter>() ) {
var mf : MeshFilter = sgo.AddComponent(MeshFilter);
}
mf = sgo.GetComponent(MeshFilter);
mf.sharedMesh = CreateNewMesh();
}
I wouldn’t think the language would matter - I’m using unityscript but sharedMesh should behave the same for both… right?
You’re using the .mesh property in CreateNewMesh - that threw a leak exception for me in the editor. Perhaps C# ‘crashes’ on that exception? Try .sharedMesh instead, maybe that’ll do it.
On a side note, I’ve got the script(s) working with the following; it even can animate uvs! Only down side is that annoying mesh leak error. Anyone know how to manually catch/clean leaked meshes?
(Feel free to use, I assume no liability, yada yada):
#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 Start () {
rowNum = Mathf.Clamp (rowNum,1,15);
columnNum = Mathf.Clamp (columnNum,1,15);
Offset();
if(isAnimated){
Animate();
}
}
function Update () {
if(!Application.isPlaying||isAnimated)
Offset();
}