Пример #1
0
        public static void ComputeLuminanceMinMax(CommandBuffer cmd, ComputeBuffer targetBuffer, Texture input)
        {
            MixtureUtils.SetupComputeTextureDimension(cmd, histogramCompute, input.dimension);

            // Clear buffers
            cmd.SetComputeBufferParam(histogramCompute, clearLuminanceKernel, "_ImageLuminance", luminanceBuffer);
            int dispatchCount = input.width * input.height * TextureUtils.GetSliceCount(input) / 64;
            // Limit computing to 8K textures
            int yCount = Mathf.Clamp(dispatchCount / dispatchGroupSizeX / 64, 1, dispatchGroupSizeX);
            int xCount = Mathf.Clamp(dispatchCount / yCount / 8, 1, dispatchGroupSizeX);

            cmd.SetComputeIntParam(histogramCompute, "_DispatchSizeX", dispatchGroupSizeX);
            cmd.DispatchCompute(histogramCompute, clearLuminanceKernel, xCount, yCount, TextureUtils.GetSliceCount(input));

            // Find luminance min / max in the texture
            cmd.SetComputeTextureParam(histogramCompute, computeLuminanceBufferKernel, "_Input", input);
            cmd.SetComputeBufferParam(histogramCompute, computeLuminanceBufferKernel, "_ImageLuminance", luminanceBuffer);
            cmd.SetComputeVectorParam(histogramCompute, "_InputTextureSize", new Vector4(input.width, input.height, TextureUtils.GetSliceCount(input), 0));
            MixtureUtils.SetTextureWithDimension(cmd, histogramCompute, computeLuminanceBufferKernel, "_Input", input);
            cmd.SetComputeVectorParam(histogramCompute, "_RcpTextureSize", new Vector4(1.0f / input.width, 1.0f / input.height, 1.0f / TextureUtils.GetSliceCount(input), 0));
            cmd.DispatchCompute(histogramCompute, computeLuminanceBufferKernel, Mathf.Max(1, input.width / 8), Mathf.Max(1, input.height / 8), TextureUtils.GetSliceCount(input));

            ReduceLuminanceBuffer(cmd, dispatchCount);

            cmd.SetComputeBufferParam(histogramCompute, copyMinMaxToBuffer, "_ImageLuminance", luminanceBuffer);
            cmd.SetComputeBufferParam(histogramCompute, copyMinMaxToBuffer, "_Target", targetBuffer);
            cmd.DispatchCompute(histogramCompute, copyMinMaxToBuffer, 1, 1, 1);
        }
        public override void OnInteractivePreviewGUI(Rect previewRect, GUIStyle background)
        {
            HandleZoomAndPan(previewRect);

            if (firstLockedPreviewTarget?.previewTexture != null && e.type == EventType.Repaint)
            {
                MixtureUtils.SetupDimensionKeyword(previewMaterial, firstLockedPreviewTarget.previewTexture.dimension);

                // Set texture property based on the dimension
                MixtureUtils.SetTextureWithDimension(previewMaterial, "_MainTex0", firstLockedPreviewTarget.previewTexture);
                MixtureUtils.SetTextureWithDimension(previewMaterial, "_MainTex1", secondLockedPreviewTarget.previewTexture);

                previewMaterial.SetFloat("_ComparisonSlider", compareSlider);
                previewMaterial.SetFloat("_ComparisonEnabled", compareEnabled ? 1 : 0);
                previewMaterial.SetFloat("_CompareMode", (int)compareMode);
                previewMaterial.SetFloat("_PreviewMip", mipLevel);
                previewMaterial.SetFloat("_YRatio", previewRect.height / previewRect.width);
                previewMaterial.SetFloat("_Zoom", zoom);
                previewMaterial.SetVector("_Pan", shaderPos / previewRect.size);
                previewMaterial.SetFloat("_FilterMode", (int)filterMode);
                previewMaterial.SetFloat("_Exp", exposure);
                previewMaterial.SetVector("_TextureSize", new Vector4(firstLockedPreviewTarget.previewTexture.width, firstLockedPreviewTarget.previewTexture.height, 1.0f / firstLockedPreviewTarget.previewTexture.width, 1.0f / firstLockedPreviewTarget.previewTexture.height));
                previewMaterial.SetVector("_Channels", MixtureEditorUtils.GetChannelsMask(channels));
                previewMaterial.SetFloat("_IsSRGB0", firstLockedPreviewTarget is OutputNode o0 && o0.mainOutput.sRGB ? 1 : 0);
                previewMaterial.SetFloat("_IsSRGB1", secondLockedPreviewTarget is OutputNode o1 && o1.mainOutput.sRGB ? 1 : 0);
                EditorGUI.DrawPreviewTexture(previewRect, Texture2D.whiteTexture, previewMaterial);
            }
            else
            {
                EditorGUI.DrawRect(previewRect, new Color(1, 0, 1, 1));
            }
        }
