diff --git a/assets/avatars/accessory_belt_01.glb b/assets/avatars/accessory_belt_01.glb index 90381c5..9d254b0 100644 Binary files a/assets/avatars/accessory_belt_01.glb and b/assets/avatars/accessory_belt_01.glb differ diff --git a/assets/avatars/accessory_necklace_01.glb b/assets/avatars/accessory_necklace_01.glb index d92f58c..cd46013 100644 Binary files a/assets/avatars/accessory_necklace_01.glb and b/assets/avatars/accessory_necklace_01.glb differ diff --git a/assets/avatars/back_backpack_01.glb b/assets/avatars/back_backpack_01.glb index 7e79fcd..244c86a 100644 Binary files a/assets/avatars/back_backpack_01.glb and b/assets/avatars/back_backpack_01.glb differ diff --git a/assets/avatars/base_human_male_01.glb b/assets/avatars/base_human_male_01.glb index 15d54f2..4fc9328 100644 Binary files a/assets/avatars/base_human_male_01.glb and b/assets/avatars/base_human_male_01.glb differ diff --git a/assets/avatars/chest_bandit_01.glb b/assets/avatars/chest_bandit_01.glb index 8bc2b83..bbb5050 100644 Binary files a/assets/avatars/chest_bandit_01.glb and b/assets/avatars/chest_bandit_01.glb differ diff --git a/assets/avatars/face_glasses_01.glb b/assets/avatars/face_glasses_01.glb index 1c6339e..e0b2f3c 100644 Binary files a/assets/avatars/face_glasses_01.glb and b/assets/avatars/face_glasses_01.glb differ diff --git a/assets/avatars/hair_mohawk_01.glb b/assets/avatars/hair_mohawk_01.glb index 0f1cc97..0caea8a 100644 Binary files a/assets/avatars/hair_mohawk_01.glb and b/assets/avatars/hair_mohawk_01.glb differ diff --git a/assets/avatars/hair_ponytail_01.glb b/assets/avatars/hair_ponytail_01.glb index 7c1a03f..3557312 100644 Binary files a/assets/avatars/hair_ponytail_01.glb and b/assets/avatars/hair_ponytail_01.glb differ diff --git a/assets/avatars/head_cyber_01.glb b/assets/avatars/head_cyber_01.glb index 6bce48d..508b2f0 100644 Binary files a/assets/avatars/head_cyber_01.glb and b/assets/avatars/head_cyber_01.glb differ diff --git a/assets/avatars/left_foot_boot_01.glb b/assets/avatars/left_foot_boot_01.glb index 0fbdbb2..4797936 100644 Binary files a/assets/avatars/left_foot_boot_01.glb and b/assets/avatars/left_foot_boot_01.glb differ diff --git a/assets/avatars/left_hand_glove_01.glb b/assets/avatars/left_hand_glove_01.glb index fa634a5..497e6e6 100644 Binary files a/assets/avatars/left_hand_glove_01.glb and b/assets/avatars/left_hand_glove_01.glb differ diff --git a/assets/avatars/pants_cargo_01.glb b/assets/avatars/pants_cargo_01.glb index 4c24171..266d846 100644 Binary files a/assets/avatars/pants_cargo_01.glb and b/assets/avatars/pants_cargo_01.glb differ diff --git a/assets/avatars/right_foot_boot_01.glb b/assets/avatars/right_foot_boot_01.glb index 1c8e6a4..6a0dbe0 100644 Binary files a/assets/avatars/right_foot_boot_01.glb and b/assets/avatars/right_foot_boot_01.glb differ diff --git a/assets/avatars/right_hand_glove_01.glb b/assets/avatars/right_hand_glove_01.glb index c7ecc04..70b7dcf 100644 Binary files a/assets/avatars/right_hand_glove_01.glb and b/assets/avatars/right_hand_glove_01.glb differ diff --git a/scripts/game.gd b/scripts/game.gd index a4696aa..af6cbf5 100644 --- a/scripts/game.gd +++ b/scripts/game.gd @@ -46,13 +46,25 @@ static func _build_label() -> String: func _show_build_stamp() -> void: var layer := CanvasLayer.new() + layer.layer = 128 add_child(layer) var lbl := Label.new() lbl.text = "build %s" % _build_label() - lbl.add_theme_color_override("font_color", Color(1, 1, 1, 0.5)) - lbl.add_theme_font_size_override("font_size", 13) - lbl.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_LEFT) - lbl.position = Vector2(8, -22) + lbl.add_theme_color_override("font_color", Color(1, 1, 0.45)) + lbl.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.85)) + lbl.add_theme_constant_override("outline_size", 4) + 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) diff --git a/scripts/main_menu.gd b/scripts/main_menu.gd index 0fe689a..a8a21d2 100644 --- a/scripts/main_menu.gd +++ b/scripts/main_menu.gd @@ -63,10 +63,21 @@ static func _build_label() -> String: func _ready() -> void: var v := Label.new() 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.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_RIGHT) - v.position = Vector2(-140, -22) + # Full-width strip pinned to the bottom, text right-aligned. A bare + # 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) # Cache node references. diff --git a/scripts/tools/gen_placeholder_avatars.gd b/scripts/tools/gen_placeholder_avatars.gd index 6878faf..bc9be0f 100644 --- a/scripts/tools/gen_placeholder_avatars.gd +++ b/scripts/tools/gen_placeholder_avatars.gd @@ -6,38 +6,42 @@ extends SceneTree ## customization / in-world rendering can be built and tested now; real art ## 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 ## Output: res://assets/avatars/*.glb (13 attachments + 1 rigged base body) const OUT_DIR := "res://assets/avatars/" -# Canonical rig — must match avatar_loader.gd CANONICAL_BONES. Each entry: -# name -> [parent_name, global_rest_position] (T-pose, Y-up, metres) +# Canonical rig -- must match avatar_loader.gd CANONICAL_BONES. Each entry: +# name -> [parent_name, global_rest_position] (A-pose, arms down, Y-up, metres) const BONES := { "Root": ["", Vector3(0.00, 0.00, 0.00)], - "Hips": ["Root", Vector3(0.00, 0.95, 0.00)], - "Spine": ["Hips", Vector3(0.00, 1.10, 0.00)], - "Chest": ["Spine", Vector3(0.00, 1.30, 0.00)], - "Neck": ["Chest", Vector3(0.00, 1.48, 0.00)], - "Head": ["Neck", Vector3(0.00, 1.60, 0.00)], - "HeadTop": ["Head", Vector3(0.00, 1.78, 0.00)], - "Jaw": ["Head", Vector3(0.00, 1.56, 0.06)], - "LeftEye": ["Head", Vector3(0.04, 1.64, 0.09)], - "RightEye": ["Head", Vector3(-0.04, 1.64, 0.09)], - "LeftShoulder": ["Chest", Vector3(0.06, 1.42, 0.00)], - "LeftUpperArm": ["LeftShoulder", Vector3(0.18, 1.42, 0.00)], - "LeftLowerArm": ["LeftUpperArm", Vector3(0.44, 1.42, 0.00)], - "LeftHand": ["LeftLowerArm", Vector3(0.68, 1.42, 0.00)], - "RightShoulder": ["Chest", Vector3(-0.06, 1.42, 0.00)], - "RightUpperArm": ["RightShoulder", Vector3(-0.18, 1.42, 0.00)], - "RightLowerArm": ["RightUpperArm", Vector3(-0.44, 1.42, 0.00)], - "RightHand": ["RightLowerArm", Vector3(-0.68, 1.42, 0.00)], - "LeftUpperLeg": ["Hips", Vector3(0.11, 0.90, 0.00)], - "LeftLowerLeg": ["LeftUpperLeg", Vector3(0.11, 0.50, 0.00)], - "LeftFoot": ["LeftLowerLeg", Vector3(0.11, 0.08, 0.04)], - "RightUpperLeg": ["Hips", Vector3(-0.11, 0.90, 0.00)], - "RightLowerLeg": ["RightUpperLeg", Vector3(-0.11, 0.50, 0.00)], - "RightFoot": ["RightLowerLeg", Vector3(-0.11, 0.08, 0.04)], + "Hips": ["Root", Vector3(0.00, 0.80, 0.00)], + "Spine": ["Hips", Vector3(0.00, 1.00, 0.00)], + "Chest": ["Spine", Vector3(0.00, 1.22, 0.00)], + "Neck": ["Chest", Vector3(0.00, 1.36, 0.00)], + "Head": ["Neck", Vector3(0.00, 1.44, 0.00)], + "HeadTop": ["Head", Vector3(0.00, 1.92, 0.00)], + "Jaw": ["Head", Vector3(0.00, 1.54, 0.14)], + "LeftEye": ["Head", Vector3(0.12, 1.66, 0.28)], + "RightEye": ["Head", Vector3(-0.12, 1.66, 0.28)], + "LeftShoulder": ["Chest", Vector3(0.22, 1.34, 0.00)], + "LeftUpperArm": ["LeftShoulder", Vector3(0.45, 1.30, 0.00)], + "LeftLowerArm": ["LeftUpperArm", Vector3(0.45, 1.02, 0.00)], + "LeftHand": ["LeftLowerArm", Vector3(0.45, 0.74, 0.00)], + "RightShoulder": ["Chest", Vector3(-0.22, 1.34, 0.00)], + "RightUpperArm": ["RightShoulder", Vector3(-0.45, 1.30, 0.00)], + "RightLowerArm": ["RightUpperArm", Vector3(-0.45, 1.02, 0.00)], + "RightHand": ["RightLowerArm", Vector3(-0.45, 0.74, 0.00)], + "LeftUpperLeg": ["Hips", Vector3(0.17, 0.78, 0.00)], + "LeftLowerLeg": ["LeftUpperLeg", Vector3(0.17, 0.40, 0.00)], + "LeftFoot": ["LeftLowerLeg", Vector3(0.17, 0.05, 0.05)], + "RightUpperLeg": ["Hips", Vector3(-0.17, 0.78, 0.00)], + "RightLowerLeg": ["RightUpperLeg", Vector3(-0.17, 0.40, 0.00)], + "RightFoot": ["RightLowerLeg", Vector3(-0.17, 0.05, 0.05)], } # Order matters: parents before children. @@ -50,44 +54,44 @@ const BONE_ORDER := [ "RightUpperLeg", "RightLowerLeg", "RightFoot", ] -# Body segments: [boneA, boneB, radius] -> a capsule-ish box between the two, -# fully weighted to boneA. boneB "" means a small blob at boneA. -const SEGMENTS := [ - ["Hips", "Spine", 0.14], - ["Spine", "Chest", 0.15], - ["Chest", "Neck", 0.13], - ["Neck", "Head", 0.05], - ["Head", "", 0.11], - ["LeftUpperArm", "LeftLowerArm", 0.055], - ["LeftLowerArm", "LeftHand", 0.045], - ["LeftHand", "", 0.05], - ["RightUpperArm", "RightLowerArm", 0.055], - ["RightLowerArm", "RightHand", 0.045], - ["RightHand", "", 0.05], - ["LeftUpperLeg", "LeftLowerLeg", 0.08], - ["LeftLowerLeg", "LeftFoot", 0.06], - ["LeftFoot", "", 0.06], - ["RightUpperLeg", "RightLowerLeg", 0.08], - ["RightLowerLeg", "RightFoot", 0.06], - ["RightFoot", "", 0.06], +# Roblox-classic colour blocks. +const C_SKIN := Color(0.96, 0.80, 0.19) # bright yellow (head + arms) +const C_SHIRT := Color(0.05, 0.41, 0.67) # bright blue (torso) +const C_PANTS := Color(0.18, 0.49, 0.30) # bright green (legs) +const C_FACE := Color(0.05, 0.05, 0.06) # near-black (eyes + smile) + +# Body parts: [bone, centre, size, colour]. Each part is one rigid box, fully +# weighted to its bone -- so the rig still drives it, but it reads as a clean +# solid block (no banding, no capsule taper). +const PARTS := [ + ["Head", Vector3(0.00, 1.62, 0.00), Vector3(0.60, 0.56, 0.56), C_SKIN], + ["Spine", Vector3(0.00, 1.06, 0.00), Vector3(0.74, 0.64, 0.38), C_SHIRT], + ["LeftUpperArm", Vector3(0.45, 1.04, 0.00), Vector3(0.27, 0.66, 0.31), C_SKIN], + ["RightUpperArm", Vector3(-0.45, 1.04, 0.00), Vector3(0.27, 0.66, 0.31), C_SKIN], + ["LeftUpperLeg", Vector3(0.17, 0.39, 0.00), Vector3(0.31, 0.80, 0.33), C_PANTS], + ["RightUpperLeg", Vector3(-0.17, 0.39, 0.00), Vector3(0.31, 0.80, 0.33), C_PANTS], + # painted-on face -- thin plates on the front of the head (+Z), rigged to Head + ["Head", Vector3(0.12, 1.66, 0.285), Vector3(0.07, 0.10, 0.02), C_FACE], + ["Head", Vector3(-0.12, 1.66, 0.285), Vector3(0.07, 0.10, 0.02), C_FACE], + ["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] # Mesh is built in _attachment_mesh(). const ATTACHMENTS := { - "head_cyber_01": ["head", Vector3(0, 0.02, 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_ponytail_01": ["ponytail", Vector3(0, 0.0, -0.08), Color(0.45, 0.30, 0.15)], - "face_glasses_01": ["glasses", Vector3(0, 0.06, 0.10), Color(0.10, 0.10, 0.12)], - "chest_bandit_01": ["torso", Vector3(0, 0.0, 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)], - "pants_cargo_01": ["hips", Vector3(0, -0.18, 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)], - "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)], - "right_foot_boot_01": ["boot", Vector3(0, -0.02, 0.03), 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_necklace_01": ["belt", Vector3(0, 1.34, 0.02), Color(0.85, 0.75, 0.20)], + "head_cyber_01": ["head", Vector3(0, 0.04, 0.0), Color(0.20, 0.85, 0.95)], + "hair_mohawk_01": ["mohawk", Vector3(0, 0.0, 0.0), Color(0.90, 0.20, 0.35)], + "hair_ponytail_01": ["ponytail", Vector3(0, -0.06, -0.16), Color(0.45, 0.30, 0.15)], + "face_glasses_01": ["glasses", Vector3(0, 0.12, 0.16), Color(0.10, 0.10, 0.12)], + "chest_bandit_01": ["torso", Vector3(0, -0.12, 0.0), Color(0.55, 0.20, 0.20)], + "back_backpack_01": ["box", Vector3(0, -0.06, -0.28), Color(0.30, 0.35, 0.25)], + "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)], + "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.05), 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.80, 0.0), Color(0.20, 0.18, 0.12)], + "accessory_necklace_01": ["necklace", Vector3(0, 1.30, 0.06), Color(0.85, 0.75, 0.20)], } var _fail := 0 @@ -108,7 +112,7 @@ func _initialize() -> void: # --------------------------------------------------------------------------- -# Base body — rigged, skinned +# Base body -- rigged, skinned # --------------------------------------------------------------------------- func _global_rest(bone: String) -> Transform3D: @@ -143,36 +147,46 @@ func _gen_base_body() -> void: for bone in BONE_ORDER: 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 := {} for b in range(BONE_ORDER.size()): bind_index[BONE_ORDER[b]] = b - for seg in SEGMENTS: - var a: String = seg[0] - var b: String = seg[1] - var r: float = seg[2] - var pa: Vector3 = BONES[a][1] - var pb: Vector3 = pa + Vector3(0, 0.12, 0) if b == "" else BONES[b][1] - _append_box_between(verts, normals, bones, weights, pa, pb, r, bind_index[a]) - - var arr := [] - arr.resize(Mesh.ARRAY_MAX) - arr[Mesh.ARRAY_VERTEX] = verts - arr[Mesh.ARRAY_NORMAL] = normals - arr[Mesh.ARRAY_BONES] = bones - arr[Mesh.ARRAY_WEIGHTS] = weights + # One surface per distinct colour so parts stay flat-shaded solids. + var groups: Dictionary = {} # Color (as key string) -> {color, verts, normals, bones, weights} + for part in PARTS: + var bone: String = part[0] + var centre: Vector3 = part[1] + var size: Vector3 = part[2] + var col: Color = part[3] + var key := col.to_html() + if not groups.has(key): + groups[key] = { + "color": col, + "verts": PackedVector3Array(), + "normals": PackedVector3Array(), + "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() - mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr) - var mat := StandardMaterial3D.new() - mat.albedo_color = Color(0.78, 0.66, 0.55) - mesh.surface_set_material(0, mat) + var surf := 0 + for key in groups: + var gg = groups[key] + 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() mi.name = "Body" @@ -185,38 +199,28 @@ func _gen_base_body() -> void: root.free() -# Append an axis-aligned-ish box spanning pa..pb, all verts weighted 1.0 to bone_idx. -func _append_box_between(verts: PackedVector3Array, normals: PackedVector3Array, +# Append an axis-aligned box (centre, size) with every vert weighted 1.0 to bone_idx. +func _append_box(verts: PackedVector3Array, normals: PackedVector3Array, bones: PackedInt32Array, weights: PackedFloat32Array, - pa: Vector3, pb: Vector3, r: float, bone_idx: int) -> void: - var axis := pb - pa - var len := axis.length() - if len < 0.001: - axis = Vector3(0, 0.1, 0) - len = 0.1 - var dir := axis / len - var up := Vector3.UP if absf(dir.dot(Vector3.UP)) < 0.95 else Vector3.FORWARD - 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, + centre: Vector3, size: Vector3, bone_idx: int) -> void: + var h := size * 0.5 + # 8 corners + var c: Array[Vector3] = [ + centre + Vector3(-h.x, -h.y, -h.z), centre + Vector3(h.x, -h.y, -h.z), + centre + Vector3(h.x, -h.y, h.z), centre + Vector3(-h.x, -h.y, h.z), + centre + Vector3(-h.x, h.y, -h.z), centre + Vector3(h.x, h.y, -h.z), + centre + Vector3(h.x, h.y, h.z), centre + Vector3(-h.x, h.y, h.z), ] - # 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 := [ - [0, 1, 2, 3], [7, 6, 5, 4], # caps - [0, 4, 5, 1], [1, 5, 6, 2], # sides - [2, 6, 7, 3], [3, 7, 4, 0], + [0, 3, 2, 1], # bottom (-Y) + [4, 5, 6, 7], # top (+Y) + [0, 1, 5, 4], # -Z + [2, 3, 7, 6], # +Z + [1, 2, 6, 5], # +X + [3, 0, 4, 7], # -X ] 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() for tri in [[0, 1, 2], [0, 2, 3]]: 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: @@ -239,6 +243,7 @@ func _gen_attachment(id: String, kind: String, offset: Vector3, col: Color) -> v mi.position = offset var mat := StandardMaterial3D.new() mat.albedo_color = col + mat.roughness = 0.9 mi.material_override = mat root.add_child(mi) _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: match kind: "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": - 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": - 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": - 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": - 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": - 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": - 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": - 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": - 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": - 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()