diff --git a/com.unity.gpuanimation/Unity.GPUAnimation/ConvertToGPUCharacter.cs b/com.unity.gpuanimation/Unity.GPUAnimation/ConvertToGPUCharacter.cs index c2e45ee..dd846e9 100644 --- a/com.unity.gpuanimation/Unity.GPUAnimation/ConvertToGPUCharacter.cs +++ b/com.unity.gpuanimation/Unity.GPUAnimation/ConvertToGPUCharacter.cs @@ -11,7 +11,7 @@ public static BlobAssetReference CreateClipSet(KeyframeTe using (var builder = new BlobBuilder(Allocator.Temp)) { ref var root = ref builder.ConstructRoot(); - var clips = builder.Allocate(data.Animations.Count, ref root.Clips); + var clips = builder.Allocate(ref root.Clips, data.Animations.Count); for (int i = 0; i != data.Animations.Count; i++) clips[i] = new BakedAnimationClip(data.AnimationTextures, data.Animations[i]); @@ -43,7 +43,7 @@ public static void AddCharacterComponents(EntityManager manager, Entity entity, var renderCharacter = new RenderCharacter { - Material = renderer.sharedMaterial, + Materials = renderer.sharedMaterials, AnimationTexture = bakedData.AnimationTextures, Mesh = bakedData.NewMesh, ReceiveShadows = renderer.receiveShadows, diff --git a/com.unity.gpuanimation/Unity.GPUAnimation/GpuCharacterRenderSystem.cs b/com.unity.gpuanimation/Unity.GPUAnimation/GpuCharacterRenderSystem.cs index 3da591d..27da72d 100644 --- a/com.unity.gpuanimation/Unity.GPUAnimation/GpuCharacterRenderSystem.cs +++ b/com.unity.gpuanimation/Unity.GPUAnimation/GpuCharacterRenderSystem.cs @@ -87,7 +87,7 @@ public float ComputeNormalizedTime(float time) struct RenderCharacter : ISharedComponentData, IEquatable { //@TODO: Would be nice if we had BlobAssetReference in shared component data support (Serialize not supported...) - public Material Material; + public Material[] Materials; public AnimationTextures AnimationTexture; public Mesh Mesh; public bool ReceiveShadows; @@ -95,14 +95,29 @@ struct RenderCharacter : ISharedComponentData, IEquatable public bool Equals(RenderCharacter other) { - return Material == other.Material && AnimationTexture.Equals(other.AnimationTexture) && Mesh == other.Mesh && ReceiveShadows == other.ReceiveShadows && CastShadows == other.CastShadows; + bool eq = AnimationTexture.Equals(other.AnimationTexture) && Mesh == other.Mesh && ReceiveShadows == other.ReceiveShadows && CastShadows == other.CastShadows; + if (Materials == null || other.Materials == null ) + { + eq &= Materials == other.Materials; + } + else + { + for (int m = 0; m < Materials.Length && eq ; ++m ) + eq &= Materials[m] == other.Materials[m]; + } + return eq; } - + public override int GetHashCode() { unchecked { - var hashCode = (ReferenceEquals(Material, null) ? 0 : Material.GetHashCode()); + int hashCode = 0; + if ( !ReferenceEquals( Materials, null )) + { + for (int m = 0; m < Materials.Length; ++m) + hashCode = (hashCode * 397) ^ Materials[m].GetHashCode(); + } hashCode = (hashCode * 397) ^ AnimationTexture.GetHashCode(); hashCode = (hashCode * 397) ^ (ReferenceEquals(Mesh, null) ? 0 : Mesh.GetHashCode()); return hashCode; @@ -184,18 +199,18 @@ protected override JobHandle OnUpdate(JobHandle inputDeps) foreach (var character in _Characters) { - if (character.Material == null || character.Mesh == null) + if (character.Materials == null || character.Mesh == null || character.Materials[0] == null ) continue; //@TODO: Currently we never cleanup the _Drawers cache when the last entity with that renderer disappears. InstancedSkinningDrawer drawer; if (!_Drawers.TryGetValue(character, out drawer)) { - drawer = new InstancedSkinningDrawer(character.Material, character.Mesh, character.AnimationTexture); + drawer = new InstancedSkinningDrawer(character.Materials, character.Mesh, character.AnimationTexture); _Drawers.Add(character, drawer); } - m_Characters.SetFilter(character); + m_Characters.SetSharedComponentFilter(character); Profiler.BeginSample("ExtractState"); JobHandle jobA, jobB; diff --git a/com.unity.gpuanimation/Unity.GPUAnimation/InstancedSkinningDrawer.cs b/com.unity.gpuanimation/Unity.GPUAnimation/InstancedSkinningDrawer.cs index 4e89248..82ed1b9 100644 --- a/com.unity.gpuanimation/Unity.GPUAnimation/InstancedSkinningDrawer.cs +++ b/com.unity.gpuanimation/Unity.GPUAnimation/InstancedSkinningDrawer.cs @@ -11,42 +11,71 @@ public class InstancedSkinningDrawer : IDisposable { private const int PreallocatedBufferSize = 1024; - private ComputeBuffer argsBuffer; + private ComputeBuffer[] argsBuffers; private readonly uint[] indirectArgs = new uint[5] { 0, 0, 0, 0, 0 }; private ComputeBuffer textureCoordinatesBuffer; private ComputeBuffer objectToWorldBuffer; - private Material material; + private Material[] materials; private Mesh mesh; - public unsafe InstancedSkinningDrawer(Material srcMaterial, Mesh meshToDraw, AnimationTextures animTexture) + unsafe void init(Material[] srcMaterials, Mesh meshToDraw, AnimationTextures animTexture) { this.mesh = meshToDraw; - this.material = new Material(srcMaterial); - argsBuffer = new ComputeBuffer(1, indirectArgs.Length * sizeof(uint), ComputeBufferType.IndirectArguments); - indirectArgs[0] = mesh.GetIndexCount(0); - indirectArgs[1] = (uint)0; - argsBuffer.SetData(indirectArgs); + this.materials = new Material[ srcMaterials.Length ]; + this.argsBuffers = new ComputeBuffer[ srcMaterials.Length ]; + for (int mat = 0; mat < srcMaterials.Length; ++mat) + { + this.materials[mat] = new Material(srcMaterials[mat]); + + this.materials[mat].SetBuffer("textureCoordinatesBuffer", textureCoordinatesBuffer); + this.materials[mat].SetBuffer("objectToWorldBuffer", objectToWorldBuffer); + this.materials[mat].SetTexture("_AnimationTexture0", animTexture.Animation0); + this.materials[mat].SetTexture("_AnimationTexture1", animTexture.Animation1); + this.materials[mat].SetTexture("_AnimationTexture2", animTexture.Animation2); + + argsBuffers[mat] = new ComputeBuffer(1, indirectArgs.Length * sizeof(uint), ComputeBufferType.IndirectArguments); + + indirectArgs[0] = mesh.GetIndexCount(0); + indirectArgs[1] = (uint)0; + argsBuffers[mat].SetData(indirectArgs); + } objectToWorldBuffer = new ComputeBuffer(PreallocatedBufferSize, 16 * sizeof(float)); textureCoordinatesBuffer = new ComputeBuffer(PreallocatedBufferSize, 3 * sizeof(float)); - this.material.SetBuffer("textureCoordinatesBuffer", textureCoordinatesBuffer); - this.material.SetBuffer("objectToWorldBuffer", objectToWorldBuffer); - this.material.SetTexture("_AnimationTexture0", animTexture.Animation0); - this.material.SetTexture("_AnimationTexture1", animTexture.Animation1); - this.material.SetTexture("_AnimationTexture2", animTexture.Animation2); + } + + public unsafe InstancedSkinningDrawer(Material srcMaterial, Mesh meshToDraw, AnimationTextures animTexture) + { + init(new Material[] { srcMaterial }, meshToDraw, animTexture); + } + + public unsafe InstancedSkinningDrawer(Material[] srcMaterials, Mesh meshToDraw, AnimationTextures animTexture) + { + init( srcMaterials, meshToDraw, animTexture); } public void Dispose() { - UnityEngine.Object.DestroyImmediate(material); + if (materials != null) + { + for ( int mat=0; mat TextureCoordinates, NativeArray ObjectToWorld, ShadowCastingMode shadowCastingMode, bool receiveShadows) { // CHECK: Systems seem to be called when exiting playmode once things start getting destroyed, such as the mesh here. - if (mesh == null || material == null) + if (mesh == null || materials == null || materials[0]==null ) return; int count = TextureCoordinates.Length; @@ -69,9 +98,6 @@ public void Draw(NativeArray TextureCoordinates, NativeArray O objectToWorldBuffer = new ComputeBuffer(TextureCoordinates.Length, 16 * sizeof(float)); textureCoordinatesBuffer = new ComputeBuffer(TextureCoordinates.Length, 3 * sizeof(float)); } - - this.material.SetBuffer("textureCoordinatesBuffer", textureCoordinatesBuffer); - this.material.SetBuffer("objectToWorldBuffer", objectToWorldBuffer); Profiler.BeginSample("Modify compute buffers"); @@ -79,16 +105,35 @@ public void Draw(NativeArray TextureCoordinates, NativeArray O objectToWorldBuffer.SetData(ObjectToWorld, 0, 0, count); textureCoordinatesBuffer.SetData(TextureCoordinates, 0, 0, count); - - Profiler.EndSample(); - Profiler.EndSample(); + for (int mat = 0; mat < materials.Length; ++mat) + { + this.materials[mat].SetBuffer("textureCoordinatesBuffer", textureCoordinatesBuffer); + this.materials[mat].SetBuffer("objectToWorldBuffer", objectToWorldBuffer); + } - //indirectArgs[1] = (uint)data.Count; indirectArgs[1] = (uint)count; - argsBuffer.SetData(indirectArgs); - Graphics.DrawMeshInstancedIndirect(mesh, 0, material, new Bounds(Vector3.zero, 1000000 * Vector3.one), argsBuffer, 0, new MaterialPropertyBlock(), shadowCastingMode, receiveShadows); + for (int smi = 0; smi < mesh.subMeshCount; ++smi) + { + indirectArgs[0] = mesh.GetIndexCount(smi); + indirectArgs[2] = mesh.GetIndexStart(smi); + indirectArgs[3] = mesh.GetBaseVertex(smi); + argsBuffers[smi].SetData(indirectArgs); + } + + Profiler.EndSample(); + + Profiler.EndSample(); + + // todo: use one argbuffer and an offset? + for (int smi = 0; smi < mesh.subMeshCount; ++smi) + { + Graphics.DrawMeshInstancedIndirect(mesh, smi, materials[smi], + new Bounds(Vector3.zero, 1000000 * Vector3.one), + argsBuffers[smi], 0, + new MaterialPropertyBlock(), shadowCastingMode, receiveShadows); + } } } } \ No newline at end of file diff --git a/com.unity.gpuanimation/Unity.GPUAnimation/KeyframeTextureBaker.cs b/com.unity.gpuanimation/Unity.GPUAnimation/KeyframeTextureBaker.cs old mode 100755 new mode 100644 index 89337bb..0da530c --- a/com.unity.gpuanimation/Unity.GPUAnimation/KeyframeTextureBaker.cs +++ b/com.unity.gpuanimation/Unity.GPUAnimation/KeyframeTextureBaker.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using UnityEditor; using UnityEngine; +using UnityEngine.Rendering; using Object = System.Object; @@ -320,8 +321,16 @@ public static void CopyMeshData(this Mesh originalMesh, Mesh newMesh) newMesh.normals = originalMesh.normals; newMesh.uv = originalMesh.uv; newMesh.tangents = originalMesh.tangents; + + newMesh.subMeshCount = originalMesh.subMeshCount; + for (int smi = 0; smi < originalMesh.subMeshCount; ++smi ) + { + var sm = originalMesh.GetSubMesh(smi); + newMesh.SetSubMesh(smi, sm, MeshUpdateFlags.Default); + } + newMesh.name = originalMesh.name; - } + } private static float Distance(Color r1, Color r2) {