Пример #3
0
        protected override bool ProcessNode(CommandBuffer cmd)
        {
            if (!base.ProcessNode(cmd) || input == null)
            {
                return(false);
            }

            SyncSettings();

            UpdateTempRenderTexture(ref outputR);
            UpdateTempRenderTexture(ref outputG);
            UpdateTempRenderTexture(ref outputB);
            UpdateTempRenderTexture(ref outputA);

            SetMaterialParams(outputRMat, 0);
            SetMaterialParams(outputGMat, 1);
            SetMaterialParams(outputBMat, 2);
            SetMaterialParams(outputAMat, 3);

            void SetMaterialParams(Material m, int component)
            {
                MixtureUtils.SetTextureWithDimension(m, "_Source", input);
                m.SetColor("_NeutralColor", neutralColor);
                m.SetFloat("_Mode", (int)mode);
                m.SetInt("_Component", component);
            }

            return(true);
        }
Пример #4
0
        protected override bool ProcessNode(CommandBuffer cmd)
        {
            if (!base.ProcessNode(cmd) || input == null)
            {
                return(false);
            }

            HistogramUtility.ComputeLuminanceMinMax(cmd, minMaxBuffer, input);
            TextureUtils.UpdateTextureFromCurve(interpolationCurve, ref curveTexture);

            var mat = tempRenderTexture.material = GetTempMaterial("Hidden/Mixture/Levels");

            mat.SetFloat("_Mode", (int)mode);
            mat.SetFloat("_ManualMin", min);
            mat.SetFloat("_ManualMax", max);
            mat.SetVector("_RcpTextureSize", new Vector4(1.0f / input.width, 1.0f / input.height, 1.0f / TextureUtils.GetSliceCount(input), 0));
            MixtureUtils.SetupDimensionKeyword(mat, tempRenderTexture.dimension);
            MixtureUtils.SetTextureWithDimension(mat, "_Input", input);
            mat.SetBuffer("_Luminance", minMaxBuffer);
            mat.SetTexture("_InterpolationCurve", curveTexture);

            tempRenderTexture.Update();
            CustomTextureManager.UpdateCustomRenderTexture(cmd, tempRenderTexture);

            output = tempRenderTexture;

            return(true);
        }
