test : opti
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System;
|
||||
|
||||
[assembly: InternalsVisibleTo("MeshBakerTests2")]
|
||||
[assembly: InternalsVisibleTo("MeshBakerTests")]
|
||||
|
||||
public class AssemblyInfo
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 128f1b6366765e846853f8e143ca26cd
|
||||
timeCreated: 1543357217
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/AssemblyInfo.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,26 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using DigitalOpus.MB.Core;
|
||||
|
||||
public class MB2_UpdateSkinnedMeshBoundsFromBones : MonoBehaviour {
|
||||
SkinnedMeshRenderer smr;
|
||||
Transform[] bones;
|
||||
|
||||
void Start () {
|
||||
smr = GetComponent<SkinnedMeshRenderer>();
|
||||
if (smr == null){
|
||||
Debug.LogError("Need to attach MB2_UpdateSkinnedMeshBoundsFromBones script to an object with a SkinnedMeshRenderer component attached.");
|
||||
return;
|
||||
}
|
||||
bones = smr.bones;
|
||||
bool origVal = smr.updateWhenOffscreen;
|
||||
smr.updateWhenOffscreen = true;
|
||||
smr.updateWhenOffscreen = origVal;
|
||||
}
|
||||
|
||||
void Update () {
|
||||
if (smr != null){
|
||||
MB3_MeshCombiner.UpdateSkinnedMeshApproximateBoundsFromBonesStatic(bones,smr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfe3957da2b5efe438f7ffe6a2cfa712
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB2_UpdateSkinnedMeshBoundsFromBones.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,38 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using DigitalOpus.MB.Core;
|
||||
|
||||
public class MB2_UpdateSkinnedMeshBoundsFromBounds : MonoBehaviour {
|
||||
public List<GameObject> objects;
|
||||
SkinnedMeshRenderer smr;
|
||||
|
||||
void Start () {
|
||||
smr = GetComponent<SkinnedMeshRenderer>();
|
||||
if (smr == null){
|
||||
Debug.LogError("Need to attach MB2_UpdateSkinnedMeshBoundsFromBounds script to an object with a SkinnedMeshRenderer component attached.");
|
||||
return;
|
||||
}
|
||||
if (objects == null || objects.Count == 0){
|
||||
Debug.LogWarning("The MB2_UpdateSkinnedMeshBoundsFromBounds had no Game Objects. It should have the same list of game objects that the MeshBaker does.");
|
||||
smr = null;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < objects.Count; i++){
|
||||
if (objects[i] == null || objects[i].GetComponent<Renderer>() == null){
|
||||
Debug.LogError("The list of objects had nulls or game objects without a renderer attached at position " + i);
|
||||
smr = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
bool origVal = smr.updateWhenOffscreen;
|
||||
smr.updateWhenOffscreen = true;
|
||||
smr.updateWhenOffscreen = origVal;
|
||||
}
|
||||
|
||||
void Update () {
|
||||
if (smr != null && objects != null){
|
||||
MB3_MeshCombiner.UpdateSkinnedMeshApproximateBoundsFromBoundsStatic(objects,smr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f4510fdae919c84a82b04658438580e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB2_UpdateSkinnedMeshBoundsFromBounds.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,73 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using DigitalOpus.MB.Core;
|
||||
|
||||
public class MB3_BatchPrefabBaker : MonoBehaviour {
|
||||
public MB2_LogLevel LOG_LEVEL = MB2_LogLevel.info;
|
||||
|
||||
[System.Serializable]
|
||||
public class MB3_PrefabBakerRow{
|
||||
public GameObject sourcePrefab;
|
||||
public GameObject resultPrefab;
|
||||
}
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
[NonReorderable] //see MB-136 for why this is here
|
||||
#endif
|
||||
public MB3_PrefabBakerRow[] prefabRows = new MB3_PrefabBakerRow[0];
|
||||
|
||||
public string outputPrefabFolder = "";
|
||||
|
||||
[ContextMenu("Create Instances For Prefab Rows")]
|
||||
public void CreateSourceAndResultPrefabInstances()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// instantiate the prefabs
|
||||
List<GameObject> srcPrefabs = new List<GameObject>();
|
||||
List<GameObject> resultPrefabs = new List<GameObject>();
|
||||
for (int i = 0; i < prefabRows.Length; i++)
|
||||
{
|
||||
if (prefabRows[i].sourcePrefab != null && prefabRows[i].resultPrefab != null)
|
||||
{
|
||||
GameObject src = (GameObject)UnityEditor.PrefabUtility.InstantiatePrefab(prefabRows[i].sourcePrefab);
|
||||
GameObject result = (GameObject)UnityEditor.PrefabUtility.InstantiatePrefab(prefabRows[i].resultPrefab);
|
||||
srcPrefabs.Add(src);
|
||||
resultPrefabs.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 offsetX = new Vector3(2, 0, 0);
|
||||
|
||||
// layout the prefabs
|
||||
GameObject srcRoot = new GameObject("SourcePrefabInstances");
|
||||
GameObject resultRoot = new GameObject("ResultPrefabInstance");
|
||||
|
||||
Vector3 srcPos = Vector3.zero - offsetX;
|
||||
Vector3 resultPos = Vector3.zero + offsetX;
|
||||
for (int i = 0; i < srcPrefabs.Count; i++)
|
||||
{
|
||||
Renderer[] rs = srcPrefabs[i].GetComponentsInChildren<Renderer>(true);
|
||||
Bounds b = new Bounds(Vector3.zero, Vector3.one);
|
||||
if (rs.Length > 0)
|
||||
{
|
||||
b = rs[0].bounds;
|
||||
for (int bndsIdx = 1; bndsIdx < rs.Length; bndsIdx++)
|
||||
{
|
||||
b.Encapsulate(rs[bndsIdx].bounds);
|
||||
}
|
||||
}
|
||||
|
||||
srcPrefabs[i].transform.parent = srcRoot.transform;
|
||||
resultPrefabs[i].transform.parent = resultRoot.transform;
|
||||
srcPrefabs[i].transform.localPosition = srcPos + new Vector3(-b.extents.x, 0, b.extents.z + b.extents.z * .3f);
|
||||
resultPrefabs[i].transform.localPosition = resultPos + new Vector3(b.extents.x, 0, b.extents.z + b.extents.z * .3f);
|
||||
srcPos += new Vector3(0,0,b.size.z + 1f);
|
||||
resultPos += new Vector3(0, 0, b.size.z + 1f);
|
||||
}
|
||||
#else
|
||||
Debug.LogError("Cannot be used outside the editor");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0409865d977e644d97db08d14bfa7f8
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_BatchPrefabBaker.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
public class MB3_BoneWeightCopier : MonoBehaviour {
|
||||
public GameObject inputGameObject;
|
||||
public GameObject outputPrefab;
|
||||
public float radius = .01f;
|
||||
public SkinnedMeshRenderer seamMesh;
|
||||
public string outputFolder;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4f7f279433826c4db0bf060ba15c0a1
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_BoneWeightCopier.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace DigitalOpus.MB.Core
|
||||
{
|
||||
public class MB3_Comment : MonoBehaviour
|
||||
{
|
||||
[Multiline]
|
||||
public string comment;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4154d7f8918b2b24f8079460bf2ec3ed
|
||||
timeCreated: 1536791543
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_Comment.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class MB3_DisableHiddenAnimations : MonoBehaviour {
|
||||
public List<Animation> animationsToCull = new List<Animation>();
|
||||
|
||||
void Start () {
|
||||
if (GetComponent<SkinnedMeshRenderer> () == null) {
|
||||
Debug.LogError ("The MB3_CullHiddenAnimations script was placed on and object " + name + " which has no SkinnedMeshRenderer attached");
|
||||
}
|
||||
}
|
||||
|
||||
void OnBecameVisible(){
|
||||
for (int i = 0; i < animationsToCull.Count; i++) {
|
||||
if (animationsToCull[i] != null) animationsToCull[i].enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void OnBecameInvisible(){
|
||||
for (int i = 0; i < animationsToCull.Count; i++) {
|
||||
if (animationsToCull[i] != null) animationsToCull[i].enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c48ae3fc24ee5b4db7320b8d0e1d35d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_DisableHiddenAnimations.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,835 @@
|
||||
/**
|
||||
* \brief Hax! DLLs cannot interpret preprocessor directives, so this class acts as a "bridge"
|
||||
*/
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
|
||||
#if MB_USING_HDRP && UNITY_2019_3_OR_NEWER
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
#elif MB_USING_HDRP && UNITY_2018_4_OR_NEWER
|
||||
using UnityEngine.Experimental.Rendering.HDPipeline;
|
||||
#endif
|
||||
|
||||
#if MB_USING_ADDRESSABLES
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
#endif
|
||||
|
||||
namespace DigitalOpus.MB.Core
|
||||
{
|
||||
public class MBVersionConcrete : MBVersionInterface
|
||||
{
|
||||
public string version()
|
||||
{
|
||||
return "3.40.1";
|
||||
}
|
||||
|
||||
public bool Is_2017_1_OrNewer()
|
||||
{
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool Is_2018_3_OrNewer()
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool GetActive(GameObject go)
|
||||
{
|
||||
#if UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5
|
||||
return go.active;
|
||||
#else
|
||||
return go.activeInHierarchy;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SetActive(GameObject go, bool isActive)
|
||||
{
|
||||
#if UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5
|
||||
go.active = isActive;
|
||||
#else
|
||||
go.SetActive(isActive);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SetActiveRecursively(GameObject go, bool isActive)
|
||||
{
|
||||
#if UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5
|
||||
go.SetActiveRecursively(isActive);
|
||||
#else
|
||||
go.SetActive(isActive);
|
||||
#endif
|
||||
}
|
||||
|
||||
public UnityEngine.Object[] FindSceneObjectsOfType(Type t)
|
||||
{
|
||||
#if UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5
|
||||
return GameObject.FindSceneObjectsOfType(t);
|
||||
#elif UNITY_2023_1_OR_NEWER
|
||||
return UnityEngine.Object.FindObjectsByType(t, FindObjectsSortMode.None);
|
||||
#else
|
||||
return GameObject.FindObjectsOfType(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Some platforms Unity uses a swizzled graphics format. Platforms that support DXT formats.
|
||||
/// Other platforms unity uses regular formats
|
||||
/// </summary>
|
||||
public bool IsSwizzledNormalMapPlatform()
|
||||
{
|
||||
bool isSupported;
|
||||
#if UNITY_2023_2_OR_NEWER
|
||||
GraphicsFormatUsage gfu = GraphicsFormatUsage.Linear;
|
||||
isSupported = SystemInfo.IsFormatSupported( GraphicsFormat.RGBA_DXT5_SRGB, gfu) ||
|
||||
SystemInfo.IsFormatSupported( GraphicsFormat.RGBA_DXT5_UNorm, gfu) ||
|
||||
SystemInfo.IsFormatSupported( GraphicsFormat.RGBA_DXT1_SRGB, gfu) ||
|
||||
SystemInfo.IsFormatSupported( GraphicsFormat.RGBA_DXT1_UNorm, gfu);
|
||||
#else
|
||||
FormatUsage gfu = FormatUsage.Linear;
|
||||
isSupported = SystemInfo.IsFormatSupported(GraphicsFormat.RGBA_DXT5_SRGB, gfu) ||
|
||||
SystemInfo.IsFormatSupported(GraphicsFormat.RGBA_DXT5_UNorm, gfu) ||
|
||||
SystemInfo.IsFormatSupported(GraphicsFormat.RGBA_DXT1_SRGB, gfu) ||
|
||||
SystemInfo.IsFormatSupported(GraphicsFormat.RGBA_DXT1_UNorm, gfu);
|
||||
#endif
|
||||
return isSupported;
|
||||
}
|
||||
|
||||
public bool IsMaterialKeywordValid(Material mat, string keyword)
|
||||
{
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
LocalKeywordSpace ks = mat.shader.keywordSpace;
|
||||
return ks.FindKeyword(keyword).isValid;
|
||||
#else
|
||||
// There is no API for checking if a Material has a keyword
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OptimizeMesh(Mesh m)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
m.Optimize();
|
||||
#elif UNITY_5_5_OR_NEWER
|
||||
// Unity 5.5 to 2018.4
|
||||
UnityEditor.MeshUtility.Optimize(m);
|
||||
#else
|
||||
// Pre 5.5
|
||||
m.Optimize();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
public bool IsRunningAndMeshNotReadWriteable(Mesh m)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
#if UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5
|
||||
return false;
|
||||
#else
|
||||
return !m.isReadable;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 _HALF_UV = new Vector2(.5f, .5f);
|
||||
public Vector2[] GetMeshUV1s(Mesh m, MB2_LogLevel LOG_LEVEL)
|
||||
{
|
||||
Vector2[] uv;
|
||||
#if (UNITY_4_6 || UNITY_4_7 || UNITY_4_5 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5)
|
||||
uv = m.uv1;
|
||||
|
||||
#else
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) MB2_Log.LogDebug("UV1 does not exist in Unity 5+");
|
||||
uv = m.uv;
|
||||
#endif
|
||||
if (uv.Length == 0)
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.debug) MB2_Log.LogDebug("Mesh " + m + " has no uv1s. Generating");
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Mesh " + m + " didn't have uv1s. Generating uv1s.");
|
||||
uv = new Vector2[m.vertexCount];
|
||||
for (int i = 0; i < uv.Length; i++) { uv[i] = _HALF_UV; }
|
||||
}
|
||||
return uv;
|
||||
}
|
||||
|
||||
public Vector2[] GetMeshUVChannel(int channel, Mesh m, MB2_LogLevel LOG_LEVEL)
|
||||
{
|
||||
Vector2[] uvs = new Vector2[0];
|
||||
|
||||
switch (channel)
|
||||
{
|
||||
case 0:
|
||||
uvs = m.uv;
|
||||
break;
|
||||
case 2:
|
||||
uvs = m.uv2;
|
||||
break;
|
||||
case 3:
|
||||
uvs = m.uv3;
|
||||
break;
|
||||
case 4:
|
||||
uvs = m.uv4;
|
||||
break;
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
case 5:
|
||||
uvs = m.uv5;
|
||||
break;
|
||||
case 6:
|
||||
uvs = m.uv6;
|
||||
break;
|
||||
case 7:
|
||||
uvs = m.uv7;
|
||||
break;
|
||||
case 8:
|
||||
uvs = m.uv8;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
Debug.LogError("Mesh does not have UV channel " + channel);
|
||||
break;
|
||||
}
|
||||
|
||||
if (uvs.Length == 0)
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.debug) MB2_Log.LogDebug("Mesh " + m + " has no uv" + channel + ". Generating");
|
||||
uvs = new Vector2[m.vertexCount];
|
||||
for (int i = 0; i < uvs.Length; i++) { uvs[i] = _HALF_UV; }
|
||||
}
|
||||
|
||||
return uvs;
|
||||
}
|
||||
|
||||
public void MeshClear(Mesh m, bool t)
|
||||
{
|
||||
#if UNITY_3_5
|
||||
m.Clear();
|
||||
#else
|
||||
m.Clear(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void MeshAssignUVChannel(int channel, Mesh m, Vector2[] uvs)
|
||||
{
|
||||
switch (channel)
|
||||
{
|
||||
case 0:
|
||||
m.uv = uvs;
|
||||
break;
|
||||
case 2:
|
||||
m.uv2 = uvs;
|
||||
break;
|
||||
case 3:
|
||||
m.uv3 = uvs;
|
||||
break;
|
||||
case 4:
|
||||
m.uv4 = uvs;
|
||||
break;
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
case 5:
|
||||
m.uv5 = uvs;
|
||||
break;
|
||||
case 6:
|
||||
m.uv6 = uvs;
|
||||
break;
|
||||
case 7:
|
||||
m.uv7 = uvs;
|
||||
break;
|
||||
case 8:
|
||||
m.uv8 = uvs;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
Debug.LogError("Mesh does not have UV channel " + channel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector4 GetLightmapTilingOffset(Renderer r)
|
||||
{
|
||||
#if (UNITY_4_6 || UNITY_4_7 || UNITY_4_5 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5)
|
||||
return r.lightmapTilingOffset ;
|
||||
#else
|
||||
return r.lightmapScaleOffset; //r.lightmapScaleOffset ;
|
||||
#endif
|
||||
}
|
||||
#if UNITY_5_OR_NEWER
|
||||
public Transform[] GetBones(Renderer r, bool isSkinnedMeshWithBones)
|
||||
{
|
||||
if (r is SkinnedMeshRenderer)
|
||||
{
|
||||
Transform[] bone;
|
||||
//check if I need to deoptimize
|
||||
Animator anim = r.GetComponentInParent<Animator>();
|
||||
|
||||
if (anim != null)
|
||||
{
|
||||
if (anim.hasTransformHierarchy)
|
||||
{
|
||||
//nothing to do
|
||||
} else if (anim.isOptimizable)
|
||||
{
|
||||
//Deoptimize
|
||||
AnimatorUtility.DeoptimizeTransformHierarchy(anim.gameObject);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Could not getBones. Bones optimized but could not create TransformHierarchy.");
|
||||
return null;
|
||||
}
|
||||
bone = ((SkinnedMeshRenderer)r).bones;
|
||||
//can't deoptimize here because the transforms need to exist for the combined mesh
|
||||
} else
|
||||
{
|
||||
//no Animator component but check to see if bones were optimized on import
|
||||
bone = ((SkinnedMeshRenderer)r).bones;
|
||||
#if UNITY_EDITOR
|
||||
if (bone.Length == 0)
|
||||
{
|
||||
Mesh m = ((SkinnedMeshRenderer)r).sharedMesh;
|
||||
if (m.bindposes.Length != bone.Length) Debug.LogError("SkinnedMesh (" + r.gameObject + ") in the list of objects to combine has no bones. Check that 'optimize game object' is not checked in the 'Rig' tab of the asset importer. Mesh Baker cannot combine optimized skinned meshes because the bones are not available.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return bone;
|
||||
}
|
||||
else if (r is MeshRenderer)
|
||||
{
|
||||
Transform[] bone = new Transform[1];
|
||||
bone[0] = r.transform;
|
||||
return bone;
|
||||
}
|
||||
else {
|
||||
Debug.LogError("Could not getBones. Object is not a Renderer.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public Transform[] GetBones(Renderer r, bool isSkinnedMeshWithBones)
|
||||
{
|
||||
if (isSkinnedMeshWithBones)
|
||||
{
|
||||
Transform[] bone = ((SkinnedMeshRenderer)r).bones;
|
||||
#if UNITY_EDITOR
|
||||
if (bone.Length == 0)
|
||||
{
|
||||
Mesh m = ((SkinnedMeshRenderer)r).sharedMesh;
|
||||
if (m.bindposes.Length != bone.Length) Debug.LogError("SkinnedMesh (" + r.gameObject + ") in the list of objects to combine has no bones. Check that 'optimize game object' is not checked in the 'Rig' tab of the asset importer. Mesh Baker cannot combine optimized skinned meshes because the bones are not available.");
|
||||
|
||||
if (m.blendShapeCount > 0)
|
||||
{
|
||||
// Some skinned meshes have only blend shapes, no bones.
|
||||
// In this case the SkinneMeshRenderer.transform acts like a bone.
|
||||
bone = new Transform[1];
|
||||
bone[0] = r.transform;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return bone;
|
||||
}
|
||||
else if (r is MeshRenderer ||
|
||||
(r is SkinnedMeshRenderer && !isSkinnedMeshWithBones))
|
||||
{
|
||||
Transform[] bone = new Transform[1];
|
||||
bone[0] = r.transform;
|
||||
return bone;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Could not getBones. Object does not have a renderer");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public int GetBlendShapeFrameCount(Mesh m, int shapeIndex)
|
||||
{
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
return m.GetBlendShapeFrameCount(shapeIndex);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public float GetBlendShapeFrameWeight(Mesh m, int shapeIndex, int frameIndex)
|
||||
{
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
return m.GetBlendShapeFrameWeight(shapeIndex, frameIndex);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void GetBlendShapeFrameVertices(Mesh m, int shapeIndex, int frameIndex, Vector3[] vs, Vector3[] ns, Vector3[] ts)
|
||||
{
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
m.GetBlendShapeFrameVertices(shapeIndex, frameIndex, vs, ns, ts);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ClearBlendShapes(Mesh m)
|
||||
{
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
m.ClearBlendShapes();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void AddBlendShapeFrame(Mesh m, string nm, float wt, Vector3[] vs, Vector3[] ns, Vector3[] ts)
|
||||
{
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
m.AddBlendShapeFrame(nm, wt, vs, ns, ts);
|
||||
#endif
|
||||
}
|
||||
|
||||
public int MaxMeshVertexCount()
|
||||
{
|
||||
#if UNITY_2017_3_OR_NEWER
|
||||
return 2147483646;
|
||||
#else
|
||||
return 65535;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SetMeshIndexFormatAndClearMesh(Mesh m, int numVerts, bool vertices, bool justClearTriangles)
|
||||
{
|
||||
#if UNITY_2017_3_OR_NEWER
|
||||
if (vertices && numVerts > 65534 && m.indexFormat == UnityEngine.Rendering.IndexFormat.UInt16)
|
||||
{
|
||||
MBVersion.MeshClear(m, false);
|
||||
m.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
||||
return;
|
||||
}
|
||||
else if (vertices && numVerts <= 65534 && m.indexFormat == UnityEngine.Rendering.IndexFormat.UInt32)
|
||||
{
|
||||
MBVersion.MeshClear(m, false);
|
||||
m.indexFormat = UnityEngine.Rendering.IndexFormat.UInt16;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (justClearTriangles)
|
||||
{
|
||||
MBVersion.MeshClear(m, true); //clear just triangles
|
||||
}
|
||||
else
|
||||
{//clear all the data and start with a blank mesh
|
||||
MBVersion.MeshClear(m, false);
|
||||
}
|
||||
}
|
||||
|
||||
public bool GraphicsUVStartsAtTop()
|
||||
{
|
||||
#if UNITY_2023_2_OR_NEWER
|
||||
return false;
|
||||
#elif UNITY_2017_1_OR_NEWER
|
||||
return SystemInfo.graphicsUVStartsAtTop;
|
||||
#else
|
||||
if (SystemInfo.graphicsDeviceVersion.Contains("metal"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// "opengl es, direct3d"
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prior to Unity 2022.1 this is not available
|
||||
/// </summary>
|
||||
public bool IsTexture_sRGBgammaCorrected(Texture2D tex, bool hint)
|
||||
{
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
return tex.isDataSRGB;
|
||||
#else
|
||||
return hint;
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool IsTextureReadable(Texture2D tex)
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
return tex.isReadable;
|
||||
#else
|
||||
try
|
||||
{
|
||||
tex.GetPixel(0, 0);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public float GetScaleInLightmap(MeshRenderer r)
|
||||
{
|
||||
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
|
||||
if (r == null) return 1f;
|
||||
else return r.scaleInLightmap;
|
||||
#else
|
||||
return 1f;
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool CollectPropertyNames(List<ShaderTextureProperty> texPropertyNames, ShaderTextureProperty[] shaderTexPropertyNames, List<ShaderTextureProperty> _customShaderPropNames, Material resultMaterial, MB2_LogLevel LOG_LEVEL)
|
||||
{
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
// 2018.2 and up
|
||||
// Collect the property names from the shader
|
||||
// Check with the lists of property names to flag which ones are normal maps.
|
||||
if (resultMaterial != null && resultMaterial.shader != null)
|
||||
{
|
||||
Shader s = resultMaterial.shader;
|
||||
|
||||
for (int i = 0; i < s.GetPropertyCount(); i++)
|
||||
{
|
||||
if (s.GetPropertyType(i) == UnityEngine.Rendering.ShaderPropertyType.Texture)
|
||||
{
|
||||
string matPropName = s.GetPropertyName(i);
|
||||
if (resultMaterial.GetTextureOffset(matPropName) != new Vector2(0f, 0f))
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Result material has non-zero offset for property " + matPropName + ". This is probably incorrect.");
|
||||
}
|
||||
|
||||
if (resultMaterial.GetTextureScale(matPropName) != new Vector2(1f, 1f))
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Result material should probably have tiling of 1,1 for propert " + matPropName);
|
||||
}
|
||||
|
||||
ShaderTextureProperty pn = null;
|
||||
// We need to know if the property is a normal map or not.
|
||||
// first check the list of default names
|
||||
for (int defaultIdx = 0; defaultIdx < shaderTexPropertyNames.Length; defaultIdx++)
|
||||
{
|
||||
if (shaderTexPropertyNames[defaultIdx].name == matPropName)
|
||||
{
|
||||
pn = new ShaderTextureProperty(matPropName,
|
||||
shaderTexPropertyNames[defaultIdx].isNormalMap,
|
||||
shaderTexPropertyNames[defaultIdx].isGammaCorrected,
|
||||
shaderTexPropertyNames[defaultIdx].isNormalDontKnow
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// now check the list of custom property names
|
||||
for (int custPropIdx = 0; custPropIdx < _customShaderPropNames.Count; custPropIdx++)
|
||||
{
|
||||
if (_customShaderPropNames[custPropIdx].name == matPropName)
|
||||
{
|
||||
pn = new ShaderTextureProperty(matPropName,
|
||||
_customShaderPropNames[custPropIdx].isNormalMap,
|
||||
_customShaderPropNames[custPropIdx].isGammaCorrected,
|
||||
_customShaderPropNames[custPropIdx].isNormalDontKnow);
|
||||
}
|
||||
}
|
||||
|
||||
if (pn == null)
|
||||
{
|
||||
pn = new ShaderTextureProperty(matPropName, false, true, true);
|
||||
}
|
||||
|
||||
texPropertyNames.Add(pn);
|
||||
}
|
||||
}
|
||||
|
||||
// If using URP or HDRP AND using a prepackaged pipeline shader AND both _BaseMap and _MainTex are present, get rid of _MainTex since its essentially a duplicate of _BaseMap
|
||||
MBVersion.PipelineType pipelineType = DetectPipeline();
|
||||
int _MainTexIndex = texPropertyNames.FindIndex(pn => pn.name.Equals("_MainTex"));
|
||||
if (pipelineType == MBVersion.PipelineType.URP && s.name.StartsWith("Universal Render Pipeline/") && _MainTexIndex != -1 && texPropertyNames.FindIndex(pn => pn.name.Equals("_BaseMap")) != -1)
|
||||
{
|
||||
texPropertyNames.RemoveAt(_MainTexIndex);
|
||||
//Debug.Log("Removed _MainTex");
|
||||
}
|
||||
// HDRP uses _BaseColorMap instead of _BaseMap but same idea
|
||||
else if (pipelineType == MBVersion.PipelineType.HDRP && s.name.StartsWith("HDRP/") && _MainTexIndex != -1 && texPropertyNames.FindIndex(pn => pn.name.Equals("_BaseColorMap")) != -1)
|
||||
{
|
||||
texPropertyNames.RemoveAt(_MainTexIndex);
|
||||
//Debug.Log("Removed _MainTex");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif UNITY_2018_3_OR_NEWER
|
||||
// 2018.2 and up
|
||||
// Collect the property names from the material
|
||||
// Check with the lists of property names to flag which ones are normal maps.
|
||||
string[] matPropertyNames = resultMaterial.GetTexturePropertyNames();
|
||||
for (int matIdx = 0; matIdx < matPropertyNames.Length; matIdx++)
|
||||
{
|
||||
string matPropName = matPropertyNames[matIdx];
|
||||
if (resultMaterial.GetTextureOffset(matPropName) != new Vector2(0f, 0f))
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Result material has non-zero offset for property " + matPropName + ". This is probably incorrect.");
|
||||
}
|
||||
|
||||
if (resultMaterial.GetTextureScale(matPropName) != new Vector2(1f, 1f))
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Result material should probably have tiling of 1,1 for propert " + matPropName);
|
||||
}
|
||||
|
||||
ShaderTextureProperty pn = null;
|
||||
// We need to know if the property is a normal map or not.
|
||||
// first check the list of default names
|
||||
for (int defaultIdx = 0; defaultIdx < shaderTexPropertyNames.Length; defaultIdx++)
|
||||
{
|
||||
if (shaderTexPropertyNames[defaultIdx].name == matPropName)
|
||||
{
|
||||
pn = new ShaderTextureProperty(matPropName, shaderTexPropertyNames[defaultIdx].isNormalMap);
|
||||
}
|
||||
}
|
||||
|
||||
// now check the list of custom property names
|
||||
for (int custPropIdx = 0; custPropIdx < _customShaderPropNames.Count; custPropIdx++)
|
||||
{
|
||||
if (_customShaderPropNames[custPropIdx].name == matPropName)
|
||||
{
|
||||
pn = new ShaderTextureProperty(matPropName, _customShaderPropNames[custPropIdx].isNormalMap);
|
||||
}
|
||||
}
|
||||
|
||||
if (pn == null)
|
||||
{
|
||||
pn = new ShaderTextureProperty(matPropName, false, true);
|
||||
}
|
||||
|
||||
texPropertyNames.Add(pn);
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
{ // Pre 2018.2, doesn't have API for querying material for property names.
|
||||
//Collect the property names for the textures
|
||||
string shaderPropStr = "";
|
||||
for (int i = 0; i < shaderTexPropertyNames.Length; i++)
|
||||
{
|
||||
if (resultMaterial.HasProperty(shaderTexPropertyNames[i].name))
|
||||
{
|
||||
shaderPropStr += ", " + shaderTexPropertyNames[i].name;
|
||||
if (!texPropertyNames.Contains(shaderTexPropertyNames[i])) texPropertyNames.Add(shaderTexPropertyNames[i]);
|
||||
if (resultMaterial.GetTextureOffset(shaderTexPropertyNames[i].name) != new Vector2(0f, 0f))
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Result material has non-zero offset. This is may be incorrect.");
|
||||
}
|
||||
if (resultMaterial.GetTextureScale(shaderTexPropertyNames[i].name) != new Vector2(1f, 1f))
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Result material should have tiling of 1,1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _customShaderPropNames.Count; i++)
|
||||
{
|
||||
if (resultMaterial.HasProperty(_customShaderPropNames[i].name))
|
||||
{
|
||||
shaderPropStr += ", " + _customShaderPropNames[i].name;
|
||||
texPropertyNames.Add(_customShaderPropNames[i]);
|
||||
if (resultMaterial.GetTextureOffset(_customShaderPropNames[i].name) != new Vector2(0f, 0f))
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Result material has non-zero offset. This is probably incorrect.");
|
||||
}
|
||||
if (resultMaterial.GetTextureScale(_customShaderPropNames[i].name) != new Vector2(1f, 1f))
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Result material should probably have tiling of 1,1.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Result material shader does not use property " + _customShaderPropNames[i].name + " in the list of custom shader property names");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void DoSpecialRenderPipeline_TexturePackerFastSetup(GameObject cameraGameObject)
|
||||
{
|
||||
#if MB_USING_HDRP && UNITY_2018_4_OR_NEWER
|
||||
MBVersion.PipelineType pipelineType = DetectPipeline();
|
||||
if (pipelineType != MBVersion.PipelineType.HDRP)
|
||||
{
|
||||
Debug.LogError("The 'PlayerSettings -> Other Settings -> Scripting Define Symbols' included the symbol 'MB_USING_HDRP' which should only be used " +
|
||||
"if the GraphicsSettings -> Render Pipeline Asset is HDRenderPipelineAsset. The Render Pipeline Asset is NOT HDRenderPipelineAsset. Please " +
|
||||
" remove the symbol MB_USING_HDRP from PlayerSettings -> Other Settings -> Scripting Define Symbols");
|
||||
}
|
||||
|
||||
HDAdditionalCameraData acd = cameraGameObject.GetComponent<HDAdditionalCameraData>();
|
||||
if (acd == null)
|
||||
{
|
||||
acd = cameraGameObject.AddComponent<HDAdditionalCameraData>();
|
||||
}
|
||||
|
||||
acd.volumeLayerMask = LayerMask.GetMask("UI");
|
||||
#endif
|
||||
}
|
||||
|
||||
public ColorSpace GetProjectColorSpace()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isEditor)
|
||||
{
|
||||
return UnityEditor.PlayerSettings.colorSpace;
|
||||
}
|
||||
#endif
|
||||
if (QualitySettings.desiredColorSpace != QualitySettings.activeColorSpace)
|
||||
{
|
||||
Debug.LogError("The active color space (" + QualitySettings.activeColorSpace + ") is not the desired color space (" + QualitySettings.desiredColorSpace + "). Baked atlases may be off.");
|
||||
}
|
||||
|
||||
return QualitySettings.activeColorSpace;
|
||||
}
|
||||
|
||||
public MBVersion.PipelineType DetectPipeline()
|
||||
{
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
var rp = UnityEngine.Rendering.GraphicsSettings.defaultRenderPipeline;
|
||||
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
// Check if there is an override for this quality level
|
||||
rp = QualitySettings.renderPipeline != null ? QualitySettings.renderPipeline : rp;
|
||||
#endif
|
||||
|
||||
if (rp != null)
|
||||
{
|
||||
// SRP
|
||||
var srpType = rp.GetType().ToString();
|
||||
if (srpType.Contains("HDRenderPipelineAsset"))
|
||||
{
|
||||
return MBVersion.PipelineType.HDRP;
|
||||
}
|
||||
else if (srpType.Contains("UniversalRenderPipelineAsset") || srpType.Contains("LightweightRenderPipelineAsset"))
|
||||
{
|
||||
return MBVersion.PipelineType.URP;
|
||||
}
|
||||
else return MBVersion.PipelineType.Unsupported;
|
||||
}
|
||||
#elif UNITY_2017_1_OR_NEWER
|
||||
if (UnityEngine.Rendering.GraphicsSettings.renderPipelineAsset != null) {
|
||||
// SRP not supported before 2019
|
||||
return MBVersion.PipelineType.Unsupported;
|
||||
}
|
||||
#endif
|
||||
// no SRP
|
||||
return MBVersion.PipelineType.Default;
|
||||
}
|
||||
|
||||
public string UnescapeURL(string url)
|
||||
{
|
||||
#if UNITY_2017_3_OR_NEWER
|
||||
return UnityEngine.Networking.UnityWebRequest.UnEscapeURL(url);
|
||||
#else
|
||||
// Not correct but not going to spend a lot of effort writing custom
|
||||
// code for versions of Unity soon to be depricated.
|
||||
return url;
|
||||
#endif
|
||||
}
|
||||
|
||||
public IEnumerator FindRuntimeMaterialsFromAddresses(MB2_TextureBakeResults texBakeResult, MB2_TextureBakeResults.CoroutineResult isComplete)
|
||||
{
|
||||
#if MB_USING_ADDRESSABLES
|
||||
Debug.LogError("Currently the runtimeMaterial is not used. This may change in the future.");
|
||||
/*
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Debug.LogError("FindRuntimeMaterialsFromAddresses is a coroutine. It is only necessary to use this at runtime.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
// Find a distinct set of addressable keys from the TextureBakeResult.
|
||||
List<MB_MaterialAndUVRect> distinctMats = new List<MB_MaterialAndUVRect>();
|
||||
for (int i = 0; i < texBakeResult.materialsAndUVRects.Length; i++)
|
||||
{
|
||||
int idx = distinctMats.FindIndex(0, distinctMats.Count, x => x.material == texBakeResult.materialsAndUVRects[i].material);
|
||||
if (idx == -1)
|
||||
{
|
||||
distinctMats.Add(texBakeResult.materialsAndUVRects[i]);
|
||||
idx = distinctMats.Count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
List<string> keys = new List<string>();
|
||||
for (int i = 0; i < distinctMats.Count; i++)
|
||||
{
|
||||
if (distinctMats[i].matAddressablesPKey != null && distinctMats[i].matAddressablesPKey != "")
|
||||
keys.Add(distinctMats[i].matAddressablesPKey);
|
||||
}
|
||||
|
||||
// Look up the locations for these keys.
|
||||
AsyncOperationHandle<IList<IResourceLocation>> locations = Addressables.LoadResourceLocationsAsync((IEnumerable) keys, Addressables.MergeMode.Union, typeof(Material));
|
||||
yield return locations;
|
||||
|
||||
// Look up the materials for these locations.
|
||||
Dictionary<string, Material> address_2_material_map = new Dictionary<string, Material>();
|
||||
int numCalled = 0;
|
||||
foreach (IResourceLocation location in locations.Result)
|
||||
{
|
||||
AsyncOperationHandle<Material> handle =
|
||||
Addressables.LoadAssetAsync<Material>(location);
|
||||
handle.Completed += obj => address_2_material_map.Add(location.PrimaryKey, obj.Result);
|
||||
yield return handle;
|
||||
numCalled++;
|
||||
}
|
||||
|
||||
// Assign the found materials to the TextureBakeResult.
|
||||
int numRuntimeMatsMapped = 0;
|
||||
for (int i = 0; i < texBakeResult.materialsAndUVRects.Length; i++)
|
||||
{
|
||||
if (address_2_material_map.ContainsKey(texBakeResult.materialsAndUVRects[i].matAddressablesPKey))
|
||||
{
|
||||
texBakeResult.materialsAndUVRects[i].runtimeMaterial = address_2_material_map[texBakeResult.materialsAndUVRects[i].matAddressablesPKey];
|
||||
numRuntimeMatsMapped++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
isComplete.isComplete = true;
|
||||
yield break;
|
||||
#else
|
||||
if (!Application.isPlaying) Debug.LogError("FindRuntimeMaterialsFromAddresses is a coroutine. It is only necessary to use this at runtime.");
|
||||
Debug.LogError("The MB_USING_ADDRESSABLES define was not set in PlayerSettings -> Script Define Symbols. If you are using addressables and you want to use this method, that must be set.");
|
||||
isComplete.isComplete = true;
|
||||
yield break;
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool IsAssetInProject(UnityEngine.Object target)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (UnityEditor.AssetDatabase.Contains(target))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f1719ea9a4347c4799756ac016a69e3
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_MBVersionConcrete.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,132 @@
|
||||
//----------------------------------------------
|
||||
// MeshBaker
|
||||
// Copyright © 2011-2012 Ian Deane
|
||||
//----------------------------------------------
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using DigitalOpus.MB.Core;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/// <summary>
|
||||
/// Component that manages a single combined mesh.
|
||||
///
|
||||
/// This class is a Component. It must be added to a GameObject to use it. It is a wrapper for MB2_MeshCombiner which contains the same functionality but is not a component
|
||||
/// so it can be instantiated like a normal class.
|
||||
/// </summary>
|
||||
public class MB3_MeshBaker : MB3_MeshBakerCommon {
|
||||
|
||||
[SerializeField] protected MB3_MeshCombinerSingle _meshCombiner = new MB3_MeshCombinerSingle();
|
||||
|
||||
// [ContextMenu("Print Timings")]
|
||||
public void PrintTimings()
|
||||
{
|
||||
double db_showHideGameObjects = 0;
|
||||
double db_addDeleteGameObjects = 0;
|
||||
|
||||
double db_addDeleteGameObjects_InitFromMeshCombiner = 0;
|
||||
double db_addDeleteGameObjects_Init = 0;
|
||||
double db_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers = 0;
|
||||
double db_addDeleteGameObjects_CopyFromDGOMeshToBuffers = 0;
|
||||
double db_addDeleteGameObjects_CollectMeshData = 0;
|
||||
|
||||
double db_addDeleteGameObjects_CollectMeshData_a = 0;
|
||||
double db_addDeleteGameObjects_CollectMeshData_b = 0;
|
||||
double db_addDeleteGameObjects_CollectMeshData_c = 0;
|
||||
|
||||
double db_apply = 0;
|
||||
double db_applyShowHide = 0;
|
||||
double db_updateGameObjects = 0;
|
||||
|
||||
{
|
||||
MB3_MeshCombinerSingle c = _meshCombiner;
|
||||
|
||||
db_showHideGameObjects += c.db_showHideGameObjects.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects += c.db_addDeleteGameObjects.Elapsed.TotalSeconds;
|
||||
|
||||
db_addDeleteGameObjects_CollectMeshData += c.db_addDeleteGameObjects_CollectMeshData.Elapsed.TotalSeconds;
|
||||
|
||||
db_addDeleteGameObjects_CollectMeshData_a += c.db_addDeleteGameObjects_CollectMeshData_a.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects_CollectMeshData_b += c.db_addDeleteGameObjects_CollectMeshData_b.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects_CollectMeshData_c += c.db_addDeleteGameObjects_CollectMeshData_c.Elapsed.TotalSeconds;
|
||||
|
||||
db_addDeleteGameObjects_InitFromMeshCombiner += c.db_addDeleteGameObjects_InitFromMeshCombiner.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects_Init += c.db_addDeleteGameObjects_Init.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers += c.db_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects_CopyFromDGOMeshToBuffers += c.db_addDeleteGameObjects_CopyFromDGOMeshToBuffers.Elapsed.TotalSeconds;
|
||||
|
||||
db_apply += c.db_apply.Elapsed.TotalSeconds;
|
||||
db_applyShowHide += c.db_applyShowHide.Elapsed.TotalSeconds;
|
||||
db_updateGameObjects += c.db_updateGameObjects.Elapsed.TotalSeconds;
|
||||
}
|
||||
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine("Timings " + (_meshCombiner.settings.meshAPI == MB_MeshCombineAPIType.betaNativeArrayAPI ? " newMeshAPI " : " oldMeshAPI"));
|
||||
sb.AppendLine("db_showHideGameObjects\t" + db_showHideGameObjects);
|
||||
sb.AppendLine("db_addDeleteGameObjects\t" + db_addDeleteGameObjects);
|
||||
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CollectMeshData\t" + db_addDeleteGameObjects_CollectMeshData);
|
||||
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CollectMeshDataA\t\t" + db_addDeleteGameObjects_CollectMeshData_a);
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CollectMeshDataB\t\t" + db_addDeleteGameObjects_CollectMeshData_b);
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CollectMeshDataC\t\t" + db_addDeleteGameObjects_CollectMeshData_c);
|
||||
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_InitFromMeshCombiner\t" + db_addDeleteGameObjects_InitFromMeshCombiner);
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_Init\t" + db_addDeleteGameObjects_Init);
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers\t" + db_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers);
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CopyFromDGOMeshToBuffers\t" + db_addDeleteGameObjects_CopyFromDGOMeshToBuffers);
|
||||
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CollectMeshData tdb_addDeleteGameObjects_CollectMeshData ");
|
||||
//sb.AppendLine("\t\t\t\t MeshChannelsCache_NativeArray.db_AA\t" + MeshChannelsCache_NativeArray.db_AA);
|
||||
//sb.AppendLine("\t\t\t\t MeshChannelsCache_NativeArray.db_BB\t" + MeshChannelsCache_NativeArray.db_BB);
|
||||
//sb.AppendLine("\t\t\t\t MeshChannelsCache_NativeArray.db_CC\t" + MeshChannelsCache_NativeArray.db_CC);
|
||||
//sb.AppendLine("\t\t\t\t MeshChannelsCache_NativeArray.db_DD\t" + MeshChannelsCache_NativeArray.db_DD);
|
||||
|
||||
|
||||
sb.AppendLine("db_apply\t" + db_apply);
|
||||
sb.AppendLine("db_applyShowHide\t" + db_applyShowHide);
|
||||
sb.AppendLine("db_updateGameObjects\t" + db_updateGameObjects);
|
||||
Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
public override MB3_MeshCombiner meshCombiner{
|
||||
get{return _meshCombiner;}
|
||||
}
|
||||
|
||||
public void BuildSceneMeshObject(){
|
||||
_meshCombiner.BuildSceneMeshObject();
|
||||
}
|
||||
|
||||
public virtual bool ShowHide(GameObject[] gos, GameObject[] deleteGOs){
|
||||
return _meshCombiner.ShowHideGameObjects(gos, deleteGOs);
|
||||
}
|
||||
|
||||
public virtual void ApplyShowHide(){
|
||||
_meshCombiner.ApplyShowHide();
|
||||
}
|
||||
|
||||
public override bool AddDeleteGameObjects(GameObject[] gos, GameObject[] deleteGOs, bool disableRendererInSource){
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
// if ((_meshCombiner.outputOption == MB2_OutputOptions.bakeIntoSceneObject || (_meshCombiner.outputOption == MB2_OutputOptions.bakeIntoPrefab && _meshCombiner.renderType == MB_RenderType.skinnedMeshRenderer) )) BuildSceneMeshObject();
|
||||
_meshCombiner.name = name + "-mesh";
|
||||
return _meshCombiner.AddDeleteGameObjects(gos,deleteGOs,disableRendererInSource);
|
||||
}
|
||||
|
||||
public override bool AddDeleteGameObjectsByID(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource){
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
// if ((_meshCombiner.outputOption == MB2_OutputOptions.bakeIntoSceneObject || (_meshCombiner.outputOption == MB2_OutputOptions.bakeIntoPrefab && _meshCombiner.renderType == MB_RenderType.skinnedMeshRenderer) )) BuildSceneMeshObject();
|
||||
_meshCombiner.name = name + "-mesh";
|
||||
return _meshCombiner.AddDeleteGameObjectsByID(gos,deleteGOinstanceIDs,disableRendererInSource);
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
{
|
||||
if (meshCombiner != null)
|
||||
{
|
||||
meshCombiner.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2fb2e0d8bc810bb48b63c91af80d5f17
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_MeshBaker.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,518 @@
|
||||
//----------------------------------------------
|
||||
// MeshBaker
|
||||
// Copyright © 2011-2012 Ian Deane
|
||||
//----------------------------------------------
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using DigitalOpus.MB.Core;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Maps a list of source materials to a combined material. Included in MB2_TextureBakeResults
|
||||
/// </summary>
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Abstract root of the mesh combining classes
|
||||
/// </summary>
|
||||
public abstract class MB3_MeshBakerCommon : MB3_MeshBakerRoot
|
||||
{
|
||||
public static int VERSION { get { return 100; } }
|
||||
|
||||
public int version;
|
||||
|
||||
//todo should be list of <Renderer>
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
[NonReorderable] //see MB-136 for why this is here
|
||||
#endif
|
||||
public List<GameObject> objsToMesh;
|
||||
|
||||
public abstract MB3_MeshCombiner meshCombiner
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public bool useObjsToMeshFromTexBaker = true;
|
||||
|
||||
[UnityEngine.Serialization.FormerlySerializedAs("clearBuffersAfterBake")]
|
||||
[SerializeField]
|
||||
[HideInInspector]
|
||||
private bool _clearBuffersAfterBake;
|
||||
public bool clearBuffersAfterBake
|
||||
{
|
||||
// At version 100 we moved the MeshBakerCommon.clearBuffersAfterBake field into the meshCombiner.clearBuffersAfterBaker field.
|
||||
// This is complicated because the field is serialized in many scenes. We use the UpgradeToCurrentVersion system to do one time copy
|
||||
// This value.
|
||||
get
|
||||
{
|
||||
if (version < 100)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
return _clearBuffersAfterBake;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("MeshBaker.clearBuffersAfterBake is deprecated, use the meshCombiner.clearBuffersAfterBake field");
|
||||
return meshCombiner.clearBuffersAfterBake;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
if (version < 100)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
_clearBuffersAfterBake = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("MeshBaker.clearBuffersAfterBake is deprecated, use the meshCombiner.clearBuffersAfterBake field");
|
||||
meshCombiner.clearBuffersAfterBake = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//t0do put this in the batch baker
|
||||
public string bakeAssetsInPlaceFolderPath;
|
||||
|
||||
[HideInInspector] public GameObject resultPrefab;
|
||||
|
||||
/// <summary>
|
||||
/// If checked then an instance will be left in the scene after baking. Otherwise scene instance will be deleted after prefab is baked.
|
||||
/// </summary>
|
||||
[HideInInspector] public bool resultPrefabLeaveInstanceInSceneAfterBake;
|
||||
|
||||
/// <summary>
|
||||
/// Optional, combined mesh renderers will be children of this object if it exists.
|
||||
/// </summary>
|
||||
[HideInInspector] public Transform parentSceneObject;
|
||||
|
||||
/// <summary>
|
||||
/// Used to
|
||||
/// </summary>
|
||||
public void UpgradeToCurrentVersionIfNecessary()
|
||||
{
|
||||
if (version == VERSION) return;
|
||||
if (version < 100)
|
||||
{
|
||||
// At version == 100 we deprecated the MeshBaker.clearBuffersAfterBake field.
|
||||
// We use the field in the meshCombiner.clearBuffersAfterBake.
|
||||
meshCombiner.clearBuffersAfterBake = _clearBuffersAfterBake;
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
version = VERSION;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[ContextMenu("Create Mesh Baker Settings Asset")]
|
||||
public void CreateMeshBakerSettingsAsset()
|
||||
{
|
||||
string newFilePath = UnityEditor.EditorUtility.SaveFilePanelInProject("New Mesh Baker Settings", "MeshBakerSettings", "asset", "Create a new Mesh Baker Settings Asset");
|
||||
if (newFilePath != null)
|
||||
{
|
||||
MB3_MeshCombinerSettings asset = ScriptableObject.CreateInstance<MB3_MeshCombinerSettings>();
|
||||
UnityEditor.AssetDatabase.CreateAsset(asset, newFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
[ContextMenu("Copy settings from Shared Settings")]
|
||||
public void CopyMySettingsToAssignedSettingsAsset()
|
||||
{
|
||||
if (meshCombiner.settingsHolder == null)
|
||||
{
|
||||
Debug.LogError("No Shared Settings Asset Assigned.");
|
||||
return;
|
||||
}
|
||||
|
||||
UnityEditor.Undo.RecordObject(this, "Undo copy settings");
|
||||
_CopySettings(meshCombiner.settingsHolder.GetMeshBakerSettings(), meshCombiner);
|
||||
Debug.Log("Copied settings from assigned Shared Settings to this Mesh Baker.");
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
}
|
||||
|
||||
[ContextMenu("Copy settings to Shared Settings")]
|
||||
public void CopyAssignedSettingsAssetToMySettings()
|
||||
{
|
||||
if (meshCombiner.settingsHolder == null)
|
||||
{
|
||||
Debug.LogError("No Shared Settings Asset Assigned.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (meshCombiner.settingsHolder is UnityEngine.Object) UnityEditor.Undo.RecordObject((UnityEngine.Object)meshCombiner.settingsHolder, "Undo copy settings");
|
||||
_CopySettings(meshCombiner, meshCombiner.settingsHolder.GetMeshBakerSettings());
|
||||
Debug.Log("Copied settings from this Mesh Baker to the assigned Shared Settings asset.");
|
||||
if (meshCombiner.settingsHolder is UnityEngine.Object) UnityEditor.EditorUtility.SetDirty((UnityEngine.Object)meshCombiner.settingsHolder);
|
||||
}
|
||||
|
||||
void _CopySettings(MB_IMeshBakerSettings src, MB_IMeshBakerSettings targ)
|
||||
{
|
||||
targ.clearBuffersAfterBake = src.clearBuffersAfterBake;
|
||||
targ.doBlendShapes = src.doBlendShapes;
|
||||
targ.doCol = src.doCol;
|
||||
targ.doNorm = src.doNorm;
|
||||
targ.doTan = src.doTan;
|
||||
targ.doUV = src.doUV;
|
||||
targ.doUV3 = src.doUV3;
|
||||
targ.doUV4 = src.doUV4;
|
||||
targ.doUV5 = src.doUV5;
|
||||
targ.doUV6 = src.doUV6;
|
||||
targ.doUV7 = src.doUV7;
|
||||
targ.doUV8 = src.doUV8;
|
||||
targ.optimizeAfterBake = src.optimizeAfterBake;
|
||||
targ.pivotLocationType = src.pivotLocationType;
|
||||
targ.lightmapOption = src.lightmapOption;
|
||||
targ.renderType = src.renderType;
|
||||
targ.uv2UnwrappingParamsHardAngle = src.uv2UnwrappingParamsHardAngle;
|
||||
targ.uv2UnwrappingParamsPackMargin = src.uv2UnwrappingParamsPackMargin;
|
||||
}
|
||||
#endif
|
||||
|
||||
public override MB2_TextureBakeResults textureBakeResults
|
||||
{
|
||||
get { return meshCombiner.textureBakeResults; }
|
||||
set { meshCombiner.textureBakeResults = value; }
|
||||
}
|
||||
|
||||
public override List<GameObject> GetObjectsToCombine()
|
||||
{
|
||||
if (useObjsToMeshFromTexBaker)
|
||||
{
|
||||
MB3_TextureBaker tb = gameObject.GetComponent<MB3_TextureBaker>();
|
||||
if (tb == null && gameObject.transform.parent != null) tb = gameObject.transform.parent.GetComponent<MB3_TextureBaker>();
|
||||
if (tb != null)
|
||||
{
|
||||
return tb.GetObjectsToCombine();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Use Objects To Mesh From Texture Baker was checked but no texture baker");
|
||||
return new List<GameObject>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objsToMesh == null) objsToMesh = new List<GameObject>();
|
||||
if (objsToMesh.Count == 1 && objsToMesh[0] == null) objsToMesh.Clear();
|
||||
return objsToMesh;
|
||||
}
|
||||
}
|
||||
|
||||
[ContextMenu("Purge Objects to Combine of null references")]
|
||||
public override void PurgeNullsFromObjectsToCombine()
|
||||
{
|
||||
if (useObjsToMeshFromTexBaker)
|
||||
{
|
||||
MB3_TextureBaker tb = gameObject.GetComponent<MB3_TextureBaker>();
|
||||
if (tb == null && gameObject.transform.parent != null)
|
||||
{
|
||||
tb = gameObject.transform.parent.GetComponent<MB3_TextureBaker>();
|
||||
}
|
||||
if (tb != null)
|
||||
{
|
||||
tb.PurgeNullsFromObjectsToCombine();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Use Objects To Mesh From Texture Baker was checked but no texture baker, could not purge");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objsToMesh == null)
|
||||
{
|
||||
objsToMesh = new List<GameObject>();
|
||||
}
|
||||
Debug.Log(string.Format("Purged {0} null references from objects to combine list.", objsToMesh.RemoveAll(obj => obj == null)));
|
||||
}
|
||||
}
|
||||
|
||||
public void EnableDisableSourceObjectRenderers(bool show)
|
||||
{
|
||||
for (int i = 0; i < GetObjectsToCombine().Count; i++)
|
||||
{
|
||||
GameObject go = GetObjectsToCombine()[i];
|
||||
if (go != null)
|
||||
{
|
||||
Renderer mr = MB_Utility.GetRenderer(go);
|
||||
if (mr != null)
|
||||
{
|
||||
mr.enabled = show;
|
||||
}
|
||||
|
||||
LODGroup lodG = mr.GetComponentInParent<LODGroup>();
|
||||
if (lodG != null)
|
||||
{
|
||||
bool isOnlyInGroup = true;
|
||||
LOD[] lods = lodG.GetLODs();
|
||||
for (int j = 0; j < lods.Length; j++)
|
||||
{
|
||||
for (int k = 0; k < lods[j].renderers.Length; k++)
|
||||
{
|
||||
if (lods[j].renderers[k] != mr)
|
||||
{
|
||||
isOnlyInGroup = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isOnlyInGroup)
|
||||
{
|
||||
lodG.enabled = show;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the meshs and mesh related data but does not destroy it.
|
||||
/// </summary>
|
||||
public virtual void ClearMesh()
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
meshCombiner.ClearMesh();
|
||||
}
|
||||
|
||||
public virtual void ClearMesh(MB2_EditorMethodsInterface editorMethods)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
meshCombiner.ClearMesh(editorMethods);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears and desroys the mesh. Clears mesh related data.
|
||||
/// </summary>
|
||||
public virtual void DestroyMesh()
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
meshCombiner.DestroyMesh();
|
||||
}
|
||||
|
||||
public virtual void DestroyMeshEditor(MB2_EditorMethodsInterface editorMethods)
|
||||
{
|
||||
meshCombiner.DestroyMeshEditor(editorMethods);
|
||||
}
|
||||
|
||||
public virtual int GetNumObjectsInCombined()
|
||||
{
|
||||
return meshCombiner.GetNumObjectsInCombined();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture baker on this component or its parent if it exists
|
||||
/// </summary>
|
||||
/// <returns>The texture baker.</returns>
|
||||
public MB3_TextureBaker GetTextureBaker()
|
||||
{
|
||||
MB3_TextureBaker tb = GetComponent<MB3_TextureBaker>();
|
||||
if (tb != null) return tb;
|
||||
if (transform.parent != null && gameObject.transform.parent != null) return transform.parent.GetComponent<MB3_TextureBaker>();
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds and deletes objects from the combined mesh. gos and deleteGOs can be null.
|
||||
/// You need to call Apply or ApplyAll to see the changes.
|
||||
/// objects in gos must not include objects already in the combined mesh.
|
||||
/// objects in gos and deleteGOs must be the game objects with a Renderer component
|
||||
/// This method is slow, so should be called as infrequently as possible.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The first generated combined mesh
|
||||
/// </returns>
|
||||
/// <param name='gos'>
|
||||
/// gos. Array of objects to add to the combined mesh. Array can be null. Must not include objects
|
||||
/// already in the combined mesh. Array must contain game objects with a render component.
|
||||
/// </param>
|
||||
/// <param name='deleteGOs'>
|
||||
/// deleteGOs. Array of objects to delete from the combined mesh. Array can be null.
|
||||
/// </param>
|
||||
/// <param name='disableRendererInSource'>
|
||||
/// Disable renderer component on objects in gos after they have been added to the combined mesh.
|
||||
/// </param>
|
||||
/// <param name='fixOutOfBoundUVs'>
|
||||
/// Whether to fix out of bounds UVs in meshes as they are being added. This paramater should be set to the same as the combined material.
|
||||
/// </param>
|
||||
/// </summary>
|
||||
public abstract bool AddDeleteGameObjects(GameObject[] gos, GameObject[] deleteGOs, bool disableRendererInSource = true);
|
||||
|
||||
/// <summary>
|
||||
/// This is the best version to use for deleting game objects since the source GameObjects may have been destroyed
|
||||
/// Internaly Mesh Baker only stores the instanceID for Game Objects, so objects can be removed after they have been destroyed
|
||||
/// </summary>
|
||||
public abstract bool AddDeleteGameObjectsByID(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource = true);
|
||||
|
||||
/// <summary>
|
||||
/// Apply changes to the mesh. All channels set in this instance will be set in the combined mesh.
|
||||
/// </summary>
|
||||
public virtual bool Apply(MB3_MeshCombiner.GenerateUV2Delegate uv2GenerationMethod = null)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
meshCombiner.name = name + "-mesh";
|
||||
bool success = meshCombiner.Apply(uv2GenerationMethod);
|
||||
if (parentSceneObject != null && meshCombiner.resultSceneObject != null)
|
||||
{
|
||||
meshCombiner.resultSceneObject.transform.parent = parentSceneObject;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applys the changes to flagged properties of the mesh. This method is slow, and should only be called once per frame. The speed is directly proportional to the number of flags that are true. Only apply necessary properties.
|
||||
/// </summary>
|
||||
public virtual bool Apply(bool triangles,
|
||||
bool vertices,
|
||||
bool normals,
|
||||
bool tangents,
|
||||
bool uvs,
|
||||
bool uv2,
|
||||
bool uv3,
|
||||
bool uv4,
|
||||
bool colors,
|
||||
bool bones = false,
|
||||
bool blendShapesFlag = false,
|
||||
MB3_MeshCombiner.GenerateUV2Delegate uv2GenerationMethod = null)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
meshCombiner.name = name + "-mesh";
|
||||
bool success = meshCombiner.Apply(triangles, vertices, normals, tangents, uvs, uv2, uv3, uv4, colors, bones, blendShapesFlag, uv2GenerationMethod);
|
||||
if (parentSceneObject != null && meshCombiner.resultSceneObject != null)
|
||||
{
|
||||
meshCombiner.resultSceneObject.transform.parent = parentSceneObject;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public virtual bool CombinedMeshContains(GameObject go)
|
||||
{
|
||||
return meshCombiner.CombinedMeshContains(go);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the data in the combined mesh for meshes that are already in the combined mesh.
|
||||
/// This is faster than adding and removing a mesh and has a much lower memory footprint.
|
||||
/// This method can only be used if the meshes being updated have the same layout(number of
|
||||
/// vertices, triangles, submeshes).
|
||||
/// This is faster than removing and re-adding
|
||||
/// For efficiency update as few channels as possible.
|
||||
/// Apply must be called to apply the changes to the combined mesh
|
||||
/// </summary>
|
||||
public virtual bool UpdateGameObjects(GameObject[] gos)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
meshCombiner.name = name + "-mesh";
|
||||
return meshCombiner.UpdateGameObjects(gos, true, true, true, true, true,
|
||||
false, false, false, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the data in the combined mesh for meshes that are already in the combined mesh.
|
||||
/// This is faster than adding and removing a mesh and has a much lower memory footprint.
|
||||
/// This method can only be used if the meshes being updated have the same layout(number of
|
||||
/// vertices, triangles, submeshes).
|
||||
/// This is faster than removing and re-adding
|
||||
/// For efficiency update as few channels as possible.
|
||||
/// Apply must be called to apply the changes to the combined mesh
|
||||
/// </summary>
|
||||
public virtual bool UpdateGameObjects(GameObject[] gos, bool updateBounds)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
meshCombiner.name = name + "-mesh";
|
||||
return meshCombiner.UpdateGameObjects(gos, true, true, true, true, true,
|
||||
false, false, false, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the data in the combined mesh for meshes that are already in the combined mesh.
|
||||
/// This is faster than adding and removing a mesh and has a much lower memory footprint.
|
||||
/// This method can only be used if the meshes being updated have the same layout(number of
|
||||
/// vertices, triangles, submeshes).
|
||||
/// This is faster than removing and re-adding
|
||||
/// For efficiency update as few channels as possible.
|
||||
/// Apply must be called to apply the changes to the combined mesh
|
||||
/// </summary>
|
||||
public virtual bool UpdateGameObjects(GameObject[] gos, bool recalcBounds, bool updateVertices, bool updateNormals, bool updateTangents,
|
||||
bool updateUV, bool updateUV1, bool updateUV2,
|
||||
bool updateColors, bool updateSkinningInfo)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
meshCombiner.name = name + "-mesh";
|
||||
return meshCombiner.UpdateGameObjects(gos, recalcBounds, updateVertices, updateNormals, updateTangents, updateUV, updateUV2, false, false, updateColors, updateSkinningInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the data in the combined mesh for meshes that are already in the combined mesh.
|
||||
/// This is faster than adding and removing a mesh and has a much lower memory footprint.
|
||||
/// This method can only be used if the meshes being updated have the same layout(number of
|
||||
/// vertices, triangles, submeshes).
|
||||
/// This is faster than removing and re-adding
|
||||
/// For efficiency update as few channels as possible.
|
||||
/// Apply must be called to apply the changes to the combined mesh
|
||||
/// </summary>
|
||||
public virtual bool UpdateGameObjects(GameObject[] gos, bool recalcBounds,
|
||||
bool updateVertices, bool updateNormals, bool updateTangents,
|
||||
bool updateUV, bool updateUV2, bool updateUV3, bool updateUV4,
|
||||
bool updateUV5, bool updateUV6, bool updateUV7, bool updateUV8,
|
||||
bool updateColors, bool updateSkinningInfo)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
meshCombiner.name = name + "-mesh";
|
||||
return meshCombiner.UpdateGameObjects(gos, recalcBounds, updateVertices, updateNormals, updateTangents, updateUV, updateUV2, updateUV3, updateUV4, updateUV5, updateUV6, updateUV7, updateUV8, updateColors, updateSkinningInfo);
|
||||
}
|
||||
|
||||
|
||||
public virtual void UpdateSkinnedMeshApproximateBounds()
|
||||
{
|
||||
if (_ValidateForUpdateSkinnedMeshBounds())
|
||||
{
|
||||
meshCombiner.UpdateSkinnedMeshApproximateBounds();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void UpdateSkinnedMeshApproximateBoundsFromBones()
|
||||
{
|
||||
if (_ValidateForUpdateSkinnedMeshBounds())
|
||||
{
|
||||
meshCombiner.UpdateSkinnedMeshApproximateBoundsFromBones();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void UpdateSkinnedMeshApproximateBoundsFromBounds()
|
||||
{
|
||||
if (_ValidateForUpdateSkinnedMeshBounds())
|
||||
{
|
||||
meshCombiner.UpdateSkinnedMeshApproximateBoundsFromBounds();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual bool _ValidateForUpdateSkinnedMeshBounds()
|
||||
{
|
||||
if (meshCombiner.outputOption == MB2_OutputOptions.bakeMeshAssetsInPlace)
|
||||
{
|
||||
Debug.LogWarning("Can't UpdateSkinnedMeshApproximateBounds when output type is bakeMeshAssetsInPlace");
|
||||
return false;
|
||||
}
|
||||
if (meshCombiner.resultSceneObject == null)
|
||||
{
|
||||
Debug.LogWarning("Result Scene Object does not exist. No point in calling UpdateSkinnedMeshApproximateBounds.");
|
||||
return false;
|
||||
}
|
||||
SkinnedMeshRenderer smr = meshCombiner.resultSceneObject.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||
if (smr == null)
|
||||
{
|
||||
Debug.LogWarning("No SkinnedMeshRenderer on result scene object.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb955c20e5d3cce44b756cc24d501cb7
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_MeshBakerCommon.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,847 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DigitalOpus.MB.Core;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
public class MB3_MeshBakerGrouper : MonoBehaviour, MB_IMeshBakerSettingsHolder
|
||||
{
|
||||
public enum ClusterType
|
||||
{
|
||||
none,
|
||||
grid,
|
||||
pie,
|
||||
agglomerative,
|
||||
}
|
||||
|
||||
public static readonly Color WHITE_TRANSP = new Color(1f,1f,1f,.1f);
|
||||
|
||||
public MB3_MeshBakerGrouperBehaviour grouper;
|
||||
public ClusterType clusterType = ClusterType.none;
|
||||
|
||||
/// <summary>
|
||||
/// Baked meshes will be added as a child of this scene object.
|
||||
/// </summary>
|
||||
public Transform parentSceneObject;
|
||||
public GrouperData data;
|
||||
|
||||
// these are for getting a reasonable bounds in which to draw gizmos.
|
||||
[HideInInspector] public Bounds sourceObjectBounds = new Bounds(Vector3.zero, Vector3.one);
|
||||
|
||||
public string prefabOptions_outputFolder = "";
|
||||
public bool prefabOptions_autoGeneratePrefabs;
|
||||
public bool prefabOptions_mergeOutputIntoSinglePrefab;
|
||||
|
||||
public MB3_MeshCombinerSettings meshBakerSettingsAsset;
|
||||
public MB3_MeshCombinerSettingsData meshBakerSettings;
|
||||
|
||||
public MB_IMeshBakerSettings GetMeshBakerSettings()
|
||||
{
|
||||
if (meshBakerSettingsAsset == null)
|
||||
{
|
||||
if (meshBakerSettings == null) meshBakerSettings = new MB3_MeshCombinerSettingsData();
|
||||
return meshBakerSettings;
|
||||
}
|
||||
else
|
||||
{
|
||||
return meshBakerSettingsAsset.GetMeshBakerSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public void GetMeshBakerSettingsAsSerializedProperty(out string propertyName, out UnityEngine.Object targetObj)
|
||||
{
|
||||
if (meshBakerSettingsAsset == null)
|
||||
{
|
||||
targetObj = this;
|
||||
propertyName = "meshBakerSettings";
|
||||
}
|
||||
else
|
||||
{
|
||||
targetObj = meshBakerSettingsAsset;
|
||||
propertyName = "data";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
if (grouper == null)
|
||||
{
|
||||
grouper = CreateGrouper(clusterType);
|
||||
}
|
||||
grouper.DrawGizmos(sourceObjectBounds, data);
|
||||
}
|
||||
|
||||
public MB3_MeshBakerGrouperBehaviour CreateGrouper(ClusterType t)
|
||||
{
|
||||
if (t == ClusterType.grid) grouper = new MB3_MeshBakerGrouperGrid();
|
||||
if (t == ClusterType.pie) grouper = new MB3_MeshBakerGrouperPie();
|
||||
if (t == ClusterType.agglomerative)
|
||||
{
|
||||
grouper = new MB3_MeshBakerGrouperCluster();
|
||||
}
|
||||
if (t == ClusterType.none) grouper = new MB3_MeshBakerGrouperNone();
|
||||
return grouper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all child MeshBakers for the current object
|
||||
/// </summary>
|
||||
public void DeleteAllChildMeshBakers()
|
||||
{
|
||||
MB3_MeshBakerCommon[] mBakers = GetComponentsInChildren<MB3_MeshBakerCommon>();
|
||||
for (int i = 0; i < mBakers.Length; i++)
|
||||
{
|
||||
MB3_MeshBakerCommon mb = mBakers[i];
|
||||
GameObject resultGameObject = mb.meshCombiner.resultSceneObject;
|
||||
MB_Utility.Destroy(resultGameObject);
|
||||
MB_Utility.Destroy(mb.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Organize a TextureBakers objects to be combined into groups and generate a MeshBaker child for each group.
|
||||
/// </summary>
|
||||
public List<MB3_MeshBakerCommon> GenerateMeshBakers()
|
||||
{
|
||||
MB3_TextureBaker tb = GetComponent<MB3_TextureBaker>();
|
||||
if (tb == null)
|
||||
{
|
||||
Debug.LogError("There must be an MB3_TextureBaker attached to this game object.");
|
||||
return new List<MB3_MeshBakerCommon>();
|
||||
}
|
||||
|
||||
if (tb.GetObjectsToCombine().Count == 0)
|
||||
{
|
||||
Debug.LogError("The MB3_MeshBakerGrouper creates clusters based on the objects to combine in the MB3_TextureBaker component. There were no objects in this list.");
|
||||
return new List<MB3_MeshBakerCommon>();
|
||||
}
|
||||
|
||||
//check if any of the objes that will be added to bakers already exist in child bakers
|
||||
List<GameObject> objsWeAreGrouping = tb.GetObjectsToCombine();
|
||||
MB3_MeshBakerCommon[] alreadyExistBakers = GetComponentsInChildren<MB3_MeshBakerCommon>();
|
||||
bool foundChildBakersWithObjsToCombine = false;
|
||||
for (int i = 0; i < alreadyExistBakers.Length; i++)
|
||||
{
|
||||
List<GameObject> childOjs2Combine = alreadyExistBakers[i].GetObjectsToCombine();
|
||||
for (int j = 0; j < childOjs2Combine.Count; j++)
|
||||
{
|
||||
if (childOjs2Combine[j] != null && objsWeAreGrouping.Contains(childOjs2Combine[j]))
|
||||
{
|
||||
foundChildBakersWithObjsToCombine = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool proceed = true;
|
||||
if (foundChildBakersWithObjsToCombine)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
proceed = EditorUtility.DisplayDialog("Replace Previous Generated MeshBaker Objects", "Delete child MeshBaker objects?\n\n" +
|
||||
"This grouper has child MeshBaker objects from a previous clustering. Do you want to delete these and create new ones?", "OK", "Cancel");
|
||||
#else
|
||||
proceed = false;
|
||||
Debug.LogError("There are previously generated MeshBaker objects. Please use the editor to delete or replace them");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Application.isPlaying && prefabOptions_autoGeneratePrefabs)
|
||||
{
|
||||
Debug.LogError("Can only use Auto Generate Prefabs in the editor when the game is not playing.");
|
||||
proceed = false;
|
||||
}
|
||||
|
||||
List<MB3_MeshBakerCommon> newBakers;
|
||||
if (proceed)
|
||||
{
|
||||
if (foundChildBakersWithObjsToCombine) DeleteAllChildMeshBakers();
|
||||
if (grouper == null || grouper.GetClusterType() != clusterType)
|
||||
{
|
||||
grouper = CreateGrouper(clusterType);
|
||||
}
|
||||
newBakers = grouper.DoClustering(tb, this, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
newBakers = new List<MB3_MeshBakerCommon>();
|
||||
}
|
||||
|
||||
if (parentSceneObject != null &&
|
||||
MB_Utility.IsSceneInstance(parentSceneObject.gameObject))
|
||||
{
|
||||
for (int i = 0; i < newBakers.Count; i++)
|
||||
{
|
||||
newBakers[i].parentSceneObject = parentSceneObject;
|
||||
}
|
||||
}
|
||||
|
||||
return newBakers;
|
||||
}
|
||||
}
|
||||
|
||||
namespace DigitalOpus.MB.Core
|
||||
{
|
||||
/// all properties go here so that settings are remembered as user switches between cluster types
|
||||
[Serializable]
|
||||
public class GrouperData
|
||||
{
|
||||
public bool clusterOnLMIndex;
|
||||
public bool clusterByLODLevel;
|
||||
public Vector3 origin;
|
||||
|
||||
//Normally these properties would be in the subclasses but putting them here makes writing the inspector much easier
|
||||
//for grid
|
||||
public Vector3 cellSize = new Vector3(5, 5, 5);
|
||||
|
||||
//for pie
|
||||
public int pieNumSegments = 4;
|
||||
public Vector3 pieAxis = Vector3.up;
|
||||
public float ringSpacing = 100f;
|
||||
public bool combineSegmentsInInnermostRing = false;
|
||||
|
||||
//for clustering
|
||||
public bool includeCellsWithOnlyOneRenderer = true;
|
||||
public MB3_AgglomerativeClustering cluster;
|
||||
public float maxDistBetweenClusters = 1f;
|
||||
public float _lastMaxDistBetweenClusters;
|
||||
public float _ObjsExtents = 10f;
|
||||
public float _minDistBetweenClusters = .001f;
|
||||
public List<MB3_AgglomerativeClustering.ClusterNode> _clustersToDraw = new List<MB3_AgglomerativeClustering.ClusterNode>();
|
||||
public float[] _radii;
|
||||
}
|
||||
|
||||
public abstract class MB3_MeshBakerGrouperBehaviour
|
||||
{
|
||||
public abstract Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection, GrouperData d);
|
||||
public abstract void DrawGizmos(Bounds sourceObjectBounds, GrouperData d);
|
||||
public List<MB3_MeshBakerCommon> DoClustering(MB3_TextureBaker tb, MB3_MeshBakerGrouper grouper, GrouperData d)
|
||||
{
|
||||
List<MB3_MeshBakerCommon> outBakers = new List<MB3_MeshBakerCommon>();
|
||||
if (grouper.prefabOptions_autoGeneratePrefabs || grouper.prefabOptions_mergeOutputIntoSinglePrefab)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Debug.LogError("Cannot generate prefabs while playing. Prefabs can only be generated in the editor and not in play mode.");
|
||||
return outBakers;
|
||||
}
|
||||
}
|
||||
|
||||
//todo warn for no objects and no Texture Bake Result
|
||||
Dictionary<string, List<Renderer>> cell2objs = FilterIntoGroups(tb.GetObjectsToCombine(), d);
|
||||
|
||||
if (d.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;
|
||||
}
|
||||
if (d.clusterByLODLevel)
|
||||
{
|
||||
//visit each cell
|
||||
//visit each renderer
|
||||
//check if that renderer is a child of an LOD group
|
||||
// visit each LOD level check if this renderer is in that list.
|
||||
// if not add it to LOD0 for that cell
|
||||
// otherwise add it to LODX for that cell creating LODs as necessary
|
||||
Dictionary<string, List<Renderer>> cell2objsNew = new Dictionary<string, List<Renderer>>();
|
||||
foreach (string key in cell2objs.Keys)
|
||||
{
|
||||
List<Renderer> gaws = cell2objs[key];
|
||||
foreach (Renderer r in gaws)
|
||||
{
|
||||
if (r == null) continue;
|
||||
bool foundInLOD = false;
|
||||
LODGroup lodg = r.GetComponentInParent<LODGroup>();
|
||||
if (lodg != null)
|
||||
{
|
||||
LOD[] lods = lodg.GetLODs();
|
||||
for (int i = 0; i < lods.Length; i++)
|
||||
{
|
||||
LOD lod = lods[i];
|
||||
if (Array.Find<Renderer>(lod.renderers, x => x == r) != null)
|
||||
{
|
||||
foundInLOD = true;
|
||||
List<Renderer> rs;
|
||||
string newKey = String.Format("{0}_LOD{1}", key, i);
|
||||
if (!cell2objsNew.TryGetValue(newKey, out rs))
|
||||
{
|
||||
rs = new List<Renderer>();
|
||||
cell2objsNew.Add(newKey, rs);
|
||||
}
|
||||
if (!rs.Contains(r)) rs.Add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!foundInLOD)
|
||||
{
|
||||
List<Renderer> rs;
|
||||
string newKey = String.Format("{0}_LOD0", key);
|
||||
if (!cell2objsNew.TryGetValue(newKey, out rs))
|
||||
{
|
||||
rs = new List<Renderer>();
|
||||
cell2objsNew.Add(newKey, rs);
|
||||
}
|
||||
if (!rs.Contains(r)) rs.Add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
cell2objs = cell2objsNew;
|
||||
}
|
||||
|
||||
int clustersWithOnlyOneRenderer = 0;
|
||||
foreach (string key in cell2objs.Keys)
|
||||
{
|
||||
List<Renderer> gaws = cell2objs[key];
|
||||
if (gaws.Count > 1 || grouper.data.includeCellsWithOnlyOneRenderer)
|
||||
{
|
||||
outBakers.Add(AddMeshBaker(grouper, tb, key, gaws));
|
||||
}
|
||||
else
|
||||
{
|
||||
clustersWithOnlyOneRenderer++;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log(String.Format("Found {0} cells with Renderers. Not creating bakers for {1} because there is only one mesh in the cell. Creating {2} bakers.", cell2objs.Count, clustersWithOnlyOneRenderer, cell2objs.Count - clustersWithOnlyOneRenderer));
|
||||
return outBakers;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
MB3_MeshBakerCommon AddMeshBaker(MB3_MeshBakerGrouper grouper, 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;
|
||||
newMeshBaker.meshCombiner.settingsHolder = grouper;
|
||||
for (int i = 0; i < gaws.Count; i++)
|
||||
{
|
||||
newMeshBaker.GetObjectsToCombine().Add(gaws[i].gameObject);
|
||||
}
|
||||
|
||||
return newMeshBaker;
|
||||
}
|
||||
|
||||
public virtual MB3_MeshBakerGrouper.ClusterType GetClusterType()
|
||||
{
|
||||
return MB3_MeshBakerGrouper.ClusterType.none;
|
||||
}
|
||||
}
|
||||
|
||||
public class MB3_MeshBakerGrouperNone : MB3_MeshBakerGrouperBehaviour
|
||||
{
|
||||
public override Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection, GrouperData d)
|
||||
{
|
||||
Debug.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++)
|
||||
{
|
||||
if (selection[i] != null)
|
||||
{
|
||||
rs.Add(selection[i].GetComponent<Renderer>());
|
||||
}
|
||||
}
|
||||
|
||||
cell2objs.Add("MeshBaker", rs);
|
||||
return cell2objs;
|
||||
}
|
||||
|
||||
public override void DrawGizmos(Bounds sourceObjectBounds, GrouperData d)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override MB3_MeshBakerGrouper.ClusterType GetClusterType()
|
||||
{
|
||||
return MB3_MeshBakerGrouper.ClusterType.none;
|
||||
}
|
||||
}
|
||||
|
||||
public class MB3_MeshBakerGrouperGrid : MB3_MeshBakerGrouperBehaviour
|
||||
{
|
||||
public override Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection, GrouperData d)
|
||||
{
|
||||
Dictionary<string, List<Renderer>> cell2objs = new Dictionary<string, List<Renderer>>();
|
||||
if (d.cellSize.x <= 0f || d.cellSize.y <= 0f || d.cellSize.z <= 0f)
|
||||
{
|
||||
Debug.LogError("cellSize x,y,z must all be greater than zero.");
|
||||
return cell2objs;
|
||||
}
|
||||
|
||||
Debug.Log("Collecting renderers in each cell");
|
||||
foreach (GameObject t in selection)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObject go = t;
|
||||
Renderer mr = go.GetComponent<Renderer>();
|
||||
if (mr is MeshRenderer || mr is SkinnedMeshRenderer)
|
||||
{
|
||||
//get the cell this gameObject is in
|
||||
Vector3 gridVector = mr.bounds.center;
|
||||
gridVector.x = Mathf.Floor((gridVector.x - d.origin.x) / d.cellSize.x) * d.cellSize.x;
|
||||
gridVector.y = Mathf.Floor((gridVector.y - d.origin.y) / d.cellSize.y) * d.cellSize.y;
|
||||
gridVector.z = Mathf.Floor((gridVector.z - d.origin.z) / d.cellSize.z) * d.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(mr))
|
||||
{
|
||||
//Debug.Log("Adding " + mr + " todo " + gridVectorStr);
|
||||
objs.Add(mr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cell2objs;
|
||||
}
|
||||
|
||||
public override void DrawGizmos(Bounds sourceObjectBounds, GrouperData d)
|
||||
{
|
||||
Vector3 cs = d.cellSize;
|
||||
if (cs.x <= .00001f || cs.y <= .00001f || cs.z <= .00001f) return;
|
||||
Gizmos.color = MB3_MeshBakerGrouper.WHITE_TRANSP;
|
||||
Vector3 p = sourceObjectBounds.center - sourceObjectBounds.extents;
|
||||
Vector3 offset = d.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(d.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override MB3_MeshBakerGrouper.ClusterType GetClusterType()
|
||||
{
|
||||
return MB3_MeshBakerGrouper.ClusterType.grid;
|
||||
}
|
||||
}
|
||||
|
||||
public class MB3_MeshBakerGrouperPie : MB3_MeshBakerGrouperBehaviour
|
||||
{
|
||||
public override Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection, GrouperData d)
|
||||
{
|
||||
Dictionary<string, List<Renderer>> cell2objs = new Dictionary<string, List<Renderer>>();
|
||||
if (d.pieNumSegments == 0)
|
||||
{
|
||||
Debug.LogError("pieNumSegments must be greater than zero.");
|
||||
return cell2objs;
|
||||
}
|
||||
|
||||
if (d.pieAxis.magnitude <= .000001f)
|
||||
{
|
||||
Debug.LogError("Pie axis vector is too short.");
|
||||
return cell2objs;
|
||||
}
|
||||
|
||||
if (d.ringSpacing <= .000001f)
|
||||
{
|
||||
Debug.LogError("Ring spacing is too small.");
|
||||
return cell2objs;
|
||||
}
|
||||
|
||||
d.pieAxis.Normalize();
|
||||
Quaternion pieAxis2yIsUp = Quaternion.FromToRotation(d.pieAxis, Vector3.up);
|
||||
|
||||
Debug.Log("Collecting renderers in each cell");
|
||||
foreach (GameObject t in selection)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObject go = t;
|
||||
Renderer mr = go.GetComponent<Renderer>();
|
||||
if (mr is MeshRenderer || mr is SkinnedMeshRenderer)
|
||||
{
|
||||
//get the cell this gameObject is in
|
||||
Vector3 origin2obj = mr.bounds.center - d.origin;
|
||||
origin2obj = pieAxis2yIsUp * origin2obj;
|
||||
Vector2 origin2Obj2D = new Vector2(origin2obj.x, origin2obj.z);
|
||||
float radius = origin2Obj2D.magnitude;
|
||||
origin2obj.Normalize();
|
||||
|
||||
float deg_aboutY = 0f;
|
||||
if (Mathf.Abs(origin2obj.x) < 10e-5f && Mathf.Abs(origin2obj.z) < 10e-5f)
|
||||
{
|
||||
deg_aboutY = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
deg_aboutY = Mathf.Atan2(origin2obj.x, origin2obj.z) * Mathf.Rad2Deg;
|
||||
if (deg_aboutY < 0f) deg_aboutY = 360f + deg_aboutY;
|
||||
}
|
||||
|
||||
// Debug.Log ("Obj " + mr + " angle " + d_aboutY);
|
||||
int segment = Mathf.FloorToInt(deg_aboutY / 360f * d.pieNumSegments);
|
||||
int ring = Mathf.FloorToInt(radius / d.ringSpacing);
|
||||
if (ring == 0 && d.combineSegmentsInInnermostRing)
|
||||
{
|
||||
segment = 0;
|
||||
}
|
||||
|
||||
List<Renderer> objs = null;
|
||||
string segStr = "seg_" + segment + "_ring_" + ring;
|
||||
if (cell2objs.ContainsKey(segStr))
|
||||
{
|
||||
objs = cell2objs[segStr];
|
||||
}
|
||||
else
|
||||
{
|
||||
objs = new List<Renderer>();
|
||||
cell2objs.Add(segStr, objs);
|
||||
}
|
||||
|
||||
if (!objs.Contains(mr))
|
||||
{
|
||||
objs.Add(mr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cell2objs;
|
||||
}
|
||||
|
||||
public override void DrawGizmos(Bounds sourceObjectBounds, GrouperData d)
|
||||
{
|
||||
|
||||
if (d.pieAxis.magnitude < .1f) return;
|
||||
if (d.pieNumSegments < 1) return;
|
||||
|
||||
Gizmos.color = MB3_MeshBakerGrouper.WHITE_TRANSP;
|
||||
float rad = sourceObjectBounds.extents.magnitude;
|
||||
|
||||
int numRings = Mathf.CeilToInt(rad / d.ringSpacing);
|
||||
numRings = Mathf.Max(1, numRings);
|
||||
for (int i = 0; i < numRings; i++)
|
||||
{
|
||||
DrawCircle(d.pieAxis.normalized, d.origin, d.ringSpacing * (i + 1), 24);
|
||||
}
|
||||
|
||||
Quaternion yIsUp2PieAxis = Quaternion.FromToRotation(Vector3.up, d.pieAxis);
|
||||
Quaternion rStep = Quaternion.AngleAxis(180f / d.pieNumSegments, Vector3.up);
|
||||
Vector3 r = Vector3.forward;
|
||||
for (int i = 0; i < d.pieNumSegments; i++)
|
||||
{
|
||||
Vector3 rr = yIsUp2PieAxis * r;
|
||||
Vector3 origin = d.origin;
|
||||
int nr = numRings;
|
||||
if (d.combineSegmentsInInnermostRing)
|
||||
{
|
||||
origin = d.origin + rr.normalized * d.ringSpacing;
|
||||
nr = numRings - 1;
|
||||
}
|
||||
|
||||
if (nr == 0) break;
|
||||
|
||||
Gizmos.DrawLine(origin, origin + nr * d.ringSpacing * rr.normalized);
|
||||
r = rStep * r;
|
||||
r = rStep * r;
|
||||
}
|
||||
}
|
||||
|
||||
static int MaxIndexInVector3(Vector3 v)
|
||||
{
|
||||
int idx = 0;
|
||||
float val = v.x;
|
||||
if (v.y > val)
|
||||
{
|
||||
idx = 1;
|
||||
val = v.y;
|
||||
}
|
||||
if (v.z > val)
|
||||
{
|
||||
idx = 2;
|
||||
val = v.z;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
public static void DrawCircle(Vector3 axis, Vector3 center, float radius, int subdiv)
|
||||
{
|
||||
Quaternion q = Quaternion.AngleAxis(360 / subdiv, axis);
|
||||
int maxIdx = MaxIndexInVector3(axis);
|
||||
int otherIdx = maxIdx == 0 ? maxIdx + 1 : maxIdx - 1;
|
||||
Vector3 r = axis; //r construct a vector perpendicular to axis
|
||||
float temp = r[maxIdx];
|
||||
r[maxIdx] = r[otherIdx];
|
||||
r[otherIdx] = -temp;
|
||||
r = Vector3.ProjectOnPlane(r, axis);
|
||||
r.Normalize();
|
||||
r *= radius;
|
||||
for (int i = 0; i < subdiv + 1; i++)
|
||||
{
|
||||
Vector3 r2 = q * r;
|
||||
Gizmos.color = MB3_MeshBakerGrouper.WHITE_TRANSP;
|
||||
Gizmos.DrawLine(center + r, center + r2);
|
||||
r = r2;
|
||||
}
|
||||
}
|
||||
public override MB3_MeshBakerGrouper.ClusterType GetClusterType()
|
||||
{
|
||||
return MB3_MeshBakerGrouper.ClusterType.pie;
|
||||
}
|
||||
}
|
||||
|
||||
public class MB3_MeshBakerGrouperCluster : MB3_MeshBakerGrouperBehaviour
|
||||
{
|
||||
|
||||
public override Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection, GrouperData d)
|
||||
{
|
||||
Dictionary<string, List<Renderer>> cell2objs = new Dictionary<string, List<Renderer>>();
|
||||
for (int i = 0; i < d._clustersToDraw.Count; i++)
|
||||
{
|
||||
MB3_AgglomerativeClustering.ClusterNode node = d._clustersToDraw[i];
|
||||
List<Renderer> rrs = new List<Renderer>();
|
||||
for (int j = 0; j < node.leafs.Length; j++)
|
||||
{
|
||||
Renderer r = d.cluster.clusters[node.leafs[j]].leaf.go.GetComponent<Renderer>();
|
||||
if (r is MeshRenderer || r is SkinnedMeshRenderer)
|
||||
{
|
||||
rrs.Add(r);
|
||||
}
|
||||
}
|
||||
cell2objs.Add("Cluster_" + i, rrs);
|
||||
}
|
||||
return cell2objs;
|
||||
}
|
||||
|
||||
public void BuildClusters(List<GameObject> gos, ProgressUpdateCancelableDelegate progFunc, GrouperData d)
|
||||
{
|
||||
if (gos.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("No objects to cluster. Add some objects to the list of Objects To Combine.");
|
||||
return;
|
||||
}
|
||||
if (d.cluster == null) { d.cluster = new MB3_AgglomerativeClustering(); }
|
||||
List<MB3_AgglomerativeClustering.item_s> its = new List<MB3_AgglomerativeClustering.item_s>();
|
||||
for (int i = 0; i < gos.Count; i++)
|
||||
{
|
||||
if (gos[i] != null && its.Find(x => x.go == gos[i]) == null)
|
||||
{
|
||||
Renderer mr = gos[i].GetComponent<Renderer>();
|
||||
if (mr != null && (mr is MeshRenderer || mr is SkinnedMeshRenderer))
|
||||
{
|
||||
MB3_AgglomerativeClustering.item_s ii = new MB3_AgglomerativeClustering.item_s();
|
||||
ii.go = gos[i];
|
||||
ii.coord = mr.bounds.center;
|
||||
its.Add(ii);
|
||||
}
|
||||
}
|
||||
}
|
||||
d.cluster.items = its;
|
||||
//yield return cluster.agglomerate();
|
||||
d.cluster.agglomerate(progFunc);
|
||||
if (!d.cluster.wasCanceled)
|
||||
{
|
||||
float smallest, largest;
|
||||
_BuildListOfClustersToDraw(progFunc, out smallest, out largest, d);
|
||||
d.maxDistBetweenClusters = Mathf.Lerp(smallest, largest, .9f);
|
||||
}
|
||||
}
|
||||
|
||||
public void _BuildListOfClustersToDraw(ProgressUpdateCancelableDelegate progFunc, out float smallest, out float largest, GrouperData d)
|
||||
{
|
||||
if (d._clustersToDraw == null)
|
||||
{
|
||||
d._clustersToDraw = new List<MB3_AgglomerativeClustering.ClusterNode>();
|
||||
}
|
||||
d._clustersToDraw.Clear();
|
||||
if (d.cluster.clusters == null || d.cluster.clusters.Length == 0)
|
||||
{
|
||||
smallest = 1f;
|
||||
largest = 10f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (progFunc != null) progFunc("Building Clusters To Draw A:", 0);
|
||||
largest = 1f;
|
||||
smallest = 10e6f;
|
||||
for (int i = 0; i < d.cluster.clusters.Length; i++)
|
||||
{
|
||||
MB3_AgglomerativeClustering.ClusterNode node = d.cluster.clusters[i];
|
||||
//don't draw clusters that were merged too far apart and only want leaf nodes
|
||||
if (node.distToMergedCentroid <= d.maxDistBetweenClusters /*&& node.leaf == null*/)
|
||||
{
|
||||
if (d.includeCellsWithOnlyOneRenderer)
|
||||
{
|
||||
d._clustersToDraw.Add(node);
|
||||
}
|
||||
else if (node.leaf == null)
|
||||
{
|
||||
d._clustersToDraw.Add(node);
|
||||
}
|
||||
}
|
||||
if (node.distToMergedCentroid > largest)
|
||||
{
|
||||
largest = node.distToMergedCentroid;
|
||||
}
|
||||
if (node.height > 0 && node.distToMergedCentroid < smallest)
|
||||
{
|
||||
smallest = node.distToMergedCentroid;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (progFunc != null) progFunc("Building Clusters To Draw B:", 0);
|
||||
{
|
||||
List<MB3_AgglomerativeClustering.ClusterNode> removeMe = new List<MB3_AgglomerativeClustering.ClusterNode>();
|
||||
for (int i = 0; i < d._clustersToDraw.Count; i++)
|
||||
{
|
||||
removeMe.Add(d._clustersToDraw[i].cha);
|
||||
removeMe.Add(d._clustersToDraw[i].chb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < removeMe.Count; i++)
|
||||
{
|
||||
d._clustersToDraw.Remove(removeMe[i]);
|
||||
}
|
||||
}
|
||||
|
||||
d._radii = new float[d._clustersToDraw.Count];
|
||||
if (progFunc != null) progFunc("Building Clusters To Draw C:", 0);
|
||||
for (int i = 0; i < d._radii.Length; i++)
|
||||
{
|
||||
MB3_AgglomerativeClustering.ClusterNode n = d._clustersToDraw[i];
|
||||
Bounds b = new Bounds(n.centroid, Vector3.one);
|
||||
for (int j = 0; j < n.leafs.Length; j++)
|
||||
{
|
||||
Renderer r = d.cluster.clusters[n.leafs[j]].leaf.go.GetComponent<Renderer>();
|
||||
if (r != null)
|
||||
{
|
||||
b.Encapsulate(r.bounds);
|
||||
}
|
||||
}
|
||||
d._radii[i] = b.extents.magnitude;
|
||||
}
|
||||
if (progFunc != null) progFunc("Building Clusters To Draw D:", 0);
|
||||
if (smallest >= largest)
|
||||
{
|
||||
Debug.LogError("The smallest distance between clusters is greater than the largest distance between clusters. This should not happen.");
|
||||
smallest = 10e-6f;
|
||||
if (largest < 10f)
|
||||
{
|
||||
largest = 10f;
|
||||
}
|
||||
}
|
||||
d._ObjsExtents = largest + 1f;
|
||||
d._minDistBetweenClusters = 0.1f * smallest;
|
||||
|
||||
if (d._ObjsExtents < 2f) d._ObjsExtents = 2f;
|
||||
}
|
||||
|
||||
public override void DrawGizmos(Bounds sceneObjectBounds, GrouperData d)
|
||||
{
|
||||
if (d.cluster == null || d.cluster.clusters == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Gizmos.color = MB3_MeshBakerGrouper.WHITE_TRANSP;
|
||||
for (int i = 0; i < d._clustersToDraw.Count; i++)
|
||||
{
|
||||
Gizmos.color = MB3_MeshBakerGrouper.WHITE_TRANSP;
|
||||
MB3_AgglomerativeClustering.ClusterNode node = d._clustersToDraw[i];
|
||||
Gizmos.DrawWireSphere(node.centroid, d._radii[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public override MB3_MeshBakerGrouper.ClusterType GetClusterType()
|
||||
{
|
||||
return MB3_MeshBakerGrouper.ClusterType.agglomerative;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a97974931c5043247b11cd77898c1702
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_MeshBakerGrouper.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,210 @@
|
||||
//----------------------------------------------
|
||||
// MeshBaker
|
||||
// Copyright © 2011-2012 Ian Deane
|
||||
//----------------------------------------------
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using DigitalOpus.MB.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Root class of all the baking Components
|
||||
/// </summary>
|
||||
public abstract class MB3_MeshBakerRoot : MonoBehaviour {
|
||||
|
||||
/**
|
||||
* Transparent shaders often require objects to be sorted along
|
||||
*/
|
||||
public class ZSortObjects
|
||||
{
|
||||
public Vector3 sortAxis;
|
||||
public class Item
|
||||
{
|
||||
public GameObject go;
|
||||
public Vector3 point;
|
||||
}
|
||||
|
||||
public class ItemComparer : IComparer<Item>
|
||||
{
|
||||
public int Compare(Item a, Item b)
|
||||
{
|
||||
return (int)Mathf.Sign(b.point.z - a.point.z);
|
||||
}
|
||||
}
|
||||
|
||||
public void SortByDistanceAlongAxis(List<GameObject> gos)
|
||||
{
|
||||
if (sortAxis == Vector3.zero)
|
||||
{
|
||||
Debug.LogError("The sort axis cannot be the zero vector.");
|
||||
return;
|
||||
}
|
||||
Debug.Log("Z sorting meshes along axis numObjs=" + gos.Count);
|
||||
List<Item> items = new List<Item>();
|
||||
Quaternion q = Quaternion.FromToRotation(sortAxis, Vector3.forward);
|
||||
for (int i = 0; i < gos.Count; i++)
|
||||
{
|
||||
if (gos[i] != null)
|
||||
{
|
||||
Item item = new Item();
|
||||
item.point = gos[i].transform.position;
|
||||
item.go = gos[i];
|
||||
item.point = q * item.point;
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
items.Sort(new ItemComparer());
|
||||
|
||||
for (int i = 0; i < gos.Count; i++)
|
||||
{
|
||||
gos[i] = items[i].go;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 sortAxis;
|
||||
|
||||
[HideInInspector] public abstract MB2_TextureBakeResults textureBakeResults{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
//todo switch this to List<Renderer>
|
||||
public virtual List<GameObject> GetObjectsToCombine(){
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual void PurgeNullsFromObjectsToCombine()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static bool DoCombinedValidate(MB3_MeshBakerRoot mom, MB_ObjsToCombineTypes objToCombineType, MB2_EditorMethodsInterface editorMethods, MB2_ValidationLevel validationLevel){
|
||||
if (mom.textureBakeResults == null){
|
||||
Debug.LogError("Need to set Texture Bake Result on " + mom);
|
||||
return false;
|
||||
}
|
||||
if (mom is MB3_MeshBakerCommon){
|
||||
MB3_MeshBakerCommon momMB = (MB3_MeshBakerCommon) mom;
|
||||
MB3_TextureBaker tb = momMB.GetTextureBaker();
|
||||
if (tb != null && tb.textureBakeResults != mom.textureBakeResults){
|
||||
Debug.LogWarning("Texture Bake Result on this component is not the same as the Texture Bake Result on the MB3_TextureBaker.");
|
||||
}
|
||||
}
|
||||
|
||||
List<GameObject> objsToMesh = mom.GetObjectsToCombine();
|
||||
if (!ValidateTextureBakerGameObjects(mom, objsToMesh, validationLevel)) {
|
||||
return false;
|
||||
}
|
||||
List<GameObject> objs;
|
||||
|
||||
if (mom is MB3_MeshBaker)
|
||||
{
|
||||
objs = mom.GetObjectsToCombine();
|
||||
//if (((MB3_MeshBaker)mom).useObjsToMeshFromTexBaker && tb != null) objs = tb.GetObjectsToCombine();
|
||||
if (objs == null || objs.Count == 0)
|
||||
{
|
||||
Debug.LogError("No meshes to combine. Please assign some meshes to combine.");
|
||||
return false;
|
||||
}
|
||||
if (mom is MB3_MeshBaker && ((MB3_MeshBaker)mom).meshCombiner.settings.renderType == MB_RenderType.skinnedMeshRenderer){
|
||||
if (!editorMethods.ValidateSkinnedMeshes(objs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (editorMethods != null){
|
||||
editorMethods.CheckPrefabTypes(objToCombineType, objsToMesh);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ValidateTextureBakerGameObjects(MB3_MeshBakerRoot mom, List<GameObject> objsToMesh, MB2_ValidationLevel validationLevel)
|
||||
{
|
||||
Dictionary<int,MB_Utility.MeshAnalysisResult> meshAnalysisResultCache = null;
|
||||
if (validationLevel == MB2_ValidationLevel.robust){
|
||||
meshAnalysisResultCache = new Dictionary<int, MB_Utility.MeshAnalysisResult>();
|
||||
}
|
||||
Dictionary<string, Material> matName2Mat = new Dictionary<string, Material>();
|
||||
for (int i = 0; i < objsToMesh.Count; i++){
|
||||
GameObject go = objsToMesh[i];
|
||||
if (go == null){
|
||||
Debug.LogError(string.Format("The list of objects to combine contains a null at position {0}. Select and use [shift + delete] to remove the object, or purge all null objects from the context menu.", i));
|
||||
return false;
|
||||
}
|
||||
for (int j = i + 1; j < objsToMesh.Count; j++){
|
||||
if (objsToMesh[i] == objsToMesh[j]){
|
||||
Debug.LogError("The list of objects to combine contains duplicates at " + i + " and " + j);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Material[] mats = MB_Utility.GetGOMaterials(go);
|
||||
if (mats.Length == 0){
|
||||
Debug.LogError("Object " + go + " in the list of objects to be combined does not have a material");
|
||||
return false;
|
||||
}
|
||||
Mesh m = MB_Utility.GetMesh(go);
|
||||
if (m == null){
|
||||
Debug.LogError("Object " + go + " in the list of objects to be combined does not have a mesh");
|
||||
return false;
|
||||
}
|
||||
if (m != null && mom.textureBakeResults != null){ //This check can be very expensive and it only warns so only do this if we are in the editor.
|
||||
if (Application.isEditor &&
|
||||
!Application.isPlaying &&
|
||||
mom.textureBakeResults.doMultiMaterial &&
|
||||
validationLevel >= MB2_ValidationLevel.robust){
|
||||
MB_Utility.MeshAnalysisResult mar;
|
||||
if (!meshAnalysisResultCache.TryGetValue(m.GetInstanceID(),out mar)){
|
||||
MB_Utility.doSubmeshesShareVertsOrTris(m,ref mar);
|
||||
meshAnalysisResultCache.Add (m.GetInstanceID(),mar);
|
||||
}
|
||||
if (mar.hasOverlappingSubmeshVerts){
|
||||
Debug.LogWarning("Object " + objsToMesh[i] + " in the list of objects to combine has overlapping submeshes (submeshes share vertices). If the UVs associated with the shared vertices are important then this bake may not work. If you are using multiple materials then this object can only be combined with objects that use the exact same set of textures (each atlas contains one texture). There may be other undesirable side affects as well. Mesh Master, available in the asset store can fix overlapping submeshes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MBVersion.IsUsingAddressables())
|
||||
{
|
||||
HashSet<string> materialsWithDuplicateNames = new HashSet<string>();
|
||||
for (int matIdx = 0; matIdx < mats.Length; matIdx++)
|
||||
{
|
||||
if (mats[matIdx] != null)
|
||||
{
|
||||
if (matName2Mat.ContainsKey(mats[matIdx].name))
|
||||
{
|
||||
if (mats[matIdx] != matName2Mat[mats[matIdx].name])
|
||||
{
|
||||
// This is an error. If using addressables we consider materials that have the same name to be the same material when baking at runtime.
|
||||
// Two different material must NOT have the same name.
|
||||
materialsWithDuplicateNames.Add(mats[matIdx].name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
matName2Mat.Add(mats[matIdx].name, mats[matIdx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (materialsWithDuplicateNames.Count > 0)
|
||||
{
|
||||
String[] stringArray = new String[materialsWithDuplicateNames.Count];
|
||||
materialsWithDuplicateNames.CopyTo(stringArray);
|
||||
string matsWithSameName = string.Join(",", stringArray);
|
||||
Debug.LogError("The source objects use different materials that have the same name (" + matsWithSameName + "). " +
|
||||
"If using addressables, materials with the same name are considered to be the same material when baking meshes at runtime. " +
|
||||
"If you want to use this Material Bake Result at runtime then all source materials must have distinct names. Baking in edit-mode will still work.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aceaf5bd3ec59834bbd2a309fb7b0967
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_MeshBakerRoot.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,111 @@
|
||||
//----------------------------------------------
|
||||
// MeshBaker
|
||||
// Copyright © 2011-2012 Ian Deane
|
||||
//----------------------------------------------
|
||||
using UnityEngine;
|
||||
using DigitalOpus.MB.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Component that is an endless mesh. You don't need to worry about the 65k limit when adding meshes. It is like a List of combined meshes. Internally it manages
|
||||
/// a collection of CombinedMeshes that are added and deleted as necessary.
|
||||
///
|
||||
/// Note that this implementation does
|
||||
/// not attempt to split meshes. Each mesh is added to one of the internal meshes as an atomic unit.
|
||||
///
|
||||
/// This class is a Component. It must be added to a GameObject to use it. It is a wrapper for MB2_Multi_meshCombiner which contains the same functionality but is not a component
|
||||
/// so it can be instantiated like a normal class.
|
||||
/// </summary>
|
||||
public class MB3_MultiMeshBaker : MB3_MeshBakerCommon {
|
||||
|
||||
[SerializeField] protected MB3_MultiMeshCombiner _meshCombiner = new MB3_MultiMeshCombiner();
|
||||
|
||||
// [ContextMenu("Print Timings")]
|
||||
public void PrintTimings()
|
||||
{
|
||||
double db_showHideGameObjects = 0;
|
||||
double db_addDeleteGameObjects = 0;
|
||||
|
||||
double db_addDeleteGameObjects_InitFromMeshCombiner = 0;
|
||||
double db_addDeleteGameObjects_Init = 0;
|
||||
double db_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers = 0;
|
||||
double db_addDeleteGameObjects_CopyFromDGOMeshToBuffers = 0;
|
||||
double db_addDeleteGameObjects_CollectMeshData = 0;
|
||||
|
||||
double db_apply = 0;
|
||||
double db_applyShowHide = 0;
|
||||
double db_updateGameObjects = 0;
|
||||
|
||||
for (int i = 0; i < _meshCombiner.meshCombiners.Count; i++)
|
||||
{
|
||||
MB3_MeshCombinerSingle c = _meshCombiner.meshCombiners[i].combinedMesh;
|
||||
|
||||
db_showHideGameObjects += c.db_showHideGameObjects.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects += c.db_addDeleteGameObjects.Elapsed.TotalSeconds;
|
||||
|
||||
db_addDeleteGameObjects_CollectMeshData += c.db_addDeleteGameObjects_CollectMeshData.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects_InitFromMeshCombiner += c.db_addDeleteGameObjects_InitFromMeshCombiner.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects_Init += c.db_addDeleteGameObjects_Init.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers += c.db_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers.Elapsed.TotalSeconds;
|
||||
db_addDeleteGameObjects_CopyFromDGOMeshToBuffers += c.db_addDeleteGameObjects_CopyFromDGOMeshToBuffers.Elapsed.TotalSeconds;
|
||||
|
||||
db_apply += c.db_apply.Elapsed.TotalSeconds;
|
||||
db_applyShowHide += c.db_applyShowHide.Elapsed.TotalSeconds;
|
||||
db_updateGameObjects += c.db_updateGameObjects.Elapsed.TotalSeconds;
|
||||
}
|
||||
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine("Timings " + (_meshCombiner.settings.meshAPI == MB_MeshCombineAPIType.betaNativeArrayAPI ? " newMeshAPI " : " oldMeshAPI"));
|
||||
sb.AppendLine("db_showHideGameObjects\t" + db_showHideGameObjects);
|
||||
sb.AppendLine("db_addDeleteGameObjects\t" + db_addDeleteGameObjects);
|
||||
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CollectMeshData\t" + db_addDeleteGameObjects_CollectMeshData);
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_InitFromMeshCombiner\t" + db_addDeleteGameObjects_InitFromMeshCombiner);
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_Init\t" + db_addDeleteGameObjects_Init);
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers\t" + db_addDeleteGameObjects_CopyArraysFromPreviousBakeBuffersToNewBuffers);
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CopyFromDGOMeshToBuffers\t" + db_addDeleteGameObjects_CopyFromDGOMeshToBuffers);
|
||||
|
||||
sb.AppendLine("\t\tdb_addDeleteGameObjects_CollectMeshData tdb_addDeleteGameObjects_CollectMeshData ");
|
||||
//sb.AppendLine("\t\t\t\t MeshChannelsCache_NativeArray.db_AA\t" + MeshChannelsCache_NativeArray.db_AA);
|
||||
//sb.AppendLine("\t\t\t\t MeshChannelsCache_NativeArray.db_BB\t" + MeshChannelsCache_NativeArray.db_BB);
|
||||
//sb.AppendLine("\t\t\t\t MeshChannelsCache_NativeArray.db_CC\t" + MeshChannelsCache_NativeArray.db_CC);
|
||||
//sb.AppendLine("\t\t\t\t MeshChannelsCache_NativeArray.db_DD\t" + MeshChannelsCache_NativeArray.db_DD);
|
||||
|
||||
|
||||
sb.AppendLine("db_apply\t" + db_apply);
|
||||
sb.AppendLine("db_applyShowHide\t" + db_applyShowHide);
|
||||
sb.AppendLine("db_updateGameObjects\t" + db_updateGameObjects);
|
||||
Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
public override MB3_MeshCombiner meshCombiner{
|
||||
get {return _meshCombiner;}
|
||||
}
|
||||
|
||||
public override bool AddDeleteGameObjects(GameObject[] gos, GameObject[] deleteGOs, bool disableRendererInSource)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
if (_meshCombiner.resultSceneObject == null){
|
||||
_meshCombiner.resultSceneObject = new GameObject("CombinedMesh-" + name);
|
||||
}
|
||||
meshCombiner.name = name + "-mesh";
|
||||
return _meshCombiner.AddDeleteGameObjects(gos,deleteGOs,disableRendererInSource);
|
||||
}
|
||||
|
||||
public override bool AddDeleteGameObjectsByID(GameObject[] gos, int[] deleteGOs, bool disableRendererInSource)
|
||||
{
|
||||
UpgradeToCurrentVersionIfNecessary();
|
||||
if (_meshCombiner.resultSceneObject == null){
|
||||
_meshCombiner.resultSceneObject = new GameObject("CombinedMesh-" + name);
|
||||
}
|
||||
meshCombiner.name = name + "-mesh";
|
||||
return _meshCombiner.AddDeleteGameObjectsByID(gos,deleteGOs,disableRendererInSource);
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
{
|
||||
if (_meshCombiner != null)
|
||||
{
|
||||
_meshCombiner.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79177c6ffa4ff3846a904f185a7591cf
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_MultiMeshBaker.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,778 @@
|
||||
//----------------------------------------------
|
||||
// MeshBaker
|
||||
// Copyright © 2011-2012 Ian Deane
|
||||
//----------------------------------------------
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using DigitalOpus.MB.Core;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Component that handles baking materials into a combined material.
|
||||
///
|
||||
/// The result of the material baking process is a MB2_TextureBakeResults object, which
|
||||
/// becomes the input for the mesh baking.
|
||||
///
|
||||
/// This class uses the MB_TextureCombiner to do the combining.
|
||||
///
|
||||
/// This class is a Component (MonoBehavior) so it is serialized and found using GetComponent. If
|
||||
/// you want to access the texture baking functionality without creating a Component then use MB_TextureCombiner
|
||||
/// directly.
|
||||
/// </summary>
|
||||
public class MB3_TextureBaker : MB3_MeshBakerRoot
|
||||
{
|
||||
public MB2_LogLevel LOG_LEVEL = MB2_LogLevel.info;
|
||||
|
||||
[SerializeField]
|
||||
protected MB2_TextureBakeResults _textureBakeResults;
|
||||
public override MB2_TextureBakeResults textureBakeResults
|
||||
{
|
||||
get { return _textureBakeResults; }
|
||||
set { _textureBakeResults = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected int _atlasPadding = 1;
|
||||
public virtual int atlasPadding
|
||||
{
|
||||
get { return _atlasPadding; }
|
||||
set { _atlasPadding = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected int _maxAtlasSize = MB2_TexturePacker.MAX_ATLAS_SIZE;
|
||||
public virtual int maxAtlasSize
|
||||
{
|
||||
get { return _maxAtlasSize; }
|
||||
set { _maxAtlasSize = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _useMaxAtlasWidthOverride = false;
|
||||
public virtual bool useMaxAtlasWidthOverride
|
||||
{
|
||||
get { return _useMaxAtlasWidthOverride; }
|
||||
set { _useMaxAtlasWidthOverride = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected int _maxAtlasWidthOverride = MB2_TexturePacker.MAX_ATLAS_SIZE;
|
||||
public virtual int maxAtlasWidthOverride
|
||||
{
|
||||
get { return _maxAtlasWidthOverride; }
|
||||
set { _maxAtlasWidthOverride = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _useMaxAtlasHeightOverride = false;
|
||||
public virtual bool useMaxAtlasHeightOverride
|
||||
{
|
||||
get { return _useMaxAtlasHeightOverride; }
|
||||
set { _useMaxAtlasHeightOverride = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected int _maxAtlasHeightOverride = MB2_TexturePacker.MAX_ATLAS_SIZE;
|
||||
public virtual int maxAtlasHeightOverride
|
||||
{
|
||||
get { return _maxAtlasHeightOverride; }
|
||||
set { _maxAtlasHeightOverride = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _resizePowerOfTwoTextures = false;
|
||||
public virtual bool resizePowerOfTwoTextures
|
||||
{
|
||||
get { return _resizePowerOfTwoTextures; }
|
||||
set { _resizePowerOfTwoTextures = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _fixOutOfBoundsUVs = false; //is considerMeshUVs but can't change because it would break all existing bakers
|
||||
public virtual bool fixOutOfBoundsUVs
|
||||
{
|
||||
get { return _fixOutOfBoundsUVs; }
|
||||
set { _fixOutOfBoundsUVs = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected int _maxTilingBakeSize = 1024;
|
||||
public virtual int maxTilingBakeSize
|
||||
{
|
||||
get { return _maxTilingBakeSize; }
|
||||
set { _maxTilingBakeSize = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected MB2_PackingAlgorithmEnum _packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
|
||||
public virtual MB2_PackingAlgorithmEnum packingAlgorithm
|
||||
{
|
||||
get { return _packingAlgorithm; }
|
||||
set { _packingAlgorithm = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected int _layerTexturePackerFastMesh = -1;
|
||||
public virtual int layerForTexturePackerFastMesh
|
||||
{
|
||||
get { return _layerTexturePackerFastMesh; }
|
||||
set { _layerTexturePackerFastMesh = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _meshBakerTexturePackerForcePowerOfTwo = true;
|
||||
public bool meshBakerTexturePackerForcePowerOfTwo
|
||||
{
|
||||
get { return _meshBakerTexturePackerForcePowerOfTwo; }
|
||||
set { _meshBakerTexturePackerForcePowerOfTwo = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
[NonReorderable] //see MB-136 for why this is here
|
||||
#endif
|
||||
protected List<ShaderTextureProperty> _customShaderProperties = new List<ShaderTextureProperty>();
|
||||
public virtual List<ShaderTextureProperty> customShaderProperties
|
||||
{
|
||||
get { return _customShaderProperties; }
|
||||
set { _customShaderProperties = value; }
|
||||
}
|
||||
|
||||
|
||||
[SerializeField]
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
[NonReorderable] //see MB-136 for why this is here
|
||||
#endif
|
||||
protected List<string> _texturePropNamesToIgnore = new List<string>();
|
||||
public virtual List<string> texturePropNamesToIgnore
|
||||
{
|
||||
get { return _texturePropNamesToIgnore; }
|
||||
set { _texturePropNamesToIgnore = value; }
|
||||
}
|
||||
|
||||
//this is depricated
|
||||
[SerializeField]
|
||||
protected List<string> _customShaderPropNames_Depricated = new List<string>();
|
||||
public virtual List<string> customShaderPropNames
|
||||
{
|
||||
get { return _customShaderPropNames_Depricated; }
|
||||
set { _customShaderPropNames_Depricated = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected MB2_TextureBakeResults.ResultType _resultType;
|
||||
public virtual MB2_TextureBakeResults.ResultType resultType
|
||||
{
|
||||
get { return _resultType; }
|
||||
set { _resultType = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _doMultiMaterial;
|
||||
public virtual bool doMultiMaterial
|
||||
{
|
||||
get { return _doMultiMaterial; }
|
||||
set { _doMultiMaterial = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _doMultiMaterialSplitAtlasesIfTooBig = true;
|
||||
public virtual bool doMultiMaterialSplitAtlasesIfTooBig
|
||||
{
|
||||
get { return _doMultiMaterialSplitAtlasesIfTooBig; }
|
||||
set { _doMultiMaterialSplitAtlasesIfTooBig = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _doMultiMaterialSplitAtlasesIfOBUVs = true;
|
||||
public virtual bool doMultiMaterialSplitAtlasesIfOBUVs
|
||||
{
|
||||
get { return _doMultiMaterialSplitAtlasesIfOBUVs; }
|
||||
set { _doMultiMaterialSplitAtlasesIfOBUVs = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected Material _resultMaterial;
|
||||
public virtual Material resultMaterial
|
||||
{
|
||||
get { return _resultMaterial; }
|
||||
set { _resultMaterial = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _considerNonTextureProperties = false;
|
||||
public bool considerNonTextureProperties
|
||||
{
|
||||
get { return _considerNonTextureProperties; }
|
||||
set { _considerNonTextureProperties = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
protected bool _doSuggestTreatment = true;
|
||||
public bool doSuggestTreatment
|
||||
{
|
||||
get { return _doSuggestTreatment; }
|
||||
set { _doSuggestTreatment = value; }
|
||||
}
|
||||
|
||||
private MB3_TextureCombiner.CreateAtlasesCoroutineResult _coroutineResult;
|
||||
public MB3_TextureCombiner.CreateAtlasesCoroutineResult CoroutineResult
|
||||
{
|
||||
get
|
||||
{
|
||||
return _coroutineResult;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
[NonReorderable] //see MB-136 for why this is here
|
||||
#endif
|
||||
public MB_MultiMaterial[] resultMaterials = new MB_MultiMaterial[0];
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
[NonReorderable] //see MB-136 for why this is here
|
||||
#endif
|
||||
public MB_MultiMaterialTexArray[] resultMaterialsTexArray = new MB_MultiMaterialTexArray[0];
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
[NonReorderable] //see MB-136 for why this is here
|
||||
#endif
|
||||
public MB_TextureArrayFormatSet[] textureArrayOutputFormats;
|
||||
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
[NonReorderable] //see MB-136 for why this is here
|
||||
#endif
|
||||
public List<GameObject> objsToMesh; //todo make this Renderer
|
||||
|
||||
public override List<GameObject> GetObjectsToCombine()
|
||||
{
|
||||
if (objsToMesh == null) objsToMesh = new List<GameObject>();
|
||||
if (objsToMesh.Count == 1 && objsToMesh[0] == null) objsToMesh.Clear();
|
||||
return objsToMesh;
|
||||
}
|
||||
|
||||
[ContextMenu("Purge Objects to Combine of null references")]
|
||||
public override void PurgeNullsFromObjectsToCombine()
|
||||
{
|
||||
if (objsToMesh == null)
|
||||
{
|
||||
objsToMesh = new List<GameObject>();
|
||||
}
|
||||
Debug.Log(string.Format("Purged {0} null references from objects to combine list.", objsToMesh.RemoveAll(obj => obj == null)));
|
||||
}
|
||||
|
||||
public MB_AtlasesAndRects[] CreateAtlases()
|
||||
{
|
||||
return CreateAtlases(null, false, null);
|
||||
}
|
||||
|
||||
public delegate void OnCombinedTexturesCoroutineSuccess();
|
||||
public delegate void OnCombinedTexturesCoroutineFail();
|
||||
public OnCombinedTexturesCoroutineSuccess onBuiltAtlasesSuccess;
|
||||
public OnCombinedTexturesCoroutineFail onBuiltAtlasesFail;
|
||||
public MB_AtlasesAndRects[] OnCombinedTexturesCoroutineAtlasesAndRects;
|
||||
|
||||
public IEnumerator CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
|
||||
{
|
||||
yield return _CreateAtlasesCoroutine(progressInfo, coroutineResult, saveAtlasesAsAssets, editorMethods, maxTimePerFrame);
|
||||
|
||||
if (coroutineResult.success && onBuiltAtlasesSuccess != null)
|
||||
{
|
||||
onBuiltAtlasesSuccess();
|
||||
}
|
||||
|
||||
if (!coroutineResult.success && onBuiltAtlasesFail != null)
|
||||
{
|
||||
onBuiltAtlasesFail();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator _CreateAtlasesCoroutineAtlases(MB3_TextureCombiner combiner, ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
|
||||
{
|
||||
int numResults = 1;
|
||||
if (_doMultiMaterial)
|
||||
{
|
||||
numResults = resultMaterials.Length;
|
||||
}
|
||||
|
||||
OnCombinedTexturesCoroutineAtlasesAndRects = new MB_AtlasesAndRects[numResults];
|
||||
for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
|
||||
{
|
||||
OnCombinedTexturesCoroutineAtlasesAndRects[i] = new MB_AtlasesAndRects();
|
||||
}
|
||||
|
||||
//Do the material combining.
|
||||
for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
|
||||
{
|
||||
Material resMatToPass = null;
|
||||
List<Material> sourceMats = null;
|
||||
if (_doMultiMaterial)
|
||||
{
|
||||
sourceMats = resultMaterials[i].sourceMaterials;
|
||||
resMatToPass = resultMaterials[i].combinedMaterial;
|
||||
combiner.fixOutOfBoundsUVs = resultMaterials[i].considerMeshUVs;
|
||||
}
|
||||
else
|
||||
{
|
||||
resMatToPass = _resultMaterial;
|
||||
}
|
||||
|
||||
MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult();
|
||||
yield return combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo, OnCombinedTexturesCoroutineAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, texturePropNamesToIgnore, editorMethods, coroutineResult2, maxTimePerFrame,
|
||||
onlyPackRects: false, splitAtlasWhenPackingIfTooBig: false);
|
||||
coroutineResult.success = coroutineResult2.success;
|
||||
if (!coroutineResult.success)
|
||||
{
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
unpackMat2RectMap(OnCombinedTexturesCoroutineAtlasesAndRects);
|
||||
if (coroutineResult.success && editorMethods != null) editorMethods.GetMaterialPrimaryKeysIfAddressables(textureBakeResults);
|
||||
//Save the results
|
||||
textureBakeResults.resultType = MB2_TextureBakeResults.ResultType.atlas;
|
||||
textureBakeResults.resultMaterialsTexArray = new MB_MultiMaterialTexArray[0];
|
||||
textureBakeResults.doMultiMaterial = _doMultiMaterial;
|
||||
if (_doMultiMaterial)
|
||||
{
|
||||
textureBakeResults.resultMaterials = resultMaterials;
|
||||
}
|
||||
else
|
||||
{
|
||||
MB_MultiMaterial[] resMats = new MB_MultiMaterial[1];
|
||||
resMats[0] = new MB_MultiMaterial();
|
||||
resMats[0].combinedMaterial = _resultMaterial;
|
||||
resMats[0].considerMeshUVs = _fixOutOfBoundsUVs;
|
||||
resMats[0].sourceMaterials = new List<Material>();
|
||||
for (int i = 0; i < textureBakeResults.materialsAndUVRects.Length; i++)
|
||||
{
|
||||
resMats[0].sourceMaterials.Add(textureBakeResults.materialsAndUVRects[i].material);
|
||||
}
|
||||
textureBakeResults.resultMaterials = resMats;
|
||||
}
|
||||
|
||||
if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Created Atlases");
|
||||
}
|
||||
|
||||
internal IEnumerator _CreateAtlasesCoroutineTextureArray(MB3_TextureCombiner combiner, ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
|
||||
{
|
||||
MB_TextureArrayResultMaterial[] bakedMatsAndSlices = null;
|
||||
|
||||
// Validate the formats
|
||||
if (textureArrayOutputFormats == null || textureArrayOutputFormats.Length == 0)
|
||||
{
|
||||
Debug.LogError("No Texture Array Output Formats. There must be at least one entry.");
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < textureArrayOutputFormats.Length; i++)
|
||||
{
|
||||
if (!textureArrayOutputFormats[i].ValidateTextureImporterFormatsExistsForTextureFormats(editorMethods, i))
|
||||
{
|
||||
Debug.LogError("Could not map the selected texture format to a Texture Importer Format. Safest options are ARGB32, or RGB24.");
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int resMatIdx = 0; resMatIdx < resultMaterialsTexArray.Length; resMatIdx++)
|
||||
{
|
||||
MB_MultiMaterialTexArray textureArraySliceConfig = resultMaterialsTexArray[resMatIdx];
|
||||
if (textureArraySliceConfig.combinedMaterial == null)
|
||||
{
|
||||
Debug.LogError("Material is null for Texture Array Slice Configuration: " + resMatIdx + ".");
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
|
||||
|
||||
List<MB_TexArraySlice> slices = textureArraySliceConfig.slices;
|
||||
for (int sliceIdx = 0; sliceIdx < slices.Count; sliceIdx++)
|
||||
{
|
||||
for (int srcMatIdx = 0; srcMatIdx < slices[sliceIdx].sourceMaterials.Count; srcMatIdx++)
|
||||
{
|
||||
MB_TexArraySliceRendererMatPair sourceMat = slices[sliceIdx].sourceMaterials[srcMatIdx];
|
||||
if (sourceMat.sourceMaterial == null)
|
||||
{
|
||||
Debug.LogError("Source material is null for Texture Array Slice Configuration: " + resMatIdx + " slice: " + sliceIdx);
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (slices[sliceIdx].considerMeshUVs)
|
||||
{
|
||||
if (sourceMat.renderer == null)
|
||||
{
|
||||
Debug.LogError("Renderer is null for Texture Array Slice Configuration: " + resMatIdx + " slice: " + sliceIdx + ". If considerUVs is enabled then a renderer must be supplied for each source material. The same source material can be used multiple times.");
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO check for duplicate source mats.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initialize structure to store results. For texture arrays the structure is two layers deep.
|
||||
// First layer is resultMaterial / submesh (each result material can use a different shader)
|
||||
// Second layer is a set of TextureArrays for the TextureProperties on that result material.
|
||||
int numResultMats = resultMaterialsTexArray.Length;
|
||||
bakedMatsAndSlices = new MB_TextureArrayResultMaterial[numResultMats];
|
||||
for (int resMatIdx = 0; resMatIdx < bakedMatsAndSlices.Length; resMatIdx++)
|
||||
{
|
||||
bakedMatsAndSlices[resMatIdx] = new MB_TextureArrayResultMaterial();
|
||||
int numSlices = resultMaterialsTexArray[resMatIdx].slices.Count;
|
||||
MB_AtlasesAndRects[] slices = bakedMatsAndSlices[resMatIdx].slices = new MB_AtlasesAndRects[numSlices];
|
||||
for (int j = 0; j < numSlices; j++) slices[j] = new MB_AtlasesAndRects();
|
||||
}
|
||||
|
||||
// Some of the slices will be atlases (more than one atlas per slice).
|
||||
// Do the material combining for these. First loop over the result materials (1 per submeshes).
|
||||
for (int resMatIdx = 0; resMatIdx < bakedMatsAndSlices.Length; resMatIdx++)
|
||||
{
|
||||
yield return MB_TextureArrays._CreateAtlasesCoroutineSingleResultMaterial(resMatIdx, bakedMatsAndSlices[resMatIdx], resultMaterialsTexArray[resMatIdx],
|
||||
objsToMesh,
|
||||
combiner,
|
||||
textureArrayOutputFormats,
|
||||
resultMaterialsTexArray,
|
||||
customShaderProperties,
|
||||
texturePropNamesToIgnore,
|
||||
progressInfo, coroutineResult, saveAtlasesAsAssets, editorMethods, maxTimePerFrame);
|
||||
if (!coroutineResult.success) yield break;
|
||||
}
|
||||
|
||||
if (coroutineResult.success)
|
||||
{
|
||||
// Save the results into the TextureBakeResults.
|
||||
unpackMat2RectMap(bakedMatsAndSlices);
|
||||
if (editorMethods != null) editorMethods.GetMaterialPrimaryKeysIfAddressables(textureBakeResults);
|
||||
textureBakeResults.resultType = MB2_TextureBakeResults.ResultType.textureArray;
|
||||
textureBakeResults.resultMaterials = new MB_MultiMaterial[0];
|
||||
textureBakeResults.resultMaterialsTexArray = resultMaterialsTexArray;
|
||||
if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Created Texture2DArrays");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Failed to create Texture2DArrays");
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator _CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
|
||||
{
|
||||
MBVersionConcrete mbv = new MBVersionConcrete();
|
||||
this.OnCombinedTexturesCoroutineAtlasesAndRects = null;
|
||||
|
||||
if (maxTimePerFrame <= 0f)
|
||||
{
|
||||
Debug.LogError("maxTimePerFrame must be a value greater than zero");
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;
|
||||
if (!DoCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, null, vl))
|
||||
{
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
if (_doMultiMaterial && !_ValidateResultMaterials())
|
||||
{
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
else if (resultType == MB2_TextureBakeResults.ResultType.textureArray)
|
||||
{
|
||||
//TODO validate texture arrays.
|
||||
}
|
||||
else if (!_doMultiMaterial)
|
||||
{
|
||||
if (_resultMaterial == null)
|
||||
{
|
||||
Debug.LogError("Combined Material is null please create and assign a result material.");
|
||||
coroutineResult.isFinished = true;
|
||||
yield break;
|
||||
}
|
||||
Shader targShader = _resultMaterial.shader;
|
||||
for (int i = 0; i < objsToMesh.Count; i++)
|
||||
{
|
||||
Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
|
||||
for (int j = 0; j < ms.Length; j++)
|
||||
{
|
||||
Material m = ms[j];
|
||||
if (m != null && m.shader != targShader)
|
||||
{
|
||||
Debug.LogWarning("Game object " + objsToMesh[i] + " does not use shader " + targShader + " it may not have the required textures. If not small solid color textures will be generated.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MB3_TextureCombiner combiner = CreateAndConfigureTextureCombiner();
|
||||
combiner.saveAtlasesAsAssets = saveAtlasesAsAssets;
|
||||
|
||||
OnCombinedTexturesCoroutineAtlasesAndRects = null;
|
||||
if (resultType == MB2_TextureBakeResults.ResultType.textureArray)
|
||||
{
|
||||
yield return _CreateAtlasesCoroutineTextureArray(combiner, progressInfo, coroutineResult, saveAtlasesAsAssets, editorMethods, maxTimePerFrame);
|
||||
if (!coroutineResult.success) yield break;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return _CreateAtlasesCoroutineAtlases(combiner, progressInfo, coroutineResult, saveAtlasesAsAssets, editorMethods, maxTimePerFrame);
|
||||
if (!coroutineResult.success) yield break;
|
||||
}
|
||||
|
||||
//set the texture bake resultAtlasesAndRects on the Mesh Baker component if it exists
|
||||
MB3_MeshBakerCommon[] mb = GetComponentsInChildren<MB3_MeshBakerCommon>();
|
||||
for (int i = 0; i < mb.Length; i++)
|
||||
{
|
||||
mb[i].textureBakeResults = textureBakeResults;
|
||||
}
|
||||
|
||||
coroutineResult.isFinished = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the atlases.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The atlases.
|
||||
/// </returns>
|
||||
/// <param name='progressInfo'>
|
||||
/// Progress info is a delegate function that displays a progress dialog. Can be null
|
||||
/// </param>
|
||||
/// <param name='saveAtlasesAsAssets'>
|
||||
/// if true atlases are saved as assets in the project folder. Othersise they are instances in memory
|
||||
/// </param>
|
||||
/// <param name='editorMethods'>
|
||||
/// Texture format tracker. Contains editor functionality such as save assets. Can be null.
|
||||
/// </param>
|
||||
public MB_AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null)
|
||||
{
|
||||
MB_AtlasesAndRects[] mAndAs = null;
|
||||
|
||||
try
|
||||
{
|
||||
_coroutineResult = new MB3_TextureCombiner.CreateAtlasesCoroutineResult();
|
||||
MB3_TextureCombiner.RunCorutineWithoutPause(CreateAtlasesCoroutine(progressInfo, _coroutineResult, saveAtlasesAsAssets, editorMethods, 1000f), 0);
|
||||
if (_coroutineResult.success && textureBakeResults != null)
|
||||
{
|
||||
mAndAs = this.OnCombinedTexturesCoroutineAtlasesAndRects;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (saveAtlasesAsAssets)
|
||||
{ //Atlases were saved to project so we don't need these ones
|
||||
if (mAndAs != null)
|
||||
{
|
||||
for (int j = 0; j < mAndAs.Length; j++)
|
||||
{
|
||||
MB_AtlasesAndRects mAndA = mAndAs[j];
|
||||
if (mAndA != null && mAndA.atlases != null)
|
||||
{
|
||||
for (int i = 0; i < mAndA.atlases.Length; i++)
|
||||
{
|
||||
if (mAndA.atlases[i] != null)
|
||||
{
|
||||
if (editorMethods != null) editorMethods.Destroy(mAndA.atlases[i]);
|
||||
else MB_Utility.Destroy(mAndA.atlases[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mAndAs;
|
||||
}
|
||||
|
||||
void unpackMat2RectMap(MB_AtlasesAndRects[] rawResults)
|
||||
{
|
||||
List<MB_MaterialAndUVRect> mss = new List<MB_MaterialAndUVRect>();
|
||||
for (int i = 0; i < rawResults.Length; i++)
|
||||
{
|
||||
List<MB_MaterialAndUVRect> map = rawResults[i].mat2rect_map;
|
||||
if (map != null)
|
||||
{
|
||||
for (int j = 0; j < map.Count; j++)
|
||||
{
|
||||
map[j].textureArraySliceIdx = -1;
|
||||
mss.Add(map[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textureBakeResults.version = MB2_TextureBakeResults.VERSION;
|
||||
textureBakeResults.materialsAndUVRects = mss.ToArray();
|
||||
}
|
||||
|
||||
internal void unpackMat2RectMap(MB_TextureArrayResultMaterial[] rawResults)
|
||||
{
|
||||
List<MB_MaterialAndUVRect> mss = new List<MB_MaterialAndUVRect>();
|
||||
for (int resMatIdx = 0; resMatIdx < rawResults.Length; resMatIdx++)
|
||||
{
|
||||
MB_AtlasesAndRects[] slices = rawResults[resMatIdx].slices;
|
||||
for (int sliceIdx = 0; sliceIdx < slices.Length; sliceIdx++)
|
||||
{
|
||||
List<MB_MaterialAndUVRect> map = slices[sliceIdx].mat2rect_map;
|
||||
if (map != null)
|
||||
{
|
||||
for (int rectIdx = 0; rectIdx < map.Count; rectIdx++)
|
||||
{
|
||||
map[rectIdx].textureArraySliceIdx = sliceIdx;
|
||||
mss.Add(map[rectIdx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textureBakeResults.version = MB2_TextureBakeResults.VERSION;
|
||||
textureBakeResults.materialsAndUVRects = mss.ToArray();
|
||||
}
|
||||
|
||||
public MB3_TextureCombiner CreateAndConfigureTextureCombiner()
|
||||
{
|
||||
MB3_TextureCombiner combiner = new MB3_TextureCombiner();
|
||||
combiner.LOG_LEVEL = LOG_LEVEL;
|
||||
combiner.atlasPadding = _atlasPadding;
|
||||
combiner.maxAtlasSize = _maxAtlasSize;
|
||||
combiner.maxAtlasHeightOverride = _maxAtlasHeightOverride;
|
||||
combiner.maxAtlasWidthOverride = _maxAtlasWidthOverride;
|
||||
combiner.useMaxAtlasHeightOverride = _useMaxAtlasHeightOverride;
|
||||
combiner.useMaxAtlasWidthOverride = _useMaxAtlasWidthOverride;
|
||||
combiner.customShaderPropNames = _customShaderProperties;
|
||||
combiner.fixOutOfBoundsUVs = _fixOutOfBoundsUVs;
|
||||
combiner.maxTilingBakeSize = _maxTilingBakeSize;
|
||||
combiner.packingAlgorithm = _packingAlgorithm;
|
||||
combiner.layerTexturePackerFastMesh = _layerTexturePackerFastMesh;
|
||||
combiner.resultType = _resultType;
|
||||
combiner.meshBakerTexturePackerForcePowerOfTwo = _meshBakerTexturePackerForcePowerOfTwo;
|
||||
combiner.resizePowerOfTwoTextures = _resizePowerOfTwoTextures;
|
||||
combiner.considerNonTextureProperties = _considerNonTextureProperties;
|
||||
return combiner;
|
||||
}
|
||||
|
||||
public static void ConfigureNewMaterialToMatchOld(Material newMat, Material original)
|
||||
{
|
||||
if (original == null)
|
||||
{
|
||||
Debug.LogWarning("Original material is null, could not copy properties to " + newMat + ". Setting shader to " + newMat.shader);
|
||||
return;
|
||||
}
|
||||
newMat.shader = original.shader;
|
||||
newMat.CopyPropertiesFromMaterial(original);
|
||||
ShaderTextureProperty[] texPropertyNames = MB3_TextureCombinerPipeline.shaderTexPropertyNames;
|
||||
for (int j = 0; j < texPropertyNames.Length; j++)
|
||||
{
|
||||
Vector2 scale = Vector2.one;
|
||||
Vector2 offset = Vector2.zero;
|
||||
if (newMat.HasProperty(texPropertyNames[j].name))
|
||||
{
|
||||
newMat.SetTextureOffset(texPropertyNames[j].name, offset);
|
||||
newMat.SetTextureScale(texPropertyNames[j].name, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string PrintSet(HashSet<Material> s)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (Material m in s)
|
||||
{
|
||||
sb.Append(m + ",");
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
bool _ValidateResultMaterials()
|
||||
{
|
||||
HashSet<Material> allMatsOnObjs = new HashSet<Material>();
|
||||
for (int i = 0; i < objsToMesh.Count; i++)
|
||||
{
|
||||
if (objsToMesh[i] != null)
|
||||
{
|
||||
Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
|
||||
for (int j = 0; j < ms.Length; j++)
|
||||
{
|
||||
if (ms[j] != null) allMatsOnObjs.Add(ms[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resultMaterials.Length < 1)
|
||||
{
|
||||
Debug.LogError("Using multiple materials but there are no 'Source Material To Combined Mappings'. You need at least one.");
|
||||
}
|
||||
|
||||
HashSet<Material> allMatsInMapping = new HashSet<Material>();
|
||||
for (int i = 0; i < resultMaterials.Length; i++)
|
||||
{
|
||||
for (int j = i + 1; j < resultMaterials.Length; j++)
|
||||
{
|
||||
if (resultMaterials[i].combinedMaterial == resultMaterials[j].combinedMaterial)
|
||||
{
|
||||
Debug.LogError(String.Format("Source To Combined Mapping: Submesh {0} and Submesh {1} use the same combined material. These should be different", i, j));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MB_MultiMaterial mm = resultMaterials[i];
|
||||
if (mm.combinedMaterial == null)
|
||||
{
|
||||
Debug.LogError("Combined Material is null please create and assign a result material.");
|
||||
return false;
|
||||
}
|
||||
Shader targShader = mm.combinedMaterial.shader;
|
||||
for (int j = 0; j < mm.sourceMaterials.Count; j++)
|
||||
{
|
||||
if (mm.sourceMaterials[j] == null)
|
||||
{
|
||||
Debug.LogError("There are null entries in the list of Source Materials");
|
||||
return false;
|
||||
}
|
||||
if (targShader != mm.sourceMaterials[j].shader)
|
||||
{
|
||||
Debug.LogWarning("Source material " + mm.sourceMaterials[j] + " does not use shader " + targShader + " it may not have the required textures. If not empty textures will be generated.");
|
||||
}
|
||||
if (allMatsInMapping.Contains(mm.sourceMaterials[j]))
|
||||
{
|
||||
Debug.LogError("A Material " + mm.sourceMaterials[j] + " appears more than once in the list of source materials in the source material to combined mapping. Each source material must be unique.");
|
||||
return false;
|
||||
}
|
||||
allMatsInMapping.Add(mm.sourceMaterials[j]);
|
||||
}
|
||||
}
|
||||
|
||||
if (allMatsOnObjs.IsProperSubsetOf(allMatsInMapping))
|
||||
{
|
||||
allMatsInMapping.ExceptWith(allMatsOnObjs);
|
||||
Debug.LogWarning("There are materials in the mapping that are not used on your source objects: " + PrintSet(allMatsInMapping));
|
||||
}
|
||||
if (resultMaterials != null && resultMaterials.Length > 0 && allMatsInMapping.IsProperSubsetOf(allMatsOnObjs))
|
||||
{
|
||||
allMatsOnObjs.ExceptWith(allMatsInMapping);
|
||||
Debug.LogError("There are materials on the objects to combine that are not in the mapping: " + PrintSet(allMatsOnObjs));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 077f80fe3940dc7468ecec90989abe66
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MB3_TextureBaker.cs
|
||||
uploadId: 797180
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "MeshBakerCore",
|
||||
"references": [
|
||||
"GUID:65d6e1e69ebbde8418716e338cd47019"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f877850438bd15c46b9c80ce60930133
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 31895
|
||||
packageName: Mesh Baker Free
|
||||
packageVersion: 3.40.1
|
||||
assetPath: Assets/MeshBaker/scripts/MeshBakerCore.asmdef
|
||||
uploadId: 797180
|
||||
Reference in New Issue
Block a user