Пример #1
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            if (Event.current.type == EventType.MouseDrag)
            {
                return(true);
            }

            Material mat = TerrainPaintUtility.GetBuiltinPaintMaterial();

            Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize);

            TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect);

            Vector4 brushParams = new Vector4(editContext.brushStrength * 0.01f, 0.0f, m_StampHeight, 0.0f);

            if (Event.current.shift)
            {
                brushParams.x = -brushParams.x;
            }

            mat.SetTexture("_BrushTex", editContext.brushTexture);
            mat.SetVector("_BrushParams", brushParams);
            Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.StampHeight);

            TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Stamp");
            return(true);
        }
Пример #2
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            if (Event.current.type == EventType.MouseDown)
            {
                m_PrevBrushPos = editContext.uv;
                return(false);
            }

            if (Event.current.type == EventType.MouseDrag && m_PreviousEvent == EventType.MouseDrag)
            {
                Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize);
                TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect);

                Vector2 smudgeDir = editContext.uv - m_PrevBrushPos;

                Material mat         = GetPaintMaterial();
                Vector4  brushParams = new Vector4(editContext.brushStrength, smudgeDir.x, smudgeDir.y, 0);
                mat.SetTexture("_BrushTex", editContext.brushTexture);
                mat.SetVector("_BrushParams", brushParams);
                Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 0);

                TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Smudge Height");

                m_PrevBrushPos = editContext.uv;
            }
            m_PreviousEvent = Event.current.type;
            return(false);
        }
Пример #3
0
        private void StampRender(TerrainPaintUtility.PaintContext read, TerrainPaintUtility.PaintContext write, Material mat, int materialPass)
        {
            // since we only blit the areas that a writeRect is located, we need to get the rest of the texture in destination too
            Graphics.Blit(write.sourceRenderTexture, write.destinationRenderTexture, TerrainPaintUtility.GetBlitMaterial(), 0);

            read.sourceRenderTexture.filterMode = FilterMode.Point;
            mat.SetTexture("_CloneLocation", read.sourceRenderTexture);

            // only blit areas that we can read from in the read context (protects against writing uninitialized memory in the texture when read rect is off of terrain)
            for (int i = 0; i < read.clippedTiles.Length; ++i)
            {
                RectInt writeRect = read.clippedTiles[i];
                if (writeRect.width == 0 || writeRect.height == 0)
                {
                    continue;
                }

                writeRect.x      /= read.brushRect.width;
                writeRect.y      /= read.brushRect.height;
                writeRect.width  /= read.brushRect.width;
                writeRect.height /= read.brushRect.height;
                mat.SetVector("_WriteRect", new Vector4(writeRect.x, writeRect.y, writeRect.xMax, writeRect.yMax));
                Graphics.Blit(write.sourceRenderTexture, write.destinationRenderTexture, mat, materialPass);
            }
        }
Пример #4
0
        private void PaintAlphamap(Rect writeBrushRect, Terrain terrain, Material mat)
        {
            // paint each layer from the sample to the clone location (adds layer if not present already)
            for (int i = 0; i < m_Sample.m_Terrain.terrainData.terrainLayers.Length; ++i)
            {
                TerrainPaintUtility.PaintContext write = TerrainPaintUtility.BeginPaintTexture(terrain,
                                                                                               writeBrushRect,
                                                                                               m_Sample.m_Terrain.terrainData.terrainLayers[i]);

                if (write == null)
                {
                    continue;
                }

                // read created manually to force read to not add the layer if it wasnt already on the terrain, and to use write's rect with offset
                TerrainPaintUtility.PaintContext read = new TerrainPaintUtility.PaintContext();

                read.brushRect = new RectInt(write.brushRect.position + m_CloneRectPixelOffsetFromStampRect, write.brushRect.size);

                // TODO(wyatt): Uncomment this once Andrew's API changes make it to trunk
                read.CreateTerrainTiles(m_Sample.m_Terrain,
                                        m_Sample.m_Terrain.terrainData.alphamapWidth,
                                        m_Sample.m_Terrain.terrainData.alphamapHeight);
                read.CreateRenderTargets(RenderTextureFormat.R8);
                read.GatherAlphamap(m_Sample.m_Terrain, m_Sample.m_Terrain.terrainData.terrainLayers[i], false);

                // render mix of clone and stamp areas
                StampRender(read, write, mat, (int)ShaderPasses.CloneAlphamap);

                TerrainPaintUtility.ReleaseContextResources(read);
                TerrainPaintUtility.EndPaintTexture(write, "Terrain Paint - Clone Stamp Tool (Alphamap layer " + i + ")");
            }
        }
