Created
July 6, 2016 03:20
-
-
Save ChrisTowles/e2ff48624afc223a72fb094f43d0aaa0 to your computer and use it in GitHub Desktop.
Updated Unity 5.3 Bake Material to Texture.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This doesn't work or at least it didn't for the shader i was trying to use it with. | |
// Just Sharing Becasue i got farther with this than other version I found around the internet. | |
// | |
// Quit working on this because the shader i was trying to convert to a Standard Unity Shader | |
// Really could not be done as it was based reflections of orginal object (PolyWorld). | |
//orginal - http://wiki.unity3d.com/index.php/Bake_Material_to_Texture | |
using UnityEngine; | |
using UnityEditor; | |
using System.Collections; | |
using UnityEngine; | |
using UnityEditor; | |
using System.Collections; | |
public class BakeMaterialSettings | |
{ | |
private static string kEditorPrefsName = "BakeMaterialSettings"; | |
public static int kBakingLayerShouldBeUnusedInScene = 30; | |
public static string[] kStandardTexNames = { "_MainTex", "_BumpMap", "_Detail", "_ParallaxMap", "_Parallax" }; | |
public bool bakeAlpha = false; | |
public bool bakeMainTexAsWhite = false; | |
public int minTextureResolution = 8; | |
public int maxTextureResolution = 2048; | |
public bool emptyScene = false; | |
public bool useCustomLights = false; | |
public Color ambient = Color.black; | |
public static int kLights = 3; | |
public bool[] enableLight = new bool[kLights]; | |
public Color[] colorLight = new Color[kLights]; | |
public Vector2[] dirLight = new Vector2[kLights]; | |
public BakeMaterialSettings() | |
{ | |
Load(); | |
} | |
public void Load() | |
{ | |
bakeAlpha = EditorPrefs.GetBool(kEditorPrefsName + ".bakeAlpha"); | |
bakeMainTexAsWhite = EditorPrefs.GetBool(kEditorPrefsName + ".bakeMainTexAsWhite"); | |
minTextureResolution = EditorPrefs.GetInt(kEditorPrefsName + ".minTextureResolution", 8); | |
maxTextureResolution = EditorPrefs.GetInt(kEditorPrefsName + ".maxTextureResolution", 2048); | |
emptyScene = EditorPrefs.GetBool(kEditorPrefsName + ".emptyScene"); | |
useCustomLights = EditorPrefs.GetBool(kEditorPrefsName + ".useCustomLights"); | |
ambient.r = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.r"); | |
ambient.g = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.g"); | |
ambient.b = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.b"); | |
ambient.a = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.a", 1.0f); | |
for (int q = 0; q < kLights; ++q) | |
{ | |
enableLight[q] = EditorPrefs.GetBool(kEditorPrefsName + ".enableLight" + q); | |
colorLight[q].r = EditorPrefs.GetFloat(kEditorPrefsName + ".color.r" + q, 0.5f); | |
colorLight[q].g = EditorPrefs.GetFloat(kEditorPrefsName + ".color.g" + q, 0.5f); | |
colorLight[q].b = EditorPrefs.GetFloat(kEditorPrefsName + ".color.b" + q, 0.5f); | |
colorLight[q].a = EditorPrefs.GetFloat(kEditorPrefsName + ".color.a" + q, 1.0f); | |
dirLight[q].x = EditorPrefs.GetFloat(kEditorPrefsName + ".dir.x" + q); | |
dirLight[q].y = EditorPrefs.GetFloat(kEditorPrefsName + ".dir.y" + q); | |
} | |
} | |
public void Save() | |
{ | |
EditorPrefs.SetBool(kEditorPrefsName + ".bakeAlpha", bakeAlpha); | |
EditorPrefs.SetBool(kEditorPrefsName + ".bakeMainTexAsWhite", bakeMainTexAsWhite); | |
EditorPrefs.SetInt(kEditorPrefsName + ".minTextureResolution", minTextureResolution); | |
EditorPrefs.SetInt(kEditorPrefsName + ".maxTextureResolution", maxTextureResolution); | |
EditorPrefs.GetBool(kEditorPrefsName + ".emptyScene", emptyScene); | |
EditorPrefs.SetBool(kEditorPrefsName + ".useCustomLights", useCustomLights); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.r", ambient.r); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.g", ambient.g); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.b", ambient.b); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.a", ambient.a); | |
for (int q = 0; q < kLights; ++q) | |
{ | |
EditorPrefs.SetBool(kEditorPrefsName + ".enableLight" + q, enableLight[q]); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".color.r" + q, colorLight[q].r); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".color.g" + q, colorLight[q].g); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".color.b" + q, colorLight[q].b); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".color.a" + q, colorLight[q].a); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".dir.x" + q, dirLight[q].x); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".dir.y" + q, dirLight[q].y); | |
} | |
} | |
} | |
public class BakeMaterial : EditorWindow | |
{ | |
private static string kMateriBakeNodeName = "__MateriaBakeSetup"; | |
private static Vector2 kWindowMinSize = new Vector2(300, 386); | |
private BakeMaterialSettings settings; | |
private static bool visible = false; | |
private GameObject camera; | |
private GameObject plane; | |
private Texture previewTexture; | |
private GameObject[] lights = new GameObject[BakeMaterialSettings.kLights]; | |
private bool stateChanged = false; | |
private Vector2 texViewScrollPosition = Vector2.zero; | |
private Material lastMaterial; | |
private string originalScene = ""; | |
private bool scheduleBakeOnNextUpdate = false; | |
private void SetupScene() | |
{ | |
DestroyScene(); | |
GameObject oldGo = GameObject.Find(kMateriBakeNodeName); | |
if (oldGo) | |
DestroyImmediate(oldGo); | |
camera = new GameObject(kMateriBakeNodeName, typeof(Camera)); | |
plane = GameObject.CreatePrimitive(PrimitiveType.Plane); | |
Camera cam = camera.GetComponent<Camera>(); | |
cam.backgroundColor = Color.black; | |
cam.clearFlags = CameraClearFlags.SolidColor; | |
cam.orthographic = true; | |
cam.orthographicSize = 5.0f; | |
cam.cullingMask = 1 << BakeMaterialSettings.kBakingLayerShouldBeUnusedInScene; | |
plane.transform.parent = cam.transform; | |
plane.transform.position = Vector3.forward * 10.0f; | |
plane.transform.rotation = Quaternion.Euler(0, 0, 180) * Quaternion.Euler(-90, 0, 0); | |
plane.layer = BakeMaterialSettings.kBakingLayerShouldBeUnusedInScene; | |
for(int i = 0; i < lights.Length; i++) | |
{ | |
lights[i] = new GameObject(); | |
lights[i].AddComponent<Light>(); | |
var light = lights[i].GetComponent<Light>(); | |
light.type = LightType.Directional; | |
light.cullingMask = 1 << BakeMaterialSettings.kBakingLayerShouldBeUnusedInScene; | |
lights[i].transform.parent = cam.transform; | |
lights[i].SetActive(false); | |
} | |
} | |
private void UpdateScene(Material m) | |
{ | |
for (int q = 0; q < BakeMaterialSettings.kLights; ++q) | |
{ | |
lights[q].SetActive(settings.useCustomLights & settings.enableLight[q]); | |
lights[q].GetComponent<Light>().color = settings.colorLight[q]; | |
lights[q].transform.rotation = | |
Quaternion.AngleAxis(settings.dirLight[q].x, Vector3.up) * | |
Quaternion.AngleAxis(settings.dirLight[q].y, Vector3.right); | |
} | |
if (settings.useCustomLights) | |
RenderSettings.ambientLight = settings.ambient; | |
else if (settings.emptyScene) | |
RenderSettings.ambientLight = Color.white; | |
plane.GetComponent<Renderer>().material = m; | |
} | |
private void DestroyScene() | |
{ | |
GameObject.DestroyImmediate(camera); | |
GameObject.DestroyImmediate(plane); | |
GameObject.DestroyImmediate(previewTexture); | |
} | |
RenderTexture UpdateMaterialPreview(Material m) | |
{ | |
if (!m) | |
return null; | |
var saveAmbientLight = RenderSettings.ambientLight; | |
var saveMainTexture = m.mainTexture; | |
if (settings.bakeMainTexAsWhite) | |
m.mainTexture = null; | |
// setup | |
if (!camera) | |
SetupScene(); | |
camera.SetActive(true); | |
UpdateScene(m); | |
var res = FindLargestTextureResolution(plane.GetComponent<Renderer>().sharedMaterial, settings.minTextureResolution, settings.maxTextureResolution); | |
var rt = RenderCameraToRenderTexture(camera.GetComponent<Camera>(), Mathf.FloorToInt(res.x), Mathf.FloorToInt(res.y)); | |
// restore | |
camera.SetActive(false); | |
RenderSettings.ambientLight = saveAmbientLight; | |
m.mainTexture = saveMainTexture; | |
previewTexture = rt; | |
return rt; | |
} | |
void CaptureMaterial(Material m) | |
{ | |
var matAssetPath = AssetDatabase.GetAssetPath(m); | |
var assetPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(matAssetPath), System.IO.Path.GetFileNameWithoutExtension(matAssetPath)); | |
var rt = UpdateMaterialPreview(m); | |
RenderTextureToPNG(rt, settings.bakeAlpha, assetPath + ".png"); | |
} | |
void OnEnable() | |
{ | |
if (settings == null) | |
settings = new BakeMaterialSettings(); | |
SetupScene(); | |
visible = true; | |
} | |
void OnDisable() | |
{ | |
DestroyScene(); | |
settings.Save(); | |
visible = false; | |
} | |
static Material GetTargetMaterial() | |
{ | |
Material material = null; | |
var id = Selection.activeInstanceID; | |
if (id > 0) | |
{ | |
var obj = EditorUtility.InstanceIDToObject(id); | |
if (obj != null) | |
{ | |
var mesh = ((GameObject)obj).GetComponent<MeshRenderer>(); | |
if (mesh != null) | |
{ | |
material = mesh.material; | |
} | |
} | |
} | |
return material; | |
} | |
void OnSelectionChange() | |
{ | |
Repaint(); | |
} | |
void Update() | |
{ | |
bool rebuildScene = false; | |
if (scheduleBakeOnNextUpdate) | |
{ | |
Bake(); | |
scheduleBakeOnNextUpdate = false; | |
rebuildScene = true; | |
} | |
if (originalScene == "" && EditorApplication.currentScene == "") | |
settings.emptyScene = true; | |
if (settings.emptyScene && originalScene == "" && EditorApplication.currentScene != "") | |
{ | |
DestroyScene(); | |
if (EditorApplication.SaveCurrentSceneIfUserWantsTo()) | |
{ | |
originalScene = EditorApplication.currentScene; | |
EditorApplication.NewScene(); | |
} | |
else | |
settings.emptyScene = false; | |
rebuildScene = true; | |
} | |
else if (!settings.emptyScene && originalScene != "") | |
{ | |
EditorApplication.OpenScene(originalScene); | |
rebuildScene = true; | |
originalScene = ""; | |
} | |
if (rebuildScene) | |
{ | |
SetupScene(); | |
} | |
if (rebuildScene || stateChanged || !settings.emptyScene) | |
{ | |
UpdateMaterialPreview(lastMaterial); | |
Repaint(); | |
stateChanged = false; | |
} | |
} | |
void OnGUI() | |
{ | |
var material = GetTargetMaterial(); | |
if (material == null) | |
return; | |
if (lastMaterial != material) | |
UpdateMaterialPreview(material); | |
if (material) | |
lastMaterial = material; | |
EditorGUILayout.BeginHorizontal(); | |
EditorGUILayout.BeginVertical(GUILayout.MaxWidth(200)); | |
if (!(originalScene == "" && EditorApplication.currentScene == "")) | |
{ | |
settings.emptyScene = !EditorGUILayout.BeginToggleGroup("Scene ligthing", !settings.emptyScene); | |
EditorGUILayout.EndToggleGroup(); | |
} | |
settings.useCustomLights = EditorGUILayout.BeginToggleGroup("Custom lighting", settings.useCustomLights); | |
if (settings.useCustomLights) | |
{ | |
EditorGUI.indentLevel = 1; | |
settings.ambient = EditorGUILayout.ColorField("Ambient", settings.ambient); | |
for (int q = 0; q < BakeMaterialSettings.kLights; ++q) | |
{ | |
settings.enableLight[q] = EditorGUILayout.BeginToggleGroup("Light", settings.enableLight[q]); | |
EditorGUI.indentLevel = 2; | |
settings.colorLight[q] = EditorGUILayout.ColorField("Color", settings.colorLight[q]); | |
settings.dirLight[q] = EditorGUILayout.Vector2Field("Direction", settings.dirLight[q]); | |
EditorGUILayout.EndToggleGroup(); | |
} | |
} | |
EditorGUI.indentLevel = 0; | |
EditorGUILayout.EndToggleGroup(); | |
settings.bakeAlpha = EditorGUILayout.Toggle("Bake Alpha", settings.bakeAlpha); | |
settings.bakeMainTexAsWhite = !EditorGUILayout.Toggle("MainTex", !settings.bakeMainTexAsWhite); | |
settings.minTextureResolution = EditorGUILayout.IntField("Min Resolution", settings.minTextureResolution); | |
settings.maxTextureResolution = EditorGUILayout.IntField("Max Resolution", settings.maxTextureResolution); | |
settings.minTextureResolution = Mathf.Max(2, settings.minTextureResolution); | |
settings.maxTextureResolution = Mathf.Max(settings.minTextureResolution, settings.maxTextureResolution); | |
EditorGUILayout.BeginHorizontal(); | |
if (GUILayout.Button("Bake")) | |
{ | |
CaptureMaterial(lastMaterial); | |
} | |
if (GUILayout.Button("Bake Selected")) | |
{ | |
scheduleBakeOnNextUpdate = true; | |
} | |
EditorGUILayout.EndHorizontal(); | |
EditorGUILayout.EndVertical(); | |
texViewScrollPosition = EditorGUILayout.BeginScrollView(texViewScrollPosition); | |
var r = GUILayoutUtility.GetAspectRect(1.0f); | |
if (previewTexture) | |
EditorGUI.DrawPreviewTexture(r, previewTexture); | |
EditorGUILayout.EndScrollView(); | |
EditorGUILayout.EndHorizontal(); | |
if (GUI.changed) | |
{ | |
stateChanged = true; | |
} | |
} | |
[MenuItem("Tools/Bake Material ...", false, 5)] | |
static void CreateBakeEditor() | |
{ | |
var window = EditorWindow.GetWindow(typeof(BakeMaterial)); | |
window.minSize = kWindowMinSize; | |
window.Show(); | |
} | |
[MenuItem("Tools/Bake Selected Materials", false, 4)] | |
static void Bake() | |
{ | |
var instanceIDs = Selection.instanceIDs; | |
var currentScene = EditorApplication.currentScene; | |
var wasAlreadyVisible = BakeMaterial.visible; | |
var window = (BakeMaterial)EditorWindow.GetWindow(typeof(BakeMaterial)); | |
if (window.settings.emptyScene) | |
{ | |
if (!EditorApplication.SaveCurrentSceneIfUserWantsTo()) | |
return; | |
EditorApplication.NewScene(); | |
} | |
window.SetupScene(); | |
foreach (var i in instanceIDs) | |
{ | |
Material m = EditorUtility.InstanceIDToObject(i) as Material; | |
if (m) | |
window.CaptureMaterial(m); | |
} | |
window.DestroyScene(); | |
if (!window.settings.emptyScene && !string.IsNullOrEmpty(currentScene)) | |
{ | |
EditorApplication.OpenScene(currentScene); | |
} | |
if (!wasAlreadyVisible) | |
window.Close(); | |
} | |
static Vector2 FindLargestTextureResolution(Material m, int minTexRes, int maxTexRes) | |
{ | |
var res = new Vector2(minTexRes, minTexRes); | |
foreach (var n in BakeMaterialSettings.kStandardTexNames) | |
{ | |
if (!m.HasProperty(n)) | |
continue; | |
Texture t = m.GetTexture(n); | |
if (!t) | |
continue; | |
res.x = Mathf.Max(res.x, t.width); | |
res.y = Mathf.Max(res.y, t.height); | |
} | |
res.x = Mathf.Min(res.x, maxTexRes); | |
res.y = Mathf.Min(res.y, maxTexRes); | |
return res; | |
} | |
static RenderTexture RenderCameraToRenderTexture(Camera cam, int width, int height) | |
{ | |
var rt = cam.GetComponent<Camera>().targetTexture; | |
if (rt && rt.width != width && rt.height != height) | |
DestroyImmediate(rt); | |
if (!rt) | |
rt = new RenderTexture(width, height, 24); | |
cam.GetComponent<Camera>().targetTexture = rt; | |
cam.GetComponent<Camera>().Render(); | |
return rt; | |
} | |
static void RenderTextureToPNG(RenderTexture rt, bool bakeAlpha, string assetPath) | |
{ | |
RenderTexture.active = rt; | |
var screenShot = new Texture2D(rt.width, rt.height, bakeAlpha ? TextureFormat.ARGB32 : TextureFormat.RGB24, false); | |
screenShot.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); | |
RenderTexture.active = null; | |
var bytes = screenShot.EncodeToPNG(); | |
System.IO.File.WriteAllBytes(assetPath, bytes); | |
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); | |
} | |
} | |
{ | |
private static string kEditorPrefsName = "BakeMaterialSettings"; | |
public static int kBakingLayerShouldBeUnusedInScene = 30; | |
public static string[] kStandardTexNames = { "_MainTex", "_BumpMap", "_Detail", "_ParallaxMap", "_Parallax" }; | |
public bool bakeAlpha = false; | |
public bool bakeMainTexAsWhite = false; | |
public int minTextureResolution = 8; | |
public int maxTextureResolution = 2048; | |
public bool emptyScene = false; | |
public bool useCustomLights = false; | |
public Color ambient = Color.black; | |
public static int kLights = 3; | |
public bool[] enableLight = new bool[kLights]; | |
public Color[] colorLight = new Color[kLights]; | |
public Vector2[] dirLight = new Vector2[kLights]; | |
public BakeMaterialSettings() | |
{ | |
Load(); | |
} | |
public void Load() | |
{ | |
bakeAlpha = EditorPrefs.GetBool(kEditorPrefsName + ".bakeAlpha"); | |
bakeMainTexAsWhite = EditorPrefs.GetBool(kEditorPrefsName + ".bakeMainTexAsWhite"); | |
minTextureResolution = EditorPrefs.GetInt(kEditorPrefsName + ".minTextureResolution", 8); | |
maxTextureResolution = EditorPrefs.GetInt(kEditorPrefsName + ".maxTextureResolution", 2048); | |
emptyScene = EditorPrefs.GetBool(kEditorPrefsName + ".emptyScene"); | |
useCustomLights = EditorPrefs.GetBool(kEditorPrefsName + ".useCustomLights"); | |
ambient.r = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.r"); | |
ambient.g = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.g"); | |
ambient.b = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.b"); | |
ambient.a = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.a", 1.0f); | |
for (int q = 0; q < kLights; ++q) | |
{ | |
enableLight[q] = EditorPrefs.GetBool(kEditorPrefsName + ".enableLight" + q); | |
colorLight[q].r = EditorPrefs.GetFloat(kEditorPrefsName + ".color.r" + q, 0.5f); | |
colorLight[q].g = EditorPrefs.GetFloat(kEditorPrefsName + ".color.g" + q, 0.5f); | |
colorLight[q].b = EditorPrefs.GetFloat(kEditorPrefsName + ".color.b" + q, 0.5f); | |
colorLight[q].a = EditorPrefs.GetFloat(kEditorPrefsName + ".color.a" + q, 1.0f); | |
dirLight[q].x = EditorPrefs.GetFloat(kEditorPrefsName + ".dir.x" + q); | |
dirLight[q].y = EditorPrefs.GetFloat(kEditorPrefsName + ".dir.y" + q); | |
} | |
} | |
public void Save() | |
{ | |
EditorPrefs.SetBool(kEditorPrefsName + ".bakeAlpha", bakeAlpha); | |
EditorPrefs.SetBool(kEditorPrefsName + ".bakeMainTexAsWhite", bakeMainTexAsWhite); | |
EditorPrefs.SetInt(kEditorPrefsName + ".minTextureResolution", minTextureResolution); | |
EditorPrefs.SetInt(kEditorPrefsName + ".maxTextureResolution", maxTextureResolution); | |
EditorPrefs.GetBool(kEditorPrefsName + ".emptyScene", emptyScene); | |
EditorPrefs.SetBool(kEditorPrefsName + ".useCustomLights", useCustomLights); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.r", ambient.r); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.g", ambient.g); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.b", ambient.b); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.a", ambient.a); | |
for (int q = 0; q < kLights; ++q) | |
{ | |
EditorPrefs.SetBool(kEditorPrefsName + ".enableLight" + q, enableLight[q]); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".color.r" + q, colorLight[q].r); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".color.g" + q, colorLight[q].g); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".color.b" + q, colorLight[q].b); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".color.a" + q, colorLight[q].a); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".dir.x" + q, dirLight[q].x); | |
EditorPrefs.SetFloat(kEditorPrefsName + ".dir.y" + q, dirLight[q].y); | |
} | |
} | |
} | |
public class BakeMaterial : EditorWindow | |
{ | |
private static string kMateriBakeNodeName = "__MateriaBakeSetup"; | |
private static Vector2 kWindowMinSize = new Vector2(300, 386); | |
private BakeMaterialSettings settings; | |
private static bool visible = false; | |
private GameObject camera; | |
private GameObject plane; | |
private Texture previewTexture; | |
private GameObject[] lights = new GameObject[BakeMaterialSettings.kLights]; | |
private bool stateChanged = false; | |
private Vector2 texViewScrollPosition = Vector2.zero; | |
private Material lastMaterial; | |
private string originalScene = ""; | |
private bool scheduleBakeOnNextUpdate = false; | |
private void SetupScene() | |
{ | |
DestroyScene(); | |
GameObject oldGo = GameObject.Find(kMateriBakeNodeName); | |
if (oldGo) | |
DestroyImmediate(oldGo); | |
camera = new GameObject(kMateriBakeNodeName, typeof(Camera)); | |
plane = GameObject.CreatePrimitive(PrimitiveType.Plane); | |
Camera cam = camera.GetComponent<Camera>(); | |
cam.backgroundColor = Color.black; | |
cam.clearFlags = CameraClearFlags.SolidColor; | |
cam.orthographic = true; | |
cam.orthographicSize = 5.0f; | |
cam.cullingMask = 1 << BakeMaterialSettings.kBakingLayerShouldBeUnusedInScene; | |
plane.transform.parent = cam.transform; | |
plane.transform.position = Vector3.forward * 10.0f; | |
plane.transform.rotation = Quaternion.Euler(0, 0, 180) * Quaternion.Euler(-90, 0, 0); | |
plane.layer = BakeMaterialSettings.kBakingLayerShouldBeUnusedInScene; | |
for(int i = 0; i < lights.Length; i++) | |
{ | |
lights[i] = new GameObject(); | |
lights[i].AddComponent<Light>(); | |
var light = lights[i].GetComponent<Light>(); | |
light.type = LightType.Directional; | |
light.cullingMask = 1 << BakeMaterialSettings.kBakingLayerShouldBeUnusedInScene; | |
lights[i].transform.parent = cam.transform; | |
lights[i].SetActive(false); | |
} | |
} | |
private void UpdateScene(Material m) | |
{ | |
for (int q = 0; q < BakeMaterialSettings.kLights; ++q) | |
{ | |
lights[q].SetActive(settings.useCustomLights & settings.enableLight[q]); | |
lights[q].GetComponent<Light>().color = settings.colorLight[q]; | |
lights[q].transform.rotation = | |
Quaternion.AngleAxis(settings.dirLight[q].x, Vector3.up) * | |
Quaternion.AngleAxis(settings.dirLight[q].y, Vector3.right); | |
} | |
if (settings.useCustomLights) | |
RenderSettings.ambientLight = settings.ambient; | |
else if (settings.emptyScene) | |
RenderSettings.ambientLight = Color.white; | |
plane.GetComponent<Renderer>().material = m; | |
} | |
private void DestroyScene() | |
{ | |
GameObject.DestroyImmediate(camera); | |
GameObject.DestroyImmediate(plane); | |
GameObject.DestroyImmediate(previewTexture); | |
} | |
RenderTexture UpdateMaterialPreview(Material m) | |
{ | |
if (!m) | |
return null; | |
var saveAmbientLight = RenderSettings.ambientLight; | |
var saveMainTexture = m.mainTexture; | |
if (settings.bakeMainTexAsWhite) | |
m.mainTexture = null; | |
// setup | |
if (!camera) | |
SetupScene(); | |
camera.SetActive(true); | |
UpdateScene(m); | |
var res = FindLargestTextureResolution(plane.GetComponent<Renderer>().sharedMaterial, settings.minTextureResolution, settings.maxTextureResolution); | |
var rt = RenderCameraToRenderTexture(camera.GetComponent<Camera>(), Mathf.FloorToInt(res.x), Mathf.FloorToInt(res.y)); | |
// restore | |
camera.SetActive(false); | |
RenderSettings.ambientLight = saveAmbientLight; | |
m.mainTexture = saveMainTexture; | |
previewTexture = rt; | |
return rt; | |
} | |
void CaptureMaterial(Material m) | |
{ | |
var matAssetPath = AssetDatabase.GetAssetPath(m); | |
var assetPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(matAssetPath), System.IO.Path.GetFileNameWithoutExtension(matAssetPath)); | |
var rt = UpdateMaterialPreview(m); | |
RenderTextureToPNG(rt, settings.bakeAlpha, assetPath + ".png"); | |
} | |
void OnEnable() | |
{ | |
if (settings == null) | |
settings = new BakeMaterialSettings(); | |
SetupScene(); | |
visible = true; | |
} | |
void OnDisable() | |
{ | |
DestroyScene(); | |
settings.Save(); | |
visible = false; | |
} | |
static Material GetTargetMaterial() | |
{ | |
Material material = null; | |
var id = Selection.activeInstanceID; | |
if (id > 0) | |
{ | |
var obj = EditorUtility.InstanceIDToObject(id); | |
if (obj != null) | |
{ | |
var mesh = ((GameObject)obj).GetComponent<MeshRenderer>(); | |
if (mesh != null) | |
{ | |
material = mesh.material; | |
} | |
} | |
} | |
return material; | |
} | |
void OnSelectionChange() | |
{ | |
Repaint(); | |
} | |
void Update() | |
{ | |
bool rebuildScene = false; | |
if (scheduleBakeOnNextUpdate) | |
{ | |
Bake(); | |
scheduleBakeOnNextUpdate = false; | |
rebuildScene = true; | |
} | |
if (originalScene == "" && EditorApplication.currentScene == "") | |
settings.emptyScene = true; | |
if (settings.emptyScene && originalScene == "" && EditorApplication.currentScene != "") | |
{ | |
DestroyScene(); | |
if (EditorApplication.SaveCurrentSceneIfUserWantsTo()) | |
{ | |
originalScene = EditorApplication.currentScene; | |
EditorApplication.NewScene(); | |
} | |
else | |
settings.emptyScene = false; | |
rebuildScene = true; | |
} | |
else if (!settings.emptyScene && originalScene != "") | |
{ | |
EditorApplication.OpenScene(originalScene); | |
rebuildScene = true; | |
originalScene = ""; | |
} | |
if (rebuildScene) | |
{ | |
SetupScene(); | |
} | |
if (rebuildScene || stateChanged || !settings.emptyScene) | |
{ | |
UpdateMaterialPreview(lastMaterial); | |
Repaint(); | |
stateChanged = false; | |
} | |
} | |
void OnGUI() | |
{ | |
var material = GetTargetMaterial(); | |
if (material == null) | |
return; | |
if (lastMaterial != material) | |
UpdateMaterialPreview(material); | |
if (material) | |
lastMaterial = material; | |
EditorGUILayout.BeginHorizontal(); | |
EditorGUILayout.BeginVertical(GUILayout.MaxWidth(200)); | |
if (!(originalScene == "" && EditorApplication.currentScene == "")) | |
{ | |
settings.emptyScene = !EditorGUILayout.BeginToggleGroup("Scene ligthing", !settings.emptyScene); | |
EditorGUILayout.EndToggleGroup(); | |
} | |
settings.useCustomLights = EditorGUILayout.BeginToggleGroup("Custom lighting", settings.useCustomLights); | |
if (settings.useCustomLights) | |
{ | |
EditorGUI.indentLevel = 1; | |
settings.ambient = EditorGUILayout.ColorField("Ambient", settings.ambient); | |
for (int q = 0; q < BakeMaterialSettings.kLights; ++q) | |
{ | |
settings.enableLight[q] = EditorGUILayout.BeginToggleGroup("Light", settings.enableLight[q]); | |
EditorGUI.indentLevel = 2; | |
settings.colorLight[q] = EditorGUILayout.ColorField("Color", settings.colorLight[q]); | |
settings.dirLight[q] = EditorGUILayout.Vector2Field("Direction", settings.dirLight[q]); | |
EditorGUILayout.EndToggleGroup(); | |
} | |
} | |
EditorGUI.indentLevel = 0; | |
EditorGUILayout.EndToggleGroup(); | |
settings.bakeAlpha = EditorGUILayout.Toggle("Bake Alpha", settings.bakeAlpha); | |
settings.bakeMainTexAsWhite = !EditorGUILayout.Toggle("MainTex", !settings.bakeMainTexAsWhite); | |
settings.minTextureResolution = EditorGUILayout.IntField("Min Resolution", settings.minTextureResolution); | |
settings.maxTextureResolution = EditorGUILayout.IntField("Max Resolution", settings.maxTextureResolution); | |
settings.minTextureResolution = Mathf.Max(2, settings.minTextureResolution); | |
settings.maxTextureResolution = Mathf.Max(settings.minTextureResolution, settings.maxTextureResolution); | |
EditorGUILayout.BeginHorizontal(); | |
if (GUILayout.Button("Bake")) | |
{ | |
CaptureMaterial(lastMaterial); | |
} | |
if (GUILayout.Button("Bake Selected")) | |
{ | |
scheduleBakeOnNextUpdate = true; | |
} | |
EditorGUILayout.EndHorizontal(); | |
EditorGUILayout.EndVertical(); | |
texViewScrollPosition = EditorGUILayout.BeginScrollView(texViewScrollPosition); | |
var r = GUILayoutUtility.GetAspectRect(1.0f); | |
if (previewTexture) | |
EditorGUI.DrawPreviewTexture(r, previewTexture); | |
EditorGUILayout.EndScrollView(); | |
EditorGUILayout.EndHorizontal(); | |
if (GUI.changed) | |
{ | |
stateChanged = true; | |
} | |
} | |
[MenuItem("Tools/Bake Material ...", false, 5)] | |
static void CreateBakeEditor() | |
{ | |
var window = EditorWindow.GetWindow(typeof(BakeMaterial)); | |
window.minSize = kWindowMinSize; | |
window.Show(); | |
} | |
[MenuItem("Tools/Bake Selected Materials", false, 4)] | |
static void Bake() | |
{ | |
var instanceIDs = Selection.instanceIDs; | |
var currentScene = EditorApplication.currentScene; | |
var wasAlreadyVisible = BakeMaterial.visible; | |
var window = (BakeMaterial)EditorWindow.GetWindow(typeof(BakeMaterial)); | |
if (window.settings.emptyScene) | |
{ | |
if (!EditorApplication.SaveCurrentSceneIfUserWantsTo()) | |
return; | |
EditorApplication.NewScene(); | |
} | |
window.SetupScene(); | |
foreach (var i in instanceIDs) | |
{ | |
Material m = EditorUtility.InstanceIDToObject(i) as Material; | |
if (m) | |
window.CaptureMaterial(m); | |
} | |
window.DestroyScene(); | |
if (!window.settings.emptyScene && !string.IsNullOrEmpty(currentScene)) | |
{ | |
EditorApplication.OpenScene(currentScene); | |
} | |
if (!wasAlreadyVisible) | |
window.Close(); | |
} | |
static Vector2 FindLargestTextureResolution(Material m, int minTexRes, int maxTexRes) | |
{ | |
var res = new Vector2(minTexRes, minTexRes); | |
foreach (var n in BakeMaterialSettings.kStandardTexNames) | |
{ | |
if (!m.HasProperty(n)) | |
continue; | |
Texture t = m.GetTexture(n); | |
if (!t) | |
continue; | |
res.x = Mathf.Max(res.x, t.width); | |
res.y = Mathf.Max(res.y, t.height); | |
} | |
res.x = Mathf.Min(res.x, maxTexRes); | |
res.y = Mathf.Min(res.y, maxTexRes); | |
return res; | |
} | |
static RenderTexture RenderCameraToRenderTexture(Camera cam, int width, int height) | |
{ | |
var rt = cam.GetComponent<Camera>().targetTexture; | |
if (rt && rt.width != width && rt.height != height) | |
DestroyImmediate(rt); | |
if (!rt) | |
rt = new RenderTexture(width, height, 24); | |
cam.GetComponent<Camera>().targetTexture = rt; | |
cam.GetComponent<Camera>().Render(); | |
return rt; | |
} | |
static void RenderTextureToPNG(RenderTexture rt, bool bakeAlpha, string assetPath) | |
{ | |
RenderTexture.active = rt; | |
var screenShot = new Texture2D(rt.width, rt.height, bakeAlpha ? TextureFormat.ARGB32 : TextureFormat.RGB24, false); | |
screenShot.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); | |
RenderTexture.active = null; | |
var bytes = screenShot.EncodeToPNG(); | |
System.IO.File.WriteAllBytes(assetPath, bytes); | |
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment