247 lines
8.4 KiB
C#
247 lines
8.4 KiB
C#
|
|
/*******************************************************************************
|
|||
|
|
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
|||
|
|
|
|||
|
|
NOTICE:All information contained herein is, and remains the property of
|
|||
|
|
PICO Technology Co., Ltd. The intellectual and technical concepts
|
|||
|
|
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
|||
|
|
covered by patents, patents in process, and are protected by trade secret or
|
|||
|
|
copyright law. Dissemination of this information or reproduction of this
|
|||
|
|
material is strictly forbidden unless prior written permission is obtained from
|
|||
|
|
PICO Technology Co., Ltd.
|
|||
|
|
*******************************************************************************/
|
|||
|
|
|
|||
|
|
using UnityEngine;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Text;
|
|||
|
|
|
|||
|
|
namespace Unity.XR.PXR
|
|||
|
|
{
|
|||
|
|
public class PXR_ObjImporter : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private static PXR_ObjImporter instance;
|
|||
|
|
|
|||
|
|
public static PXR_ObjImporter Instance
|
|||
|
|
{
|
|||
|
|
get { return instance ?? (instance = new PXR_ObjImporter()); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<int> triangles;
|
|||
|
|
private List<Vector3> vertices;
|
|||
|
|
private List<Vector2> uv;
|
|||
|
|
private List<Vector3> normals;
|
|||
|
|
private List<PxrVector3Int> faceData;
|
|||
|
|
private List<int> intArray;
|
|||
|
|
|
|||
|
|
private const int MinPow10 = -16;
|
|||
|
|
private const int MaxPow10 = 16;
|
|||
|
|
private const int NumPows10 = MaxPow10 - MinPow10 + 1;
|
|||
|
|
private static readonly float[] pow10 = GenerateLookupTable();
|
|||
|
|
|
|||
|
|
public Mesh ImportFile(string filePath)
|
|||
|
|
{
|
|||
|
|
triangles = new List<int>();
|
|||
|
|
vertices = new List<Vector3>();
|
|||
|
|
uv = new List<Vector2>();
|
|||
|
|
normals = new List<Vector3>();
|
|||
|
|
faceData = new List<PxrVector3Int>();
|
|||
|
|
intArray = new List<int>();
|
|||
|
|
|
|||
|
|
LoadMeshData(filePath);
|
|||
|
|
|
|||
|
|
Vector3[] newVerts = new Vector3[faceData.Count];
|
|||
|
|
Vector2[] newUVs = new Vector2[faceData.Count];
|
|||
|
|
Vector3[] newNormals = new Vector3[faceData.Count];
|
|||
|
|
|
|||
|
|
for (int i = 0; i < faceData.Count; i++)
|
|||
|
|
{
|
|||
|
|
newVerts[i] = vertices[faceData[i].x - 1];
|
|||
|
|
if (faceData[i].y >= 1)
|
|||
|
|
newUVs[i] = uv[faceData[i].y - 1];
|
|||
|
|
|
|||
|
|
if (faceData[i].z >= 1)
|
|||
|
|
newNormals[i] = normals[faceData[i].z - 1];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Mesh mesh = new Mesh();
|
|||
|
|
mesh.vertices = newVerts;
|
|||
|
|
mesh.uv = newUVs;
|
|||
|
|
mesh.normals = newNormals;
|
|||
|
|
mesh.triangles = triangles.ToArray();
|
|||
|
|
mesh.RecalculateBounds();
|
|||
|
|
|
|||
|
|
return mesh;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void LoadMeshData(string fileName)
|
|||
|
|
{
|
|||
|
|
StringBuilder sb = new StringBuilder();
|
|||
|
|
string text = File.ReadAllText(fileName);
|
|||
|
|
int start = 0;
|
|||
|
|
string objectName = null;
|
|||
|
|
int faceDataCount = 0;
|
|||
|
|
|
|||
|
|
StringBuilder sbFloat = new StringBuilder();
|
|||
|
|
|
|||
|
|
for (int i = 0; i < text.Length; i++)
|
|||
|
|
{
|
|||
|
|
if (text[i] == '\n')
|
|||
|
|
{
|
|||
|
|
sb.Remove(0, sb.Length);
|
|||
|
|
|
|||
|
|
sb.Append(text, start + 1, i - start);
|
|||
|
|
start = i;
|
|||
|
|
|
|||
|
|
if (sb[0] == 'o' && sb[1] == ' ')
|
|||
|
|
{
|
|||
|
|
sbFloat.Remove(0, sbFloat.Length);
|
|||
|
|
int j = 2;
|
|||
|
|
while (j < sb.Length)
|
|||
|
|
{
|
|||
|
|
objectName += sb[j];
|
|||
|
|
j++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (sb[0] == 'v' && sb[1] == ' ') // Vertices
|
|||
|
|
{
|
|||
|
|
int splitStart = 2;
|
|||
|
|
|
|||
|
|
vertices.Add(new Vector3(GetFloat(sb, ref splitStart, ref sbFloat),
|
|||
|
|
GetFloat(sb, ref splitStart, ref sbFloat), GetFloat(sb, ref splitStart, ref sbFloat)));
|
|||
|
|
}
|
|||
|
|
else if (sb[0] == 'v' && sb[1] == 't' && sb[2] == ' ') // UV
|
|||
|
|
{
|
|||
|
|
int splitStart = 3;
|
|||
|
|
|
|||
|
|
uv.Add(new Vector2(GetFloat(sb, ref splitStart, ref sbFloat),
|
|||
|
|
GetFloat(sb, ref splitStart, ref sbFloat)));
|
|||
|
|
}
|
|||
|
|
else if (sb[0] == 'v' && sb[1] == 'n' && sb[2] == ' ') // Normals
|
|||
|
|
{
|
|||
|
|
int splitStart = 3;
|
|||
|
|
|
|||
|
|
normals.Add(new Vector3(GetFloat(sb, ref splitStart, ref sbFloat),
|
|||
|
|
GetFloat(sb, ref splitStart, ref sbFloat), GetFloat(sb, ref splitStart, ref sbFloat)));
|
|||
|
|
}
|
|||
|
|
else if (sb[0] == 'f' && sb[1] == ' ')
|
|||
|
|
{
|
|||
|
|
int splitStart = 2;
|
|||
|
|
|
|||
|
|
int j = 1;
|
|||
|
|
intArray.Clear();
|
|||
|
|
int info = 0;
|
|||
|
|
|
|||
|
|
while (splitStart < sb.Length && char.IsDigit(sb[splitStart]))
|
|||
|
|
{
|
|||
|
|
faceData.Add(new PxrVector3Int(GetInt(sb, ref splitStart, ref sbFloat),
|
|||
|
|
GetInt(sb, ref splitStart, ref sbFloat), GetInt(sb, ref splitStart, ref sbFloat)));
|
|||
|
|
j++;
|
|||
|
|
|
|||
|
|
intArray.Add(faceDataCount);
|
|||
|
|
faceDataCount++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
info += j;
|
|||
|
|
j = 1;
|
|||
|
|
while (j + 2 < info)
|
|||
|
|
{
|
|||
|
|
triangles.Add(intArray[0]);
|
|||
|
|
triangles.Add(intArray[j]);
|
|||
|
|
triangles.Add(intArray[j + 1]);
|
|||
|
|
|
|||
|
|
j++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private float GetFloat(StringBuilder sb, ref int start, ref StringBuilder sbFloat)
|
|||
|
|
{
|
|||
|
|
sbFloat.Remove(0, sbFloat.Length);
|
|||
|
|
while (start < sb.Length &&
|
|||
|
|
(char.IsDigit(sb[start]) || sb[start] == '-' || sb[start] == '.'))
|
|||
|
|
{
|
|||
|
|
sbFloat.Append(sb[start]);
|
|||
|
|
start++;
|
|||
|
|
}
|
|||
|
|
start++;
|
|||
|
|
|
|||
|
|
return ParseFloat(sbFloat);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private int GetInt(StringBuilder sb, ref int start, ref StringBuilder sbInt)
|
|||
|
|
{
|
|||
|
|
sbInt.Remove(0, sbInt.Length);
|
|||
|
|
while (start < sb.Length &&
|
|||
|
|
(char.IsDigit(sb[start])))
|
|||
|
|
{
|
|||
|
|
sbInt.Append(sb[start]);
|
|||
|
|
start++;
|
|||
|
|
}
|
|||
|
|
start++;
|
|||
|
|
|
|||
|
|
return IntParseFast(sbInt);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static float[] GenerateLookupTable()
|
|||
|
|
{
|
|||
|
|
var result = new float[(-MinPow10 + MaxPow10) * 10];
|
|||
|
|
for (int i = 0; i < result.Length; i++)
|
|||
|
|
result[i] = (float)((i / NumPows10) *
|
|||
|
|
Mathf.Pow(10, i % NumPows10 + MinPow10));
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private float ParseFloat(StringBuilder value)
|
|||
|
|
{
|
|||
|
|
float result = 0;
|
|||
|
|
bool negate = false;
|
|||
|
|
int len = value.Length;
|
|||
|
|
int decimalIndex = value.Length;
|
|||
|
|
for (int i = len - 1; i >= 0; i--)
|
|||
|
|
if (value[i] == '.')
|
|||
|
|
{ decimalIndex = i; break; }
|
|||
|
|
int offset = -MinPow10 + decimalIndex;
|
|||
|
|
for (int i = 0; i < decimalIndex; i++)
|
|||
|
|
if (i != decimalIndex && value[i] != '-')
|
|||
|
|
result += pow10[(value[i] - '0') * NumPows10 + offset - i - 1];
|
|||
|
|
else if (value[i] == '-')
|
|||
|
|
negate = true;
|
|||
|
|
for (int i = decimalIndex + 1; i < len; i++)
|
|||
|
|
if (i != decimalIndex)
|
|||
|
|
result += pow10[(value[i] - '0') * NumPows10 + offset - i];
|
|||
|
|
if (negate)
|
|||
|
|
result = -result;
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private int IntParseFast(StringBuilder value)
|
|||
|
|
{
|
|||
|
|
int result = 0;
|
|||
|
|
for (int i = 0; i < value.Length; i++)
|
|||
|
|
{
|
|||
|
|
result = 10 * result + (value[i] - 48);
|
|||
|
|
}
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public sealed class PxrVector3Int
|
|||
|
|
{
|
|||
|
|
public int x { get; set; }
|
|||
|
|
public int y { get; set; }
|
|||
|
|
public int z { get; set; }
|
|||
|
|
|
|||
|
|
public PxrVector3Int() { }
|
|||
|
|
|
|||
|
|
public PxrVector3Int(int intX, int intY, int intZ)
|
|||
|
|
{
|
|||
|
|
x = intX;
|
|||
|
|
y = intY;
|
|||
|
|
z = intZ;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|