Пример #5
0
        public static void ShowDefaultPreviewBrush(Terrain terrain, Texture brushTexture, float brushStrength, float brushSize, float futurePreviewScale)
        {
            Ray        mouseRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
            RaycastHit hit;

            if (terrain.GetComponent <Collider>().Raycast(mouseRay, out hit, Mathf.Infinity))
            {
                if (Event.current.shift)
                {
                    brushStrength = -brushStrength;
                }

                Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, hit.textureCoord, brushSize);
                TerrainPaintUtility.PaintContext ctx = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect);

                ctx.sourceRenderTexture.filterMode = FilterMode.Bilinear;
                brushTexture.filterMode            = FilterMode.Bilinear;

                Vector2 topLeft = ctx.brushRect.min;
                float   xfrac   = ((topLeft.x - (int)topLeft.x) / (float)ctx.sourceRenderTexture.width);
                float   yfrac   = ((topLeft.y - (int)topLeft.y) / (float)ctx.sourceRenderTexture.height);

                Vector4 texScaleOffset = new Vector4(0.5f, 0.5f, 0.5f + xfrac + 0.5f / (float)ctx.sourceRenderTexture.width, 0.5f + yfrac + 0.5f / (float)ctx.sourceRenderTexture.height);

                DrawDefaultBrushPreviewMesh(terrain, hit, ctx.sourceRenderTexture, brushTexture, brushStrength * 0.01f, brushSize, defaultPreviewPatchMesh, false, texScaleOffset);
                if ((futurePreviewScale > Mathf.Epsilon) && Event.current.control)
                {
                    DrawDefaultBrushPreviewMesh(terrain, hit, ctx.sourceRenderTexture, brushTexture, futurePreviewScale, brushSize, defaultPreviewPatchMesh, true, texScaleOffset);
                }

                TerrainPaintUtility.ReleaseContextResources(ctx);
            }
        }
Пример #6
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            if (m_Mesh == null || Event.current.type != EventType.MouseDown || Event.current.shift == true)
            {
                return(false);
            }

            Vector3 terrainSize     = terrain.terrainData.size;
            float   maxScale        = Mathf.Max(m_StampScale.x, m_StampScale.z);
            Vector2 brushSizeScaled = new Vector2(maxScale * 2.0f, maxScale * 2.0f);
            Rect    brushRect       = new Rect(editContext.uv * new Vector2(terrainSize.x, terrainSize.z) - brushSizeScaled * 0.5f, brushSizeScaled);

            TerrainPaintUtility.PaintContext context = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect);
            Material mat = GetPaintMaterial();

            DrawMesh(terrain, context, maxScale, mat);

            // draw to heightmap
            mat.SetTexture("_MeshStampTex", m_MeshRenderTexture);
            Graphics.Blit(context.sourceRenderTexture, context.destinationRenderTexture, mat, (int)ShaderPasses.StampToHeightmap);

            TerrainPaintUtility.EndPaintHeightmap(context, "Terrain Paint - Mesh Stamp");
            RenderTexture.ReleaseTemporary(m_MeshRenderTexture);
            m_MeshRenderTexture = null;
            return(true);
        }
