Hair simulation 프로젝트 진행 중에
정적인 model, 움직이는 model과 Hair의 충돌 처리 부분을 진행하기 위해서는
(1) Static Mesh에서의 정점 배열 정보(Pos, index 등)를 Access
(2) Skeletal Mesh에서의 정점 배열 정보(Pos, index 등)를 Access
를 처리해야 했다.
이 파트 진행에만 구글의 바다를 ...한참동안 떠돌아다녔다ㅜㅜ 꽤 헤매었던 기억이 있음
결론적으로는 해결했고!
내 프로젝트에는 잘 적용되었기에 해당 포스팅을 써본다.
나는 이렇게 해봤다~는 공유 목적으로 작성하므로 내용이 정확하지 않을 수 있다.
[1] Static Mesh
/** Pointer to the data used to render this static mesh. */
TUniquePtr<class FStaticMeshRenderData> RenderData;
RenderData가 StaticMesh에 대한 다양한 데이터를 가지고있다.
UStaticMesh* usm = m_StaticMesh->GetStaticMesh();
if (m_StaticMesh == nullptr) { UE_LOG(LogTemp, Error, TEXT("ERR::HeadMesh::No Static Mesh Set")); }
// Store Static Mesh LOD0 Buffer Pointers
FStaticMeshLODResources* lod0 = *(usm->RenderData->LODResources.GetData());
smData.vb = &(lod0->VertexBuffers.PositionVertexBuffer); // Pos
smData.smvb = &(lod0->VertexBuffers.StaticMeshVertexBuffer); // Static Mesh Buffer
smData.cvb = &(lod0->VertexBuffers.ColorVertexBuffer); // Color
smData.ib = &(lod0->IndexBuffer); // Tri Inds
위의 코드에서 smdata는 Static Mesh 관련 데이터를 저장하기 위한 struct였다. 그대로 코드를 들고오다보니..ㅎ
해당 버텍스 버퍼에서 X, Y, Z의 위치를 받아올 수 있고+GetComponentLocation() 과정을 쭉 거쳐
// 코드 중 일부
// Mesh Init
Vector3f MeshVertex = Vector3f(
GetComponentLocation().X + smData.vb->VertexPosition(i).X,
GetComponentLocation().Y + smData.vb->VertexPosition(i).Y,
GetComponentLocation().Z + smData.vb->VertexPosition(i).Z);
mesh->vertices.push_back(MeshVertex);
DrawDebugPoint()로 쭉 확인을 해보면, 정점 위치가 제대로 나온다.
👍
[2] Skeletal Mesh
해당 파트는 하도 자료가 안 나왔고, 나도 땅 파보다 성공했기 때문에..
부정확한 정보일 수 있다
ACharacter class에 존재하는 GetMesh()로 charcter가 가진 mesh를 받는다.
/** Returns Mesh subobject **/
FORCEINLINE class USkeletalMeshComponent* GetMesh() const { return Mesh; }
이후 Static과 마찬가지로 메시에 대한 정보를 받아오면 된다.
그러나 Static과 같이 정보가 RenderData와 같은 구조에 한데 모여있는 것이 아니라서(찾지 못한 것일 수도 있다) 여러 데이터에서 끌어왔다.
USkeletalMeshComponent* SMComponent = GetMesh();
USkeletalMesh* SM = SMComponent->SkeletalMesh;
FSkeletalMeshRenderData* SMRenderData = SM->GetResourceForRendering();
FSkeletalMeshLODRenderData& SMLodRender = SMRenderData->LODRenderData[0];
smData.vb = SMComponent->GetSkinWeightBuffer(0); //Pos
smData.smvb = &(SMLodRender.StaticVertexBuffers.StaticMeshVertexBuffer); //Static Mesh
smData.cvb = &(SMLodRender.StaticVertexBuffers.ColorVertexBuffer); //Color
index buffer는 array로 받아올 수 있게 되어있어서 아래와 같이 처리했다.
// ----- 위에서도 사용된 코드 -----//
USkeletalMeshComponent* SMComponent = GetMesh();
USkeletalMesh* SM = SMComponent->SkeletalMesh;
// ------------------------------//
FSkeletalMeshModel* SMResource = SM->GetImportedModel();
FSkeletalMeshLODModel &SMModel = SMResource->LODModels[0];
// Array로 받아온다
TArray<uint32> indices = SMModel.IndexBuffer;
GetSkinWeightBuffer(0)에서 바로 pos정보를 받아오고 싶었는데 되지 않았다.
GetSkinnedVertexPosition()이라는 USkeletalMeshComponent의 함수로 진행한다.
+GetActorLocation() Actor가 존재하는 위치에 vertex가 찍히도록 한다
//Update every vertex position in every render section
for (int32 j = 0; j < SMLodRender.RenderSections.Num(); j++)
{
for (int32 i = 0; i < SMLodRender.RenderSections[j].GetNumVertices(); i++)
{
FVector VertexPosition = SMComponent->GetSkinnedVertexPosition(
SMComponent,
SMLodRender.RenderSections[j].BaseVertexIndex + i,
SMLodRender,
*smData.vb)
+ GetActorLocation() + SMComponent->GetRelativeLocation();
Vector3f MeshNormal = Vector3f(
smData.smvb->VertexTangentZ(i).X,
smData.smvb->VertexTangentZ(i).Y,
smData.smvb->VertexTangentZ(i).Z);
cmesh->normals.push_back(MeshNormal);
if (smData.has_col)
{
FColor vc = SMComponent->GetVertexColor(SMLodRender.RenderSections[j].BaseVertexIndex + i);
Vector3f MeshCol = Vector3f(vc.R, vc.G, vc.B);
cmesh->colors.push_back(MeshCol);
}
}
}
VertexPosition은 TArray<FVector> 변수(smData.Pos)에 쭉 저장해주었다
저장된 vertexposition은 index buffer에 저장된 정보로 접근하면 된다.
// 코드 중 일부
#define POINTS_PER_VERTEX 3
#define TOTAL_FLOATS_IN_TRIANGLE 9
int triangleIndex = 0;
for (int i = 0; i < smData.tri_count; ++i)
{
int vertexNumber[4] = { 0, 0, 0 };
vertexNumber[0] = smData.Ind[3 * i];
vertexNumber[1] = smData.Ind[3 * i + 1];
vertexNumber[2] = smData.Ind[3 * i + 2];
int tCounter = 0;
for (int j = 0; j < POINTS_PER_VERTEX; j++)
{
obj->faces[triangleIndex + tCounter] = obj->vertices[3 * vertexNumber[j]];
obj->faces[triangleIndex + tCounter + 1] = obj->vertices[3 * vertexNumber[j] + 1];
obj->faces[triangleIndex + tCounter + 2] = obj->vertices[3 * vertexNumber[j] + 2];
tCounter += POINTS_PER_VERTEX;
}
//------- For Debugging -------//
FVector vec1(obj->faces[triangleIndex], obj->faces[triangleIndex + 1], obj->faces[triangleIndex + 2]);
FVector vec2(obj->faces[triangleIndex + 3], obj->faces[triangleIndex + 4], obj->faces[triangleIndex + 5]);
FVector vec3(obj->faces[triangleIndex + 6], obj->faces[triangleIndex + 7], obj->faces[triangleIndex + 8]);
DrawDebugLine(world, vec1, vec2, FColor::Blue, true, -1, 0, 0.1);
DrawDebugLine(world, vec2, vec3, FColor::Blue, true, -1, 0, 0.1);
DrawDebugLine(world, vec3, vec1, FColor::Blue, true, -1, 0, 0.1);
triangleIndex += TOTAL_FLOATS_IN_TRIANGLE;
}
마찬가지로 DrawDebugLine()으로 vertex pos 및 index가 잘 저장되었나 확인해본다
굿! 🤗
써놓고보니 가독성이 너무 별로지만 일단 작성해놓고 이후에 수정을 거치겠다
나처럼 헤매던 사람들이 조금이나마 도움이 되길 바라면서 하핫..
진행한 프로젝트 관련 포스팅도 조만간 해야겠다
끝~