Roblox-style blocky avatar + actually-visible build stamp
checkpoint / checkpoint (push) Successful in 1m52s
checkpoint / checkpoint (push) Successful in 1m52s
Avatar: rebuild the placeholder base body as a Roblox-classic (R6) figure -- six chunky solid box parts (head, torso, two arms, two legs) skinned one part per bone onto the same 24-bone canonical rig, arms hanging at the sides instead of a T-pose, plus a painted-on smile face. Classic yellow/blue/green "noob" palette, flat single-colour surfaces (the old capsule-segment chain read as a banded scarecrow). Attachments resized to match the new proportions; head/hair/glove primitives are now boxes too (dropped ~130KB spheres to ~3KB each). Build stamp: it never rendered because `set_anchors_and_offsets_preset()` plus `.position` on a zero-size Label collapses the rect to negative width. Switched to a bottom-anchored full-width strip with explicit offsets and text alignment, brighter colour + black outline. Shows on the main menu (bottom-right) and in-world HUD (bottom-left) as `build PC3 <commit>`. Verified: avatar smoke 14/14 from source and against the exported pack; game.tscn + main_menu.tscn boot headless with no script errors. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jtxAiu5dAW4WxCNdGkrkJ
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+16
-4
@@ -46,13 +46,25 @@ static func _build_label() -> String:
|
|||||||
|
|
||||||
func _show_build_stamp() -> void:
|
func _show_build_stamp() -> void:
|
||||||
var layer := CanvasLayer.new()
|
var layer := CanvasLayer.new()
|
||||||
|
layer.layer = 128
|
||||||
add_child(layer)
|
add_child(layer)
|
||||||
var lbl := Label.new()
|
var lbl := Label.new()
|
||||||
lbl.text = "build %s" % _build_label()
|
lbl.text = "build %s" % _build_label()
|
||||||
lbl.add_theme_color_override("font_color", Color(1, 1, 1, 0.5))
|
lbl.add_theme_color_override("font_color", Color(1, 1, 0.45))
|
||||||
lbl.add_theme_font_size_override("font_size", 13)
|
lbl.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.85))
|
||||||
lbl.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_LEFT)
|
lbl.add_theme_constant_override("outline_size", 4)
|
||||||
lbl.position = Vector2(8, -22)
|
lbl.add_theme_font_size_override("font_size", 14)
|
||||||
|
# Anchor a full-width strip to the bottom of the screen and left-align the
|
||||||
|
# text in it. (A bare preset + .position on a zero-size Label collapses the
|
||||||
|
# rect to negative width and nothing draws -- which is why this never showed.)
|
||||||
|
lbl.set_anchors_preset(Control.PRESET_BOTTOM_WIDE)
|
||||||
|
lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||||
|
lbl.vertical_alignment = VERTICAL_ALIGNMENT_BOTTOM
|
||||||
|
lbl.offset_left = 8
|
||||||
|
lbl.offset_right = -8
|
||||||
|
lbl.offset_top = -30
|
||||||
|
lbl.offset_bottom = -6
|
||||||
|
lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
layer.add_child(lbl)
|
layer.add_child(lbl)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+14
-3
@@ -63,10 +63,21 @@ static func _build_label() -> String:
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
var v := Label.new()
|
var v := Label.new()
|
||||||
v.text = "build %s" % _build_label()
|
v.text = "build %s" % _build_label()
|
||||||
v.add_theme_color_override("font_color", Color(1, 1, 1, 0.4))
|
v.add_theme_color_override("font_color", Color(1, 1, 1, 0.7))
|
||||||
|
v.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.85))
|
||||||
|
v.add_theme_constant_override("outline_size", 4)
|
||||||
v.add_theme_font_size_override("font_size", 12)
|
v.add_theme_font_size_override("font_size", 12)
|
||||||
v.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_RIGHT)
|
# Full-width strip pinned to the bottom, text right-aligned. A bare
|
||||||
v.position = Vector2(-140, -22)
|
# BOTTOM_RIGHT preset + .position on a zero-size Label collapses the rect
|
||||||
|
# and nothing renders -- which is why this never showed up.
|
||||||
|
v.set_anchors_preset(Control.PRESET_BOTTOM_WIDE)
|
||||||
|
v.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||||
|
v.vertical_alignment = VERTICAL_ALIGNMENT_BOTTOM
|
||||||
|
v.offset_left = 8
|
||||||
|
v.offset_right = -10
|
||||||
|
v.offset_top = -28
|
||||||
|
v.offset_bottom = -6
|
||||||
|
v.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
add_child(v)
|
add_child(v)
|
||||||
|
|
||||||
# Cache node references.
|
# Cache node references.
|
||||||
|
|||||||
@@ -6,38 +6,42 @@ extends SceneTree
|
|||||||
## customization / in-world rendering can be built and tested now; real art
|
## customization / in-world rendering can be built and tested now; real art
|
||||||
## swaps in later as a pure content change (catalog paths are unchanged).
|
## swaps in later as a pure content change (catalog paths are unchanged).
|
||||||
##
|
##
|
||||||
|
## The base body is a Roblox-classic (R6) style blocky figure: six chunky box
|
||||||
|
## parts (head, torso, two arms, two legs) skinned one-part-per-bone onto the
|
||||||
|
## 24-bone canonical rig, arms hanging at the sides, plus a painted-on face.
|
||||||
|
##
|
||||||
## Run: godot --headless --path . --script res://scripts/tools/gen_placeholder_avatars.gd
|
## Run: godot --headless --path . --script res://scripts/tools/gen_placeholder_avatars.gd
|
||||||
## Output: res://assets/avatars/*.glb (13 attachments + 1 rigged base body)
|
## Output: res://assets/avatars/*.glb (13 attachments + 1 rigged base body)
|
||||||
|
|
||||||
const OUT_DIR := "res://assets/avatars/"
|
const OUT_DIR := "res://assets/avatars/"
|
||||||
|
|
||||||
# Canonical rig — must match avatar_loader.gd CANONICAL_BONES. Each entry:
|
# Canonical rig -- must match avatar_loader.gd CANONICAL_BONES. Each entry:
|
||||||
# name -> [parent_name, global_rest_position] (T-pose, Y-up, metres)
|
# name -> [parent_name, global_rest_position] (A-pose, arms down, Y-up, metres)
|
||||||
const BONES := {
|
const BONES := {
|
||||||
"Root": ["", Vector3(0.00, 0.00, 0.00)],
|
"Root": ["", Vector3(0.00, 0.00, 0.00)],
|
||||||
"Hips": ["Root", Vector3(0.00, 0.95, 0.00)],
|
"Hips": ["Root", Vector3(0.00, 0.80, 0.00)],
|
||||||
"Spine": ["Hips", Vector3(0.00, 1.10, 0.00)],
|
"Spine": ["Hips", Vector3(0.00, 1.00, 0.00)],
|
||||||
"Chest": ["Spine", Vector3(0.00, 1.30, 0.00)],
|
"Chest": ["Spine", Vector3(0.00, 1.22, 0.00)],
|
||||||
"Neck": ["Chest", Vector3(0.00, 1.48, 0.00)],
|
"Neck": ["Chest", Vector3(0.00, 1.36, 0.00)],
|
||||||
"Head": ["Neck", Vector3(0.00, 1.60, 0.00)],
|
"Head": ["Neck", Vector3(0.00, 1.44, 0.00)],
|
||||||
"HeadTop": ["Head", Vector3(0.00, 1.78, 0.00)],
|
"HeadTop": ["Head", Vector3(0.00, 1.92, 0.00)],
|
||||||
"Jaw": ["Head", Vector3(0.00, 1.56, 0.06)],
|
"Jaw": ["Head", Vector3(0.00, 1.54, 0.14)],
|
||||||
"LeftEye": ["Head", Vector3(0.04, 1.64, 0.09)],
|
"LeftEye": ["Head", Vector3(0.12, 1.66, 0.28)],
|
||||||
"RightEye": ["Head", Vector3(-0.04, 1.64, 0.09)],
|
"RightEye": ["Head", Vector3(-0.12, 1.66, 0.28)],
|
||||||
"LeftShoulder": ["Chest", Vector3(0.06, 1.42, 0.00)],
|
"LeftShoulder": ["Chest", Vector3(0.22, 1.34, 0.00)],
|
||||||
"LeftUpperArm": ["LeftShoulder", Vector3(0.18, 1.42, 0.00)],
|
"LeftUpperArm": ["LeftShoulder", Vector3(0.45, 1.30, 0.00)],
|
||||||
"LeftLowerArm": ["LeftUpperArm", Vector3(0.44, 1.42, 0.00)],
|
"LeftLowerArm": ["LeftUpperArm", Vector3(0.45, 1.02, 0.00)],
|
||||||
"LeftHand": ["LeftLowerArm", Vector3(0.68, 1.42, 0.00)],
|
"LeftHand": ["LeftLowerArm", Vector3(0.45, 0.74, 0.00)],
|
||||||
"RightShoulder": ["Chest", Vector3(-0.06, 1.42, 0.00)],
|
"RightShoulder": ["Chest", Vector3(-0.22, 1.34, 0.00)],
|
||||||
"RightUpperArm": ["RightShoulder", Vector3(-0.18, 1.42, 0.00)],
|
"RightUpperArm": ["RightShoulder", Vector3(-0.45, 1.30, 0.00)],
|
||||||
"RightLowerArm": ["RightUpperArm", Vector3(-0.44, 1.42, 0.00)],
|
"RightLowerArm": ["RightUpperArm", Vector3(-0.45, 1.02, 0.00)],
|
||||||
"RightHand": ["RightLowerArm", Vector3(-0.68, 1.42, 0.00)],
|
"RightHand": ["RightLowerArm", Vector3(-0.45, 0.74, 0.00)],
|
||||||
"LeftUpperLeg": ["Hips", Vector3(0.11, 0.90, 0.00)],
|
"LeftUpperLeg": ["Hips", Vector3(0.17, 0.78, 0.00)],
|
||||||
"LeftLowerLeg": ["LeftUpperLeg", Vector3(0.11, 0.50, 0.00)],
|
"LeftLowerLeg": ["LeftUpperLeg", Vector3(0.17, 0.40, 0.00)],
|
||||||
"LeftFoot": ["LeftLowerLeg", Vector3(0.11, 0.08, 0.04)],
|
"LeftFoot": ["LeftLowerLeg", Vector3(0.17, 0.05, 0.05)],
|
||||||
"RightUpperLeg": ["Hips", Vector3(-0.11, 0.90, 0.00)],
|
"RightUpperLeg": ["Hips", Vector3(-0.17, 0.78, 0.00)],
|
||||||
"RightLowerLeg": ["RightUpperLeg", Vector3(-0.11, 0.50, 0.00)],
|
"RightLowerLeg": ["RightUpperLeg", Vector3(-0.17, 0.40, 0.00)],
|
||||||
"RightFoot": ["RightLowerLeg", Vector3(-0.11, 0.08, 0.04)],
|
"RightFoot": ["RightLowerLeg", Vector3(-0.17, 0.05, 0.05)],
|
||||||
}
|
}
|
||||||
|
|
||||||
# Order matters: parents before children.
|
# Order matters: parents before children.
|
||||||
@@ -50,44 +54,44 @@ const BONE_ORDER := [
|
|||||||
"RightUpperLeg", "RightLowerLeg", "RightFoot",
|
"RightUpperLeg", "RightLowerLeg", "RightFoot",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Body segments: [boneA, boneB, radius] -> a capsule-ish box between the two,
|
# Roblox-classic colour blocks.
|
||||||
# fully weighted to boneA. boneB "" means a small blob at boneA.
|
const C_SKIN := Color(0.96, 0.80, 0.19) # bright yellow (head + arms)
|
||||||
const SEGMENTS := [
|
const C_SHIRT := Color(0.05, 0.41, 0.67) # bright blue (torso)
|
||||||
["Hips", "Spine", 0.14],
|
const C_PANTS := Color(0.18, 0.49, 0.30) # bright green (legs)
|
||||||
["Spine", "Chest", 0.15],
|
const C_FACE := Color(0.05, 0.05, 0.06) # near-black (eyes + smile)
|
||||||
["Chest", "Neck", 0.13],
|
|
||||||
["Neck", "Head", 0.05],
|
# Body parts: [bone, centre, size, colour]. Each part is one rigid box, fully
|
||||||
["Head", "", 0.11],
|
# weighted to its bone -- so the rig still drives it, but it reads as a clean
|
||||||
["LeftUpperArm", "LeftLowerArm", 0.055],
|
# solid block (no banding, no capsule taper).
|
||||||
["LeftLowerArm", "LeftHand", 0.045],
|
const PARTS := [
|
||||||
["LeftHand", "", 0.05],
|
["Head", Vector3(0.00, 1.62, 0.00), Vector3(0.60, 0.56, 0.56), C_SKIN],
|
||||||
["RightUpperArm", "RightLowerArm", 0.055],
|
["Spine", Vector3(0.00, 1.06, 0.00), Vector3(0.74, 0.64, 0.38), C_SHIRT],
|
||||||
["RightLowerArm", "RightHand", 0.045],
|
["LeftUpperArm", Vector3(0.45, 1.04, 0.00), Vector3(0.27, 0.66, 0.31), C_SKIN],
|
||||||
["RightHand", "", 0.05],
|
["RightUpperArm", Vector3(-0.45, 1.04, 0.00), Vector3(0.27, 0.66, 0.31), C_SKIN],
|
||||||
["LeftUpperLeg", "LeftLowerLeg", 0.08],
|
["LeftUpperLeg", Vector3(0.17, 0.39, 0.00), Vector3(0.31, 0.80, 0.33), C_PANTS],
|
||||||
["LeftLowerLeg", "LeftFoot", 0.06],
|
["RightUpperLeg", Vector3(-0.17, 0.39, 0.00), Vector3(0.31, 0.80, 0.33), C_PANTS],
|
||||||
["LeftFoot", "", 0.06],
|
# painted-on face -- thin plates on the front of the head (+Z), rigged to Head
|
||||||
["RightUpperLeg", "RightLowerLeg", 0.08],
|
["Head", Vector3(0.12, 1.66, 0.285), Vector3(0.07, 0.10, 0.02), C_FACE],
|
||||||
["RightLowerLeg", "RightFoot", 0.06],
|
["Head", Vector3(-0.12, 1.66, 0.285), Vector3(0.07, 0.10, 0.02), C_FACE],
|
||||||
["RightFoot", "", 0.06],
|
["Head", Vector3(0.00, 1.52, 0.285), Vector3(0.26, 0.05, 0.02), C_FACE],
|
||||||
]
|
]
|
||||||
|
|
||||||
# Attachments: id -> [Mesh, local_offset_from_mount_bone, colour]
|
# Attachments: id -> [Mesh, local_offset_from_mount_bone, colour]
|
||||||
# Mesh is built in _attachment_mesh().
|
# Mesh is built in _attachment_mesh().
|
||||||
const ATTACHMENTS := {
|
const ATTACHMENTS := {
|
||||||
"head_cyber_01": ["head", Vector3(0, 0.02, 0.0), Color(0.20, 0.85, 0.95)],
|
"head_cyber_01": ["head", Vector3(0, 0.04, 0.0), Color(0.20, 0.85, 0.95)],
|
||||||
"hair_mohawk_01": ["mohawk", Vector3(0, 0.02, 0.0), Color(0.90, 0.20, 0.35)],
|
"hair_mohawk_01": ["mohawk", Vector3(0, 0.0, 0.0), Color(0.90, 0.20, 0.35)],
|
||||||
"hair_ponytail_01": ["ponytail", Vector3(0, 0.0, -0.08), Color(0.45, 0.30, 0.15)],
|
"hair_ponytail_01": ["ponytail", Vector3(0, -0.06, -0.16), Color(0.45, 0.30, 0.15)],
|
||||||
"face_glasses_01": ["glasses", Vector3(0, 0.06, 0.10), Color(0.10, 0.10, 0.12)],
|
"face_glasses_01": ["glasses", Vector3(0, 0.12, 0.16), Color(0.10, 0.10, 0.12)],
|
||||||
"chest_bandit_01": ["torso", Vector3(0, 0.0, 0.0), Color(0.55, 0.20, 0.20)],
|
"chest_bandit_01": ["torso", Vector3(0, -0.12, 0.0), Color(0.55, 0.20, 0.20)],
|
||||||
"back_backpack_01": ["box", Vector3(0, 0.0, -0.16), Color(0.30, 0.35, 0.25)],
|
"back_backpack_01": ["box", Vector3(0, -0.06, -0.28), Color(0.30, 0.35, 0.25)],
|
||||||
"pants_cargo_01": ["hips", Vector3(0, -0.18, 0.0), Color(0.30, 0.35, 0.45)],
|
"pants_cargo_01": ["hips", Vector3(0, -0.04, 0.0), Color(0.30, 0.35, 0.45)],
|
||||||
"left_hand_glove_01": ["blob", Vector3(0, 0.0, 0.0), Color(0.15, 0.15, 0.18)],
|
"left_hand_glove_01": ["blob", Vector3(0, 0.0, 0.0), Color(0.15, 0.15, 0.18)],
|
||||||
"right_hand_glove_01": ["blob", Vector3(0, 0.0, 0.0), Color(0.15, 0.15, 0.18)],
|
"right_hand_glove_01": ["blob", Vector3(0, 0.0, 0.0), Color(0.15, 0.15, 0.18)],
|
||||||
"left_foot_boot_01": ["boot", Vector3(0, -0.02, 0.03), Color(0.12, 0.10, 0.09)],
|
"left_foot_boot_01": ["boot", Vector3(0, -0.02, 0.05), Color(0.12, 0.10, 0.09)],
|
||||||
"right_foot_boot_01": ["boot", Vector3(0, -0.02, 0.03), Color(0.12, 0.10, 0.09)],
|
"right_foot_boot_01": ["boot", Vector3(0, -0.02, 0.05), Color(0.12, 0.10, 0.09)],
|
||||||
"accessory_belt_01": ["belt", Vector3(0, 0.98, 0.0), Color(0.20, 0.18, 0.12)],
|
"accessory_belt_01": ["belt", Vector3(0, 0.80, 0.0), Color(0.20, 0.18, 0.12)],
|
||||||
"accessory_necklace_01": ["belt", Vector3(0, 1.34, 0.02), Color(0.85, 0.75, 0.20)],
|
"accessory_necklace_01": ["necklace", Vector3(0, 1.30, 0.06), Color(0.85, 0.75, 0.20)],
|
||||||
}
|
}
|
||||||
|
|
||||||
var _fail := 0
|
var _fail := 0
|
||||||
@@ -108,7 +112,7 @@ func _initialize() -> void:
|
|||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Base body — rigged, skinned
|
# Base body -- rigged, skinned
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
func _global_rest(bone: String) -> Transform3D:
|
func _global_rest(bone: String) -> Transform3D:
|
||||||
@@ -143,36 +147,46 @@ func _gen_base_body() -> void:
|
|||||||
for bone in BONE_ORDER:
|
for bone in BONE_ORDER:
|
||||||
skin.add_named_bind(bone, _global_rest(bone).affine_inverse())
|
skin.add_named_bind(bone, _global_rest(bone).affine_inverse())
|
||||||
|
|
||||||
# Build one ArrayMesh surface from all segments, CPU-skinned to bind indices.
|
|
||||||
var verts := PackedVector3Array()
|
|
||||||
var normals := PackedVector3Array()
|
|
||||||
var bones := PackedInt32Array()
|
|
||||||
var weights := PackedFloat32Array()
|
|
||||||
|
|
||||||
var bind_index := {}
|
var bind_index := {}
|
||||||
for b in range(BONE_ORDER.size()):
|
for b in range(BONE_ORDER.size()):
|
||||||
bind_index[BONE_ORDER[b]] = b
|
bind_index[BONE_ORDER[b]] = b
|
||||||
|
|
||||||
for seg in SEGMENTS:
|
# One surface per distinct colour so parts stay flat-shaded solids.
|
||||||
var a: String = seg[0]
|
var groups: Dictionary = {} # Color (as key string) -> {color, verts, normals, bones, weights}
|
||||||
var b: String = seg[1]
|
for part in PARTS:
|
||||||
var r: float = seg[2]
|
var bone: String = part[0]
|
||||||
var pa: Vector3 = BONES[a][1]
|
var centre: Vector3 = part[1]
|
||||||
var pb: Vector3 = pa + Vector3(0, 0.12, 0) if b == "" else BONES[b][1]
|
var size: Vector3 = part[2]
|
||||||
_append_box_between(verts, normals, bones, weights, pa, pb, r, bind_index[a])
|
var col: Color = part[3]
|
||||||
|
var key := col.to_html()
|
||||||
var arr := []
|
if not groups.has(key):
|
||||||
arr.resize(Mesh.ARRAY_MAX)
|
groups[key] = {
|
||||||
arr[Mesh.ARRAY_VERTEX] = verts
|
"color": col,
|
||||||
arr[Mesh.ARRAY_NORMAL] = normals
|
"verts": PackedVector3Array(),
|
||||||
arr[Mesh.ARRAY_BONES] = bones
|
"normals": PackedVector3Array(),
|
||||||
arr[Mesh.ARRAY_WEIGHTS] = weights
|
"bones": PackedInt32Array(),
|
||||||
|
"weights": PackedFloat32Array(),
|
||||||
|
}
|
||||||
|
var gg = groups[key]
|
||||||
|
_append_box(gg.verts, gg.normals, gg.bones, gg.weights,
|
||||||
|
centre, size, bind_index[bone])
|
||||||
|
|
||||||
var mesh := ArrayMesh.new()
|
var mesh := ArrayMesh.new()
|
||||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr)
|
var surf := 0
|
||||||
var mat := StandardMaterial3D.new()
|
for key in groups:
|
||||||
mat.albedo_color = Color(0.78, 0.66, 0.55)
|
var gg = groups[key]
|
||||||
mesh.surface_set_material(0, mat)
|
var arr := []
|
||||||
|
arr.resize(Mesh.ARRAY_MAX)
|
||||||
|
arr[Mesh.ARRAY_VERTEX] = gg.verts
|
||||||
|
arr[Mesh.ARRAY_NORMAL] = gg.normals
|
||||||
|
arr[Mesh.ARRAY_BONES] = gg.bones
|
||||||
|
arr[Mesh.ARRAY_WEIGHTS] = gg.weights
|
||||||
|
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr)
|
||||||
|
var mat := StandardMaterial3D.new()
|
||||||
|
mat.albedo_color = gg.color
|
||||||
|
mat.roughness = 0.9
|
||||||
|
mesh.surface_set_material(surf, mat)
|
||||||
|
surf += 1
|
||||||
|
|
||||||
var mi := MeshInstance3D.new()
|
var mi := MeshInstance3D.new()
|
||||||
mi.name = "Body"
|
mi.name = "Body"
|
||||||
@@ -185,38 +199,28 @@ func _gen_base_body() -> void:
|
|||||||
root.free()
|
root.free()
|
||||||
|
|
||||||
|
|
||||||
# Append an axis-aligned-ish box spanning pa..pb, all verts weighted 1.0 to bone_idx.
|
# Append an axis-aligned box (centre, size) with every vert weighted 1.0 to bone_idx.
|
||||||
func _append_box_between(verts: PackedVector3Array, normals: PackedVector3Array,
|
func _append_box(verts: PackedVector3Array, normals: PackedVector3Array,
|
||||||
bones: PackedInt32Array, weights: PackedFloat32Array,
|
bones: PackedInt32Array, weights: PackedFloat32Array,
|
||||||
pa: Vector3, pb: Vector3, r: float, bone_idx: int) -> void:
|
centre: Vector3, size: Vector3, bone_idx: int) -> void:
|
||||||
var axis := pb - pa
|
var h := size * 0.5
|
||||||
var len := axis.length()
|
# 8 corners
|
||||||
if len < 0.001:
|
var c: Array[Vector3] = [
|
||||||
axis = Vector3(0, 0.1, 0)
|
centre + Vector3(-h.x, -h.y, -h.z), centre + Vector3(h.x, -h.y, -h.z),
|
||||||
len = 0.1
|
centre + Vector3(h.x, -h.y, h.z), centre + Vector3(-h.x, -h.y, h.z),
|
||||||
var dir := axis / len
|
centre + Vector3(-h.x, h.y, -h.z), centre + Vector3(h.x, h.y, -h.z),
|
||||||
var up := Vector3.UP if absf(dir.dot(Vector3.UP)) < 0.95 else Vector3.FORWARD
|
centre + Vector3(h.x, h.y, h.z), centre + Vector3(-h.x, h.y, h.z),
|
||||||
var right := dir.cross(up).normalized()
|
|
||||||
up = right.cross(dir).normalized()
|
|
||||||
|
|
||||||
var corners: Array[Vector3] = [
|
|
||||||
-right * r - up * r, right * r - up * r,
|
|
||||||
right * r + up * r, -right * r + up * r,
|
|
||||||
]
|
]
|
||||||
# 8 corners: bottom ring at pa, top ring at pb
|
|
||||||
var pts: Array[Vector3] = []
|
|
||||||
for c in corners:
|
|
||||||
pts.append(pa + c)
|
|
||||||
for c in corners:
|
|
||||||
pts.append(pb + c)
|
|
||||||
|
|
||||||
var faces := [
|
var faces := [
|
||||||
[0, 1, 2, 3], [7, 6, 5, 4], # caps
|
[0, 3, 2, 1], # bottom (-Y)
|
||||||
[0, 4, 5, 1], [1, 5, 6, 2], # sides
|
[4, 5, 6, 7], # top (+Y)
|
||||||
[2, 6, 7, 3], [3, 7, 4, 0],
|
[0, 1, 5, 4], # -Z
|
||||||
|
[2, 3, 7, 6], # +Z
|
||||||
|
[1, 2, 6, 5], # +X
|
||||||
|
[3, 0, 4, 7], # -X
|
||||||
]
|
]
|
||||||
for f in faces:
|
for f in faces:
|
||||||
var q: Array[Vector3] = [pts[f[0]], pts[f[1]], pts[f[2]], pts[f[3]]]
|
var q: Array[Vector3] = [c[f[0]], c[f[1]], c[f[2]], c[f[3]]]
|
||||||
var n: Vector3 = (q[1] - q[0]).cross(q[2] - q[0]).normalized()
|
var n: Vector3 = (q[1] - q[0]).cross(q[2] - q[0]).normalized()
|
||||||
for tri in [[0, 1, 2], [0, 2, 3]]:
|
for tri in [[0, 1, 2], [0, 2, 3]]:
|
||||||
for vi in tri:
|
for vi in tri:
|
||||||
@@ -227,7 +231,7 @@ func _append_box_between(verts: PackedVector3Array, normals: PackedVector3Array,
|
|||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Attachments — plain static meshes
|
# Attachments -- plain static meshes
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
func _gen_attachment(id: String, kind: String, offset: Vector3, col: Color) -> void:
|
func _gen_attachment(id: String, kind: String, offset: Vector3, col: Color) -> void:
|
||||||
@@ -239,6 +243,7 @@ func _gen_attachment(id: String, kind: String, offset: Vector3, col: Color) -> v
|
|||||||
mi.position = offset
|
mi.position = offset
|
||||||
var mat := StandardMaterial3D.new()
|
var mat := StandardMaterial3D.new()
|
||||||
mat.albedo_color = col
|
mat.albedo_color = col
|
||||||
|
mat.roughness = 0.9
|
||||||
mi.material_override = mat
|
mi.material_override = mat
|
||||||
root.add_child(mi)
|
root.add_child(mi)
|
||||||
_write_glb(root, id)
|
_write_glb(root, id)
|
||||||
@@ -248,25 +253,27 @@ func _gen_attachment(id: String, kind: String, offset: Vector3, col: Color) -> v
|
|||||||
func _attachment_mesh(kind: String) -> Mesh:
|
func _attachment_mesh(kind: String) -> Mesh:
|
||||||
match kind:
|
match kind:
|
||||||
"head":
|
"head":
|
||||||
var m := SphereMesh.new(); m.radius = 0.13; m.height = 0.26; return m
|
var m := BoxMesh.new(); m.size = Vector3(0.60, 0.56, 0.56); return m
|
||||||
"mohawk":
|
"mohawk":
|
||||||
var m := PrismMesh.new(); m.size = Vector3(0.06, 0.16, 0.30); return m
|
var m := PrismMesh.new(); m.size = Vector3(0.08, 0.20, 0.44); return m
|
||||||
"ponytail":
|
"ponytail":
|
||||||
var m := CapsuleMesh.new(); m.radius = 0.04; m.height = 0.28; return m
|
var m := BoxMesh.new(); m.size = Vector3(0.14, 0.30, 0.16); return m
|
||||||
"glasses":
|
"glasses":
|
||||||
var m := BoxMesh.new(); m.size = Vector3(0.20, 0.05, 0.02); return m
|
var m := BoxMesh.new(); m.size = Vector3(0.44, 0.10, 0.03); return m
|
||||||
"torso":
|
"torso":
|
||||||
var m := BoxMesh.new(); m.size = Vector3(0.34, 0.44, 0.22); return m
|
var m := BoxMesh.new(); m.size = Vector3(0.80, 0.66, 0.42); return m
|
||||||
"box":
|
"box":
|
||||||
var m := BoxMesh.new(); m.size = Vector3(0.26, 0.32, 0.14); return m
|
var m := BoxMesh.new(); m.size = Vector3(0.34, 0.40, 0.16); return m
|
||||||
"hips":
|
"hips":
|
||||||
var m := BoxMesh.new(); m.size = Vector3(0.32, 0.30, 0.20); return m
|
var m := BoxMesh.new(); m.size = Vector3(0.66, 0.34, 0.40); return m
|
||||||
"blob":
|
"blob":
|
||||||
var m := SphereMesh.new(); m.radius = 0.06; m.height = 0.12; return m
|
var m := BoxMesh.new(); m.size = Vector3(0.30, 0.24, 0.34); return m
|
||||||
"boot":
|
"boot":
|
||||||
var m := BoxMesh.new(); m.size = Vector3(0.10, 0.10, 0.20); return m
|
var m := BoxMesh.new(); m.size = Vector3(0.34, 0.16, 0.42); return m
|
||||||
"belt":
|
"belt":
|
||||||
var m := TorusMesh.new(); m.inner_radius = 0.12; m.outer_radius = 0.17; return m
|
var m := TorusMesh.new(); m.inner_radius = 0.22; m.outer_radius = 0.30; return m
|
||||||
|
"necklace":
|
||||||
|
var m := TorusMesh.new(); m.inner_radius = 0.10; m.outer_radius = 0.14; return m
|
||||||
_:
|
_:
|
||||||
return BoxMesh.new()
|
return BoxMesh.new()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user