Skip to content

Commit 4f37b62

Browse files
committed
Add obj format export option
1 parent 8525f1b commit 4f37b62

File tree

6 files changed

+196
-11
lines changed

6 files changed

+196
-11
lines changed

Assets/Editor/EditorConfig.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public class EditorConfig
1313

1414
public static Color DownloadButtonDisabledColor = new Color(0.45f, 0.45f, 0.45f);
1515

16+
public static Color ExportButtonEnabledColor = new Color(0.30f, 0.35f, 0.85f);
17+
18+
public static Color ExportButtonDisabledColor = new Color(0.45f, 0.45f, 0.45f);
19+
1620
public static Color RemoveButtonColor = new Color(0.5f, 0.5f, 0.5f);
1721

1822
public static GUILayoutOption SmallButtonWidth = GUILayout.Width(50.0f);

Assets/Editor/MapzenMapEditor.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Linq;
33
using System.Collections.Generic;
44
using Mapzen;
5+
using Mapzen.Unity;
56
using UnityEditor;
67

78
[CustomEditor(typeof(MapzenMap))]
@@ -10,6 +11,7 @@ public class MapzenMapEditor : Editor
1011
private MapzenMap mapzenMap;
1112
private bool showTileDataFoldout = false;
1213

14+
1315
void OnEnable()
1416
{
1517
this.mapzenMap = (MapzenMap)target;
@@ -45,6 +47,19 @@ public override void OnInspectorGUI()
4547

4648
EditorConfig.ResetColor();
4749

50+
valid = mapzenMap.MeshFilters.Count > 0;
51+
52+
EditorConfig.SetColor(valid ?
53+
EditorConfig.ExportButtonEnabledColor :
54+
EditorConfig.ExportButtonDisabledColor);
55+
56+
if (GUILayout.Button("Export to OBJ"))
57+
{
58+
ModelExporter.OBJ(mapzenMap.MeshFilters, mapzenMap.RegionName);
59+
}
60+
61+
EditorConfig.ResetColor();
62+
4863
SavePreferences();
4964
}
5065

Assets/Editor/ModelExporter.cs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
using System;
2+
using System.Text;
3+
using System.IO;
4+
using System.Collections.Generic;
5+
using UnityEngine;
6+
using UnityEditor;
7+
8+
public class ModelExporter
9+
{
10+
private struct MaterialDesc
11+
{
12+
public string mainTexture;
13+
public Color color;
14+
}
15+
16+
public static void OBJ(List<MeshFilter> meshes, string filename)
17+
{
18+
int vertexOffset = 0;
19+
int normalOffset = 0;
20+
int uvOffset = 0;
21+
22+
StringBuilder builder = new StringBuilder();
23+
24+
builder.Append("# Exported with Tangram Unity\n");
25+
builder.Append("# Visit https://github.com/tangrams/tangram-unity/ for more details\n\n");
26+
builder.Append("mtllib " + filename + ".mtl\n");
27+
28+
foreach (var meshFilter in meshes)
29+
{
30+
Mesh mesh = meshFilter.sharedMesh;
31+
32+
Material[] materials = meshFilter.GetComponent<Renderer>().sharedMaterials;
33+
34+
builder.Append("g ").Append(meshFilter.name).Append("\n");
35+
36+
foreach (Vector3 lv in mesh.vertices)
37+
{
38+
Vector3 wv = meshFilter.transform.TransformPoint(lv);
39+
builder.Append(string.Format("v {0} {1} {2}\n", -wv.x, wv.y, wv.z));
40+
}
41+
42+
builder.Append("\n");
43+
44+
foreach (Vector3 ln in mesh.normals)
45+
{
46+
Vector3 wn = meshFilter.transform.TransformDirection(ln);
47+
builder.Append(string.Format("vn {0} {1} {2}\n", -wn.x, wn.y, wn.z));
48+
}
49+
50+
builder.Append("\n");
51+
52+
foreach (Vector2 uv in mesh.uv)
53+
{
54+
builder.Append(string.Format("vt {0} {1}\n", uv.x, uv.y));
55+
}
56+
57+
for (int i = 0; i < mesh.subMeshCount; ++i)
58+
{
59+
var material = materials[i];
60+
61+
builder.Append("\n");
62+
builder.Append("usemtl ").Append(material.name).Append("\n");
63+
builder.Append("usemap ").Append(material.name).Append("\n");
64+
65+
int[] triangles = mesh.GetTriangles(i);
66+
for (int j = 0; j < triangles.Length; j += 3)
67+
{
68+
if (mesh.uv.Length > 0)
69+
{
70+
builder.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n",
71+
triangles[j + 0] + 1 + vertexOffset,
72+
triangles[j + 1] + 1 + vertexOffset,
73+
triangles[j + 2] + 1 + vertexOffset));
74+
}
75+
else
76+
{
77+
builder.Append(string.Format("f {1}//{1} {0}//{0} {2}//{2}\n",
78+
triangles[j + 0] + 1 + vertexOffset,
79+
triangles[j + 1] + 1 + vertexOffset,
80+
triangles[j + 2] + 1 + vertexOffset));
81+
}
82+
}
83+
}
84+
85+
vertexOffset += mesh.vertices.Length;
86+
}
87+
88+
var materialAssetPerName = new Dictionary<string, MaterialDesc>();
89+
foreach (var meshFilter in meshes)
90+
{
91+
Mesh mesh = meshFilter.sharedMesh;
92+
Material[] materials = meshFilter.GetComponent<Renderer>().sharedMaterials;
93+
94+
for (int i = 0; i < mesh.subMeshCount; ++i)
95+
{
96+
var material = materials[i];
97+
string mainTexture = null;
98+
if (material.mainTexture != null)
99+
{
100+
mainTexture = AssetDatabase.GetAssetPath(material.mainTexture);
101+
}
102+
if (!materialAssetPerName.ContainsKey(material.name))
103+
{
104+
MaterialDesc materialDesc = new MaterialDesc();
105+
materialDesc.mainTexture = mainTexture;
106+
materialDesc.color = material.color;
107+
materialAssetPerName.Add(material.name, materialDesc);
108+
}
109+
}
110+
}
111+
112+
using (StreamWriter sw = new StreamWriter(filename + ".mtl"))
113+
{
114+
foreach (var materialAssetPair in materialAssetPerName)
115+
{
116+
MaterialDesc materialDesc = materialAssetPair.Value;
117+
118+
sw.Write("\n");
119+
sw.Write("newmtl {0}\n", materialAssetPair.Key);
120+
sw.Write("Ka 1.0 1.0 1.0\n");
121+
sw.Write(string.Format("Kd {0} {1} {2}\n",
122+
materialDesc.color.r,
123+
materialDesc.color.g,
124+
materialDesc.color.b));
125+
sw.Write("Ks 0.0 0.0 0.0\n");
126+
sw.Write("d 1.0\n");
127+
sw.Write("Ns 0.0\n");
128+
sw.Write("illum 2\n");
129+
130+
if (materialDesc.mainTexture != null)
131+
{
132+
string dest = materialDesc.mainTexture;
133+
int stripIndex = dest.LastIndexOf("/");
134+
if (stripIndex >= 0)
135+
{
136+
dest = dest.Substring(stripIndex + 1).Trim();
137+
}
138+
File.Copy(materialDesc.mainTexture, dest);
139+
sw.Write("map_Kd {0}\n", dest);
140+
}
141+
}
142+
}
143+
144+
using (StreamWriter sw = new StreamWriter(filename + ".obj"))
145+
{
146+
sw.Write(builder.ToString());
147+
}
148+
149+
Debug.Log("Model exported as " + filename + ".obj");
150+
}
151+
}

