사전 스키닝 메시 렌더러
인터페이스

스키닝 메시 렌더러

gabury1고친 사람 github-actions[bot]

스키닝 메시 렌더러는 Unity 엔진에서 움직이는 캐릭터의 겉모습을 그려 주는 부품입니다. 캐릭터 안에는 화면에 안 보이는 뼈대가 있습니다. 이 렌더러는 뼈대가 움직인 만큼 겉모습을 휘게 한 뒤 화면에 그립니다. 걷는 사람이나 날개를 퍼덕이는 새처럼 모양이 바뀌는 물체에 붙습니다.

쉽고 빠른 이해

무슨 일을 하는 물건인가 — 뼈대를 따라 휘는 캐릭터를 그립니다. 캐릭터가 팔을 들면 팔을 덮은 겉면이 함께 올라간 모습으로 그려집니다.

왜 이렇게 하나 — 가만히 있는 물체를 그리는 렌더러는 모양이 늘 같다고 보고 그립니다. 움직이는 캐릭터는 화면을 새로 그릴 때마다 겉면을 다시 휘어야 합니다. 그래서 이 일을 맡는 렌더러를 따로 둡니다.

어떻게 도나

  1. 애니메이션이 뼈대의 자세를 바꿉니다
  2. 렌더러가 뼈들의 새 자세를 모아 겉면의 점들을 옮깁니다
  3. 옮긴 겉면을 화면에 그립니다

대가 — 화면을 그릴 때마다 겉면의 점을 전부 다시 계산합니다. 가만히 있는 물체보다 비쌉니다. 그래서 캐릭터가 화면 밖이면 계산을 건너뜁니다. 화면 밖인지는 미리 정해 둔 상자로 판정합니다. 팔이 그 상자 밖으로 뻗으면 판정이 틀려 캐릭터가 화면 끝에서 사라집니다.

상세

이 절은 먼저 스키닝 메시 렌더러가 무엇을 받아 무엇을 그리는지를 잡습니다. 그 바탕이 되는 Unity 의 부품 조립 방식과 스키닝 계산을 짧게 풉니다. 이어서 캐릭터 하나를 놓고 렌더러가 무엇을 쥐는지와 한 프레임에 무엇을 하는지를 따라갑니다. 끝에서는 화면 밖 판정, 표정 같은 모양 바꾸기, 코드에서 다루는 법, 비용을 봅니다.

그리는 물건과 받는 것

Unity 는 게임을 만드는 엔진입니다. 그 안에서 화면에 무언가를 그리는 부품을 렌더러라고 부릅니다. 스키닝 메시 렌더러는 그중 모양이 바뀌는 물체를 맡는 렌더러입니다.

받는 것은 셋입니다. 그릴 겉면, 그 겉면을 끌고 다닐 뼈들, 겉면에 입힐 재질입니다. 내놓는 것은 뼈들의 지금 자세대로 휜 겉면이 그려진 화면입니다.

게임은 화면 한 장을 그리고 다음 장을 그리기를 1초에 수십 번 되풀이합니다. 그 한 장을 프레임이라고 부릅니다. 스키닝 메시 렌더러는 이 일을 프레임마다 새로 합니다. 캐릭터의 자세가 프레임마다 바뀌기 때문입니다.

Unity 는 모양이 바뀌는 모형을 장면에 넣으면 이 렌더러를 알아서 붙여 줍니다. 그래서 개발자가 손으로 붙이는 일은 드뭅니다. 대개는 이미 붙어 있는 것을 찾아 설정을 바꾸거나 코드에서 값을 읽습니다.

게임 오브젝트에 붙이는 컴포넌트

Unity 의 장면은 게임 오브젝트들로 이루어집니다. 게임 오브젝트는 장면 안의 물체 하나입니다. 그 자체로는 이름과 위치만 가진 빈 껍데기입니다.

물체가 할 일은 컴포넌트를 붙여서 정합니다. 컴포넌트는 기능 하나를 맡는 부품입니다. 그리는 컴포넌트를 붙이면 보입니다. 충돌을 맡는 컴포넌트를 붙이면 부딪힙니다.

