Beispiel #1
0
        Texture2D CreateEnvMapTextureFromResult()
        {
            Assert.IsNotNull(m_ColorCorrect);

            var mat = DelightingService.GetLatLongMaterial(
                vm.latLongA,
                vm.normalsTexture,
                vm.latLongAverage,
                vm.overrideReferenceZone,
                vm.latLongExposure,
                vm.safetyZoneParams,
                true);

            var temporaryRT = RenderTexture.GetTemporary(vm.latLongA.width, vm.latLongA.height, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear);

            DelightingHelpers.PushSRGBWrite(false);
            Graphics.Blit(null, temporaryRT, mat, 0);
            DelightingHelpers.PopSRGBWrite();

            var           exportedLatLong = new Texture2D(vm.latLongA.width, vm.latLongA.height, TextureFormat.RGBAFloat, false, true);
            RenderTexture previous        = RenderTexture.active;

            RenderTexture.active = temporaryRT;
            exportedLatLong.ReadPixels(new Rect(0, 0, vm.latLongA.width, vm.latLongA.height), 0, 0, false);
            exportedLatLong.Apply();
            RenderTexture.active = previous;
            GL.sRGBWrite         = false;

            return(exportedLatLong);
        }
Beispiel #2
0
        public void Dispose()
        {
            m_ViewModel.Dispose();
            DelightingHelpers.DeleteRTIfRequired(m_Result);
            m_Result = null;
            DelightingHelpers.DeleteRTIfRequired(m_AOCorrected);
            m_AOCorrected = null;
            DelightingHelpers.DeleteRTIfRequired(m_ColorCorrect);
            m_ColorCorrect = null;
            DelightingHelpers.DeleteRTIfRequired(m_DefaultMask);
            m_DefaultMask = null;


            if (m_LatLongArray != null)
            {
                m_LatLongArray.Release();
                m_LatLongArray = null;
            }
            if (vm.latLongAverage != null)
            {
                vm.latLongAverage.Release();
                vm.latLongAverage = null;
            }
            if (m_LutArrayGather != null)
            {
                m_LutArrayGather.Release();
                m_LutArrayGather = null;
            }
        }
Beispiel #3
0
 public void Dispose()
 {
     EditorApplication.update -= Update;
     DelightingHelpers.DeleteRTIfRequired(latLongA);
     latLongA = null;
     DelightingHelpers.DeleteRTIfRequired(bakedLUT);
     bakedLUT         = null;
     PropertyChanged -= OnPropertyChanged;
 }
        public override void OnGUI()
        {
            SetValue(kLatLongExposure, EditorGUILayout.Slider(Content.kLatLongExposureLabel, GetValue(kLatLongExposure), 0, 1));

            var latLongA = GetValue(kLatLongA);

            if (latLongA != null)
            {
                var mat = DelightingService.GetLatLongMaterial(
                    latLongA,
                    GetValue(kNormalsTexture),
                    GetValue(kLatLongAverage),
                    GetValue(kOverrideReferenceZone),
                    GetValue(kLatLongExposure),
                    GetValue(kSafetyZoneParams),
                    false);

                var oldRt = RenderTexture.active;
                m_latLongExposed = DelightingHelpers.InstantiateRTIfRequired(m_latLongExposed, latLongA.width, latLongA.height, false, TextureWrapMode.Clamp);
                DelightingHelpers.PushSRGBWrite(false);
                Graphics.Blit(null, m_latLongExposed, mat);
                DelightingHelpers.PopSRGBWrite();
                RenderTexture.active = oldRt;

                GUILayout.BeginHorizontal();
                EditorGUILayout.LabelField(Content.kLatLongALabel, EditorStyles.boldLabel);
                GUILayout.FlexibleSpace();
                if (GUILayout.Button(Content.kExportLabel))
                {
                    ExecuteCommand(kCmdExportMainEnvMap);
                }
                GUILayout.EndHorizontal();

                EditorGUILayout.Space();

                var rect = GUILayoutUtility.GetAspectRect(latLongA.width / (float)latLongA.height);
                GUI.DrawTexture(rect, m_latLongExposed);
                EditorGUILayout.Space();
            }



            var bakedLut = GetValue(kBakedLUT);

            if (bakedLut != null)
            {
                EditorGUILayout.Space();

                EditorGUILayout.LabelField(Content.kBakedLUTLabel, EditorStyles.boldLabel);

                EditorGUILayout.Space();

                var rect = GUILayoutUtility.GetAspectRect(bakedLut.width / (float)bakedLut.height);
                GUI.DrawTexture(rect, bakedLut);
                EditorGUILayout.Space();
            }
        }
