模型烘焙後保存mesh數據生成新的預製體
unity版本5.4.1
1、C#代碼控制模型烘焙後生成新的材質球保存mesh數據,並關聯到新生成的預製體。
SetUVData.cs用於掛在遊戲物體上,設置你要賦值的數據,代碼如下:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteInEditMode]
public class SetUVData : MonoBehaviour {
public bool preservePrefab = false;
//下面的是另一種加載預製體的方法-----------------------------------------------
// MeshRenderer[] renderers ;
// Transform[] renderers ;
// public List <RendererInfo> m_RendererInfo;
// [System.Serializable]
// public struct RendererInfo
// {
// public Renderer renderer;
// public int lightmapIndex;
// public Vector4 lightmapOffsetScale;
// }
// void Awake()
// {
// Debug.Log ("--------Awake----------");
//// LoadLightmap ();
// renderers = GetComponentsInChildren<Transform> ();
//
// for (int i = 0; i < renderers.Length; i++)
// {
// Debug.Log ("renders [i].lightmapIndex "+i);
//// Debug.Log ("renders [i].lightmapIndex "+i+" " + renderers [i].lightmapIndex);
// }
// }
// void Start()
// {
// RaycastHit hit;
// Vector3 pos = transform.position + new Vector3 (0, 0.1f,0);
// Debug.Log ("pos " + pos);
//
// if (Physics.Raycast (pos, -Vector3.up, out hit, 100f,LayerMask.GetMask ("Lighting"))) { //LayerMask..GetMask ("Lighting")
// Debug.DrawLine (transform.position, hit.point, Color.red);
// Debug.Log ("???????????"+ hit.collider.gameObject);
// }
// }
/// <summary>
/// Saves the lightmap.保存光照貼圖信息到預製體
/// </summary>
// public void SaveLightmap() {
// Debug.Log ("----------SaveLightmap-----------");
// m_RendererInfo.Clear ();
//
// for (int i = 0; i < renderers.Length; i++)
// {
// if(renderers[i].lightmapIndex != -1)
// {
// RendererInfo info = new RendererInfo ();
// info.renderer = renderers[i];
// info.lightmapOffsetScale = renderers [i].lightmapScaleOffset;
// info.lightmapIndex = renderers [i].lightmapIndex;
//
// m_RendererInfo.Add (info);
// }
// }
// }
/// <summary>
/// Loads the lightmap.加載光照貼圖信息到預製體
/// </summary>
// public void LoadLightmap() {
// Debug.Log ("----------LoadLightmap-----------");
// if (m_RendererInfo.Count <= 0)
// return;
//
// for (int i = 0; i < m_RendererInfo.Count; i++)
// {
// m_RendererInfo [i].renderer.lightmapIndex = m_RendererInfo [i].lightmapIndex; //將結構體中第二三的參數設置到1中
// m_RendererInfo [i].renderer.lightmapScaleOffset = m_RendererInfo [i].lightmapOffsetScale;
// }
// }
//
}
CreatUV3.cs用於自定義inspector界面及將型烘焙後生成新的材質球保存mesh數據,生成新的預製體。將這個文件放Editor文件夾下,代碼如下:
using UnityEngine;
using System.Collections;
using UnityEditor;
[CustomEditor(typeof(SetUVData))]
public class CreatUV3 : Editor {
SetUVData originalObj;
Mesh mesh;
MeshFilter [] meshFilters;
LightmapData lightmapData;
Texture2D lightmapTex2d;
Vector2 texSize;
Renderer renderer;
//inspector自定義界面編輯, custom inspector
public override void OnInspectorGUI()
{
DrawDefaultInspector();
originalObj = (SetUVData)target;
if (GUILayout.Button ("Write UV Data", GUILayout.Height (20))) {
GameObject prefab = originalObj.gameObject;
WriteDataAll (originalObj.gameObject);
if(originalObj.preservePrefab)
{
prefab = BuildPrefab () as GameObject;
EditorUtility.SetDirty (prefab);
}
}
}
/// <summary>
/// Getoriginals the name of the object.獲取當前物體的名字
/// </summary>
/// <returns>The object name.</returns>
string GetoriginalObjName()
{
string originalObjName = originalObj.gameObject.name;
return originalObjName;
}
//創建預製體
public object BuildPrefab()
{
Debug.Log ("==========BuildPrefab =============");
object temPrefab = PrefabUtility.CreateEmptyPrefab ("Assets/"+"newPfb/"+GetoriginalObjName() + ".prefab");
temPrefab = PrefabUtility.ReplacePrefab (originalObj.gameObject, temPrefab as UnityEngine.Object);
return temPrefab;
}
/// <summary>
/// Writes the data all.寫入所有的子對象中
/// </summary>
/// <param name="obj">Object.</param>
void WriteDataAll(GameObject obj)
{
Debug.Log ("originalObj.transform.childCount "+obj.transform.childCount);
meshFilters = obj.GetComponentsInChildren<MeshFilter> ();
for(int i = 0;i<meshFilters.Length;i++)
{
Debug.Log (string.Format("i{0}, meshFilters [i]: {1} ",i,meshFilters [i]) );
// GameObject target = meshFilters [i].gameObject;
if(meshFilters[i].sharedMesh == null)
{
Debug.Log (obj.name+"???meshFilters lost");
}
WriteData (meshFilters [i]);
}
}
/// <summary>
/// Writes the data.將originalObj數據寫入到mesh中,WriteData in mesh
/// </summary>
/// <param name="originalObjChuild">Original object chuild.</param>
public void WriteData (MeshFilter mf) {
mesh = GameObject.Instantiate (mf.sharedMesh) as Mesh;
// renderer = originalObjChuild.GetComponent<Renderer> ();
if (!mf.transform.GetComponent<Renderer>()) {
Debug.Log("???? no render ???");
return;
}
renderer = mf.transform.GetComponent<Renderer> ();
Vector3[] vertices = mesh.vertices;
Vector2[] newUV = new Vector2[vertices.Length];
lightmapData = LightmapSettings.lightmaps [0]; //獲取當前的光照貼圖序號.烘焙一張光照貼圖
lightmapTex2d = lightmapData.lightmapFar; //光照圖儲存所有入射光線。
string texPath = AssetDatabase.GetAssetPath (lightmapTex2d);
TextureImporter importer = TextureImporter.GetAtPath (texPath) as TextureImporter;
if (!importer.isReadable) {
importer.isReadable = true;
AssetDatabase.ImportAsset (texPath, ImportAssetOptions.ForceUpdate); //用戶啓動資源導入ImportAssetOptions.ForceUpdate
}
//UV賦值
for (int i = 0; i < vertices.Length; i++) {
// pos = originalObjChuild.TransformPoint (vertices[i]);
newUV [i] = new Vector2 (mesh.uv2 [i].x * renderer.lightmapScaleOffset.x + renderer.lightmapScaleOffset.z,
mesh.uv2 [i].y * renderer.lightmapScaleOffset.y + renderer.lightmapScaleOffset.w);
}
mesh.uv3 = newUV; //數組的形式賦值,一定要給UV3賦值這個
// mesh.colors = newColors; //數組的形式賦值
// mf.sharedMesh = mesh; //烘焙後mesh存儲了Lightmap的UV2偏移信息
if (EditorUtility.IsPersistent (mf.sharedMesh)) {
// string vpDataPath = AssetDatabase.GetAssetPath (mf.sharedMesh);
// Debug.Log ("vpDataPath " + vpDataPath);
// vpDataPath = vpDataPath.Substring (0, vpDataPath.LastIndexOf ("."));
// vpDataPath += "1.asset"; //保存地址爲原地址的位置,名字+1
AssetDatabase.CreateAsset (mesh, "Assets/" + "newMesh/" + mf.gameObject.name + ".asset");
mf.sharedMesh = mesh;
} else {
// string vpDataPath = EditorUtility.SaveFilePanelInProject ("save Mesh", "mesh", "asset", "Pick a location to save your mesh."); //打開電腦的文件保存窗口
AssetDatabase.CreateAsset (mesh, "Assets/" + "newMesh/" + mf.gameObject.name + ".asset"); //mf.sharedMesh會加上clone
mf.sharedMesh = mesh;
}
}
}
2、shader讀取當前場景的烘焙貼圖,並解碼烘焙貼圖。
//unity版本5.4.1,其他unity版本可能寫法什麼的不一樣一些。
Shader "LT/LightmapTest"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float2 uv2 : TEXCOORD2;
// float2 uv3 : TEXCOORD3;
float4 color:COLOR;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 col : TEXCOORD1;
float2 uv2 : TEXCOORD2;
// float2 uv3 : TEXCOORD3;
};
sampler2D _MainTex;
float4 _MainTex_ST;
half4 unity_LightmapST;
sampler2D unity_Lightmap;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.col = v.color;
// o.uv3 = v.uv3;
#ifndef LIGHTMAP_OFF
o.uv2 = v.uv2.xy * unity_LightmapST.xy + unity_LightmapST.zw; //模型自帶的UV2,烘焙後unity會根據模型的UV2來排列光照貼圖,據說。。。
#endif
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
#ifndef LIGHTMAP_OFF
fixed3 lm = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap,i.uv2)); //解碼光照貼圖
#endif
col.rgb *= lm;
return col;
// return fixed4(i.uv2,0,1); //發現UV2烘焙前後不一樣了,是因爲網格合併了嗎
}
ENDCG
}
}
fallback "Diffuse"
}