기능을 상속으로 쌓지 않고 부품으로 골라 끼우는 방식입니다. 그래서 같은 컴포넌트를 성격이 다른 물체 여럿에 붙일 수 있습니다.

모든 게임 오브젝트에는 트랜스폼이라는 컴포넌트가 하나씩 붙어 있습니다. 트랜스폼은 그 물체의 위치·회전·크기를 담습니다. 게임 오브젝트끼리 부모와 자식으로 이어지면 자식의 트랜스폼은 부모를 따라 움직입니다.

스키닝 메시 렌더러도 이런 컴포넌트 하나입니다. Unity 의 스크립트 언어인 C 에서는 SkinnedMeshRenderer 라는 클래스로 보입니다. 이 클래스는 모든 렌더러의 공통 부모인 Renderer 를 물려받습니다.

스키닝 계산

3차원 물체의 겉면은 작은 삼각형 수천에서 수만 개를 이어 붙여 만듭니다. 이 삼각형 묶음이 메시입니다.

삼각형 모서리가 만나는 점은 꼭짓점입니다. 그래픽스에서는 같은 점을 정점이라고도 부릅니다. 겉면을 휘게 한다는 말은 이 꼭짓점들을 옮긴다는 말입니다.

캐릭터 안에는 화면에 안 그려지는 뼈대가 따로 있습니다. 이 뼈대를 스켈레톤이라고도 부릅니다. 뼈대를 움직이면 겉면의 꼭짓점이 따라 움직여야 합니다.

그래서 꼭짓점마다 어느 뼈를 얼마나 따라갈지 미리 적어 둡니다. 뼈가 움직이면 그 비율대로 꼭짓점을 옮깁니다. 이 계산이 스키닝입니다.

얼마나 따라갈지를 적은 수를 가중치라고 부릅니다. 팔꿈치 둘레의 꼭짓점은 위팔 뼈와 아래팔 뼈를 반씩 따라가는 식입니다. 그래서 팔을 굽히면 팔꿈치 살갗이 그 중간쯤으로 접힙니다.

스키닝 메시 렌더러의 「스키닝」이 이 계산입니다. 뼈대의 자세를 프레임마다 정하는 일은 스켈레탈 애니메이션이 맡습니다. 렌더러는 정해진 자세를 받아 겉면에 옮기고 그리는 일을 맡습니다.

가만히 있는 물체의 렌더러와 비교

모양이 안 바뀌는 물체는 다른 두 컴포넌트로 그립니다. 메시 필터가 메시를 쥡니다. 메시 렌더러가 그 메시를 그립니다. 바위나 벽처럼 전체가 함께 옮겨질 뿐 휘지 않는 물체가 여기에 듭니다.

이 둘로는 캐릭터를 못 그립니다. 메시 렌더러는 받은 메시의 모양을 바꾸지 않고 그리기 때문입니다. 물체 전체가 옮겨지거나 돌 수는 있지만 팔만 따로 굽힐 수는 없습니다.

메시 렌더러 스키닝 메시 렌더러
메시를 쥐는 곳 옆에 붙은 메시 필터 자기 자신
뼈 없다 뼈 목록을 쥔다
매 프레임 꼭짓점 계산 없다 스키닝을 돌린다
화면 밖 판정에 쓰는 상자 메시에서 바로 구한다 따로 정해 둔 상자를 쓴다

표의 둘째와 셋째 줄이 스키닝 메시 렌더러가 따로 있는 이유입니다. 마지막 줄은 아래 「화면 밖 판정과 바운드」 소절에서 다시 봅니다.

캐릭터 하나의 짜임

사람 캐릭터 모형을 Unity 장면에 넣었다고 해 보겠습니다. 맨 위에 캐릭터 이름의 게임 오브젝트가 하나 생깁니다. 그 아래에 두 갈래가 매달립니다.

한 갈래는 뼈대입니다. 뼈 하나하나가 각각 게임 오브젝트입니다. 뼈를 움직인다는 말은 그 게임 오브젝트의 트랜스폼을 바꾼다는 말입니다.

뼈들은 부모와 자식으로 이어집니다. 맨 위 뼈인 골반을 루트 뼈라고 부릅니다. 골반 아래에 척추가, 척추 아래에 팔이 매달립니다.

