feat(clothing): tee, jeans and shoes as separate skinned meshes
Follows the character-artist clothing workflow literally: duplicate the body's own faces for the garment base, solidify for cloth thickness, and keep each piece a separate mesh. Attached as leader-pose components beside the hair, so no second rig. - Tools/character_clothing_build.py builds three garments from the body mesh, trimmed geometrically (height band plus a width limit) instead of by dominant bone: the bone filter left holes wherever a face's strongest bone was outside the allowed list. - Tools/ue_character_clothing_import.py imports them as CharacterTee / CharacterJeans / CharacterShoes, each arriving with its own single material slot. - The pawn attaches all three, hidden with the body in first person. Three traps recorded in MEMORY.md, each of which cost a build: MPFB weights its helper geometry to groups that dominate every vertex, Blender refuses to apply a modifier to a mesh with shape keys, and object-mode polygon selection is discarded on entering edit mode - the delete wiped the whole garment. Known defects, in TODO.md: the garments have coverage holes at shoulders, hips and knees, and the hair reads light and wispy since its material was repointed to the masked strand sheet.
This commit is contained in:
1 parent
85a8437cbc
commit
86e9c5b693
50 files changed
+408
-46
No files matched your search
@@ -117,6 +117,30 @@ AGigLineCharacter::AGigLineCharacter()
|
||||
HairMesh->SetLeaderPoseComponent(GetMesh());
|
||||
}
|
||||
|
||||
// Garments: tee, jeans, shoes. Each is its own mesh with its own single material,
|
||||
// attached to the capsule and posed from the body so there is no second rig.
|
||||
static const TCHAR* GarmentPaths[] = {
|
||||
TEXT("/Game/Test/Character/CharacterTee.CharacterTee"),
|
||||
TEXT("/Game/Test/Character/CharacterJeans.CharacterJeans"),
|
||||
TEXT("/Game/Test/Character/CharacterShoes.CharacterShoes"),
|
||||
};
|
||||
for (const TCHAR* Path : GarmentPaths)
|
||||
{
|
||||
USkeletalMeshComponent* Piece = CreateDefaultSubobject<USkeletalMeshComponent>(
|
||||
FName(*FString::Printf(TEXT("Cloth_%s"), *FPaths::GetBaseFilename(Path))));
|
||||
Piece->SetupAttachment(GetCapsuleComponent());
|
||||
Piece->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
Piece->SetHiddenInGame(true);
|
||||
Piece->SetRelativeLocation(FVector(0.0f, 0.0f, -87.5f));
|
||||
Piece->SetRelativeRotation(FRotator(0.0f, -90.0f, 0.0f));
|
||||
if (USkeletalMesh* Mesh = LoadObject<USkeletalMesh>(nullptr, Path))
|
||||
{
|
||||
Piece->SetSkeletalMesh(Mesh);
|
||||
Piece->SetLeaderPoseComponent(GetMesh());
|
||||
}
|
||||
Clothing.Add(Piece);
|
||||
}
|
||||
|
||||
// Third-person boom. bDoCollisionTest is the camera-collision feature: the arm
|
||||
// shortens when something is between the pivot and the desired camera position.
|
||||
ThirdPersonArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("ThirdPersonArm"));
|
||||
@@ -826,6 +850,13 @@ void AGigLineCharacter::ToggleCamera()
|
||||
{
|
||||
HairMesh->SetHiddenInGame(!bThirdPerson);
|
||||
}
|
||||
for (USkeletalMeshComponent* Piece : Clothing)
|
||||
{
|
||||
if (Piece)
|
||||
{
|
||||
Piece->SetHiddenInGame(!bThirdPerson);
|
||||
}
|
||||
}
|
||||
if (bThirdPerson)
|
||||
{
|
||||
UpdateBodyAnimation();
|
||||
|
||||
Reference in new issue
Block a user