Monday, February 18, 2013

box projection of textures on procedural tunnels

So the last 3 days I did box projection texture mapping on some curvaceous abstract procedural shapes made with marching cubes.

Perlin noise tunnels with box projection UVs

at the start I had 3 lines of code that puts the 3 planes of the box X/Y/Z onto any rounded surface and that was easy, the tricky thing was finding how to calculate the joining triangles in between the planes
moral of the story is to definitely make pictures of the triangles that you are editing and not just launch off into some formula, and to have some good mesh troubleshooting tools so you can see within unity the triangles stats by clicking on each triangle.

Wiki says that there are algorithms for making cubic projection seamless but you will be hard pressed to find some papers and posts on that topic.

Buy the UV cubic remapping code for $5 if you want! it is in actionscript/JS and it is pretty straightforwards so you can adapt it to C etc. You will have to have some mesh to apply it to!

Unity actually can return the 3 corners of the triangle that you click on and all the information about them which is extremely useful and handy code here it is, adapt it for your purpose.

       

//#pragma strict
var cubicobject : GameObject;
// Attach this script to a camera and it will
// draw a debug line triangle triangle
// at the triangle where you place the mouse.
function Update () {
    // Only if we hit something, do we continue
    var hit : RaycastHit;
    if (Physics.Raycast (camera.ScreenPointToRay(Input.mousePosition), hit)&&Input.GetMouseButtonDown(0)){

 //var cubicscript = cubicobject.GetComponent(otherscript);
 //var facing :int[] = cubicscript.aspect;//use this to get any information is from other scripts
 
    // Just in case, also make sure the collider also has a renderer
    // material and texture
  var meshCollider = hit.collider as MeshCollider;
  if (meshCollider == null || meshCollider.sharedMesh == null)
   return;

  var mesh : Mesh = meshCollider.sharedMesh;
  var vertices = mesh.vertices;
  var triangles = mesh.triangles;
  var uvs = mesh.uv;
  
  var t0 = hit.triangleIndex * 3 + 0;
  var t1 = hit.triangleIndex * 3 + 1;    
  var t2 = hit.triangleIndex * 3 + 2;   
  
  // Extract local space vertices that were hit
  var p0 = vertices[triangles[t0]];
  var p1 = vertices[triangles[t1]];    
  var p2 = vertices[triangles[t2]];   
  
  var u0 = uvs[triangles[t0]];
  var u1 = uvs[triangles[t1]];    
  var u2 = uvs[triangles[t2]];  
   
  Debug.Log(   " IND1   "+ triangles[t0] + " IND2   "+ triangles[t1] +" IND3   "+ triangles[t2]  );  
  Debug.Log(   " HIT1   "+ p0*100000 + " HIT2   "+ p1* 100000 +" HIT3   "+ p2*100000  );
  Debug.Log(   " UVS1   "+ u0*100000 + " UVS2   "+ u1*100000 +" UVS3   "+ u2*100000  );
    
  // Transform local space vertices to world space
  var hitTransform : Transform = hit.collider.transform;
  p0 = hitTransform.TransformPoint(p0);
  p1 = hitTransform.TransformPoint(p1);
  p2 = hitTransform.TransformPoint(p2);

  // Display with Debug.DrawLine
  Debug.DrawLine(p0, p1,Color.green, 2, false);
  Debug.DrawLine(p1, p2,Color.green, 2, false);
  Debug.DrawLine(p2, p0,Color.green, 2, false);
  
  
 }
}

       
 


The final step with these tunnels is figure out how to calculate normals relative to each of vertex, based not on the mesh itself, but the curvy Perlin noise formula underlying it.
In case you ever wondered, This is what the normals look like that are generated from vertex positions in the program:
Obviously, some normals that are close together point against each other creating shadow boundaries.(This is a blocky cave using triangles over 3 m long which doesn't look very natural!)

The nicest way to make normals from this kind of blob shape,would be to create an equivalent blog slightly larger, for example with the boundary equals to 1.01, and then find the closest point from a vertex to the theoretical surface. For that I figure you would distribute 50 points onto a quadrant of the surface closest to the vertex and take the closest one. that's the mathematically nicest way to do it.

Perhaps I will try less head scratching methods, for example just taking the vertex and normal arrays, and averaging out the normals that are close to each other, with a median or a weighted average.

here's the code that will show you the normals-(in the scene view only)-using debug.line


for(i=0;i<vertex_number;i++) {                                                                                                              
Debug.DrawLine (object_size*vertices[i],object_size*vertices[i]+normals[i], Color.red);}                      

the funny thing is-I don't know why I am making these tunnels, it wasn't the plan at all. They are pretty and I wanted to make them nice, sure, but originally my mission was to make a shape generator that does literally millions of colourful caricature shapes and patterns, so I can generate intriguing, jolly, and pretty meshes to put in my games by the bucket load and make infinite landscapes full of things to explore. but if I can just figure these normals out so I can make smooth tunnels, then I will have a truly awesome tunnel generator for myself and others.

No comments:

Post a Comment