다른 갈래는 겉면입니다. 몸통 겉면을 맡은 게임 오브젝트에 스키닝 메시 렌더러가 붙어 있습니다. 이 렌더러는 뼈 게임 오브젝트들의 트랜스폼을 목록으로 가리킵니다.

flowchart TD
    C["캐릭터 · 맨 위 게임 오브젝트"]
    C --> B["몸통 겉면 · 스키닝 메시 렌더러"]
    C --> H["골반 · 루트 뼈"]
    H --> S["척추"]
    H --> L["왼허벅지"]
    S --> A["왼팔"]
    B -. 뼈 목록으로 가리킨다 .-> H
    B -.-> S
    B -.-> L
    B -.-> A

그림에서 실선은 부모와 자식 관계입니다. 점선은 렌더러가 뼈를 가리키는 관계입니다. 렌더러는 뼈를 자식으로 품지 않습니다. 뼈는 따로 매달려 있습니다. 렌더러는 그 위치를 읽어 오기만 합니다.

렌더러가 쥐는 것을 이름으로 적으면 이렇습니다.

설정 담는 것
Mesh 휘게 할 메시. 꼭짓점마다 뼈 번호와 가중치가 함께 담겨 있다
뼈 목록 메시의 뼈 번호가 가리키는 뼈 트랜스폼들
Root Bone 루트 뼈. 화면 밖 판정 상자가 이 뼈를 따라 움직인다
Materials 앞에서 말한 겉면 재질인 머티리얼. 색·질감·빛 반응을 정한다

메시 안의 꼭짓점은 「3번 뼈를 0.5 만큼」처럼 번호로만 뼈를 압니다. 그 3번이 장면의 어느 게임 오브젝트인지는 뼈 목록이 이어 줍니다. 그래서 목록의 순서가 어긋나면 팔 꼭짓점이 다리를 따라가는 식으로 모양이 엉킵니다.

한 프레임에 하는 일

프레임 한 장을 그리는 동안 스키닝 메시 렌더러는 아래 순서를 밟습니다.

flowchart TD
    A["애니메이션이 뼈 트랜스폼을 바꾼다"]
    A --> B{"판정 상자가 화면 안에 있나"}
    B -->|밖| X["이번 프레임은 스키닝을 건너뛴다"]
    B -->|안| C["뼈 목록에서 지금 자세를 모은다"]
    C --> D["꼭짓점을 가중치대로 옮긴다"]
    D --> E["머티리얼을 입혀 그린다"]

첫 단계는 렌더러의 일이 아닙니다. 애니메이션을 돌리는 컴포넌트가 뼈 게임 오브젝트를 움직여 둡니다. 렌더러는 그 결과를 읽기만 합니다. 그래서 뼈를 코드로 직접 돌려도 겉면은 똑같이 따라 휩니다.

둘째 단계가 비용을 아낍니다. 화면에 안 보이는 캐릭터의 꼭짓점을 옮겨 봐야 그릴 일이 없습니다. 판정에 쓰는 상자는 다음 소절에서 봅니다.

넷째 단계의 계산은 엔진 설정에 따라 CPU(Central Processing Unit, 중앙 처리 장치)에서 돌 수도, 그래픽 카드에서 돌 수도 있습니다. 어느 쪽에서 돌든 렌더러를 쓰는 코드는 바뀌지 않습니다.

그래픽 카드의 계산 장치를 GPU(Graphics Processing Unit, 그래픽 처리 장치)라고 부릅니다. 스키닝을 GPU 쪽으로 넘기는 방식을 GPU 스키닝이라고 부릅니다.

화면 밖 판정과 바운드

렌더러는 캐릭터를 감싸는 네모난 상자 하나로 화면 안팎을 가립니다. 이런 상자를 바운딩 박스라고 부릅니다. 스키닝 메시 렌더러의 설정에서는 Bounds 라고 적힙니다.

상자가 카메라 시야에서 완전히 벗어나면 그리지 않습니다. 시야 밖 물체를 이렇게 걸러 내는 일이 프러스텀 컬링입니다.

