Tattoo test bed: Quaternius v3-v6 bakes + Lena pipeline (bake, de-mirror, re-UV, viewers)
Session 2026-07-23/24 additions on top of the existing Quaternius bed: - bake_lena.gd: 6-piece bake on QuatSkin Lena (chiefs-mark/iron-spine arms, voyagers/storm-bearer legs, star-eye chest, hearth-warmth back); global-axis wrap frame + 3cm junction blend kill the elbow split line - demirror_lena.gd: tri-level split of mirror-shared limb UVs (arms 100%->0%, legs 99%->5% crotch-only residual) - reuv_lena.gd: Quaternius-style semantic re-UV (16 islands, cylinder limbs + cylinder head/torso with planar caps) + texture transfer; fixes armpit/chin/ cheek planar smears; single 4096 atlas, per-side tattoos native - main_lena / anim_lena viewers (18 UAL clips, U light toggle) + probes + shots Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# Color signature of Lena's painted bra vs bare skin (for a fabric-skip predicate).
|
||||
extends SceneTree
|
||||
|
||||
const GLB_PATH := "C:/Users/CAN/tinqs-ltd/ariki-game/assets/quaternius/derived-bodies/Ariki_Female_QuatSkin.glb"
|
||||
|
||||
func _init() -> void:
|
||||
var doc := GLTFDocument.new()
|
||||
var state := GLTFState.new()
|
||||
if doc.append_from_file(GLB_PATH, state) != OK:
|
||||
quit(1)
|
||||
return
|
||||
var scene := doc.generate_scene(state)
|
||||
var skel: Skeleton3D = null
|
||||
var body: Node = null
|
||||
var stack: Array = [scene]
|
||||
while not stack.is_empty():
|
||||
var n: Node = stack.pop_back()
|
||||
if n is Skeleton3D and skel == null:
|
||||
skel = n
|
||||
if (n is MeshInstance3D or n.get_class() == "ImporterMeshInstance3D") \
|
||||
and String(n.name).to_lower().contains("lena"):
|
||||
body = n
|
||||
for c in n.get_children():
|
||||
stack.push_back(c)
|
||||
var mesh = body.mesh
|
||||
if mesh is ImporterMesh:
|
||||
mesh = mesh.get_mesh()
|
||||
var arrays: Array = mesh.surface_get_arrays(0)
|
||||
var verts: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX]
|
||||
var uvs: PackedVector2Array = arrays[Mesh.ARRAY_TEX_UV]
|
||||
var normals: PackedVector3Array = arrays[Mesh.ARRAY_NORMAL]
|
||||
var mat: Material = mesh.surface_get_material(0)
|
||||
var img: Image = (mat as BaseMaterial3D).albedo_texture.get_image()
|
||||
img.clear_mipmaps()
|
||||
img.convert(Image.FORMAT_RGBA8)
|
||||
var tw := img.get_width()
|
||||
var th := img.get_height()
|
||||
|
||||
# bands: [label, ymin, ymax] — front-facing, near body midline (|x|<0.15)
|
||||
for band in [["bra front", 1.16, 1.32], ["belly skin", 0.98, 1.07],
|
||||
["upper chest", 1.34, 1.40], ["hip underwear", 0.82, 0.90],
|
||||
["thigh skin", 0.55, 0.75]]:
|
||||
var sr := 0.0
|
||||
var sg := 0.0
|
||||
var sb := 0.0
|
||||
var cnt := 0
|
||||
var rb_min := 1.0
|
||||
var rb_max := -1.0
|
||||
for v in verts.size():
|
||||
var p := verts[v]
|
||||
if p.y < band[1] or p.y > band[2] or absf(p.x) > 0.15 or normals[v].z < 0.25:
|
||||
continue
|
||||
var px := clampi(int(uvs[v].x * tw), 0, tw - 1)
|
||||
var py := clampi(int(uvs[v].y * th), 0, th - 1)
|
||||
var c := img.get_pixel(px, py)
|
||||
sr += c.r
|
||||
sg += c.g
|
||||
sb += c.b
|
||||
var rb := (c.r - c.b) / maxf(c.r, 0.001)
|
||||
rb_min = minf(rb_min, rb)
|
||||
rb_max = maxf(rb_max, rb)
|
||||
cnt += 1
|
||||
if cnt > 0:
|
||||
print("%s: n=%d avg RGB (%.3f, %.3f, %.3f) (r-b)/r range %.3f..%.3f" %
|
||||
[band[0], cnt, sr / cnt, sg / cnt, sb / cnt, rb_min, rb_max])
|
||||
quit()
|
||||
Reference in New Issue
Block a user