Пример #5
0
        public static void ComputeHistogram(CommandBuffer cmd, Texture input, HistogramData data)
        {
            using (new ProfilingScope(cmd, new ProfilingSampler("Generate Histogram")))
            {
                MixtureUtils.SetupComputeTextureDimension(cmd, histogramCompute, input.dimension);

                // Clear buffers
                cmd.SetComputeBufferParam(histogramCompute, clearKernel, "_ImageLuminance", luminanceBuffer);
                cmd.SetComputeBufferParam(histogramCompute, clearKernel, "_Histogram", data.histogram);
                int dispatchCount = input.width * input.height * TextureUtils.GetSliceCount(input) / 64;
                // Limit computing to 8K textures
                int yCount = Mathf.Clamp(dispatchCount / dispatchGroupSizeX / 64, 1, dispatchGroupSizeX);
                int xCount = Mathf.Clamp(dispatchCount / yCount / 8, 1, dispatchGroupSizeX);
                cmd.SetComputeIntParam(histogramCompute, "_DispatchSizeX", dispatchGroupSizeX);
                cmd.DispatchCompute(histogramCompute, clearKernel, xCount, yCount, 1);

                // Find luminance min / max in the texture
                // TODO: handle texture 3D and Cube
                cmd.SetComputeTextureParam(histogramCompute, computeLuminanceBufferKernel, "_Input", input);
                cmd.SetComputeBufferParam(histogramCompute, computeLuminanceBufferKernel, "_ImageLuminance", luminanceBuffer);
                cmd.SetComputeVectorParam(histogramCompute, "_InputTextureSize", new Vector4(input.width, input.height, TextureUtils.GetSliceCount(input), 0));
                cmd.SetComputeVectorParam(histogramCompute, "_RcpTextureSize", new Vector4(1.0f / input.width, 1.0f / input.height, 1.0f / TextureUtils.GetSliceCount(input), 0));
                MixtureUtils.SetTextureWithDimension(cmd, histogramCompute, computeLuminanceBufferKernel, "_Input", input);
                cmd.DispatchCompute(histogramCompute, computeLuminanceBufferKernel, Mathf.Max(1, input.width / 8), Mathf.Max(1, input.height / 8), TextureUtils.GetSliceCount(input));

                ReduceLuminanceBuffer(cmd, dispatchCount);

                // Generate histogram data in compute buffer
                cmd.SetComputeBufferParam(histogramCompute, generateHistogramKernel, "_ImageLuminance", luminanceBuffer);
                cmd.SetComputeBufferParam(histogramCompute, generateHistogramKernel, "_Histogram", data.histogram);
                cmd.SetComputeTextureParam(histogramCompute, generateHistogramKernel, "_Input", input);
                cmd.SetComputeIntParam(histogramCompute, "_HistogramBucketCount", data.bucketCount);
                cmd.SetComputeVectorParam(histogramCompute, "_RcpTextureSize", new Vector4(1.0f / input.width, 1.0f / input.height, 1.0f / TextureUtils.GetSliceCount(input), 0));
                MixtureUtils.SetTextureWithDimension(cmd, histogramCompute, generateHistogramKernel, "_Input", input);
                cmd.DispatchCompute(histogramCompute, generateHistogramKernel, Mathf.Max(1, input.width / 8), Mathf.Max(1, input.height / 8), TextureUtils.GetSliceCount(input));

                cmd.SetComputeBufferParam(histogramCompute, computeHistogramDataKernel, "_HistogramData", data.histogramData);
                cmd.SetComputeBufferParam(histogramCompute, computeHistogramDataKernel, "_Histogram", data.histogram);
                cmd.DispatchCompute(histogramCompute, computeHistogramDataKernel, Mathf.Max(1, data.bucketCount / 64), 1, 1);

                // Request histogram data back for inspector
                cmd.RequestAsyncReadback(luminanceBuffer, 8, 0, (c) => {
                    var d = c.GetData <float>();
                    if (d.Length > 0)
                    {
                        data.minLuminance = d[0];
                        data.maxLuminance = d[1];
                    }
                });
            }
        }
