dp-konzultace/procedural_mesh_maker.gd

133 lines
3.4 KiB
GDScript

@tool
extends Node
@export_tool_button("Generate Portal Mesh")
var _generate_portal_mesh: Callable = generate_portal_mesh
@export_tool_button("Remove Mesh")
var _remove_mesh: Callable = func(): portal.mesh = null
@export var portal: MyPortal
@export_range(0.1, 10, 0.01) var height: float = 2.0:
set(v):
height = v
if Engine.is_editor_hint(): generate_portal_mesh()
@export_range(0.1, 10, 0.01) var width: float = 1.0:
set(v):
width = v
if Engine.is_editor_hint(): generate_portal_mesh()
## Player camera's NEAR clip distance
@export_range(0, 0.2, 0.001) var indent: float = 0.1:
set(v):
indent = v
generate_portal_mesh()
@export var portal_material: BaseMaterial3D
func _get_configuration_warnings() -> PackedStringArray:
var warnings: Array = []
if portal == null:
warnings.append("Assign a portal to generate the mesh for")
return warnings
func generate_portal_mesh() -> void:
if portal == null:
push_error("No portal")
return
if portal.mesh != null:
push_warning("The portal %s already has a mesh! Replacing." % portal.name)
portal.mesh = null
var mesh = ArrayMesh.new()
print("[PMM] Creating mesh")
var surface_array: Array = []
surface_array.resize(Mesh.ARRAY_MAX)
var verts: PackedVector3Array = PackedVector3Array()
var uvs: PackedVector2Array = PackedVector2Array()
var normals: PackedVector3Array = PackedVector3Array()
var indices: PackedInt32Array = PackedInt32Array()
# Just to save some chars
var w: float = width / 2
var h: float = height / 2
# Outside rect
var TOP_LEFT: Vector3 = Vector3(-w, h, 0)
var TOP_RIGHT: Vector3 = Vector3(w, h, 0)
var BOTTOM_LEFT: Vector3 = Vector3(-w, -h, 0)
var BOTTOM_RIGHT: Vector3 = Vector3(w, -h, 0)
# Inside rect, indented
var INDENT_TL: Vector3 = TOP_LEFT + Vector3(indent, -indent, -indent)
var INDENT_TR: Vector3 = TOP_RIGHT + Vector3(-indent, -indent, -indent)
var INDENT_BL: Vector3 = BOTTOM_LEFT + Vector3(indent, indent, -indent)
var INDENT_BR: Vector3 = BOTTOM_RIGHT + Vector3(-indent, indent, -indent)
verts.append_array([
TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,
INDENT_TL, INDENT_TR, INDENT_BL, INDENT_BR
])
var ix: float = indent / width
var iy: float = indent / height
uvs.append_array([
Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), # Outside UVs
Vector2(ix, iy), Vector2(1-ix, iy), Vector2(ix, 1-iy), Vector2(1-ix, 1-iy) # Indented UVs
])
# We are going for a flat-surface look here. Portals should be unshaded anyways.
normals.append_array([
Vector3.BACK, Vector3.BACK, Vector3.BACK, Vector3.BACK,
Vector3.BACK, Vector3.BACK, Vector3.BACK, Vector3.BACK
])
# 0 ----------- 1
# | \ / |
# | 4-------5 |
# | | | |
# | | | |
# | 6-------7 |
# | / \ |
# 2 ----------- 3
# Triangles are clockwise!
indices.append_array([
0, 1, 4,
4, 1, 5, # Top section done
1, 3, 5,
5, 3, 7, # right section done
3, 2, 7,
7, 2, 6, # bottom section done
2, 0, 6,
6, 0, 4, # left section done
4, 5, 6,
6, 5, 7, # middle sectiondone
])
surface_array[Mesh.ARRAY_VERTEX] = verts
surface_array[Mesh.ARRAY_TEX_UV] = uvs
surface_array[Mesh.ARRAY_NORMAL] = normals
surface_array[Mesh.ARRAY_INDEX] = indices
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array)
if portal_material:
mesh.surface_set_material(0, portal_material)
mesh.surface_set_name(0, "Portal Material")
portal.mesh = mesh
print("[PMM] Mesh assigned")