Beispiel #5
0
        List <string> GetErrorMessagesFrom(Delighting.ErrorCode errorCode)
        {
            int width = 0, height = 0;

            if (baseTexture != null)
            {
                width  = baseTexture.width;
                height = baseTexture.height;
            }
            var errors = new List <string>();

            DelightingHelpers.GetErrorMessagesFrom(errorCode, errors, width, height);
            return(errors);
        }
Beispiel #6
0
        public Delighting.ErrorCode RenderPreview()
        {
            var error = ValidateInputs();

            if (result == null)
            {
                error |= Delighting.ErrorCode.PreviewNotAvailable;
            }
            if (error != Delighting.ErrorCode.NoErrors)
            {
                return(error);
            }

            // Prepare RT target
            vm.previewTexture = DelightingHelpers.InstantiateRTIfRequired(vm.previewTexture, result.width, result.height, false, TextureWrapMode.Clamp);

            // Store local variables
            var previewTexture          = vm.previewTexture;
            var delighted               = result;
            var leftViewMode            = vm.leftViewMode;
            var rightViewMode           = vm.rightViewMode;
            var compareViewLerp         = vm.compareViewLerp;
            var baseTexture             = vm.baseTexture;
            var normalsTexture          = vm.normalsTexture;
            var bentNormalsTexture      = vm.bentNormalsTexture;
            var ambientOcclusionTexture = vm.ambientOcclusionTexture;
            var maskTexture             = vm.maskTexture;

            // Material setup
            kPreviewMaterial.SetFloat("_ComparePos", compareViewLerp);
            SetupPreviewMaterial("Left", leftViewMode, baseTexture, delighted, normalsTexture, bentNormalsTexture, ambientOcclusionTexture, maskTexture);
            SetupPreviewMaterial("Right", rightViewMode, baseTexture, delighted, normalsTexture, bentNormalsTexture, ambientOcclusionTexture, maskTexture);

            var oldRt = RenderTexture.active;

            Graphics.Blit(null, previewTexture, kPreviewMaterial, 0);
            RenderTexture.active = oldRt;

            vm.SetPropertyChanged(DelightingViewModel.Properties.kPreviewTexture);

            return(Delighting.ErrorCode.NoErrors);
        }
Beispiel #7
0
        Texture2D CreateDelightedTextureFromResult()
        {
            Assert.IsNotNull(m_ColorCorrect);

            var temporaryRT = RenderTexture.GetTemporary(m_ColorCorrect.width, m_ColorCorrect.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);

#if UNITY_2018_1_OR_NEWER
            DelightingHelpers.PushSRGBWrite(true);
#else
            DelightingHelpers.PushSRGBWrite(false);
#endif
            Graphics.Blit(m_ColorCorrect, temporaryRT);
            DelightingHelpers.PopSRGBWrite();

            var           exportedUnlit = new Texture2D(m_ColorCorrect.width, m_ColorCorrect.height, TextureFormat.ARGB32, false, false);
            RenderTexture previous      = RenderTexture.active;
            RenderTexture.active = temporaryRT;
            exportedUnlit.ReadPixels(new Rect(0, 0, m_ColorCorrect.width, m_ColorCorrect.height), 0, 0, false);
            exportedUnlit.Apply();
            RenderTexture.active = previous;

            return(exportedUnlit);
        }
