修改脚本
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
@@ -46,8 +46,12 @@ namespace CC
|
||||
//Async loading
|
||||
private Coroutine activeCoroutine;
|
||||
|
||||
//Store character LOD size for hair/apparel bounds
|
||||
//Store character LOD for hair/apparel bounds
|
||||
private float mainLODSize;
|
||||
private LODGroup mainLODGroup;
|
||||
|
||||
//Main mesh bones
|
||||
private Dictionary<string, Transform> mainMeshBoneMap;
|
||||
|
||||
#region Initialize script
|
||||
|
||||
@@ -69,8 +73,6 @@ namespace CC
|
||||
CC_UI_Manager.instance.onDrag += OnPartDragged;
|
||||
}
|
||||
|
||||
mainLODSize = GetComponent<LODGroup>() == null ? 1.5f : GetComponentInChildren<LODGroup>().size;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
@@ -115,11 +117,17 @@ namespace CC
|
||||
//Initializes this script - run on Start by default but you can run it whenever, see InstantiateCharacter for example
|
||||
public void Initialize()
|
||||
{
|
||||
//Delete cosmetic prefabs
|
||||
foreach (var toDelete in GetComponentsInChildren<DeleteOnStart>())
|
||||
{
|
||||
Destroy(toDelete.gameObject);
|
||||
}
|
||||
|
||||
//Get main mesh LOD size and bone hierarchy
|
||||
mainLODGroup = GetComponent<LODGroup>();
|
||||
mainLODSize = mainLODGroup == null ? 1.5f : mainLODGroup.size;
|
||||
if (MainMesh != null) mainMeshBoneMap = MainMesh.rootBone.GetComponentsInChildren<Transform>(true).ToDictionary(t => t.name, t => t);
|
||||
|
||||
foreach (var mesh in GetComponentsInChildren<SkinnedMeshRenderer>())
|
||||
{
|
||||
//Add a blendshape manager script to every mesh
|
||||
@@ -234,57 +242,6 @@ namespace CC
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveToPrefab()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
//Clone character data
|
||||
string characterDataJSON = JsonUtility.ToJson(StoredCharacterData, true);
|
||||
var characterDataCopy = JsonUtility.FromJson<CC_CharacterData>(characterDataJSON);
|
||||
|
||||
//Load original prefab to duplicate
|
||||
var ogPrefab = Resources.Load(StoredCharacterData.CharacterPrefab);
|
||||
if (ogPrefab == null) throw new System.Exception("Prefab not assigned in character data");
|
||||
var newPrefab = (GameObject)PrefabUtility.InstantiatePrefab(ogPrefab);
|
||||
|
||||
//Delete character in JSON file
|
||||
if (File.Exists(SavePath))
|
||||
{
|
||||
//Load CC_SaveData from JSON file
|
||||
string jsonLoad = File.ReadAllText(SavePath);
|
||||
var CC_SaveData = JsonUtility.FromJson<CC_SaveData>(jsonLoad);
|
||||
int index = CC_SaveData.SavedCharacters.FindIndex(t => t.CharacterName == StoredCharacterData.CharacterName);
|
||||
if (index != -1)
|
||||
{
|
||||
CC_SaveData.SavedCharacters.RemoveAt(index);
|
||||
string jsonSave = JsonUtility.ToJson(CC_SaveData, true);
|
||||
File.WriteAllText(SavePath, jsonSave);
|
||||
}
|
||||
}
|
||||
|
||||
//Update name and prefab
|
||||
string prefabSuffix = "_" + CharacterName;
|
||||
characterDataCopy.CharacterName = CharacterName;
|
||||
|
||||
//Create new prefab
|
||||
string prefabPath = AssetDatabase.GetAssetPath(ogPrefab);
|
||||
string newPath = prefabPath.Replace(".prefab", prefabSuffix + ".prefab");
|
||||
newPrefab.GetComponent<CharacterCustomization>().CharacterName = CharacterName;
|
||||
newPrefab.GetComponent<CharacterCustomization>().Autoload = true;
|
||||
PrefabUtility.SaveAsPrefabAsset(newPrefab, newPath);
|
||||
|
||||
//Overwrite or add new preset
|
||||
int presetIndex = Presets.Presets.FindIndex(t => t.CharacterName == characterDataCopy.CharacterName);
|
||||
if (presetIndex != -1)
|
||||
{
|
||||
Presets.Presets[presetIndex] = characterDataCopy;
|
||||
}
|
||||
else Presets.Presets.Add(characterDataCopy);
|
||||
|
||||
DestroyImmediate(newPrefab);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SaveToPreset(string presetName)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
@@ -533,14 +490,18 @@ namespace CC
|
||||
|
||||
public void setHair(int selection, int slot)
|
||||
{
|
||||
if (slot >= HairTables.Count) Debug.LogError("Tried to set hair from non-existing hair table");
|
||||
if (slot >= HairTables.Count) Debug.LogError("Tried to set hair from non-existing hair table, index: " + slot);
|
||||
|
||||
if (HairTables[slot].Hairstyles.Count > selection)
|
||||
{
|
||||
scrObj_Hair.Hairstyle HairData = HairTables[slot].Hairstyles[selection];
|
||||
|
||||
//Destroy active GameObject
|
||||
if (HairObjects[slot] != null) Destroy(HairObjects[slot]);
|
||||
if (HairObjects[slot] != null)
|
||||
{
|
||||
removeFromLODGroup(HairObjects[slot].GetComponentsInChildren<Renderer>());
|
||||
Destroy(HairObjects[slot]);
|
||||
}
|
||||
|
||||
//Set mesh if valid
|
||||
if (HairTables[slot].Hairstyles[selection].Mesh != null)
|
||||
@@ -560,40 +521,8 @@ namespace CC
|
||||
}
|
||||
}
|
||||
|
||||
//Add CopyPose script
|
||||
if (HairData.AddCopyPoseScript)
|
||||
{
|
||||
HairObject.AddComponent<CopyPose>();
|
||||
}
|
||||
//Otherwise assume hierarchy is the same
|
||||
else
|
||||
{
|
||||
foreach (var mesh in HairObject.GetComponentsInChildren<SkinnedMeshRenderer>())
|
||||
{
|
||||
var mainMeshTransforms = MainMesh.rootBone.GetComponentsInChildren<Transform>();
|
||||
var mainMeshBoneMap = mainMeshTransforms.ToDictionary(t => t.name, t => t);
|
||||
|
||||
var mainMeshBones = new Transform[mesh.bones.Length];
|
||||
var oldMeshRoot = mesh.rootBone;
|
||||
|
||||
//Map old bones to new bones
|
||||
for (var i = 0; i < mesh.bones.Length; i++)
|
||||
{
|
||||
if (mesh.bones[i] == null) continue;
|
||||
mainMeshBoneMap.TryGetValue(mesh.bones[i].name, out mainMeshBones[i]);
|
||||
}
|
||||
|
||||
//Clean up old root and reassign properties
|
||||
Destroy(oldMeshRoot.gameObject);
|
||||
mesh.bones = mainMeshBones;
|
||||
mesh.rootBone = MainMesh.rootBone;
|
||||
mesh.localBounds = MainMesh.localBounds;
|
||||
}
|
||||
|
||||
//Recalculate bounds
|
||||
var lodGroup = HairObject.GetComponentInChildren<LODGroup>();
|
||||
if (lodGroup != null) { lodGroup.RecalculateBounds(); lodGroup.size = mainLODSize; }
|
||||
}
|
||||
//Copy character bones to hair mesh
|
||||
copyBones(HairObject, HairData.AddCopyPoseScript);
|
||||
}
|
||||
|
||||
//Set shadow map
|
||||
@@ -640,7 +569,7 @@ namespace CC
|
||||
{
|
||||
if (slot >= ApparelTables.Count)
|
||||
{
|
||||
Debug.LogError("Tried to set apparel from non-existing apparel table");
|
||||
Debug.LogError("Tried to set apparel from non-existing apparel table: " + slot);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -712,7 +641,11 @@ namespace CC
|
||||
#endregion Handle conflicting slots
|
||||
|
||||
//Destroy active GameObject
|
||||
if (ApparelObjects[slot] != null) Destroy(ApparelObjects[slot]);
|
||||
if (ApparelObjects[slot] != null)
|
||||
{
|
||||
removeFromLODGroup(ApparelObjects[slot].GetComponentsInChildren<Renderer>());
|
||||
Destroy(ApparelObjects[slot]);
|
||||
}
|
||||
|
||||
//Set mesh if valid
|
||||
if (ApparelTables[slot].Items[selection].Mesh != null)
|
||||
@@ -757,40 +690,8 @@ namespace CC
|
||||
mesh.materials = baseMaterials;
|
||||
}
|
||||
|
||||
//Add CopyPose script
|
||||
if (ApparelData.AddCopyPoseScript)
|
||||
{
|
||||
ApparelObject.AddComponent<CopyPose>();
|
||||
}
|
||||
//Otherwise assume hierarchy is the same
|
||||
else
|
||||
{
|
||||
foreach (var mesh in ApparelObject.GetComponentsInChildren<SkinnedMeshRenderer>())
|
||||
{
|
||||
var mainMeshTransforms = MainMesh.rootBone.GetComponentsInChildren<Transform>();
|
||||
var mainMeshBoneMap = mainMeshTransforms.ToDictionary(t => t.name, t => t);
|
||||
|
||||
var mainMeshBones = new Transform[mesh.bones.Length];
|
||||
var oldMeshRoot = mesh.rootBone;
|
||||
|
||||
//Map old bones to new bones
|
||||
for (var i = 0; i < mesh.bones.Length; i++)
|
||||
{
|
||||
if (mesh.bones[i] == null) continue;
|
||||
mainMeshBoneMap.TryGetValue(mesh.bones[i].name, out mainMeshBones[i]);
|
||||
}
|
||||
|
||||
//Clean up old root and reassign properties
|
||||
Destroy(oldMeshRoot.gameObject);
|
||||
mesh.bones = mainMeshBones;
|
||||
mesh.rootBone = MainMesh.rootBone;
|
||||
mesh.localBounds = MainMesh.localBounds;
|
||||
}
|
||||
|
||||
//Recalculate bounds
|
||||
var lodGroup = ApparelObject.GetComponentInChildren<LODGroup>();
|
||||
if (lodGroup != null) { lodGroup.RecalculateBounds(); lodGroup.size = mainLODSize; }
|
||||
}
|
||||
//Copy character bones to apparel mesh
|
||||
copyBones(ApparelObject, ApparelData.AddCopyPoseScript);
|
||||
}
|
||||
|
||||
//Set foot offset
|
||||
@@ -855,6 +756,101 @@ namespace CC
|
||||
}
|
||||
}
|
||||
|
||||
private void copyBones(GameObject GO, bool addCopyPoseScript)
|
||||
{
|
||||
var meshes = GO.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
|
||||
//Add CopyPose script or reassign bones
|
||||
if (addCopyPoseScript)
|
||||
{
|
||||
GO.AddComponent<CopyPose>().ParseBones(mainMeshBoneMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var mesh in meshes)
|
||||
{
|
||||
var mainMeshBones = new Transform[mesh.bones.Length];
|
||||
var oldMeshRoot = mesh.rootBone;
|
||||
|
||||
for (var i = 0; i < mesh.bones.Length; i++)
|
||||
mainMeshBoneMap.TryGetValue(mesh.bones[i].name, out mainMeshBones[i]);
|
||||
|
||||
Destroy(oldMeshRoot.gameObject);
|
||||
mesh.bones = mainMeshBones;
|
||||
mesh.rootBone = MainMesh.rootBone;
|
||||
}
|
||||
}
|
||||
|
||||
//Recalculate bounds
|
||||
foreach (var mesh in meshes)
|
||||
mesh.localBounds = MainMesh.localBounds;
|
||||
|
||||
//Merge LODs
|
||||
var childLODGroup = GO.GetComponentInChildren<LODGroup>();
|
||||
if (mainLODGroup != null && childLODGroup != null)
|
||||
{
|
||||
var mainLODs = mainLODGroup.GetLODs();
|
||||
var childLODs = childLODGroup.GetLODs();
|
||||
|
||||
//Temporarily store renderers before destroying child LODGroup
|
||||
var childRenderersPerLOD = childLODs.Select(lod => lod.renderers).ToList();
|
||||
|
||||
//Destroy the child LODGroup
|
||||
DestroyImmediate(childLODGroup);
|
||||
|
||||
//Determine the maximum LOD count
|
||||
int maxLodCount = Mathf.Max(mainLODs.Length, childRenderersPerLOD.Count);
|
||||
LOD[] mergedLODs = new LOD[maxLodCount];
|
||||
|
||||
for (int i = 0; i < maxLodCount; i++)
|
||||
{
|
||||
Renderer[] combinedRenderers;
|
||||
float screenRelativeHeight;
|
||||
|
||||
if (i < mainLODs.Length && i < childRenderersPerLOD.Count)
|
||||
{
|
||||
//Both have this LOD level - merge renderers, keep main's distance
|
||||
combinedRenderers = mainLODs[i].renderers.Where(r => r).Concat(childRenderersPerLOD[i]).ToArray();
|
||||
screenRelativeHeight = mainLODs[i].screenRelativeTransitionHeight;
|
||||
}
|
||||
else if (i < mainLODs.Length)
|
||||
{
|
||||
//Only main has this LOD level
|
||||
combinedRenderers = mainLODs[i].renderers.Where(r => r).ToArray();
|
||||
screenRelativeHeight = mainLODs[i].screenRelativeTransitionHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Only child has this LOD level - use child's distance
|
||||
combinedRenderers = childRenderersPerLOD[i];
|
||||
screenRelativeHeight = childLODs[i].screenRelativeTransitionHeight;
|
||||
}
|
||||
|
||||
mergedLODs[i] = new LOD(screenRelativeHeight, combinedRenderers);
|
||||
}
|
||||
|
||||
//Apply and update
|
||||
mainLODGroup.SetLODs(mergedLODs);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeFromLODGroup(IEnumerable<Renderer> renderersToRemove)
|
||||
{
|
||||
if (mainLODGroup == null || renderersToRemove == null) return;
|
||||
|
||||
//Get current LODs
|
||||
var lods = mainLODGroup.GetLODs();
|
||||
|
||||
//Remove renderers
|
||||
for (int i = 0; i < lods.Length; i++)
|
||||
{
|
||||
lods[i].renderers = lods[i].renderers.Except(renderersToRemove).ToArray();
|
||||
}
|
||||
|
||||
mainLODGroup.SetLODs(lods);
|
||||
}
|
||||
|
||||
|
||||
public void randomizeAll()
|
||||
{
|
||||
if (Randomizer == null) return;
|
||||
@@ -906,6 +902,7 @@ namespace CC
|
||||
|
||||
public List<Material> getRelevantMaterials(int materialIndex, string meshTag)
|
||||
{
|
||||
//Get meshes by tag if desired, otherwise get all meshes
|
||||
IEnumerable<Renderer> meshes = string.IsNullOrEmpty(meshTag)
|
||||
? gameObject.GetComponentsInChildren<Renderer>()
|
||||
: getMeshByTag(meshTag);
|
||||
@@ -924,7 +921,7 @@ namespace CC
|
||||
}
|
||||
else
|
||||
{
|
||||
//Add all materials
|
||||
//Otherwise add all materials
|
||||
materials.AddRange(mesh.materials);
|
||||
}
|
||||
}
|
||||
@@ -940,14 +937,17 @@ namespace CC
|
||||
//Set texture property
|
||||
public void setTextureProperty(CC_Property p, bool save = false, Texture2D t = null)
|
||||
{
|
||||
if (t != null) p.stringValue = t.name;
|
||||
//Get relevant materials and set texture
|
||||
foreach (var material in getRelevantMaterials(p.materialIndex, p.meshTag))
|
||||
{
|
||||
if (material.HasProperty(p.propertyName)) material.SetTexture(p.propertyName, (t != null) ? t : Resources.Load<Texture2D>(p.stringValue));
|
||||
}
|
||||
|
||||
if (save) saveProperty(ref StoredCharacterData.TextureProperties, p);
|
||||
if (save)
|
||||
{
|
||||
if (t != null) p.stringValue = t.name; //Store string value if saving
|
||||
saveProperty(ref StoredCharacterData.TextureProperties, p);
|
||||
}
|
||||
}
|
||||
|
||||
//Set float property
|
||||
@@ -976,6 +976,7 @@ namespace CC
|
||||
|
||||
public bool findProperty(List<CC_Property> properties, CC_Property p, out CC_Property pOut, out int index)
|
||||
{
|
||||
//Properties are "equal" if property name, material index and mesh tag are identical
|
||||
int i = properties.FindIndex(t => t.propertyName == p.propertyName && t.materialIndex == p.materialIndex && t.meshTag == p.meshTag);
|
||||
if (i >= 0)
|
||||
{
|
||||
|
||||
@@ -6,43 +6,31 @@ namespace CC
|
||||
{
|
||||
public class CopyPose : MonoBehaviour
|
||||
{
|
||||
private Transform[] SourceHierarchy;
|
||||
private Transform[] TargetHierarchy;
|
||||
public List<Transform> SourceBones = new List<Transform>();
|
||||
public List<Transform> TargetBones = new List<Transform>();
|
||||
|
||||
private void Start()
|
||||
public void ParseBones(Dictionary<string, Transform> mainMeshBoneMap)
|
||||
{
|
||||
//Get meshes
|
||||
var mainScript = GetComponentInParent<CharacterCustomization>();
|
||||
var sourceMesh = mainScript.MainMesh;
|
||||
var targetMeshes = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
var targetHierarchy = GetRootBone(GetComponentInChildren<SkinnedMeshRenderer>().rootBone).GetComponentsInChildren<Transform>();
|
||||
|
||||
//Copy bounds from character
|
||||
var LODGroup = GetComponentInChildren<LODGroup>();
|
||||
var mainLODGroup = mainScript.GetComponent<LODGroup>();
|
||||
if (LODGroup != null) { LODGroup.RecalculateBounds(); LODGroup.size = (mainLODGroup == null) ? 1.5f : mainLODGroup.size; }
|
||||
var targetBonesDict = targetHierarchy.ToDictionary(t => t.name, t => t);
|
||||
|
||||
foreach (var mesh in targetMeshes)
|
||||
foreach (var (boneName, sourceBone) in mainMeshBoneMap)
|
||||
{
|
||||
mesh.localBounds = sourceMesh.localBounds;
|
||||
if (!targetBonesDict.TryGetValue(boneName, out var targetBone)) continue;
|
||||
|
||||
//Re-parent & reset local transform
|
||||
targetBone.SetParent(sourceBone);
|
||||
targetBone.localPosition = Vector3.zero;
|
||||
targetBone.localRotation = Quaternion.identity;
|
||||
targetBone.localScale = Vector3.one;
|
||||
|
||||
if (!TargetBones.Contains(targetBone)) TargetBones.Add(targetBone);
|
||||
}
|
||||
|
||||
//Get bone hierarchies
|
||||
SourceHierarchy = sourceMesh.rootBone.GetComponentsInChildren<Transform>();
|
||||
TargetHierarchy = GetRootBone(targetMeshes[0].rootBone).GetComponentsInChildren<Transform>();
|
||||
|
||||
var targetBonesDict = TargetHierarchy.ToDictionary(t => t.name, t => t);
|
||||
|
||||
//Only copy bones that are found in both hierarchies, also ensures order is the same
|
||||
foreach (Transform child in SourceHierarchy)
|
||||
//Rename bones to avoid duplicate object names
|
||||
foreach (var bone in targetHierarchy)
|
||||
{
|
||||
//Check if a bone with the same name exists in the target hierarchy using the dictionary
|
||||
if (targetBonesDict.TryGetValue(child.name, out var targetBone))
|
||||
{
|
||||
SourceBones.Add(child);
|
||||
TargetBones.Add(targetBone);
|
||||
}
|
||||
bone.name += "_" + GetInstanceID();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +40,16 @@ namespace CC
|
||||
return GetRootBone(bone.parent);
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
private void OnDestroy()
|
||||
{
|
||||
//Copy bone transform
|
||||
for (int i = 0; i < SourceBones.Count; i++)
|
||||
if (TargetBones == null) return;
|
||||
|
||||
foreach (Transform t in TargetBones)
|
||||
{
|
||||
TargetBones[i].localPosition = SourceBones[i].localPosition;
|
||||
TargetBones[i].localRotation = SourceBones[i].localRotation;
|
||||
TargetBones[i].localScale = SourceBones[i].localScale;
|
||||
if (t != null)
|
||||
{
|
||||
Destroy(t.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace CC
|
||||
public class HeadColliders : MonoBehaviour
|
||||
{
|
||||
public List<ColliderSetup> colliders = new List<ColliderSetup>();
|
||||
public List<GameObject> colliderObjects = new List<GameObject>();
|
||||
|
||||
public void createColliders()
|
||||
{
|
||||
@@ -23,8 +24,8 @@ namespace CC
|
||||
|
||||
private void CreateColliderObject(Vector3 localPosition, string label)
|
||||
{
|
||||
GameObject colliderObject = new GameObject(label);
|
||||
//colliderObject.layer = LayerMask.NameToLayer("UI");
|
||||
GameObject colliderObject = new(label);
|
||||
colliderObjects.Add(colliderObject);
|
||||
|
||||
colliderObject.transform.SetParent(transform);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace CC
|
||||
public class PhysicsManager : MonoBehaviour
|
||||
{
|
||||
public Animator animator;
|
||||
public CapsuleCollider capsule;
|
||||
private Rigidbody[] rigidBodies;
|
||||
private Collider[] colliders;
|
||||
private ModifyBone[] modifyBones;
|
||||
@@ -20,7 +19,6 @@ namespace CC
|
||||
private void Awake()
|
||||
{
|
||||
if (animator == null) animator = gameObject.GetComponent<Animator>();
|
||||
if (capsule == null) capsule = gameObject.GetComponent<CapsuleCollider>();
|
||||
rigidBodies = gameObject.GetComponentsInChildren<Rigidbody>();
|
||||
colliders = gameObject.GetComponentsInChildren<Collider>();
|
||||
modifyBones = gameObject.GetComponentsInChildren<ModifyBone>();
|
||||
@@ -36,7 +34,6 @@ namespace CC
|
||||
//Disable colliders if not in customization mode
|
||||
foreach (var item in colliders)
|
||||
{
|
||||
if (item == capsule) continue; //Ignore capsule
|
||||
item.enabled = customizing;
|
||||
}
|
||||
}
|
||||
@@ -61,9 +58,6 @@ namespace CC
|
||||
item.enabled = true;
|
||||
}
|
||||
|
||||
//Disable capsule when customizing
|
||||
if (capsule != null) capsule.enabled = false;
|
||||
|
||||
customizing = true;
|
||||
}
|
||||
|
||||
@@ -85,9 +79,6 @@ namespace CC
|
||||
|
||||
if (ragdolling) yield return new WaitForFixedUpdate();
|
||||
|
||||
//Disable capsule when ragdolling or customizing
|
||||
if (capsule != null) capsule.enabled = !ragdolling;
|
||||
|
||||
//Enable physics
|
||||
foreach (var item in rigidBodies)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user