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)); } }
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); }
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); }
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]; } }); } }
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)); } }
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); }
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); }
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); }
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); }
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); }