Пример #7
0
        private void DrawMesh(Terrain terrain, TerrainPaintUtility.PaintContext context, float maxScale, Material mat)
        {
            m_MeshRenderTexture  = RenderTexture.GetTemporary(context.brushRect.width, context.brushRect.height, 0, terrain.terrainData.heightmapTexture.format, RenderTextureReadWrite.Linear);
            RenderTexture.active = m_MeshRenderTexture;

            // clear black when adding, and white when subtracting
            GL.Clear(true, true, (!Event.current.control) ? Color.black : Color.white, 1.0f);

            // adjust the scale of the mesh to be xyz = 1,y,1 for standard scale of 1,1,1. BrushSize will expand mesh in texture, therefore we need to inverse the scale here
            Vector3 adjustedScale = new Vector3(1, m_StampScale.y / maxScale, 1);

            if (m_StampScale.x > m_StampScale.z)
            {
                adjustedScale.z = m_StampScale.z / m_StampScale.x;
                adjustedScale.y = m_StampScale.y / m_StampScale.x;
            }
            else if (m_StampScale.z > m_StampScale.x)
            {
                adjustedScale.x = m_StampScale.x / m_StampScale.z;
                adjustedScale.y = m_StampScale.y / m_StampScale.z;
            }

            // setup the matrices for rendering manually (to render without a camera)
            Matrix4x4 proj              = Matrix4x4.Ortho(-1.0f, 1.0f, -1.0f, 1.0f, terrain.terrainData.size.y * 2.0f, -1.0f);
            Matrix4x4 view              = Matrix4x4.LookAt(new Vector3(0, 0, -terrain.terrainData.size.y), Vector3.forward, Vector3.up);
            Matrix4x4 drawTranslate     = Matrix4x4.Translate(new Vector3(0, 0, terrain.terrainData.size.y * 0.5f));
            Matrix4x4 stampTranslate    = Matrix4x4.Translate(new Vector3(0, 0, m_SceneRaycastHitPoint.y * 0.5f));
            Matrix4x4 scale             = Matrix4x4.Scale(adjustedScale);
            Matrix4x4 rotate            = Matrix4x4.Rotate(Quaternion.AngleAxis(90.0f, new Vector3(1, 0, 0)) * m_StampRotation);
            Matrix4x4 postScale         = Matrix4x4.Scale(new Vector3(1, 1, maxScale * 0.5f));
            Matrix4x4 postScaleRotScale = postScale * rotate * scale;

            mat.SetMatrix("_MVP", proj * view * drawTranslate * postScaleRotScale);
            mat.SetMatrix("_Model", stampTranslate * postScaleRotScale);
            mat.SetVector("_StampParams", new Vector4(
                              terrain.terrainData.size.y,               // terrain max height
                              m_SceneRaycastHitPoint.y * 0.5f,          // desired mesh height
                              m_OverwriteMode ? 100.0f : 0.0f,          // if in override
                              !Event.current.control ? 100.0f : 0.0f)); // if adding or not
            mat.SetVector("_BrushParams", new Vector4(m_StampHeight * 0.5f, 0.0f, 0.0f, 0.0f));

            // back face culling = boolean operation addition, front face culling = boolean operation subtraction
            if (!Event.current.control)
            {
                mat.SetPass((int)ShaderPasses.DepthPassFrontFaces);
            }
            else
            {
                mat.SetPass((int)ShaderPasses.DepthPassBackFaces);
            }

            GL.PushMatrix();
            Graphics.DrawMeshNow(m_Mesh, Matrix4x4.identity);
            GL.PopMatrix();
        }
Пример #8
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize);

            TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect);

            Material mat         = TerrainPaintUtility.GetBuiltinPaintMaterial();
            Vector4  brushParams = new Vector4(editContext.brushStrength, 0.0f, 0.0f, 0.0f);

            mat.SetTexture("_BrushTex", editContext.brushTexture);
            mat.SetVector("_BrushParams", brushParams);
            Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.SmoothHeights);

            TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Smooth Height");
            return(true);
        }