Пример #6
0
        public override void OnInteractivePreviewGUI(Rect previewRect, GUIStyle background)
        {
            HandleZoomAndPan(previewRect);

            if (mixtureInspector.firstLockedPreviewTarget?.previewTexture != null && e.type == EventType.Repaint)
            {
                mixtureInspector.volumeCameraMatrix = Matrix4x4.Rotate(Quaternion.Euler(mixtureInspector.cameraYAxis, mixtureInspector.cameraXAxis, 0));

                MixtureUtils.SetupDimensionKeyword(previewMaterial, mixtureInspector.firstLockedPreviewTarget.previewTexture.dimension);

                // Set texture property based on the dimension
                MixtureUtils.SetTextureWithDimension(previewMaterial, "_MainTex0", mixtureInspector.firstLockedPreviewTarget.previewTexture);
                MixtureUtils.SetTextureWithDimension(previewMaterial, "_MainTex1", mixtureInspector.secondLockedPreviewTarget.previewTexture);

                previewMaterial.SetFloat("_ComparisonSlider", mixtureInspector.compareSlider);
                previewMaterial.SetFloat("_ComparisonSlider3D", mixtureInspector.compareSlider3D);
                previewMaterial.SetVector("_MouseUV", mixtureInspector.mouseUV);
                previewMaterial.SetMatrix("_CameraMatrix", mixtureInspector.volumeCameraMatrix);
                previewMaterial.SetFloat("_CameraZoom", mixtureInspector.cameraZoom);
                previewMaterial.SetFloat("_ComparisonEnabled", mixtureInspector.compareEnabled ? 1 : 0);
                previewMaterial.SetFloat("_CompareMode", (int)mixtureInspector.compareMode);
                previewMaterial.SetFloat("_PreviewMip", mixtureInspector.mipLevel);
                previewMaterial.SetFloat("_YRatio", previewRect.height / previewRect.width);
                previewMaterial.SetFloat("_Zoom", mixtureInspector.zoom);
                previewMaterial.SetVector("_Pan", mixtureInspector.shaderPos / previewRect.size);
                previewMaterial.SetFloat("_FilterMode", (int)mixtureInspector.filterMode);
                previewMaterial.SetFloat("_Exp", mixtureInspector.exposure);
                previewMaterial.SetVector("_TextureSize", new Vector4(mixtureInspector.firstLockedPreviewTarget.previewTexture.width, mixtureInspector.firstLockedPreviewTarget.previewTexture.height, 1.0f / mixtureInspector.firstLockedPreviewTarget.previewTexture.width, 1.0f / mixtureInspector.firstLockedPreviewTarget.previewTexture.height));
                previewMaterial.SetVector("_Channels", MixtureEditorUtils.GetChannelsMask(mixtureInspector.channels));
                previewMaterial.SetFloat("_IsSRGB0", mixtureInspector.firstLockedPreviewTarget is OutputNode o0 && o0.mainOutput.sRGB ? 1 : 0);
                previewMaterial.SetFloat("_IsSRGB1", mixtureInspector.secondLockedPreviewTarget is OutputNode o1 && o1.mainOutput.sRGB ? 1 : 0);
                previewMaterial.SetFloat("_PreserveAspect", mixtureInspector.preserveAspect ? 1 : 0);
                previewMaterial.SetFloat("_Texture3DMode", (int)mixtureInspector.texture3DPreviewMode);
                previewMaterial.SetFloat("_Density", mixtureInspector.texture3DDensity);
                previewMaterial.SetFloat("_SDFOffset", mixtureInspector.texture3DDistanceFieldOffset);
                previewMaterial.SetFloat("_SDFChannel", (int)mixtureInspector.sdfChannel);
                previewMaterial.SetFloat("_ShowCubeBackface", mixtureInspector.showCubeBackface ? 1 : 0);
                previewMaterial.SetFloat("_InvertSurface", mixtureInspector.invertSurface ? 1 : 0);
                previewMaterial.SetFloat("_VolumetricDensityChannel", mixtureInspector.volumetricDensityChannel);
                EditorGUI.DrawPreviewTexture(previewRect, Texture2D.whiteTexture, previewMaterial);
            }
            else
            {
                EditorGUI.DrawRect(previewRect, new Color(1, 0, 1, 1));
            }
        }
