Advertisement
Guest User

Jon Martin

a guest
Jan 14th, 2011
698
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.96 KB | None | 0 0
  1. //OBJ import for Unity3d 1/3
  2. //OBJ.cs by bartek drozdz of http://www.everyday3d.com (ammendments by Jon Martin of jon-martin.com & fusedworks.com)
  3.  
  4. using UnityEngine;
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Globalization;
  9. using System.Text.RegularExpressions;
  10. using System.IO;
  11.  
  12. public class OBJ : MonoBehaviour {
  13.    
  14.     public string objPath;
  15.    
  16.     /* OBJ file tags */
  17.     private const string O  = "o";
  18.     private const string G  = "g";
  19.     private const string V  = "v";
  20.     private const string VT = "vt";
  21.     private const string VN = "vn";
  22.     private const string F  = "f";
  23.     private const string MTL = "mtllib";
  24.     private const string UML = "usemtl";
  25.  
  26.     /* MTL file tags */
  27.     private const string NML = "newmtl";
  28.     private const string NS = "Ns"; // Shininess
  29.     private const string KA = "Ka"; // Ambient component (not supported)
  30.     private const string KD = "Kd"; // Diffuse component
  31.     private const string KS = "Ks"; // Specular component
  32.     private const string D = "d";   // Transparency (not supported)
  33.     private const string TR = "Tr"; // Same as 'd'
  34.     private const string ILLUM = "illum"; // Illumination model. 1 - diffuse, 2 - specular
  35.     private const string MAP_KD = "map_Kd"; // Diffuse texture (other textures are not supported)
  36.    
  37.     private string basepath;
  38.     private string mtllib;
  39.     private GeometryBuffer buffer;
  40.  
  41.     void Start ()
  42.     {
  43.         buffer = new GeometryBuffer ();
  44.         //ALTERATION 0:- To Cater for Local Files.
  45.         if (!objPath.Contains("http://")) {
  46.             basepath=Path.GetDirectoryName(objPath);
  47.             objPath="file:///"+objPath;
  48.             basepath="file:///"+basepath+Path.DirectorySeparatorChar;
  49.         } else {
  50.             basepath = (objPath.IndexOf("/") == -1) ? "" : objPath.Substring(0, objPath.LastIndexOf("/") + 1);
  51.         }
  52.         StartCoroutine (Load (objPath));
  53.     }
  54.    
  55.     public IEnumerator Load(string path) {
  56.         WWW loader = new WWW(path);
  57.         yield return loader;
  58.         SetGeometryData(loader.text);
  59.        
  60.         if(hasMaterials) {
  61.             loader = new WWW(basepath + mtllib);
  62.             yield return loader;
  63.            
  64.             //ALTERATION 4:- Lets say the user moved the material library elsewhere
  65.             //See also new function in GeometryBuffer ReturnMaterialNames()
  66.             //and correction to OBJ.GetMaterial() to cater for this.
  67.             if (loader.error != null) {
  68.                 //Could allow user to choose new path here for material library or create alert!
  69.                 string[] emats=buffer.ReturnMaterialNames(); //retrieves material names from groups
  70.                 // builds material data with defaults
  71.                 materialData = new List<MaterialData>();
  72.                 MaterialData nmd = new MaterialData();
  73.                 foreach(string mname in emats) {
  74.                     nmd = new MaterialData();
  75.                     nmd.name = mname;
  76.                     nmd.diffuse = new Color(0.5f, 0.5f, 0.5f, 1.0f);
  77.                     materialData.Add(nmd);
  78.                 }
  79.                
  80.                
  81.             } else {
  82.                 SetMaterialData(loader.text);              
  83.                 foreach(MaterialData m in materialData) {
  84.                     if(m.diffuseTexPath != null) {
  85.                         WWW texloader = new WWW(basepath + m.diffuseTexPath);
  86.                         yield return texloader;
  87.                         m.diffuseTex = texloader.texture;
  88.                     }
  89.                 }
  90.                
  91.             }
  92.         }
  93.         Build();
  94.     }
  95.  
  96.     private void SetGeometryData(string data) {
  97.         //ALTERATION 1:- Major Problems with different OBJ file format whitespace, this helped:-.
  98.         data = data.Replace("\r\n","\n");
  99.        
  100.         string[] lines = data.Split("\n".ToCharArray()); //
  101.         for(int i = 0; i < lines.Length; i++) {
  102.             string l = lines[i];
  103.             if(l.IndexOf("#") != -1) l = l.Substring(0, l.IndexOf("#"));
  104.            
  105.             //ALTERATION 1:- whitespace leading to null values, this helped:-
  106.             l=Regex.Replace(l,@"\s+"," ");
  107.             l=l.Trim();
  108.            
  109.             string[] p = l.Split(" ".ToCharArray());  
  110.  
  111.             switch(p[0]) {
  112.                 case O:
  113.                     buffer.PushObject(p[1].Trim());
  114.                     break;
  115.                 case G:
  116.                     buffer.PushGroup(p[1].Trim());
  117.                     break;
  118.                 case V:    
  119.                     if (p.Length>=3) {
  120.                         buffer.PushVertex( new Vector3( cf(p[1]), cf(p[2]), cf(p[3]) ) );
  121.                     }
  122.                     break;
  123.                 case VT:
  124.                     if (p.Length>=2) {
  125.                         buffer.PushUV(new Vector2( cf(p[1]), cf(p[2]) ));
  126.                     }
  127.                     break;
  128.                 case VN:
  129.                     if (p.Length>=3) {
  130.                         buffer.PushNormal(new Vector3( cf(p[1]), cf(p[2]), cf(p[3]) ));
  131.                     }
  132.                     break;
  133.                 case F:
  134.                     if (p.Length>=4) {
  135.                         string[] c;
  136.                         // ALTERATION 2:- Rough Fix to deal with quads and polys there may be better methods
  137.                         for (int j=0;j<p.Length-3;j++) {    //Amount of Triangles To Make up Face
  138.                             FaceIndices fi = new FaceIndices(); //Get first point
  139.                                 c=p[1].Trim().Split("/".ToCharArray());
  140.                                 if (c.Length > 0 && c[0] != string.Empty) {fi.vi = ci(c[0])-1;}
  141.                                 if (c.Length > 1 && c[1] != string.Empty) {fi.vu = ci(c[1])-1;}
  142.                                 if (c.Length > 2 && c[2] != string.Empty) {fi.vn = ci(c[2])-1;}
  143.                             buffer.PushFace(fi);
  144.                             for (int k=0;k<2;k++) {            
  145.                                 fi = new FaceIndices(); //Get second and third points (depending on p length)
  146.                                     int no=2+k+j;
  147.                                     c=p[no].Trim().Split("/".ToCharArray());
  148.                                     if (c.Length > 0 && c[0] != string.Empty) {fi.vi = ci(c[0])-1;}
  149.                                     if (c.Length > 1 && c[1] != string.Empty) {fi.vu = ci(c[1])-1;}
  150.                                     if (c.Length > 2 && c[2] != string.Empty) {fi.vn = ci(c[2])-1;}
  151.                                 buffer.PushFace(fi);
  152.                             }
  153.                         }
  154.                     }
  155.                     break;
  156.                 case MTL:
  157.                     mtllib = p[1].Trim();
  158.                     break;
  159.                 case UML:
  160.                     buffer.PushMaterialName(p[1].Trim());
  161.                     break;
  162.             }
  163.         }
  164.         buffer.Trace();
  165.     }
  166.    
  167.     private float cf(string v) {
  168.             return Convert.ToSingle(v.Trim(), new CultureInfo("en-US"));
  169.     }
  170.    
  171.     private int ci(string v) {
  172.             return Convert.ToInt32(v.Trim(), new CultureInfo("en-US"));
  173.     }
  174.    
  175.     private bool hasMaterials {
  176.         get {
  177.             return mtllib != null;
  178.         }
  179.     }
  180.    
  181.     /* ############## MATERIALS */
  182.     private List<MaterialData> materialData;
  183.     private class MaterialData {
  184.         public string name;
  185.         public Color ambient;
  186.         public Color diffuse;
  187.         public Color specular;
  188.         public float shininess;
  189.         public float alpha;
  190.         public int illumType;
  191.         public string diffuseTexPath;
  192.         public Texture2D diffuseTex;
  193.     }
  194.    
  195.     private void SetMaterialData(string data) {
  196.         //ALTERATION 1:- Major Problems with different OBJ file format whitespace, this helped:-.
  197.         data = data.Replace("\r\n","\n");
  198.        
  199.         string[] lines = data.Split("\n".ToCharArray());
  200.        
  201.         materialData = new List<MaterialData>();
  202.         MaterialData current = new MaterialData();
  203.        
  204.         for(int i = 0; i < lines.Length; i++) {
  205.             string l = lines[i];
  206.            
  207.             if(l.IndexOf("#") != -1) l = l.Substring(0, l.IndexOf("#"));
  208.             //ALTERATION 1:- whitespace leading to null values, this helped:-
  209.             l=Regex.Replace(l,@"\s+"," ");
  210.             l=l.Trim();
  211.            
  212.             string[] p = l.Split(" ".ToCharArray());
  213.            
  214.             switch(p[0]) {
  215.                 case NML:
  216.                     current = new MaterialData();
  217.                     current.name = p[1].Trim();
  218.                     materialData.Add(current);
  219.                     break;
  220.                 case KA:
  221.                     current.ambient = gc(p);
  222.                     break;
  223.                 case KD:
  224.                     current.diffuse = gc(p);
  225.                     break;
  226.                 case KS:
  227.                     current.specular = gc(p);
  228.                     break;
  229.                 case NS:
  230.                     current.shininess = cf(p[1]) / 1000;
  231.                     break;
  232.                 case D:
  233.                 case TR:
  234.                     current.alpha = cf(p[1]);
  235.                     break;
  236.                 case MAP_KD:
  237.                     current.diffuseTexPath = p[1].Trim();
  238.                     break;
  239.                 case ILLUM:
  240.                     current.illumType = ci(p[1]);
  241.                     break;
  242.                    
  243.             }
  244.         }  
  245.     }
  246.    
  247.     private Material GetMaterial(MaterialData md) {
  248.         Material m;
  249.        
  250.         if(md.illumType == 2) {
  251.             m =  new Material(Shader.Find("Specular"));
  252.             m.SetColor("_SpecColor", md.specular);
  253.             m.SetFloat("_Shininess", md.shininess);
  254.         } else {
  255.             m =  new Material(Shader.Find("Diffuse"));
  256.         }
  257.        
  258.         m.SetColor("_Color", md.diffuse);
  259.        
  260.         if(md.diffuseTex != null) m.SetTexture("_MainTex", md.diffuseTex);
  261.        
  262.         return m;
  263.     }
  264.    
  265.     private Color gc(string[] p) {
  266.         return new Color( cf(p[1]), cf(p[2]), cf(p[3]) );
  267.     }
  268.  
  269.     private void Build() {
  270.         Dictionary<string, Material> materials = new Dictionary<string, Material>();
  271.        
  272.         if(hasMaterials) {
  273.             foreach(MaterialData md in materialData) {
  274.                 materials.Add(md.name, GetMaterial(md));
  275.             }
  276.         } else {
  277.             //ALTERATION 3:- No Material library Found error found on a turbosquid .obj I downloaded
  278.             //Updated GeometryBuffer.PushGroup() adding g.materialName = "default";  as usemtl entry normally folows g group entry in obj file and will overwrite this "default" material name.
  279.             //This now works for object with no mtl libraries
  280.             Material m =  new Material(Shader.Find("Diffuse"));
  281.             m.SetColor("_Color", new Color(0.5f, 0.5f, 0.5f, 1.0f));
  282.             materials.Add("default", m);
  283.         }
  284.        
  285.         GameObject[] ms = new GameObject[buffer.numObjects];
  286.        
  287.         if(buffer.numObjects == 1) {
  288.             gameObject.AddComponent(typeof(MeshFilter));
  289.             gameObject.AddComponent(typeof(MeshRenderer));
  290.             ms[0] = gameObject;
  291.         } else if(buffer.numObjects > 1) {
  292.             for(int i = 0; i < buffer.numObjects; i++) {
  293.                 GameObject go = new GameObject();
  294.                 go.transform.parent = gameObject.transform;
  295.                 go.AddComponent(typeof(MeshFilter));
  296.                 go.AddComponent(typeof(MeshRenderer));
  297.                 ms[i] = go;
  298.             }
  299.         }
  300.        
  301.         buffer.PopulateMeshes(ms, materials);
  302.     }
  303. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement