로블록스에서 시각적으로 화려한 거대 오픈월드를 제작할 때, 가장 큰 장애물은 저사양 모바일 기기의 심각한 렉과 튕김 현상입니다. 수백 개의 고폴리곤 MeshPart가 워크스페이스에 배치되면 과도한 드로우콜(Draw Call)과 버텍스 연산으로 인해 프레임이 곤두박질치고 발열 쓰로틀링이 발생합니다.
체계적인 Level of Detail (LOD) 파이프라인을 구축하면 시각적 퀄리티를 유지하면서도 저사양 기기 호환성을 완벽히 확보할 수 있습니다. `RenderFidelity.Performance` 엔진 내장 LOD, Luau 기반의 거리별 지오메트리 스왑 매니저, 2D 빌보드 임포스터(Impostor), 그리고 StreamingEnabled 메모리 제어를 결합해 전 기기 60 FPS 방어를 달성할 수 있습니다.
1. GPU 병목의 근원: 드로우콜과 버텍스 연산 과부하
로블록스 렌더링 파이프라인의 하드웨어 한계 분석:
- 드로우콜(Draw Call) 오버헤드: 고유한 재질과 텍스처를 가진 개별 메시마다 CPU가 GPU에 그리기 명령을 전달합니다. 드로우콜이 1,500회를 넘어서면 모바일 CPU 병목으로 프레임이 급락합니다.
- 원거리 버텍스 낭비: 화면에서 고작 15픽셀을 차지하는 먼 거리의 나무에 10,000개의 삼각형 버텍스를 연산하는 것은 심각한 GPU 래스터화 자원 낭비입니다.
- 재질 전환 쓰래싱(Texture Thrashing): 텍스처 아틀라스를 사용하지 않아 재질 교체가 잦아지면 GPU 파이프라인이 정체됩니다.
- 모바일 발열 쓰로틀링: GPU 사용률이 100%에 달하면 기기가 발열을 막기 위해 5분 만에 클럭을 강제 다운시켜 60 FPS에서 20 FPS 이하로 추락합니다.
2. RenderFidelity와 로블록스 네이티브 LOD 시스템
엔진 내장 메시 간소화 기능을 극대화하는 설정법:
- `RenderFidelity.Precise`: 모든 거리에서 100% 원본 지오메트리를 유지합니다. 1인칭 손에 든 무기나 상호작용 퍼즐에는 필수적이지만, 거대 환경 프랍에 적용하면 치명적입니다.
- `RenderFidelity.Performance`: 원본의 100%, 50%, 25%, 12.5% 삼각형으로 구성된 4단계 LOD를 엔진이 자동 생성하고 화면 면적에 따라 매끄럽게 교체합니다.
- `CollisionFidelity.Box` 적용: 원거리 배경이나 작은 장식 오브젝트는 충돌 모델을 `Box`로 단순화하거나 `CanCollide`를 꺼서 CPU 물리 스레드를 해방합니다.
- 자동 메시 인스턴싱(Instancing): 동일한 크기와 재질을 공유하는 동일 MeshPart들은 최신 렌더러가 자동으로 1개의 드로우콜로 묶어 처리합니다.
--!strict
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local LODManager = {}
type LODModel = {
HighDetail: Model,
LowDetail: Model,
Impostor: BillboardGui,
Position: Vector3,
CurrentTier: number -- 1: 고화질, 2: 저폴리, 3: 2D 임포스터, 4: 완전 컬링
}
local registeredLODs: {LODModel} = {}
local DIST_HIGH_TO_LOW = 120
local DIST_LOW_TO_IMPOSTOR = 350
local DIST_CULL = 800
function LODManager.Register(high: Model, low: Model, impostor: BillboardGui, centerPos: Vector3)
table.insert(registeredLODs, {
HighDetail = high,
LowDetail = low,
Impostor = impostor,
Position = centerPos,
CurrentTier = 1
})
low.Parent = nil
impostor.Enabled = false
end
local frameCounter = 0
RunService.Heartbeat:Connect(function()
frameCounter += 1
if frameCounter % 6 ~= 0 then return end -- 6프레임마다 1회 실행 (~10Hz) CPU 절약
local camera = Workspace.CurrentCamera
if not camera then return end
local camPos = camera.CFrame.Position
for _, lod in ipairs(registeredLODs) do
local offset = lod.Position - camPos
local distSq = offset.X * offset.X + offset.Y * offset.Y + offset.Z * offset.Z
local newTier = 1
if distSq > (DIST_CULL * DIST_CULL) then
newTier = 4 -- 완전 컬링 (렌더링 제외)
elseif distSq > (DIST_LOW_TO_IMPOSTOR * DIST_LOW_TO_IMPOSTOR) then
newTier = 3 -- 2D 빌보드 임포스터
elseif distSq > (DIST_HIGH_TO_LOW * DIST_HIGH_TO_LOW) then
newTier = 2 -- 저폴리곤 메시 모델
else
newTier = 1 -- 고화질 원본 모델
end
if newTier ~= lod.CurrentTier then
lod.CurrentTier = newTier
lod.HighDetail.Parent = (newTier == 1) and Workspace or nil
lod.LowDetail.Parent = (newTier == 2) and Workspace or nil
lod.Impostor.Enabled = (newTier == 3)
end
end
end)
return LODManager
3. 빌보드 임포스터(Impostor)와 2D 스프라이트 캐싱
원거리 3D 지오메트리를 극도로 가벼운 2D 스프라이트로 교체하는 기법:
- 빌보드 임포스터 원리: 300스터드 밖의 5,000폴리곤 건물이나 나무를 1장의 2D 평면 텍스처(Quad)로 대체하여 원거리 시각차 없이 연산량을 제로화합니다.
- 극적인 폴리곤 절감: 원거리 숲의 나무 500그루를 3D 모델에서 2D BillboardGui로 교체하면 폴리곤 수가 250만 개에서 단 1,000개로 감소합니다.
- 드로우콜 압축: 임포스터에 사용되는 텍스처를 1장의 스프라이트 시트로 묶어 수백 개의 배경 오브젝트를 단 1회의 드로우콜로 렌더링합니다.
- 디더링(Dithering) 교차 전환: 3D 모델과 2D 임포스터 사이의 전환 시 깜빡임(Popping)을 방지하기 위해 디더링 투명도 페이드를 적용합니다.
4. StreamingEnabled와 메모리 경계 아키텍처
광활한 맵을 모바일 메모리에 안전하게 로드하는 스트리밍 설계:
- `StreamingMinRadius` 최소화: 모바일 기기의 스폰 초기 튕김을 막기 위해 최소 반경을 64스터드 수준으로 타이트하게 설정합니다.
- `ModelStreamingMode.Atomic`: 엘리베이터나 탑승물처럼 조각나면 물리 버그가 생기는 복합 모델은 원자 단위(Atomic)로 한꺼번에 로드되도록 강제합니다.
- `ModelStreamingMode.Persistent`: 랜드마크나 핵심 건물은 메모리에서 영구 유지(Persistent)하여 원거리 수평선이 비어 보이는 현상을 차단합니다.
- 저메모리 감지 대응: 클라이언트에서 `Workspace.LowMemory` 신호를 수신하면 파티클 생성률을 50% 깎고 임포스터 전환 거리를 단축합니다.
5. 모바일 우선 상용 프로덕션 최적화 체크리스트
부드러운 60 FPS 출시를 위한 실전 가이드라인:
- 텍스처 아틀라스 통합: 자잘한 소품 텍스처들을 1024x1024 한 장에 패킹하여 GPU 배칭 효율을 극대화합니다.
- 불필요한 CastShadow 제거: 풀잎, 자갈, 작은 쓰레기 등 미세 소품들의 `CastShadow`를 꺼서 동적 그림자 맵 연산을 경감합니다.
- 로블록스 마이크로프로파일러 검증: `RenderJob`과 `PrepareJob` 소요 시간을 확인하여 1프레임 렌더 타임이 16.6ms(60FPS) 이하를 유지하는지 확인합니다.
- 모바일 에뮬레이터 저사양 테스트: 출시 전 스튜디오의 저사양 기기 프로필에서 메모리 피크와 프레임 드랍을 철저히 검증합니다.
Frequently Asked Questions
RenderFidelity.Performance와 커스텀 Luau LOD의 차이점은 무엇인가요?
Performance는 단일 메시의 버텍스를 엔진이 자동 감축하지만, 모델 전체를 2D 빌보드로 바꾸거나 부속 파츠를 완전히 숨길 수는 없습니다. 둘을 결합해야 최대 성능을 냅니다.
배경 오브젝트의 CanCollide를 끄면 그래픽 렌더링도 빨라지나요?
네. CanCollide와 CanQuery를 끄면 물리 엔진뿐만 아니라 로블록스의 공간 파티셔닝 트리(Octree) 연산이 간소화되어 PrepareJob 렌더링 준비 단계가 대폭 단축됩니다.
모바일 환경에서 안전한 드로우콜 한계치는 얼마인가요?
일반적으로 400~800 드로우콜 이내가 안전합니다. 1,200 드로우콜을 넘어서면 보급형 안드로이드 스마트폰에서 심각한 프레임 드랍과 발열이 발생합니다.