172 lines
5.7 KiB
GDScript
172 lines
5.7 KiB
GDScript
@tool
|
|
extends MeshInstance3D
|
|
class_name LineRenderer3D
|
|
|
|
@export var points: Array[Vector3] = [Vector3(0,0,0),Vector3(0,5,0)]:
|
|
set(new_points): points = new_points
|
|
@export var start_thickness:float = 0.1:
|
|
set(new_start_thickness): start_thickness = new_start_thickness
|
|
@export var end_thickness:float = 0.1:
|
|
set(new_end_thickness): end_thickness = new_end_thickness
|
|
@export var corner_resolution:int = 5:
|
|
set(new_corner_resolution): corner_resolution = new_corner_resolution
|
|
@export var cap_resolution:int = 5:
|
|
set(new_cap_resolution): cap_resolution = new_cap_resolution
|
|
@export var draw_caps:bool = true:
|
|
set(new_draw_caps): draw_caps = new_draw_caps
|
|
@export var draw_crners:bool = true:
|
|
set(new_draw_crners): draw_crners = new_draw_crners
|
|
@export var use_global_coords:bool = true:
|
|
set(new_use_global_coords): use_global_coords = new_use_global_coords
|
|
@export var tile_texture:bool = true:
|
|
set(new_tile_texture): tile_texture = new_tile_texture
|
|
|
|
var camera : Camera3D
|
|
var cameraOrigin : Vector3
|
|
|
|
func _enter_tree():
|
|
mesh = ImmediateMesh.new()
|
|
|
|
func _ready():
|
|
pass
|
|
|
|
func _process(_delta):
|
|
if points.size() < 2:
|
|
return
|
|
|
|
camera = get_viewport().get_camera_3d()
|
|
if camera == null:
|
|
return
|
|
cameraOrigin = to_local(camera.get_global_transform().origin)
|
|
|
|
var progressStep:float = 1.0 / points.size();
|
|
var progress:float = 0;
|
|
var thickness:float = lerp(start_thickness, end_thickness, progress);
|
|
var nextThickness:float = lerp(start_thickness, end_thickness, progress + progressStep);
|
|
|
|
var surface:SurfaceTool = SurfaceTool.new()
|
|
surface.begin(Mesh.PRIMITIVE_TRIANGLES)
|
|
|
|
for i in range(points.size() - 1):
|
|
var A:Vector3 = points[i]
|
|
var B:Vector3 = points[i+1]
|
|
|
|
if use_global_coords:
|
|
A = to_local(A)
|
|
B = to_local(B)
|
|
|
|
var AB:Vector3 = B - A;
|
|
var orthogonalABStart:Vector3 = (cameraOrigin - ((A + B) / 2)).cross(AB).normalized() * thickness;
|
|
var orthogonalABEnd:Vector3 = (cameraOrigin - ((A + B) / 2)).cross(AB).normalized() * nextThickness;
|
|
|
|
var AtoABStart:Vector3 = A + orthogonalABStart
|
|
var AfromABStart:Vector3 = A - orthogonalABStart
|
|
var BtoABEnd:Vector3 = B + orthogonalABEnd
|
|
var BfromABEnd:Vector3 = B - orthogonalABEnd
|
|
|
|
if i == 0:
|
|
if draw_caps:
|
|
cap(surface, A, B, thickness, cap_resolution)
|
|
|
|
if tile_texture:
|
|
var ABLen = AB.length()
|
|
var ABFloor = floor(ABLen)
|
|
var ABFrac = ABLen - ABFloor
|
|
|
|
surface.set_uv(Vector2(ABFloor, 0))
|
|
surface.add_vertex(AtoABStart)
|
|
surface.set_uv(Vector2(-ABFrac, 0))
|
|
surface.add_vertex(BtoABEnd)
|
|
surface.set_uv(Vector2(ABFloor, 1))
|
|
surface.add_vertex(AfromABStart)
|
|
surface.set_uv(Vector2(-ABFrac, 0))
|
|
surface.add_vertex(BtoABEnd)
|
|
surface.set_uv(Vector2(-ABFrac, 1))
|
|
surface.add_vertex(BfromABEnd)
|
|
surface.set_uv(Vector2(ABFloor, 1))
|
|
surface.add_vertex(AfromABStart)
|
|
else:
|
|
surface.set_uv(Vector2(1, 0))
|
|
surface.add_vertex(AtoABStart)
|
|
surface.set_uv(Vector2(0, 0))
|
|
surface.add_vertex(BtoABEnd)
|
|
surface.set_uv(Vector2(1, 1))
|
|
surface.add_vertex(AfromABStart)
|
|
surface.set_uv(Vector2(0, 0))
|
|
surface.add_vertex(BtoABEnd)
|
|
surface.set_uv(Vector2(0, 1))
|
|
surface.add_vertex(BfromABEnd)
|
|
surface.set_uv(Vector2(1, 1))
|
|
surface.add_vertex(AfromABStart)
|
|
|
|
if i == points.size() - 2:
|
|
if draw_caps:
|
|
cap(surface, B, A, nextThickness, cap_resolution)
|
|
else:
|
|
if draw_crners:
|
|
var C = points[i+2]
|
|
if use_global_coords:
|
|
C = to_local(C)
|
|
|
|
var BC = C - B;
|
|
var orthogonalBCStart = (cameraOrigin - ((B + C) / 2)).cross(BC).normalized() * nextThickness;
|
|
|
|
var angleDot = AB.dot(orthogonalBCStart)
|
|
|
|
if angleDot > 0 and not angleDot == 1:
|
|
corner(surface, B, BtoABEnd, B + orthogonalBCStart, corner_resolution)
|
|
elif angleDot < 0 and not angleDot == -1:
|
|
corner(surface, B, B - orthogonalBCStart, BfromABEnd, corner_resolution)
|
|
|
|
progress += progressStep;
|
|
thickness = lerp(start_thickness, end_thickness, progress);
|
|
nextThickness = lerp(start_thickness, end_thickness, progress + progressStep);
|
|
|
|
surface.generate_normals()
|
|
surface.generate_tangents()
|
|
mesh = surface.commit()
|
|
|
|
func cap(surface: SurfaceTool, center:Vector3, pivot:Vector3, thickness:float, cap_resolution:int):
|
|
var orthogonal:Vector3 = (cameraOrigin - center).cross(center - pivot).normalized() * thickness;
|
|
var axis:Vector3 = (center - cameraOrigin).normalized();
|
|
|
|
var vertex_array:Array = []
|
|
for i in range(cap_resolution + 1):
|
|
vertex_array.append(Vector3(0,0,0))
|
|
vertex_array[0] = center + orthogonal;
|
|
vertex_array[cap_resolution] = center - orthogonal;
|
|
|
|
for i in range(1, cap_resolution):
|
|
vertex_array[i] = center + (orthogonal.rotated(axis, lerp(0.0, PI, float(i) / cap_resolution)));
|
|
|
|
for i in range(1, cap_resolution + 1):
|
|
surface.set_uv(Vector2(0, (i - 1) / cap_resolution))
|
|
surface.add_vertex(vertex_array[i - 1]);
|
|
surface.set_uv(Vector2(0, (i - 1) / cap_resolution))
|
|
surface.add_vertex(vertex_array[i]);
|
|
surface.set_uv(Vector2(0.5, 0.5))
|
|
surface.add_vertex(center);
|
|
|
|
func corner(surface: SurfaceTool, center:Vector3, start:Vector3, end:Vector3, cap_resolution:int):
|
|
var vertex_array:Array = []
|
|
for i in range(cap_resolution + 1):
|
|
vertex_array.append(Vector3(0,0,0))
|
|
vertex_array[0] = start;
|
|
vertex_array[cap_resolution] = end;
|
|
|
|
var axis:Vector3 = start.cross(end).normalized()
|
|
var offset:Vector3 = start - center
|
|
var angle:float = offset.angle_to(end - center)
|
|
|
|
for i in range(1, cap_resolution):
|
|
vertex_array[i] = center + offset.rotated(axis, lerp(0.0, angle, float(i) / cap_resolution));
|
|
|
|
for i in range(1, cap_resolution + 1):
|
|
surface.set_uv(Vector2(0, (i - 1) / cap_resolution))
|
|
surface.add_vertex(vertex_array[i - 1]);
|
|
surface.set_uv(Vector2(0, (i - 1) / cap_resolution))
|
|
surface.add_vertex(vertex_array[i]);
|
|
surface.set_uv(Vector2(0.5, 0.5))
|
|
surface.add_vertex(center);
|
|
|