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:
|
||||
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)
|
||||
|
||||
|
||||
|
||||
+14
-3
@@ -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.
|
||||
|
||||
@@ -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)],
|
||||
"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.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)],
|
||||
"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()
|
||||
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 = Color(0.78, 0.66, 0.55)
|
||||
mesh.surface_set_material(0, mat)
|
||||
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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user