Tanoda
FBXUnityMaterialGetter.cs
Go to the documentation of this file.
1// ===============================================================================================
2// The MIT License (MIT) for UnityFBXExporter
3//
4// UnityFBXExporter was created for Building Crafter (http://u3d.as/ovC) a tool to rapidly
5// create high quality buildings right in Unity with no need to use 3D modeling programs.
6//
7// Copyright (c) 2016 | 8Bit Goose Games, Inc.
8//
9// Permission is hereby granted, free of charge, to any person obtaining a copy
10// of this software and associated documentation files (the "Software"), to deal
11// in the Software without restriction, including without limitation the rights
12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
13// of the Software, and to permit persons to whom the Software is furnished to do so,
14// subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be included in all
17// copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
20// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
24// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25//
26// ===============================================================================================
27
28using UnityEngine;
29using System.Text;
30using System.Collections.Generic;
31using System.Linq;
32using System.IO;
33#if UNITY_EDITOR
34using UnityEditor;
35#endif
37
38namespace UnityFBXExporter
39{
41 {
42
51 public static void GetAllMaterialsToString(GameObject gameObj, string newPath, bool copyMaterials, bool copyTextures, out Material[] materials, out string matObjects, out string connections)
52 {
53 StringBuilder tempObjectSb = new StringBuilder();
54 StringBuilder tempConnectionsSb = new StringBuilder();
55
56 // Need to get all unique materials for the submesh here and then write them in
57 //@cartzhang modify.As meshrender and skinnedrender is same level in inherit relation shape.
58 // if not check,skinned render ,may lost some materials.
59 Renderer[] meshRenders = gameObj.GetComponentsInChildren<Renderer>();
60
61 List<Material> uniqueMaterials = new List<Material>();
62
63 // Gets all the unique materials within this GameObject Hierarchy
64 for(int i = 0; i < meshRenders.Length; i++)
65 {
66 for(int n = 0; n < meshRenders[i].sharedMaterials.Length; n++)
67 {
68 Material mat = meshRenders[i].sharedMaterials[n];
69
70 if(uniqueMaterials.Contains(mat) == false && mat != null)
71 {
72 uniqueMaterials.Add(mat);
73 }
74 }
75 }
76
77 for (int i = 0; i < uniqueMaterials.Count; i++)
78 {
79 Material mat = uniqueMaterials[i];
80
81 // We rename the material if it is being copied
82 string materialName = mat.name;
83 if(copyMaterials)
84 materialName = gameObj.name + "_" + mat.name;
85
86 int referenceId = Mathf.Abs(mat.GetInstanceID());
87
88 Color color1;
89
90 if (mat.HasProperty("_Color"))
91 {
92 color1 = mat.color;
93 }
94 else
95 {
96 color1 = mat.GetColor("_Diffusecolor");
97 }
98
99 tempObjectSb.AppendLine();
100 tempObjectSb.AppendLine("\tMaterial: " + referenceId + ", \"Material::" + materialName + "\", \"\" {");
101 tempObjectSb.AppendLine("\t\tVersion: 102");
102 tempObjectSb.AppendLine("\t\tShadingModel: \"phong\"");
103 tempObjectSb.AppendLine("\t\tMultiLayer: 0");
104 tempObjectSb.AppendLine("\t\tProperties70: {");
105 tempObjectSb.AppendFormat("\t\t\tP: \"Diffuse\", \"Vector3D\", \"Vector\", \"\",{0},{1},{2}", FE.FBXFormat(color1.r), FE.FBXFormat(color1.g), FE.FBXFormat(color1.b));
106 tempObjectSb.AppendLine();
107 tempObjectSb.AppendFormat("\t\t\tP: \"DiffuseColor\", \"Color\", \"\", \"A\",{0},{1},{2}", FE.FBXFormat(color1.r), FE.FBXFormat(color1.g), FE.FBXFormat(color1.b));
108 tempObjectSb.AppendLine();
109
110 // TODO: Figure out if this property can be written to the FBX file
111 // if(mat.HasProperty("_MetallicGlossMap"))
112 // {
113 // Debug.Log("has metallic gloss map");
114 // Color color = mat.GetColor("_Color");
115 // tempObjectSb.AppendFormat("\t\t\tP: \"Specular\", \"Vector3D\", \"Vector\", \"\",{0},{1},{2}", color.r, color.g, color.r);
116 // tempObjectSb.AppendLine();
117 // tempObjectSb.AppendFormat("\t\t\tP: \"SpecularColor\", \"ColorRGB\", \"Color\", \" \",{0},{1},{2}", color.r, color.g, color.b);
118 // tempObjectSb.AppendLine();
119 // }
120
121 if(mat.HasProperty("_SpecColor"))
122 {
123 Color color = mat.GetColor("_SpecColor");
124 tempObjectSb.AppendFormat("\t\t\tP: \"Specular\", \"Vector3D\", \"Vector\", \"\",{0},{1},{2}", FE.FBXFormat(color.r), FE.FBXFormat(color.g), FE.FBXFormat(color.r));
125 tempObjectSb.AppendLine();
126 tempObjectSb.AppendFormat("\t\t\tP: \"SpecularColor\", \"ColorRGB\", \"Color\", \" \",{0},{1},{2}", FE.FBXFormat(color.r), FE.FBXFormat(color.g), FE.FBXFormat(color.b));
127 tempObjectSb.AppendLine();
128 }
129
130 if(mat.HasProperty("_Mode"))
131 {
132 Color color = Color.white;
133
134 switch((int)mat.GetFloat("_Mode"))
135 {
136 case 0: // Map is opaque
137
138 break;
139
140 case 1: // Map is a cutout
141 // TODO: Add option if it is a cutout
142 break;
143
144 case 2: // Map is a fade
145 color = mat.GetColor("_Color");
146
147 tempObjectSb.AppendFormat("\t\t\tP: \"TransparentColor\", \"Color\", \"\", \"A\",{0},{1},{2}", FE.FBXFormat(color.r), FE.FBXFormat(color.g), FE.FBXFormat(color.b));
148 tempObjectSb.AppendLine();
149 tempObjectSb.AppendFormat("\t\t\tP: \"Opacity\", \"double\", \"Number\", \"\",{0}", FE.FBXFormat(color.a));
150 tempObjectSb.AppendLine();
151 break;
152
153 case 3: // Map is transparent
154 color = mat.GetColor("_Color");
155
156 tempObjectSb.AppendFormat("\t\t\tP: \"TransparentColor\", \"Color\", \"\", \"A\",{0},{1},{2}", FE.FBXFormat(color.r), FE.FBXFormat(color.g), FE.FBXFormat(color.b));
157 tempObjectSb.AppendLine();
158 tempObjectSb.AppendFormat("\t\t\tP: \"Opacity\", \"double\", \"Number\", \"\",{0}", FE.FBXFormat(color.a));
159 tempObjectSb.AppendLine();
160 break;
161 }
162 }
163
164 // NOTE: Unity doesn't currently import this information (I think) from an FBX file.
165 if(mat.HasProperty("_EmissionColor"))
166 {
167 Color color = mat.GetColor("_EmissionColor");
168
169 tempObjectSb.AppendFormat("\t\t\tP: \"Emissive\", \"Vector3D\", \"Vector\", \"\",{0},{1},{2}", FE.FBXFormat(color.r), FE.FBXFormat(color.g), FE.FBXFormat(color.b));
170 tempObjectSb.AppendLine();
171
172 float averageColor = (color.r + color.g + color.b) / 3f;
173
174 tempObjectSb.AppendFormat("\t\t\tP: \"EmissiveFactor\", \"Number\", \"\", \"A\",{0}", FE.FBXFormat(averageColor));
175 tempObjectSb.AppendLine();
176 }
177
178 // TODO: Add these to the file based on their relation to the PBR files
179// tempObjectSb.AppendLine("\t\t\tP: \"AmbientColor\", \"Color\", \"\", \"A\",0,0,0");
180// tempObjectSb.AppendLine("\t\t\tP: \"ShininessExponent\", \"Number\", \"\", \"A\",6.31179285049438");
181// tempObjectSb.AppendLine("\t\t\tP: \"Ambient\", \"Vector3D\", \"Vector\", \"\",0,0,0");
182// tempObjectSb.AppendLine("\t\t\tP: \"Shininess\", \"double\", \"Number\", \"\",6.31179285049438");
183// tempObjectSb.AppendLine("\t\t\tP: \"Reflectivity\", \"double\", \"Number\", \"\",0");
184
185 tempObjectSb.AppendLine("\t\t}");
186 tempObjectSb.AppendLine("\t}");
187
188 string textureObjects;
189 string textureConnections;
190
191 SerializedTextures(gameObj, newPath, mat, materialName, copyTextures, out textureObjects, out textureConnections);
192
193 tempObjectSb.Append(textureObjects);
194 tempConnectionsSb.Append(textureConnections);
195 }
196
197 materials = uniqueMaterials.ToArray<Material>();
198
199 matObjects = tempObjectSb.ToString();
200 connections = tempConnectionsSb.ToString();
201 }
202
211 private static void SerializedTextures(GameObject gameObj, string newPath, Material material, string materialName, bool copyTextures, out string objects, out string connections)
212 {
213 // TODO: FBX import currently only supports Diffuse Color and Normal Map
214 // Because it is undocumented, there is no way to easily find out what other textures
215 // can be attached to an FBX file so it is imported into the PBR shaders at the same time.
216 // Also NOTE, Unity 5.1.2 will import FBX files with legacy shaders. This is fix done
217 // in at least 5.3.4.
218
219 StringBuilder objectsSb = new StringBuilder();
220 StringBuilder connectionsSb = new StringBuilder();
221
222 int materialId = Mathf.Abs(material.GetInstanceID());
223
224 Texture mainTexture = material.GetTexture("_MainTex");
225
226 string newObjects = null;
227 string newConnections = null;
228
229 // Serializeds the Main Texture, one of two textures that can be stored in FBX's sysytem
230 if(mainTexture != null)
231 {
232 SerializeOneTexture(gameObj, newPath, material, materialName, materialId, copyTextures, "_MainTex", "DiffuseColor", out newObjects, out newConnections);
233 objectsSb.AppendLine(newObjects);
234 connectionsSb.AppendLine(newConnections);
235 }
236
237 if(SerializeOneTexture(gameObj, newPath, material, materialName, materialId, copyTextures, "_BumpMap", "NormalMap", out newObjects, out newConnections))
238 {
239 objectsSb.AppendLine(newObjects);
240 connectionsSb.AppendLine(newConnections);
241 }
242
243 connections = connectionsSb.ToString();
244 objects = objectsSb.ToString();
245 }
246
247 private static bool SerializeOneTexture(GameObject gameObj,
248 string newPath,
249 Material material,
250 string materialName,
251 int materialId,
252 bool copyTextures,
253 string unityExtension,
254 string textureType,
255 out string objects,
256 out string connections)
257 {
258 StringBuilder objectsSb = new StringBuilder();
259 StringBuilder connectionsSb = new StringBuilder();
260
261 Texture texture = material.GetTexture(unityExtension);
262
263 if(texture == null)
264 {
265 objects = "";
266 connections = "";
267 return false;
268 }
269 string originalAssetPath = "";
270
271#if UNITY_EDITOR
272 originalAssetPath = AssetDatabase.GetAssetPath(texture);
273#else
274 Debug.LogError("Unity FBX Exporter can not serialize textures at runtime (yet). Look in FBXUnityMaterialGetter around line 250ish. Fix it and contribute to the project!");
275 objects = "";
276 connections = "";
277 return false;
278#endif
279 string fullDataFolderPath = Application.dataPath;
280 string textureFilePathFullName = originalAssetPath;
281 string textureName = Path.GetFileNameWithoutExtension(originalAssetPath);
282 string textureExtension = Path.GetExtension(originalAssetPath);
283
284 // If we are copying the textures over, we update the relative positions
285 if(copyTextures)
286 {
287 int indexOfAssetsFolder = fullDataFolderPath.LastIndexOf("/Assets");
288 fullDataFolderPath = fullDataFolderPath.Remove(indexOfAssetsFolder, fullDataFolderPath.Length - indexOfAssetsFolder);
289
290 string newPathFolder = newPath.Remove(newPath.LastIndexOf('/') + 1, newPath.Length - newPath.LastIndexOf('/') - 1);
291 textureName = gameObj.name + "_" + material.name + unityExtension;
292
293 textureFilePathFullName = fullDataFolderPath + "/" + newPathFolder + textureName + textureExtension;
294 }
295
296 long textureReference = FBXExporter.GetRandomFBXId();
297
298 // TODO - test out different reference names to get one that doesn't load a _MainTex when importing.
299
300 objectsSb.AppendLine("\tTexture: " + textureReference + ", \"Texture::" + materialName + "\", \"\" {");
301 objectsSb.AppendLine("\t\tType: \"TextureVideoClip\"");
302 objectsSb.AppendLine("\t\tVersion: 202");
303 objectsSb.AppendLine("\t\tTextureName: \"Texture::" + materialName + "\"");
304 objectsSb.AppendLine("\t\tProperties70: {");
305 objectsSb.AppendLine("\t\t\tP: \"CurrentTextureBlendMode\", \"enum\", \"\", \"\",0");
306 objectsSb.AppendLine("\t\t\tP: \"UVSet\", \"KString\", \"\", \"\", \"map1\"");
307 objectsSb.AppendLine("\t\t\tP: \"UseMaterial\", \"bool\", \"\", \"\",1");
308 objectsSb.AppendLine("\t\t}");
309 objectsSb.AppendLine("\t\tMedia: \"Video::" + materialName + "\"");
310
311 // Sets the absolute path for the copied texture
312 objectsSb.Append("\t\tFileName: \"");
313 objectsSb.Append(textureFilePathFullName);
314 objectsSb.AppendLine("\"");
315
316 // Sets the relative path for the copied texture
317 // TODO: If we don't copy the textures to a relative path, we must find a relative path to write down here
318 if(copyTextures)
319 objectsSb.AppendLine("\t\tRelativeFilename: \"/Textures/" + textureName + textureExtension + "\"");
320
321 objectsSb.AppendLine("\t\tModelUVTranslation: 0,0"); // TODO: Figure out how to get the UV translation into here
322 objectsSb.AppendLine("\t\tModelUVScaling: 1,1"); // TODO: Figure out how to get the UV scaling into here
323 objectsSb.AppendLine("\t\tTexture_Alpha_Source: \"None\""); // TODO: Add alpha source here if the file is a cutout.
324 objectsSb.AppendLine("\t\tCropping: 0,0,0,0");
325 objectsSb.AppendLine("\t}");
326
327 connectionsSb.AppendLine("\t;Texture::" + textureName + ", Material::" + materialName + "\"");
328 connectionsSb.AppendLine("\tC: \"OP\"," + textureReference + "," + materialId + ", \"" + textureType + "\"");
329
330 connectionsSb.AppendLine();
331
332 objects = objectsSb.ToString();
333 connections = connectionsSb.ToString();
334
335 return true;
336 }
337 }
338}
UnityFBXExporter.FBXExporter FE
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
UnityEngine.Color Color
Definition: TestScript.cs:32
static void GetAllMaterialsToString(GameObject gameObj, string newPath, bool copyMaterials, bool copyTextures, out Material[] materials, out string matObjects, out string connections)
Finds all materials in a gameobject and writes them to a string that can be read by the FBX writer