Skip to content

Unity 5 upgrade (backwards compatible); Add support for TGA textures; Performance improvements in parsing; Fix edge case bug for continuing usemtl across groups #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.DS_Store
.meta
51 changes: 15 additions & 36 deletions OBJ/src/GeometryBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,16 @@ public GeometryBuffer() {

public void PushObject(string name) {
//Debug.Log("Adding new object " + name + ". Current is empty: " + isEmpty);
string currentMaterial = current.groups [current.groups.Count - 1].materialName;

if(isEmpty) objects.Remove(current);

ObjectData n = new ObjectData();
n.name = name;
objects.Add(n);

GroupData g = new GroupData();
g.materialName = currentMaterial;
g.name = "default";
n.groups.Add(g);

Expand All @@ -68,8 +71,11 @@ public void PushObject(string name) {
}

public void PushGroup(string name) {
string currentMaterial = current.groups [current.groups.Count - 1].materialName;

if(curgr.isEmpty) current.groups.Remove(curgr);
GroupData g = new GroupData();
g.materialName = currentMaterial;
if (name == null) {
name = "Unnamed-"+unnamedGroupIndex;
unnamedGroupIndex++;
Expand Down Expand Up @@ -126,7 +132,7 @@ public void Trace() {
public bool hasNormals { get { return normals.Count > 0; } }

public static int MAX_VERTICES_LIMIT_FOR_A_MESH = 64999;

public void PopulateMeshes(GameObject[] gs, Dictionary<string, Material> mats) {
if(gs.Length != numObjects) return; // Should not happen unless obj file is corrupt...
Debug.Log("PopulateMeshes GameObjects count:"+gs.Length);
Expand All @@ -140,7 +146,7 @@ public void PopulateMeshes(GameObject[] gs, Dictionary<string, Material> mats) {
Vector3[] tvertices = new Vector3[od.allFaces.Count];
Vector2[] tuvs = new Vector2[od.allFaces.Count];
Vector3[] tnormals = new Vector3[od.allFaces.Count];

int k = 0;
foreach(FaceIndices fi in od.allFaces) {
if (k >= MAX_VERTICES_LIMIT_FOR_A_MESH) {
Expand All @@ -152,18 +158,18 @@ public void PopulateMeshes(GameObject[] gs, Dictionary<string, Material> mats) {
if(hasNormals && fi.vn >= 0) tnormals[k] = normals[fi.vn];
k++;
}

Mesh m = (gs[i].GetComponent(typeof(MeshFilter)) as MeshFilter).mesh;
m.vertices = tvertices;
if(hasUVs) m.uv = tuvs;
if(objectHasNormals) m.normals = tnormals;

if(od.groups.Count == 1) {
Debug.Log("PopulateMeshes only one group: "+od.groups[0].name);
GroupData gd = od.groups[0];
string matName = (gd.materialName != null) ? gd.materialName : "default"; // MAYBE: "default" may not enough.
if (mats.ContainsKey(matName)) {
gs[i].renderer.material = mats[matName];
gs[i].GetComponent<Renderer>().material = mats[matName];
Debug.Log("PopulateMeshes mat:"+matName+" set.");
}
else {
Expand All @@ -173,7 +179,7 @@ public void PopulateMeshes(GameObject[] gs, Dictionary<string, Material> mats) {
for(int j = 0; j < triangles.Length; j++) triangles[j] = j;

m.triangles = triangles;

} else {
int gl = od.groups.Count;
Material[] materials = new Material[gl];
Expand All @@ -198,38 +204,11 @@ public void PopulateMeshes(GameObject[] gs, Dictionary<string, Material> mats) {
m.SetTriangles(triangles, j);
}

gs[i].renderer.materials = materials;
gs[i].GetComponent<Renderer>().materials = materials;
}
if (!objectHasNormals) {
m.RecalculateNormals();
}
}
}
}



























}
140 changes: 95 additions & 45 deletions OBJ/src/OBJ.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
public class OBJ : MonoBehaviour {

public string objPath;

#if UNITY_5
public bool useLegacyShaders = false; // compatibility option for previous users of OBJ.cs using Unity5
#else
private bool useLegacyShaders = true;
#endif

/* OBJ file tags */
private const string O = "o";
private const string G = "g";
Expand All @@ -35,73 +40,105 @@ public class OBJ : MonoBehaviour {
private const string MAP_KE = "map_Ke"; // Emissive texture
private const string MAP_BUMP = "map_bump"; // Bump map texture
private const string BUMP = "bump"; // Bump map texture

/* Material shaders */
#if UNITY_5
private const string DIFFUSE_SHADER = "Standard";
private const string SPECULAR_SHADER = "Standard (Specular setup)";
private const string BUMPED_DIFFUSE_SHADER = "Standard";
private const string BUMPED_SPECULAR_SHADER = "Standard (Specular setup)";

private const string LEGACY_DIFFUSE_SHADER = "Legacy Shaders/Diffuse";
private const string LEGACY_SPECULAR_SHADER = "Legacy Shaders/Specular";
private const string LEGACY_BUMPED_DIFFUSE_SHADER = "Legacy Shaders/Bumped Diffuse";
private const string LEGACY_BUMPED_SPECULAR_SHADER = "Legacy Shaders/Bumped Specular";
#else
private const string DIFFUSE_SHADER = "Diffuse";
private const string SPECULAR_SHADER = "Specular";
private const string BUMPED_DIFFUSE_SHADER = "Bumped Diffuse";
private const string BUMPED_SPECULAR_SHADER = "Bumped Specular";

private const string LEGACY_DIFFUSE_SHADER = DIFFUSE_SHADER;
private const string LEGACY_SPECULAR_SHADER = SPECULAR_SHADER;
private const string LEGACY_BUMPED_DIFFUSE_SHADER = BUMPED_DIFFUSE_SHADER;
private const string LEGACY_BUMPED_SPECULAR_SHADER = BUMPED_SPECULAR_SHADER;
#endif


private string basepath;
private string mtllib;
private GeometryBuffer buffer;

void Start ()
{
buffer = new GeometryBuffer ();

StartCoroutine (Load (objPath));
}

public IEnumerator Load(string path) {
yield return 0; // play nice by not hogging the main thread

basepath = (path.IndexOf("/") == -1) ? "" : path.Substring(0, path.LastIndexOf("/") + 1);

WWW loader = new WWW(path);
yield return loader;
SetGeometryData(loader.text);
yield return StartCoroutine(SetGeometryData(loader.text));

if(hasMaterials) {
loader = new WWW(basepath + mtllib);
Debug.Log("base path = "+basepath);
Debug.Log("MTL path = "+(basepath + mtllib));
string mtlPath = basepath + mtllib;
loader = new WWW (mtlPath);
yield return loader;

if (loader.error != null) {
Debug.LogError(loader.error);
}
else {
SetMaterialData(loader.text);
}

foreach(MaterialData m in materialData) {
if(m.diffuseTexPath != null) {
WWW texloader = GetTextureLoader(m, m.diffuseTexPath);
yield return texloader;
if (texloader.error != null) {
Debug.LogError(texloader.error);
} else {
m.diffuseTex = texloader.texture;

if (materialData != null) {
foreach(MaterialData m in materialData) {
if(m.diffuseTexPath != null) {
string texpath = basepath + m.diffuseTexPath;
loader = new WWW(texpath);
yield return loader;

if (loader.error != null) {
Debug.LogError(loader.error);
} else {
m.diffuseTex = GetTexture(loader);
}
}
}
if(m.bumpTexPath != null) {
WWW texloader = GetTextureLoader(m, m.bumpTexPath);
yield return texloader;
if (texloader.error != null) {
Debug.LogError(texloader.error);
} else {
m.bumpTex = texloader.texture;

if(m.bumpTexPath != null) {
string texpath = basepath + m.bumpTexPath;
loader = new WWW(texpath);
yield return loader;

if (loader.error != null) {
Debug.LogError(loader.error);
} else {
m.bumpTex = GetTexture(loader);
}
}
}
}
}

Build();

Build();
}

private WWW GetTextureLoader(MaterialData m, string texpath) {
char[] separators = {'/', '\\'};
string[] components = texpath.Split(separators);
string filename = components[components.Length-1];
string ext = Path.GetExtension(filename).ToLower();
if (ext != ".png" && ext != ".jpg") {

private Texture2D GetTexture(WWW loader) {
string ext = Path.GetExtension(loader.url).ToLower();
if (ext != ".png" && ext != ".jpg" && ext != ".tga") {
Debug.LogWarning("maybe unsupported texture format:"+ext);
}
WWW texloader = new WWW(basepath + filename);
Debug.Log("texture path for material("+m.name+") = "+(basepath + filename));
return texloader;

return (ext == ".tga" ? TGALoader.LoadTGA (new MemoryStream(loader.bytes)) : loader.texture);
// refactor this method to add support for more formats
}

private void GetFaceIndicesByOneFaceLine(FaceIndices[] faces, string[] p, bool isFaceIndexPlus) {
Expand Down Expand Up @@ -155,18 +192,22 @@ private void GetFaceIndicesByOneFaceLine(FaceIndices[] faces, string[] p, bool i
}
}

private void SetGeometryData(string data) {
private IEnumerator SetGeometryData(string data) {
yield return 0; // play nice by not hogging the main thread

string[] lines = data.Split("\n".ToCharArray());
Regex regexWhitespaces = new Regex(@"\s+");

bool isFirstInGroup = true;
bool isFaceIndexPlus = true;

for(int i = 0; i < lines.Length; i++) {
string l = lines[i].Trim();
if(l.IndexOf("#") != -1) { // comment line

if(l.Length > 0 && l[0] == '#') { // comment line
continue;
}
string[] p = regexWhitespaces.Split(l);
string[] p = l.Replace(" ", " ").Split(' ');

switch(p[0]) {
case O:
buffer.PushObject(p[1].Trim());
Expand Down Expand Up @@ -221,8 +262,8 @@ private void SetGeometryData(string data) {
buffer.PushMaterialName(p[1].Trim());
break;
}
if (i % 7000 == 0) yield return 0; // play nice with main thread while parsing large objs
}

// buffer.Trace();
}

Expand All @@ -231,7 +272,7 @@ private float cf(string v) {
return float.Parse(v);
}
catch(Exception e) {
print(e);
Debug.LogError("Error parsing: " + v + ": " + e);
return 0;
}
}
Expand All @@ -241,7 +282,7 @@ private int ci(string v) {
return int.Parse(v);
}
catch(Exception e) {
print(e);
Debug.LogError(e);
return 0;
}
}
Expand Down Expand Up @@ -274,7 +315,7 @@ private void SetMaterialData(string data) {
materialData = new List<MaterialData>();
MaterialData current = new MaterialData();
Regex regexWhitespaces = new Regex(@"\s+");

for(int i = 0; i < lines.Length; i++) {
string l = lines[i].Trim();

Expand Down Expand Up @@ -318,19 +359,28 @@ private void SetMaterialData(string data) {
Debug.Log("this line was not processed :" +l );
break;
}
}
}
}

private Material GetMaterial(MaterialData md) {
Material m;
string shaderName;

if(md.illumType == 2) {
string shaderName = (md.bumpTex != null)? "Bumped Specular" : "Specular";
if (useLegacyShaders) {
shaderName = (md.bumpTex != null)? LEGACY_BUMPED_SPECULAR_SHADER : LEGACY_SPECULAR_SHADER;
} else {
shaderName = (md.bumpTex != null)? BUMPED_SPECULAR_SHADER : SPECULAR_SHADER;
}
m = new Material(Shader.Find(shaderName));
m.SetColor("_SpecColor", md.specular);
m.SetFloat("_Shininess", md.shininess);
} else {
string shaderName = (md.bumpTex != null)? "Bumped Diffuse" : "Diffuse";
if (useLegacyShaders) {
shaderName = (md.bumpTex != null)? LEGACY_BUMPED_DIFFUSE_SHADER : LEGACY_DIFFUSE_SHADER;
} else {
shaderName = (md.bumpTex != null)? BUMPED_DIFFUSE_SHADER : DIFFUSE_SHADER;
}
m = new Material(Shader.Find(shaderName));
}

Expand Down
Loading