Advertisement
Guest User

Fixed FastObjImporter script

a guest
Dec 18th, 2017
1,586
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.11 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text;
  5.  
  6. public sealed class FastObjImporter
  7. {
  8.  
  9.     #region singleton
  10.     // Singleton code
  11.     // Static can be called from anywhere without having to make an instance
  12.     private static FastObjImporter _instance;
  13.  
  14.     // If called check if there is an instance, otherwise create it
  15.     public static FastObjImporter Instance
  16.     {
  17.         get { return _instance ?? (_instance = new FastObjImporter()); }
  18.     }
  19.     #endregion
  20.  
  21.     private List<int> triangles;
  22.     private List<Vector3> vertices;
  23.     private List<Vector2> uv;
  24.     private List<Vector3> normals;
  25.     private List<Vector3Int> faceData;
  26.     private List<int> intArray;
  27.  
  28.     private const int MIN_POW_10 = -16;
  29.     private const int MAX_POW_10 = 16;
  30.     private const int NUM_POWS_10 = MAX_POW_10 - MIN_POW_10 + 1;
  31.     private static readonly float[] pow10 = GenerateLookupTable();
  32.  
  33.     // Use this for initialization
  34.     public Mesh ImportFile(string filePath)
  35.     {
  36.         triangles = new List<int>();
  37.         vertices = new List<Vector3>();
  38.         uv = new List<Vector2>();
  39.         normals = new List<Vector3>();
  40.         faceData = new List<Vector3Int>();
  41.         intArray = new List<int>();
  42.  
  43.         LoadMeshData(filePath);
  44.  
  45.         Vector3[] newVerts = new Vector3[faceData.Count];
  46.         Vector2[] newUVs = new Vector2[faceData.Count];
  47.         Vector3[] newNormals = new Vector3[faceData.Count];
  48.  
  49.         /* The following foreach loops through the facedata and assigns the appropriate vertex, uv, or normal
  50.          * for the appropriate Unity mesh array.
  51.          */
  52.         for (int i = 0; i < faceData.Count; i++)
  53.         {
  54.             newVerts[i] = vertices[faceData[i].x - 1];
  55.             if (faceData[i].y >= 1)
  56.             {
  57.                 //Added this if statement to fix Index bug
  58.                 if ((faceData[i].y - 1) < uv.Count - 1)
  59.                 {
  60.                     newUVs[i] = uv[faceData[i].y - 1];
  61.                 }
  62.             }
  63.  
  64.             if (faceData[i].z >= 1)
  65.                 newNormals[i] = normals[faceData[i].z - 1];
  66.         }
  67.  
  68.         Mesh mesh = new Mesh();
  69.  
  70.         mesh.vertices = newVerts;
  71.         mesh.uv = newUVs;
  72.         mesh.normals = newNormals;
  73.         mesh.triangles = triangles.ToArray();
  74.  
  75.         mesh.RecalculateBounds();
  76.         //mesh.Optimize();
  77.  
  78.         return mesh;
  79.     }
  80.  
  81.     private void LoadMeshData(string fileName)
  82.     {
  83.  
  84.         StringBuilder sb = new StringBuilder();
  85.         string text = File.ReadAllText(fileName);
  86.         int start = 0;
  87.         string objectName = null;
  88.         int faceDataCount = 0;
  89.  
  90.         StringBuilder sbFloat = new StringBuilder();
  91.  
  92.         for (int i = 0; i < text.Length; i++)
  93.         {
  94.             if (text[i] == '\n')
  95.             {
  96.                 sb.Remove(0, sb.Length);
  97.  
  98.                 // Start +1 for whitespace '\n'
  99.                 sb.Append(text, start + 1, i - start);
  100.                 start = i;
  101.  
  102.                 if (sb[0] == 'o' && sb[1] == ' ')
  103.                 {
  104.                     sbFloat.Remove(0, sbFloat.Length);
  105.                     int j = 2;
  106.                     while (j < sb.Length)
  107.                     {
  108.                         objectName += sb[j];
  109.                         j++;
  110.                     }
  111.                 }
  112.                 else if (sb[0] == 'v' && sb[1] == ' ') // Vertices
  113.                 {
  114.                     int splitStart = 2;
  115.  
  116.                     vertices.Add(new Vector3(GetFloat(sb, ref splitStart, ref sbFloat),
  117.                         GetFloat(sb, ref splitStart, ref sbFloat), GetFloat(sb, ref splitStart, ref sbFloat)));
  118.                 }
  119.                 else if (sb[0] == 'v' && sb[1] == 't' && sb[2] == ' ') // UV
  120.                 {
  121.                     int splitStart = 3;
  122.  
  123.                     uv.Add(new Vector2(GetFloat(sb, ref splitStart, ref sbFloat),
  124.                         GetFloat(sb, ref splitStart, ref sbFloat)));
  125.                 }
  126.                 else if (sb[0] == 'v' && sb[1] == 'n' && sb[2] == ' ') // Normals
  127.                 {
  128.                     int splitStart = 3;
  129.  
  130.                     normals.Add(new Vector3(GetFloat(sb, ref splitStart, ref sbFloat),
  131.                         GetFloat(sb, ref splitStart, ref sbFloat), GetFloat(sb, ref splitStart, ref sbFloat)));
  132.                 }
  133.                 else if (sb[0] == 'f' && sb[1] == ' ')
  134.                 {
  135.                     int splitStart = 2;
  136.  
  137.                     int j = 1;
  138.                     intArray.Clear();
  139.                     int info = 0;
  140.                     // Add faceData, a face can contain multiple triangles, facedata is stored in following order vert, uv, normal. If uv or normal are / set it to a 0
  141.                     while (splitStart < sb.Length && char.IsDigit(sb[splitStart]))
  142.                     {
  143.                         faceData.Add(new Vector3Int(GetInt(sb, ref splitStart, ref sbFloat),
  144.                             GetInt(sb, ref splitStart, ref sbFloat), GetInt(sb, ref splitStart, ref sbFloat)));
  145.                         j++;
  146.  
  147.                         intArray.Add(faceDataCount);
  148.                         faceDataCount++;
  149.                     }
  150.  
  151.                     info += j;
  152.                     j = 1;
  153.                     while (j + 2 < info) //Create triangles out of the face data.  There will generally be more than 1 triangle per face.
  154.                     {
  155.                         triangles.Add(intArray[0]);
  156.                         triangles.Add(intArray[j]);
  157.                         triangles.Add(intArray[j + 1]);
  158.  
  159.                         j++;
  160.                     }
  161.                 }
  162.             }
  163.         }
  164.     }
  165.  
  166.     private float GetFloat(StringBuilder sb, ref int start, ref StringBuilder sbFloat)
  167.     {
  168.         sbFloat.Remove(0, sbFloat.Length);
  169.         while (start < sb.Length &&
  170.                (char.IsDigit(sb[start]) || sb[start] == '-' || sb[start] == '.'))
  171.         {
  172.             sbFloat.Append(sb[start]);
  173.             start++;
  174.         }
  175.         start++;
  176.  
  177.         return ParseFloat(sbFloat);
  178.     }
  179.  
  180.     private int GetInt(StringBuilder sb, ref int start, ref StringBuilder sbInt)
  181.     {
  182.         sbInt.Remove(0, sbInt.Length);
  183.         while (start < sb.Length &&
  184.                (char.IsDigit(sb[start])))
  185.         {
  186.             sbInt.Append(sb[start]);
  187.             start++;
  188.         }
  189.         start++;
  190.  
  191.         return IntParseFast(sbInt);
  192.     }
  193.  
  194.  
  195.     private static float[] GenerateLookupTable()
  196.     {
  197.         var result = new float[(-MIN_POW_10 + MAX_POW_10) * 10];
  198.         for (int i = 0; i < result.Length; i++)
  199.             result[i] = (float)((i / NUM_POWS_10) *
  200.                     Mathf.Pow(10, i % NUM_POWS_10 + MIN_POW_10));
  201.         return result;
  202.     }
  203.  
  204.     private float ParseFloat(StringBuilder value)
  205.     {
  206.         float result = 0;
  207.         bool negate = false;
  208.         int len = value.Length;
  209.         int decimalIndex = value.Length;
  210.         for (int i = len - 1; i >= 0; i--)
  211.             if (value[i] == '.')
  212.             { decimalIndex = i; break; }
  213.         int offset = -MIN_POW_10 + decimalIndex;
  214.         for (int i = 0; i < decimalIndex; i++)
  215.             if (i != decimalIndex && value[i] != '-')
  216.                 result += pow10[(value[i] - '0') * NUM_POWS_10 + offset - i - 1];
  217.             else if (value[i] == '-')
  218.                 negate = true;
  219.         for (int i = decimalIndex + 1; i < len; i++)
  220.             if (i != decimalIndex)
  221.                 result += pow10[(value[i] - '0') * NUM_POWS_10 + offset - i];
  222.         if (negate)
  223.             result = -result;
  224.         return result;
  225.     }
  226.  
  227.     private int IntParseFast(StringBuilder value)
  228.     {
  229.         // An optimized int parse method.
  230.         int result = 0;
  231.         for (int i = 0; i < value.Length; i++)
  232.         {
  233.             result = 10 * result + (value[i] - 48);
  234.         }
  235.         return result;
  236.     }
  237. }
  238.  
  239. public sealed class Vector3Int
  240. {
  241.     public int x { get; set; }
  242.     public int y { get; set; }
  243.     public int z { get; set; }
  244.  
  245.     public Vector3Int() { }
  246.  
  247.     public Vector3Int(int x, int y, int z)
  248.     {
  249.         this.x = x;
  250.         this.y = y;
  251.         this.z = z;
  252.     }
  253. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement