ProceduralMeshComponent Voxel GenerateMesh CreateMeshSection Normal Tangent Unreal Insights OnConstruction Normal Tangent
t에서 길이가 p와 같은 부분 문자열을 모두 확인한다.p보다 작거나 같으면 카운트한다.p는 길이가 같으므로 문자열 비교(<=)를 그대로 사용해도 된다.#include <string>
using namespace std;
int solution(string t, string p) {
int answer = 0;
for (size_t i = 0; i <= t.size() - p.size(); i++)
{
string part = t.substr(i, p.size());
if (part <= p) answer++;
}
return answer;
}
string::substr(pos, len)은 pos부터 len개만큼 잘라온다.part와 p의 길이가 항상 같기 때문에 문자열 비교가 숫자 비교처럼 동작한다."9" > "10"처럼 문자열 비교 결과가 숫자 비교와 달라질 수 있다.stoll로 숫자 변환을 하지 않아도 되므로 오버플로우 걱정을 줄일 수 있다.| 기능 | 설명 | 기획 연관성 |
|---|---|---|
| 렌더링 | 3D/2D 그래픽 출력 | 그래픽 품질, 화면 연출, 분위기 기획에 영향 |
| 물리 엔진 | 충돌, 중력, 시뮬레이션 | 물리 기반 퍼즐, 낙하, 투사체, 탈것 시스템 기획과 연결 |
| 애니메이션 | 캐릭터 동작 제어 | 이동, 공격, 피격, 사망 등 캐릭터 상태 표현과 연결 |
| AI | 경로 탐색, 행동 트리 | 적 행동 패턴, NPC 반응, 전투 난이도 기획과 연결 |
| UI / UMG | 화면 인터페이스 | HUD, 메뉴, 체력바, 점수판 등 사용자 정보 전달 담당 |
| DataTable | 게임 데이터 에셋 | 밸런스 수치, 아이템 정보, 웨이브 데이터 등을 쉽게 수정 가능 |
| 블루프린트 | 비주얼 스크립팅 | 기획자가 코드를 몰라도 간단한 로직 수정 가능 |
팀 프로젝트 One, Two... Shoot!에서 포탄에 맞은 지형이 파괴되는 기능을 만들기 위해 복셀 기반 지형 청크를 구현했다.
현재 구조는 AVoxelChunkActor가 TArray<bool>로 복셀 데이터를 들고 있고, ProceduralMeshComponent로 노출된 면만 메시로 만든다. 청크 크기는 현재 16 * 16 * 16이라 총 4096개의 복셀을 다룬다. 파괴 테스트는 우클릭/디버그 함수로 청크 안의 임의 지점을 잡고, 그 주변 복셀을 false로 바꾼 뒤 메시를 다시 생성하는 방식으로 진행했다.
구현한 핵심 흐름은 다음과 같다.
AddFaceCreateMeshSection_LinearColor로 Procedural Mesh 생성처음에는 단순히 복셀 몇 개를 지우는 작업이라고 생각했지만, 실제 비용은 삭제 자체보다 GenerateMesh()와 CreateMeshSection()에서 발생한다. 복셀을 지울 때마다 전체 청크 메시를 다시 만들면, 청크 크기가 조금만 커져도 우클릭 파괴마다 끊김이 생길 수 있다.
오늘 가장 오래 붙잡고 있었던 문제는 복셀 메시가 Lit 머티리얼에서 검게 보이는 문제였다. 처음에는 머티리얼이나 조명 문제라고 생각했는데, 실제 핵심은 Normal, Tangent, 그리고 삼각형 정점 순서였다.
Normal은 면이 어느 방향을 보고 있는지 알려주는 값이다. 언리얼의 Lit 머티리얼은 이 Normal을 기준으로 빛을 계산한다. 그래서 면은 실제로 위를 보고 있는데 Normal이 반대 방향을 가리키면, 빛을 제대로 받지 못해서 검게 보일 수 있다.
문제가 됐던 부분은 사각형 면 하나를 삼각형 두 개로 나누는 순서였다.
0, 1, 2 -> 0, 2, 1
0, 2, 3 -> 0, 3, 2
같은 네 점으로 같은 사각형을 만들더라도 엔진 입장에서는 서로 반대 방향을 보는 면이다. 이 순서를 바꾸면 메시의 앞면/뒷면 판정과 조명 계산 방향이 달라진다. 그래서 어떤 순서에서는 빛을 받는 것처럼 보이고, 어떤 순서에서는 Lit 머티리얼이 검게 보일 수 있다.
Tangent는 표면 위에서 UV의 U 방향이 증가하는 축이다. 처음에는 CalculateTangentsForMesh()를 쓰면 자동으로 해결될 줄 알았다. 하지만 이 함수는 내가 넘긴 Vertices, Triangles, UVs를 기준으로 Normal과 Tangent를 계산한다. 즉, 삼각형 정점 순서나 UV가 이상하면 자동 계산 결과도 같이 이상해진다.
결국 Emissive를 켜면 색이 보이고, Lit에서는 검게 보였던 이유는 메시가 엔진에게 “내 표면은 이 방향을 보고 있다”는 정보를 제대로 전달하지 못했기 때문이었다.
BeginPlay()에서만 메시를 생성하면 에디터에서 플레이 전에는 복셀이 안 보이는 것이 정상이다. 에디터에서도 보이게 하려면 OnConstruction()에서 메시를 만들 수 있다.
하지만 OnConstruction()은 액터를 움직이거나 값이 바뀔 때도 호출될 수 있다. 여기에 무거운 메시 재생성을 넣으면 BP 액터를 조금 움직일 때마다 렉이 크게 발생한다.
지금 단계에서는 CallInEditor 버튼으로 필요할 때만 재생성하는 방식이 더 안전하다.
UFUNCTION(CallInEditor, Category = "Voxel")
void RebuildChunk();