Beispiel #8
0
        IEnumerator LoadAssets(string[] assetPaths)
        {
            var result = new LoadAssetFolderOperation();

            for (int i = 0; i < assetPaths.Length; i++)
            {
                var assetPath = assetPaths[i];
                if (assetPath.EndsWith(".meta"))
                {
                    continue;
                }

                if (DelightingHelpers.IsPathSuffixed(assetPath, vm.positionsTextureSuffix))
                {
                    var texture = AssetDatabase.LoadAssetAtPath <Texture2D>(assetPath);
                    if (texture != null)
                    {
                        log.LogFormat(LogType.Log, "Found Position Texture {0}", assetPath);
                        result.positionTexture    = texture;
                        result.hasPositionTexture = true;
                    }
                }
                else if (DelightingHelpers.IsPathSuffixed(assetPath, vm.ambientOcclusionTextureSuffix))
                {
                    var texture = AssetDatabase.LoadAssetAtPath <Texture2D>(assetPath);
                    if (texture != null)
                    {
                        log.LogFormat(LogType.Log, "Found Ambient Occlusion Texture {0}", assetPath);
                        result.ambientOcclusionTexture    = texture;
                        result.hasAmbientOcclusionTexture = true;
                    }
                }
                else if (DelightingHelpers.IsPathSuffixed(assetPath, vm.baseTextureSuffix))
                {
                    var texture = AssetDatabase.LoadAssetAtPath <Texture2D>(assetPath);
                    if (texture != null)
                    {
                        log.LogFormat(LogType.Log, "Found Base Texture {0}", assetPath);
                        result.baseTexture    = texture;
                        result.hasBaseTexture = true;
                    }
                }
                else if (DelightingHelpers.IsPathSuffixed(assetPath, vm.bentNormalsTextureSuffix))
                {
                    var texture = AssetDatabase.LoadAssetAtPath <Texture2D>(assetPath);
                    if (texture != null)
                    {
                        log.LogFormat(LogType.Log, "Found Bent Normals Texture {0}", assetPath);
                        result.bentNormalsTexture    = texture;
                        result.hasBentNormalsTexture = true;
                    }
                }
                else if (DelightingHelpers.IsPathSuffixed(assetPath, vm.normalsTextureSuffix))
                {
                    var texture = AssetDatabase.LoadAssetAtPath <Texture2D>(assetPath);
                    if (texture != null)
                    {
                        log.LogFormat(LogType.Log, "Found Normals Texture {0}", assetPath);
                        result.normalsTexture    = texture;
                        result.hasNormalsTexture = true;
                    }
                }
                else if (DelightingHelpers.IsPathSuffixed(assetPath, vm.maskTextureSuffix))
                {
                    var texture = AssetDatabase.LoadAssetAtPath <Texture2D>(assetPath);
                    if (texture != null)
                    {
                        log.LogFormat(LogType.Log, "Found Normals Texture {0}", assetPath);
                        result.maskTexture    = texture;
                        result.hasMaskTexture = true;
                    }
                }

                yield return(null);
            }

            yield return(result);
        }