Пример #9
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize);

            TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect);

            Material mat         = GetPaintMaterial();
            Vector4  brushParams = new Vector4(editContext.brushStrength, 0.0f, m_FeatureSize, 0.0f);

            mat.SetTexture("_BrushTex", editContext.brushTexture);
            mat.SetVector("_BrushParams", brushParams);
            Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 0);

            TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Terrace Erosion");
            return(false);
        }
Пример #10
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            float brushStrength = Event.current.shift ? -editContext.brushStrength : editContext.brushStrength;

            Material mat       = TerrainPaintUtility.GetBuiltinPaintMaterial();
            Rect     brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize);

            TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect);

            // apply brush
            Vector4 brushParams = new Vector4(brushStrength * 0.01f, 0.0f, 0.0f, 0.0f);

            mat.SetTexture("_BrushTex", editContext.brushTexture);
            mat.SetVector("_BrushParams", brushParams);
            Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.RaiseLowerHeight);

            TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Raise or Lower Height");
            return(true);
        }
Пример #11
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize);

            TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintTexture(terrain, brushRect, m_SelectedTerrainLayer);
            if (paintContext == null)
            {
                return(false);
            }

            Material mat = TerrainPaintUtility.GetBuiltinPaintMaterial();
            // apply brush
            Vector4 brushParams = new Vector4(editContext.brushStrength, m_SplatAlpha, 0.0f, 0.0f);

            mat.SetTexture("_BrushTex", editContext.brushTexture);
            mat.SetVector("_BrushParams", brushParams);
            Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.PaintTexture);

            TerrainPaintUtility.EndPaintTexture(paintContext, "Terrain Paint - Texture");
            return(true);
        }
Пример #12
0
        private void PaintHeightmap(Rect writeBrushRect, Terrain terrain, Material mat)
        {
            TerrainPaintUtility.PaintContext write = TerrainPaintUtility.BeginPaintHeightmap(terrain, writeBrushRect);

            // read created manually to use write's rect with offset
            TerrainPaintUtility.PaintContext read = new TerrainPaintUtility.PaintContext();
            read.brushRect = new RectInt(write.brushRect.position + m_CloneRectPixelOffsetFromStampRect, write.brushRect.size);

            // TODO(wyatt): Uncomment this once Andrew's API changes make it to trunk
            read.CreateTerrainTiles(m_Sample.m_Terrain,
                                    m_Sample.m_Terrain.terrainData.heightmapWidth,
                                    m_Sample.m_Terrain.terrainData.heightmapHeight);
            read.CreateRenderTargets(m_Sample.m_Terrain.terrainData.heightmapTexture.format);
            read.GatherHeightmap(m_Sample.m_Terrain);

            // render mix of clone and stamp areas
            StampRender(read, write, mat, (int)ShaderPasses.CloneHeightmap);

            TerrainPaintUtility.ReleaseContextResources(read);
            TerrainPaintUtility.EndPaintHeightmap(write, "Terrain Paint - Clone Stamp Tool (Heightmap)");
        }
Пример #13
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize);

            TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect);

            float finalTwistAmount = m_TwistAmount * -0.001f; //scale to a reasonable value and negate so default mode is clockwise

            if (Event.current.shift)
            {
                finalTwistAmount *= -1.0f;
            }

            Material mat         = GetPaintMaterial();
            Vector4  brushParams = new Vector4(editContext.brushStrength, 0.0f, finalTwistAmount, 0.0f);

            mat.SetTexture("_BrushTex", editContext.brushTexture);
            mat.SetVector("_BrushParams", brushParams);
            Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 0);

            TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Twist Height");
            return(false);
        }
