├── ThreeExporter
├── .gitignore
├── code
│ ├── Core.cs.meta
│ ├── Util.cs.meta
│ ├── Exporter.cs.meta
│ ├── Settings.cs.meta
│ ├── Util.cs
│ ├── Settings.cs
│ ├── Exporter.cs
│ └── Core.cs
├── ThreeExporter.userprefs
├── ThreeExporter.sln
├── AssemblyInfo.cs
└── ThreeExporter.csproj
├── ThreeExporter.userprefs
├── ThreeExporter.sln
├── LICENSE
└── README.md
/ThreeExporter/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | bin/*
3 | obj
--------------------------------------------------------------------------------
/ThreeExporter/code/Core.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a83909a014ea74696ac56df916d16fa8
3 | timeCreated: 1474100988
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/ThreeExporter/code/Util.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0e983a81ede9c4102b78e8363080afde
3 | timeCreated: 1474100988
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/ThreeExporter/code/Exporter.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2a719ae9026464eba9c9ac1b47df6a60
3 | timeCreated: 1474100988
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/ThreeExporter/code/Settings.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 534629c61aa8b49a6b2a5dc4477817de
3 | timeCreated: 1474100988
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/ThreeExporter.userprefs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ThreeExporter/ThreeExporter.userprefs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ThreeExporter/code/Util.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 |
5 | namespace Three {
6 | public static class Util {
7 |
8 | public static string ColorToHex(Color32 color) {
9 | string hex = color.r.ToString("X2") + color.g.ToString("X2") + color.b.ToString("X2");
10 | return hex;
11 | }
12 |
13 | public static string ToJSONArray(string[] strings) {
14 | return "[" + string.Join (",", strings) + "]";
15 | }
16 |
17 | }
18 | }
--------------------------------------------------------------------------------
/ThreeExporter/code/Settings.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | namespace Three {
5 | public struct Settings {
6 |
7 | public int decimalPlaces;
8 | public string saveFolder;
9 | public float lightMapRGBMConstant;
10 | public bool exportCameras;
11 | public bool exportColliders;
12 | public bool exportTextures;
13 | public bool exportLightmaps;
14 | public bool exportLights;
15 | public bool exportAmbientLight;
16 | public bool exportScripts;
17 |
18 | public int threeRevision;
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/ThreeExporter/ThreeExporter.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreeExporter", "ThreeExporter.csproj", "{7B2BF8C3-45F4-464A-A822-5478F0D02AFB}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {7B2BF8C3-45F4-464A-A822-5478F0D02AFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {7B2BF8C3-45F4-464A-A822-5478F0D02AFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {7B2BF8C3-45F4-464A-A822-5478F0D02AFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {7B2BF8C3-45F4-464A-A822-5478F0D02AFB}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | EndGlobal
18 |
--------------------------------------------------------------------------------
/ThreeExporter.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreeExporter", "ThreeExporter\ThreeExporter.csproj", "{7B2BF8C3-45F4-464A-A822-5478F0D02AFB}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {7B2BF8C3-45F4-464A-A822-5478F0D02AFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {7B2BF8C3-45F4-464A-A822-5478F0D02AFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {7B2BF8C3-45F4-464A-A822-5478F0D02AFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {7B2BF8C3-45F4-464A-A822-5478F0D02AFB}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(MonoDevelopProperties) = preSolution
18 | StartupItem = ThreeExporter\ThreeExporter.csproj
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Nick Janssen
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unity to three.js exporter
2 |
3 | **Due to changing API's this plugin is currently broken on Unity 5.5\. The last working version is Unity 5.4. Pull requests welcome!**
4 |
5 | Export your Unity scenes to the popular JSON format used in Three.js.
6 |
7 | [Demo](http://threejsexporter.nickjanssen.com/) - [Changelog](https://docs.google.com/document/d/1H9vKY0JmplnizOQT7eYrC5wk91BsCfSEu_v6pGOdnYk/pub?embedded=true) - [Source code](https://github.com/nickjanssen/ThreeExporter) - [FAQ](https://docs.google.com/document/u/1/d/e/2PACX-1vSUesxdSq9f2ysP3TdDqRrISXwYq9bFK4dGTDPhsmVhk9bjiZHReEnSBzprcz5DvsU02hE2uScqR3wq/pub)
8 |
9 | **Supported:**
10 | * Vertices
11 | * UV's
12 | * Normals
13 | * Faces
14 | * Textures
15 | * Materials
16 | * Colliders
17 | * Cameras
18 | * Lights
19 | * Lightmaps
20 | * Script Properties
21 |
22 | Requires three.js r71 or higher.
23 |
24 | The Three.js Exporter can be found under the Window menu bar.
25 |
26 | To load the exported JSON file, use the [THREE.ObjectLoader](http://threejs.org/docs/#Reference/Loaders/ObjectLoader) class. See the demo's source code for an example.
--------------------------------------------------------------------------------
/ThreeExporter/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 |
4 | // Information about this assembly is defined by the following attributes.
5 | // Change them to the values specific to your project.
6 |
7 | [assembly: AssemblyTitle("ThreeExporter")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("")]
12 | [assembly: AssemblyCopyright("nickjanssen")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
19 |
20 | [assembly: AssemblyVersion("1.0.*")]
21 |
22 | // The following attributes are used to specify the signing key for the assembly,
23 | // if desired. See the Mono documentation for more information about signing.
24 |
25 | //[assembly: AssemblyDelaySign(false)]
26 | //[assembly: AssemblyKeyFile("")]
27 |
28 |
--------------------------------------------------------------------------------
/ThreeExporter/ThreeExporter.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {7B2BF8C3-45F4-464A-A822-5478F0D02AFB}
9 | Library
10 | ThreeExporter
11 | ThreeExporter
12 | v3.5
13 |
14 |
15 | True
16 | full
17 | False
18 | bin
19 | DEBUG;
20 | prompt
21 | 4
22 | False
23 |
24 |
25 | none
26 | True
27 | bin
28 | prompt
29 | 4
30 | False
31 |
32 |
33 |
34 |
35 | lib\UnityEditor.dll
36 |
37 |
38 | lib\UnityEngine.dll
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/ThreeExporter/code/Exporter.cs:
--------------------------------------------------------------------------------
1 | // Three.js Exporter for Unity
2 | // http://threejsexporter.nickjanssen.com/
3 | // Written by Nick Janssen - info@nickjanssen.com
4 |
5 | using UnityEditor;
6 | using UnityEditor.SceneManagement;
7 | using UnityEngine;
8 | using System;
9 | using System.IO;
10 | using System.Collections;
11 | using System.Collections.Generic;
12 |
13 | namespace Three {
14 | public class Exporter : EditorWindow
15 | {
16 | public string[] threeRevisions = new string[] {"r71", "r72 and above"};
17 |
18 | public Settings settings;
19 | private static Core threeExporter = new Core();
20 |
21 | private static bool CreateTargetFolder(string folder) {
22 | try {
23 | System.IO.Directory.CreateDirectory(folder);
24 | }
25 | catch (Exception e) {
26 | Debug.LogException(e);
27 | return false;
28 | }
29 |
30 | return true;
31 | }
32 |
33 | private static bool CleanDirectory(string folder) {
34 | System.IO.DirectoryInfo dirInfo = new DirectoryInfo(folder);
35 |
36 | try {
37 | foreach (FileInfo file in dirInfo.GetFiles()) {
38 | file.Delete();
39 | }
40 | foreach (DirectoryInfo dir in dirInfo.GetDirectories()) {
41 | dir.Delete(true);
42 | }
43 | }
44 | catch (Exception e) {
45 | Debug.LogException(e);
46 | return false;
47 | }
48 |
49 | return true;
50 | }
51 |
52 |
53 | bool advancedSettings;
54 | int decimalPlaces = 4;
55 | float lightMapRGBMConstant = 5.0f;
56 | string targetPath = Path.GetFullPath(".") + Path.DirectorySeparatorChar + "ThreeExport";
57 | string subFolderName;
58 | string jsonFilename = "scene.json";
59 | bool openFolderAfterExporting = true;
60 | bool exportCameras = true;
61 | bool exportColliders = true;
62 | bool exportTextures = true;
63 | bool exportLightmaps = true;
64 | bool exportLights = true;
65 | bool exportAmbientLight = true;
66 | bool exportScripts = true;
67 | bool includeInactiveObjects = false;
68 | int threeRevision = 1;
69 |
70 | Vector2 scrollPos;
71 |
72 | [MenuItem("Window/Three.js Exporter")]
73 | public static void ShowWindow() {
74 | EditorWindow.GetWindow(typeof(Exporter));
75 | }
76 |
77 | void OnEnable()
78 | {
79 | SetSceneName (false);
80 | }
81 |
82 | void Export() {
83 | settings.saveFolder = targetPath + System.IO.Path.DirectorySeparatorChar + System.IO.Path.GetFileNameWithoutExtension(subFolderName);
84 | settings.decimalPlaces = decimalPlaces;
85 | settings.lightMapRGBMConstant = lightMapRGBMConstant;
86 | settings.exportCameras = exportCameras;
87 | settings.exportColliders = exportColliders;
88 | settings.exportTextures = exportTextures;
89 | settings.exportLightmaps = exportLightmaps;
90 | settings.exportLights = exportLights;
91 | settings.exportAmbientLight = exportAmbientLight;
92 | settings.threeRevision = threeRevision + 71;
93 |
94 | settings.exportScripts = exportScripts;
95 |
96 | Transform[] selection = Selection.GetTransforms (SelectionMode.Editable | SelectionMode.ExcludePrefab);
97 |
98 | if (selection.Length == 0) {
99 | EditorUtility.DisplayDialog ("Nothing selected.", "Please select one or more objects.", "");
100 | return;
101 | }
102 |
103 | if (!CreateTargetFolder (settings.saveFolder)) {
104 | return;
105 | }
106 |
107 | // if (!CleanDirectory (saveFolder))
108 | // return;
109 |
110 | List allSelectedObjects = new List();
111 | foreach (Transform selectedObject in selection) {
112 | foreach (var child in selectedObject.GetComponentsInChildren(includeInactiveObjects)) {
113 | allSelectedObjects.Add(child);
114 | }
115 | }
116 | Transform[] allSelectedObjectsArray = allSelectedObjects.ToArray ();
117 |
118 | string meshToJSON = threeExporter.ConvertToJSON(allSelectedObjectsArray, settings);
119 | string fullSavePath = System.IO.Path.Combine(settings.saveFolder, jsonFilename);
120 |
121 | using (StreamWriter sw = new StreamWriter(fullSavePath)) {
122 | sw.Write (meshToJSON);
123 | }
124 |
125 | if (exportTextures) {
126 | threeExporter.CopyTextures (allSelectedObjectsArray, settings);
127 | }
128 |
129 | EditorUtility.DisplayDialog("Completed.", "Exported " + allSelectedObjectsArray.Length + " objects to " + fullSavePath, "");
130 |
131 | if (openFolderAfterExporting) {
132 | EditorUtility.RevealInFinder (settings.saveFolder);
133 | }
134 |
135 | }
136 |
137 | void SetSceneName(bool showWarning)
138 | {
139 | string name = EditorSceneManager.GetActiveScene ().name;
140 |
141 | if (showWarning && name == "") {
142 | EditorUtility.DisplayDialog ("Cannot find scene.", "Please save the scene you are currently working on or load a different one.", "");
143 | } else {
144 | subFolderName = Path.GetFileNameWithoutExtension (name);
145 | }
146 | }
147 |
148 |
149 | void OnGUI()
150 | {
151 | bool cannotContinue = false;
152 |
153 | EditorGUILayout.BeginVertical();
154 | scrollPos =
155 | EditorGUILayout.BeginScrollView(scrollPos);
156 | {
157 | GUILayout.Label ("Basic Settings", EditorStyles.boldLabel);
158 |
159 | EditorGUILayout.LabelField ("Target Folder");
160 | EditorGUILayout.HelpBox (targetPath, MessageType.None);
161 |
162 | GUILayout.BeginHorizontal ();
163 | GUILayout.FlexibleSpace ();
164 |
165 | if (GUILayout.Button ("Change Target Path")) {
166 | targetPath = EditorUtility.OpenFolderPanel ("Choose Target Path", targetPath, "");
167 | }
168 |
169 | GUILayout.EndHorizontal ();
170 |
171 | EditorGUILayout.HelpBox ("Inside the Target Path, I will create an additional folder that contains a JSON file and all textures.", MessageType.Info);
172 |
173 |
174 | subFolderName = EditorGUILayout.TextField ("Folder Name", subFolderName);
175 |
176 | GUILayout.BeginHorizontal ();
177 | GUILayout.FlexibleSpace ();
178 | if (GUILayout.Button ("Set to Scene Name")) {
179 | SetSceneName (true);
180 | }
181 | GUILayout.EndHorizontal ();
182 |
183 | EditorGUILayout.Space ();
184 |
185 | jsonFilename = EditorGUILayout.TextField ("JSON Filename ", jsonFilename);
186 |
187 | EditorGUILayout.Space ();
188 |
189 | GUILayout.BeginHorizontal ();
190 | EditorGUILayout.LabelField ("Target Three.js Revision");
191 | GUILayout.FlexibleSpace ();
192 | threeRevision = EditorGUILayout.Popup(threeRevision, threeRevisions);
193 | GUILayout.EndHorizontal ();
194 |
195 |
196 |
197 | EditorGUILayout.Space ();
198 |
199 | exportCameras = EditorGUILayout.Toggle ("Export Cameras", exportCameras);
200 | exportColliders = EditorGUILayout.Toggle ("Export Colliders", exportColliders);
201 | exportTextures = EditorGUILayout.Toggle ("Export Textures", exportTextures);
202 | exportLightmaps = EditorGUILayout.Toggle ("Export Lightmaps", exportLightmaps);
203 |
204 |
205 | if (exportLightmaps && Lightmapping.giWorkflowMode == Lightmapping.GIWorkflowMode.Iterative) {
206 | cannotContinue = true;
207 | EditorGUILayout.HelpBox ("Please turn off Auto Baking and rebake the scene once in order for me to access the lightmaps.", MessageType.Error);
208 |
209 | GUILayout.BeginHorizontal ();
210 | GUILayout.FlexibleSpace ();
211 | if (GUILayout.Button ("Turn off Auto Baking")) {
212 | Lightmapping.giWorkflowMode = Lightmapping.GIWorkflowMode.OnDemand;
213 | Lightmapping.BakeAsync ();
214 | }
215 | GUILayout.EndHorizontal ();
216 | }
217 |
218 |
219 | exportLights = EditorGUILayout.Toggle ("Export Lights", exportLights);
220 | if (exportLights) {
221 | EditorGUILayout.HelpBox ("Lights that are only used for lightmapping will not be exported. Check the Baking property of your lights and change it to Mixed if you do want them.", MessageType.Info);
222 | }
223 |
224 | exportAmbientLight = EditorGUILayout.Toggle ("Export Ambient Light", exportAmbientLight);
225 | if (exportAmbientLight) {
226 | EditorGUILayout.HelpBox ("An ambient light will be exported with the Ambient Color set in your scene's Lighting Settings.", MessageType.Info);
227 | }
228 |
229 | exportScripts = EditorGUILayout.Toggle ("Export Script Properties", exportScripts);
230 | if (exportScripts) {
231 | EditorGUILayout.HelpBox ("If your Gameobjects contain Scripts, I will export their public properties. I will take all public properties of each script and put them in the userData field of the object. The actual scripts will not be exported.", MessageType.Info);
232 | }
233 |
234 | includeInactiveObjects = EditorGUILayout.Toggle ("Include Inactive Objects", includeInactiveObjects);
235 |
236 | EditorGUILayout.Space ();
237 |
238 | advancedSettings = EditorGUILayout.BeginToggleGroup ("Advanced Settings", advancedSettings);
239 |
240 | lightMapRGBMConstant = EditorGUILayout.FloatField ("Lightmap Contrast", lightMapRGBMConstant);
241 | EditorGUILayout.HelpBox ("In order to convert Unity lightmaps to Three.js, I have to create PNG's from Unity's EXR format. This may cause the resulting PNG lightmaps to look slightly different. Adjust this constant to tweak the contrast of your exported PNG lightmaps. Lower values make your lightmaps darker, higher values make them brighter.", MessageType.Info);
242 |
243 | decimalPlaces = EditorGUILayout.IntField ("Decimal Places", decimalPlaces);
244 | EditorGUILayout.HelpBox ("I will round all position, rotation and scale vectors using these given decimal places. A lower value results in a lighter file but may cause the model to look inaccurate. ", MessageType.Info);
245 |
246 | EditorGUILayout.EndToggleGroup ();
247 |
248 | GUILayout.BeginHorizontal ();
249 | EditorGUILayout.LabelField ("Open Target Folder After Exporting");
250 | GUILayout.FlexibleSpace ();
251 | openFolderAfterExporting = EditorGUILayout.Toggle (openFolderAfterExporting);
252 | GUILayout.EndHorizontal ();
253 | }
254 | EditorGUILayout.EndScrollView();
255 | EditorGUILayout.EndVertical();
256 |
257 | if (cannotContinue) {
258 | GUI.enabled = false;
259 | }
260 | if (GUILayout.Button ("Export")) {
261 | Export();
262 | }
263 | GUI.enabled = true;
264 | }
265 | }
266 | }
--------------------------------------------------------------------------------
/ThreeExporter/code/Core.cs:
--------------------------------------------------------------------------------
1 | // Three.js Exporter for Unity
2 | // http://threejsexporter.nickjanssen.com/
3 | // Written by Nick Janssen - info@nickjanssen.com
4 |
5 | using UnityEngine;
6 | using UnityEditor;
7 | using System;
8 | using System.Text;
9 | using System.IO;
10 | using System.Collections;
11 | using System.Collections.Generic;
12 | using System.Reflection;
13 |
14 |
15 | namespace Three {
16 | public class Core {
17 |
18 | List commonTextures = new List
19 | { "_MainTex", "_BumpMap", "_OcclusionMap" };
20 |
21 | string GetValidFileNameFromString(string file) {
22 | Array.ForEach(Path.GetInvalidFileNameChars(),
23 | c => file = file.Replace(c.ToString(), String.Empty));
24 |
25 | return file;
26 | }
27 |
28 | public bool CopyTextures(Transform[] transforms, Settings settings) {
29 |
30 | Dictionary usedMaterials = new Dictionary ();
31 |
32 | foreach (Transform transform in transforms) {
33 | MeshFilter meshFilter = transform.GetComponent();
34 | if (meshFilter != null) {
35 | Material[] mats = meshFilter.GetComponent().sharedMaterials;
36 |
37 | for (int i=0; i < mats.Length; i ++) {
38 | Material mat = mats[i];
39 |
40 | if (!mat) {
41 | continue;
42 | }
43 |
44 | if (!usedMaterials.ContainsValue(mat)) {
45 | usedMaterials.Add(System.Guid.NewGuid().ToString(), mat);
46 | }
47 | }
48 | }
49 | }
50 |
51 |
52 | foreach(KeyValuePair entry in usedMaterials) {
53 | commonTextures.ForEach(delegate(String texName) {
54 | if (!entry.Value.HasProperty(texName) || !entry.Value.GetTexture(texName)) return;
55 |
56 | Texture2D tex = (Texture2D) entry.Value.GetTexture(texName);
57 |
58 | var texturePath = AssetDatabase.GetAssetPath(tex);
59 | var textureExtension = System.IO.Path.GetExtension(texturePath).ToLower();
60 |
61 | // var filename = System.IO.Path.GetFileName(texturePath);
62 | // var destFile = System.IO.Path.Combine(settings.saveFolder, filename);
63 | // System.IO.File.Copy(texturePath, destFile, true);
64 | // }
65 | // else {
66 | // else if (textureExtension != ".psd") {
67 | var texturePathPNG = System.IO.Path.ChangeExtension(texturePath, ".png");
68 | var texturePathJPG = System.IO.Path.ChangeExtension(texturePath, ".jpg");
69 |
70 | var filenamePNG = GetValidFileNameFromString(entry.Value.name) + "_" + System.IO.Path.GetFileName(texturePathPNG);
71 | var filenameJPG = GetValidFileNameFromString(entry.Value.name) + "_" + System.IO.Path.GetFileName(texturePathJPG);
72 |
73 | var destFilePNG = System.IO.Path.Combine(settings.saveFolder, filenamePNG);
74 | var destFileJPG = System.IO.Path.Combine(settings.saveFolder, filenameJPG);
75 |
76 | TextureImporter ti = (TextureImporter) TextureImporter.GetAtPath(texturePath);
77 | // TextureImporterFormat oldformat = ti.textureFormat;
78 | TextureImporterType oldtype = ti.textureType;
79 |
80 | if (texName == "_BumpMap") {
81 | ti.textureType = TextureImporterType.Default;
82 | }
83 |
84 | // ti.textureFormat = TextureImporterFormat.RGBA32;
85 | ti.isReadable = true;
86 |
87 | AssetDatabase.ImportAsset(texturePath);
88 |
89 | if (textureExtension == ".jpg") {
90 | File.WriteAllBytes(destFileJPG, tex.EncodeToJPG());
91 | }
92 | else {
93 | File.WriteAllBytes(destFilePNG, tex.EncodeToPNG());
94 | }
95 |
96 |
97 | ti.textureType = oldtype;
98 | // ti.textureFormat = oldformat;
99 | ti.isReadable = false;
100 | AssetDatabase.ImportAsset(texturePath);
101 |
102 | });
103 | }
104 |
105 | // Copy lightmaps
106 | LightmapData[] lightmaps = UnityEngine.LightmapSettings.lightmaps;
107 | List lightmapTextures = new List();
108 | if (settings.exportLightmaps) {
109 | for (int i = 0; i < lightmaps.Length; i++) {
110 | if (lightmaps [i].lightmapLight) {
111 | lightmapTextures.Add (lightmaps [i].lightmapLight);
112 | }
113 | if (lightmaps [i].lightmapDir) {
114 | lightmapTextures.Add (lightmaps [i].lightmapDir);
115 | }
116 | }
117 | }
118 |
119 |
120 | lightmapTextures.ForEach (delegate(Texture2D tex) {
121 |
122 | var texturePath = AssetDatabase.GetAssetPath (tex);
123 | var texturePathPNG = System.IO.Path.ChangeExtension (texturePath, ".png");
124 |
125 | //System.IO.File.Copy(texturePath, System.IO.Path.Combine(settings.saveFolder, System.IO.Path.GetFileName(texturePath)), true);
126 |
127 | var destFilePNG = System.IO.Path.Combine (settings.saveFolder, System.IO.Path.GetFileName (texturePathPNG));
128 |
129 | TextureImporter ti = (TextureImporter)TextureImporter.GetAtPath (texturePath);
130 | // TextureImporterFormat oldformat = ti.textureFormat;
131 | TextureImporterType oldType = ti.textureType;
132 | TextureImporterSettings textureImporterSettings = new TextureImporterSettings ();
133 | if (oldType == TextureImporterType.Lightmap) {
134 | ti.textureType = TextureImporterType.Default;
135 | // ti.lightmap = false;
136 |
137 | ti.ReadTextureSettings (textureImporterSettings);
138 | // settings.rgbm = TextureImporterRGBMMode.Off;
139 | ti.SetTextureSettings (textureImporterSettings);
140 | }
141 |
142 | // ti.textureCompression = TextureImporterCompression.Uncompressed;
143 | ti.isReadable = true;
144 | ti.SaveAndReimport ();
145 |
146 | Color[] pix = tex.GetPixels (0, 0, tex.width, tex.height);
147 |
148 | for (int i = 0; i < pix.Length; i++) {
149 | // http://graphicrants.blogspot.jp/2009/04/rgbm-color-encoding.html
150 | pix [i].r *= pix [i].a * settings.lightMapRGBMConstant;
151 | pix [i].g *= pix [i].a * settings.lightMapRGBMConstant;
152 | pix [i].b *= pix [i].a * settings.lightMapRGBMConstant;
153 | }
154 |
155 | Texture2D destTex = new Texture2D (tex.width, tex.height, TextureFormat.RGB24, false);
156 | destTex.hideFlags = HideFlags.HideAndDontSave;
157 | destTex.SetPixels (pix);
158 | destTex.Apply ();
159 |
160 | File.WriteAllBytes (destFilePNG, destTex.EncodeToPNG ());
161 |
162 | GameObject.DestroyImmediate (destTex);
163 |
164 | if (oldType == TextureImporterType.Lightmap) {
165 | ti.textureType = TextureImporterType.Lightmap;
166 |
167 | ti.ReadTextureSettings (textureImporterSettings);
168 | ti.SetTextureSettings (textureImporterSettings);
169 | }
170 |
171 | ti.isReadable = false;
172 | ti.SaveAndReimport ();
173 |
174 | });
175 |
176 | return true;
177 | }
178 |
179 | public struct Submesh {
180 | public MeshFilter meshFilter;
181 | public Mesh mesh;
182 | public int subMeshIndex;
183 | }
184 |
185 | public struct TextureImageLink {
186 | public Texture texture;
187 | public string filename;
188 | }
189 |
190 | public struct MeshMaterialLink {
191 | public MeshFilter meshFilter;
192 | public Material material;
193 | public int subMeshIndex;
194 | }
195 |
196 | public struct MaterialTextureLink {
197 | public Material material;
198 | public Texture texture;
199 | public string textureUnityIdentifier;
200 | public bool needsCleanup;
201 | }
202 |
203 | private StringBuilder jsonFile = new StringBuilder();
204 |
205 | private void writeJSON(int tabs, string content, bool writeNewLine=true) {
206 | for (int i = 0; i < tabs; i++) {
207 | jsonFile.Append("\t");
208 | }
209 | jsonFile.Append(content);
210 | if (writeNewLine) {
211 | jsonFile.Append(System.Environment.NewLine);
212 | }
213 | }
214 |
215 | private void writeMatrix(int tabs, Transform transform, Settings settings) {
216 | writeJSON(tabs, "\"matrix\": [", false);
217 | {
218 | Matrix4x4 m = Matrix4x4.TRS(new Vector3(), Quaternion.identity, new Vector3(-1, 1, 1));
219 | m *= transform.localToWorldMatrix;
220 | m *= Matrix4x4.TRS(new Vector3(), Quaternion.AngleAxis(180, new Vector3(1, 0, 0)), new Vector3(1, 1, 1));
221 | m *= Matrix4x4.TRS(new Vector3(), Quaternion.AngleAxis(90, new Vector3(0, 1, 0)), new Vector3(1, 1, 1));
222 | m *= Matrix4x4.TRS(new Vector3(), Quaternion.identity, new Vector3(1, -1, 1));
223 |
224 | for (int j = 0; j <= 3; j++) {
225 | for (int k = 0; k <= 3; k++) {
226 | float test = m[k,j];
227 | test = (float)Math.Round(test, settings.decimalPlaces);
228 | writeJSON(0, test.ToString(), false);
229 | if (!(j == 3 && k == 3)) {
230 | writeJSON(0, ",", false);
231 | }
232 | }
233 | }
234 | writeJSON(0, "]");
235 | }
236 | }
237 |
238 |
239 | public string ConvertToJSON(Transform[] transforms, Settings settings) {
240 |
241 | Dictionary usedMaterials = new Dictionary ();
242 |
243 | foreach (Transform transform in transforms) {
244 | MeshFilter meshFilter = transform.GetComponent();
245 | if (meshFilter != null) {
246 | Material[] mats = meshFilter.GetComponent().sharedMaterials;
247 |
248 | for (int i=0; i < mats.Length; i ++) {
249 | Material mat = mats[i];
250 |
251 | if (!mat) {
252 | continue;
253 | }
254 |
255 | if (!usedMaterials.ContainsValue(mat)) {
256 | usedMaterials.Add(System.Guid.NewGuid().ToString(), mat);
257 | }
258 | }
259 | }
260 | }
261 |
262 | Dictionary usedSubmeshes = new Dictionary ();
263 |
264 | foreach (Transform transform in transforms) {
265 | MeshFilter meshFilter = transform.GetComponent();
266 | if (meshFilter != null) {
267 | if (meshFilter.sharedMesh == null) {
268 | Debug.LogError("'" + transform.name + "' appears to be missing a mesh! Please verify its mesh filter.", transform);
269 | }
270 | else {
271 | for (int i = 0; i < meshFilter.sharedMesh.subMeshCount; i++) {
272 | Submesh submesh;
273 | submesh.mesh = meshFilter.sharedMesh;
274 | submesh.meshFilter = meshFilter;
275 | submesh.subMeshIndex = i;
276 | usedSubmeshes.Add(System.Guid.NewGuid().ToString(), submesh);
277 | }
278 | }
279 | }
280 | }
281 |
282 | Dictionary meshMaterialLinks = new Dictionary ();
283 | Dictionary usedLightmapTextures = new Dictionary ();
284 | Dictionary usedImages = new Dictionary ();
285 | List addedTextures = new List();
286 |
287 | foreach (Transform transform in transforms) {
288 | MeshFilter meshFilter = transform.GetComponent();
289 | if (meshFilter != null) {
290 | Material[] mats = meshFilter.GetComponent().sharedMaterials;
291 |
292 | for (int i=0; i < mats.Length; i ++) {
293 |
294 | if (!mats[i]) {
295 | Debug.LogError("'" + transform.name + "' has a bad/missing material!", transform);
296 | continue;
297 | }
298 |
299 | MeshMaterialLink meshMaterialLink;
300 |
301 | meshMaterialLink.meshFilter = meshFilter;
302 | meshMaterialLink.material = mats[i];
303 | meshMaterialLink.subMeshIndex = i;
304 |
305 | commonTextures.ForEach(delegate(String texName) {
306 |
307 | if ( !meshMaterialLink.material.HasProperty(texName) ) return;
308 |
309 | Texture tex = meshMaterialLink.material.GetTexture(texName);
310 | if (tex != null && !addedTextures.Contains(tex)) {
311 |
312 | // MaterialTextureLink materialTextureLink;
313 | // materialTextureLink.texture = tex;
314 | // materialTextureLink.material = meshMaterialLink.material;
315 | // materialTextureLink.textureUnityIdentifier = texName;
316 | // materialTextureLink.needsCleanup = false;
317 |
318 | TextureImageLink textureImageLink;
319 | textureImageLink.texture = tex;
320 | string texturePath = AssetDatabase.GetAssetPath(tex);
321 |
322 | var textureExtension = System.IO.Path.GetExtension(texturePath).ToLower();
323 | if (textureExtension != ".png" && textureExtension != ".jpg") {
324 | // Other textures get converted to png automatically
325 | texturePath = System.IO.Path.ChangeExtension (texturePath, ".png");
326 | }
327 |
328 | textureImageLink.filename = GetValidFileNameFromString(meshMaterialLink.material.name) + "_" +System.IO.Path.GetFileName(texturePath);
329 |
330 | addedTextures.Add(tex);
331 | // usedTextures.Add(System.Guid.NewGuid().ToString(), materialTextureLink);
332 | usedImages.Add(System.Guid.NewGuid().ToString(), textureImageLink);
333 | }
334 | });
335 |
336 | meshMaterialLinks.Add(System.Guid.NewGuid().ToString(), meshMaterialLink);
337 |
338 | }
339 | }
340 | }
341 |
342 | // Add lightmaps
343 | LightmapData[] lightmapData = UnityEngine.LightmapSettings.lightmaps;
344 | if (settings.exportLightmaps) {
345 | for (int i = 0; i < lightmapData.Length; i++) {
346 | if (lightmapData [i].lightmapLight) {
347 | TextureImageLink textureImageLink;
348 | textureImageLink.texture = lightmapData [i].lightmapLight;
349 |
350 | string texturePath = AssetDatabase.GetAssetPath (lightmapData [i].lightmapLight);
351 | string texturePathPNG = System.IO.Path.ChangeExtension (texturePath, ".png");
352 | textureImageLink.filename = System.IO.Path.GetFileName (texturePathPNG);
353 |
354 | Material lightMapMaterial = new Material (Shader.Find ("Diffuse"));
355 | lightMapMaterial.hideFlags = HideFlags.HideAndDontSave;
356 | MaterialTextureLink materialTextureLink;
357 | materialTextureLink.texture = textureImageLink.texture;
358 | lightMapMaterial.name = "lightmap";
359 | lightMapMaterial.SetTexture ("_MainTex", materialTextureLink.texture);
360 | materialTextureLink.material = lightMapMaterial;
361 | materialTextureLink.textureUnityIdentifier = "_MainTex";
362 | materialTextureLink.needsCleanup = true;
363 |
364 | usedLightmapTextures.Add (System.Guid.NewGuid ().ToString (), materialTextureLink);
365 |
366 | usedImages.Add (System.Guid.NewGuid ().ToString (), textureImageLink);
367 | }
368 |
369 | if (lightmapData [i].lightmapDir) {
370 | TextureImageLink textureImageLink;
371 | textureImageLink.texture = lightmapData [i].lightmapDir;
372 |
373 | string texturePath = AssetDatabase.GetAssetPath (lightmapData [i].lightmapDir);
374 | string texturePathPNG = System.IO.Path.ChangeExtension (texturePath, ".png");
375 | textureImageLink.filename = System.IO.Path.GetFileName (texturePathPNG);
376 |
377 | usedImages.Add (System.Guid.NewGuid ().ToString (), textureImageLink);
378 | }
379 | }
380 | }
381 |
382 | jsonFile.Length = 0;
383 |
384 | writeJSON (0, "{");
385 |
386 | // Metadata
387 | writeJSON (1, "\"metadata\": {");
388 | {
389 |
390 | writeJSON(2, "\"version\": \"" + 4.3f + "\",");
391 | writeJSON(2, "\"type\": " + "\"Object\",");
392 | writeJSON(2, "\"generator\": " + "\"UnityThreeExporter\"");
393 |
394 | }
395 |
396 | writeJSON (1, "},");
397 |
398 | // Geometries
399 | writeJSON (1, "\"geometries\": [");
400 | {
401 | int count = 0;
402 | foreach(KeyValuePair entry in usedSubmeshes) {
403 |
404 | writeJSON (2, "{");
405 |
406 | int[] subMeshTriangles = entry.Value.mesh.GetTriangles(entry.Value.subMeshIndex);
407 | // List subMeshTrianglesList = new List(subMeshTriangles);
408 |
409 | writeJSON(3, "\"uuid\": \"" + entry.Key + "\", ");
410 | writeJSON(3, "\"type\": \"" + "Geometry" + "\", ");
411 |
412 | int lowestFaceIndex = int.MaxValue;
413 | for (int i = 0; i < subMeshTriangles.Length; i++) {
414 | if (subMeshTriangles[i] < lowestFaceIndex) {
415 | lowestFaceIndex = subMeshTriangles[i];
416 | }
417 | }
418 |
419 | int highestFaceIndex = -1;
420 | for (int i = 0; i < subMeshTriangles.Length; i++) {
421 | if (subMeshTriangles[i] > highestFaceIndex) {
422 | highestFaceIndex = subMeshTriangles[i];
423 | }
424 | }
425 |
426 | writeJSON(3, "\"data\": {");
427 | {
428 |
429 | writeJSON(4, "\"vertices\": [", false);
430 | {
431 | for (int i = lowestFaceIndex; i <= highestFaceIndex; i++) {
432 | Vector3 vertex = entry.Value.mesh.vertices[i];
433 | writeJSON(0, Math.Round(vertex.z, settings.decimalPlaces) + ",", false);
434 | writeJSON(0, Math.Round(vertex.y, settings.decimalPlaces) + ",", false);
435 | writeJSON(0, Math.Round(vertex.x, settings.decimalPlaces) + ((i < highestFaceIndex) ? "," : ""), false);
436 | }
437 | }
438 | writeJSON(0, "],");
439 |
440 | writeJSON(4, "\"normals\": [", false);
441 | {
442 | if (entry.Value.mesh.normals.Length > 0) {
443 | for (int i = lowestFaceIndex; i <= highestFaceIndex; i++) {
444 | Vector3 normal = entry.Value.mesh.normals[i];
445 | writeJSON(0, Math.Round(normal.z, settings.decimalPlaces) + ",", false);
446 | writeJSON(0, Math.Round(normal.y, settings.decimalPlaces) + ",", false);
447 | writeJSON(0, Math.Round(normal.x, settings.decimalPlaces) + ((i < highestFaceIndex) ? "," : ""), false);
448 | }
449 | }
450 | }
451 | writeJSON(0, "],");
452 |
453 | writeJSON(4, "\"uvs\": [", false);
454 | {
455 | Vector2[] meshUv1 = entry.Value.mesh.uv;
456 | Vector2[] meshUv2 = entry.Value.mesh.uv2;
457 |
458 | if (entry.Value.meshFilter.GetComponent().lightmapIndex >= 0 &&
459 | meshUv2.Length == 0) {
460 | meshUv2 = (Vector2[]) meshUv1.Clone();
461 | }
462 |
463 | // Alter lightmaps
464 | if (entry.Value.meshFilter.GetComponent().lightmapIndex >= 0) {
465 | if (entry.Value.mesh.uv2.Length > 0) {
466 | for (int i = lowestFaceIndex; i <= highestFaceIndex; i++) {
467 | meshUv2[i].x *= entry.Value.meshFilter.GetComponent().lightmapScaleOffset.x;
468 | meshUv2[i].y *= entry.Value.meshFilter.GetComponent().lightmapScaleOffset.y;
469 |
470 | meshUv2[i].x += entry.Value.meshFilter.GetComponent().lightmapScaleOffset.z;
471 | meshUv2[i].y += entry.Value.meshFilter.GetComponent().lightmapScaleOffset.w;
472 | }
473 | }
474 | else {
475 | for (int i = lowestFaceIndex; i <= highestFaceIndex; i++) {
476 | meshUv1[i].x *= entry.Value.meshFilter.GetComponent().lightmapScaleOffset.x;
477 | meshUv1[i].y *= entry.Value.meshFilter.GetComponent().lightmapScaleOffset.y;
478 |
479 | meshUv1[i].x += entry.Value.meshFilter.GetComponent().lightmapScaleOffset.z;
480 | meshUv1[i].y += entry.Value.meshFilter.GetComponent().lightmapScaleOffset.w;
481 | }
482 | }
483 | }
484 |
485 | writeJSON(0, "[", false);
486 | {
487 | if (meshUv1.Length > 0) {
488 | for (int i = lowestFaceIndex; i <= highestFaceIndex; i++) {
489 | Vector3 uv = meshUv1[i];
490 | writeJSON(0, uv.x + ",", false);
491 | writeJSON(0, uv.y + ((i < highestFaceIndex) ? "," : ""), false);
492 | }
493 | }
494 | }
495 | writeJSON(0, "],", false);
496 |
497 |
498 | writeJSON(0, "[", false);
499 | {
500 | int lightmapIndex = entry.Value.meshFilter.GetComponent().lightmapIndex;
501 | if (entry.Value.mesh.uv2.Length > 0) {
502 | for (int i = lowestFaceIndex; i <= highestFaceIndex; i++) {
503 | Vector3 uv = meshUv2[i];
504 | writeJSON(0, uv.x + ",", false);
505 | writeJSON(0, uv.y + ((i < highestFaceIndex) ? "," : ""), false);
506 | }
507 | }
508 | else if (entry.Value.meshFilter.GetComponent().lightmapIndex >= 0 &&
509 | entry.Value.mesh.uv2.Length == 0) {
510 | for (int i = lowestFaceIndex; i <= highestFaceIndex; i++) {
511 | Vector3 uv = meshUv1[i];
512 | writeJSON(0, uv.x + ",", false);
513 | writeJSON(0, uv.y + ((i < highestFaceIndex) ? "," : ""), false);
514 | }
515 | }
516 | }
517 | writeJSON(0, "]", false);
518 |
519 | }
520 | writeJSON(0, "],");
521 |
522 | writeJSON(4, "\"faces\": [", false);
523 | {
524 |
525 | for (int i = 0; i < subMeshTriangles.Length; i++) {
526 | subMeshTriangles[i] = subMeshTriangles[i] - lowestFaceIndex;
527 | }
528 |
529 | int[] triangles = subMeshTriangles;
530 | for (int j = 0; j < triangles.Length; j += 3) {
531 |
532 | writeJSON(0, 8 + ",", false);
533 |
534 | writeJSON(0, triangles[j+2] + ",", false);
535 | writeJSON(0, triangles[j+1] + ",", false);
536 | writeJSON(0, triangles[j].ToString(), false);
537 |
538 | if (entry.Value.mesh.uv.Length > 0) {
539 | writeJSON(0, ",", false);
540 | writeJSON(0, triangles[j+2] + ",", false);
541 | writeJSON(0, triangles[j+1] + ",", false);
542 | writeJSON(0, triangles[j].ToString(), false);
543 | }
544 |
545 | if (entry.Value.mesh.uv2.Length > 0 ||
546 | (entry.Value.meshFilter.GetComponent().lightmapIndex >= 0 &&
547 | entry.Value.mesh.uv2.Length == 0)) {
548 | writeJSON(0, ",", false);
549 | writeJSON(0, triangles[j+2] + ",", false);
550 | writeJSON(0, triangles[j+1] + ",", false);
551 | writeJSON(0, triangles[j].ToString(), false);
552 | }
553 |
554 | writeJSON(0, ((j < triangles.Length - 3) ? "," : ""), false);
555 |
556 | }
557 |
558 | }
559 | writeJSON(0, "]");
560 | }
561 | writeJSON (3, "}");
562 |
563 |
564 | writeJSON (2, "}", false);
565 |
566 | if (count < usedSubmeshes.Count - 1) {
567 | writeJSON (0, ",");
568 | }
569 | else {
570 | writeJSON (0, "");
571 | }
572 |
573 | count++;
574 | }
575 | }
576 | writeJSON (1, "],");
577 |
578 | // Materials
579 | writeJSON (1, "\"materials\": [");
580 | {
581 | int count = 0;
582 | foreach(KeyValuePair meshMaterialLink in meshMaterialLinks) {
583 |
584 | writeJSON (2, "{");
585 |
586 | Material mat = meshMaterialLink.Value.material;
587 |
588 | writeJSON(3, "\"uuid\": \"" + meshMaterialLink.Key + "\",");
589 | writeJSON(3, "\"name\": \"" + mat.name + "\", ");
590 |
591 | writeJSON(3, "\"type\": \"" + "MeshPhongMaterial" + "\",");
592 |
593 | if (meshMaterialLink.Value.material.HasProperty("_Color")) {
594 | writeJSON(3, "\"color\": \"" + "0x" + Util.ColorToHex(meshMaterialLink.Value.material.GetColor("_Color")) + "\",");
595 | }
596 |
597 | if (meshMaterialLink.Value.material.HasProperty("_SpecColor")) {
598 | writeJSON(3, "\"specular\": \"" + "0x" + Util.ColorToHex(meshMaterialLink.Value.material.GetColor("_SpecColor")) + "\",");
599 | }
600 | if (meshMaterialLink.Value.material.HasProperty("_EmissionColor")) {
601 | writeJSON(3, "\"emissive\": \"" + "0x" + Util.ColorToHex(meshMaterialLink.Value.material.GetColor("_EmissionColor")) + "\",");
602 | }
603 |
604 | if (meshMaterialLink.Value.material.HasProperty("_Shininess")) {
605 | writeJSON(3, "\"shininess\": " + meshMaterialLink.Value.material.GetFloat("_Shininess") + ",");
606 | }
607 |
608 | if (meshMaterialLink.Value.material.HasProperty("_Color")) {
609 | writeJSON(3, "\"opacity\": " + (meshMaterialLink.Value.material.GetColor("_Color").a) + ",");
610 | }
611 |
612 | string mapId = null;
613 | string normalMapId = null;
614 | string aoMapId = null;
615 |
616 | foreach(KeyValuePair usedMaterial in usedMaterials) {
617 | if (usedMaterial.Value == mat) {
618 | if (mat.HasProperty("_MainTex") &&
619 | mat.GetTexture ("_MainTex")) {
620 | mapId = usedMaterial.Key + "_MainTex";
621 | }
622 | if (mat.HasProperty("_BumpMap") &&
623 | mat.GetTexture ("_BumpMap")) {
624 | normalMapId = usedMaterial.Key + "_BumpMap";
625 | }
626 | if (mat.HasProperty("_OcclusionMap") &&
627 | mat.GetTexture ("_OcclusionMap")) {
628 | aoMapId = usedMaterial.Key + "_OcclusionMap";
629 | }
630 | }
631 | }
632 |
633 |
634 | if (mapId != null) {
635 | writeJSON(3, "\"map\": \"" + mapId + "\",");
636 | }
637 | if (normalMapId != null) {
638 | writeJSON(3, "\"normalMap\": \"" + normalMapId + "\",");
639 | }
640 | if (aoMapId != null) {
641 | writeJSON(3, "\"aoMap\": \"" + aoMapId + "\",");
642 | }
643 |
644 | // Add lightmaps
645 | // Problem is that in Unity, lightmaps are per object while in ThreeJS
646 | // they are per material. Because of this, we have create a separate material for each object.
647 | int lightmapIndex = meshMaterialLink.Value.meshFilter.GetComponent().lightmapIndex;
648 |
649 | // Only if the object is lightmapped
650 | if (lightmapIndex >= 0) {
651 | LightmapData usedLightMap = lightmapData[lightmapIndex];
652 |
653 | foreach(KeyValuePair usedTexture in usedLightmapTextures) {
654 | if (usedTexture.Value.texture == usedLightMap.lightmapLight) {
655 | writeJSON(3, "\"lightMap\": \"" + usedTexture.Key + "_MainTex\",");
656 | }
657 | }
658 | }
659 |
660 | bool transparent = false;
661 | if (meshMaterialLink.Value.material.HasProperty("_Mode") &&
662 | meshMaterialLink.Value.material.GetFloat("_Mode") != 0) {
663 | transparent = true;
664 | }
665 | else if (meshMaterialLink.Value.material.shader.name.Contains("Transparent")) {
666 | transparent = true;
667 | }
668 |
669 | if (meshMaterialLink.Value.material.shader.name.Contains("Additive")) {
670 | transparent = true;
671 | writeJSON(3, "\"blending\": 2,");
672 | }
673 |
674 | writeJSON(3, "\"transparent\": " + ((transparent) ? "true" : "false") + ",");
675 |
676 | bool wireframe = false;
677 | writeJSON(3, "\"wireframe\": " + ((wireframe) ? "true" : "false"));
678 |
679 | writeJSON (2, "}", false);
680 |
681 | if (count < meshMaterialLinks.Count - 1) {
682 | writeJSON (0, ",");
683 | }
684 | else {
685 | writeJSON (0, "");
686 | }
687 |
688 | count++;
689 |
690 | }
691 |
692 | }
693 | writeJSON (1, "],");
694 |
695 |
696 | writeJSON (1, "\"object\": {");
697 | // Objects
698 | {
699 | writeJSON(2, "\"uuid\": \"" + System.Guid.NewGuid().ToString() + "\",");
700 | writeJSON(2, "\"type\": \"" + "Object3D" + "\",");
701 | writeJSON(2, "\"name\": \"" + "World" + "\",");
702 |
703 | writeJSON(2, "\"matrix\": [", false);
704 | {
705 | Matrix4x4 m = Matrix4x4.identity;
706 |
707 | for (int j = 0; j <= 3; j++) {
708 | for (int k = 0; k <= 3; k++) {
709 | float test = m[k,j];
710 | test = (float)Math.Round(test, settings.decimalPlaces);
711 | writeJSON(0, test.ToString(), false);
712 | if (!(j == 3 && k == 3)) {
713 | writeJSON(0, ",", false);
714 | }
715 | }
716 | }
717 | }
718 | writeJSON(0, "],");
719 |
720 | writeJSON(2, "\"children\": [");
721 |
722 | if (settings.exportAmbientLight) {
723 | // Add ambient light
724 | writeJSON(3, "{");
725 | {
726 | writeJSON(4, "\"uuid\": \"" + System.Guid.NewGuid().ToString() + "\",");
727 | writeJSON(4, "\"type\": \"" + "AmbientLight" + "\",");
728 | writeJSON(4, "\"color\": \"" + "#" + Util.ColorToHex(RenderSettings.ambientLight) + "\",");
729 | writeJSON(4, "\"name\": \"RenderSettingsAmbientLight\"");
730 | }
731 | writeJSON(3, "},", true);
732 | }
733 |
734 | int transformsThatWillBeWritten = 0;
735 | foreach (Transform transform in transforms) {
736 |
737 | if (settings.exportCameras) {
738 | Camera camera = transform.GetComponent();
739 | if (camera != null) {
740 | writeJSON(3, "{");
741 |
742 | {
743 | writeJSON(4, "\"uuid\": \"" + System.Guid.NewGuid().ToString() + "\",");
744 | writeJSON(4, "\"type\": \"" + "PerspectiveCamera" + "\",");
745 | writeJSON(4, "\"name\": \"" + transform.name + "\",");
746 | writeJSON(4, "\"fov\": \"" + camera.fieldOfView.ToString() + "\",");
747 | writeJSON(4, "\"aspect\": \"" + camera.aspect.ToString() + "\",");
748 | writeJSON(4, "\"near\": \"" + camera.nearClipPlane.ToString() + "\",");
749 | writeJSON(4, "\"far\": \"" + camera.farClipPlane.ToString() + "\", ");
750 |
751 | writeMatrix(4, transform, settings);
752 | }
753 |
754 | writeJSON(3, "},", true);
755 |
756 | transformsThatWillBeWritten++;
757 | }
758 | }
759 |
760 | if (settings.exportLights) {
761 | Light light = transform.GetComponent();
762 | if (light != null) {
763 | if (light.type == LightType.Directional || light.type == LightType.Point || light.type == LightType.Spot) {
764 |
765 | SerializedObject serialObj = new SerializedObject(light);
766 | SerializedProperty lightmapProp = serialObj.FindProperty("m_Lightmapping");
767 |
768 | // Debug.Log ("m_Lightmapping");
769 | // Debug.Log (lightmapProp.intValue);
770 |
771 | // Only add the lights if they are set to something else than Baked Only
772 | if (lightmapProp.intValue != 2) {
773 | writeJSON(3, "{");
774 |
775 | {
776 | writeJSON(4, "\"uuid\": \"" + System.Guid.NewGuid().ToString() + "\",");
777 |
778 | if (light.type == LightType.Directional) {
779 | writeJSON(4, "\"type\": \"" + "DirectionalLight" + "\",");
780 | }
781 |
782 | if (light.type == LightType.Point) {
783 | writeJSON(4, "\"type\": \"" + "PointLight" + "\",");
784 | }
785 |
786 | if (light.type == LightType.Spot) {
787 | writeJSON(4, "\"type\": \"" + "SpotLight" + "\",");
788 | writeJSON(4, "\"distance\": " + light.range + ",");
789 | writeJSON(4, "\"angle\": " + light.spotAngle + ",");
790 | }
791 |
792 |
793 | // THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay );
794 |
795 |
796 | writeJSON(4, "\"color\": \"" + "#" + Util.ColorToHex(light.color) + "\",");
797 |
798 | writeJSON(4, "\"name\": \"" + transform.name + "\",");
799 | writeJSON(4, "\"intensity\": " + light.intensity.ToString() + ",");
800 |
801 | writeMatrix(4, transform, settings);
802 | }
803 |
804 | writeJSON(3, "},", true);
805 |
806 | transformsThatWillBeWritten++;
807 | }
808 | }
809 | }
810 | }
811 |
812 |
813 | writeJSON(3, "{");
814 |
815 | writeJSON(4, "\"uuid\": \"" + System.Guid.NewGuid().ToString() + "\",");
816 | writeJSON(4, "\"type\": \"" + "Object3D" + "\",");
817 | writeJSON(4, "\"name\": \"" + transform.name + "\",");
818 |
819 |
820 | if ((settings.exportColliders && transform.GetComponent() != null) ||
821 | (transform.GetComponent() != null) ||
822 | (settings.exportScripts && transform.GetComponent() != null)) {
823 |
824 | writeJSON(4, "\"children\": [");
825 |
826 | bool hasWrittenChildren = false;
827 |
828 | if (settings.exportColliders) {
829 | Collider collider = transform.GetComponent();
830 | if (collider != null) {
831 | hasWrittenChildren = true;
832 | writeJSON(5, "{");
833 |
834 | {
835 | writeJSON(6, "\"uuid\": \"" + System.Guid.NewGuid().ToString() + "\",");
836 | writeJSON(6, "\"name\": \"" + transform.name + "_Collider\",");
837 | writeJSON(6, "\"type\": \"" + "Object3D" + "\",");
838 |
839 | writeJSON(6, "\"userData\": {");
840 |
841 |
842 | BoxCollider boxCollider = transform.GetComponent();
843 | if (boxCollider != null) {
844 | writeJSON(7, "\"type\": \"" + "BoxCollider" + "\",");
845 | }
846 |
847 | SphereCollider sphereCollider = transform.GetComponent();
848 | if (sphereCollider != null) {
849 | writeJSON(7, "\"type\": \"" + "SphereCollider" + "\",");
850 | }
851 |
852 | MeshCollider meshCollider = transform.GetComponent();
853 | if (meshCollider != null) {
854 | writeJSON(7, "\"type\": \"" + "MeshCollider" + "\"");
855 | // NO COMMA!
856 | }
857 |
858 | CapsuleCollider capsuleCollider = transform.GetComponent();
859 | if (capsuleCollider != null) {
860 | writeJSON(7, "\"type\": \"" + "CapsuleCollider" + "\",");
861 | }
862 |
863 |
864 | {
865 | if (boxCollider != null) {
866 |
867 | Vector3 adjustedCenter = boxCollider.center;
868 |
869 | //adjustedCenter.x *= -1;
870 |
871 | string[] center = {adjustedCenter.z.ToString(),
872 | adjustedCenter.y.ToString(),
873 | adjustedCenter.x.ToString()};
874 |
875 | writeJSON(7, "\"center\": " + Util.ToJSONArray(center) + ",");
876 |
877 | string[] size = {boxCollider.size.z.ToString(),
878 | boxCollider.size.y.ToString(),
879 | boxCollider.size.x.ToString()};
880 |
881 | writeJSON(7, "\"size\": " + Util.ToJSONArray(size) + "");
882 | }
883 | }
884 | {
885 | if (sphereCollider != null) {
886 |
887 | Vector3 adjustedCenter = sphereCollider.center;
888 |
889 | //adjustedCenter.x *= -1;
890 |
891 | string[] center = {adjustedCenter.z.ToString(),
892 | adjustedCenter.y.ToString(),
893 | adjustedCenter.x.ToString()};
894 |
895 |
896 | writeJSON(7, "\"center\": " + Util.ToJSONArray(center) + ",");
897 | writeJSON(7, "\"radius\": " + sphereCollider.radius.ToString() + "");
898 | }
899 | }
900 | {
901 | if (capsuleCollider != null) {
902 |
903 | Vector3 adjustedCenter = capsuleCollider.center;
904 |
905 | //adjustedCenter.x *= -1;
906 |
907 | string[] center = {adjustedCenter.z.ToString(),
908 | adjustedCenter.y.ToString(),
909 | adjustedCenter.x.ToString()};
910 |
911 | writeJSON(7, "\"center\": " + Util.ToJSONArray(center) + ",");
912 | writeJSON(7, "\"radius\": " + capsuleCollider.radius.ToString() + ",");
913 | writeJSON(7, "\"height\": " + capsuleCollider.height.ToString() + "");
914 | }
915 | }
916 | writeJSON(6, "}");
917 | }
918 |
919 | writeJSON(5, "},", true);
920 |
921 | }
922 | }
923 |
924 | MeshFilter meshFilter = transform.GetComponent();
925 | if (meshFilter != null && meshFilter.sharedMesh != null) {
926 |
927 | for (int i = 0; i < meshFilter.sharedMesh.subMeshCount; i++) {
928 |
929 | string geoKey = null;
930 | foreach(KeyValuePair usedSubmesh in usedSubmeshes) {
931 | if (usedSubmesh.Value.meshFilter == meshFilter && usedSubmesh.Value.subMeshIndex == i) {
932 | geoKey = usedSubmesh.Key;
933 | }
934 | }
935 |
936 | string matKey = null;
937 | foreach(KeyValuePair meshMaterialLink in meshMaterialLinks) {
938 | if (meshMaterialLink.Value.meshFilter == meshFilter && i == meshMaterialLink.Value.subMeshIndex) {
939 | matKey = meshMaterialLink.Key;
940 | }
941 | }
942 |
943 | if (geoKey != null && matKey != null ) {
944 | hasWrittenChildren = true;
945 | writeJSON(5, "{");
946 | {
947 | writeJSON(6, "\"uuid\": \"" + System.Guid.NewGuid().ToString() + "\",");
948 | writeJSON(6, "\"type\": \"" + "Mesh" + "\",");
949 | writeJSON(6, "\"name\": \"" + meshFilter.name + "_SubMesh " + i + "\",");
950 |
951 | foreach(KeyValuePair usedSubmesh in usedSubmeshes) {
952 | if (usedSubmesh.Value.meshFilter == meshFilter && usedSubmesh.Value.subMeshIndex == i) {
953 | writeJSON(6, "\"geometry\": \"" + geoKey + "\",");
954 |
955 |
956 |
957 | foreach(KeyValuePair meshMaterialLink in meshMaterialLinks) {
958 | if (meshMaterialLink.Value.meshFilter == meshFilter && i == meshMaterialLink.Value.subMeshIndex) {
959 | writeJSON(6, "\"material\": \"" + matKey + "\",");
960 | break;
961 | }
962 | }
963 |
964 | break;
965 | }
966 | }
967 |
968 |
969 | writeJSON(6, "\"userdata\": {}");
970 |
971 |
972 |
973 | }
974 | writeJSON(5, "},", true);
975 | }
976 |
977 | }
978 | }
979 |
980 | MonoBehaviour monoBehaviour = transform.GetComponent();
981 | if (monoBehaviour != null) {
982 | hasWrittenChildren = true;
983 |
984 | writeJSON(5, "{");
985 | {
986 | writeJSON(6, "\"uuid\": \"" + System.Guid.NewGuid().ToString() + "\",");
987 | writeJSON(6, "\"type\": \"" + "Object3D" + "\",");
988 | writeJSON(6, "\"name\": \"" + monoBehaviour.name + "_Script\",");
989 |
990 | writeJSON(6, "\"userData\": {");
991 |
992 | {
993 | const BindingFlags flags = /*BindingFlags.NonPublic | */BindingFlags.Public |
994 | BindingFlags.Instance | BindingFlags.Static;
995 | FieldInfo[] fields = monoBehaviour.GetType().GetFields(flags);
996 | foreach (FieldInfo fieldInfo in fields)
997 | {
998 | object fieldObj = fieldInfo.GetValue(monoBehaviour);
999 | if (fieldObj != null) {
1000 | string fieldValue = fieldObj.ToString();
1001 | // if (fieldInfo.FieldType == typeof(float) ||
1002 | // fieldInfo.FieldType == typeof(int) ||
1003 | // fieldInfo.FieldType == typeof(double)) {
1004 | double n;
1005 | bool needQuotes = !double.TryParse(fieldValue, out n);
1006 |
1007 | if (fieldValue == "True" || fieldValue == "False") {
1008 | fieldValue = fieldValue.ToLower();
1009 | needQuotes = false;
1010 | }
1011 |
1012 | if (!needQuotes) {
1013 | writeJSON(7, "\"" + fieldInfo.Name + "\": " + fieldValue + ",");
1014 | }
1015 | else {
1016 | writeJSON(7, "\"" + fieldInfo.Name + "\": \"" + fieldValue + "\",");
1017 | }
1018 | }
1019 | }
1020 |
1021 | writeJSON(7, "\"type\": \"" + "Script" + "\"");
1022 |
1023 | }
1024 | writeJSON(6, "}");
1025 | }
1026 | writeJSON(5, "},", true);
1027 |
1028 |
1029 | }
1030 |
1031 | if (hasWrittenChildren) {
1032 | jsonFile.Length = jsonFile.Length - (1 + System.Environment.NewLine.Length);
1033 | writeJSON (0, "", true);
1034 | }
1035 |
1036 | writeJSON(4, "],");
1037 |
1038 | }//s
1039 |
1040 | writeMatrix(4, transform, settings);
1041 |
1042 | writeJSON(3, "},", true);
1043 | transformsThatWillBeWritten++;
1044 |
1045 | }
1046 |
1047 |
1048 |
1049 | // Remove the final comma
1050 | if (transformsThatWillBeWritten > 0) {
1051 | jsonFile.Length = jsonFile.Length - (1 + System.Environment.NewLine.Length);
1052 | writeJSON(0, "", true);
1053 | }
1054 |
1055 | writeJSON (2, "]");
1056 | }
1057 | writeJSON (1, "},");
1058 |
1059 | // Images
1060 | writeJSON (1, "\"images\": [");
1061 | {
1062 | int count = 0;
1063 | foreach(KeyValuePair entry in usedImages) {
1064 | writeJSON (2, "{");
1065 |
1066 | writeJSON(3, "\"url\": \"" + entry.Value.filename + "\",");
1067 | writeJSON(3, "\"uuid\": \"" + entry.Key + "\",");
1068 | writeJSON(3, "\"name\": \"" + entry.Value.filename + "\",");
1069 | writeJSON(3, "\"originalUrl\": \"" + entry.Value.filename + "\"");
1070 |
1071 | writeJSON (2, "}", false);
1072 |
1073 | if (count < usedImages.Count - 1) {
1074 | writeJSON (0, ",");
1075 | }
1076 | else {
1077 | writeJSON (0, "");
1078 | }
1079 |
1080 | count++;
1081 | }
1082 | }
1083 | writeJSON (1, "],");
1084 |
1085 | // Textures
1086 | writeJSON (1, "\"textures\": [");
1087 | {
1088 | int count = 0;
1089 |
1090 |
1091 | foreach(KeyValuePair usedTexture in usedLightmapTextures) {
1092 | // Quickly mix in the remaining lightmap textures
1093 | usedMaterials.Add(usedTexture.Key, usedTexture.Value.material);
1094 | }
1095 |
1096 |
1097 | foreach(KeyValuePair usedMaterial in usedMaterials) {
1098 |
1099 | commonTextures.ForEach (delegate(String texName) {
1100 | if (usedMaterial.Value.name != "lightmap") {
1101 | if (!usedMaterial.Value.HasProperty (texName) || !usedMaterial.Value.GetTexture (texName)) {
1102 | return;
1103 | }
1104 | }
1105 | else {
1106 | if (texName != "_MainTex") {
1107 | return;
1108 | }
1109 | }
1110 |
1111 | Texture2D tex = (Texture2D)usedMaterial.Value.GetTexture (texName);
1112 |
1113 | writeJSON (2, "{");
1114 |
1115 | writeJSON (3, "\"uuid\": \"" + usedMaterial.Key + texName + "\",");
1116 | // writeJSON (3, "\"name\": \"_" + usedMaterial.Value.name + "\",");
1117 | writeJSON (3, "\"offset\": [", false);
1118 | {
1119 | Vector2 vecOffset = usedMaterial.Value.GetTextureOffset (texName);
1120 |
1121 | writeJSON (0, vecOffset.x + ", ", false);
1122 | writeJSON (0, vecOffset.y.ToString (), false);
1123 | }
1124 | writeJSON (0, "],");
1125 |
1126 | writeJSON (3, "\"repeat\": [", false);
1127 | {
1128 | Vector2 vecScale = usedMaterial.Value.GetTextureScale ("_MainTex");
1129 | writeJSON (0, vecScale.x + ", ", false);
1130 | writeJSON (0, vecScale.y.ToString (), false);
1131 | }
1132 | writeJSON (0, "],");
1133 |
1134 | if (tex.filterMode == FilterMode.Point) {
1135 | if (settings.threeRevision == 71) {
1136 | writeJSON (3, "\"magFilter\": \"" + "NearestFilter" + "\",");
1137 | writeJSON (3, "\"minFilter\": \"" + "NearestMipMapNearestFilter" + "\",");
1138 | } else {
1139 | writeJSON (3, "\"magFilter\": " + "1003" + ",");
1140 | writeJSON (3, "\"minFilter\": " + "1004" + ",");
1141 | }
1142 | } else {
1143 | if (settings.threeRevision == 71) {
1144 | writeJSON (3, "\"magFilter\": \"" + "LinearFilter" + "\",");
1145 | writeJSON (3, "\"minFilter\": \"" + "LinearMipMapLinearFilter" + "\",");
1146 | } else {
1147 | writeJSON (3, "\"magFilter\": " + "1006" + ",");
1148 | writeJSON (3, "\"minFilter\": " + "1008" + ",");
1149 | }
1150 | }
1151 |
1152 | writeJSON (3, "\"wrap\": [", false);
1153 | {
1154 | if (tex.wrapMode == TextureWrapMode.Repeat) {
1155 | if (settings.threeRevision == 71) {
1156 | writeJSON (0, "\"RepeatWrapping\",", false);
1157 | writeJSON (0, "\"RepeatWrapping\"", false);
1158 | } else {
1159 | writeJSON (0, "1000,", false);
1160 | writeJSON (0, "1000", false);
1161 | }
1162 | } else {
1163 | if (settings.threeRevision == 71) {
1164 | writeJSON (0, "\"ClampToEdgeWrapping\",", false);
1165 | writeJSON (0, "\"ClampToEdgeWrapping\"", false);
1166 | } else {
1167 | writeJSON (0, "1001,", false);
1168 | writeJSON (0, "1001", false);
1169 | }
1170 | }
1171 | }
1172 | writeJSON (0, "],");
1173 |
1174 | foreach (KeyValuePair usedImage in usedImages) {
1175 | if (usedImage.Value.texture == tex) {
1176 | writeJSON (3, "\"image\": \"" + usedImage.Key + "\",");
1177 | writeJSON (3, "\"name\": \"" + usedImage.Value.filename + "\",");
1178 | }
1179 | }
1180 |
1181 | writeJSON (3, "\"anisotropy\": " + 16 + "");
1182 |
1183 | writeJSON (2, "}", false);
1184 |
1185 | writeJSON (0, ",");
1186 |
1187 | count++;
1188 |
1189 | });
1190 |
1191 | }
1192 |
1193 | if (count > 0) {
1194 | // Remove final comma
1195 | jsonFile.Length = jsonFile.Length - (1 + System.Environment.NewLine.Length);
1196 | writeJSON(0, "");
1197 | }
1198 | }
1199 | writeJSON (1, "]");
1200 |
1201 | writeJSON (0, "}", false);
1202 |
1203 | // Free created Materials
1204 | foreach (KeyValuePair usedTexture in usedLightmapTextures) {
1205 | if (usedTexture.Value.needsCleanup) {
1206 | GameObject.DestroyImmediate(usedTexture.Value.material);
1207 | }
1208 | }
1209 |
1210 | return jsonFile.ToString();
1211 | }
1212 |
1213 |
1214 | }
1215 | }
--------------------------------------------------------------------------------