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 _animatorClipInfos = new List(); 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 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(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 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(); 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() == 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(); prefabList.RemoveAll(p => p == null); prefabList.RemoveAll(p => p.GetComponent() == 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(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(); 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(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(); 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