@tool extends Node3D @onready var mesh: MeshInstance3D = $Line @onready var plane: MeshInstance3D = $Plane @onready var x_axis: Sprite3D = $XAxis const RADIUS = 0.005 const STEPS = 5 @export var size: Vector2 = Vector2(0.5, 0.3) var points = R.state([]) var minmax = R.computed(func(_arg): if points.value.size() == 0: return [Vector2(0, 0), Vector2(0, 0)] var min=points.value[0] var max=points.value[0] for point in points.value: min.x=min(min.x, point.x) min.y=min(min.y, point.y) max.x=max(max.x, point.x) max.y=max(max.y, point.y) return [min, max] ) var relative_points = R.computed(func(_arg): var min=minmax.value[0] var max=minmax.value[1] return points.value.map(func(point): return Vector2(inverse_lerp(min.x, max.x, point.x), inverse_lerp(min.y, max.y, point.y)) ) ) func _ready(): for i in range(100): points.value.append(Vector2(i, sin(i / 10.0))) R.effect(func(_arg): mesh.mesh=generate_mesh(relative_points.value) ) plane.position = Vector3(size.x / 2, size.y / 2, -0.001) plane.mesh.size = size func generate_mesh(points: Array): if points.size() < 2: return null var sf = SurfaceTool.new() sf.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP) for i in range(points.size() - 1): var point = points[i] var next_point = points[i + 1] var angle = (next_point - point).angle_to(Vector2(1, 0)) var up = Vector2(0, 1).rotated( - angle) var p0 = point + up * RADIUS * 2 var p1 = point + up * - RADIUS * 2 sf.add_vertex(Vector3(p0.x * size.x, p0.y * size.y, 0)) sf.add_vertex(Vector3(p1.x * size.x, p1.y * size.y, 0)) sf.index() sf.generate_normals() var _mesh = sf.commit() sf.clear() sf.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP) for i in range(points.size() - 1): var point = points[i] sf.add_vertex(Vector3(point.x * size.x, point.y * size.y, RADIUS)) sf.add_vertex(Vector3(point.x * size.x, point.y * size.y, -RADIUS)) return sf.commit(_mesh)