Beispiel #9
0
        IEnumerator DoProcess(Delighting.ProcessArgs args, bool dryRun)
        {
            // ------------------------------------------------------------------------------------
            // Render loop goes here

            ///
            if (args.fromStep == Delighting.ProcessStep.Gather)
            {
                // Prepare outputs
                if (!dryRun)
                {
                    m_Result      = DelightingHelpers.InstantiateRTIfRequired(m_Result, vm.baseTexture.width, vm.baseTexture.height, true, TextureWrapMode.Clamp);
                    m_AOCorrected = DelightingHelpers.InstantiateRTIfRequired(m_AOCorrected, vm.ambientOcclusionTexture.width, vm.ambientOcclusionTexture.height, true, TextureWrapMode.Clamp);
                    vm.latLongA   = DelightingHelpers.InstantiateRTIfRequired(vm.latLongA, kEnvSize, kEnvSize / 2, false, TextureWrapMode.Clamp);
                    vm.bakedLUT   = DelightingHelpers.InstantiateRTIfRequired(vm.bakedLUT, 64, 64, false, TextureWrapMode.Clamp);
                }
                yield return(null);

                RenderTexture GlobalLatLong = null;
                if (!dryRun)
                {
                    GlobalLatLong = vm.latLongA;
                    if (m_LatLongArray != null)
                    {
                        m_LatLongArray.Release();
                        m_LatLongArray = null;
                    }

                    if (vm.latLongAverage != null)
                    {
                        vm.latLongAverage.Release();
                        vm.latLongAverage = null;
                    }

                    // Recover missing AO from BaseTex
                    processAOrecover();
                }
                yield return(null);

                if (!dryRun)
                {
                    // LatLong array gather pass
                    m_LatLongArray = GatherLLArray(GlobalLatLong.width, GlobalLatLong.height); // Store colors per direction info as LatLong map
                    CleanBuffer(m_LatLongArray, 1);                                            // Remove small weight points
                }
                yield return(null);


                if (!dryRun)
                {
                    // Store and normalize the Global LatLong
                    NormalizeLatLong(m_LatLongArray, GlobalLatLong);
                }
                yield return(null);

                if (!dryRun)
                {
                    // Find the average color and use it as color reference
                    vm.latLongAverage = AverageLatLong(GlobalLatLong);
                }
                yield return(null);
            }

            ///
            if (args.fromStep == Delighting.ProcessStep.Delight ||
                args.fromStep == Delighting.ProcessStep.Gather)
            {
                if (!dryRun)
                {
                    Assert.IsNotNull(m_LatLongArray);
                    Assert.IsNotNull(vm.latLongAverage);

                    // Prepare outputs
                    if (m_LutArrayGather != null)
                    {
                        m_LutArrayGather.Release();
                        m_LutArrayGather = null;
                    }

                    // Inververse IBL pass: use the LatLong array to get back the albedo. No occlusion compensation
                    DelightingArray(m_Result, m_LatLongArray, vm.latLongAverage, kEnvSize, kEnvSize / 2);
                }
                yield return(null);


                if (!dryRun)
                {
                    // LUT Gathering pass - Gather Occlusion + GI and store it in a LUT
                    m_LutArrayGather = GatherLUTArray(true, vm.bakedLUT.width, vm.bakedLUT.height);

                    CleanBuffer(m_LutArrayGather, 1);
                }
                yield return(null);

                if (!dryRun)
                {
                    NormalizeLUT(m_LutArrayGather, vm.bakedLUT); // Used just to make the preview !!! Change the name
                }
                yield return(null);

                // Apply LUT
                if (!dryRun)
                {
                    ApplyLUTArray(m_Result, m_LutArrayGather, vm.latLongAverage, vm.bakedLUT.width, vm.bakedLUT.height, kGridSize); // Apply inverse LUT for de-light Occlusion + GI
                }
                yield return(null);
            }

            ///
            if (args.fromStep == Delighting.ProcessStep.Delight ||
                args.fromStep == Delighting.ProcessStep.Gather ||
                args.fromStep == Delighting.ProcessStep.ColorCorrection)
            {
                if (!dryRun)
                {
                    m_ColorCorrect = DelightingHelpers.InstantiateRTIfRequired(m_ColorCorrect, vm.baseTexture.width, vm.baseTexture.height, false, TextureWrapMode.Clamp);
                    ColorCorrection(m_ColorCorrect, m_LatLongArray, vm.latLongAverage, kEnvSize, kEnvSize / 2); // Apply Color Correction using Reference/Average Color, and various filters
                }
                yield return(null);
            }

            // End of render loop
            // ------------------------------------------------------------------------------------

            yield return(dryRun
                ? null
                : new ProcessOperation()
            {
                error = Delighting.ErrorCode.NoErrors,
                result = args.calculateResult ? CreateDelightedTextureFromResult() : null
            });
        }
