public void RenderBillboardCells() { Profiler.BeginSample("Draw billboards"); var farCullDistance = Mathf.RoundToInt(VegetationSettings.GetBillboardDistance()); var isPlaying = Application.isPlaying; var shadowCastingMode = VegetationSettings.GetBillboardShadowCastingMode(); var layer = VegetationSettings.GetLayer(VegetationType.Tree); var positionMatrix = Matrix4x4.TRS(FloatingOriginOffset, Quaternion.identity, Vector3.one); for (var i = 0; i <= VegetationStudioCameraList.Count - 1; i++) { if (!VegetationStudioCameraList[i].Enabled) { continue; } var targetCamera = VegetationStudioCameraList[i].RenderDirectToCamera ? VegetationStudioCameraList[i].SelectedCamera : null; if (!isPlaying) { targetCamera = null; } for (var j = 0; j <= VegetationStudioCameraList[i].BillboardJobCullingGroup.VisibleCellIndexList.Length - 1; j++) { var index = VegetationStudioCameraList[i].BillboardJobCullingGroup.VisibleCellIndexList[j]; var billboardCell = BillboardCellList[index]; for (var k = 0; k <= billboardCell.VegetationPackageBillboardInstancesList.Count - 1; k++) { for (var l = 0; l <= billboardCell.VegetationPackageBillboardInstancesList[k].BillboardInstanceList.Count - 1; l++) { var billboardInstance = billboardCell.VegetationPackageBillboardInstancesList[k] .BillboardInstanceList[l]; if (billboardInstance.Loaded && billboardInstance.InstanceCount > 0) { if (VegetationStudioCameraList[i].SelectedCamera == null) { continue; } var vegetationItemModelInfo = VegetationPackageProModelsList[k].VegetationItemModelList[l]; var vegetationItemInfoPro = VegetationPackageProList[k].VegetationInfoList[l]; if (!vegetationItemInfoPro.UseBillboards) { continue; } var camPos = VegetationStudioCameraList[i].SelectedCamera.transform.position; var renderDistanceFactor = vegetationItemInfoPro.RenderDistanceFactor; if (VegetationSettings.DisableRenderDistanceFactor) { renderDistanceFactor = 1; } var cullDistance = Mathf.RoundToInt(VegetationSettings.GetTreeDistance() * renderDistanceFactor); if (vegetationItemModelInfo.BillboardLODFadeCrossfade) { cullDistance -= 10; } vegetationItemModelInfo.BillboardMaterial.SetVector(_cameraPositionID, camPos); MaterialPropertyBlock materialPropertyBlock = vegetationItemModelInfo.CameraBillboardMaterialPropertyBlockList[i]; materialPropertyBlock.SetInt(_cullDistanceID, VegetationStudioCameraList[i].RenderBillboardsOnly ? 0 : cullDistance); materialPropertyBlock.SetInt(_farCullDistanceID, farCullDistance); Graphics.DrawMesh(billboardInstance.Mesh, positionMatrix, vegetationItemModelInfo.BillboardMaterial, layer, targetCamera, 0, materialPropertyBlock, shadowCastingMode, true); } } } } } Profiler.EndSample(); }
void DrawCellsIndirectComputeShader() { Profiler.BeginSample("Draw instanced indirect vegetation"); float lodBias = QualitySettings.lodBias * VegetationSettings.LODDistanceFactor; Vector4 floatingOriginOffsetVector4 = new Vector4(FloatingOriginOffset.x, FloatingOriginOffset.y, FloatingOriginOffset.z, 0); Vector3 sunLightDirection = SunDirectionalLight ? SunDirectionalLight.transform.forward : new Vector3(0, 0, 0); float minBoundsHeight = VegetationSystemBounds.center.y - VegetationSystemBounds.extents.y; Vector3 planeOrigin = new Vector3(0, minBoundsHeight, 0); bool shadowCulling = (SunDirectionalLight != null); for (int i = 0; i <= VegetationStudioCameraList.Count - 1; i++) { if (!VegetationStudioCameraList[i].Enabled) { continue; } if (VegetationStudioCameraList[i].RenderBillboardsOnly) { continue; } SetFrustumCullingPlanes(VegetationStudioCameraList[i].SelectedCamera); var targetCamera = VegetationStudioCameraList[i].RenderDirectToCamera ? VegetationStudioCameraList[i].SelectedCamera : null; for (int j = 0; j <= VegetationPackageProList.Count - 1; j++) { for (int k = 0; k <= VegetationPackageProList[j].VegetationInfoList.Count - 1; k++) { VegetationItemInfoPro vegetationItemInfo = VegetationPackageProList[j].VegetationInfoList[k]; if (vegetationItemInfo.VegetationRenderMode != VegetationRenderMode.InstancedIndirect) { continue; } VegetationItemModelInfo vegetationItemModelInfo = VegetationPackageProModelsList[j].VegetationItemModelList[k]; float vegetationItemCullDistance; float renderDistanceFactor = vegetationItemModelInfo.VegetationItemInfo.RenderDistanceFactor; if (VegetationSettings.DisableRenderDistanceFactor) { renderDistanceFactor = 1; } //if (vegetationItemModelInfo.DistanceBand == 0) if (vegetationItemModelInfo.VegetationItemInfo.VegetationType == VegetationType.Tree || vegetationItemModelInfo.VegetationItemInfo.VegetationType == VegetationType.LargeObjects) { vegetationItemCullDistance = VegetationSettings.GetTreeDistance() * renderDistanceFactor; } else { vegetationItemCullDistance = VegetationSettings.GetVegetationDistance() * renderDistanceFactor; } ShadowCastingMode shadowCastingMode = VegetationSettings.GetShadowCastingMode(vegetationItemInfo.VegetationType); if (vegetationItemInfo.DisableShadows) { shadowCastingMode = ShadowCastingMode.Off; } bool useShadowCulling = shadowCulling && shadowCastingMode == ShadowCastingMode.On; useShadowCulling = useShadowCulling && vegetationItemModelInfo.DistanceBand == 1; LayerMask layer = VegetationSettings.GetLayer(vegetationItemInfo.VegetationType); int totalInstanceCount = 0; _hasBufferList.Clear(); for (int l = 0; l <= VegetationStudioCameraList[i].JobCullingGroup.VisibleCellIndexList.Length - 1; l++) { int potentialVisibleCellIndex = VegetationStudioCameraList[i].JobCullingGroup.VisibleCellIndexList[l]; VegetationCell vegetationCell = VegetationStudioCameraList[i] .PotentialVisibleCellList[potentialVisibleCellIndex]; BoundingSphereInfo boundingSphereInfo = VegetationStudioCameraList[i] .GetBoundingSphereInfo(potentialVisibleCellIndex); int vegetationItemDistanceBand = vegetationItemModelInfo.DistanceBand; if (boundingSphereInfo.CurrentDistanceBand > vegetationItemDistanceBand) { continue; } if (vegetationCell.VegetationPackageInstancesList[j].VegetationItemMatrixList[k].Length == 0) { continue; } ComputeBufferInfo computeBufferInfo = vegetationCell.VegetationPackageInstancesList[j] .VegetationItemComputeBufferList[k]; if (!computeBufferInfo.Created) { continue; } _hasBufferList.Add(vegetationCell); } if (_hasBufferList.Count == 0) { continue; } int buffercount = 15; for (int m = 0; m <= _hasBufferList.Count - 1; m++) { totalInstanceCount += _hasBufferList[m].VegetationPackageInstancesList[j] .VegetationItemMatrixList[k].Length; } if (totalInstanceCount == 0) { continue; } CameraComputeBuffers cameraComputeBuffers = vegetationItemModelInfo.CameraComputeBufferList[i]; if (totalInstanceCount > cameraComputeBuffers.MergeBuffer.count) { cameraComputeBuffers.UpdateComputeBufferSize(totalInstanceCount + 5000); } cameraComputeBuffers.MergeBuffer.SetCounterValue(0); MergeBufferShader.SetBuffer(MergeBufferKernelHandle, _mergeBufferID, cameraComputeBuffers.MergeBuffer); for (int m = 0; m <= _hasBufferList.Count - 1; m += buffercount) { int instanceCount0 = _hasBufferList[m].VegetationPackageInstancesList[j] .VegetationItemMatrixList[k].Length; for (int n = 1; n <= buffercount - 1; n++) { if (m + n < _hasBufferList.Count) { int tempInstanceCount = _hasBufferList[m + n].VegetationPackageInstancesList[j] .VegetationItemMatrixList[k].Length; if (tempInstanceCount > instanceCount0) { instanceCount0 = tempInstanceCount; } } } // ReSharper disable once RedundantCast int threadGroups = Mathf.CeilToInt((float)instanceCount0 / 32f); if (threadGroups == 0) { continue; } SetComputeShaderBuffer(_mergeSourceBuffer0ID, _mergeInstanceCount0ID, m, j, k); SetComputeShaderBuffer(_mergeSourceBuffer1ID, _mergeInstanceCount1ID, m + 1, j, k); SetComputeShaderBuffer(_mergeSourceBuffer2ID, _mergeInstanceCount2ID, m + 2, j, k); SetComputeShaderBuffer(_mergeSourceBuffer3ID, _mergeInstanceCount3ID, m + 3, j, k); SetComputeShaderBuffer(_mergeSourceBuffer4ID, _mergeInstanceCount4ID, m + 4, j, k); SetComputeShaderBuffer(_mergeSourceBuffer5ID, _mergeInstanceCount5ID, m + 5, j, k); SetComputeShaderBuffer(_mergeSourceBuffer6ID, _mergeInstanceCount6ID, m + 6, j, k); SetComputeShaderBuffer(_mergeSourceBuffer7ID, _mergeInstanceCount7ID, m + 7, j, k); SetComputeShaderBuffer(_mergeSourceBuffer8ID, _mergeInstanceCount8ID, m + 8, j, k); SetComputeShaderBuffer(_mergeSourceBuffer9ID, _mergeInstanceCount9ID, m + 9, j, k); SetComputeShaderBuffer(_mergeSourceBuffer10ID, _mergeInstanceCount10ID, m + 10, j, k); SetComputeShaderBuffer(_mergeSourceBuffer11ID, _mergeInstanceCount11ID, m + 11, j, k); SetComputeShaderBuffer(_mergeSourceBuffer12ID, _mergeInstanceCount12ID, m + 12, j, k); SetComputeShaderBuffer(_mergeSourceBuffer13ID, _mergeInstanceCount13ID, m + 13, j, k); SetComputeShaderBuffer(_mergeSourceBuffer14ID, _mergeInstanceCount14ID, m + 14, j, k); MergeBufferShader.Dispatch(MergeBufferKernelHandle, threadGroups, 1, 1); } for (int n = 0; n <= vegetationItemModelInfo.VegetationMeshLod0.subMeshCount - 1; n++) { ComputeBuffer.CopyCount(cameraComputeBuffers.MergeBuffer, cameraComputeBuffers.ArgsBufferMergedLOD0List[n], sizeof(uint) * 1); } int threadGroupsFrustum = Mathf.CeilToInt(totalInstanceCount / 32f); if (threadGroupsFrustum == 0) { continue; } cameraComputeBuffers.VisibleBufferLOD0.SetCounterValue(0); cameraComputeBuffers.VisibleBufferLOD1.SetCounterValue(0); cameraComputeBuffers.VisibleBufferLOD2.SetCounterValue(0); cameraComputeBuffers.VisibleBufferLOD3.SetCounterValue(0); cameraComputeBuffers.ShadowBufferLOD0.SetCounterValue(0); cameraComputeBuffers.ShadowBufferLOD1.SetCounterValue(0); cameraComputeBuffers.ShadowBufferLOD2.SetCounterValue(0); cameraComputeBuffers.ShadowBufferLOD3.SetCounterValue(0); bool useLODs = true; FrusumMatrixShader.SetFloat(_cullFarStartID, vegetationItemCullDistance); FrusumMatrixShader.SetVector(_floatingOriginOffsetID, floatingOriginOffsetVector4); FrusumMatrixShader.SetBuffer(FrustumKernelHandle, _sourceBufferID, cameraComputeBuffers.MergeBuffer); FrusumMatrixShader.SetBuffer(FrustumKernelHandle, _visibleBufferLod0ID, cameraComputeBuffers.VisibleBufferLOD0); FrusumMatrixShader.SetBuffer(FrustumKernelHandle, _visibleBufferLod1ID, cameraComputeBuffers.VisibleBufferLOD1); FrusumMatrixShader.SetBuffer(FrustumKernelHandle, _visibleBufferLod2ID, cameraComputeBuffers.VisibleBufferLOD2); FrusumMatrixShader.SetBuffer(FrustumKernelHandle, _visibleBufferLod3ID, cameraComputeBuffers.VisibleBufferLOD3); FrusumMatrixShader.SetBuffer(FrustumKernelHandle, _shadowBufferLod0ID, cameraComputeBuffers.ShadowBufferLOD0); FrusumMatrixShader.SetBuffer(FrustumKernelHandle, _shadowBufferLod1ID, cameraComputeBuffers.ShadowBufferLOD1); FrusumMatrixShader.SetBuffer(FrustumKernelHandle, _shadowBufferLod2ID, cameraComputeBuffers.ShadowBufferLOD2); FrusumMatrixShader.SetBuffer(FrustumKernelHandle, _shadowBufferLod3ID, cameraComputeBuffers.ShadowBufferLOD3); FrusumMatrixShader.SetInt(_instanceCountID, totalInstanceCount); FrusumMatrixShader.SetBool(_useLodsID, useLODs); FrusumMatrixShader.SetBool(_noFrustumCullingID, VegetationStudioCameraList[i].CameraCullingMode == CameraCullingMode.Complete360); FrusumMatrixShader.SetBool(_shadowCullingID, useShadowCulling); FrusumMatrixShader.SetFloat(_boundingSphereRadiusID, vegetationItemModelInfo.BoundingSphereRadius); FrusumMatrixShader.SetFloat(_lod1Distance, vegetationItemModelInfo.LOD1Distance); FrusumMatrixShader.SetFloat(_lod2Distance, vegetationItemModelInfo.LOD2Distance); FrusumMatrixShader.SetFloat(_lod3Distance, vegetationItemModelInfo.LOD3Distance); FrusumMatrixShader.SetVector(_lightDirection, sunLightDirection); FrusumMatrixShader.SetVector(_planeOrigin, planeOrigin); FrusumMatrixShader.SetVector(_boundsSize, vegetationItemModelInfo.VegetationItemInfo.Bounds.size); FrusumMatrixShader.SetFloat(_lodFactor, vegetationItemInfo.LODFactor); FrusumMatrixShader.SetFloat(_lodBias, lodBias * 2); FrusumMatrixShader.SetFloat(_lodFadeDistance, 10); FrusumMatrixShader.SetInt(_lodCount, vegetationItemModelInfo.LODCount); FrusumMatrixShader.Dispatch(FrustumKernelHandle, threadGroupsFrustum, 1, 1); for (int n = 0; n <= vegetationItemModelInfo.VegetationMeshLod0.subMeshCount - 1; n++) { ComputeBuffer.CopyCount(cameraComputeBuffers.VisibleBufferLOD0, cameraComputeBuffers.ArgsBufferMergedLOD0List[n], sizeof(uint) * 1); ComputeBuffer.CopyCount(cameraComputeBuffers.ShadowBufferLOD0, cameraComputeBuffers.ShadowArgsBufferMergedLOD0List[n], sizeof(uint) * 1); } if (useLODs) { for (int n = 0; n <= vegetationItemModelInfo.VegetationMeshLod1.subMeshCount - 1; n++) { ComputeBuffer.CopyCount(cameraComputeBuffers.VisibleBufferLOD1, cameraComputeBuffers.ArgsBufferMergedLOD1List[n], sizeof(uint) * 1); ComputeBuffer.CopyCount(cameraComputeBuffers.ShadowBufferLOD1, cameraComputeBuffers.ShadowArgsBufferMergedLOD1List[n], sizeof(uint) * 1); } for (int n = 0; n <= vegetationItemModelInfo.VegetationMeshLod2.subMeshCount - 1; n++) { ComputeBuffer.CopyCount(cameraComputeBuffers.VisibleBufferLOD2, cameraComputeBuffers.ArgsBufferMergedLOD2List[n], sizeof(uint) * 1); ComputeBuffer.CopyCount(cameraComputeBuffers.ShadowBufferLOD2, cameraComputeBuffers.ShadowArgsBufferMergedLOD2List[n], sizeof(uint) * 1); } for (int n = 0; n <= vegetationItemModelInfo.VegetationMeshLod3.subMeshCount - 1; n++) { ComputeBuffer.CopyCount(cameraComputeBuffers.VisibleBufferLOD3, cameraComputeBuffers.ArgsBufferMergedLOD3List[n], sizeof(uint) * 1); ComputeBuffer.CopyCount(cameraComputeBuffers.ShadowBufferLOD3, cameraComputeBuffers.ShadowArgsBufferMergedLOD3List[n], sizeof(uint) * 1); } } //TODO calculate bounds one for each LOD float boundsDistance = vegetationItemCullDistance * 2 + vegetationItemModelInfo.BoundingSphereRadius; Bounds cellBounds = new Bounds(VegetationStudioCameraList[i].SelectedCamera.transform.position, new Vector3(boundsDistance, boundsDistance, boundsDistance)); RenderVegetationItemLODIndirect(vegetationItemModelInfo, cellBounds, 0, i, targetCamera, shadowCastingMode, layer, false); if (shadowCastingMode == ShadowCastingMode.On) { RenderVegetationItemLODIndirect(vegetationItemModelInfo, cellBounds, 0, i, targetCamera, ShadowCastingMode.ShadowsOnly, layer, true); } if (useLODs) { if (vegetationItemModelInfo.LODCount > 1) { RenderVegetationItemLODIndirect(vegetationItemModelInfo, cellBounds, 1, i, targetCamera, shadowCastingMode, layer, false); if (shadowCastingMode == ShadowCastingMode.On) { RenderVegetationItemLODIndirect(vegetationItemModelInfo, cellBounds, 1, i, targetCamera, ShadowCastingMode.ShadowsOnly, layer, true); } } if (vegetationItemModelInfo.LODCount > 2) { RenderVegetationItemLODIndirect(vegetationItemModelInfo, cellBounds, 2, i, targetCamera, shadowCastingMode, layer, false); if (shadowCastingMode == ShadowCastingMode.On) { RenderVegetationItemLODIndirect(vegetationItemModelInfo, cellBounds, 2, i, targetCamera, ShadowCastingMode.ShadowsOnly, layer, true); } } if (vegetationItemModelInfo.LODCount > 3) { RenderVegetationItemLODIndirect(vegetationItemModelInfo, cellBounds, 3, i, targetCamera, shadowCastingMode, layer, false); if (shadowCastingMode == ShadowCastingMode.On) { RenderVegetationItemLODIndirect(vegetationItemModelInfo, cellBounds, 3, i, targetCamera, ShadowCastingMode.ShadowsOnly, layer, true); } } } } } } Profiler.EndSample(); }