Ejemplo n.º 1
0
        private void UpdateTexture()
        {
            // create preview RT here and keep until the next Repaint
            if (m_previewRT != null)
            {
                RenderTexture.ReleaseTemporary(m_previewRT);
            }

            NoiseSettings noiseSettings = m_serializedNoise.targetObject as NoiseSettings;

            m_previewRT = RenderTexture.GetTemporary(512, 512, 0, NoiseUtils.previewFormat);
            RenderTexture tempRT = RenderTexture.GetTemporary(512, 512, 0, NoiseUtils.singleChannelFormat);

            RenderTexture prevActive = RenderTexture.active;

            NoiseUtils.Blit2D(noiseSettings, tempRT);

            NoiseUtils.BlitPreview2D(tempRT, m_previewRT);

            RenderTexture.active = prevActive;

            RenderTexture.ReleaseTemporary(tempRT);

            m_image.image = m_previewRT;
        }
Ejemplo n.º 2
0
        private void Export2D()
        {
            Texture2D texture = null;

            try
            {
                string path = EditorUtility.SaveFilePanel("Export Noise To Texture2D",
                                                          Application.dataPath,
                                                          "New Noise Texture2D.png",
                                                          "png");

                if (!path.StartsWith(Application.dataPath))
                {
                    Debug.LogError("You must specificy a path in your project's Assets folder to export a Noise Texture");
                }

                if (!string.IsNullOrEmpty(path))
                {
                    EditorUtility.DisplayProgressBar("Exporting Noise to Texture2D", "Making some noise...", 0.1f);

                    texture = NoiseUtils.BakeToTexture2D(m_noise, dims2D.x, dims2D.y, m_format, TextureCreationFlags.None);

                    byte[] bytes = ImageConversion.EncodeToPNG(texture);

                    System.IO.File.WriteAllBytes(path, bytes);

                    Texture2D.DestroyImmediate(texture);
                    texture = null;

                    string assetPath = path.Remove(0, Application.dataPath.Length - "Assets".Length);

                    AssetDatabase.Refresh();

                    EditorUtility.ClearProgressBar();

                    texture = AssetDatabase.LoadAssetAtPath <Texture2D>(assetPath);
                    EditorGUIUtility.PingObject(texture);
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e);

                if (texture != null)
                {
                    Texture2D.DestroyImmediate(texture);
                }

                Debug.Log("Exception caught");

                EditorUtility.ClearProgressBar();
            }
        }
        private void Export3D()
        {
            Texture3D texture = null;

            var textureDims   = m_exportDims3D.value;
            var textureFormat = m_exportFormat.value;

            try
            {
                string path = EditorUtility.SaveFilePanel("Export Noise To Texture3D",
                                                          Application.dataPath,
                                                          "New Noise Texture3D.asset",
                                                          "asset");

                if (string.IsNullOrEmpty(path))
                {
                    return;
                }

                if (!path.StartsWith(Application.dataPath))
                {
                    Debug.LogError("You must specificy a path in your project's Assets folder to export a Noise Texture");
                }

                if (!string.IsNullOrEmpty(path) && path.StartsWith(Application.dataPath))
                {
                    EditorUtility.DisplayProgressBar("Exporting Noise to Texture3D", "Making some noise...", 0.1f);

                    texture = NoiseUtils.BakeToTexture3D(m_noiseUpdateTarget, textureDims.x, textureDims.y, textureDims.z, textureFormat, TextureCreationFlags.None);

                    AssetDatabase.CreateAsset(texture, path.Remove(0, Application.dataPath.Length - "Assets".Length));

                    AssetDatabase.Refresh();

                    EditorUtility.ClearProgressBar();

                    EditorGUIUtility.PingObject(texture);
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e);

                if (texture != null)
                {
                    Texture2D.DestroyImmediate(texture);
                }

                EditorUtility.ClearProgressBar();
            }
        }
        protected override void OnEval(FilterContext fc, RenderTexture sourceRenderTexture, RenderTexture destinationRenderTexture)
        {
            if (m_noiseSettings == null)
            {
                m_noiseSettings = ScriptableObject.CreateInstance <NoiseSettings>();
            }

            m_noiseSettings.useTextureForPositions = m_useHeightmap;

            if (m_useHeightmap)
            {
                m_noiseSettings.positionTexture = fc.rtHandleCollection[FilterContext.Keywords.Heightmap];
            }

            Vector3 brushPosWS = fc.brushPos - m_lastBrushPosition;

            brushPosWS.y        = 0;
            m_lastBrushPosition = fc.brushPos;
            float brushSize     = fc.brushSize;
            float brushRotation = fc.brushRotation - m_lastRotation;

            m_lastRotation = fc.brushRotation;
            // TODO(wyatt): remove magic number and tie it into NoiseSettingsGUI preview size somehow
            float previewSize = 1 / 512f;

            // get proper noise material from current noise settings
            NoiseSettings noiseSettings = m_noiseSettings;
            Material      mat           = NoiseUtils.GetDefaultBlitMaterial(noiseSettings);

            // setup the noise material with values in noise settings
            noiseSettings.SetupMaterial(mat);

            // change pos and scale so they match the noiseSettings preview
            bool isWorldSpace = false == m_isLocalSpace;

            brushSize  = isWorldSpace ? brushSize * previewSize : 1;
            brushPosWS = isWorldSpace ? brushPosWS * previewSize : Vector3.zero;

            // compensate for the difference between the size of the rotated brush and the square noise RT
            var brushTransform  = GetBrushTransform(fc);
            var scaleMultiplier = new Vector2(
                1.0f / (fc.brushSize / brushTransform.GetBrushXYBounds().width),
                1.0f / (fc.brushSize / brushTransform.GetBrushXYBounds().height));

            Quaternion rotQ = Quaternion.AngleAxis(-brushRotation, Vector3.up);

            // accumulate transformation delta
            m_noiseToWorld *= Matrix4x4.TRS(brushPosWS, rotQ, Vector3.one);

            mat.SetMatrix(NoiseSettings.ShaderStrings.transform, noiseSettings.trs * m_noiseToWorld * Matrix4x4.Scale(new Vector3(scaleMultiplier.x, 1.0f, scaleMultiplier.y) * brushSize));

            int pass = NoiseUtils.kNumBlitPasses * NoiseLib.GetNoiseIndex(noiseSettings.domainSettings.noiseTypeName);

            var desc = destinationRenderTexture.descriptor;

            desc.graphicsFormat = NoiseUtils.singleChannelFormat;
            desc.sRGB           = false;
            RTHandle rt = RTUtils.GetTempHandle(desc);

            Graphics.Blit(sourceRenderTexture, rt, mat, pass);

            Material blendMat = FilterUtility.blendModesMaterial;

            blendMat.SetTexture("_BlendTex", rt);
            Graphics.Blit(sourceRenderTexture, destinationRenderTexture, blendMat, 1);
            RTUtils.Release(rt);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Renders an interactive Noise Preview along with tooltip icons and an optional Export button that opens a new ExportNoiseWindow.
        /// A background image is also rendered behind the preview that takes up the entire width of the EditorWindow currently being drawn.
        /// </summary>
        /// <param name = "minSize"> Minimum size for the Preview </param>
        /// <param name = "showExportButton"> Whether or not to render the Export button </param>
        public void DrawPreviewTexture(float minSize, bool showExportButton = true)
        {
            // Draw label with tooltip
            GUILayout.Label(Styles.noisePreview);

            float padding   = 4f;
            float iconWidth = 40f;
            int   size      = (int)Mathf.Min(minSize, EditorGUIUtility.currentViewWidth);
            Rect  totalRect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, size + padding * 2); // extra pixels for highlight border

            Color prev = GUI.color;

            GUI.color = new Color(.15f, .15f, .15f, 1f);
            GUI.DrawTexture(totalRect, Texture2D.whiteTexture, ScaleMode.StretchToFill, false);
            GUI.color = Color.white;

            // draw info icon
            // if(totalRect.Contains(Event.current.mousePosition))
            {
                Rect infoIconRect = new Rect(totalRect.x + padding, totalRect.y + padding, iconWidth, iconWidth);
                GUI.Label(infoIconRect, Styles.infoIcon);
                // GUI.Label( infoIconRect, Styles.noiseTooltip );
            }

            // draw export button
            float buttonWidth  = GUI.skin.button.CalcSize(Styles.export).x;
            float buttonHeight = EditorGUIUtility.singleLineHeight;
            Rect  exportRect   = new Rect(totalRect.xMax - buttonWidth - padding, totalRect.yMax - buttonHeight - padding, buttonWidth, buttonHeight);

            if (GUI.Button(exportRect, Styles.export))
            {
                serializedNoise.ApplyModifiedProperties();
                serializedNoise.Update();

                ExportNoiseWindow.ShowWindow(serializedNoise.targetObject as NoiseSettings);
            }

            float safeSpace   = Mathf.Max(iconWidth * 2, buttonWidth * 2) + padding * 4;
            float minWidth    = Mathf.Min(size, totalRect.width - safeSpace);
            Rect  previewRect = new Rect(totalRect.x + totalRect.width / 2 - minWidth / 2, totalRect.y + totalRect.height / 2 - minWidth / 2, minWidth, minWidth);

            EditorGUIUtility.AddCursorRect(previewRect, MouseCursor.Pan);

            if (previewRect.Contains(Event.current.mousePosition))
            {
                serializedNoise.Update();

                HandlePreviewTextureInput(previewRect);

                serializedNoise.ApplyModifiedProperties();
            }

            if (Event.current.type == EventType.Repaint)
            {
                RenderTexture prevActive = RenderTexture.active;

                // create preview RT here and keep until the next Repaint
                var previewRT = RenderTexture.GetTemporary(512, 512, 0, NoiseUtils.previewFormat);

                NoiseSettings noiseSettings = serializedNoise.targetObject as NoiseSettings;
                RenderTexture tempRT        = RenderTexture.GetTemporary(512, 512, 0, NoiseUtils.singleChannelFormat);

                NoiseUtils.Blit2D(noiseSettings, tempRT);
                NoiseUtils.BlitPreview2D(tempRT, previewRT);
                RenderTexture.active = prevActive;
                GUI.DrawTexture(previewRect, previewRT, ScaleMode.ScaleToFit, false);

                RenderTexture.ReleaseTemporary(tempRT);
                RenderTexture.ReleaseTemporary(previewRT);
            }

            GUI.color = prev;
        }
        private void ApplyBrushInternal(Terrain terrain, PaintContext ctx, BrushTransform brushXform, Vector3 brushPosWS,
                                        float brushRotation, float brushStrength, float brushSize, Texture brushTexture)
        {
            var prevRT = RenderTexture.active;

            var brushPositionOffset = brushPosWS - m_lastBrushPosition;

            m_lastBrushPosition   = brushPosWS;
            brushPositionOffset.y = 0;

            var rotationDelta = brushRotation - m_lastRotation;

            m_lastRotation = brushRotation;

            //blit steps
            //1. blit noise to intermediate RT, this includes all the noise transformations and filters,
            //using the appropriate noise material. do this with NoiseUtils.Blit2D?
            //2. use that noise texture and mult it with brushmask to paint height on terrain

            // TODO(wyatt): remove magic number and tie it into NoiseSettingsGUI preview size somehow
            float previewSize = 1 / 512f;

            // get proper noise material from current noise settings
            NoiseSettings noiseSettings = this.noiseSettings;
            Material      matNoise      = NoiseUtils.GetDefaultBlitMaterial(noiseSettings);

            // setup the noise material with values in noise settings
            noiseSettings.SetupMaterial(matNoise);

            // change pos and scale so they match the noiseSettings preview
            bool isWorldSpace = (m_toolSettings.coordSpace == CoordinateSpace.World);

            brushSize           = isWorldSpace ? brushSize * previewSize : 1;
            brushPositionOffset = isWorldSpace ? brushPositionOffset * previewSize : Vector3.zero;
            var brushTransform  = NoiseFilter.GetBrushTransform(rotationDelta, brushSize);
            var scaleMultiplier = new Vector2(
                1.0f / (brushSize / brushTransform.GetBrushXYBounds().width),
                1.0f / (brushSize / brushTransform.GetBrushXYBounds().height));

            // // override noise transform
            Quaternion rotQ = Quaternion.AngleAxis(-rotationDelta, Vector3.up);

            // accumulate transformation delta
            m_noiseToWorld *= Matrix4x4.TRS(brushPositionOffset, rotQ, Vector3.one);

            matNoise.SetMatrix(NoiseSettings.ShaderStrings.transform, noiseSettings.trs * m_noiseToWorld * Matrix4x4.Scale(new Vector3(scaleMultiplier.x, 1.0f, scaleMultiplier.y) * brushSize));

            var noisePass = NoiseUtils.kNumBlitPasses * NoiseLib.GetNoiseIndex(noiseSettings.domainSettings.noiseTypeName);

            // render the noise field to a texture
            // TODO(wyatt): Handle the 3D case. Would need to blit to Volume Texture
            var rtDesc = ctx.destinationRenderTexture.descriptor;

            rtDesc.graphicsFormat = NoiseUtils.singleChannelFormat;
            rtDesc.sRGB           = false;
            var noiseRT = RTUtils.GetTempHandle(rtDesc);

            RenderTexture.active = noiseRT; // keep this
            Graphics.Blit(noiseRT, matNoise, noisePass);

            // then add the result to the heightmap using the noise height tool shader
            Material matFinal  = paintMaterial;
            var      brushMask = RTUtils.GetTempHandle(ctx.sourceRenderTexture.width, ctx.sourceRenderTexture.height, 0, FilterUtility.defaultFormat);

            Utility.SetFilterRT(commonUI, ctx.sourceRenderTexture, brushMask, matFinal);
            TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushXform, matFinal);
            // set brush params
            Vector4 brushParams = new Vector4(0.01f * brushStrength, 0.0f, brushSize, 1 / brushSize);

            matFinal.SetVector("_BrushParams", brushParams);
            matFinal.SetTexture("_BrushTex", brushTexture);
            matFinal.SetTexture("_NoiseTex", noiseRT);
            matFinal.SetVector("_WorldHeightRemap", m_toolSettings.worldHeightRemap);
            Graphics.Blit(ctx.sourceRenderTexture, ctx.destinationRenderTexture, matFinal, 0);

            RTUtils.Release(noiseRT);
            RTUtils.Release(brushMask);

            RenderTexture.active = prevRT;
        }
        private void ApplyBrushInternal(Terrain terrain, PaintContext ctx, BrushTransform brushTransform)
        {
            Init();

            m_rtCollection.ReleaseRTHandles();
            m_rtCollection.GatherRTHandles(ctx.sourceRenderTexture.width, ctx.sourceRenderTexture.height, 16);

            Graphics.Blit(ctx.sourceRenderTexture, m_rtCollection[RenderTextureIDs.sourceHeight]);

            Material mat       = GetMaterial();
            var      brushMask = RTUtils.GetTempHandle(ctx.sourceRenderTexture.width, ctx.sourceRenderTexture.height, 0, FilterUtility.defaultFormat);

            Utility.SetFilterRT(commonUI, ctx.sourceRenderTexture, brushMask, mat);

            Matrix4x4 toolMatrix = Matrix4x4.TRS(Vector3.zero, toolSettings.rotation, toolSettings.scale);

            Bounds modelBounds   = activeMesh.bounds;
            float  maxModelScale = Mathf.Max(Mathf.Max(modelBounds.size.x, modelBounds.size.y), modelBounds.size.z);
            // maxModelScale *= Mathf.Sqrt( 2 + maxModelScale * maxModelScale / 4 ) * .5f; // mult so the mesh fits a little better within the camera / stamp texture bounds
            // maxModelScale /= 1.414f;
            float x   = .5f;
            float y   = .5f;
            float xy  = Mathf.Sqrt(x * x + y * y);
            float z   = .5f;
            float xyz = Mathf.Sqrt(xy * xy + z * z);

            maxModelScale *= xyz;

            // build the model matrix to transform the mesh with. we want to scale it to fit in the brush bounds and also center it in the brush bounds
            Matrix4x4 model = toolMatrix * Matrix4x4.Scale(Vector3.one / maxModelScale) * Matrix4x4.Translate(-modelBounds.center);

            // get the world bounds here so we can calculate the needed offset along the up axis
            // Bounds worldBounds = MeshUtility.TransformBounds( model, activeMesh.bounds );
            // float localHeightOffset = Mathf.Min( worldBounds.extents.y, toolSettings.stampHeight / brushUI.terrainUnderCursor.terrainData.size.y  * .5f );
            // Matrix4x4 localHeightOffsetMatrix = Matrix4x4.Translate( Vector3.up * localHeightOffset );
            // apply the local height offset
            // model = localHeightOffsetMatrix * model;

            Vector3 translate = Vector3.up * (toolSettings.stampHeight) / commonUI.terrainUnderCursor.terrainData.size.y;

            // translate = translate / brushUI.brushStrength * .5f;
            model = Matrix4x4.Translate(translate) * model;

            // actually render the mesh to texture to be used with the tool shader
            MeshUtils.RenderTopdownProjection(activeMesh, model,
                                              m_rtCollection[RenderTextureIDs.meshStamp],
                                              MeshUtils.defaultProjectionMaterial,
                                              MeshUtils.ShaderPass.Height);
            // this doesn't actually apply any noise to the destination RT but will color the destination RT based on whether the fragment values are (+) or (-)
            NoiseUtils.BlitPreview2D(m_rtCollection[RenderTextureIDs.meshStamp], m_rtCollection[RenderTextureIDs.meshStampPreview]);

            // generate a mask for the mesh to be used in the compositing shader
            MeshUtils.RenderTopdownProjection(activeMesh, model,
                                              m_rtCollection[RenderTextureIDs.meshStampMask],
                                              MeshUtils.defaultProjectionMaterial,
                                              MeshUtils.ShaderPass.Mask);

            // perform actual composite of mesh stamp and terrain source heightmap
            float   brushStrength = Event.current.control ? -commonUI.brushStrength : commonUI.brushStrength;
            Vector4 brushParams   = new Vector4(brushStrength, toolSettings.blendAmount, (commonUI.raycastHitUnderCursor.point.y - commonUI.terrainUnderCursor.GetPosition().y) / commonUI.terrainUnderCursor.terrainData.size.y * .5f, toolSettings.stampHeight / commonUI.terrainUnderCursor.terrainData.size.y * .5f);

            mat.SetVector("_BrushParams", brushParams);
            mat.SetTexture("_MeshStampTex", m_rtCollection[RenderTextureIDs.meshStamp]);
            mat.SetTexture("_MeshMaskTex", m_rtCollection[RenderTextureIDs.meshStampMask]);
            mat.SetFloat("_TerrainHeight", commonUI.terrainUnderCursor.terrainData.size.y);
            TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushTransform, mat);
            Graphics.Blit(ctx.sourceRenderTexture, ctx.destinationRenderTexture, mat, 0);
            Graphics.Blit(ctx.destinationRenderTexture, m_rtCollection[RenderTextureIDs.combinedHeight]);

            // restore old render target
            RenderTexture.active = ctx.oldRenderTexture;
            RTUtils.Release(brushMask);
        }