Beispiel #10
0
        public override void OnGUI()
        {
            var displays  = GetValue(kDisplayedUI);
            var errorCode = GetValue(kInputErrorCode);

            m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);
            if ((displays & DelightingUI.Display.SectionInput) != 0)
            {
                EditorGUILayout.Space();
                SetValue(kFoldInputParameters, EditorGUIXLayout.InspectorFoldout(GetValue(kFoldInputParameters), Content.inputParametersTitle, DelightingHelpers.GetIcon(errorCode, kInputError)));
                if (GetValue(kFoldInputParameters))
                {
                    ++EditorGUI.indentLevel;
                    if ((displays & DelightingUI.Display.FieldBaseTexture) != 0)
                    {
                        SetValue(kBaseTexture, EditorGUIXLayout.InlineObjectField(Content.baseTextureLabel, GetValue(kBaseTexture), DelightingHelpers.GetIcon(errorCode, kBaseValueError)));
                    }
                    if ((displays & DelightingUI.Display.FieldNormalsTexture) != 0)
                    {
                        SetValue(kNormalsTexture, EditorGUIXLayout.InlineObjectField(Content.normalsTextureLabel, GetValue(kNormalsTexture), DelightingHelpers.GetIcon(errorCode, kNormalsValueError)));
                    }
                    if ((displays & DelightingUI.Display.FieldBentNormalsTexture) != 0)
                    {
                        SetValue(kBentNormalsTexture, EditorGUIXLayout.InlineObjectField(Content.bentNormalsTextureLabel, GetValue(kBentNormalsTexture), DelightingHelpers.GetIcon(errorCode, kBentNormalsValueError)));
                    }
                    if ((displays & DelightingUI.Display.FieldAmbientOcclusionTexture) != 0)
                    {
                        SetValue(kAmbientOcclusionTexture, EditorGUIXLayout.InlineObjectField(Content.ambientOcclusionTextureLabel, GetValue(kAmbientOcclusionTexture), DelightingHelpers.GetIcon(errorCode, kAmbientOcclusionValueError)));
                    }
                    --EditorGUI.indentLevel;
                }

                EditorGUILayout.Space();
                SetValue(kFoldOptionalParameters, EditorGUIXLayout.InspectorFoldout(GetValue(kFoldOptionalParameters), Content.optionalParametersTitle, DelightingHelpers.GetIcon(errorCode, kOptionalError)));
                if (GetValue(kFoldOptionalParameters))
                {
                    ++EditorGUI.indentLevel;
                    if ((displays & DelightingUI.Display.FieldPositionTexture) != 0)
                    {
                        SetValue(kPositionTexture, EditorGUIXLayout.InlineObjectField(Content.positionTextureLabel, GetValue(kPositionTexture), DelightingHelpers.GetIcon(errorCode, kPositionValueError)));
                    }
                    if ((displays & DelightingUI.Display.FieldMaskTexture) != 0)
                    {
                        SetValue(kMaskTexture, EditorGUIXLayout.InlineObjectField(Content.maskLabel, GetValue(kMaskTexture), DelightingHelpers.GetIcon(errorCode, kMaskValueError)));
                    }
                    if ((displays & DelightingUI.Display.FieldSwitchYZAxes) != 0)
                    {
                        SetValue(kSwitchYZaxes, EditorGUILayout.Toggle(Content.switchYZLabel, GetValue(kSwitchYZaxes)));
                    }
                    --EditorGUI.indentLevel;
                }
            }

            if ((displays & DelightingUI.Display.SectionDelighting) != 0)
            {
                EditorGUILayout.Space();
                SetValue(kFoldDelightingParameters, EditorGUIXLayout.InspectorFoldout(GetValue(kFoldDelightingParameters), Content.delightingParametersTitle));
                if (GetValue(kFoldDelightingParameters))
                {
                    ++EditorGUI.indentLevel;
                    GUI.enabled = GetValue(kPreviewTexture) != null;

                    //if ((displays & DelightingUI.Display.FieldNoiseReduction) != 0)
                    // SetValue(kSmoothNormals, EditorGUILayout.Slider(Content.smoothNormalsLabel, GetValue(kSmoothNormals), 0, 2));
                    if ((displays & DelightingUI.Display.FieldRemoveHighlights) != 0)
                    {
                        SetValue(kRemoveHighlights, EditorGUILayout.Slider(Content.removeHighlightsLabel, GetValue(kRemoveHighlights), 0, 1));
                    }
                    if ((displays & DelightingUI.Display.FieldRemoveDarkNoise) != 0)
                    {
                        SetValue(kRemoveDarkNoise, EditorGUILayout.Slider(Content.removeDarkNoiseLabel, GetValue(kRemoveDarkNoise), 0, 1));
                    }
                    if ((displays & DelightingUI.Display.FieldSeparateDarkAreas) != 0)
                    {
                        SetValue(kSeparateDarkAreas, EditorGUILayout.Slider(Content.separateDarkAreasLabel, GetValue(kSeparateDarkAreas), 0, 1));
                    }
                    if ((displays & DelightingUI.Display.FieldForceLocalDelighting) != 0)
                    {
                        SetValue(kForceLocalDelighting, EditorGUILayout.Slider(Content.forceLocalDelightingLabel, GetValue(kForceLocalDelighting), 0, 1));
                    }

                    GUI.enabled = true;
                    --EditorGUI.indentLevel;
                }
            }

            if ((displays & DelightingUI.Display.SectionImport) != 0)
            {
                EditorGUILayout.Space();
                SetValue(kFoldImportParameters, EditorGUIXLayout.InspectorFoldout(GetValue(kFoldImportParameters), Content.importPanelTitle));
                if (GetValue(kFoldImportParameters))
                {
                    ++EditorGUI.indentLevel;
                    SetValue(kBaseTextureSuffix, EditorGUILayout.TextField(Content.baseTextureLabel, GetValue(kBaseTextureSuffix)));
                    SetValue(kNormalsTextureSuffix, EditorGUILayout.TextField(Content.normalsTextureLabel, GetValue(kNormalsTextureSuffix)));
                    SetValue(kBentNormalsTextureSuffix, EditorGUILayout.TextField(Content.bentNormalsTextureLabel, GetValue(kBentNormalsTextureSuffix)));
                    SetValue(kAmbientOcclusionTextureSuffix, EditorGUILayout.TextField(Content.ambientOcclusionTextureLabel, GetValue(kAmbientOcclusionTextureSuffix)));
                    SetValue(kPositionsTextureSuffix, EditorGUILayout.TextField(Content.positionTextureLabel, GetValue(kPositionsTextureSuffix)));
                    SetValue(kMaskTextureSuffix, EditorGUILayout.TextField(Content.maskLabel, GetValue(kMaskTextureSuffix)));
                    --EditorGUI.indentLevel;
                }
            }

            var messages = GetValue(kInspectorErrorMessages);

            if (messages != null)
            {
                EditorGUILayout.Space();
                for (int i = 0; i < messages.Count; i++)
                {
                    EditorGUILayout.HelpBox(messages[i], MessageType.Error, true);
                }
            }

            if ((displays & (DelightingUI.Display.ButtonCompute | DelightingUI.Display.ButtonExport)) != 0)
            {
                var computeStyle = Styles.largeButton;
                var exportStyle  = Styles.largeButton;

                if ((displays & (DelightingUI.Display.ButtonCompute | DelightingUI.Display.ButtonExport)) ==
                    (DelightingUI.Display.ButtonCompute | DelightingUI.Display.ButtonExport))
                {
                    computeStyle = Styles.largeButtonLeft;
                    exportStyle  = Styles.largeButtonRight;
                }

                GUILayout.Box(GUIContent.none, Styles.separator);
                GUI.enabled = GetValue(kHasValidInput);
                GUILayout.BeginHorizontal();
                if ((displays & DelightingUI.Display.ButtonCompute) != 0 &&
                    GUILayout.Button(Content.computeLabel, computeStyle))
                {
                    ExecuteCommand(kCmdProcessFromGather);
                }
                if ((displays & DelightingUI.Display.ButtonExport) != 0 &&
                    GUILayout.Button(Content.exportLabel, exportStyle))
                {
                    ExecuteCommand(kCmdExport);
                }
                GUILayout.EndHorizontal();
            }
            GUI.enabled = true;

            if ((displays & DelightingUI.Display.SectionDebug) != 0)
            {
                EditorGUILayout.Space();
                SetValue(kFoldDebugParameters, EditorGUIXLayout.InspectorFoldout(GetValue(kFoldDebugParameters), Content.debugPanelTitle));
                if (GetValue(kFoldDebugParameters))
                {
                    ++EditorGUI.indentLevel;
                    m_DebugTexture.OnGUI();
                    --EditorGUI.indentLevel;
                }
            }
            EditorGUILayout.EndScrollView();
        }
