Draw custom editor geometry for a node

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By matrem
:warning: Old Version Published before Godot 3 was released.

Is it possible to draw custom geometry for a node in the editor scene ?

After some search it comes up I can use tool keyword and ImmediateGeometry, or perhaps set up a different spatial gizmo with EditorGismo.create_spatial_gizmo, but i get nothing to work.
Someone propose me to use _draw but it seems to only work for Node2Ds.

:bust_in_silhouette: Reply From: Zylann

The key is to use tool, which will execute the node’s script into the editor as if it was in game. It’s powerful but needs some caution to not mix up game and tool code too much.

Then you can draw stuff the same way as you would draw in game, litterally.

In 2D, it’s easily done with _draw(), and calling update() to redraw if needed.

In 3D, you can indeed use ImmediateGeometry (again, the same way you would in game), but it’s also possible to generate a mesh with SurfaceTool and display it with a MeshInstance, or even talk directly to VisualServer. In the 3D editor itself, that’s how things are done most of the time.

Thanks, yes it’s for 3D, in godot 3.0.
I’ll investigate more drawing with immediate geometry.

matrem | 2017-11-29 06:29

Ok I get something working with :

tool

extends Spatial

var geom
var color = Color(1, 1, 1)
export var radius = 1.0 setget radius_set
const resolution = 20

func _ready():
	instantiate_geom()

func radius_set(new_radius):
	radius = new_radius
	rebuild_geom()

func instantiate_geom():
	if Engine.is_editor_hint() :
		if geom == null :
			geom = $geom
			if geom == null :
				print("new geom")
				geom = ImmediateGeometry.new()
				geom.set_name("geom")
				add_child(geom)
				init_geom()
			else :
				print("found geom : " + geom)

func init_geom() :
	if Engine.is_editor_hint() :
		geom.clear()
		geom.begin(Mesh.PRIMITIVE_LINE_STRIP)
		geom.set_color(color)
		for v in range(resolution+1) :
			var cursor = PI * 2 * v / resolution
			geom.add_vertex(Vector3(cos(cursor), 0, sin(cursor))*radius)
		geom.end()
		geom.begin(Mesh.PRIMITIVE_LINE_STRIP)
		geom.set_color(color)
		for v in range(resolution+1) :
			var cursor = PI * 2 * v / resolution
			geom.add_vertex(Vector3(cos(cursor), sin(cursor), 0)*radius)
		geom.end()
		geom.begin(Mesh.PRIMITIVE_LINE_STRIP)
		geom.set_color(color)
		for v in range(resolution+1) :
			var cursor = PI * 2 * v / resolution
			geom.add_vertex(Vector3(0, cos(cursor), sin(cursor))*radius)
		geom.end()

func rebuild_geom():
	instantiate_geom()
	init_geom()

func _process(delta):
	instantiate_geom()

But I have some problems :slight_smile: :

  • I guess there a bug with tool script not getting alive since the next godot launch
  • set_color does’nt do anything
  • is there a way to change line width?

matrem | 2017-11-29 20:49

Hi, I reply here because I have the same questions : set_color doesn’t work ? Is there a way to change line width ?
Thanks guys.

Elis4 | 2018-10-01 23:34

To those who are asking about line width: no, line can not have width by definition. If something has a width then it’s already a polygon. If you want bold line - draw rectangle instead.
But I’m also confused about set_color function. Is it works? If it is, then how it supposed to be used?

Ternvein | 2019-04-24 12:23

For set_color to work, the ImmediateGeometry node needs to have a material considering vertex colors as albedo, which is not the case with the default material. For example:

var mat = SpatialMaterial.new()
mat.flags_unshaded = true
mat.vertex_color_use_as_albedo = true
geom.material_override = mat

Zylann | 2019-04-24 18:34

Indeed, I forgot that vertex color is ignored by default material… Thanks, Zylann.

Ternvein | 2019-04-25 08:00