light: raise the sun so the character leaves building shadow (needs approval)
The skin was never grey. A red test colour reached the render and the slot was confirmed holding M_Character_Skin, so the material and the assignment were both fine - the body was simply standing in building shadow and lit almost entirely by the blue skylight (intensity 2.6). Warm skin under blue fill reads blue-grey. Raising the sun from pitch -62 to -74, same camera: face (99, 98, 100) -> (131, 121, 117) arms (67, 74, 81) -> (71, 78, 85) This touches every approved shot, so it sits on the branch for the owner's approval rather than being folded in. Also records that the Unreal commandlet silently drops unknown switches, which is why a --unlit-test flag never took effect.
This commit is contained in:
1 parent
7c57bf318b
commit
bea6aa3e05
39 files changed
+64
-53
No files matched your search
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.
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.
@@ -510,3 +510,5 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
- **Edit-mode selection reverts to vertex selection.** Setting `polygon.select` in object mode and then entering edit mode re-derives selection from the vertices, which were all still selected - deleting "the unselected faces" wiped the entire garment. Filter with `bmesh.ops.delete(context="FACES")` instead.
|
||||
- **`ConstructorHelpers::FObjectFinder` outside a constructor is a fatal error**, not a warning: the game dies in `Tick` with "FObjectFinders can't be used outside of constructors". Use `LoadObject<T>(nullptr, Path)` for runtime loads and keep `FObjectFinder` to the constructor.
|
||||
- **A 1 cm solidify shell lets the body poke through.** Garments built by duplicating body faces needed 2 cm of solidify plus an 8 mm fatten along their own normals before the cloth read as continuous at shoulders, hips and knees.
|
||||
- **Warm skin sampling as blue-grey was lighting, not material.** The body stood in building shadow and was lit almost entirely by the blue `Demo_SkyLight` (intensity 2.6): face (99, 98, 100), arms (67, 74, 81). Raising the sun to pitch -74 moved the face to (131, 121, 117). A deliberate red test colour reaching the render first proved the material and the slot assignment were fine, which is what stopped a long hunt in the wrong place.
|
||||
- **The Unreal commandlet drops unknown command-line switches.** A `--unlit-test` flag passed after `-script` never reached Python; an environment variable does get through (and even that proved unnecessary once the red test settled the question).
|
||||
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.
@@ -25,7 +25,7 @@ Actionable task list for this project. This file is the single, central place fo
|
||||
- **Clothing exists now** (`Tools/character_clothing_build.py` + `Tools/ue_character_clothing_import.py`): tee, jeans and shoes as three separate skinned meshes, built from the body's own faces per the character-artist workflow (duplicate faces, solidify for thickness, one mesh per piece), imported as `CharacterTee` / `CharacterJeans` / `CharacterShoes` and attached as leader-pose components. The navy tee, dark jeans and off-white shoes read correctly at review distance.
|
||||
- **Garment coverage fixed 2026-11-09.** Solidify thickness raised to 2 cm plus a normal fatten pass of 8 mm closed the shoulders, hips and knees; the tee, jeans and shoes now read as continuous cloth. Evaluation against the blueprint improved from **mean ΔE 31.9 → 21.8** and **palette ΔE 25.4 → 19.7**; the montage is `Art/characters/blueprints/match-front.png`.
|
||||
- **Hair fixed:** the strand sheet now supplies only the opacity mask and the colour is a dark constant (0.030/0.020/0.014). Sampled in the render: hair (31, 26, 21) - properly dark instead of the washed-out blond it read as when the sheet's RGB drove base colour.
|
||||
- **Skin colour: assignment proved, tone unexplained.** A runtime log confirmed the slot holds `M_Character_Skin` (`slot0=M_Character_Skin slots=1`), and a deliberate red test colour reached the render - so binding works. But the intended warm tone (0.78/0.55/0.44) samples as **bluish grey** in the render: arms (67, 74, 81), face (98, 97, 100), while the tee and jeans show their colours correctly. Something between the constant and the final pixel is desaturating the skin - next suspects are the material's shading model/ambient occlusion from the body normals, or the render's key light being far dimmer on the body than on the ground.
|
||||
- **Skin colour explained 2026-11-09: the character stands in building shadow.** The material, the assignment and the tone were all correct; the body was lit almost entirely by the blue sky light (intensity 2.6), so warm skin sampled as grey-blue. Raising the sun from pitch -62 to -74 lifted the face from (99, 98, 100) to (131, 121, 117) and the arms from (67, 74, 81) to (71, 78, 85) at the same camera. **That is a lighting change affecting every approved shot, so it is on this branch awaiting the owner's approval, not merged.** Original note: A runtime log confirmed the slot holds `M_Character_Skin` (`slot0=M_Character_Skin slots=1`), and a deliberate red test colour reached the render - so binding works. But the intended warm tone (0.78/0.55/0.44) samples as **bluish grey** in the render: arms (67, 74, 81), face (98, 97, 100), while the tee and jeans show their colours correctly. Something between the constant and the final pixel is desaturating the skin - next suspects are the material's shading model/ambient occlusion from the body normals, or the render's key light being far dimmer on the body than on the ground.
|
||||
- **Figure segmentation is explicit, not automatic.** Auto-detection failed on the review shots: the backdrop (sky band, pale wall, dark pavement) is larger and more saturated than the subject, so every size-based rule picked a backdrop blob. `--render-box` takes the figure box as fractions of the frame. A background plate rendered without the character would make this automatic.
|
||||
- `Tools/ue_character_materials.py` (wiring the generated textures into the skin and hair materials) **segfaults in the headless commandlet** when it edits the material graph. Not wired; the hair keeps the dark base colour it carries from Blender. Needs either an editor-session run or a material asset built from scratch instead of edited in place.
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ def build():
|
||||
# 3. Ambience. A height fog gives the street depth and hides the terrain
|
||||
# edge that otherwise reads as a black band at the horizon.
|
||||
sun = spawn(unreal.DirectionalLight, unreal.Vector(0, 0, 2000), "Demo_Sun",
|
||||
unreal.Rotator(pitch=-62.0, yaw=120.0, roll=0.0))
|
||||
unreal.Rotator(pitch=-74.0, yaw=120.0, roll=0.0))
|
||||
if sun:
|
||||
comp = sun.get_component_by_class(unreal.DirectionalLightComponent)
|
||||
if comp:
|
||||
@@ -341,7 +341,7 @@ def build():
|
||||
comp.set_mobility(unreal.ComponentMobility.MOVABLE)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
log(f"sun mobility not set: {exc!r}")
|
||||
log("staged: Demo_Sun (pitch -62, yaw 120, intensity 4, warm; higher sun so both frontages read)")
|
||||
log("staged: Demo_Sun (pitch -74, yaw 120, intensity 4, warm; higher sun lifts the north sidewalk out of building shadow)")
|
||||
|
||||
sky = spawn(unreal.SkyLight, unreal.Vector(0, 0, 2000), "Demo_SkyLight")
|
||||
if sky:
|
||||
|
||||
@@ -71,7 +71,7 @@ def new_material(name):
|
||||
return material
|
||||
|
||||
|
||||
def skin_material(diffuse, detail):
|
||||
def skin_material(diffuse, detail, unlit_test=False):
|
||||
material = new_material("M_Character_Skin")
|
||||
lib = unreal.MaterialEditingLibrary
|
||||
|
||||
@@ -84,13 +84,20 @@ def skin_material(diffuse, detail):
|
||||
# was always working - the skin simply reads dark under the demo's key light. This
|
||||
# tone is lifted to sit in shadow the way the blueprint's skin does.
|
||||
base.set_editor_property("constant", unreal.LinearColor(0.78, 0.55, 0.44, 1.0))
|
||||
lib.connect_material_property(base, "", unreal.MaterialProperty.MP_BASE_COLOR)
|
||||
if unlit_test:
|
||||
# Diagnostic: unlit renders the constant exactly, so the render tells us whether
|
||||
# a wrong skin tone comes from lighting/shading or from the material itself.
|
||||
material.set_editor_property("shading_model", unreal.MaterialShadingModel.MSM_UNLIT)
|
||||
lib.connect_material_property(base, "", unreal.MaterialProperty.MP_EMISSIVE_COLOR)
|
||||
else:
|
||||
lib.connect_material_property(base, "", unreal.MaterialProperty.MP_BASE_COLOR)
|
||||
|
||||
rough = lib.create_material_expression(material, unreal.MaterialExpressionConstant, -200, -200)
|
||||
rough.set_editor_property("r", 0.58)
|
||||
lib.connect_material_property(rough, "", unreal.MaterialProperty.MP_ROUGHNESS)
|
||||
lib.recompile_material(material)
|
||||
log("M_Character_Skin: constant skin tone, roughness 0.58 "
|
||||
log(("M_Character_Skin: UNLIT TEST, emissive " if unlit_test else
|
||||
"M_Character_Skin: constant skin tone, roughness 0.58 ")
|
||||
"(baked diffuse not used - it samples black on this mesh)")
|
||||
return material
|
||||
|
||||
@@ -118,14 +125,14 @@ def hair_material(strands):
|
||||
return material
|
||||
|
||||
|
||||
def main():
|
||||
def main(unlit_test=False):
|
||||
diffuse = unreal.EditorAssetLibrary.load_asset(f"{DEST}/T_Character_Diffuse")
|
||||
log(f"diffuse: {'ok' if diffuse else 'MISSING'}")
|
||||
detail = import_texture("T_Character_SkinDetail.png")
|
||||
strands = import_texture("T_Character_Hair.png")
|
||||
|
||||
if diffuse and detail:
|
||||
skin_material(diffuse, detail)
|
||||
skin_material(diffuse, detail, unlit_test=unlit_test)
|
||||
|
||||
if strands:
|
||||
hair = hair_material(strands)
|
||||
@@ -144,7 +151,9 @@ def main():
|
||||
|
||||
|
||||
try:
|
||||
main()
|
||||
# Environment, not a command-line flag: the commandlet drops unknown switches, so
|
||||
# the flag never reached Python. An env var is inherited.
|
||||
main(unlit_test=os.environ.get("GIGLINE_UNLIT_TEST") == "1")
|
||||
except Exception as exc: # noqa: BLE001
|
||||
import traceback
|
||||
log(f"FAILED: {type(exc).__name__}: {exc}")
|
||||
|
||||
Reference in new issue
Block a user