유니티 이벤트 함수
함수명 | 설명 |
Awake | - 스크립트가 실행될 때 한 번만 호출 - 스크립트가 비활성화되어 있어도 실행 - 코루틴으로 실행 불가 - 게임의 상태, 변수의 초기화에 사용 |
Start | - 모든 Awake가 실행된 이후 호출 - 코루틴으로 실행 가능 |
Update | - 프레임마다 호출되는 함수 |
LateUpdate | - 모든 Update가 실행된 이후 호출 - Update 함수에서 전처리가 끝난 후 실행하는 로직을 담당 |
FixedUpdate | - 물리 엔진의 시뮬레이션 계산 주기(0.02초)로 실행 |
OnEnable | - 게임 오브젝트, 스크립트가 활성화됐을 때 실행 - 코루틴 사용 불가 |
OnDisable | - 게임 오브젝트, 스크립트가 비활성화됐을 때 실행 - 코루틴 사용 불가 |
OnGUI | - 레거시 GUI 관련 함수를 사용할 때 활용 |
GetAxis와 GetAxisRaw
GetAxis
: -1.0f ~ 1.0f 사이의 연속적인 값을 반환
GetAxisRaw
: -1.0f, 0.0f, 1.0f의 세 가지 값만 반환
Vector3 구조체
속성 | 설명 |
magnitude | 벡터의 길이 |
sqrMagnitude | 벡터의 길이의 제곱 |
normalized | 크기가 1인 벡터, 정규화 벡터 |
컴포넌트 캐시 처리
private Transform tr;
void Awake()
{
tr = Getcomponent<Transform>();
}
void Update()
{
// transform.position += Vector3.forward * 1;
tr.position += Vector3.forward * 1;
}
프레임마다 호출되는 Update에서 매번 컴포넌트에 접근하는 방식은 성능 최적화에 좋지 않다. 미리 컴포넌트를 초기화한 후 변수로서 활용하는 것이 바람직하다.
이동, 회전
Translate
void Translate(Vector3 direction, [Space relativeTo]);
// moveDir 방향으로 moveSpeed 속도로 초당 이동
tr.Translate(moveDir.normalized * moveSpeed * Time.deltaTime);
[Space relativeTo]는 Space.Self 혹은 Space.World를 인자로 전달하여 로컬과 월드 기준 이동을 선택할 수 있다. 기본적으로는 로컬 좌표를 기준으로 이동한다.
Rotate
void Rotate(Vector3 eulerAngles, [Space relativeTo]);
void Rotate(float xAngle, float yAngle, float zAngle, [Space relativeTo]);
void Rotate(Vector3 axis, float angle, [Space relativeTo]);
// Vector3.up 축을 기준으로 rotationDir 방향으로 turnSpeed 속도로 초당 회전
tr.Rotate(Vector3.up * turnSpeed * Time.deltaTime * rotationDir);
애니메이션
애니메이션 타입
AnimationType | 설명 |
None | 애니메이션을 사용하지 않는다 |
Legacy | 하위 호환성을 유지하기 위한 이전 방식의 애니메이션. |
Generic | 메카님 애니메이션. 인체형 모델이 아닌 3D 모델에 적용. 리타게팅할 수 없음. |
Humanoid | 메카님 애니메이션. 리타게팅이 가능하며, 사람과 같이 2족 보행하는 모델에 적용. |
레거시 애니메이션 : 하위 호환성을 고려한 애니메이션. 소스 코드로 컨트롤해야 함
메카님 애니메이션 : 모션 캡처 애니메이션, 리타게팅 기능
레거시는 이전 기능이므로 사용을 지양하는 것이 좋다고 한다.
Animation은 Legacy를 위한 컴포넌트이고, Animator는 Mechanim을 위한 컴포넌트이다.
Legacy는 모델링에 포함된 애니메이션을 활용하며, Mechanim은 분리된 애니메이션을 모델에 적용하여 사용한다.
Legacy 소스코드
void Start()
{
anim = GetComponent<Animation>();
}
void Play()
{
anim.Play("Idle");
}
void BlendingPlay()
{
// Run 애니메이션을 0.25초의 보간과정을 거치면서 재생
anim.CrossFade("Run", 0.25f);
}
그림자
그림자 종류
Shadow Type | 설명 |
No Shadows | 그림자를 적용하지 않는다 |
Hard Shadows | 그림자를 표현하지만, 외곽선에 계단 현상이 발생한다 |
Soft Shadows | 그림자를 표현하지만, 가장 많은 부하를 준다 |
Cast Shadows
Cast Shadows Type | 설명 |
Off | 그림자를 만들지 않는다 |
On | 그림자를 만든다 |
Two Sided | 백 페이스 컬링을 무시하고 그림자를 양면으로 만든다 |
Shadows Only | 그림자를 만들지만, 자신은 렌더링하지 않는다 |
Two Sided는 Plane, Quad처럼 단면만 렌더링하는 모델에 유용하다.
Receive Shadows
: 다른 그림자에 들어갔을 때 표면에 그림자의 영향을 받는지에 대한 여부.
해당 옵션을 비활성화하면, 파라솔 밑에 사람이 누워있을 때 파라솔의 그림자가 사람 위에 그려지지 않는다.
Level Of Detail
LOD
화면을 렌더링하는 카메라로부터 멀리 떨어질수록 낮은 폴리곤으로 변경해 렌더링 부하를 줄여주는 기법이다.
LOD Group 컴포넌트
[Component] →[Rendering] → [LOD Group]으로 추가한다.
LOD 구간별 메시를 드래그 앤드 드롭으로 할당하면 각 LOD 구간마다 할당된 메시가 렌더링된다.
Follow Camera 로직
LateUpdate
void LateUpdate()
{
// 추적해야 할 대상의 뒤쪽으로 distance만큼 이동
// 높이를 height만큼 이동
camTr.position = targetTr.position + (-targetTr.forward * distance) + (Vector3.up * height);
// Camera를 타겟의 피벗 좌표를 향해 회전
camTr.LookAt(targetTr.position + (targetTr.up * targetOffset);
}
만일 LateUpdate가 아니라 Update에 작성하는 경우, 플레이어의 이동 로직과 카메라의 Follow 로직의 순서가 불규칙해서 카메라가 떨리는 현상이 발생할 수 있다.
따라서, LateUpdate에 로직을 구현하여 순서를 보장해주어야 한다.
Lerp, Slerp, SmoothDamp
Lerp (선형 보간 함수)
Vector3.Lerp(시작 좌표, 종료 좌표, t);
Mathf.Lerp(시작 값, 종료 값, t);
Quaternion.Lerp(시작 각도, 종료 각도, t);
// Mathf.Lerp(0, 10, 0.8f) 8을 반환
Slerp (구면 선형 보간 함수)
Vector3.Slerp(시작 좌표, 종료 좌표, t);
Quaternion.Slerp(시작 각도, 종료 각도, t);
SmoothDamp ( 테일러 급수를 3차 항까지 전개한 지수 근사치 활용)
Vector3.SmoothDamp(
Vector3 current, // 현재 위치
Vector3 target, // 목표 위치
ref Vector3 currentVelocity, // 현재 속도
float smoothTime, // 목표 위치까지의 도달 시간
float maxSpeed, // 최대 속력 제한 값(Default : Mathf.Infinity)
float deltaTime); // 프레임 보정을 위한 델타 타임(Default : Time.deltaTime)
// 구면 선형 보간
camTr.position = Vector3.Slerp(camTr.position, pos, Time.deltaTime * damping);
// SmoothDamp
Vector3 velocity = Vector3.zero;
float damping = 0.1f;
camTr.position = Vector3.SmoothDamp(camTr.position, pos, ref velocity, damping);
선형, 구면 선형 같은 경우에는 damping이 클수록 반응속도가 빠르지만, SmoothDamp에서는 목표 지점까지의 걸리는 시간으로 작용하기 때문에 damping 값이 작을수록 반응속도가 빠르다.
ref 키워드는 변수를 참조로 전달하겠다는 의미로서 SmoothDamp의 다른 인자 값에 따라 현재 속도가 정해지면 velocity에 속도 값이 할당이 된다.
ref는 쓰기 작업을 하지 않아도 된다. 다만, 읽기 작업이 발생하기 때문에 사전에 변수가 초기화되어 있어야 한다.out은 함수 내부에서 반드시 쓰기 작업을 진행해야 한다. 따라서, 초기화가 되지 않은 변수를 넘겨주어도 에러가 발생하지 않는다.
느낀 점
컴포넌트 캐시 처리가 다소 흥미롭게 다가왔던 것 같아요. 지금까지는 Update에서 transform에 직접 접근하는 방식으로 구현했었는데, 생각해보니 컴포넌트에 접근하는 데에도 비용이 소모될 것을 고려하면 미리 선언을 해두는 방식이 최적화에 확실히 도움이 될 것 같습니다.
아직 4장이라 익숙한 부분들이 많지만, 독학하면서 놓친 것들이 여럿 눈에 보이네요. 이런 사소한 디테일까지 학습할 수 있어서 매우 도움이 됩니다.
'유니티 > [서적] 절대강좌 유니티' 카테고리의 다른 글
[절대강좌 유니티] 01. 텍스처 및 머티리얼, 조명 (0) | 2025.02.07 |
---|