internal static void BakeSelected() { manager.volumesSelected.Clear(); foreach (GameObject go in UnityEditor.Selection.gameObjects) { ProbeVolume probeVolume = go.GetComponent <ProbeVolume>(); if (probeVolume) { manager.volumesSelected.Add(probeVolume); } } foreach (ProbeVolume v in manager.volumes) { if (manager.volumesSelected.Contains(v)) { continue; } v.ForceBakingDisabled(); } UnityEditor.Lightmapping.BakeAsync(); }
private static bool ShouldDrawGizmos(ProbeVolume probeVolume) { if (ShaderConfig.s_ProbeVolumesEvaluationMode == ProbeVolumesEvaluationModes.Disabled) { return(false); } UnityEditor.SceneView sceneView = UnityEditor.SceneView.currentDrawingSceneView; if (sceneView == null) { sceneView = UnityEditor.SceneView.lastActiveSceneView; } if (sceneView != null && !sceneView.drawGizmos) { return(false); } if (!probeVolume.enabled) { return(false); } return(probeVolume.parameters.drawProbes); }
internal void RegisterVolume(ProbeVolume volume) { if (volumes.Contains(volume)) { return; } volumes.Add(volume); }
internal void DeRegisterVolume(ProbeVolume volume) { if (!volumes.Contains(volume)) { return; } volumes.Remove(volume); HDRenderPipeline hdrp = RenderPipelineManager.currentPipeline as HDRenderPipeline; if (hdrp != null) { hdrp.ReleaseProbeVolumeFromAtlas(volume); } }
private static void DrawProbes(ProbeVolume probeVolume, UnityEditor.GizmoType gizmoType) { if (!ShouldDrawGizmos(probeVolume)) { return; } probeVolume.OnValidate(); var pointMeshList = probeVolume.m_DebugProbePointMeshList; probeVolume.m_DebugMaterial.SetPass(8); foreach (Mesh debugMesh in pointMeshList) { Graphics.DrawMeshNow(debugMesh, Matrix4x4.identity); } }
internal void ReleaseProbeVolumeFromAtlas(ProbeVolume volume) { if (ShaderConfig.s_ProbeVolumesEvaluationMode == ProbeVolumesEvaluationModes.Disabled) { return; } if (!m_SupportProbeVolume) { return; } int key = volume.GetID(); probeVolumeAtlas.ReleaseTextureSlot(key); probeVolumeAtlasOctahedralDepth.ReleaseTextureSlot(key); }
private static bool ShouldDrawGizmos(ProbeVolume probeVolume) { UnityEditor.SceneView sceneView = UnityEditor.SceneView.currentDrawingSceneView; if (sceneView == null) { sceneView = UnityEditor.SceneView.lastActiveSceneView; } if (sceneView != null && !sceneView.drawGizmos) { return(false); } if (!probeVolume.enabled) { return(false); } return(probeVolume.parameters.drawProbes); }
private static ProbeVolumeSettingsKey ComputeProbeVolumeSettingsKeyFromProbeVolume(ProbeVolume probeVolume) { return(new ProbeVolumeSettingsKey { id = probeVolume.GetID(), position = probeVolume.transform.position, rotation = probeVolume.transform.rotation, size = probeVolume.parameters.size, resolutionX = probeVolume.parameters.resolutionX, resolutionY = probeVolume.parameters.resolutionY, resolutionZ = probeVolume.parameters.resolutionZ, backfaceTolerance = probeVolume.parameters.backfaceTolerance, dilationIterations = probeVolume.parameters.dilationIterations }); }
ProbeVolumeList PrepareVisibleProbeVolumeList(ScriptableRenderContext renderContext, HDCamera hdCamera, CommandBuffer cmd) { ProbeVolumeList probeVolumes = new ProbeVolumeList(); if (ShaderConfig.s_ProbeVolumesEvaluationMode == ProbeVolumesEvaluationModes.Disabled) { return(probeVolumes); } if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.ProbeVolume)) { return(probeVolumes); } var settings = hdCamera.volumeStack.GetComponent <ProbeVolumeController>(); bool octahedralDepthOcclusionFilterIsEnabled = settings.leakMitigationMode.value == LeakMitigationMode.OctahedralDepthOcclusionFilter; using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.PrepareProbeVolumeList))) { ClearProbeVolumeAtlasIfRequested(cmd); Vector3 camPosition = hdCamera.camera.transform.position; Vector3 camOffset = Vector3.zero;// World-origin-relative if (ShaderConfig.s_CameraRelativeRendering != 0) { camOffset = camPosition; // Camera-relative } m_VisibleProbeVolumeBounds.Clear(); m_VisibleProbeVolumeData.Clear(); // Collect all visible finite volume data, and upload it to the GPU. List <ProbeVolume> volumes = ProbeVolumeManager.manager.volumes; int probeVolumesCount = Math.Min(volumes.Count, k_MaxVisibleProbeVolumeCount); int sortCount = 0; // Sort probe volumes smallest from smallest to largest volume. // Same as is done with reflection probes. // See LightLoop.cs::PrepareLightsForGPU() for original example of this. for (int probeVolumesIndex = 0; (probeVolumesIndex < volumes.Count) && (sortCount < probeVolumesCount); probeVolumesIndex++) { ProbeVolume volume = volumes[probeVolumesIndex]; #if UNITY_EDITOR if (!volume.IsAssetCompatible()) { continue; } #endif if (ShaderConfig.s_ProbeVolumesAdditiveBlending == 0 && volume.parameters.volumeBlendMode != VolumeBlendMode.Normal) { // Non-normal blend mode volumes are not supported. Skip. continue; } float probeVolumeDepthFromCameraWS = Vector3.Dot(hdCamera.camera.transform.forward, volume.transform.position - camPosition); if (probeVolumeDepthFromCameraWS >= volume.parameters.distanceFadeEnd) { // Probe volume is completely faded out from distance fade optimization. // Do not bother adding it to the list, it would evaluate to zero weight. continue; } // TODO: cache these? var obb = new OrientedBBox(Matrix4x4.TRS(volume.transform.position, volume.transform.rotation, volume.parameters.size)); // Handle camera-relative rendering. obb.center -= camOffset; // Frustum cull on the CPU for now. TODO: do it on the GPU. if (GeometryUtils.Overlap(obb, hdCamera.frustum, hdCamera.frustum.planes.Length, hdCamera.frustum.corners.Length)) { var logVolume = CalculateProbeVolumeLogVolume(volume.parameters.size); m_ProbeVolumeSortKeys[sortCount++] = PackProbeVolumeSortKey(volume.parameters.volumeBlendMode, logVolume, probeVolumesIndex); } } CoreUnsafeUtils.QuickSort(m_ProbeVolumeSortKeys, 0, sortCount - 1); // Call our own quicksort instead of Array.Sort(sortKeys, 0, sortCount) so we don't allocate memory (note the SortCount-1 that is different from original call). for (int sortIndex = 0; sortIndex < sortCount; ++sortIndex) { // In 1. we have already classify and sorted the probe volume, we need to use this sorted order here uint sortKey = m_ProbeVolumeSortKeys[sortIndex]; int probeVolumesIndex; UnpackProbeVolumeSortKey(sortKey, out probeVolumesIndex); ProbeVolume volume = volumes[probeVolumesIndex]; // TODO: cache these? var obb = new OrientedBBox(Matrix4x4.TRS(volume.transform.position, volume.transform.rotation, volume.parameters.size)); // Handle camera-relative rendering. obb.center -= camOffset; // TODO: cache these? var data = volume.parameters.ConvertToEngineData(); // Note: The system is not aware of slice packing in Z. // Need to modify scale and bias terms just before uploading to GPU. // TODO: Should we make it aware earlier up the chain? data.scale.z = data.scale.z / (float)m_ProbeVolumeAtlasSHRTDepthSliceCount; data.bias.z = data.bias.z / (float)m_ProbeVolumeAtlasSHRTDepthSliceCount; m_VisibleProbeVolumeBounds.Add(obb); m_VisibleProbeVolumeData.Add(data); } s_VisibleProbeVolumeBoundsBuffer.SetData(m_VisibleProbeVolumeBounds); s_VisibleProbeVolumeDataBuffer.SetData(m_VisibleProbeVolumeData); // Fill the struct with pointers in order to share the data with the light loop. probeVolumes.bounds = m_VisibleProbeVolumeBounds; probeVolumes.data = m_VisibleProbeVolumeData; // For now, only upload one volume per frame. // This is done: // 1) To timeslice upload cost across N frames for N volumes. // 2) To avoid creating a sync point between compute buffer upload and each volume upload. const int volumeUploadedToAtlasSHCapacity = 1; int volumeUploadedToAtlasOctahedralDepthCapacity = octahedralDepthOcclusionFilterIsEnabled ? 1 : 0; int volumeUploadedToAtlasSHCount = 0; int volumeUploadedToAtlasOctahedralDepthCount = 0; for (int sortIndex = 0; sortIndex < sortCount; ++sortIndex) { uint sortKey = m_ProbeVolumeSortKeys[sortIndex]; int probeVolumesIndex; UnpackProbeVolumeSortKey(sortKey, out probeVolumesIndex); ProbeVolume volume = volumes[probeVolumesIndex]; if (volumeUploadedToAtlasSHCount < volumeUploadedToAtlasSHCapacity) { bool volumeWasUploaded = EnsureProbeVolumeInAtlas(renderContext, cmd, volume); if (volumeWasUploaded) { ++volumeUploadedToAtlasSHCount; } } if (volumeUploadedToAtlasOctahedralDepthCount < volumeUploadedToAtlasOctahedralDepthCapacity) { bool volumeWasUploaded = EnsureProbeVolumeInAtlasOctahedralDepth(renderContext, cmd, volume); if (volumeWasUploaded) { ++volumeUploadedToAtlasOctahedralDepthCount; } } if (volumeUploadedToAtlasSHCount == volumeUploadedToAtlasSHCapacity && volumeUploadedToAtlasOctahedralDepthCount == volumeUploadedToAtlasOctahedralDepthCapacity) { // Met our capacity this frame. Early out. break; } } return(probeVolumes); } }
internal bool EnsureProbeVolumeInAtlasOctahedralDepth(ScriptableRenderContext renderContext, CommandBuffer cmd, ProbeVolume volume) { int key = volume.GetID(); int width = volume.parameters.resolutionX * volume.parameters.resolutionZ * k_ProbeOctahedralDepthWidth; int height = volume.parameters.resolutionY * k_ProbeOctahedralDepthHeight; int size = volume.parameters.resolutionX * volume.parameters.resolutionY * volume.parameters.resolutionZ * k_ProbeOctahedralDepthWidth * k_ProbeOctahedralDepthHeight; Debug.Assert(size > 0, "ProbeVolume: Encountered probe volume with resolution set to zero on all three axes."); // TODO: Store volume resolution inside the atlas's key->bias dictionary. // If resolution has changed since upload, need to free previous allocation from atlas, // and attempt to allocate a new chunk from the atlas for the new resolution settings. // Currently atlas allocator only handles splitting. Need to add merging of neighboring, empty chunks to avoid fragmentation. bool isSlotAllocated = probeVolumeAtlasOctahedralDepth.EnsureTextureSlot(out bool isUploadNeeded, out volume.parameters.octahedralDepthScaleBias, key, width, height); if (isSlotAllocated) { if (isUploadNeeded || volume.dataUpdated) { (var data, var dataValidity, var dataOctahedralDepth) = volume.GetData(); if (data == null || data.Length == 0 || !volume.IsAssetCompatible()) { ReleaseProbeVolumeFromAtlas(volume); return(false); } // Blit: { //Debug.Log("Uploading Probe Volume Data with key " + key + " at scale bias = " + volume.parameters.scaleBias); cmd.SetComputeVectorParam(s_ProbeVolumeAtlasOctahedralDepthBlitCS, HDShaderIDs._ProbeVolumeResolution, new Vector3( volume.parameters.resolutionX, volume.parameters.resolutionY, volume.parameters.resolutionZ )); cmd.SetComputeVectorParam(s_ProbeVolumeAtlasOctahedralDepthBlitCS, HDShaderIDs._ProbeVolumeResolutionInverse, new Vector3( 1.0f / (float)volume.parameters.resolutionX, 1.0f / (float)volume.parameters.resolutionY, 1.0f / (float)volume.parameters.resolutionZ )); cmd.SetComputeVectorParam(s_ProbeVolumeAtlasOctahedralDepthBlitCS, HDShaderIDs._ProbeVolumeAtlasOctahedralDepthScaleBias, volume.parameters.octahedralDepthScaleBias ); Debug.Assert(dataOctahedralDepth.Length == size, "ProbeVolume: The probe volume baked data and its resolution are out of sync! Volume data length is " + dataOctahedralDepth.Length + ", but resolution size is " + size + "."); s_ProbeVolumeAtlasOctahedralDepthBuffer.SetData(dataOctahedralDepth); cmd.SetComputeIntParam(s_ProbeVolumeAtlasOctahedralDepthBlitCS, HDShaderIDs._ProbeVolumeAtlasOctahedralDepthReadBufferCount, size); cmd.SetComputeBufferParam(s_ProbeVolumeAtlasOctahedralDepthBlitCS, s_ProbeVolumeAtlasOctahedralDepthBlitKernel, HDShaderIDs._ProbeVolumeAtlasOctahedralDepthReadBuffer, s_ProbeVolumeAtlasOctahedralDepthBuffer); cmd.SetComputeTextureParam(s_ProbeVolumeAtlasOctahedralDepthBlitCS, s_ProbeVolumeAtlasOctahedralDepthBlitKernel, HDShaderIDs._ProbeVolumeAtlasOctahedralDepthWriteTexture, m_ProbeVolumeAtlasOctahedralDepthRTHandle); // TODO: Determine optimal batch size. const int kBatchSize = 256; int numThreadGroups = Mathf.CeilToInt((float)size / (float)kBatchSize); cmd.DispatchCompute(s_ProbeVolumeAtlasOctahedralDepthBlitCS, s_ProbeVolumeAtlasOctahedralDepthBlitKernel, numThreadGroups, 1, 1); } // Convolve: { Vector4 probeVolumeAtlasOctahedralDepthScaleBiasTexels = new Vector4( Mathf.Floor(volume.parameters.octahedralDepthScaleBias.x * s_ProbeVolumeAtlasOctahedralDepthWidth + 0.5f), Mathf.Floor(volume.parameters.octahedralDepthScaleBias.y * s_ProbeVolumeAtlasOctahedralDepthHeight + 0.5f), Mathf.Floor(volume.parameters.octahedralDepthScaleBias.z * s_ProbeVolumeAtlasOctahedralDepthWidth + 0.5f), Mathf.Floor(volume.parameters.octahedralDepthScaleBias.w * s_ProbeVolumeAtlasOctahedralDepthHeight + 0.5f) ); cmd.SetComputeVectorParam(s_ProbeVolumeAtlasOctahedralDepthConvolveCS, HDShaderIDs._ProbeVolumeAtlasOctahedralDepthScaleBiasTexels, probeVolumeAtlasOctahedralDepthScaleBiasTexels ); cmd.SetComputeTextureParam(s_ProbeVolumeAtlasOctahedralDepthConvolveCS, s_ProbeVolumeAtlasOctahedralDepthConvolveKernel, HDShaderIDs._ProbeVolumeAtlasOctahedralDepthRWTexture, m_ProbeVolumeAtlasOctahedralDepthRTHandle); cmd.SetComputeIntParam(s_ProbeVolumeAtlasOctahedralDepthConvolveCS, HDShaderIDs._FilterSampleCount, 16); // TODO: Expose cmd.SetComputeFloatParam(s_ProbeVolumeAtlasOctahedralDepthConvolveCS, HDShaderIDs._FilterSharpness, 6.0f); // TODO: Expose // Warning: This kernel numthreads must be an integer multiple of OCTAHEDRAL_DEPTH_RESOLUTION // We read + write from the same texture, so any partial work would pollute / cause feedback into neighboring chunks. int widthPixels = (int)(volume.parameters.octahedralDepthScaleBias.x * (float)s_ProbeVolumeAtlasOctahedralDepthWidth); int heightPixels = (int)(volume.parameters.octahedralDepthScaleBias.y * (float)s_ProbeVolumeAtlasOctahedralDepthHeight); int probeCountX = widthPixels / k_ProbeOctahedralDepthWidth; int probeCountY = heightPixels / k_ProbeOctahedralDepthHeight; Debug.Assert((k_ProbeOctahedralDepthWidth == k_ProbeOctahedralDepthHeight) && (k_ProbeOctahedralDepthWidth == 8)); Debug.Assert((probeCountX * k_ProbeOctahedralDepthWidth) == widthPixels); Debug.Assert((probeCountY * k_ProbeOctahedralDepthHeight) == heightPixels); cmd.DispatchCompute(s_ProbeVolumeAtlasOctahedralDepthConvolveCS, s_ProbeVolumeAtlasOctahedralDepthConvolveKernel, probeCountX, probeCountY, 1); } return(true); } return(false); } Debug.Assert(isSlotAllocated, "ProbeVolume: Texture Atlas failed to allocate space for octahedral depth texture { key: " + key + " width: " + width + ", height: " + height); return(false); }
internal bool EnsureProbeVolumeInAtlas(ScriptableRenderContext renderContext, CommandBuffer cmd, ProbeVolume volume) { int key = volume.GetID(); int width = volume.parameters.resolutionX; int height = volume.parameters.resolutionY; int depth = volume.parameters.resolutionZ; int size = volume.parameters.resolutionX * volume.parameters.resolutionY * volume.parameters.resolutionZ; Debug.Assert(size > 0, "ProbeVolume: Encountered probe volume with resolution set to zero on all three axes."); // TODO: Store volume resolution inside the atlas's key->bias dictionary. // If resolution has changed since upload, need to free previous allocation from atlas, // and attempt to allocate a new chunk from the atlas for the new resolution settings. // Currently atlas allocator only handles splitting. Need to add merging of neighboring, empty chunks to avoid fragmentation. bool isSlotAllocated = probeVolumeAtlas.EnsureTextureSlot(out bool isUploadNeeded, out volume.parameters.scale, out volume.parameters.bias, key, width, height, depth); if (isSlotAllocated) { if (isUploadNeeded || volume.dataUpdated) { (var data, var dataValidity, var dataOctahedralDepth) = volume.GetData(); if (data == null || data.Length == 0 || !volume.IsAssetCompatible()) { ReleaseProbeVolumeFromAtlas(volume); return(false); } //Debug.Log("Uploading Probe Volume Data with key " + key + " at scale bias = " + volume.parameters.scaleBias); cmd.SetComputeVectorParam(s_ProbeVolumeAtlasBlitCS, HDShaderIDs._ProbeVolumeResolution, new Vector3( volume.parameters.resolutionX, volume.parameters.resolutionY, volume.parameters.resolutionZ )); cmd.SetComputeVectorParam(s_ProbeVolumeAtlasBlitCS, HDShaderIDs._ProbeVolumeResolutionInverse, new Vector3( 1.0f / (float)volume.parameters.resolutionX, 1.0f / (float)volume.parameters.resolutionY, 1.0f / (float)volume.parameters.resolutionZ )); cmd.SetComputeVectorParam(s_ProbeVolumeAtlasBlitCS, HDShaderIDs._ProbeVolumeAtlasScale, volume.parameters.scale ); cmd.SetComputeVectorParam(s_ProbeVolumeAtlasBlitCS, HDShaderIDs._ProbeVolumeAtlasBias, volume.parameters.bias ); Debug.Assert(data.Length == size, "ProbeVolume: The probe volume baked data and its resolution are out of sync! Volume data length is " + data.Length + ", but resolution size is " + size + "."); Debug.Assert(size < s_MaxProbeVolumeProbeCount, "ProbeVolume: probe volume baked data size exceeds the currently max supported blitable size. Volume data size is " + size + ", but s_MaxProbeVolumeProbeCount is " + s_MaxProbeVolumeProbeCount + ". Please decrease ProbeVolume resolution, or increase ProbeVolumeLighting.s_MaxProbeVolumeProbeCount."); s_ProbeVolumeAtlasBlitDataBuffer.SetData(data); s_ProbeVolumeAtlasBlitDataValidityBuffer.SetData(dataValidity); cmd.SetComputeIntParam(s_ProbeVolumeAtlasBlitCS, HDShaderIDs._ProbeVolumeAtlasReadBufferCount, size); cmd.SetComputeBufferParam(s_ProbeVolumeAtlasBlitCS, s_ProbeVolumeAtlasBlitKernel, HDShaderIDs._ProbeVolumeAtlasReadBuffer, s_ProbeVolumeAtlasBlitDataBuffer); cmd.SetComputeBufferParam(s_ProbeVolumeAtlasBlitCS, s_ProbeVolumeAtlasBlitKernel, HDShaderIDs._ProbeVolumeAtlasReadValidityBuffer, s_ProbeVolumeAtlasBlitDataValidityBuffer); cmd.SetComputeTextureParam(s_ProbeVolumeAtlasBlitCS, s_ProbeVolumeAtlasBlitKernel, HDShaderIDs._ProbeVolumeAtlasWriteTextureSH, m_ProbeVolumeAtlasSHRTHandle); // TODO: Determine optimal batch size. const int kBatchSize = 256; int numThreadGroups = Mathf.CeilToInt((float)size / (float)kBatchSize); cmd.DispatchCompute(s_ProbeVolumeAtlasBlitCS, s_ProbeVolumeAtlasBlitKernel, numThreadGroups, 1, 1); return(true); } return(false); } Debug.Assert(isSlotAllocated, "ProbeVolume: Texture Atlas failed to allocate space for texture { key: " + key + "width: " + width + ", height: " + height + ", depth: " + depth + "}"); return(false); }