Refine NPC fabric UVs and remove baked AO blotches
This commit is contained in:
1 parent
31574b8d82
commit
d7220c1a0a
12 files changed
+64
-13
No files matched your search
@@ -13,6 +13,10 @@ extends RefCounted
|
||||
## asphalt replaced the flat first-generation tiles. Normal maps carry the mortar,
|
||||
## paver joints and aggregate that Compatibility cannot get from screen space.
|
||||
const PICK_DIR := "res://assets/textures/ai/game_ready/v2/picks/"
|
||||
## The 256² fabric maps are authored for a fine weave; repeating them 4×
|
||||
## across the body keeps the pattern readable instead of magnifying one cell
|
||||
## into a large blotch.
|
||||
const NPC_FABRIC_UV_SCALE := Vector3(4.0, 4.0, 1.0)
|
||||
const T_BRICK := preload(PICK_DIR + "brick_facade.png")
|
||||
const T_CONCRETE := preload(PICK_DIR + "sidewalk_pavers.png")
|
||||
const T_ASPHALT := preload(PICK_DIR + "asphalt.png")
|
||||
@@ -49,6 +53,8 @@ static func npc_slot(source: Material, tint: Color) -> StandardMaterial3D:
|
||||
if material == null:
|
||||
material = StandardMaterial3D.new()
|
||||
material.albedo_color = tint
|
||||
if material.resource_name in ["cloth", "pants"]:
|
||||
material.uv1_scale = NPC_FABRIC_UV_SCALE
|
||||
return material
|
||||
|
||||
## Wire a baked AO map (red channel) into every surface of an imported mesh.
|
||||
|
||||
@@ -483,7 +483,10 @@ func _apply_outfit_materials(npc_type: int, outfit: Dictionary, cloth: Color,
|
||||
if not tints.has(slot):
|
||||
continue
|
||||
var material := Materials.npc_slot(source, tints[slot])
|
||||
if ao != null:
|
||||
# The per-character baked AO is applied to skin, hair and fixed gear.
|
||||
# On the 256² fabric maps it magnified into large patches at portrait
|
||||
# distance, so cloth/pants keep their ORM weave and rely on lighting.
|
||||
if ao != null and slot not in ["cloth", "pants"]:
|
||||
material.ao_enabled = true
|
||||
material.ao_texture = ao
|
||||
material.ao_texture_channel = BaseMaterial3D.TEXTURE_CHANNEL_RED
|
||||
|
||||
@@ -3,6 +3,7 @@ extends RefCounted
|
||||
## styles, queue slots, LOD tiers/labels, and the articulated rig structure.
|
||||
|
||||
const NpcAvatar := preload("res://src/game/npc_avatar.gd")
|
||||
const Materials := preload("res://src/game/materials.gd")
|
||||
const NpcProfile := preload("res://src/core/npc_profile.gd")
|
||||
const Rules := preload("res://src/core/rules.gd")
|
||||
|
||||
@@ -333,6 +334,33 @@ func test_skinned_outfit_tints_the_material_slots() -> bool:
|
||||
avatar.free()
|
||||
return a and b and c and d
|
||||
|
||||
func test_fabric_uv_scale_avoids_the_baked_ao_pattern() -> bool:
|
||||
var avatar := _avatar(Rules.NpcType.TOURIST, 44)
|
||||
var mi := avatar.find_child("npc_base", true, false) as MeshInstance3D
|
||||
var fabric := 0
|
||||
var skin_ao := false
|
||||
var problems: Array[String] = []
|
||||
for index in mi.mesh.get_surface_count():
|
||||
var source := mi.mesh.surface_get_material(index)
|
||||
var material := mi.get_surface_override_material(index) as StandardMaterial3D
|
||||
if source == null or material == null:
|
||||
continue
|
||||
var slot := str(source.resource_name)
|
||||
if slot in ["cloth", "pants"]:
|
||||
fabric += 1
|
||||
if not material.uv1_scale.is_equal_approx(
|
||||
Materials.NPC_FABRIC_UV_SCALE):
|
||||
problems.append("%s uv=%s" % [slot, str(material.uv1_scale)])
|
||||
if material.ao_enabled:
|
||||
problems.append("%s still uses baked AO" % slot)
|
||||
elif slot == "skin" and material.ao_enabled:
|
||||
skin_ao = true
|
||||
var a := TestUtils.check(fabric > 0 and problems.is_empty(),
|
||||
"cloth/pants use the fine-UV scale and skip baked AO (%s)" % str(problems))
|
||||
var b := TestUtils.check(skin_ao, "skin keeps its baked AO")
|
||||
avatar.free()
|
||||
return a and b
|
||||
|
||||
func test_forced_fallback_still_builds_the_procedural_rig() -> bool:
|
||||
var profile := NpcProfile.new()
|
||||
profile.id = "fallback_test"
|
||||
|
||||
Reference in new issue
Block a user