TECHARTNOMAD | TECHARTFLOWIO.COM

UNREAL ENGINE

본 인덱스 Weight 0.01 이하 이거나 버택스 하나에 12개 이상의 본 인덱스 버퍼가 걸려 있을 때 클리어 하는 함수 변경점.

jplee 2023. 8. 17. 16:55

약 한 달 전쯤인가...

테크리그 동료분이 캐릭터 얼굴 리깅을 완료 하고 마야에서 언리얼 엔진으로 넘겨준 데이터를 잠시 테스트 할 필요가 있었음.

프로모션 영상 제작용이다보니 페이셜 애니메이션이 중요한 편이었음.

바쁘다 보니 입술 쪽 스킨웨이트 테이블을 더블체크 하지 않았는데... 

버택스 하나에 8 개 이상의 본 인덱스가 걸려있었고 많은 본 웨이트가 0.01 존재. 

5.1.1 에서 구현 부분을 보면 MINWEIGHT 를 사용하고 있고 프로젝트 셋팅의

BoneWeightThreshold

가 정확히 처리가 안되어 있다.

 

InterchangeSkeletalMeshFactory.cpp

에서 살펴 볼 수 있는데...

 

5.1.1 은 아래와 같이 구현 되어 있다.

...
Influences.Sort(FCompareVertexIndex());

TArray <SkeletalMeshImportData::FRawBoneInfluence> NewInfluences;
int32	LastNewInfluenceIndex = 0;
int32	LastVertexIndex = INDEX_NONE;
int32	InfluenceCount = 0;

float TotalWeight = 0.f;
const float MINWEIGHT = 0.004f;

int MaxVertexInfluence = 0;
float MaxIgnoredWeight = 0.0f;              
.
.
.
.
.
// if less than min weight, or it's more than 8, then we clear it to use weight
if (Influences[i].Weight > MINWEIGHT && InfluenceCount < MAX_TOTAL_INFLUENCES)
{
    LastNewInfluenceIndex = NewInfluences.Add(Influences[i]);
    InfluenceCount++;
    TotalWeight += Influences[i].Weight;
}

이런 식으로 구현부가 있음.

 

5.2.1 에서 정확히 구현 되었다.

BoneWeights.h 파일을 비교 해 보면.

/** The maximum raw weight value */
static constexpr uint16 MaxRawBoneWeight = std::numeric_limits<uint16>::max();

/** The maximum raw weight value as a float value */
static constexpr float MaxRawBoneWeightFloat = static_cast<float>(std::numeric_limits<uint16>::max());

/** The inverse of the maximum raw weight value as a float value. Used for scaling. */
static constexpr float InvMaxRawBoneWeightFloat = 1.0f / MaxRawBoneWeightFloat;

/** The threshold value at or above which a 0-1 normalized bone weight value will be stored as a non-zero value after
 *  scaling and quantizing to a 16-bit integer */
static constexpr float BoneWeightThreshold = InvMaxRawBoneWeightFloat;

이렇게 정적변수들이 추가 되었다. 5.1.1 에는 

static constexpr int32 MaxInlineBoneWeightCount = MAX_TOTAL_INFLUENCES;

만 정의 되어 있었다.

 

5.2.1 의 InterchangeSkeletalMeshFactory.cpp 에서 이렇게 바뀌었다.

예전에는 0.01 값 코드에서 MINWEIGHT 변수에 할당 되어 있었기 때문에 직접 0.005 정도로 변경하고 컴파일을 해 줬었다.

// if less than min weight, or it's more than 12, then we clear it to use weight
if (Influences[i].Weight >= UE::AnimationCore::BoneWeightThreshold &&
    InfluenceCount < MAX_TOTAL_INFLUENCES)
{
    LastNewInfluenceIndex = NewInfluences.Add(Influences[i]);
    InfluenceCount++;
    TotalWeight += Influences[i].Weight;
}

또한 기본적으로 8개의 본 인덱스 버퍼로 설정 된 부분이 12로 늘어난걸 볼 수 있다.

강제로 이 본 인덱스 버퍼를 늘려주려고 했었지만 크레시가 나는데.. 귀찮아서 디버깅 안해봤다. 사실 버택스 하나에 12개의 본 인덱스 버퍼가 물릴 가능성도 거의 없으니까...

 

마지막으로 가장 올바른 것은 마야에서 스크립트로 입술이나 눈꺼플 등의 여러개의 작은 본들이 많이 관계 하고 있는 곳의 버택스 웨이트 클린업을 미리 수행 하고 오류를 없애는 것이겠다.