Files
SimUL/Assets/UMA/Core/Decals/Scripts/DecalDefinition.cs
T
2025-01-07 18:54:46 +02:00

272 lines
9.5 KiB
C#

using System.Collections.Generic;
using UMA;
using Unity.Collections;
using UnityEngine;
public class DecalDefinition
{
public string Name;
public int InitialIndex;
public GameObject DecalMeshObject;
public Mesh bakedMesh;
public Plane[] planesInWorldSpace;
public int VertexNumber;
public Vector3 WorldImpactPoint;
public Vector3 LocalImpactPoint;
public Material material;
public float offset; // zbias or offset for rendering. vertex = vertex + normal * offset.
List<DecalInstance> Instances = new List<DecalInstance>();
public GameObject InstantiateSimpleDecal(GameObject umaParent, SkinnedMeshRenderer baseRenderer)
{
// instantiate a new one here???
GameObject newDecal = GameObject.Instantiate(DecalMeshObject,umaParent.transform);
SkinnedMeshRenderer smr = newDecal.GetComponent<SkinnedMeshRenderer>();
if (smr == null)
{
Debug.LogWarning("Unable to instantiate decal - no SMR");
return null;
}
// Copy bindposes from main.
// copy bones from main.
smr.sharedMesh.bindposes = baseRenderer.sharedMesh.bindposes;
smr.bones = baseRenderer.bones;
return newDecal;
}
public void AddInstance(UMAData umaData, List<int> Vertexes)
{
}
public void AddSubmesh(SkinnedMeshRenderer smr)
{
// we can't reuse the vertexes because the UV coordinates are different...
if (Instances == null)
{
return;
}
if (Instances.Count == 0)
{
return;
}
List<Material> mats = new List<Material>();
smr.GetMaterials(mats);
mats.Add(material);
// read old data
List<Vector3> Vertexes = new List<Vector3>();
List<Vector3> Normals = new List<Vector3>();
List<Vector4> Tangents = new List<Vector4>();
List<Color32> Colors = new List<Color32>();
List<Vector2> UV = new List<Vector2>();
List<Vector2> UV2 = new List<Vector2>();
List<Vector2> UV3 = new List<Vector2>();
List<Vector2> UV4 = new List<Vector2>();
List<int> Tris = new List<int>();
// TODO: these should be NativeArray. Size to mesh size + all DI sizes.
List<byte> bonesPerVertex = new List<byte>();
List<BoneWeight1> boneWeights = new List<BoneWeight1>();
Mesh mesh = smr.sharedMesh;
mesh.GetVertices(Vertexes);
mesh.GetNormals(Normals);
mesh.GetTangents(Tangents);
mesh.GetColors(Colors);
mesh.GetUVs(0, UV);
mesh.GetUVs(1, UV2);
mesh.GetUVs(2, UV3);
mesh.GetUVs(3, UV4);
bonesPerVertex.AddRange(mesh.GetBonesPerVertex());
boneWeights.AddRange(mesh.GetAllBoneWeights());
// boneweights
// bonespervertex
// blendshapes <-- later?
int baseVertex = Vertexes.Count;
foreach(DecalInstance di in Instances)
{
Vertexes.AddRange(di.vertexes);
// add the triangles
for(int i=0;i<di.TriangleList.Length;i++)
{
Tris.Add(di.TriangleList[i] + baseVertex);
}
// add the boneweights
for(int i=0;i<di.boneWeights.Length;i++)
{
BoneWeight1 bw = di.boneWeights[i];
bw.boneIndex += baseVertex;
boneWeights.Add(bw);
}
bonesPerVertex.AddRange(di.bonesPerVertex);
// go to next DecalInstance
baseVertex += di.vertexes.Length;
}
mesh.SetVertices(Vertexes);
mesh.SetNormals(Normals);
mesh.SetTangents(Tangents);
mesh.SetColors(Colors);
mesh.SetUVs(0, UV);
mesh.SetUVs(1, UV2);
mesh.SetUVs(2, UV3);
mesh.SetUVs(3, UV4);
// Set the submesh
mesh.subMeshCount++;
int newSubmesh = mesh.subMeshCount - 1;
mesh.SetIndices(Tris, MeshTopology.Triangles, newSubmesh);
// todo: these should not use temp NativeArrays, but always be NativeArrays.
var unityBonesPerVertex = new NativeArray<byte>(bonesPerVertex.ToArray(), Allocator.Persistent);
var unityBoneWeights = new NativeArray<BoneWeight1>(boneWeights.ToArray(), Allocator.Persistent);
mesh.SetBoneWeights(unityBonesPerVertex, unityBoneWeights);
unityBonesPerVertex.Dispose();
unityBoneWeights.Dispose();
}
}
public struct faceData
{
int oldFaceNumber;
Vector3 Normal;
}
public class DecalInstance
{
float offset; // z bias, or add to vertexes?
public Vector3[] vertexes; // copied from slot(s)
public Vector3[] normals; // copied from slot(s)
public Vector4[] tangents; // copied from slot(s)
public Color32[] colors32; // copied from slot(s)
public Vector2[] uv; // calculated at capture time by projecting to plane
public int[] TriangleList; // calculated at capture time (each triangle found is translated to local triangles and added to list).
public byte[] bonesPerVertex;
public BoneWeight1[] boneWeights;
/// <summary>
/// Creates a skinned decal
/// </summary>
/// <param name="t">t is the transform of the meshes game object in the scene.</param>
/// <param name="m">m is the mesh as it is *right now* in the scene, captured at the current frame.
/// It's used in place of the meshdata, and is used for everything *except* as the vertex position
/// when creating the skinned mesh!!!</param>
/// <param name="RayOrigin">RayOrigin is the origin of the ray. Used to determine if a face is "facing" the origin of the decal.</param>
/// <param name="meshData"> This is the UMAMeshData that holds all the data. This is the information
/// that is pre-bound to the rig. It's used for constructing the submesh</param>
/// <param name="planes">planes is the list of planes in world space that define the bounds</param>
/// <returns></returns>
public bool Create(Transform t, Mesh m, Vector3 RayOrigin, UMAMeshData meshData, Plane[] planes)
{
List<Vector3> newVerts = new List<Vector3>();
List<Vector3> newNormals = new List<Vector3>();
List<Vector4> newTangents = new List<Vector4>();
List<Color32> newColors32 = new List<Color32>();
List<Vector2> newUv = new List<Vector2>();
List<int> newTriangleList = new List<int>();
List<byte> newBonesPerVertex = new List<byte>();
List<BoneWeight1> newBoneWeights = new List<BoneWeight1>();
List<int> oldVertexNumbers = new List<int>();
HashSet<int> vertHash = new HashSet<int>();
// calculate the face normals for each vertex.
// int = the source vertex number from the mesh.
// List<Vector3> = the list of normals for this vertex (one from each face it's connected to).
//Dictionary<int, List<faceData>> oldVertexnumberFaceNormals = CalculateFaceNormals(m, meshData);
List<Vector3> meshVerts = new List<Vector3>();
m.GetVertices(meshVerts);
for (int i=0;i<m.vertexCount;i++)
{
// this vertex is in world space.
Vector3 vert = t.TransformPoint(meshVerts[i]);
if (OnRight(vert,planes))
{
oldVertexNumbers.Add(i);
vertHash.Add(i);
}
}
// now look through every face that has the vertexes in it.
// if the face is facing the origin, then add it.
Plane p = new Plane();
for(int i=0;i<m.subMeshCount;i++)
{
var smd = m.GetSubMesh(i);
// UMA only creates triangle lists, so if this fails, then something has changed...
if (smd.topology == MeshTopology.Triangles)
{
int[] submeshtris = m.GetIndices(i);
for (int v=0;v<smd.indexCount;v+= 3)
{
int i1 = submeshtris[v];
int i2 = submeshtris[v + 1];
int i3 = submeshtris[v + 2];
p.Set3Points(meshVerts[i1], meshVerts[i2], meshVerts[i3]);
// Does the triangle face the origin?
if (p.GetDistanceToPoint(RayOrigin) >= 0.0f)
{
if (vertHash.Contains(i1) || vertHash.Contains(i2) || vertHash.Contains(i3))
{
// Add this triangle.
// add meshVerts[i1], meshVerts[i2], meshVerts[i3] to new triangle list.
// add translation for i1,i2,i3 to lookup (new, old)
// Calculate UV for each one based on distance to UV planes
}
}
}
}
}
return false;
}
// Return true if vertex is inside plane group.
private bool OnRight(Vector3 vert, Plane[] planes)
{
foreach (Plane p in planes)
{
if (p.GetDistanceToPoint(vert) <= 0.0f)
{
return false;
}
}
return true;
}
private Dictionary<int, List<faceData>> CalculateFaceNormals(Mesh m, UMAMeshData meshData)
{
Dictionary<int, List<faceData>> retval = new Dictionary<int, List<faceData>>();
return retval;
}
// index of vertexes in the slot.
// These need to be translate d to the mesh index after the build is complete.
// To do this, we will need to track for each slot in the UMAData (during the build process)
// What SMR the slot is actually in, in case there are multiples
// what vertex position the slot starts at in the SMR
}