yb_lin

导航

Unity烘焙材质到贴图脚本

这个脚本可以将复杂的材质,比如有法线贴图的材质进行"烘焙",转变为单一的贴图,可用来将Unity的游戏移植到移动平台时候使用.



讲脚本放Editor文件夹里,使用时选择一个Material材质,然后在菜单种"Custom/Bake Material"打开并调整照明和其他参数,点击Bake按钮,就会生成一个单一的贴图.

脚本:BakeMaterial.js
程序代码 js 代码
001 class BakeMaterialSettings
002 {
003     private static var kEditorPrefsName = "BakeMaterialSettings";
004      
005     static var kBakingLayerShouldBeUnusedInScene = 30;
006     static var kStandardTexNames = new Array ("_MainTex""_BumpMap""_Detail""_ParallaxMap""_Parallax");
007  
008     var bakeAlpha = false;
009     var bakeMainTexAsWhite = false;
010     var minTextureResolution = 8;
011     var maxTextureResolution = 2048;
012  
013     var emptyScene = false;
014     var useCustomLights = false;
015     var ambient = Color.black;
016      
017     static var kLights = 3;
018     var enableLight = new boolean[kLights];
019     var colorLight = new Color[kLights];
020     var dirLight = new Vector2[kLights];
021      
022     function BakeMaterialSettings ()
023     {
024         Load ();
025     }
026      
027     function Load ()
028     {
029         bakeAlpha = EditorPrefs.GetBool(kEditorPrefsName + ".bakeAlpha");
030         bakeMainTexAsWhite = EditorPrefs.GetBool(kEditorPrefsName + ".bakeMainTexAsWhite");
031         minTextureResolution = EditorPrefs.GetInt(kEditorPrefsName + ".minTextureResolution", 8);
032         maxTextureResolution = EditorPrefs.GetInt(kEditorPrefsName + ".maxTextureResolution", 2048);
033  
034         emptyScene = EditorPrefs.GetBool(kEditorPrefsName + ".emptyScene");
035         useCustomLights = EditorPrefs.GetBool(kEditorPrefsName + ".useCustomLights");
036         ambient.r = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.r");
037         ambient.g = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.g");
038         ambient.b = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.b");
039         ambient.a = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.a", 1.0f);
040          
041         for (var q = 0; q < kLights; ++q)
042         {
043             enableLight[q] = EditorPrefs.GetBool(kEditorPrefsName + ".enableLight" + q);
044             colorLight[q].r = EditorPrefs.GetFloat(kEditorPrefsName + ".color.r" + q, 0.5f);
045             colorLight[q].g = EditorPrefs.GetFloat(kEditorPrefsName + ".color.g" + q, 0.5f);
046             colorLight[q].b = EditorPrefs.GetFloat(kEditorPrefsName + ".color.b" + q, 0.5f);
047             colorLight[q].a = EditorPrefs.GetFloat(kEditorPrefsName + ".color.a" + q, 1.0f);
048             dirLight[q].x = EditorPrefs.GetFloat(kEditorPrefsName + ".dir.x" + q);
049             dirLight[q].y = EditorPrefs.GetFloat(kEditorPrefsName + ".dir.y" + q);
050         }
051     }
052      
053     function Save ()
054     {
055         EditorPrefs.SetBool(kEditorPrefsName + ".bakeAlpha", bakeAlpha);
056         EditorPrefs.SetBool(kEditorPrefsName + ".bakeMainTexAsWhite", bakeMainTexAsWhite);
057         EditorPrefs.SetInt(kEditorPrefsName + ".minTextureResolution", minTextureResolution);
058         EditorPrefs.SetInt(kEditorPrefsName + ".maxTextureResolution", maxTextureResolution);
059  
060         EditorPrefs.GetBool(kEditorPrefsName + ".emptyScene", emptyScene);
061         EditorPrefs.SetBool(kEditorPrefsName + ".useCustomLights", useCustomLights);
062         EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.r", ambient.r);
063         EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.g", ambient.g);
064         EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.b", ambient.b);
065         EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.a", ambient.a);
066  
067         for (var q = 0; q < kLights; ++q)
068         {
069             EditorPrefs.SetBool(kEditorPrefsName + ".enableLight" + q, enableLight[q]);
070             EditorPrefs.SetFloat(kEditorPrefsName + ".color.r" + q, colorLight[q].r);
071             EditorPrefs.SetFloat(kEditorPrefsName + ".color.g" + q, colorLight[q].g);
072             EditorPrefs.SetFloat(kEditorPrefsName + ".color.b" + q, colorLight[q].b);
073             EditorPrefs.SetFloat(kEditorPrefsName + ".color.a" + q, colorLight[q].a);
074             EditorPrefs.SetFloat(kEditorPrefsName + ".dir.x" + q, dirLight[q].x);
075             EditorPrefs.SetFloat(kEditorPrefsName + ".dir.y" + q, dirLight[q].y);
076         }
077     }
078 }
079  
080 class BakeMaterial extends EditorWindow
081 {
082     private static var kMateriBakeNodeName = "__MateriaBakeSetup";
083     private static var kWindowMinSize = Vector2 (300, 386);
084      
085     private static var settings : BakeMaterialSettings;
086     private static var visible : boolean = false;
087      
088     private var camera : GameObject;
089     private var plane : GameObject;
090     private var previewTexture : Texture;
091     private var lights : GameObject[] = new GameObject[BakeMaterialSettings.kLights];
092     private var stateChanged = false;
093      
094     private var texViewScrollPosition = Vector2.zero;
095     private var lastMaterial : Material;
096      
097     private var originalScene = "";
098      
099     private var scheduleBakeOnNextUpdate = false;
100  
101      
102     private function SetupScene ()
103     {
104         DestroyScene ();
105         var oldGo = GameObject.Find(kMateriBakeNodeName);
106         if (oldGo)
107             DestroyImmediate (oldGo);
108         camera = new GameObject (kMateriBakeNodeName, Camera);
109         plane = GameObject.CreatePrimitive (PrimitiveType.Plane);
110  
111         var cam = camera;
112         cam.camera.backgroundColor = Color.black;
113         cam.camera.clearFlags = CameraClearFlags.SolidColor;
114         cam.camera.orthographic = true;
115         cam.camera.orthographicSize = 5.0;
116         cam.camera.cullingMask = 1 << settings.kBakingLayerShouldBeUnusedInScene;
117          
118         plane.transform.parent = cam.transform;
119         plane.transform.position = Vector3.forward * 10.0;
120         plane.transform.rotation = Quaternion.Euler (0, 0, 180) * Quaternion.Euler (-90, 0, 0);
121         plane.layer = settings.kBakingLayerShouldBeUnusedInScene;
122          
123         for (var in lights)
124         {
125             l = new GameObject ("Light", Light);
126             l.light.type = LightType.Directional;
127             l.light.cullingMask = 1 << settings.kBakingLayerShouldBeUnusedInScene;
128             l.transform.parent = cam.transform;
129             l.active = false;
130         }
131     }
132      
133     private function UpdateScene (m : Material)
134     {
135         for (q = 0; q < settings.kLights; ++q)
136         {
137             lights[q].active = settings.useCustomLights & settings.enableLight[q];
138             lights[q].light.color = settings.colorLight[q];
139             lights[q].transform.rotation =
140                 Quaternion.AngleAxis(settings.dirLight[q].x, Vector3.up) *
141                 Quaternion.AngleAxis(settings.dirLight[q].y, Vector3.right);
142         }
143          
144         if (settings.useCustomLights)
145             RenderSettings.ambientLight = settings.ambient;
146         else if (settings.emptyScene)
147             RenderSettings.ambientLight = Color.white;
148              
149         plane.renderer.material = m;
150     }
151          
152     private function DestroyScene ()
153     {
154         GameObject.DestroyImmediate (camera);
155         GameObject.DestroyImmediate (plane);
156         GameObject.DestroyImmediate (previewTexture);
157     }
158  
159     function UpdateMaterialPreview (m : Material) : RenderTexture
160     {
161         if (!m)
162             return;
163          
164         var saveAmbientLight = RenderSettings.ambientLight;
165         var saveMainTexture = m.mainTexture;
166         if (settings.bakeMainTexAsWhite)
167             m.mainTexture = null;
168      
169          
170         // setup
171         if (!camera)
172             SetupScene ();
173         camera.SetActiveRecursively(true);
174         UpdateScene (m);
175          
176         var res = FindLargestTextureResolution (plane.renderer.sharedMaterial, settings.minTextureResolution, settings.maxTextureResolution);
177         var rt = RenderCameraToRenderTexture (camera.camera, res.x, res.y);
178          
179         // restore
180         camera.SetActiveRecursively(false);
181         RenderSettings.ambientLight = saveAmbientLight;
182         m.mainTexture = saveMainTexture;
183          
184         previewTexture = rt;
185         return rt;
186     }
187      
188     function CaptureMaterial(m : Material)
189     {
190         var matAssetPath = AssetDatabase.GetAssetPath (m);
191         var assetPath = System.IO.Path.Combine (System.IO.Path.GetDirectoryName (matAssetPath), System.IO.Path.GetFileNameWithoutExtension (matAssetPath));
192  
193         var rt = UpdateMaterialPreview (m);
194         RenderTextureToPNG (rt, settings.bakeAlpha, assetPath + ".png");
195     }
196  
197     function OnEnable ()
198     {
199         if (!settings)
200             settings = new BakeMaterialSettings ();
201         SetupScene ();
202         visible = true;
203     }
204      
205     function OnDisable ()
206     {
207         DestroyScene ();
208         settings.Save ();
209         visible = false;
210     }
211  
212     static function GetTargetMaterial () : Material
213     {
214         return EditorUtility.InstanceIDToObject (Selection.activeInstanceID) as Material;
215     }
216  
217     function OnSelectionChange ()
218     {
219         Repaint ();
220     }
221  
222     function Update ()
223     {
224         var rebuildScene = false;
225         if (scheduleBakeOnNextUpdate)
226         {
227             Bake ();
228             scheduleBakeOnNextUpdate = false;
229             rebuildScene = true;
230         }
231          
232         if (originalScene == "" && EditorApplication.currentScene == "")
233             settings.emptyScene = true;
234              
235         if (settings.emptyScene && originalScene == "" && EditorApplication.currentScene != "")
236         {
237             DestroyScene ();
238             if (EditorApplication.SaveCurrentSceneIfUserWantsTo ())
239             {
240                 originalScene = EditorApplication.currentScene;
241                 EditorApplication.NewScene ();
242             }
243             else
244                 settings.emptyScene = false;
245             rebuildScene = true;            
246         }
247         else if (!settings.emptyScene && originalScene != "")
248         {
249             EditorApplication.OpenScene (originalScene);
250             rebuildScene = true;
251             originalScene = "";
252         }
253          
254         if (rebuildScene)
255         {
256             SetupScene ();
257         }
258          
259         if (rebuildScene || stateChanged || !settings.emptyScene)
260         {
261             UpdateMaterialPreview (lastMaterial);
262             Repaint ();
263             stateChanged = false;
264         }
265     }
266      
267     function OnGUI ()
268     {
269         var material = GetTargetMaterial ();
270         if (lastMaterial != material)
271             UpdateMaterialPreview (material);
272         if (material)
273             lastMaterial = material;
274          
275         EditorGUILayout.BeginHorizontal();
276             EditorGUILayout.BeginVertical(GUILayout.MaxWidth(200));
277                 if (!(originalScene == "" && EditorApplication.currentScene == ""))
278                 {
279                     settings.emptyScene = !EditorGUILayout.BeginToggleGroup("Scene ligthing", !settings.emptyScene);
280                     EditorGUILayout.EndToggleGroup();
281                 }
282                 settings.useCustomLights = EditorGUILayout.BeginToggleGroup("Custom lighting", settings.useCustomLights);
283                 if (settings.useCustomLights)
284                 {
285                     EditorGUI.indentLevel = 1;
286                     settings.ambient = EditorGUILayout.ColorField("Ambient", settings.ambient);
287                     for (var q = 0; q < settings.kLights; ++q)
288                     {
289                         settings.enableLight[q] = EditorGUILayout.BeginToggleGroup("Light", settings.enableLight[q]);
290                         EditorGUI.indentLevel = 2;
291                             settings.colorLight[q] = EditorGUILayout.ColorField("Color", settings.colorLight[q]);
292                             settings.dirLight[q] = EditorGUILayout.Vector2Field("Direction", settings.dirLight[q]);
293                         EditorGUILayout.EndToggleGroup();
294                     }
295                 }
296                 EditorGUI.indentLevel = 0;
297                 EditorGUILayout.EndToggleGroup();
298                  
299                 settings.bakeAlpha = EditorGUILayout.Toggle("Bake Alpha", settings.bakeAlpha);
300                 settings.bakeMainTexAsWhite = !EditorGUILayout.Toggle("MainTex", !settings.bakeMainTexAsWhite);
301                 settings.minTextureResolution = EditorGUILayout.IntField("Min Resolution", settings.minTextureResolution);
302                 settings.maxTextureResolution = EditorGUILayout.IntField("Max Resolution", settings.maxTextureResolution);
303                 settings.minTextureResolution = Mathf.Max(2, settings.minTextureResolution);
304                 settings.maxTextureResolution = Mathf.Max(settings.minTextureResolution, settings.maxTextureResolution);
305  
306                 EditorGUILayout.BeginHorizontal();
307                 if (GUILayout.Button("Bake"))
308                 {
309                     CaptureMaterial (lastMaterial);
310                 }
311                 if (GUILayout.Button("Bake Selected"))
312                 {
313                     scheduleBakeOnNextUpdate = true;
314                 }
315                 EditorGUILayout.EndHorizontal();
316                  
317             EditorGUILayout.EndVertical();
318              
319             texViewScrollPosition = EditorGUILayout.BeginScrollView (texViewScrollPosition);
320                 var r = GUILayoutUtility.GetAspectRect(1.0f);
321                 if (previewTexture)
322                     EditorGUI.DrawPreviewTexture(r, previewTexture);
323             EditorGUILayout.EndScrollView();        
324         EditorGUILayout.EndHorizontal();
325          
326         if (GUI.changed)
327         {
328             stateChanged = true;
329         }
330     }
331      
332     @MenuItem("Custom/Bake Material ..."false, 5)
333     static function CreateBakeEditor()
334     {
335         var window = EditorWindow.GetWindow(BakeMaterial);
336         window.title = "Bake Material";
337         window.minSize = kWindowMinSize;
338         window.Show();
339     }
340  
341     @MenuItem("Custom/Bake Selected Materials"false, 4)
342     static function Bake()
343     {
344         var instanceIDs = Selection.instanceIDs;
345         var currentScene = EditorApplication.currentScene;
346      
347         var wasAlreadyVisible = BakeMaterial.visible;
348         var window = EditorWindow.GetWindow(BakeMaterial);
349          
350         if (window.settings.emptyScene)
351         {
352             if (!EditorApplication.SaveCurrentSceneIfUserWantsTo ())
353                 return;
354             EditorApplication.NewScene ();
355         }
356          
357         window.SetupScene ();
358         for (var in instanceIDs)
359         {
360             var m : Material = EditorUtility.InstanceIDToObject (i) as Material;
361             if (m)
362                 window.CaptureMaterial (m);
363         }
364         window.DestroyScene ();
365          
366         if (window.settings.emptyScene && currentScene)
367         {
368             EditorApplication.OpenScene (currentScene);
369         }
370          
371         if (!wasAlreadyVisible)
372             window.Close ();
373     }
374      
375     static function FindLargestTextureResolution (m : Material, minTexRes : int, maxTexRes : int) : Vector2
376     {
377         var res = Vector2 (minTexRes, minTexRes);
378         for (var in BakeMaterialSettings.kStandardTexNames)
379         {
380             if (!m.HasProperty (n))
381                 continue;
382          
383             var t : Texture = m.GetTexture (n);
384             if (!t)
385                 continue;
386              
387             res.x = Mathf.Max (res.x, t.width);
388             res.y = Mathf.Max (res.y, t.height);
389         }
390         res.x = Mathf.Min (res.x, maxTexRes);
391         res.y = Mathf.Min (res.y, maxTexRes);
392         return res;
393     }
394      
395     static function RenderCameraToRenderTexture (cam : Camera, width : int, height : int) : RenderTexture
396     {
397         var rt = cam.camera.targetTexture;
398         if (rt && rt.width != width && rt.height != height)
399             DestroyImmediate(rt);
400         if (!rt)
401             rt = new RenderTexture (width, height, 24);
402         cam.camera.targetTexture = rt;
403         cam.camera.Render ();
404         return rt;
405     }
406      
407     static function RenderTextureToPNG (rt : RenderTexture, bakeAlpha : boolean, assetPath : String)
408     {
409         RenderTexture.active = rt;
410          
411         var screenShot = new Texture2D (rt.width, rt.height, bakeAlpha? TextureFormat.ARGB32 : TextureFormat.RGB24, false);
412         screenShot.ReadPixels (Rect (0, 0, rt.width, rt.height), 0, 0);
413          
414         RenderTexture.active = null;
415          
416         var bytes = screenShot.EncodeToPNG ();
417         System.IO.File.WriteAllBytes (assetPath, bytes);
418          
419         AssetDatabase.ImportAsset (assetPath, ImportAssetOptions.ForceUpdate);
420     }
421 }

posted on 2011-05-06 16:26  废铁  阅读(1579)  评论(0编辑  收藏  举报