Assets/Editor/ModelExporter.cs.meta

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/Mapzen/Unity/SceneGraph.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Linq;
33
using Mapzen;
44
using UnityEngine;
5+
using System.Collections.Generic;
56

67
#if UNITY_EDITOR
78
using UnityEditor;
@@ -16,11 +17,13 @@ public class SceneGraph
1617
/// </summary>
1718
/// <param name="group">The scene group to visit.</param>
1819
/// <param name="parent">The parent transform of the generated game object for the current scene group.</param>
19-
public static void Generate(SceneGroup group, Transform parent, GameObjectOptions options)
20+
public static List<MeshFilter> Generate(SceneGroup group, Transform parent, GameObjectOptions options)
2021
{
22+
List<MeshFilter> meshFilters = new List<MeshFilter>();
23+
2124
if (group.meshData.Meshes.Count == 0 && group.childs.Count == 0)
2225
{
23-
return;
26+
return meshFilters;
2427
}
2528

2629
if (group.childs.Count > 0)
@@ -35,7 +38,7 @@ public static void Generate(SceneGroup group, Transform parent, GameObjectOption
3538

3639
foreach (var child in group.childs)
3740
{
38-
Generate(child.Value, gameObject.transform, options);
41+
meshFilters.AddRange(Generate(child.Value, gameObject.transform, options));
3942
}
4043
}
4144
else
@@ -96,8 +99,12 @@ public static void Generate(SceneGroup group, Transform parent, GameObjectOption
9699
meshColliderComponent.material = options.PhysicMaterial;
97100
meshColliderComponent.sharedMesh = mesh;
98101
}
102+
103+
meshFilters.Add(meshFilterComponent);
99104
}
100105
}
106+
107+
return meshFilters;
101108
}
102109
}
103110
}

Assets/MapzenMap.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
using System.Collections;
22
using System;
33
using System.Collections.Generic;
4-
using System.Runtime.InteropServices;
54
using UnityEngine;
6-
using UnityEngine.Networking;
7-
using Mapzen.VectorData;
85
using Mapzen.Unity;
9-
using Mapzen.VectorData.Filters;
106
using Mapzen;
117

128
public class MapzenMap : MonoBehaviour
@@ -24,7 +20,7 @@ public class MapzenMap : MonoBehaviour
2420

2521
public string RegionName = "";
2622

27-
private List<GameObject> tiles = new List<GameObject>();
23+
private List<MeshFilter> meshFilters = new List<MeshFilter>();
2824

2925
private IO tileIO = new IO();
3026

@@ -98,13 +94,13 @@ void OnTaskReady(TileTask readyTask)
9894
{
9995
tasks.Clear();
10096

101-
SceneGraph.Generate(regionMap, null, gameObjectOptions);
97+
meshFilters = SceneGraph.Generate(regionMap, null, gameObjectOptions);
10298
}
10399
}
104100

105-
public List<GameObject> Tiles
101+
public List<MeshFilter> MeshFilters
106102
{
107-
get { return tiles; }
103+
get { return meshFilters; }
108104
}
109105

110106
public List<FeatureStyle> FeatureStyling

0 commit comments

Comments
 (0)