Пример #14
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            if (Event.current.shift)
            {
                m_Height = terrain.terrainData.GetInterpolatedHeight(editContext.uv.x, editContext.uv.y) / terrain.terrainData.size.y;
                editContext.RepaintAllInspectors();
                return(true);
            }
            Material mat = TerrainPaintUtility.GetBuiltinPaintMaterial();

            Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize);

            TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect);

            Vector4 brushParams = new Vector4(editContext.brushStrength * 0.01f, 0.5f * m_Height, 0.0f, 0.0f);

            mat.SetTexture("_BrushTex", editContext.brushTexture);
            mat.SetVector("_BrushParams", brushParams);

            Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.SetHeights);

            TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Set Height");
            return(true);
        }
Пример #15
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            Vector2 uv = editContext.uv;

            //grab the starting position & height
            if (Event.current.shift)
            {
                //m_Height = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y;
                float height = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y;
                m_StartPoint   = new Vector3(uv.x, uv.y, height);
                m_StartTerrain = terrain;
                return(true);
            }

            if (!m_StartTerrain || (Event.current.type == EventType.MouseDrag))
            {
                return(true);
            }

            //get the target position & height
            float   targetHeight = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y;
            Vector3 targetPos    = new Vector3(uv.x, uv.y, targetHeight);

            if (terrain != m_StartTerrain)
            {
                //figure out the stroke vector in uv,height space
                Vector2 targetWorld = transformToWorld(terrain, uv);
                Vector2 targetUVs   = transformToUVSpace(m_StartTerrain, targetWorld);
                targetPos.x = targetUVs.x;
                targetPos.y = targetUVs.y;
            }

            Vector3 stroke       = targetPos - m_StartPoint;
            float   strokeLength = stroke.magnitude;
            int     numSplats    = (int)(strokeLength / (0.001f * m_Spacing));

            Terrain  currTerrain = m_StartTerrain;
            Material mat         = TerrainPaintUtility.GetBuiltinPaintMaterial();

            Vector2 posOffset = new Vector2(0.0f, 0.0f);

            for (int i = 0; i < numSplats; i++)
            {
                float pct = (float)i / (float)numSplats;

                float widthScale    = widthProfile.Evaluate(pct);
                float heightScale   = heightProfile.Evaluate(pct);
                float strengthScale = strengthProfile.Evaluate(pct);

                Vector3 currPos = m_StartPoint + pct * stroke;
                currPos.x += posOffset.x;
                currPos.y += posOffset.y;

                if (currPos.x >= 1.0f && (currTerrain.rightNeighbor != null))
                {
                    currTerrain  = currTerrain.rightNeighbor;
                    currPos.x   -= 1.0f;
                    posOffset.x -= 1.0f;
                }
                if (currPos.x <= 0.0f && (currTerrain.leftNeighbor != null))
                {
                    currTerrain  = currTerrain.leftNeighbor;
                    currPos.x   += 1.0f;
                    posOffset.x += 1.0f;
                }
                if (currPos.y >= 1.0f && (currTerrain.topNeighbor != null))
                {
                    currTerrain  = currTerrain.topNeighbor;
                    currPos.y   -= 1.0f;
                    posOffset.y -= 1.0f;
                }
                if (currPos.y <= 0.0f && (currTerrain.bottomNeighbor != null))
                {
                    currTerrain  = currTerrain.bottomNeighbor;
                    currPos.y   += 1.0f;
                    posOffset.y += 1.0f;
                }

                Vector2 currUV = new Vector2(currPos.x, currPos.y);

                int   finalBrushSize = (int)(widthScale * (float)editContext.brushSize);
                float finalHeight    = (m_StartPoint + heightScale * stroke).z;

                Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(currTerrain, currUV, finalBrushSize);
                TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(currTerrain, brushRect);

                Vector4 brushParams = new Vector4(strengthScale * editContext.brushStrength * 0.01f, 0.5f * finalHeight, 0.0f, editContext.brushRotation);
                mat.SetTexture("_BrushTex", editContext.brushTexture);
                mat.SetVector("_BrushParams", brushParams);

                Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 2);

                TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Bridge");
            }
            return(false);
        }