가만히 있는 물체는 메시에서 상자를 바로 구하면 됩니다. 캐릭터는 프레임마다 모양이 바뀌어서 상자도 바뀌어야 맞습니다. 그런데 상자를 정확히 구하려면 휜 꼭짓점이 먼저 있어야 합니다. 스키닝을 건너뛸지 정할 상자가 스키닝을 마친 뒤에야 나오는 셈입니다.

그래서 스키닝 메시 렌더러는 기본으로 미리 정해 둔 상자를 씁니다. 상자의 크기는 고정입니다. 위치만 루트 뼈를 따라 옮겨 다닙니다. 캐릭터가 팔을 크게 휘두르면 팔이 상자 밖으로 나갈 수 있습니다.

이때 문제가 납니다. 몸통은 화면 밖이고 휘두른 팔만 화면 안에 걸친 순간이 있습니다. 상자는 화면 밖이라 렌더러가 그리기를 건너뜁니다. 화면에 보여야 할 팔이 사라집니다.

손볼 길은 둘입니다. 하나는 Bounds 를 동작 전체가 들어갈 만큼 넉넉히 키우는 것입니다. 그러면 휘두른 팔도 상자 안에 들어옵니다.

다른 하나는 Update When Offscreen 을 켜는 것입니다. 켜면 화면 밖에서도 스키닝을 합니다. 상자도 프레임마다 다시 구합니다. 판정은 정확해집니다.

대신 안 보이는 캐릭터에도 계산을 치릅니다. 이 설정이 기본으로 꺼져 있는 까닭이 그 비용입니다.

블렌드 셰이프 — 뼈 없이 모양 바꾸기

얼굴 표정은 뼈만으로 만들기 어렵습니다. 입꼬리나 눈썹은 움직이는 점이 촘촘하고 모양이 미묘하기 때문입니다. 그래서 표정은 다른 방식으로 만듭니다.

미리 「웃는 얼굴」 메시를 하나 더 만들어 둡니다. 기본 얼굴과 웃는 얼굴 사이를 0에서 끝까지 비율로 섞습니다. 비율을 반만 주면 반쯤 웃는 얼굴이 됩니다. 이렇게 섞을 모양을 Unity 는 블렌드 셰이프라고 부릅니다. 다른 도구에서는 모프 타깃이라고도 부릅니다.

스키닝 메시 렌더러는 블렌드 셰이프도 맡습니다. 설정의 BlendShapes 에 모양마다 섞는 비율이 있습니다. 메시에 뼈가 하나도 없고 블렌드 셰이프만 있어도 이 렌더러로 그립니다.

코드에서 다루기

C# 스크립트에서는 같은 게임 오브젝트에 붙은 렌더러를 찾아 값을 읽고 바꿉니다. 아래 예는 뼈 65개와 블렌드 셰이프 2개를 가진 얼굴 모형을 놓고 씁니다.

csharp
var r = GetComponent<SkinnedMeshRenderer>();
int bones = r.bones.Length;   // 65
var m = r.sharedMesh;
int shapes = m.blendShapeCount; // 2
r.SetBlendShapeWeight(0, 100f);
float w = r.GetBlendShapeWeight(0); // 100

첫 줄은 이 게임 오브젝트에 붙은 스키닝 메시 렌더러를 찾습니다. bones 는 앞에서 본 뼈 목록입니다. sharedMesh 는 휘게 할 메시입니다. 둘째와 넷째 줄은 그 개수를 읽습니다.

다섯째 줄은 0번 블렌드 셰이프의 비율을 100 으로 올립니다. Unity 에서 이 비율이 0 이면 기본 모양입니다. 100 이면 끝까지 섞은 모양입니다. 마지막 줄은 바꾼 값을 다시 읽어 확인합니다.

BakeMesh 라는 메서드도 있습니다. 지금 프레임에 휜 모양을 새 메시 하나에 복사해 둡니다. 움직이는 캐릭터의 한순간을 멈춘 조각상으로 남기거나 잔상을 그릴 때 씁니다.

비용과 줄이는 설정

스키닝 메시 렌더러의 비용은 꼭짓점 수에 비례합니다. 프레임마다 꼭짓점 하나하나를 뼈 몇 개씩 따라 옮기기 때문입니다. 캐릭터가 많이 나오는 장면일수록 이 계산이 쌓입니다.

