using System.Collections.Generic; using Unity.Collections; using UnityEngine; using System.IO; using UnityEngine.SceneManagement; #if UNITY_EDITOR using UnityEditor; #endif namespace UMA { public class SimpleDecal : MonoBehaviour, IUMAEventHookup { // These need to be set by the editor. // **************************************************************************** public int[] boneHashes; // hash of bone names public string[] boneNames; // the names of the bones. public byte[] bonesPerVertex; // 1 per vertex public BoneWeight1[] capturedBoneWeights; // weight / boneIndex // **************************************************************************** public BoneWeight1[] finalBoneWeights = new BoneWeight1[0]; // weight / boneIndex private Dictionary NameToBone = new Dictionary(); Vector3[] translated = new Vector3[0]; public UMAMeshData meshData; public Vector3 Offset = Vector3.zero; public Vector3 Rotation = Vector3.zero; // public Quaternion Orientation = Quaternion.identity; // temp private GameObject vmarker; private GameObject sceneRoot; private Scene editorScene; private Vector3 InitialSpot; public void Configure(string[] _boneNames, int[] _boneHashes, byte[] _bonesPerVertex, BoneWeight1[] _boneWeights) { // this boneHashes = _boneHashes; boneNames = _boneNames; capturedBoneWeights = _boneWeights; bonesPerVertex = _bonesPerVertex; } #if UNITY_EDITOR public void SaveDecal(string Name, string newAssetPath, bool addToLibrary, SkinnedMeshRenderer smr, DecalDefinition decal,GameObject marker1, Scene editScene,GameObject Root) { if (newAssetPath.StartsWith(Application.dataPath)) { newAssetPath = "Assets"+ newAssetPath.Substring(Application.dataPath.Length); } string meshPath = Path.Combine(newAssetPath, Name + "_Mesh.asset"); string prefabPath = Path.Combine(newAssetPath, Name+".prefab"); string slotPath = Path.Combine(newAssetPath, Name + ".asset"); /* MeshFilter mf = decal.GetComponent(); AssetDatabase.CreateAsset(mf.mesh, meshPath ); AssetDatabase.SaveAssets(); */ InitialSpot = decal.WorldImpactPoint; vmarker = marker1; editScene = editorScene; sceneRoot = Root; meshData = new UMAMeshData(); #if USE_TestMesh MeshFilter mf = this.gameObject.GetComponent(); meshData.RetrieveDataFromUnityMesh(mf.sharedMesh); // local to world (object) // world to local (root) Matrix4x4 mat = new Matrix4x4(); Transform root = smr.rootBone; if (root == null) { foreach(Transform t in smr.transform.parent) { if (t.name.ToLower() == "root") { root = t; break; } } } if (root == null) { foreach (Transform t in smr.transform.parent) { if (t.gameObject.GetComponent() == null) { // Maybe it's this one? if (t.childCount > 0) { root = t; break; } } } } if (root == null) { mat.SetTRS(Vector3.zero, Quaternion.identity, Vector3.one); } else { mat.SetTRS(Vector3.zero, root.localRotation, Vector3.one); } /* for(int i=0;i(slotPath, false, Name); sda.slotName = Name; sda.SlotObject = prefab; /* mf = prefab.GetComponent(); mf.mesh = AssetDatabase.LoadAssetAtPath(meshPath); SkinnedMeshRenderer smr = prefab.GetComponent(); smr.sharedMesh = mf.mesh; */ EditorUtility.SetDirty(sda); AssetDatabase.SaveAssets(); if (addToLibrary) { UMAAssetIndexer.Instance.AddAsset(typeof(SlotDataAsset),Name, slotPath, sda); EditorUtility.DisplayDialog("UMA", "Decal Created and added to library", "OK"); } else { EditorUtility.DisplayDialog("UMA", "Decal Created. Don't forget to add it to the library", "OK"); } } private Vector2 GetUV(Plane[] planesinWS,Vector3 vertinWS) { Plane u0 = planesinWS[0]; Plane u1 = planesinWS[1]; Plane v0 = planesinWS[2]; Plane v1 = planesinWS[3]; float ud0 = u0.GetDistanceToPoint(vertinWS); float ud1 = u1.GetDistanceToPoint(vertinWS); float vd0 = v0.GetDistanceToPoint(vertinWS); float vd1 = v1.GetDistanceToPoint(vertinWS); float U_One = Mathf.Abs((u0.ClosestPointOnPlane(vertinWS) - u1.ClosestPointOnPlane(vertinWS)).magnitude); float V_One = Mathf.Abs((v0.ClosestPointOnPlane(vertinWS) - v1.ClosestPointOnPlane(vertinWS)).magnitude); return new Vector2(ud0 / U_One, vd0 / V_One); } /// /// planes needs to be in worldspace!!!!! /// /// /// /// /// private void ProjectUV(UMAMeshData meshData, Mesh bakedMesh, Plane[] planes, SkinnedMeshRenderer smr) { Matrix4x4 mat = smr.gameObject.transform.localToWorldMatrix; NativeArray tris = meshData.submeshes[0].GetTriangles(); for (int tri = 0; tri < tris.Length; tri+=3) { int v0index = tris[tri]; int v1index = tris[tri+1]; int v2index = tris[tri+2]; Vector3 v0 = mat * meshData.vertices[v0index]; Vector3 v1 = mat * meshData.vertices[v1index]; Vector3 v2 = mat * meshData.vertices[v2index]; Vector2 uv0 = GetUV(planes, v0); Vector2 uv1 = GetUV(planes, v1); Vector2 uv2 = GetUV(planes, v2); meshData.uv[v0index] = uv0; meshData.uv[v1index] = uv1; meshData.uv[v2index] = uv2; } } private bool PlanesContains(Plane[] planes,Vector3 vert) { foreach(Plane p in planes) { float dist = p.GetDistanceToPoint(vert); if (dist < 0.0f) { return false; } } return true; } private int[] AccumulateTriangles(Mesh bakedMesh, Plane[] planes, SkinnedMeshRenderer smr,Vector3 worldPoint) { //List insideVertexes = new List(); HashSet insideVertexes = new HashSet(); List newTriangles = new List(); /* Vector3 VertMax = new Vector3(); for(int i=0;i VertMax.y) { VertMax = vert; } if (PlanesContains(planes,vert)) { insideVertexes.Add(i); } } GameObject.Instantiate(vmarker, VertMax, Quaternion.identity,sceneRoot.transform); */ for (int i=0;i HashToPosition = new Dictionary(); SkinnedMeshRenderer renderer = umaData.GetRenderer(0); // No new bones added if (boneHashes.Length == renderer.bones.Length) { finalBoneWeights = new BoneWeight1[0]; return; } // build translation table if needed // if (NameToBone.Count != renderer.bones.Length) // { NameToBone.Clear(); for (int i = 0; i < renderer.bones.Length; i++) { Transform t = renderer.bones[i]; NameToBone.Add(UMAUtils.StringToHash(t.name), i); } // } // new bones added... need to translate finalBoneWeights = new BoneWeight1[capturedBoneWeights.Length]; for (int i = 0; i < capturedBoneWeights.Length; i++) { BoneWeight1 oldbw = capturedBoneWeights[i]; int Hash = capturedBoneWeights[i].boneIndex; if (umaData.skeleton.boneHashData.ContainsKey(Hash)) { var boneData = umaData.skeleton.boneHashData[Hash]; if (NameToBone.ContainsKey(boneData.boneNameHash)) { finalBoneWeights[i].boneIndex = NameToBone[boneData.boneNameHash]; finalBoneWeights[i].weight = capturedBoneWeights[i].weight; //Debug.Log($"UMA Bone Found with hash {boneData.boneNameHash} name {boneData.boneTransform.name}"); } else { Debug.LogError($"UMA Bone not found with hash {boneData.boneNameHash} name {boneData.boneTransform.name}"); } } else { Debug.LogError($"Decal bone not found with hash {Hash}"); } /* int Hash = boneHashes[boneWeights[i].boneIndex]; int Hash = capturedBoneWeights[i].boneIndex; if (umaData.skeleton.boneHashData.ContainsKey(Hash)) { var boneData = umaData.skeleton.boneHashData[Hash]; if (NameToBone.ContainsKey(boneData.boneNameHash)) { finalBoneWeights[i].boneIndex = NameToBone[boneData.boneNameHash]; finalBoneWeights[i].weight = capturedBoneWeights[i].weight; Debug.Log($"UMA Bone Found with hash {boneData.boneNameHash} name {boneData.boneTransform.name}"); } else { Debug.LogError($"UMA Bone not found with hash {boneData.boneNameHash} name {boneData.boneTransform.name}"); } } else { Debug.LogError($"Decal bone not found with hash {Hash}"); } */ } } public bool invert; public bool root; public bool global; public bool position; Matrix4x4 GetBoneTransform(UMAData umaData) { Matrix4x4 mat = Matrix4x4.identity; Quaternion rot = Quaternion.Euler(Rotation); mat.SetTRS(Offset, rot, Vector3.one); if (position) { Transform pos = umaData.skeleton.GetBoneTransform(UMAUtils.StringToHash("Position")); if (pos != null) { Matrix4x4 posMat = new Matrix4x4(); posMat.SetTRS(pos.localPosition, Quaternion.identity /*pos.localRotation*/, Vector3.one); if (invert) { posMat = posMat.inverse; } mat = mat * posMat; } else { Debug.Log("Position bone not found?"); } } if (global) { Transform global = umaData.skeleton.GetBoneTransform(UMAUtils.StringToHash("Global")); if (global != null) { Matrix4x4 globalMat = new Matrix4x4(); globalMat.SetTRS(global.localPosition, Quaternion.identity/*global.localRotation*/, Vector3.one); if (invert) { globalMat = globalMat.inverse; } mat = mat * globalMat; } else { Debug.Log("Global bone not found?"); } } if (root) { Transform root = umaData.umaRoot.transform; if (root != null) { Matrix4x4 rootmat = new Matrix4x4(); rootmat.SetTRS(Vector3.zero, root.localRotation, Vector3.one); if (invert) { rootmat = rootmat.inverse; } mat = mat * rootmat; } else { Debug.Log("Root bone not found?"); } } return mat; } Vector3[] TranslateVertices(Vector3[] verts, UMAData umaData) { Vector3[] tverts = new Vector3[verts.Length]; Matrix4x4 mat = GetBoneTransform(umaData); for(int i=0;i(); if (smr == null) { Debug.LogWarning("Unable to instantiate decal - no SMR"); return null; } Mesh m = new Mesh(); ApplyToMesh(m,umaData); // Copy bindposes from main. // copy bones from main. smr.sharedMesh = m; smr.sharedMesh.bindposes = baseRenderer.sharedMesh.bindposes; smr.bones = baseRenderer.bones; smr.sharedMesh = m; smr.rootBone = baseRenderer.rootBone; /* OLD BANDAGE WAY NativeArray bpv = new NativeArray(bonesPerVertex, Allocator.Temp); NativeArray bweights; bweights = new NativeArray(finalBoneWeights, Allocator.Temp); smr.sharedMesh.SetBoneWeights(bpv, bweights); */ smr.gameObject.SetActive(false); smr.gameObject.SetActive(true); return newDecal; } public void Begun(UMAData umaData) { } public void Completed(UMAData umaData,GameObject slotObject) { UpdateBones(umaData); ApplyTo(umaData, umaData.GetRenderer(0), slotObject); } public void HookupEvents(SlotDataAsset slot) { } #endregion } }