Пример #16
0
        public override void OnSceneGUI(Terrain terrain, IOnSceneGUI editContext)
        {
            TerrainPaintUtilityEditor.ShowDefaultPreviewBrush(terrain,
                                                              editContext.brushTexture,
                                                              editContext.brushStrength,
                                                              editContext.brushSize,
                                                              0.0f);

            bool drawCloneBrush = true;

            // on mouse up
            if (Event.current.type == EventType.MouseUp)
            {
                m_ActivePaint = false;
                if (!m_Aligned)
                {
                    m_Sample.m_UV       = m_SnapbackCache.m_UV;
                    m_Sample.m_Terrain  = m_SnapbackCache.m_Terrain;
                    m_Sample.m_Position = m_SnapbackCache.m_Position;
                }
            }

            // on mouse move
            if (Event.current.type == EventType.MouseMove || Event.current.type == EventType.MouseDrag)
            {
                if (m_Aligned && m_PaintedOnce)
                {
                    RaycastHit hit;
                    Ray        mouseRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
                    terrain.GetComponent <Collider>().Raycast(mouseRay, out hit, Mathf.Infinity);

                    // check for moving across tiles
                    if (terrain != m_LastPaintLocation.m_Terrain && m_LastPaintLocation.m_Terrain != null)
                    {
                        UpdateLastPosition(hit, terrain);
                    }

                    if (m_Sample.m_Terrain != null)
                    {
                        PositionCloneBrush(hit);
                    }

                    // capture last (current) location for next frame
                    m_LastPaintLocation.m_UV       = hit.textureCoord;
                    m_LastPaintLocation.m_Position = hit.point;
                    m_LastPaintLocation.m_Terrain  = terrain;
                }

                if (m_Aligned && !m_PaintedOnce)
                {
                    drawCloneBrush = false; // dont draw if we havent selected where to paint yet when aligned
                }
            }

            // draw the clone brush preview
            if (m_Sample.m_Terrain != null && drawCloneBrush)
            {
                Rect sampleRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(m_Sample.m_Terrain, m_Sample.m_UV, editContext.brushSize);
                TerrainPaintUtility.PaintContext ctx = TerrainPaintUtility.BeginPaintHeightmap(m_Sample.m_Terrain, sampleRect);

                FilterMode prevCtxFilterMode          = ctx.sourceRenderTexture.filterMode;
                FilterMode prevBrushTextureFilterMode = editContext.brushTexture.filterMode;

                ctx.sourceRenderTexture.filterMode  = FilterMode.Bilinear;
                editContext.brushTexture.filterMode = FilterMode.Bilinear;

                Vector2 topLeft = ctx.brushRect.min;
                float   xfrac   = ((topLeft.x - (int)topLeft.x) / (float)ctx.sourceRenderTexture.width);
                float   yfrac   = ((topLeft.y - (int)topLeft.y) / (float)ctx.sourceRenderTexture.height);

                Vector4 texScaleOffset = new Vector4(0.5f, 0.5f, 0.5f + xfrac + 0.5f / (float)ctx.sourceRenderTexture.width, 0.5f + yfrac + 0.5f / (float)ctx.sourceRenderTexture.height);

                RaycastHit hit = new RaycastHit();
                hit.point = m_Sample.m_Position;

                TerrainPaintUtilityEditor.DrawDefaultBrushPreviewMesh(m_Sample.m_Terrain, hit, ctx.sourceRenderTexture, editContext.brushTexture, 0.0001f, editContext.brushSize, TerrainPaintUtilityEditor.defaultPreviewPatchMesh, true, texScaleOffset);

                ctx.sourceRenderTexture.filterMode  = prevCtxFilterMode;
                editContext.brushTexture.filterMode = prevBrushTextureFilterMode;

                TerrainPaintUtility.ReleaseContextResources(ctx);
            }
        }