|
using UnityEngine;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using DigitalOpus.MB.Core;
|
|
using LuaFramework;
|
|
public class MB3_MeshBakerGrouper : MonoBehaviour {
|
|
public MB3_MeshBakerGrouperCore grouper;
|
|
|
|
//these are for getting a resonable bounds in which to draw gizmos.
|
|
[HideInInspector] public Bounds sourceObjectBounds = new Bounds(Vector3.zero,Vector3.one);
|
|
|
|
void OnDrawGizmosSelected(){
|
|
if (grouper == null) return;
|
|
if (grouper.clusterGrouper == null) return;
|
|
if (grouper.clusterGrouper.clusterType == MB3_MeshBakerGrouperCore.ClusterType.grid){
|
|
Vector3 cs = grouper.clusterGrouper.cellSize;
|
|
if (cs.x <= .00001f || cs.y <= .00001f || cs.z <= .00001f) return;
|
|
Vector3 p = sourceObjectBounds.center - sourceObjectBounds.extents;
|
|
Vector3 offset = grouper.clusterGrouper.origin;
|
|
offset.x = offset.x % cs.x;
|
|
offset.y = offset.y % cs.y;
|
|
offset.z = offset.z % cs.z;
|
|
//snap p to closest cell center
|
|
Vector3 start;
|
|
p.x = Mathf.Round((p.x) / cs.x) * cs.x + offset.x;
|
|
p.y = Mathf.Round((p.y) / cs.y) * cs.y + offset.y;
|
|
p.z = Mathf.Round((p.z) / cs.z) * cs.z + offset.z;
|
|
if (p.x > sourceObjectBounds.center.x - sourceObjectBounds.extents.x) p.x = p.x - cs.x;
|
|
if (p.y > sourceObjectBounds.center.y - sourceObjectBounds.extents.y) p.y = p.y - cs.y;
|
|
if (p.z > sourceObjectBounds.center.z - sourceObjectBounds.extents.z) p.z = p.z - cs.z;
|
|
start = p;
|
|
int numcells = Mathf.CeilToInt(sourceObjectBounds.size.x / cs.x + sourceObjectBounds.size.y / cs.y + sourceObjectBounds.size.z / cs.z);
|
|
if (numcells > 200){
|
|
Gizmos.DrawWireCube(grouper.clusterGrouper.origin + cs/2f,cs);
|
|
} else {
|
|
for (;p.x < sourceObjectBounds.center.x + sourceObjectBounds.extents.x; p.x += cs.x){
|
|
p.y = start.y;
|
|
for (;p.y < sourceObjectBounds.center.y + sourceObjectBounds.extents.y; p.y += cs.y){
|
|
p.z = start.z;
|
|
for (;p.z < sourceObjectBounds.center.z + sourceObjectBounds.extents.z; p.z += cs.z){
|
|
Gizmos.DrawWireCube(p + cs/2f,cs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (grouper.clusterGrouper.clusterType == MB3_MeshBakerGrouperCore.ClusterType.pie){
|
|
if (grouper.clusterGrouper.pieAxis.magnitude < .1f) return;
|
|
if (grouper.clusterGrouper.pieNumSegments < 1) return;
|
|
float rad = sourceObjectBounds.extents.magnitude;
|
|
DrawCircle(grouper.clusterGrouper.pieAxis,grouper.clusterGrouper.origin,rad,24);
|
|
Quaternion yIsUp2PieAxis = Quaternion.FromToRotation(Vector3.up,grouper.clusterGrouper.pieAxis);
|
|
Quaternion rStep = Quaternion.AngleAxis(180f / grouper.clusterGrouper.pieNumSegments, Vector3.up);
|
|
Vector3 r = rStep * Vector3.forward;
|
|
for (int i = 0; i < grouper.clusterGrouper.pieNumSegments; i++){
|
|
Vector3 rr = yIsUp2PieAxis * r;
|
|
Gizmos.DrawLine(grouper.clusterGrouper.origin, grouper.clusterGrouper.origin + rr * rad);
|
|
r = rStep * r;
|
|
r = rStep * r;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void DrawCircle (Vector3 axis, Vector3 center, float radius, int subdiv) {
|
|
Quaternion q = Quaternion.AngleAxis (360 / subdiv, axis);
|
|
Vector3 r = new Vector3 (axis.y, -axis.x, axis.z); //should be perpendicular to axis
|
|
r.Normalize ();
|
|
r *= radius;
|
|
for (int i = 0; i < subdiv+1; i ++) {
|
|
Vector3 r2 = q * r;
|
|
Gizmos.DrawLine (center + r, center + r2);
|
|
r = r2;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public class MB3_MeshBakerGrouperCore{
|
|
public enum ClusterType{
|
|
none,
|
|
grid,
|
|
pie,
|
|
//voroni,
|
|
}
|
|
|
|
[Serializable]
|
|
public class ClusterGrouper{
|
|
|
|
public ClusterType clusterType;
|
|
public Vector3 origin;
|
|
//for grid
|
|
public Vector3 cellSize;
|
|
//for pie
|
|
public int pieNumSegments = 4;
|
|
public Vector3 pieAxis = Vector3.up;
|
|
|
|
public Dictionary<string,List<Renderer>> FilterIntoGroups(List<GameObject> selection){
|
|
if (clusterType == ClusterType.none){
|
|
return FilterIntoGroupsNone(selection);
|
|
} else if (clusterType == ClusterType.grid) {
|
|
return FilterIntoGroupsGrid(selection);
|
|
} else if (clusterType == ClusterType.pie){
|
|
return FilterIntoGroupsPie(selection);
|
|
}
|
|
return new Dictionary<string, List<Renderer>>();
|
|
}
|
|
|
|
public Dictionary<string,List<Renderer>> FilterIntoGroupsNone(List<GameObject> selection)
|
|
{
|
|
LogManager.Log ("Filtering into groups none");
|
|
|
|
Dictionary<string,List<Renderer>> cell2objs = new Dictionary<string,List<Renderer>>();
|
|
|
|
List<Renderer> rs = new List<Renderer>();
|
|
for (int i = 0; i < selection.Count; i++)
|
|
{
|
|
rs.Add (selection[i].GetComponent<Renderer>());
|
|
}
|
|
|
|
cell2objs.Add ("MeshBaker",rs);
|
|
return cell2objs;
|
|
}
|
|
|
|
public Dictionary<string,List<Renderer>> FilterIntoGroupsGrid(List<GameObject> selection){
|
|
Dictionary<string,List<Renderer>> cell2objs = new Dictionary<string,List<Renderer>>();
|
|
if (cellSize.x <= 0f || cellSize.y <= 0f || cellSize.z <= 0f ){
|
|
LogManager.LogError ("cellSize x,y,z must all be greater than zero.");
|
|
return cell2objs;
|
|
}
|
|
|
|
LogManager.Log("Collecting renderers in each cell");
|
|
foreach (GameObject t in selection){
|
|
GameObject go = t;
|
|
Renderer[] mrs = go.GetComponentsInChildren<Renderer>();
|
|
for (int j = 0; j < mrs.Length; j++){
|
|
if (mrs[j] is MeshRenderer || mrs[j] is SkinnedMeshRenderer){
|
|
//get the cell this gameObject is in
|
|
Vector3 gridVector = mrs[j].transform.position;
|
|
gridVector.x = Mathf.Floor((gridVector.x - origin.x) / cellSize.x) * cellSize.x;
|
|
gridVector.y = Mathf.Floor((gridVector.y - origin.y) / cellSize.y) * cellSize.y;
|
|
gridVector.z = Mathf.Floor((gridVector.z - origin.z) / cellSize.z) * cellSize.z;
|
|
List<Renderer> objs = null;
|
|
string gridVectorStr = gridVector.ToString();
|
|
if (cell2objs.ContainsKey(gridVectorStr)){
|
|
objs = cell2objs[gridVectorStr];
|
|
} else {
|
|
objs = new List<Renderer>();
|
|
cell2objs.Add (gridVectorStr,objs);
|
|
}
|
|
if (!objs.Contains(mrs[j])){
|
|
objs.Add (mrs[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return cell2objs;
|
|
}
|
|
|
|
public Dictionary<string,List<Renderer>> FilterIntoGroupsPie(List<GameObject> selection){
|
|
Dictionary<string,List<Renderer>> cell2objs = new Dictionary<string,List<Renderer>>();
|
|
if (pieNumSegments == 0 ){
|
|
LogManager.LogError ("pieNumSegments must be greater than zero.");
|
|
return cell2objs;
|
|
}
|
|
|
|
if (pieAxis.magnitude <= .000001f ){
|
|
LogManager.LogError ("Pie axis must have length greater than zero.");
|
|
return cell2objs;
|
|
}
|
|
|
|
pieAxis.Normalize();
|
|
Quaternion pieAxis2yIsUp = Quaternion.FromToRotation(pieAxis,Vector3.up);
|
|
|
|
LogManager.Log("Collecting renderers in each cell");
|
|
foreach (GameObject t in selection){
|
|
GameObject go = t;
|
|
Renderer[] mrs = go.GetComponentsInChildren<Renderer>();
|
|
for (int j = 0; j < mrs.Length; j++){
|
|
if (mrs[j] is MeshRenderer || mrs[j] is SkinnedMeshRenderer){
|
|
//get the cell this gameObject is in
|
|
Vector3 origin2obj = mrs[j].transform.position - origin;
|
|
origin2obj.Normalize();
|
|
origin2obj = pieAxis2yIsUp * origin2obj;
|
|
|
|
float d_aboutY = 0f;
|
|
if (Mathf.Abs(origin2obj.x) < 10e-5f && Mathf.Abs(origin2obj.z) < 10e-5f){
|
|
d_aboutY = 0f;
|
|
} else {
|
|
d_aboutY = Mathf.Atan2(origin2obj.z,origin2obj.x) * Mathf.Rad2Deg;
|
|
if (d_aboutY < 0f) d_aboutY = 360f + d_aboutY;
|
|
}
|
|
|
|
int segment = Mathf.FloorToInt(d_aboutY / 360f * pieNumSegments);
|
|
|
|
List<Renderer> objs = null;
|
|
string segStr = "seg_" + segment;
|
|
if (cell2objs.ContainsKey(segStr)){
|
|
objs = cell2objs[segStr];
|
|
} else {
|
|
objs = new List<Renderer>();
|
|
cell2objs.Add (segStr,objs);
|
|
}
|
|
if (!objs.Contains(mrs[j])){
|
|
objs.Add (mrs[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return cell2objs;
|
|
}
|
|
}
|
|
|
|
public ClusterGrouper clusterGrouper;
|
|
public bool clusterOnLMIndex;
|
|
|
|
public void DoClustering(MB3_TextureBaker tb){
|
|
if (clusterGrouper == null){
|
|
LogManager.LogError("Cluster Grouper was null.");
|
|
return;
|
|
}
|
|
|
|
//todo warn for no objects and no material bake result
|
|
Dictionary<string,List<Renderer>> cell2objs = clusterGrouper.FilterIntoGroups(tb.GetObjectsToCombine());
|
|
|
|
LogManager.Log ("Found " + cell2objs.Count + " cells with Renderers. Creating bakers.");
|
|
if (clusterOnLMIndex){
|
|
Dictionary<string,List<Renderer>> cell2objsNew = new Dictionary<string, List<Renderer>>();
|
|
foreach (string key in cell2objs.Keys){
|
|
List<Renderer> gaws = cell2objs[key];
|
|
Dictionary<int,List<Renderer>> idx2objs = GroupByLightmapIndex(gaws);
|
|
foreach(int keyIdx in idx2objs.Keys){
|
|
string keyNew = key + "-LM-" + keyIdx;
|
|
cell2objsNew.Add (keyNew,idx2objs[keyIdx]);
|
|
}
|
|
}
|
|
cell2objs = cell2objsNew;
|
|
}
|
|
foreach (string key in cell2objs.Keys){
|
|
List<Renderer> gaws = cell2objs[key];
|
|
AddMeshBaker (tb,key,gaws);
|
|
}
|
|
}
|
|
|
|
Dictionary<int,List<Renderer>> GroupByLightmapIndex(List<Renderer> gaws){
|
|
Dictionary<int,List<Renderer>> idx2objs = new Dictionary<int, List<Renderer>>();
|
|
for (int i = 0; i < gaws.Count; i++){
|
|
List<Renderer> objs = null;
|
|
if (idx2objs.ContainsKey(gaws[i].lightmapIndex)){
|
|
objs = idx2objs[gaws[i].lightmapIndex];
|
|
} else {
|
|
objs = new List<Renderer>();
|
|
idx2objs.Add (gaws[i].lightmapIndex,objs);
|
|
}
|
|
objs.Add (gaws[i]);
|
|
}
|
|
return idx2objs;
|
|
}
|
|
|
|
void AddMeshBaker(MB3_TextureBaker tb, string key, List<Renderer> gaws){
|
|
int numVerts = 0;
|
|
for (int i = 0; i < gaws.Count; i++){
|
|
Mesh m = MB_Utility.GetMesh(gaws[i].gameObject);
|
|
if (m != null)
|
|
numVerts += m.vertexCount;
|
|
}
|
|
|
|
GameObject nmb = new GameObject("MeshBaker-" + key);
|
|
nmb.transform.position = Vector3.zero;
|
|
MB3_MeshBakerCommon newMeshBaker;
|
|
if (numVerts >= 65535){
|
|
newMeshBaker = nmb.AddComponent<MB3_MultiMeshBaker>();
|
|
newMeshBaker.useObjsToMeshFromTexBaker = false;
|
|
} else {
|
|
newMeshBaker = nmb.AddComponent<MB3_MeshBaker>();
|
|
newMeshBaker.useObjsToMeshFromTexBaker = false;
|
|
}
|
|
newMeshBaker.textureBakeResults = tb.textureBakeResults;
|
|
newMeshBaker.transform.parent = tb.transform;
|
|
for (int i = 0; i < gaws.Count; i++){
|
|
newMeshBaker.GetObjectsToCombine().Add (gaws[i].gameObject);
|
|
}
|
|
}
|
|
}
|