Autogenerating UV maps for "world space" texturing

 
Post new topic   Reply to topic    Unity Community Index // Scripting
View previous topic :: View next topic  
Author Message
robur



Joined: 13 Feb 2008
Posts: 346
Location: North Idaho

PostPosted: Sat Aug 01, 2009 2:56 am    Post subject: Autogenerating UV maps for "world space" texturing Reply with quote
Hypothetical Example:

1) I create a castle out of block prefabs (each of which has it's own custom scale in my castle design).
2) I assign a cool material to those prefabs.
3) I am disappointed to see that my castle looks terrible, as each block's texture scale is dependent on the size of the block.

Ideal example:

3) I run a script to fix the material scaling on each of my blocks, and my castle looks great!


Unfortunately, I can't figure out how to go about the script. Mike_Mac suggested I alter the UVs of my box's meshes, but as far as I can tell, UVs are just for material offsets and not for material scaling.

Can someone point me in the right direction?

Thanks!

-Aubrey

_________________
Aubrey Falconer ~ of ATI Design
Mars Explorer FTW!


Last edited by robur on Sun Aug 02, 2009 12:45 am; edited 2 times in total
Back to top
View user's profile Send private message Visit poster's website
Eric5h5



Joined: 19 Jul 2006
Posts: 10865

PostPosted: Sat Aug 01, 2009 3:24 am    Post subject: Re: Fixing texture scale through scripting Reply with quote
Sure they're for scaling. If the x and y UVs on a face, for example, go from 0 to 2, the texture would be twice as small in each direction compared to if they went from 0 to 1 (and repeated twice instead of once).

--Eric
Back to top
View user's profile Send private message Visit poster's website
robur



Joined: 13 Feb 2008
Posts: 346
Location: North Idaho

PostPosted: Sat Aug 01, 2009 3:38 am    Post subject: Reply with quote
Great!

This should work then.

I don't quite understand how the offset is specified, though. What variable controls the starting position? Do textures start at UV and end at UV2?
If only the docs were just a little more verbose... Smile

_________________
Aubrey Falconer ~ of ATI Design
Mars Explorer FTW!
Back to top
View user's profile Send private message Visit poster's website
Eric5h5



Joined: 19 Jul 2006
Posts: 10865

PostPosted: Sat Aug 01, 2009 4:00 am    Post subject: Reply with quote
I'd suggest looking up some tutorials on UV mapping.

--Eric
Back to top
View user's profile Send private message Visit poster's website
robur



Joined: 13 Feb 2008
Posts: 346
Location: North Idaho

PostPosted: Sat Aug 01, 2009 5:00 am    Post subject: Reply with quote
I can access only 1 Vector2 (named UV), containing two float values - and I need to specify a texture offset and scale in two directions, which I can't visualize how to express in any less than 4 float values. Where are the extra two floats specified?

I have read many tutorials on UV mapping, but what I need to know is nothing more than where I input the extra information into Unity's mesh object.

Thanks,

-Aubrey

_________________
Aubrey Falconer ~ of ATI Design
Mars Explorer FTW!
Back to top
View user's profile Send private message Visit poster's website
robur



Joined: 13 Feb 2008
Posts: 346
Location: North Idaho

PostPosted: Sat Aug 01, 2009 6:45 pm    Post subject: Reply with quote
OH! Each vertex in each triangle has it's own UV Embarassed

If I can figure out how to write this script, I will definitely share it on the Wiki!

_________________
Aubrey Falconer ~ of ATI Design
Mars Explorer FTW!
Back to top
View user's profile Send private message Visit poster's website
robur



Joined: 13 Feb 2008
Posts: 346
Location: North Idaho

PostPosted: Sat Aug 01, 2009 9:28 pm    Post subject: Reply with quote
I think I am close, but this script isn't quite working:

Code:
mesh = ObjectToAlter.GetComponent(MeshFilter).mesh;
var uvs = new Vector2[mesh.vertices.Length];
for (var i=0;i<uvs.Length;i++) {
   var uv : Vector3 = Vector3.Project(ObjectToAlter.transform.TransformPoint(mesh.vertices[i]), ObjectToAlter.transform.TransformDirection(mesh.normals[Mathf.CeilToInt(i / 3)]));
   uvs[i] = Vector2(uv.y, uv.z);
   Debug.Log(uv);
}
mesh.uv = uvs;


I am trying to project each vector in each mesh face in world coordinates along the normal of that face to convert it to a 2D face for use as a UV. I am using world coordinates to incorporate the transform scale of the mesh, and to ensure that textures in separate meshes align with each other instead of producing terrible looking seams where they intersect.

For an example of what I am trying to accomplish, please take a look at the left hand sphere in the first illustration at Wikipedia's page on UV mapping.

_________________
Aubrey Falconer ~ of ATI Design
Mars Explorer FTW!
Back to top
View user's profile Send private message Visit poster's website
robur



Joined: 13 Feb 2008
Posts: 346
Location: North Idaho

PostPosted: Mon Aug 03, 2009 10:36 pm    Post subject: Reply with quote
Got it working!

Code posted to the Unity Wiki:
http://www.unifycommunity.com/wiki/index.php?title=WorldUVs


_________________
Aubrey Falconer ~ of ATI Design
Mars Explorer FTW!
Back to top
View user's profile Send private message Visit poster's website
quentinp



