Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static BlobAssetReference<BakedAnimationClipSet> CreateClipSet(KeyframeTe
using (var builder = new BlobBuilder(Allocator.Temp))
{
ref var root = ref builder.ConstructRoot<BakedAnimationClipSet>();
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]);

Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,37 @@ public float ComputeNormalizedTime(float time)
struct RenderCharacter : ISharedComponentData, IEquatable<RenderCharacter>
{
//@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;
public ShadowCastingMode CastShadows;

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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,50 +11,79 @@ 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<materials.Length; ++mat )
UnityEngine.Object.DestroyImmediate(materials[mat]);
materials = null;
}

if (argsBuffer != null) argsBuffer.Dispose();
if (argsBuffers != null)
{
for ( int ab=0; ab<argsBuffers.Length; ++ab )
argsBuffers[ab].Dispose();
argsBuffers = null;
}

if (objectToWorldBuffer != null) objectToWorldBuffer.Dispose();
if (textureCoordinatesBuffer != null) textureCoordinatesBuffer.Dispose();
}

public void Draw(NativeArray<float3> TextureCoordinates, NativeArray<float4x4> 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;
Expand All @@ -69,26 +98,42 @@ public void Draw(NativeArray<float3> TextureCoordinates, NativeArray<float4x4> 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");

Profiler.BeginSample("Shader set data");

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);
}
}
}
}
11 changes: 10 additions & 1 deletion com.unity.gpuanimation/Unity.GPUAnimation/KeyframeTextureBaker.cs
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using Object = System.Object;


Expand Down Expand Up @@ -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)
{
Expand Down