- Home /
OnSceneGUI render projection onto object surface
Main question
I'm building a custom Terrain editor, and I can't determine how to get a projection of the 'brush' to flow over the terrain like the built-in Unity terrain editor.
At the moment of I'm using Handles.DrawLines
, function to render a square, but this doesn't "hug" the terrain shape.
I looked through the scripting API, but didn't find anything else in Handles
, EditorUtility
, or EditorGUIUtility
that might be useful. I could possibly create a game object in the editor that projects onto the terrain, but not sure if you can hide it, unless I can somehow create non-permanent objects in OnSceneGUI
. I could maybe use some kind of Gizmo
but that looked like it was just for static renderings around the gameobject when it's rendered / didn't look like there was an option for mouse movement.
Random side blurb
Does anyone know of a good resource for creating custom Unity Editor functionality? I've been struggling to find any kind of explanation for how to do anything beyond adding a custom property to the inspector window. This is one of the things holding me back from actually developing in Unity, because I haven't been able to learn methods to create custom tooling in order to remove repetitive tasks.
Example questions - Can I create instance variables in an Editor class? Is that safe? - The question I'm asking now about creating the projection
Answer by Thygrrr · May 15 at 06:04 PM
Do you know the Normal Vector of the Terrain at the position you want to draw the brush? (probably, because you're creating the terrain yourself)
If the brush has a transform, you can just set transform.up to that normal. If not and your brush doesn't have to be square, you can use
Handles.DrawSolidDisc(Vector3 center, Vector3 normal, float radius)
See - Unity Docs
radius can be your brush size, center is the position where the brush has touched the terrain (so its local height), and normal is the Terrain surface normal vector at that position.
That's good point, I could do something with the normal as an in-between. I'd really like to have projection down onto the terrain like the built-in terrain editor does.
I tried DrawWireDisc
, and it works fine, just doesn't project down onto the terrain. I'm using the square, so I didn't have to worry about the Texture2D.SetPixels
algorithm to get the circle right.
I was actually wondering a bit ago if maybe the Unity Terrain uses its heightmap to create a mesh and then uses the DrawMesh
from Gizmos. Didn't want to go far down into the rabbit hole before checking if there's another way.
I see - that is probably done via a shader.
Perhaps you can get some mileage out of a Projector?
I ended up looking back at using a Projector. That required me doing things a little differently. Instead of using DrawGizmos() within the Editor script, I created a full GameObject in OnEnable(), and gave it the Projector with appropriate settings. Then I reposition and toggle active state within OnSceneGUI(). I didn't think I was able to create GameObjects within the custom editor, but it seems to work fine. I created a custom Projector shader to add a sort of outline to the projection, but based it off of the shader in the Standard Assets.
Just wrote this code in case others come along and are curious. Not sure if it compiles properly because I just remade it.
\
[CustomEditor(typeof(MyThing))
public class MyEditor : Editor
{
MyThing myThing;
GameObject brush;
Projector projector;
Vector3 brushOffset = new Vector3(0, -1000, 0);
void OnEnable()
{
myThing = (MyThing) target;
brush = new GameObject();
projector = brush.AddComponent<Projector>();
// set projector settings like rotation
projector.orthographicSize = 10;
}
void OnSceneGUI()
{
// Reposition brush
brush.position = Event.current.mousePosition + brushOffset;
}
}
This is unrelated to my original question, but I also ended up using Graphics.Blit and a material to do the texture drawing. I used references from these unity docs for creating custom terrain tools and kind of reverse engineered it. https://docs.unity3d.com/Packages/com.unity.terrain-tools@4.0/manual/create-modify-terrain-heightmap.html
The one snag I hit was long render times. I was able to fix that by using AsyncGPUReadbackRequest, and inside of OnDisable() I check to make sure they're all finished. Removes a lot of lag I was getting when painting textures. https://docs.unity3d.com/ScriptReference/Rendering.AsyncGPUReadbackRequest.html
Your answer
Follow this Question
Related Questions
Custom inspector difficulties creating a Box / Group like widget 1 Answer
GUIStyle doesn't work when renamed. What to do here? 1 Answer
How can i create a pup-up menu like the one for choose the shader on materials in unity 2019? 1 Answer
Setting custom amount of space between elements in a custom inspector with EditorGUILayout ? 1 Answer
Is it possible to store and display EditorGUILayout.Toggles? 0 Answers