- Edited
Newbie but digging into Godot 4 with both hands. (and hoping this post supersedes one I attempted and hopefully successfully deleted......)
Background:
Based on code by a user named Demindiro used to create an outline around a mesh, with some tweaking here and there to work for what I need it for. It takes the mesh, makes a copy of it, and does some viewport/shader magic to create an outline around it that doesn't look horrendous as with other methods I've tried. Works exceedingly well with imported meshes.
I've modified it a bit to both work for Godot 4 and to work with _on_static_body_3d_mouse signals from scenes that contain the mesh I want to outline, so when the user mouses over it outlines and when they move away the outline disappears (by queue_freeing the node). Everything appears to work just fine. My only concern currently is each time the node is created it increments the temp number by one. So if I mouse over the object in game rapidly or slowly and watch the Remote feed I can see the counter ramp up quickly.
See image:
Ignore the 173 hits in Debugger, it's due to an unrelated mesh that I need to address but it's not causing any issues right now so....for later.
I'd assume that after freeing the node, it would reset the counter.
Is this normal behavior? It feels counter-intuitive but being I'm not super familiar with Godot as of yet, I thought I'd ask before throwing this everywhere.
outline.gd code that does the heavy lifting. Attached to outline.tscn that is a subviewport container carrying a subviewport and an additional Camera3D:
extends SubViewportContainer
@export var outline_material: Material
@export var main_camera_path := NodePath()
@onready var root: SubViewport = get_node("SubViewport")
@onready var main_camera: Camera3D = get_node(main_camera_path)
@onready var camera: Camera3D = get_node("SubViewport/Camera3D")
var nodes := {}
func outline_node(node: MeshInstance3D) -> void:
var n := MeshInstance3D.new()
n.mesh = node.mesh
n.material_override = outline_material
var e := node.connect("tree_exited", Callable(self, "remove_node").bind(n))
assert(e == OK)
node.disconnect("tree_exited", Callable(self, "remove_node").bind(n))
root.add_child(n)
nodes[n] = node
func _process(_delta: float) -> void:
call_deferred("post_process")
func post_process() -> void:
camera.fov = main_camera.fov
camera.near = main_camera.near
camera.far = main_camera.far
camera.transform = main_camera.global_transform
for n in nodes:
n.transform = nodes[n].global_transform
func remove_node(node: MeshInstance3D) -> void:
node.queue_free()
nodes.erase(node)
mouseover.gd code that watches for the signal from the mouse and passes either the mesh node to be cloned or the mesh node to be freed to the Outline scene
extends Node3D
func _on_static_body_3d_mouse_entered():
for child in $"RootNode".get_children():
$Outline.outline_node(child)
func _on_static_body_3d_mouse_exited():
for child in $"Outline/SubViewport".get_children():
if child is MeshInstance3D:
$Outline.remove_node(child)