비용을 다루는 설정은 아래와 같습니다.

설정 하는 일 내주는 것
Quality 꼭짓점마다 따라갈 뼈 수의 상한을 낮춘다 관절 둘레가 덜 매끄럽게 휠 수 있다
Update When Offscreen 꺼 두면 화면 밖에서 스키닝을 건너뛴다 판정 상자가 작으면 캐릭터가 사라진다
Bounds 화면 밖 판정 상자의 크기를 정한다 너무 크면 안 보이는 캐릭터도 계산한다

Quality 는 낮추는 쪽으로만 듣습니다. 꼭짓점마다 따라갈 뼈 수의 상한은 모형을 불러올 때 먼저 정해집니다. 이 설정은 그 값 아래로만 줄일 수 있습니다.

멀리 있는 캐릭터에 꼭짓점이 적은 메시를 바꿔 끼우는 레벨 오브 디테일도 함께 씁니다. 꼭짓점 수 자체를 줄이는 방법이라 위 설정들과 따로 듣습니다.

쓰는 물체와 안 쓰는 물체

뼈대를 따라 휘어야 하는 물체면 스키닝 메시 렌더러를 씁니다. 사람·동물 캐릭터, 꼬리, 촉수, 휘는 나뭇가지가 그렇습니다. 블렌드 셰이프로 표정을 바꾸는 얼굴도 여기에 듭니다.

옷감도 이 렌더러로 그립니다. 옷감은 뼈 대신 물리 계산이 꼭짓점을 옮깁니다. 그렇게 옮긴 겉면을 그리는 일을 이 렌더러가 맡습니다.

모양이 안 바뀌는 물체에는 메시 필터와 메시 렌더러를 씁니다. 스키닝 메시 렌더러에 뼈 없는 메시를 넣어도 그려집니다. 다만 쓰지 않는 계산 경로를 매 프레임 지나갑니다.

마디마다 단단한 조각이 이어진 물체는 갈림길입니다. 로봇 팔처럼 조각은 휘지 않고 관절에서만 꺾이는 물체가 그렇습니다.

이때는 조각마다 메시 렌더러를 붙입니다. 그 조각을 뼈 게임 오브젝트의 자식으로 매달면 됩니다. 부모를 따라 움직이는 트랜스폼만으로 충분해서 스키닝이 필요 없습니다.

스키닝 메시 렌더러는 Unity 의 이름입니다. 다른 엔진에도 같은 일을 맡는 부품이 있습니다. Unreal Engine 에서는 스켈레탈 메시 컴포넌트가 이 일을 합니다.

관련 항목

스키닝 메시 렌더러가 돌리는 변형 계산

스키닝 · 스켈레탈 애니메이션 · 스켈레톤 · 스키닝 가중치 · 바인드 포즈 · 블렌드 셰이프

스키닝 메시 렌더러가 쥐는 데이터

메시 · 정점 · 정점 속성 · 머티리얼 · 바운딩 박스 · 트랜스폼

스키닝 메시 렌더러가 붙는 Unity 구조

Unity · 게임 오브젝트 · 컴포넌트 (게임 엔진) · 애니메이터 · C · 렌더러 (게임 엔진)

스키닝 메시 렌더러를 대신하는 렌더러와 변형 기법

메시 렌더러 · 메시 필터 · 모프 타깃 · 정점 애니메이션 텍스처 · 옷감 시뮬레이션 · 스켈레탈 메시 컴포넌트

스키닝 메시 렌더러가 그리며 거치는 처리 단계

그래픽스 파이프라인 · 정점 셰이더 · 컬링 · 프러스텀 컬링 · 드로 콜 · 모션 벡터

스키닝 메시 렌더러의 비용을 줄이는 기법

GPU 스키닝 · 레벨 오브 디테일 · 인스턴싱 · 애니메이션 컬링

스키닝 데이터를 담아 오는 파일 포맷

FBX · glTF · COLLADA · USD

스키닝 메시 렌더러가 속하는 상위 분야

게임 개발 · 그래픽스 · 렌더링 · 게임 엔진

다른 이름: Skinned Mesh Renderer · SkinnedMeshRenderer · skinned mesh renderer · 스킨드 메시 렌더러