74 lines
3.1 KiB
GDScript
74 lines
3.1 KiB
GDScript
class_name QuarryShell
|
|||
|
|
extends RefCounted
|
||
|
|
|
||
|
|
const STEPS := 512
|
||
|
|
const LEVELS := [-6.0, 0.0, 2.4, 3.0, 5.4, 6.1, 8.7, 9.4, 12.2, 13.0, 16.2, 17.0, 20.4, 21.1, 24.0, 25.2, 28.2, 30.0]
|
||
|
|
|
||
|
|
static func perimeter(t: float) -> Vector3:
|
||
|
|
var corners := [Vector3(-50, 0, -69), Vector3(50, 0, -69), Vector3(50, 0, 69), Vector3(-50, 0, 69)]
|
||
|
|
var edge := floori(t * 4) % 4
|
||
|
|
return corners[edge].lerp(corners[(edge + 1) % 4], fmod(t * 4, 1.0))
|
||
|
|
|
||
|
|
static func point(i: int, level: int) -> Vector3:
|
||
|
|
var t := float(i % STEPS) / STEPS
|
||
|
|
var p := perimeter(t)
|
||
|
|
var direction := p.normalized()
|
||
|
|
var along := t * TAU
|
||
|
|
var erosion := 3.8 + sin(along * 13 + sin(along * 5) * 0.6 + level * 0.06) * 2.8 + sin(along * 31 + level * 0.15) * 0.65
|
||
|
|
var terrace := level * 0.23 + sin(along * 9 + level * 0.7) * 1.2 + sin(along * 57 + level * 2.3) * 0.65
|
||
|
|
p += direction * (terrace + erosion + sin(along * 83 + level * 0.3) * 0.28 + sin(along * 137 + level) * 0.13)
|
||
|
|
var height_scale := 1.0 + 0.15 * sin(along * 3 + 0.6) + 0.065 * cos(along * 7)
|
||
|
|
p.y = LEVELS[level] * height_scale * 0.76 + (sin(along * 17) * 0.38 + sin(along * 37 + level * 0.35) * 0.32 if level > 1 else 0.0)
|
||
|
|
if level >= LEVELS.size() - 2: p.y += sin(along * 23) * 1.1 + sin(along * 41) * 0.45
|
||
|
|
return p
|
||
|
|
|
||
|
|
static func build(root: Node3D) -> void:
|
||
|
|
# Closed contiguous rock surface. Shared vertices at every seam, including corners.
|
||
|
|
var tool := SurfaceTool.new()
|
||
|
|
tool.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||
|
|
for i in STEPS:
|
||
|
|
for j in LEVELS.size() - 1:
|
||
|
|
tool.set_smooth_group(0)
|
||
|
|
for p in [point(i, j), point(i + 1, j + 1), point(i + 1, j), point(i, j), point(i, j + 1), point(i + 1, j + 1)]:
|
||
|
|
tool.set_uv(Vector2(p.x + p.z, p.y) * 0.2)
|
||
|
|
tool.add_vertex(p)
|
||
|
|
tool.generate_normals()
|
||
|
|
var mesh := MeshInstance3D.new()
|
||
|
|
mesh.name = "ContinuousStrataWall"
|
||
|
|
mesh.mesh = tool.commit()
|
||
|
|
mesh.material_override = QuarryLandscape.sandstone(null)
|
||
|
|
root.add_child(mesh)
|
||
|
|
# Extend visual ground beneath the complete perimeter; no collider or route changes.
|
||
|
|
var floor_mesh := MeshInstance3D.new()
|
||
|
|
floor_mesh.name = "BuriedQuarryApron"
|
||
|
|
var plane := PlaneMesh.new()
|
||
|
|
plane.size = Vector2(220, 250)
|
||
|
|
floor_mesh.mesh = plane
|
||
|
|
floor_mesh.position.y = -0.045
|
||
|
|
floor_mesh.material_override = UrbanMaterials.get_surface("sand", Color("d0b895"))
|
||
|
|
root.add_child(floor_mesh)
|
||
|
|
build_scree(root)
|
||
|
|
|
||
|
|
static func build_scree(root: Node3D) -> void:
|
||
|
|
var tool := SurfaceTool.new()
|
||
|
|
tool.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||
|
|
for i in STEPS:
|
||
|
|
var a := perimeter(float(i) / STEPS)
|
||
|
|
var b := perimeter(float((i + 1) % STEPS) / STEPS)
|
||
|
|
var near_a := a * Vector3(0.915, 1, 0.94)
|
||
|
|
var near_b := b * Vector3(0.915, 1, 0.94)
|
||
|
|
near_a.y = -0.02
|
||
|
|
near_b.y = -0.02
|
||
|
|
a.y = 2.0 + sin(i * 0.83) * 0.55
|
||
|
|
b.y = 2.0 + sin(((i + 1) % STEPS) * 0.83) * 0.55
|
||
|
|
for p in [near_a, b, near_b, near_a, a, b]:
|
||
|
|
tool.set_uv(Vector2(p.x, p.z))
|
||
|
|
tool.add_vertex(p)
|
||
|
|
tool.generate_normals()
|
||
|
|
var mesh := MeshInstance3D.new()
|
||
|
|
mesh.name = "ContinuousScreeFoot"
|
||
|
|
mesh.mesh = tool.commit()
|
||
|
|
mesh.material_override = UrbanMaterials.get_surface("sand", Color("c6aa83")).duplicate()
|
||
|
|
mesh.material_override.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||
|
|
root.add_child(mesh)
|