Пример #7
0
        protected override bool ProcessNode(CommandBuffer cmd)
        {
            if (!base.ProcessNode(cmd) || textureAsset == null)
            {
                return(false);
            }

#if UNITY_EDITOR
            var importer = UnityEditor.AssetImporter.GetAtPath(UnityEditor.AssetDatabase.GetAssetPath(textureAsset));
            if (importer is UnityEditor.TextureImporter textureImporter)
            {
                normalMap = textureImporter.textureType == UnityEditor.TextureImporterType.NormalMap;
            }
#endif

            // Compressed normal maps need to be converted from AG to RG format
            if (normalMap)
            {
                if (postProcessedTexture == null)
                {
                    postProcessedTexture = new RenderTexture(1, 1, 0, GraphicsFormat.R16G16B16A16_SFloat);
                }

                if (postProcessedTexture.width != textureAsset.width || postProcessedTexture.height != textureAsset.height)
                {
                    postProcessedTexture.Release();
                    postProcessedTexture.width  = textureAsset.width;
                    postProcessedTexture.height = textureAsset.height;
                    postProcessedTexture.Create();
                }

                var blitMaterial = GetTempMaterial("Hidden/Mixture/TextureNode");
                MixtureUtils.SetTextureWithDimension(blitMaterial, "_Source", textureAsset);
                MixtureUtils.Blit(cmd, blitMaterial, textureAsset, postProcessedTexture);

                outputTexture = postProcessedTexture;
            }
            else
            {
                postProcessedTexture?.Release();
                outputTexture = textureAsset;
            }

            return(true);
        }
Пример #8
0
        protected override bool ProcessNode(CommandBuffer cmd)
        {
            if (!base.ProcessNode(cmd) || input == null)
            {
                return(false);
            }

            UpdateTempRenderTexture(ref outputR);
            UpdateTempRenderTexture(ref outputG);
            UpdateTempRenderTexture(ref outputB);
            UpdateTempRenderTexture(ref outputA);

            MixtureUtils.SetTextureWithDimension(outputRMat, "_Source", input);
            MixtureUtils.SetTextureWithDimension(outputGMat, "_Source", input);
            MixtureUtils.SetTextureWithDimension(outputBMat, "_Source", input);
            MixtureUtils.SetTextureWithDimension(outputAMat, "_Source", input);
            outputRMat.SetInt("_Component", 0);
            outputGMat.SetInt("_Component", 1);
            outputBMat.SetInt("_Component", 2);
            outputAMat.SetInt("_Component", 3);

            return(true);
        }
Пример #9
0
        protected override bool ProcessNode(CommandBuffer cmd)
        {
            rtSettings.doubleBuffered = true;
            if (!base.ProcessNode(cmd) || input == null)
            {
                return(false);
            }

            TextureUtils.CopyTexture(cmd, input, output, false);

            var mipmapGenMat = GetTempMaterial("Hidden/Mixture/GenerateMipMaps");

            if (mode == Mode.Custom)
            {
                mipmapGenMat = material;
            }
            else
            {
                output.material = null;
            }

            if (mode == Mode.Auto)
            {
                cmd.GenerateMips(output);
            }
            else
            {
                var props = new MaterialPropertyBlock();
                MixtureUtils.SetupDimensionKeyword(mipmapGenMat, rtSettings.GetTextureDimension(graph));
                mipmapGenMat.SetFloat("_Mode", (int)mode);
                MixtureUtils.SetTextureWithDimension(props, "_PreviousMip", input);
                // Manually generate mips:
                for (int i = 0; i < output.mipmapCount - 1; i++)
                {
                    props.SetFloat("_SourceMip", i);
                    float width  = Mathf.Max(1, input.width >> i);
                    float height = Mathf.Max(1, input.width >> i);
                    float depth  = Mathf.Max(1, TextureUtils.GetSliceCount(input) >> i);
                    props.SetVector("_RcpTextureSize", new Vector4(1.0f / width, 1.0f / height, 1.0f / depth, 0.0f));
                    output.material = mipmapGenMat;

                    if (mode == Mode.Gaussian)
                    {
                        // 2 passes of gaussian blur for 2D and Cubemaps
                        props.SetVector("_GaussianBlurDirection", Vector3.right);
                        CustomTextureManager.UpdateCustomRenderTexture(cmd, output, 1, i + 1, props);
                        TextureUtils.CopyTexture(cmd, output.GetDoubleBufferRenderTexture(), output, i + 1);

                        props.SetFloat("_SourceMip", i + 1);
                        MixtureUtils.SetTextureWithDimension(props, "_PreviousMip", output);
                        props.SetVector("_GaussianBlurDirection", Vector3.up);
                        CustomTextureManager.UpdateCustomRenderTexture(cmd, output, 1, i + 1, props);

                        // And a third pass if we're in 3D
                        if (input.dimension == TextureDimension.Tex3D)
                        {
                            props.SetVector("_GaussianBlurDirection", Vector3.forward);
                            TextureUtils.CopyTexture(cmd, output.GetDoubleBufferRenderTexture(), output, i + 1);
                            CustomTextureManager.UpdateCustomRenderTexture(cmd, output, 1, i + 1, props);
                        }
                    }
                    else
                    {
                        CustomTextureManager.UpdateCustomRenderTexture(cmd, output, 1, i + 1, props);
                    }

                    TextureUtils.CopyTexture(cmd, output.GetDoubleBufferRenderTexture(), output, i + 1);
                    MixtureUtils.SetTextureWithDimension(props, "_PreviousMip", output);
                }
            }
            output.material = null;

            return(true);
        }
