2026-05-04 TIL (50일차)
강사님 디지털 트윈 코드 분석
빌드 파일(Build.cs)
언리얼 엔진 프로젝트의 Build.cs 파일은 프로젝트가 사용할 외부 모듈(엔진 라이브러리)을 컴파일러에게 알려주는 연결 장부 역할을 합니다. 단순히 소스 코드만 작성한다고 기능이 작동하는 것이 아니라, 해당 기능이 담긴 라이브러리를 프로젝트에 포함(Link)시켜야 하기 때문입니다.
수정이 필요한 이유
- 최적화: 엔진의 모든 기능을 넣으면 프로젝트가 무거워지므로 필요한 모듈만 골라 담습니다.
- 링킹(Linking):
#include를 하더라도 실제 라이브러리 위치를Build.cs에 명시하지 않으면 컴파일러는 코드의 실체를 찾지 못해 링크 에러를 발생시킵니다.
‘차량(Vehicle)’ 템플릿 기본 모듈
차량의 물리 엔진과 이동 로직을 사용하기 위해 필수적으로 추가해야 하는 모듈입니다.
- ChaosVehicles
- 이유: 핵심 클래스인
UChaosWheeledVehicleMovementComponent및AWheeledVehiclePawn사용을 위해 필요합니다. - 기능: 서스펜션, 타이어 마찰력, 엔진 토크 전달 등 Chaos 물리 기반 이동 로직을 제공합니다.
- 이유: 핵심 클래스인
- PhysicsCore
- 이유: Chaos 엔진이 내부적으로 충돌 검사 및 물리 재질(Physical Material)을 처리하는 하위 API를 포함합니다.
추가 모듈
단순 주행을 넘어 도로 인식, 센서 데이터 수집, 이미지 저장 등 복합적인 시스템을 위해 필요한 모듈들입니다.
A. Landscape (지형 및 도로 데이터)
- 이유:
ALandscapeSplineActor와ULandscapeSplinesComponent참조를 위해 필요합니다. - 기능: 지형 편집기에서 생성한 도로(Spline) 데이터를 가져와 차량의 자동 주행 경로를 생성합니다.
B. RenderCore & RHI (그래픽 및 픽셀 처리)
- RenderCore: 렌더 타겟 리소스에 접근하여 화면의 픽셀 데이터(
ReadPixels)를 읽어오는 작업을 수행합니다. - RHI (Render Hardware Interface): 라이다(LiDAR) 데이터를 화면에 실시간으로 뿌리기 위해 GPU 메모리의 텍스처 영역을 직접 수정하는 하위 수준의 접근을 제공합니다.
C. ImageWrapper (데이터 저장)
- 이유: 메모리에 있는 생(Raw) 데이터를 이미지 파일로 변환하기 위해 필요합니다.
- 기능: 픽셀 데이터를 JPEG 포맷으로 압축하고 하드디스크에 파일로 저장하는 기능을 제공합니다.
정리
| 추가 모듈 | 사용된 핵심 클래스/기능 | 추가 목적 |
|---|---|---|
| ChaosVehicles | AWheeledVehiclePawn | 차량의 물리적 이동 및 제어 |
| Landscape | ULandscapeSplinesComponent | 도로 데이터를 읽어와 자동 주행 경로 생성 |
| RenderCore | ReadPixels | 카메라 센서 화면에서 이미지 데이터 추출 |
| RHI | UpdateTextureRegions | 라이다 데이터를 동적 텍스처로 실시간 렌더링 |
| ImageWrapper | IImageWrapperModule | 캡처한 데이터를 JPG 이미지 파일로 변환 및 저장 |
결론: 도로를 인식(Landscape)하고, 센서를 분석(RenderCore/RHI)하며, 이를 기록(ImageWrapper)하는 시뮬레이션 시스템이기 때문에 위와 같은 모듈 설정이 필요합니다.
차량 메인 클래스
1. 생성자
차량의 기본 뼈대를 구성하며, 물리 연산의 핵심인 이동 컴포넌트를 할당합니다.
- ChaosVehicleMovement: 차량의 물리적 거동(엔진, 변속기, 서스펜션 등)을 담당하는 컴포넌트로, 부모 클래스에서 할당받아 사용합니다.
2. SetupPlayerInputComponent
사용자의 입력(Input Action, IA)과 실제 실행될 C++ 함수를 연결하는 함수입니다.
- 입력 받은 명령(IA)을 특정 함수에 바인딩(Binding)하여, 플레이어가 키를 누를 때마다 정해진 로직이 실행되도록 설정합니다.
3. BeginPlay & EndPlay
차량의 상태를 주기적으로 체크하고 리소스를 관리합니다.
- BeginPlay:
SetTimer를 사용하여 3초마다FlippedCheck함수를 무한 반복 호출합니다. - EndPlay: 객체가 소멸될 때
ClearTimer를 호출하여 실행 중인 타이머를 종료하고 메모리 및 성능 낭비를 방지합니다.
4. Tick
물리 보정과 카메라 연출을 위해 매 프레임마다 두 가지 핵심 로직을 수행합니다.
물리 및 마찰력 보정 (Physics Damping)
- 상태 확인:
ChaosVehicleMovement->IsMovingOnGround()를 통해 차량이 현재 지면에 닿아 있는지 bool값으로 확인합니다. - 공기 마찰력 설정:
GetMesh()로 스켈레탈 메쉬를 가져와SetAngularDamping(공기 마찰력) 값을 조절합니다.- 공중에 있을 때: 값을 높게 설정하여 바퀴가 공중에서 비정상적으로 빠르게 헛도는 것을 방지합니다.
- 땅에 있을 때: 마찰력을 낮게 돌려주어 정상적인 주행과 회전이 가능하게 합니다.
- 즉, 공기마찰력이 크면 가기 힘든거 처럼 바퀴를 못움직이게 한다
카메라 정면 복원 (Camera Interpolation)
- 회전 보간: 스프링암(SpringArm)의 상대적인 Yaw 값을 체크합니다. (Yaw 0 = 차량 정면).
- 부드러운 화면 돌리기: 현재 Yaw 값을 프레임당 일정 수치만큼 0으로 보간(Interpolation)하여, 사용자가 조작하지 않을 때 카메라가 서서히 차량 정면을 바라보게 구현되었습니다.
- 좌표 갱신: 보간된 값을
SetRelativeRotation으로 갱신하여 부드러운 카메라 워킹을 완성합니다.
5. DoSteering
SetSteeringInput- 의미: 스티어링 휠/핸들 입력값을 설정합니다.
- 기능 (역할): 차량의 바퀴(주로 앞바퀴)를 좌우로 회전시킵니다.
- 입력값의 범위: 일반적으로 -1.0(왼쪽 최대) ~ 1.0(오른쪽 최대) 사이의 값을 받습니다.
0.0이 들어오면 핸들을 꺾지 않은 정면 상태를 유지합니다.
6. DoThrottle & DoBrake
공통으로 사용되는 함수
SetThrottleInput- 의미: 스로틀(가속 페달/엑셀) 입력값을 설정합니다.
- 기능 (역할): 차량 엔진에 연료를 주입하여 가속력을 발생시킵니다. 값이 커질수록 엔진 RPM이 상승하고, 기어 변속 시스템과 연동되어 바퀴에 더 큰 토크(회전력)를 전달합니다.
- 입력값의 범위: 일반적으로 0.0(가속 안 함) ~ 1.0(최대로 밟음) 사이의 값을 받습니다.
SetBrakeInput(float BrakeValue)- 의미: 브레이크(제동 페달) 입력값을 설정합니다.
- 기능 (역할): 차량의 바퀴에 물리적인 마찰(제동력)을 가해 속도를 줄이거나 멈추게 합니다.
- 입력값의 범위: 일반적으로 0.0(브레이크 안 밟음) ~ 1.0(풀 브레이크) 사이의 값을 받습니다.
각 함수 역할
- DoThrottle:
SetThrottleInput으로 엔진을 돌림과 동시에,SetBrakeInput(0.0f)을 호출하여 제동력을 강제로 0으로 만듭니다. - DoBrake:
SetBrakeInput으로 마찰을 발생시킴과 동시에,SetThrottleInput(0.0f)을 호출하여 엔진의 가속력을 강제로 차단합니다.
7. DoResetVehicle
차량이 전복되거나 지형에 갇혔을 때, 차량의 위치와 상태를 초기화하는 함수입니다.
위치 및 회전 초기화
- 공중 부양: 바퀴가 땅에 파묻히는 버그를 막기 위해, 그 자리에서 공중으로 살짝 띄워줍니다.
- 수평 맞추기: 현재 차량이 바라보는 방향(Yaw)은 그대로 유지한 채, 차가 앞뒤로 쏠린 각도(Pitch)와 뒤집힌 각도(Roll)만
0.0f로 강제 초기화하여 차를 똑바로 세웁니다.
물리적 텔레포트 적용
- 위에서 계산한 새로운 위치와 회전값을 차량에 최종 적용하여 순간이동시킵니다.
- 이때
ETeleportType::TeleportPhysics를 사용하여 일반적인 이동이 아닌 ‘물리적 텔레포트’임을 엔진에 알립니다. 차가 순간이동하는 궤적 사이에 있는 물체들과 충돌하지 않도록 물리 엔진을 잠깐 끄고 안전하게 옮겨줍니다.
잔여 관성 제거 (ZeroVector 적용)
차량 스켈레탈 메쉬에 아래 두 함수를 사용하여 FVector::ZeroVector(0,0,0)을 대입합니다. 단순히 위치만 바꾼다고 차가 멈추는 것이 아니기 때문에, 남아있는 물리적 힘을 완전히 지워주는 안전장치입니다.
SetPhysicsLinearVelocity(선속도 / 이동 속도 설정)- 무엇을 Set 하나요? 물체가 ‘직선 방향으로 날아가거나 이동하는 속도’를 설정합니다.
- 단위: cm/s (초당 센티미터)
- 기능: 물체가 X, Y, Z축 방향으로 얼마나 빠르게 뻗어나갈지 결정합니다.
- 차량 리셋 함수에서의 의미: 차가 절벽을 향해 돌진하고 있었다면, 리셋 후에도 허공에서 계속 앞으로 날아갈 것입니다. 이를 0으로 만들어 이동 속도와 관성을 0으로 만들어서 멈추게 합니다.
SetPhysicsAngularVelocityInDegrees(각속도 / 회전 속도 설정)- 무엇을 Set 하나요? 물체가 ‘제자리에서 빙글빙글 도는 회전 속도’를 설정합니다.
- 단위: Degrees/s (초당 각도)
- 기능: 물체가 각 축을 기준으로 1초에 몇 도나 회전할지 결정합니다.
- 차량 리셋 함수에서의 의미: 차가 절벽에서 떨어지면서 팽이처럼 빙글빙글 돌고 있었다면, 리셋 후에도 계속 돌려고 할 것입니다. 이를 0으로 만들어 회전 관성을 0으로해서 멈추게 합니다.
8. FlippedCheck
벡터의 내적 (Dot Product)
FVector::UpVector: 월드(지구)의 절대적인 위쪽 방향(하늘)을 가리키는 고정된 화살표(0, 0, 1)입니다.GetMesh()->GetUpVector(): 자동차 지붕에서 뻗어 나가는 자동차 기준의 위쪽 방향 화살표입니다.- 내적(Dot Product)의 성질
- 두 화살표(방향 벡터)를 내적하면, 두 화살표가 이루는 각도에 따라
1.0에서-1.0사이의 수치가 나옵니다. 1.0: 차가 평지에 똑바로 서 있음 (두 화살표가 완벽히 같은 곳을 봄, $0^\circ$)0.0: 차가 옆으로 완전히 누워 있음 (두 화살표가 수직임, $90^\circ$)-1.0: 차가 배를 까고 완전히 뒤집혀 있음 (두 화살표가 정반대를 봄, $180^\circ$)
- 두 화살표(방향 벡터)를 내적하면, 두 화살표가 이루는 각도에 따라
- 1단계: 1차 검사 현재 계산된 내적 값이 설정해 둔 최소 허용치보다 낮아지면(차가 크게 기울어지면), 상태를 기억하는
bool값을true로 변경합니다. - 2단계: 유예 및 2차 검사 3초 뒤에 다시 검사했을 때도 여전히 내적 값이 허용치보다 낮다면(같은 결과가 나오면), 일시적인 기울어짐이 아니라 완전히 전복된 것으로 확정합니다.
- 3단계: 초기화 실행 (리셋) 최종 전복 판정이 나면 즉시
DoResetVehicle()함수를 호출하여 차량의 위치와 상태를 정상으로 초기화시킵니다.
9. DoToggleSensorView
이 함수는 차량 카메라 센서가 찍고 있는 영상 데이터를 추출하여, 화면에 띄울 수 있도록 PlayerController에게 전달해 주는 역할을 합니다.
CamRT (Render Target 2D): 언리얼 엔진에서 렌더 타겟은 ‘실시간으로 그림이 그려지는 디지털 도화지’입니다. 차량 앞의 카메라 센서(CameraSensor)가 바깥 풍경을 찍으면 그 영상이 이 CamRT라는 도화지에 실시간으로 그려집니다.
CamRT 변수 사용이유
카메라 센서가 본 것을 우리가 보는 모니터(UI 위젯)에 띄우려면, 영상 데이터를 이미지(텍스처) 형태로 변환해야 합니다. RenderTarget이 그 역할을 합니다.
카메라가 렌더 타겟에 영상을 쏘면, UI는 그 렌더 타겟을 사진처럼 화면에 붙여서 보여주는 방식입니다.
10.DoToggleLidarView
자율주행 차량의 라이다(Lidar) 센서 화면을 켜고 끄는 역할을 수행합니다.
- LidarRT (라이다 화면): 카메라와 달리 GetBevRenderTarget()이라는 전용 함수를 사용합니다.
- BEV (Bird’s Eye View): ‘새의 시선’, 즉 위에서 아래로 내려다본 탑다운 평면도를 의미합니다.
- 라이다 센서가 사방으로 레이저를 쏴서 수집한 수백만 개의 점(Point Cloud) 데이터를, 위에서 내려다본 2D 텍스처(지도)로 구워낸 결과물이 바로 LidarRT입니다.
11. 기타 함수 (미사용 및 특수 용도)
- LookAround / ToggleCamera 계열: 현재 실제 로직에서 사용되지 않는 함수로 추측됩니다.
- DoBrakeStart / Stop: C++ 보다는 블루프린트에서 브레이크 등 점등과 같은 시각적 연출을 위해 구현된 것으로 보입니다.
- DoHandbrakeStart / Stop: 사이드 브레이크 기능으로, 향후 더 정교한 자율주행 알고리즘이나 드리프트 기능을 위해 남겨놓은 함수로 판단됩니다.