Untitled
unknown
csharp
2 years ago
40 kB
6
Indexable
using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using System.Threading; #if UNITY_EDITOR using UnityEditor; #endif namespace GPUInstancer { public abstract class GPUInstancerManager : MonoBehaviour { public List<GPUInstancerPrototype> prototypeList = new List<GPUInstancerPrototype>(); public bool autoSelectCamera = true; public GPUInstancerCameraData cameraData = new GPUInstancerCameraData(null); public bool useFloatingOriginHandler = false; public bool applyFloatingOriginRotationAndScale = false; public Transform floatingOriginTransform; [NonSerialized] public GPUInstancerFloatingOriginHandler floatingOriginHandler; [NonSerialized] public List<GPUInstancerRuntimeData> runtimeDataList; [NonSerialized] public Bounds instancingBounds; public bool isFrustumCulling = true; public bool isOcclusionCulling = true; public float minCullingDistance = 0; protected GPUInstancerSpatialPartitioningData<GPUInstancerCell> spData; public static List<GPUInstancerManager> activeManagerList; public static bool showRenderedAmount; protected static ComputeShader _cameraComputeShader; protected static ComputeShader _cameraComputeShaderVR; protected static int[] _cameraComputeKernelIDs; protected static ComputeShader _visibilityComputeShader; protected static int[] _instanceVisibilityComputeKernelIDs; protected static ComputeShader _bufferToTextureComputeShader; protected static int _bufferToTextureComputeKernelID; protected static ComputeShader _argsBufferComputeShader; protected static int _argsBufferDoubleInstanceCountComputeKernelID; #if UNITY_EDITOR public List<GPUInstancerPrototype> selectedPrototypeList; [NonSerialized] public GPUInstancerEditorSimulator gpuiSimulator; public bool isPrototypeTextMode = false; public bool showSceneSettingsBox = true; public bool showPrototypeBox = true; public bool showAdvancedBox = false; public bool showHelpText = false; public bool showDebugBox = true; public bool showGlobalValuesBox = true; public bool showRegisteredPrefabsBox = true; public bool showPrototypesBox = true; public bool keepSimulationLive = false; public bool updateSimulation = true; #endif public class GPUIThreadData { public Thread thread; public object parameter; } public static int maxThreads = 3; public readonly List<Thread> activeThreads = new List<Thread>(); public readonly Queue<GPUIThreadData> threadStartQueue = new Queue<GPUIThreadData>(); public readonly Queue<Action> threadQueue = new Queue<Action>(); // Tree variables public static int lastTreePositionUpdate; public static GameObject treeProxyParent; public static Dictionary<GameObject, Transform> treeProxyList; // Dict[TreePrefab, TreeProxyGO] // Time management public static int lastDrawCallFrame; public static float lastDrawCallTime; public static float timeSinceLastDrawCall; // Global Wind protected static Vector4 _windVector = Vector4.zero; [NonSerialized] protected bool isInitial = true; [NonSerialized] public bool isInitialized = false; #if UNITY_EDITOR && UNITY_2017_2_OR_NEWER [NonSerialized] public PlayModeStateChange playModeState; #endif [NonSerialized] public bool isQuiting = false; [NonSerialized] public Dictionary<GPUInstancerPrototype, GPUInstancerRuntimeData> runtimeDataDictionary; public LayerMask layerMask = ~0; public bool lightProbeDisabled = false; #region MonoBehaviour Methods public virtual void Awake() { #if UNITY_EDITOR if (Application.isBatchMode) return; #endif GPUInstancerConstants.gpuiSettings.SetDefultBindings(); GPUInstancerUtility.SetPlatformDependentVariables(); #if UNITY_EDITOR // BKOM Modification to 3rd-party code - sgravel 2021-10-28 // Remove this line to prevent the editor from checking out all prototypes on editor launch // if (!Application.isPlaying) // CheckPrototypeChanges(); #endif if (Application.isPlaying && activeManagerList == null) activeManagerList = new List<GPUInstancerManager>(); if (SystemInfo.supportsComputeShaders) { if (_visibilityComputeShader == null) { switch (GPUInstancerUtility.matrixHandlingType) { case GPUIMatrixHandlingType.MatrixAppend: _visibilityComputeShader = (ComputeShader)Resources.Load(GPUInstancerConstants.VISIBILITY_COMPUTE_RESOURCE_PATH_VULKAN); GPUInstancerConstants.DETAIL_STORE_INSTANCE_DATA = true; GPUInstancerConstants.COMPUTE_MAX_LOD_BUFFER = 2; break; case GPUIMatrixHandlingType.CopyToTexture: _visibilityComputeShader = (ComputeShader)Resources.Load(GPUInstancerConstants.VISIBILITY_COMPUTE_RESOURCE_PATH); _bufferToTextureComputeShader = (ComputeShader)Resources.Load(GPUInstancerConstants.BUFFER_TO_TEXTURE_COMPUTE_RESOURCE_PATH); _bufferToTextureComputeKernelID = _bufferToTextureComputeShader.FindKernel(GPUInstancerConstants.BUFFER_TO_TEXTURE_KERNEL); break; default: _visibilityComputeShader = (ComputeShader)Resources.Load(GPUInstancerConstants.VISIBILITY_COMPUTE_RESOURCE_PATH); break; } _instanceVisibilityComputeKernelIDs = new int[GPUInstancerConstants.VISIBILITY_COMPUTE_KERNELS.Length]; for (int i = 0; i < _instanceVisibilityComputeKernelIDs.Length; i++) _instanceVisibilityComputeKernelIDs[i] = _visibilityComputeShader.FindKernel(GPUInstancerConstants.VISIBILITY_COMPUTE_KERNELS[i]); GPUInstancerConstants.TEXTURE_MAX_SIZE = SystemInfo.maxTextureSize; _cameraComputeShader = (ComputeShader)Resources.Load(GPUInstancerConstants.CAMERA_COMPUTE_RESOURCE_PATH); _cameraComputeShaderVR = (ComputeShader)Resources.Load(GPUInstancerConstants.CAMERA_VR_COMPUTE_RESOURCE_PATH); _cameraComputeKernelIDs = new int[GPUInstancerConstants.CAMERA_COMPUTE_KERNELS.Length]; for (int i = 0; i < _cameraComputeKernelIDs.Length; i++) _cameraComputeKernelIDs[i] = _cameraComputeShader.FindKernel(GPUInstancerConstants.CAMERA_COMPUTE_KERNELS[i]); _argsBufferComputeShader = Resources.Load<ComputeShader>(GPUInstancerConstants.ARGS_BUFFER_COMPUTE_RESOURCE_PATH); _argsBufferDoubleInstanceCountComputeKernelID = _argsBufferComputeShader.FindKernel(GPUInstancerConstants.ARGS_BUFFER_DOUBLE_INSTANCE_COUNT_KERNEL); } GPUInstancerConstants.SetupComputeRuntimeModification(); GPUInstancerConstants.SetupComputeSetDataPartial(); } else if (Application.isPlaying) { Debug.LogError("Target Graphics API does not support Compute Shaders. Please refer to Minimum Requirements on GPUInstancer/ReadMe.txt for detailed information."); this.enabled = false; } showRenderedAmount = false; InitializeCameraData(); #if UNITY_EDITOR && UNITY_2017_2_OR_NEWER EditorApplication.playModeStateChanged -= HandlePlayModeStateChanged; EditorApplication.playModeStateChanged += HandlePlayModeStateChanged; #endif } public virtual void Start() { if (Application.isPlaying && SystemInfo.supportsComputeShaders) { SetupOcclusionCulling(cameraData); } #if UNITY_EDITOR // Sometimes Awake is not called on Editor Mode after compilation else if (_instanceVisibilityComputeKernelIDs == null) Awake(); #endif } public virtual void OnEnable() { #if UNITY_EDITOR if (gpuiSimulator == null) gpuiSimulator = new GPUInstancerEditorSimulator(this); #endif if (!Application.isPlaying) return; if (cameraData.mainCamera == null) { InitializeCameraData(); if (cameraData.mainCamera == null) Debug.LogWarning(GPUInstancerConstants.ERRORTEXT_cameraNotFound); } if (activeManagerList != null && !activeManagerList.Contains(this)) activeManagerList.Add(this); if (SystemInfo.supportsComputeShaders) { if (GPUInstancerConstants.gpuiSettings == null || GPUInstancerConstants.gpuiSettings.shaderBindings == null) Debug.LogWarning("No shader bindings file was supplied. Instancing will terminate!"); if (runtimeDataList == null || runtimeDataList.Count == 0) InitializeRuntimeDataAndBuffers(); isInitial = true; } if (useFloatingOriginHandler && floatingOriginTransform != null) { if (floatingOriginHandler == null) { floatingOriginHandler = floatingOriginTransform.gameObject.GetComponent<GPUInstancerFloatingOriginHandler>(); if (floatingOriginHandler == null) floatingOriginHandler = floatingOriginTransform.gameObject.AddComponent<GPUInstancerFloatingOriginHandler>(); } floatingOriginHandler.applyRotationAndScale = applyFloatingOriginRotationAndScale; if (floatingOriginHandler.gPUIManagers == null) floatingOriginHandler.gPUIManagers = new List<GPUInstancerManager>(); if (!floatingOriginHandler.gPUIManagers.Contains(this)) floatingOriginHandler.gPUIManagers.Add(this); } } public virtual void Update() { ClearCompletedThreads(); while (threadStartQueue.Count > 0 && activeThreads.Count < maxThreads) { GPUIThreadData threadData = threadStartQueue.Dequeue(); threadData.thread.Start(threadData.parameter); activeThreads.Add(threadData.thread); } if (threadQueue.Count > 0) { Action action = threadQueue.Dequeue(); if (action != null) action.Invoke(); } if (Application.isPlaying && treeProxyParent && lastTreePositionUpdate != Time.frameCount && cameraData.mainCamera != null) { treeProxyParent.transform.position = cameraData.mainCamera.transform.position; treeProxyParent.transform.rotation = cameraData.mainCamera.transform.rotation; lastTreePositionUpdate = Time.frameCount; } } public virtual void LateUpdate() { #if UNITY_EDITOR if (!Application.isPlaying) { // BKOM Modification to 3rd-party code - cmacdougall 2021-06-10 // Remove this line to prevent the editor from periodically freezing // CheckPrototypeChanges(); } else { #endif if (cameraData.mainCamera != null) { UpdateTreeMPB(); UpdateBuffers(cameraData); } #if UNITY_EDITOR } #endif } public virtual void OnDestroy() { } public virtual void Reset() { GPUInstancerConstants.gpuiSettings.SetDefultBindings(); #if UNITY_EDITOR // BKOM Modification to 3rd-party code - sgravel 2021-10-28 // Remove this line to prevent the editor from checking out all prototypes on editor launch //CheckPrototypeChanges(); #endif } public virtual void OnDisable() // could also be OnDestroy, but OnDestroy seems to be too late to prevent buffer leaks. { if (activeManagerList != null) activeManagerList.Remove(this); ClearInstancingData(); #if UNITY_EDITOR if (gpuiSimulator != null) { gpuiSimulator.ClearEditorUpdates(); gpuiSimulator = null; } #endif if (floatingOriginHandler != null && floatingOriginHandler.gPUIManagers != null && floatingOriginHandler.gPUIManagers.Contains(this)) { floatingOriginHandler.gPUIManagers.Remove(this); } } private void OnApplicationQuit() { isQuiting = true; } #endregion MonoBehaviour Methods #region Virtual Methods public virtual void ClearInstancingData() { GPUInstancerUtility.ReleaseInstanceBuffers(runtimeDataList); GPUInstancerUtility.ReleaseSPBuffers(spData); if (runtimeDataList != null) runtimeDataList.Clear(); if (runtimeDataDictionary != null) runtimeDataDictionary.Clear(); spData = null; threadStartQueue.Clear(); threadQueue.Clear(); isInitialized = false; } public virtual void GeneratePrototypes(bool forceNew = false) { ClearInstancingData(); if (forceNew || prototypeList == null) prototypeList = new List<GPUInstancerPrototype>(); else prototypeList.RemoveAll(p => p == null); GPUInstancerConstants.gpuiSettings.SetDefultBindings(); } #if UNITY_EDITOR // BKOM Modification to 3rd-party code -fchene 2021-07-14 // Added the attribute to replace the check on update [ContextMenu("Check Prototype Changes")] public virtual void CheckPrototypeChanges() { GPUInstancerConstants.gpuiSettings.SetDefultBindings(); 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) { GPUInstancerUtility.GenerateInstancedShadersForGameObject(prototype); if (string.IsNullOrEmpty(prototype.warningText)) { if (prototype.PrefabObject.GetComponentInChildren<MeshRenderer>() == null) { prototype.warningText = "Prefab object does not contain any Mesh Renderers."; } } } else { if (GPUInstancerConstants.gpuiSettings.IsStandardRenderPipeline()) GPUInstancerConstants.gpuiSettings.AddShaderVariantToCollection(GPUInstancerConstants.SHADER_GPUI_FOLIAGE); else if (GPUInstancerConstants.gpuiSettings.isURP) { if (Shader.Find(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_URP) != null) GPUInstancerConstants.gpuiSettings.AddShaderVariantToCollection(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_URP); } else if (GPUInstancerConstants.gpuiSettings.isLWRP) { if (Shader.Find(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_LWRP) != null) GPUInstancerConstants.gpuiSettings.AddShaderVariantToCollection(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_LWRP); } else if (GPUInstancerConstants.gpuiSettings.isHDRP) { if (Shader.Find(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_HDRP) != null) GPUInstancerConstants.gpuiSettings.AddShaderVariantToCollection(GPUInstancerConstants.SHADER_GPUI_FOLIAGE_HDRP); } } } } if (GPUInstancerConstants.gpuiSettings != null && GPUInstancerConstants.gpuiSettings.billboardAtlasBindings != null) { GPUInstancerConstants.gpuiSettings.billboardAtlasBindings.ClearEmptyBillboardAtlases(); //foreach (GPUInstancerPrototype prototype in prototypeList) //{ // if (prototype.prefabObject != null && prototype.useGeneratedBillboard && // (prototype.billboard == null || prototype.billboard.albedoAtlasTexture == null || prototype.billboard.normalAtlasTexture == null)) // GPUInstancerUtility.GeneratePrototypeBillboard(prototype, billboardAtlasBindings); //} } } //----------------------------------BKOM MODIFICATIONS------------------------------------------------ [ContextMenu ("Sort Items")] public virtual void SortItems () { prototypeList.Sort ((p1, p2) => { return p1.name.CompareTo (p2.name); }); } //------------------------------END BKOM MODIFICATIONS------------------------------------------------ #endif public virtual void InitializeRuntimeDataAndBuffers(bool forceNew = true) { GPUInstancerUtility.SetPlatformDependentVariables(); if (forceNew || !isInitialized) { instancingBounds = new Bounds(Vector3.zero, Vector3.one * GPUInstancerConstants.gpuiSettings.instancingBoundsSize); GPUInstancerUtility.ReleaseInstanceBuffers(runtimeDataList); GPUInstancerUtility.ReleaseSPBuffers(spData); if (runtimeDataList != null) runtimeDataList.Clear(); else runtimeDataList = new List<GPUInstancerRuntimeData>(); if (runtimeDataDictionary != null) runtimeDataDictionary.Clear(); else runtimeDataDictionary = new Dictionary<GPUInstancerPrototype, GPUInstancerRuntimeData>(); if (prototypeList == null) prototypeList = new List<GPUInstancerPrototype>(); } } public virtual void InitializeSpatialPartitioning() { } public virtual void UpdateSpatialPartitioningCells(GPUInstancerCameraData renderingCameraData) { } public virtual void DeletePrototype(GPUInstancerPrototype prototype, bool removeSO = true) { #if UNITY_EDITOR UnityEditor.Undo.RecordObject(this, "Delete prototype"); #endif prototypeList.Remove(prototype); if (removeSO && prototype.useGeneratedBillboard && prototype.billboard != null) { if (GPUInstancerConstants.gpuiSettings.billboardAtlasBindings.DeleteBillboardTextures(prototype, false)) prototype.billboard = null; } } public virtual void RemoveInstancesInsideBounds(Bounds bounds, float offset, List<GPUInstancerPrototype> prototypeFilter = null) { if (runtimeDataList != null) { foreach (GPUInstancerRuntimeData rd in runtimeDataList) { if (prototypeFilter != null && !prototypeFilter.Contains(rd.prototype)) continue; GPUInstancerUtility.RemoveInstancesInsideBounds(rd.transformationMatrixVisibilityBuffer, bounds.center, bounds.extents, offset); } } } public virtual void RemoveInstancesInsideCollider(Collider collider, float offset, List<GPUInstancerPrototype> prototypeFilter = null) { if (runtimeDataList != null) { foreach (GPUInstancerRuntimeData rd in runtimeDataList) { if (prototypeFilter != null && !prototypeFilter.Contains(rd.prototype)) continue; if (collider is BoxCollider) GPUInstancerUtility.RemoveInstancesInsideBoxCollider(rd.transformationMatrixVisibilityBuffer, (BoxCollider)collider, offset); else if (collider is SphereCollider) GPUInstancerUtility.RemoveInstancesInsideSphereCollider(rd.transformationMatrixVisibilityBuffer, (SphereCollider)collider, offset); else if (collider is CapsuleCollider) GPUInstancerUtility.RemoveInstancesInsideCapsuleCollider(rd.transformationMatrixVisibilityBuffer, (CapsuleCollider)collider, offset); else GPUInstancerUtility.RemoveInstancesInsideBounds(rd.transformationMatrixVisibilityBuffer, collider.bounds.center, collider.bounds.extents, offset); } } } public virtual void SetGlobalPositionOffset(Vector3 offsetPosition) { } public virtual void SetGlobalMatrixOffset(Matrix4x4 offsetMatrix) { } #endregion Virtual Methods #region Public Methods public void ClearCompletedThreads() { if (activeThreads.Count > 0) { for (int i = activeThreads.Count - 1; i >= 0; i--) { if (!activeThreads[i].IsAlive) activeThreads.RemoveAt(i); } } } public void InitializeCameraData() { if (autoSelectCamera || cameraData.mainCamera == null) cameraData.SetCamera(Camera.main); else cameraData.CalculateHalfAngle(); } public void SetupOcclusionCulling(GPUInstancerCameraData renderingCameraData) { if (renderingCameraData == null || renderingCameraData.mainCamera == null) return; #if UNITY_EDITOR if (renderingCameraData.mainCamera.name == GPUInstancerEditorSimulator.sceneViewCameraName || !Application.isPlaying) return; #endif if (isOcclusionCulling) { if (renderingCameraData.hiZOcclusionGenerator == null) { GPUInstancerHiZOcclusionGenerator hiZOcclusionGenerator = renderingCameraData.mainCamera.GetComponent<GPUInstancerHiZOcclusionGenerator>(); if (hiZOcclusionGenerator == null) hiZOcclusionGenerator = renderingCameraData.mainCamera.gameObject.AddComponent<GPUInstancerHiZOcclusionGenerator>(); renderingCameraData.hiZOcclusionGenerator = hiZOcclusionGenerator; renderingCameraData.hiZOcclusionGenerator.Initialize(renderingCameraData.mainCamera); } } } public void UpdateBuffers() { UpdateBuffers(cameraData); } public void UpdateBuffers(GPUInstancerCameraData renderingCameraData) { if (renderingCameraData != null && renderingCameraData.mainCamera != null && SystemInfo.supportsComputeShaders) { if (isOcclusionCulling && renderingCameraData.hiZOcclusionGenerator == null) SetupOcclusionCulling(renderingCameraData); renderingCameraData.CalculateCameraData(); instancingBounds.center = renderingCameraData.mainCamera.transform.position; if (lastDrawCallFrame != Time.frameCount) { lastDrawCallFrame = Time.frameCount; timeSinceLastDrawCall = Time.realtimeSinceStartup - lastDrawCallTime; lastDrawCallTime = Time.realtimeSinceStartup; } UpdateSpatialPartitioningCells(renderingCameraData); GPUInstancerUtility.UpdateGPUBuffers(GPUInstancerConstants.gpuiSettings.IsUseBothEyesVRCulling() ? _cameraComputeShaderVR : _cameraComputeShader, _cameraComputeKernelIDs, _visibilityComputeShader, _instanceVisibilityComputeKernelIDs, runtimeDataList, renderingCameraData, isFrustumCulling, isOcclusionCulling, showRenderedAmount, isInitial); isInitial = false; if (GPUInstancerUtility.matrixHandlingType == GPUIMatrixHandlingType.CopyToTexture) GPUInstancerUtility.DispatchBufferToTexture(runtimeDataList, _bufferToTextureComputeShader, _bufferToTextureComputeKernelID); #if GPUI_XR if (GPUInstancerConstants.gpuiSettings.isVREnabled && UnityEngine.XR.XRSettings.stereoRenderingMode == UnityEngine.XR.XRSettings.StereoRenderingMode.SinglePassInstanced) { for (int i = 0; i < runtimeDataList.Count; i++) { GPUInstancerRuntimeData runtimeData = runtimeDataList[i]; if (runtimeData == null || runtimeData.argsBuffer == null || runtimeData.argsBuffer.count == 0) continue; int count = runtimeData.argsBuffer.count / 5; _argsBufferComputeShader.SetBuffer(_argsBufferDoubleInstanceCountComputeKernelID, GPUInstancerConstants.VisibilityKernelPoperties.ARGS_BUFFER, runtimeData.argsBuffer); _argsBufferComputeShader.SetInt(GPUInstancerConstants.VisibilityKernelPoperties.COUNT, count); _argsBufferComputeShader.Dispatch(_argsBufferDoubleInstanceCountComputeKernelID, Mathf.CeilToInt(count / GPUInstancerConstants.COMPUTE_SHADER_THREAD_COUNT), 1, 1); } } #endif GPUInstancerUtility.GPUIDrawMeshInstancedIndirect(runtimeDataList, instancingBounds, renderingCameraData, layerMask, lightProbeDisabled); } } public void SetCamera(Camera camera) { if (cameraData == null) cameraData = new GPUInstancerCameraData(camera); else cameraData.SetCamera(camera); if (cameraData.hiZOcclusionGenerator != null) DestroyImmediate(cameraData.hiZOcclusionGenerator); if (isOcclusionCulling) { cameraData.hiZOcclusionGenerator = cameraData.mainCamera.GetComponent<GPUInstancerHiZOcclusionGenerator>(); if (cameraData.hiZOcclusionGenerator == null) { cameraData.hiZOcclusionGenerator = cameraData.mainCamera.gameObject.AddComponent<GPUInstancerHiZOcclusionGenerator>(); } cameraData.hiZOcclusionGenerator.Initialize(cameraData.mainCamera); } } public ComputeBuffer GetTransformDataBuffer(GPUInstancerPrototype prototype) { GPUInstancerRuntimeData runtimeData = GetRuntimeData(prototype); if (runtimeData != null) return runtimeData.transformationMatrixVisibilityBuffer; return null; } public void SetLODBias(float newLODBias, List<GPUInstancerPrototype> prototypeFilter) { if (runtimeDataList == null || newLODBias <= 0) return; foreach (GPUInstancerRuntimeData runtimeData in runtimeDataList) { if (runtimeData == null || runtimeData.lodBiasApplied <= 0 || runtimeData.lodBiasApplied == newLODBias || runtimeData.instanceLODs == null || runtimeData.instanceLODs.Count == 0 || (prototypeFilter != null && !prototypeFilter.Contains(runtimeData.prototype))) continue; for (int i = 0; i < runtimeData.instanceLODs.Count; i++) { if (i < 4) runtimeData.lodSizes[i * 4] *= runtimeData.lodBiasApplied / newLODBias; else runtimeData.lodSizes[(i - 4) * 4 + 1] *= runtimeData.lodBiasApplied / newLODBias; } runtimeData.lodBiasApplied = newLODBias; } } #region Tree Instancing Methods public void UpdateTreeMPB() { if (treeProxyList != null && treeProxyList.Count > 0) { GPUInstancerPrototypeLOD rdLOD; GPUInstancerRenderer rdRenderer; MeshRenderer meshRenderer; Transform proxyTransform; foreach (GPUInstancerRuntimeData runtimeData in runtimeDataList) { // Do not set append buffers if there is no instance of this tree prototype on the terrain if (runtimeData.bufferSize == 0) continue; if (runtimeData.prototype.treeType != GPUInstancerTreeType.SpeedTree && runtimeData.prototype.treeType != GPUInstancerTreeType.SpeedTree8) continue; proxyTransform = treeProxyList[runtimeData.prototype.PrefabObject]; if (!proxyTransform) continue; for (int lod = 0; lod < runtimeData.instanceLODs.Count; lod++) { if (proxyTransform.childCount <= lod) continue; rdLOD = runtimeData.instanceLODs[lod]; meshRenderer = proxyTransform.GetChild(lod).GetComponent<MeshRenderer>(); for (int r = 0; r < rdLOD.renderers.Count; r++) { rdRenderer = rdLOD.renderers[r]; //if (treeType == GPUInstancerTreeType.SoftOcclusionTree) //{ // // Soft occlusion shader wind parameters here. // // rdRenderer.mpb.SetFloat("_ShakeDisplacement", 0.8f); // continue; //} meshRenderer.GetPropertyBlock(rdRenderer.mpb); if (rdRenderer.shadowMPB != null) meshRenderer.GetPropertyBlock(rdRenderer.shadowMPB); } } GPUInstancerUtility.SetAppendBuffers(runtimeData); } } } // Wind workaround: public static void AddTreeProxy(GPUInstancerPrototype treePrototype, GPUInstancerRuntimeData runtimeData) { switch (treePrototype.treeType) { case GPUInstancerTreeType.SpeedTree: case GPUInstancerTreeType.SpeedTree8: if (treeProxyParent == null) { treeProxyParent = new GameObject("GPUI Tree Manager Proxy"); if (treeProxyList != null) treeProxyList.Clear(); } if (treeProxyList == null) { treeProxyList = new Dictionary<GameObject, Transform>(); // Dict[TreePrefab, TreeProxyGO] } else if (treeProxyList.ContainsKey(treePrototype.PrefabObject)) { if (treeProxyList[treePrototype.PrefabObject] == null) treeProxyList.Remove(treePrototype.PrefabObject); else return; } Mesh treeProxyMesh = new Mesh(); treeProxyMesh.name = "TreeProxyMesh"; GameObject treeProxyObjectParent = new GameObject(treeProxyList.Count + "_" + treePrototype.name); treeProxyObjectParent.transform.SetParent(treeProxyParent.transform); treeProxyObjectParent.transform.localPosition = Vector3.zero; treeProxyObjectParent.transform.localRotation = Quaternion.identity; treeProxyList.Add(treePrototype.PrefabObject, treeProxyObjectParent.transform); if (treePrototype.PrefabObject.GetComponent<LODGroup>() != null) { LOD[] speedTreeLODs = treePrototype.PrefabObject.GetComponent<LODGroup>().GetLODs(); for (int lod = 0; lod < speedTreeLODs.Length; lod++) { if (speedTreeLODs[lod].renderers[0].GetComponent<BillboardRenderer>()) continue; Material[] treeProxyMaterial = new Material[1] { new Material(Shader.Find(GPUInstancerConstants.SHADER_GPUI_TREE_PROXY)) }; InstantiateTreeProxyObject(speedTreeLODs[lod].renderers[0].gameObject, treeProxyObjectParent, treeProxyMaterial, treeProxyMesh, lod == 0); } } else { Material[] treeProxyMaterial = new Material[1] { new Material(Shader.Find(GPUInstancerConstants.SHADER_GPUI_TREE_PROXY)) }; InstantiateTreeProxyObject(treePrototype.PrefabObject, treeProxyObjectParent, treeProxyMaterial, treeProxyMesh, true); } break; case GPUInstancerTreeType.TreeCreatorTree: // no need to create a TreeCreator proxy - setting the global wind vector instead Shader.SetGlobalVector("_Wind", GetWindVector()); //Material[] treeCreatorProxyMaterials = new Material[2]; //treeCreatorProxyMaterials[0] = new Material(Shader.Find(GPUInstancerConstants.SHADER_GPUI_TREE_PROXY)); //treeCreatorProxyMaterials[1] = new Material(Shader.Find(GPUInstancerConstants.SHADER_GPUI_TREE_PROXY)); //InstantiateTreeProxyObject(treePrototype.prefabObject, treeProxyObjectParent, treeCreatorProxyMaterials, treeProxyMesh, true); break; } } public static void InstantiateTreeProxyObject(GameObject treePrefab, GameObject proxyObjectParent, Material[] proxyMaterials, Mesh proxyMesh, bool setBounds) { GameObject treeProxyObject = Instantiate(treePrefab, proxyObjectParent.transform); treeProxyObject.name = treePrefab.name; if (setBounds) proxyMesh.bounds = treeProxyObject.GetComponent<MeshFilter>().sharedMesh.bounds; // Setup Tree Proxy object mesh renderer. MeshRenderer treeProxyObjectMR = treeProxyObject.GetComponent<MeshRenderer>(); treeProxyObjectMR.shadowCastingMode = ShadowCastingMode.Off; treeProxyObjectMR.receiveShadows = false; treeProxyObjectMR.lightProbeUsage = LightProbeUsage.Off; for (int i = 0; i < proxyMaterials.Length; i++) { proxyMaterials[i].CopyPropertiesFromMaterial(treeProxyObjectMR.materials[i]); proxyMaterials[i].enableInstancing = true; } treeProxyObjectMR.sharedMaterials = proxyMaterials; treeProxyObjectMR.GetComponent<MeshFilter>().sharedMesh = proxyMesh; // Strip all unwanted components potentially on the tree prefab: Component[] allComponents = treeProxyObject.GetComponents(typeof(Component)); for (int i = 0; i < allComponents.Length; i++) { if (allComponents[i] is Transform || allComponents[i] is MeshFilter || allComponents[i] is MeshRenderer || allComponents[i] is Tree) continue; Destroy(allComponents[i]); } } #endregion Tree Instancing Methods #region Global Wind Methods public static Vector4 GetWindVector() { if (_windVector != Vector4.zero) return _windVector; UpdateSceneWind(); return _windVector; } public static void UpdateSceneWind() { WindZone[] sceneWindZones = FindObjectsOfType<WindZone>(); for (int i = 0; i < sceneWindZones.Length; i++) { if (sceneWindZones[i].mode == WindZoneMode.Directional) { _windVector = new Vector4(sceneWindZones[i].windTurbulence, sceneWindZones[i].windPulseMagnitude, sceneWindZones[i].windPulseFrequency, sceneWindZones[i].windMain); break; } } } #endregion Wind Methods public Exception threadException; public void LogThreadException() { Debug.LogException(threadException); } #if UNITY_EDITOR && UNITY_2017_2_OR_NEWER public void HandlePlayModeStateChanged(PlayModeStateChange state) { playModeState = state; } #endif public GPUInstancerRuntimeData GetRuntimeData(GPUInstancerPrototype prototype, bool logError = false) { GPUInstancerRuntimeData runtimeData = null; if (runtimeDataDictionary != null && !runtimeDataDictionary.TryGetValue(prototype, out runtimeData) && logError) Debug.LogError("Can not find runtime data for prototype: " + prototype + ". Please check if the prototype was added to the Manager and the initialize method was called."); return runtimeData; } #endregion Public Methods } }
Editor is loading...