Пример #10
0
        protected override bool ProcessNode(CommandBuffer cmd)
        {
            if (!base.ProcessNode(cmd) || textureAsset == null)
            {
                return(false);
            }

#if UNITY_EDITOR
            var importer = UnityEditor.AssetImporter.GetAtPath(UnityEditor.AssetDatabase.GetAssetPath(textureAsset));
            if (importer is UnityEditor.TextureImporter textureImporter)
            {
                normalMap = textureImporter.textureType == UnityEditor.TextureImporterType.NormalMap;
            }
#endif

            int  targetWidth     = textureAsset.width;
            int  targetHeight    = textureAsset.height;
            int  targetDepth     = TextureUtils.GetSliceCount(textureAsset);
            bool needsTempTarget = false;
            if (!IsPowerOf2(textureAsset) && POTMode != PowerOf2Mode.None)
            {
                int maxSize = Mathf.Max(Mathf.Max(targetWidth, targetHeight), targetDepth);
                int potSize = 0;

                switch (POTMode)
                {
                case PowerOf2Mode.ScaleToNextPowerOf2:
                    potSize = Mathf.NextPowerOfTwo(maxSize);
                    break;

                default:
                    potSize = Mathf.ClosestPowerOfTwo(maxSize);
                    break;
                }
                targetWidth     = targetHeight = targetDepth = potSize;
                needsTempTarget = true;
            }
            if (normalMap)
            {
                needsTempTarget = true;
            }

            if (needsTempTarget && postProcessedTexture == null)
            {
                postProcessedTexture = new RenderTexture(1, 1, 0, GraphicsFormat.R16G16B16A16_SFloat, mipCount: textureAsset.mipmapCount)
                {
                    dimension = textureAsset.dimension, enableRandomWrite = true, volumeDepth = 1
                }
            }
            ;
            else if (!needsTempTarget)
            {
                postProcessedTexture?.Release();
                postProcessedTexture = null;
            }

            if (postProcessedTexture != null && (postProcessedTexture.width != targetWidth ||
                                                 postProcessedTexture.height != targetHeight ||
                                                 postProcessedTexture.volumeDepth != targetDepth))
            {
                postProcessedTexture.Release();
                postProcessedTexture.width       = targetWidth;
                postProcessedTexture.height      = targetHeight;
                postProcessedTexture.volumeDepth = targetDepth;
                postProcessedTexture.Create();
            }
            // TODO: same alloc as normal map + scale and crop options

            // Compressed normal maps need to be converted from AG to RG format
            if (normalMap)
            {
                // Transform normal map texture into POT
                var blitMaterial = GetTempMaterial("Hidden/Mixture/TextureNode");
                MixtureUtils.SetTextureWithDimension(blitMaterial, "_Source", textureAsset);
                blitMaterial.SetInt("_POTMode", (int)POTMode);
                MixtureUtils.Blit(cmd, blitMaterial, textureAsset, postProcessedTexture, 0);

                outputTexture = postProcessedTexture;
            }
            else if (needsTempTarget)
            {
                // Transform standard texture into POT
                var blitMaterial = GetTempMaterial("Hidden/Mixture/TextureNode");
                MixtureUtils.SetTextureWithDimension(blitMaterial, "_Source", textureAsset);
                blitMaterial.SetInt("_POTMode", (int)POTMode);
                MixtureUtils.Blit(cmd, blitMaterial, textureAsset, postProcessedTexture, 1);

                outputTexture = postProcessedTexture;
            }
            else
            {
                outputTexture = textureAsset;
            }

            if (outputTexture != null)
            {
                settings.sizeMode = OutputSizeMode.Absolute;
                settings.width    = outputTexture.width;
                settings.height   = outputTexture.height;
                settings.depth    = TextureUtils.GetSliceCount(outputTexture);
            }

            return(true);
        }
