You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

677 lines
34 KiB
C#

using UnityEngine;
using System.Collections.Generic;
using System;
using UnityEngine.Jobs;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if GPU_INSTANCER
namespace GPUInstancer.CrowdAnimations
{
[ExecuteInEditMode]
public class GPUICrowdManager : GPUInstancerPrefabManager
{
protected List<AnimatorClipInfo> _animatorClipInfos = new List<AnimatorClipInfo>();
private ComputeShader _skinnedMeshAnimateComputeShader;
private int _animateBonesKernelID;
private int _animateBonesLerpedKernelID;
private int _fixWeightsKernelID;
private ComputeShader _crowdAnimatorComputeShader;
private int _crowdAnimatorKernelID;
private ComputeShader _asyncBoneUpdateComputeShader;
private int _asyncBoneUpdateKernelID;
private ComputeShader _optionalRendererBufferCopyComputeShader;
private int _optionalRendererBufferCopyKernelID;
private ComputeShader _animationBufferToTextureComputeShader;
private int _animationBufferToTextureKernelID;
private float _lastRootMotionUpdateTime;
//private static float _rootMotionFrequency = 1.0f / 90.0f;
private float _lastTransitionUpdateTime;
private static float _transitionFrequency = 1.0f / 60.0f;
private float _lastAnimateTime;
public List<GPUIAnimationEvent> animationEvents;
#if UNITY_EDITOR
public int selectedClipIndex;
public bool showEventsFoldout = true;
#endif
#region MonoBehavior Methods
public override void Awake()
{
if (GPUICrowdConstants.gpuiCrowdSettings == null)
GPUICrowdConstants.gpuiCrowdSettings = GPUICrowdSettings.GetDefaultGPUICrowdSettings();
base.Awake();
if (!GPUInstancerConstants.gpuiSettings.shaderBindings.HasExtension(GPUICrowdConstants.GPUI_EXTENSION_CODE))
{
GPUInstancerConstants.gpuiSettings.shaderBindings.AddExtension(new GPUICrowdShaderBindings());
}
}
public override void Start()
{
base.Start();
_skinnedMeshAnimateComputeShader = (ComputeShader)Resources.Load(GPUICrowdConstants.COMPUTE_SKINNED_MESH_ANIMATE_PATH);
_animateBonesKernelID = _skinnedMeshAnimateComputeShader.FindKernel(GPUICrowdConstants.COMPUTE_ANIMATE_BONES_KERNEL);
_animateBonesLerpedKernelID = _skinnedMeshAnimateComputeShader.FindKernel(GPUICrowdConstants.COMPUTE_ANIMATE_BONES_LERPED_KERNEL);
_fixWeightsKernelID = _skinnedMeshAnimateComputeShader.FindKernel(GPUICrowdConstants.COMPUTE_FIX_WEIGHTS_KERNEL);
_crowdAnimatorComputeShader = (ComputeShader)Resources.Load(GPUICrowdConstants.COMPUTE_CROWD_ANIMATOR_PATH);
_crowdAnimatorKernelID = _crowdAnimatorComputeShader.FindKernel(GPUICrowdConstants.COMPUTE_CROWD_ANIMATOR_KERNEL);
_asyncBoneUpdateComputeShader = (ComputeShader)Resources.Load(GPUICrowdConstants.COMPUTE_ASYNC_BONE_UPDATE);
_asyncBoneUpdateKernelID = _asyncBoneUpdateComputeShader.FindKernel(GPUICrowdConstants.COMPUTE_ASYNC_BONE_UPDATE_KERNEL);
_optionalRendererBufferCopyComputeShader = (ComputeShader)Resources.Load(GPUICrowdConstants.COMPUTE_OPTIONAL_RENDERER_BUFFER_COPY);
_optionalRendererBufferCopyKernelID = _optionalRendererBufferCopyComputeShader.FindKernel(GPUICrowdConstants.COMPUTE_OPTIONAL_RENDERER_BUFFER_COPY_KERNEL);
_animationBufferToTextureComputeShader = (ComputeShader)Resources.Load(GPUICrowdConstants.COMPUTE_ANIMATION_BUFFER_TO_TEXTURE);
_animationBufferToTextureKernelID = _animationBufferToTextureComputeShader.FindKernel(GPUICrowdConstants.COMPUTE_ANIMATION_BUFFER_TO_TEXTURE_KERNEL);
}
public override void OnEnable()
{
if (Application.isPlaying)
{
int count = prefabList.Count;
for (int i = 0; i < count; i++)
{
GPUICrowdPrototype crowdPrototype = (GPUICrowdPrototype)prototypeList[i];
if (crowdPrototype.animationData != null && crowdPrototype.animationData.skinnedMeshDataList != null)
{
if (crowdPrototype.animationData.applyRootMotion)
{
crowdPrototype.enableRuntimeModifications = true;
crowdPrototype.autoUpdateTransformData = true;
}
if (crowdPrototype.hasOptionalRenderers)
{
SkinnedMeshRenderer[] skinnedMeshRenderers = crowdPrototype.prefabObject.GetComponentsInChildren<SkinnedMeshRenderer>(true);
foreach (GPUISkinnedMeshData smd in crowdPrototype.animationData.skinnedMeshDataList)
{
if (smd.isOptional && !smd.isOptionalPrototypeGenerated)
{
foreach (SkinnedMeshRenderer skinnedMeshRenderer in skinnedMeshRenderers)
{
if (skinnedMeshRenderer.gameObject.name.Equals(smd.transformName))
{
GPUICrowdPrototype generatedPrototype = DefineGameObjectAsCrowdPrototypeAtRuntime(skinnedMeshRenderer.gameObject, crowdPrototype.animationData, false,
crowdPrototype);
generatedPrototype.hasOptionalRenderers = false;
generatedPrototype.enableRuntimeModifications = true;
generatedPrototype.addRemoveInstancesAtRuntime = false;
generatedPrototype.isChildPrototype = true;
generatedPrototype.parentPrototype = crowdPrototype;
generatedPrototype.autoUpdateTransformData = false;
smd.isOptionalPrototypeGenerated = true;
smd.optionalPrototype = generatedPrototype;
break;
}
}
}
}
}
}
}
}
base.OnEnable();
if (Application.isPlaying && animationEvents != null)
{
foreach (GPUIAnimationEvent animationEvent in animationEvents)
{
if (animationEvent.prototype.animationData != null && animationEvent.prototype.animationData.useCrowdAnimator)
GPUICrowdAPI.AddAnimationEvent(this, animationEvent);
}
}
}
public override void Update()
{
_transitionFrequency = 1.0f / 60.0f * Time.timeScale;
float currentTime = Time.time;
float currentDeltaTime = Time.deltaTime;
bool calculateTransitions = currentTime - _lastTransitionUpdateTime > _transitionFrequency;
if (runtimeDataList != null)
{
foreach (GPUICrowdRuntimeData runtimeData in runtimeDataList)
{
if (runtimeData.isChildRuntimeData)
continue;
GPUICrowdPrototype crowdPrototype = (GPUICrowdPrototype)runtimeData.prototype;
if (crowdPrototype.animationData == null)
continue;
// Crowd Animator Root Motion
if (crowdPrototype.animationData.useCrowdAnimator && runtimeData.instanceCount > 0)
{
if (crowdPrototype.animationData.applyRootMotion)
{
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.BeginSample("GPUI Crowd Animator Root Motion");
#endif
runtimeData.dependentJob.Complete();
runtimeData.dependentJob = new ApplyCrowdAnimatorRootMotionJob()
{
currentTime = currentTime,
lerpAmount = (currentTime - _lastRootMotionUpdateTime) * crowdPrototype.frameRate,
animationData = runtimeData.animationData,
crowdAnimatorControllerData = runtimeData.crowdAnimatorControllerData,
clipDatas = runtimeData.clipDatas,
rootMotions = runtimeData.rootMotions
}.Schedule(runtimeData.instanceTransformAccessArray);
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.EndSample();
#endif
}
if (calculateTransitions)
{
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.BeginSample("GPUI Crowd Animator Transition");
#endif
int transitionCount = runtimeData.transitioningAnimators.Count;
if (transitionCount > 0)
{
runtimeData.dependentJob.Complete();
for (int i = 0; i < transitionCount; i++)
{
if (!runtimeData.transitioningAnimators[i].ApplyTransition(runtimeData, currentTime))
{
i--;
transitionCount--;
}
}
runtimeData.animationDataModified = true;
}
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.EndSample();
#endif
}
if (runtimeData.hasEvents)
{
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.BeginSample("GPUI Crowd Animator Events");
#endif
runtimeData.dependentJob.Complete();
List<GPUInstancerPrefab> prefabInstanceList = _registeredPrefabsRuntimeData[crowdPrototype];
for (int i = prefabInstanceList.Count - 1; i >= 0; i--) // switched to for loop to not cause issues when instance is removed in the event
{
GPUICrowdPrefab prefabInstance = (GPUICrowdPrefab)prefabInstanceList[i];
if (prefabInstance.state == PrefabInstancingState.Instanced)
{
prefabInstance.crowdAnimator.ApplyAnimationEvents(runtimeData, prefabInstance, currentTime, currentDeltaTime);
}
}
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.EndSample();
#endif
}
if (crowdPrototype.animationData.applyBoneUpdates)
{
runtimeData.MakeBoneDataRequest();
}
}
}
}
_lastRootMotionUpdateTime = currentTime;
if (calculateTransitions)
_lastTransitionUpdateTime = currentTime;
base.Update();
}
public override void LateUpdate()
{
if (Application.isPlaying && runtimeDataList != null)
{
foreach (GPUICrowdRuntimeData runtimeData in runtimeDataList)
{
runtimeData.dependentJob.Complete();
UpdateAnimatorsData(runtimeData); // calculate baked animation
// Can inject code here to modify bone matrix buffers
}
_lastAnimateTime = Time.time;
}
base.LateUpdate(); // GPUI core rendering
}
#endregion MonoBehavior Methods
public override void GeneratePrototypes(bool forceNew = false)
{
ClearInstancingData();
if (forceNew || prototypeList == null)
prototypeList = new List<GPUInstancerPrototype>();
else
prototypeList.RemoveAll(p => p == null);
GPUInstancerConstants.gpuiSettings.SetDefultBindings();
GPUICrowdUtility.SetCrowdPrefabPrototypes(gameObject, prototypeList, prefabList, forceNew);
}
#if UNITY_EDITOR
public override void CheckPrototypeChanges()
{
if (!GPUInstancerConstants.gpuiSettings.shaderBindings.HasExtension(GPUICrowdConstants.GPUI_EXTENSION_CODE))
{
GPUInstancerConstants.gpuiSettings.shaderBindings.AddExtension(new GPUICrowdShaderBindings());
}
if (prototypeList == null)
GeneratePrototypes();
else
prototypeList.RemoveAll(p => p == null);
if (GPUInstancerConstants.gpuiSettings != null && GPUInstancerConstants.gpuiSettings.shaderBindings != null)
{
GPUInstancerConstants.gpuiSettings.shaderBindings.ClearEmptyShaderInstances();
foreach (GPUInstancerPrototype prototype in prototypeList)
{
if (prototype.prefabObject != null)
{
GPUICrowdUtility.GenerateInstancedShadersForGameObject(prototype);
if (string.IsNullOrEmpty(prototype.warningText))
{
if (prototype.prefabObject.GetComponentInChildren<SkinnedMeshRenderer>() == null)
{
prototype.warningText = "Prefab object does not contain any Skinned Mesh Renderers.";
}
}
}
}
}
if (GPUInstancerConstants.gpuiSettings != null && GPUInstancerConstants.gpuiSettings.billboardAtlasBindings != null)
{
GPUInstancerConstants.gpuiSettings.billboardAtlasBindings.ClearEmptyBillboardAtlases();
}
if (prefabList == null)
prefabList = new List<GameObject>();
prefabList.RemoveAll(p => p == null);
prefabList.RemoveAll(p => p.GetComponent<GPUICrowdPrefab>() == null);
prototypeList.RemoveAll(p => p == null);
prototypeList.RemoveAll(p => !prefabList.Contains(p.prefabObject));
if (prefabList.Count != prototypeList.Count)
GeneratePrototypes();
registeredPrefabs.RemoveAll(rpd => !prototypeList.Contains(rpd.prefabPrototype));
foreach (GPUInstancerPrefabPrototype prototype in prototypeList)
{
if (!registeredPrefabs.Exists(rpd => rpd.prefabPrototype == prototype))
registeredPrefabs.Add(new RegisteredPrefabsData(prototype));
}
}
#endif // UNITY_EDITOR
public override void InitializeRuntimeDataAndBuffers(bool forceNew = true)
{
base.InitializeRuntimeDataAndBuffers(forceNew);
foreach (GPUICrowdPrototype prototype in _registeredPrefabsRuntimeData.Keys)
{
if (!prototype.animationData)
continue;
GPUICrowdRuntimeData runtimeData = (GPUICrowdRuntimeData)GetRuntimeData(prototype);
foreach (GPUICrowdPrefab instance in _registeredPrefabsRuntimeData[prototype])
{
if (instance != null)
{
instance.SetupPrefabInstance(runtimeData, forceNew);
if (instance.childCrowdPrefabs != null)
{
foreach (GPUICrowdPrefab childInstance in instance.childCrowdPrefabs)
{
childInstance.SetupPrefabInstance(GetRuntimeData(childInstance.prefabPrototype));
}
}
}
}
}
}
public override GPUInstancerRuntimeData InitializeRuntimeDataForPrefabPrototype(GPUInstancerPrefabPrototype p, int additionalBufferSize = 0)
{
GPUICrowdRuntimeData runtimeData = (GPUICrowdRuntimeData) GetRuntimeData(p);
if (runtimeData == null)
{
runtimeData = new GPUICrowdRuntimeData(p);
if (!runtimeData.CreateRenderersFromGameObject(p))
return null;
runtimeDataList.Add(runtimeData);
runtimeDataDictionary.Add(p, runtimeData);
if (p.isShadowCasting)
{
runtimeData.hasShadowCasterBuffer = true;
if (!p.useOriginalShaderForShadow)
{
runtimeData.shadowCasterMaterial = new Material(Shader.Find(GPUInstancerConstants.SHADER_GPUI_SHADOWS_ONLY));
}
}
}
base.InitializeRuntimeDataForPrefabPrototype(p, additionalBufferSize);
GPUICrowdPrototype crowdPrototype = (GPUICrowdPrototype)p;
if (crowdPrototype.isChildPrototype)
{
runtimeData.isChildRuntimeData = true;
runtimeData.parentRuntimeData = (GPUICrowdRuntimeData)GetRuntimeData(crowdPrototype.parentPrototype);
runtimeData.bufferSize = runtimeData.parentRuntimeData.bufferSize;
runtimeData.instanceCount = runtimeData.parentRuntimeData.instanceCount;
if (runtimeData.instanceDataNativeArray.IsCreated)
runtimeData.instanceDataNativeArray.Dispose();
runtimeData.instanceDataNativeArray = new Unity.Collections.NativeArray<Matrix4x4>(runtimeData.parentRuntimeData.bufferSize, Unity.Collections.Allocator.Persistent);
}
return runtimeData;
}
public override void SetRenderersEnabled(GPUInstancerPrefab prefabInstance, bool enabled)
{
if (!prefabInstance || !prefabInstance.prefabPrototype || !prefabInstance.prefabPrototype.prefabObject)
return;
GPUICrowdPrototype prototype = (GPUICrowdPrototype)prefabInstance.prefabPrototype;
if (!prototype.animationData)
return;
GPUICrowdPrefab crowdPrefabInstance = (GPUICrowdPrefab)prefabInstance;
if (crowdPrefabInstance.animatorRef == null)
crowdPrefabInstance.animatorRef = crowdPrefabInstance.GetAnimator();
LODGroup lodGroup = prefabInstance.GetComponent<LODGroup>();
if (lodGroup != null)
lodGroup.enabled = enabled;
if (crowdPrefabInstance.animatorRef != null && enabled && prototype.animationData.IsOptimizeGameObjects())
AnimatorUtility.DeoptimizeTransformHierarchy(crowdPrefabInstance.animatorRef.gameObject);
if (enabled && lodGroup != null && prototype.animationData.IsOptimizeGameObjects())
{
LOD[] lods = lodGroup.GetLODs();
LOD lod;
for (int l = 0; l < lodGroup.lodCount; l++)
{
lod = lods[l];
for (int r = 0; r < lod.renderers.Length; r++)
{
if (lod.renderers[r] is SkinnedMeshRenderer)
{
if (l > 0)
((SkinnedMeshRenderer)lod.renderers[r]).bones = ((SkinnedMeshRenderer)lods[0].renderers[r]).bones;
if (GPUInstancerUtility.IsInLayer(layerMask, lod.renderers[r].gameObject.layer))
lod.renderers[r].enabled = enabled;
}
}
}
}
else
{
SkinnedMeshRenderer[] skinnedMeshRenderers = prefabInstance.GetComponentsInChildren<SkinnedMeshRenderer>(true);
if (skinnedMeshRenderers != null && skinnedMeshRenderers.Length > 0)
{
for (int mr = 0; mr < skinnedMeshRenderers.Length; mr++)
{
SkinnedMeshRenderer skinnedMeshRenderer = skinnedMeshRenderers[mr];
if (GPUInstancerUtility.IsInLayer(layerMask, skinnedMeshRenderer.gameObject.layer))
skinnedMeshRenderer.enabled = enabled;
}
}
}
if (crowdPrefabInstance.animatorRef != null)
{
if (!enabled && prototype.animationData.IsOptimizeGameObjects())
AnimatorUtility.OptimizeTransformHierarchy(crowdPrefabInstance.animatorRef.gameObject, prototype.animationData.exposedTransforms);
if (prototype.animationData.useCrowdAnimator)
crowdPrefabInstance.animatorRef.enabled = enabled;
if (enabled)
crowdPrefabInstance.animatorRef.cullingMode = prototype.animatorCullingMode;
}
}
public void UpdateAnimatorsData(GPUICrowdRuntimeData runtimeData)
{
if (runtimeData.instanceCount == 0)
return;
GPUICrowdPrototype prototype = (GPUICrowdPrototype)runtimeData.prototype;
if (prototype.animationData != null && runtimeData.animationDataBuffer != null)
{
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.BeginSample("GPUI Crowd Manager Set Modified Buffers");
#endif
if (runtimeData.transformDataModified)
{
if (runtimeData.instanceDataNativeArray.IsCreated)
runtimeData.transformationMatrixVisibilityBuffer.SetData(runtimeData.instanceDataNativeArray);
runtimeData.transformDataModified = false;
}
if (prototype.isChildPrototype)
{
_optionalRendererBufferCopyComputeShader.SetBuffer(_optionalRendererBufferCopyKernelID, GPUICrowdConstants.CrowdKernelPoperties.CHILD_INSTANCE_DATA, runtimeData.transformationMatrixVisibilityBuffer);
_optionalRendererBufferCopyComputeShader.SetBuffer(_optionalRendererBufferCopyKernelID, GPUICrowdConstants.CrowdKernelPoperties.PARENT_INSTANCE_DATA, runtimeData.parentRuntimeData.transformationMatrixVisibilityBuffer);
_optionalRendererBufferCopyComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.INSTANCE_COUNT, runtimeData.instanceCount);
_optionalRendererBufferCopyComputeShader.Dispatch(_optionalRendererBufferCopyKernelID,
Mathf.CeilToInt(runtimeData.instanceCount / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT), 1, 1);
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.EndSample();
#endif
return;
}
if (runtimeData.animationDataModified)
{
runtimeData.animationDataBuffer.SetData(runtimeData.animationData);
runtimeData.animationDataModified = false;
}
if (runtimeData.crowdAnimatorDataModified)
{
runtimeData.crowdAnimatorControllerBuffer.SetData(runtimeData.crowdAnimatorControllerData);
runtimeData.crowdAnimatorDataModified = false;
}
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.EndSample();
#endif
#region Crowd Animator
if (prototype.animationData.useCrowdAnimator)
{
_crowdAnimatorComputeShader.SetBuffer(_crowdAnimatorKernelID, GPUICrowdConstants.CrowdKernelPoperties.ANIMATION_DATA, runtimeData.animationDataBuffer);
_crowdAnimatorComputeShader.SetBuffer(_crowdAnimatorKernelID, GPUICrowdConstants.CrowdKernelPoperties.CROWD_ANIMATOR_CONTROLLER, runtimeData.crowdAnimatorControllerBuffer);
_crowdAnimatorComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.INSTANCE_COUNT, runtimeData.instanceCount);
_crowdAnimatorComputeShader.SetFloat(GPUICrowdConstants.CrowdKernelPoperties.CURRENT_TIME, Time.time);
_crowdAnimatorComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.FRAME_RATE, prototype.frameRate);
_crowdAnimatorComputeShader.Dispatch(_crowdAnimatorKernelID,
Mathf.CeilToInt(runtimeData.instanceCount / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT), 1, 1);
}
#endregion Crowd Animator
#region Mecanim Animator
else
{
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.BeginSample("GPUI UpdateAnimatorsData");
#endif
foreach (GPUICrowdPrefab prefabInstance in _registeredPrefabsRuntimeData[runtimeData.prototype])
{
if (prefabInstance.state == PrefabInstancingState.Instanced)
{
prefabInstance.mecanimAnimator.UpdateDataFromMecanimAnimator(runtimeData, prefabInstance.gpuInstancerID - 1, prefabInstance.animatorRef, _animatorClipInfos);
}
}
runtimeData.animationDataBuffer.SetData(runtimeData.animationData);
#if UNITY_EDITOR
UnityEngine.Profiling.Profiler.EndSample();
#endif
}
#endregion Mecanim Animator
#region Fix Weights
// Fix weights
_skinnedMeshAnimateComputeShader.SetBuffer(_fixWeightsKernelID, GPUICrowdConstants.CrowdKernelPoperties.ANIMATION_DATA, runtimeData.animationDataBuffer);
_skinnedMeshAnimateComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.INSTANCE_COUNT, runtimeData.instanceCount);
_skinnedMeshAnimateComputeShader.Dispatch(_fixWeightsKernelID,
Mathf.CeilToInt(runtimeData.instanceCount / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT), 1, 1);
#endregion Fix Weights
#region Apply Bone Transforms
int kernelID = _animateBonesLerpedKernelID;
if (runtimeData.disableFrameLerp)
{
kernelID = _animateBonesKernelID;
runtimeData.disableFrameLerp = false;
}
// Apply bone transforms
_skinnedMeshAnimateComputeShader.SetBuffer(kernelID, GPUICrowdConstants.CrowdKernelPoperties.ANIMATION_DATA, runtimeData.animationDataBuffer);
_skinnedMeshAnimateComputeShader.SetBuffer(kernelID, GPUICrowdConstants.CrowdKernelPoperties.ANIMATION_BUFFER, runtimeData.animationBakeBuffer);
_skinnedMeshAnimateComputeShader.SetTexture(kernelID, GPUICrowdConstants.CrowdKernelPoperties.ANIMATION_TEXTURE, prototype.animationData.animationTexture);
_skinnedMeshAnimateComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.ANIMATION_TEXTURE_SIZE_X, prototype.animationData.textureSizeX);
_skinnedMeshAnimateComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.TOTAL_NUMBER_OF_FRAMES, prototype.animationData.totalFrameCount);
_skinnedMeshAnimateComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.TOTAL_NUMBER_OF_BONES, prototype.animationData.totalBoneCount);
_skinnedMeshAnimateComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.INSTANCE_COUNT, runtimeData.instanceCount);
_skinnedMeshAnimateComputeShader.SetFloat(GPUICrowdConstants.CrowdKernelPoperties.DELTA_TIME, Time.time - _lastAnimateTime);
_skinnedMeshAnimateComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.FRAME_RATE, prototype.frameRate);
_skinnedMeshAnimateComputeShader.Dispatch(kernelID,
Mathf.CeilToInt(runtimeData.instanceCount / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT_2D),
Mathf.CeilToInt(prototype.animationData.totalBoneCount / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT_2D),
1);
if (prototype.animationData.useCrowdAnimator && prototype.animationData.applyBoneUpdates && !prototype.animationData.isSynchronousBoneUpdates)
{
_asyncBoneUpdateComputeShader.SetBuffer(_asyncBoneUpdateKernelID, GPUICrowdConstants.CrowdKernelPoperties.ANIMATION_BUFFER, runtimeData.animationBakeBuffer);
_asyncBoneUpdateComputeShader.SetBuffer(_asyncBoneUpdateKernelID, GPUICrowdConstants.CrowdKernelPoperties.ASYNC_BONE_UPDATE_DATA, runtimeData.asyncBoneUpdateDataBuffer);
_asyncBoneUpdateComputeShader.SetBuffer(_asyncBoneUpdateKernelID, GPUICrowdConstants.CrowdKernelPoperties.ASYNC_BONE_UPDATE_FILTER, runtimeData.asyncBoneUpdateFilterBuffer);
_asyncBoneUpdateComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.TOTAL_NUMBER_OF_BONES, prototype.animationData.totalBoneCount);
_asyncBoneUpdateComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.INSTANCE_COUNT, runtimeData.instanceCount);
_asyncBoneUpdateComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.BONE_FILTER_COUNT, runtimeData.asyncBoneUpdateFilterBuffer.count);
_asyncBoneUpdateComputeShader.Dispatch(_asyncBoneUpdateKernelID,
Mathf.CeilToInt(runtimeData.instanceCount / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT_2D),
Mathf.CeilToInt(runtimeData.asyncBoneUpdateFilterBuffer.count / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT_2D),
1);
runtimeData.CompleteAsyncBoneDataRequest(false, prototype.animationData.asyncBoneUpdateMaxLatency - 1);
}
#endregion Apply Bone Transforms
#region Copy To Texture
if (GPUInstancerUtility.matrixHandlingType == GPUIMatrixHandlingType.CopyToTexture)
{
_animationBufferToTextureComputeShader.SetBuffer(_animationBufferToTextureKernelID, GPUICrowdConstants.CrowdKernelPoperties.ANIMATION_BUFFER, runtimeData.animationBakeBuffer);
_animationBufferToTextureComputeShader.SetTexture(_animationBufferToTextureKernelID, GPUICrowdConstants.CrowdKernelPoperties.ANIMATION_BUFFER_TEXTURE, runtimeData.animationBakeTexture);
_animationBufferToTextureComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.TOTAL_NUMBER_OF_BONES, prototype.animationData.totalBoneCount);
_animationBufferToTextureComputeShader.SetInt(GPUICrowdConstants.CrowdKernelPoperties.INSTANCE_COUNT, runtimeData.instanceCount);
_animationBufferToTextureComputeShader.SetInt(GPUInstancerConstants.VisibilityKernelPoperties.MAX_TEXTURE_SIZE, GPUInstancerConstants.TEXTURE_MAX_SIZE);
_animationBufferToTextureComputeShader.Dispatch(_animationBufferToTextureKernelID,
Mathf.CeilToInt(runtimeData.instanceCount / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT_2D),
Mathf.CeilToInt(prototype.animationData.totalBoneCount / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT_2D),
1);
}
#endregion Copy To Texture
}
}
public GPUICrowdPrototype DefineGameObjectAsCrowdPrototypeAtRuntime(GameObject prototypeGameObject, GPUICrowdAnimationData animationData, bool attachScript = true,
GPUICrowdPrototype copySettingsFrom = null)
{
if (!Application.isPlaying)
{
Debug.LogWarning("DefineGameObjectAsCrowdPrototypeAtRuntime method is designed to use at runtime. Prototype generation canceled.");
return null;
}
if (prefabList == null)
prefabList = new List<GameObject>();
GPUICrowdPrototype crowdPrototype = GPUICrowdUtility.GenerateCrowdPrototype(prototypeGameObject, false, attachScript, copySettingsFrom);
if (!prototypeList.Contains(crowdPrototype))
prototypeList.Add(crowdPrototype);
if (!prefabList.Contains(prototypeGameObject))
prefabList.Add(prototypeGameObject);
if (crowdPrototype.minCullingDistance < minCullingDistance)
crowdPrototype.minCullingDistance = minCullingDistance;
crowdPrototype.animationData = animationData;
return crowdPrototype;
}
public override void DeletePrototype(GPUInstancerPrototype prototype, bool removeSO = true)
{
GPUICrowdPrototype crowdPrototype = (GPUICrowdPrototype)prototype;
#if UNITY_EDITOR
if (removeSO && crowdPrototype.animationData != null)
{
if (crowdPrototype.animationData.animationTexture != null)
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(crowdPrototype.animationData.animationTexture));
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(crowdPrototype.animationData));
}
#endif
base.DeletePrototype(prototype, removeSO);
}
public override void AddPrefabInstance(GPUInstancerPrefab prefabInstance, bool automaticallyIncreaseBufferSize = false)
{
base.AddPrefabInstance(prefabInstance, automaticallyIncreaseBufferSize);
GPUICrowdPrefab crowdPrefab = (GPUICrowdPrefab)prefabInstance;
if (crowdPrefab.hasChildPrefabs)
{
foreach (GPUICrowdPrefab childPrefab in crowdPrefab.childCrowdPrefabs)
{
GPUInstancerRuntimeData runtimeData = GetRuntimeData(childPrefab.prefabPrototype);
if (runtimeData.bufferSize != crowdPrefab.runtimeData.bufferSize)
{
ExpandBufferSize(runtimeData, crowdPrefab.runtimeData.bufferSize);
GPUInstancerUtility.InitializeGPUBuffer(runtimeData);
}
runtimeData.instanceCount = crowdPrefab.runtimeData.instanceCount;
childPrefab.SetupPrefabInstance(runtimeData);
}
}
}
}
}
#else //GPU_INSTANCER
namespace GPUInstancer.CrowdAnimations
{
public class GPUICrowdManager : MonoBehaviour
{
}
}
#endif //GPU_INSTANCER