Joined: 17 Apr 2009
Posts: 307
Location: Ontario, Canada

PostPosted: Tue Aug 04, 2009 1:36 pm    Post subject: Reply with quote
Great script! Of course when I need it I'll be searching around for this thread again, and not be able to find it Very Happy That's usually what happens - vaguely remembering some great solution to a problem, but not where or when I saw it!
Back to top
View user's profile Send private message
magwo



Joined: 20 May 2009
Posts: 400
Location: Sweden

PostPosted: Tue Aug 04, 2009 5:44 pm    Post subject: Reply with quote
This is quite neat. Smile
A potential productivity/quality boost for projects where the graphics don't need to be top-notch.
Back to top
View user's profile Send private message
robur



Joined: 13 Feb 2008
Posts: 346
Location: North Idaho

PostPosted: Tue Aug 04, 2009 5:58 pm    Post subject: Reply with quote
Thanks!

I created this as a component for a Unity world builder / loader library I am working on ("The Whirld Project"), and my idea is that players can create fun, highly creative worlds out of blocks - and as their skills progress, simple meshes and the like - with no knowledge prerequisites other than basic computer skills and an imagination.

A new version of this script is in the works which directly manipulates Matrix4x4s to achieve the vertex transforms to face normal space, and which will work much better for more complex meshes. And yes - I had no idea what that meant three days ago, and am still not sure that I fully comprehend it... Unity is such fun! Smile

_________________
Aubrey Falconer ~ of ATI Design
Mars Explorer FTW!
Back to top
View user's profile Send private message Visit poster's website
robur



Joined: 13 Feb 2008
Posts: 346
Location: North Idaho

PostPosted: Tue Aug 04, 2009 9:08 pm    Post subject: Reply with quote
Ok - Here's my latest editor script:

It works better than the previous one, but still fails on spheres and other more complicated meshes (some face textures are scaled correctly, but others are distorted).

The same algorithm is used for each face in each mesh - and when I Debug.DrawRay the normals my script is generating, they look correct. If anyone can determine what is going wrong, that would be great!

Code:
@MenuItem ("GameObject/World Space UVMap")
static function doMeshes() {
   if(!EditorUtility.DisplayDialog("UV Remap Confirmation", "This tool will recursively alter the UV map(s) of the mesh(es) in your selected object, altering them to all line up with each other in world space.", "Remap UVs of Selected Mesh(es)!", "Cancel")) return;
   var meshes = Selection.activeGameObject.GetComponentsInChildren(MeshFilter);
   for (var mf : MeshFilter in meshes) DoMesh(mf);
}

static function DoMesh (mf : MeshFilter) {
   var uvs = new Vector2[mf.mesh.vertices.Length];
   var tris = mf.mesh.triangles;
   var matrix : Matrix4x4 = new Matrix4x4();
   if(mf.mesh.name == "Cube" || mf.gameObject.name == "Cube") {
      var o : Vector3 = mf.transform.position;
      o.x = o.x / mf.transform.lossyScale.x; //Mathf.Repeat(o.x / mf.transform.lossyScale.x, 1);
      o.y = o.y / mf.transform.lossyScale.y; //Mathf.Repeat(o.y / mf.transform.lossyScale.y, 1);
      o.z = o.z / mf.transform.lossyScale.z; //Mathf.Repeat(o.z / mf.transform.lossyScale.z, 1);
   }
   else o = Vector3.zero;
   for (var i=0;i<tris.Length;i+=3) {
      matrix.SetTRS(Vector3.zero, Quaternion.LookRotation(Vector3.Cross(mf.mesh.vertices[tris[i]]-mf.mesh.vertices[tris[i+2]], mf.mesh.vertices[tris[i+1]]-mf.mesh.vertices[tris[i+2]]).normalized), mf.transform.lossyScale);
      var a : Vector3 = matrix.MultiplyPoint3x4(mf.mesh.vertices[tris[i]] + o);
      var b : Vector3 = matrix.MultiplyPoint3x4(mf.mesh.vertices[tris[i+1]] + o);
      var c : Vector3 = matrix.MultiplyPoint3x4(mf.mesh.vertices[tris[i+2]] + o);
      uvs[tris[i]]   = Vector2(a.x, a.y);
      uvs[tris[i+1]]   = Vector2(b.x, b.y);
      uvs[tris[i+2]]   = Vector2(c.x, c.y);
      //Debug.DrawRay((mf.mesh.vertices[tris[i]] + mf.mesh.vertices[tris[i+1]] + mf.mesh.vertices[tris[i+2]]) / 3, Vector3.Cross(mf.mesh.vertices[tris[i]]-mf.mesh.vertices[tris[i+2]], mf.mesh.vertices[tris[i+1]]-mf.mesh.vertices[tris[i+2]]).normalized);
      //Debug.DrawLine(a,b);
      //Debug.DrawLine(c,b);
      //Debug.DrawLine(a,c);
   }
    mf.mesh.uv = uvs;
}

_________________
Aubrey Falconer ~ of ATI Design
Mars Explorer FTW!
Back to top
View user's profile Send private message Visit poster's website
Post new topic   Reply to topic    Unity Community Index // Scripting All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You can attach files in this forum
You can download files in this forum