Пример #11
0
        protected override bool ProcessNode(CommandBuffer cmd)
        {
            // Force the double buffering for multi-pass flooding
            rtSettings.doubleBuffered = true;

            if (!base.ProcessNode(cmd) || input == null)
            {
                return(false);
            }

            UpdateTempRenderTexture(ref output);

            cmd.SetComputeFloatParam(computeShader, "_Threshold", threshold);
            cmd.SetComputeVectorParam(computeShader, "_Size", new Vector4(output.width, 1.0f / output.width));
            cmd.SetComputeFloatParam(computeShader, "_Distance", distance / 100.0f);
            cmd.SetComputeIntParam(computeShader, "_ThresholdMode", (int)thresholdMode);
            cmd.SetComputeIntParam(computeShader, "_DistanceMode", (int)distanceMode);
            cmd.SetComputeIntParam(computeShader, "_Mode", (int)mode);

            output.doubleBuffered = true;
            output.EnsureDoubleBufferConsistency();
            var rt = output.GetDoubleBufferRenderTexture();

            if (!rt.enableRandomWrite)
            {
                rt.Release();
                rt.enableRandomWrite = true;
                rt.Create();
            }

            MixtureUtils.SetupComputeTextureDimension(cmd, computeShader, input.dimension);

            MixtureUtils.SetTextureWithDimension(cmd, computeShader, fillUvKernel, "_Input", input);
            MixtureUtils.SetTextureWithDimension(cmd, computeShader, fillUvKernel, "_Output", output);
            MixtureUtils.SetTextureWithDimension(cmd, computeShader, fillUvKernel, "_FinalOutput", rt);
            cmd.SetComputeIntParam(computeShader, "_DistanceMode", (int)distanceMode);
            cmd.SetComputeFloatParam(computeShader, "_InputScaleFactor", (float)input.width / (float)output.width);
            DispatchCompute(cmd, fillUvKernel, output.width, output.height, output.volumeDepth);

            int maxLevels = (int)Mathf.Log(input.width, 2);

            for (int i = 0; i <= maxLevels; i++)
            {
                float offset = 1 << (maxLevels - i);
                cmd.SetComputeFloatParam(computeShader, "_InputScaleFactor", 1);
                cmd.SetComputeFloatParam(computeShader, "_Offset", offset);
                MixtureUtils.SetTextureWithDimension(cmd, computeShader, jumpFloodingKernel, "_Input", output);
                MixtureUtils.SetTextureWithDimension(cmd, computeShader, jumpFloodingKernel, "_Output", rt);
                cmd.SetComputeIntParam(computeShader, "_DistanceMode", (int)distanceMode);
                DispatchCompute(cmd, jumpFloodingKernel, output.width, output.height, output.volumeDepth);
                TextureUtils.CopyTexture(cmd, rt, output);
            }

            cmd.SetComputeFloatParam(computeShader, "_InputScaleFactor", (float)input.width / (float)output.width);
            cmd.SetComputeIntParam(computeShader, "_DistanceMode", (int)distanceMode);
            MixtureUtils.SetTextureWithDimension(cmd, computeShader, finalPassKernel, "_Input", input);
            MixtureUtils.SetTextureWithDimension(cmd, computeShader, finalPassKernel, "_Output", rt);
            MixtureUtils.SetTextureWithDimension(cmd, computeShader, finalPassKernel, "_FinalOutput", output);
            DispatchCompute(cmd, finalPassKernel, output.width, output.height, output.volumeDepth);

            return(true);
        }