Beispiel #11
0
 public override void Dispose()
 {
     base.Dispose();
     DelightingHelpers.DeleteRTIfRequired(m_latLongExposed);
     m_latLongExposed = null;
 }
        public override void OnGUI()
        {
            var controlId  = EditorGUIUtility.GetControlID(kCanvasHash, FocusType.Passive);
            var dropZoneId = EditorGUIUtility.GetControlID(kDropZoneHash, FocusType.Passive);

            var texture = GetValue(kPreviewTexture);

            var hasTexture    = texture != null;
            var targetTexture = (Texture)texture ?? Texture2D.whiteTexture;

            Rect canvasRectViewport;

            if (hasTexture)
            {
                var width  = texture != null ? texture.width : 256;
                var height = texture != null ? texture.height : 256;

                var cameraPosition = GetValue(kCameraPosition);
                var zoom           = GetValue(kZoom);
                EditorGUIXLayout.Canvas(controlId, ref cameraPosition, ref zoom, null, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
                canvasRectViewport = GUILayoutUtility.GetLastRect();
                SetValue(kCameraPosition, cameraPosition);
                SetValue(kZoom, zoom);

                GUI.BeginClip(canvasRectViewport);
                DelightingHelpers.PushSRGBWrite(false);
                GUI.DrawTexture(EditorGUIX.GetCanvasDestinationRect(cameraPosition, zoom, width, height), targetTexture, ScaleMode.ScaleToFit);
                DelightingHelpers.PopSRGBWrite();

                if (Event.current.type == EventType.Repaint)
                {
                    m_Separator.OnGUI();
                    if (GetValue(kOverrideReferenceZone))
                    {
                        m_Gizmo.OnGUI();
                    }
                }
                else
                {
                    if (GetValue(kOverrideReferenceZone))
                    {
                        m_Gizmo.OnGUI();
                    }
                    m_Separator.OnGUI();
                }
                GUI.EndClip();

                var fitCanvasToWindow = GetValue(kFitCanvasToWindow);
                if (fitCanvasToWindow && Event.current.type == EventType.Repaint)
                {
                    EditorGUIX.CancelCanvasZoom(controlId);
                    var widthRatio   = canvasRectViewport.width / (float)width;
                    var heightRatio  = canvasRectViewport.height / (float)height;
                    var widthOffset  = 0f;
                    var heightOffset = 0f;
                    if (widthRatio < heightRatio)
                    {
                        zoom         = widthRatio;
                        heightOffset = (canvasRectViewport.height - zoom * height) * 0.5f;
                    }
                    else
                    {
                        zoom        = heightRatio;
                        widthOffset = (canvasRectViewport.width - zoom * width) * 0.5f;
                    }
                    SetValue(kZoom, zoom);
                    SetValue(kCameraPosition, new Vector2(widthOffset, heightOffset));
                    SetValue(kFitCanvasToWindow, false);
                }
            }
            else
            {
                EditorGUIXLayout.DropZoneHint(Content.dropZoneLabel);
                canvasRectViewport = GUILayoutUtility.GetLastRect();
            }

            if (EditorGUIX.DropZone(dropZoneId, canvasRectViewport, CanAcceptCallback))
            {
                var objs = DragAndDrop.objectReferences;
                if (objs.Length > 0)
                {
                    var path = AssetDatabase.GetAssetPath(objs[0]);
                    if (AssetDatabase.IsValidFolder(path))
                    {
                        SetValue(kInputFolderPath, path);
                        ExecuteCommand(kCmdLoadInputFolder);
                    }
                }
            }
        }