Publish:

태그: ,

카테고리:

▶️영상 링크
5월 17일 오후 4시! 알쓸유잡 : 야 너두 쉐이더 개발할 수 있어!
셰이더에 관심이 생겼을 무렵 때맞춰 업로드 된 영상! 유익한 시청시간이었다!

  • 렌더링 파이프라인
    • Graphics API
    • GPU vs CPU
    • 배칭(Batching) vs 인스턴싱 (Instancing)
    • 메터리얼 & 쉐이더
    • 쉐이더 : 버텍스, 프래그먼트…
  • 수학
    • 삼각함수
    • 벡터
  1. 렌더링 파이프라인
    • 셰이더 : gpu가 사용하는 컴터 프로그램이다?!

Auto Graphics APIs → 체크를 풀면 선택해서 빌드할 수 있음

근데 체크를 하면 빌드할 때 벌칸것도 빌드하고 오픈지엘도 빌드하고… 패키지양이 늘어날 수 있음

셰이더의 바이너리가 다르기 때문에… 패키지 용량을 줄이고 싶으면 오토 체크 풀어야 함.

우리가 보는 메쉬는 버텍스에서 시작한다!

정점 = 버텍스

(버텍스)점이 모여 선(엣지)이 되고, 선이 모여 면(폴리곤)이 되고, 면이 모여 메쉬가 되는 것.

씬에 올려 두기전엔 비행기 오브젝트는 모델 스페이스 (형태를 구성하기 위한 버텍스 정보만) 있음.

근데 씬에 올리면, 트랜스폼이 바뀜. 공간에 놓이게 되면서 모델 스페이스에 있던 정보를 월드 공간에 있는 상대적 좌표로 변환함.- > 월드 트렌스폼

씬에 올리게 되면 카메라를 통해 보기 땜ㄴ에

카메라기준으로 변환을 다시 구성 → 뷰 스페이스, 뷰 트렌스폼

클립 스페이스 : 결국 우리가 보게 되는 건 원근법이 적용된 오브젝트의 모습… 프로젝션. Projection

시야가 뻗어나가는 거 : 시야 절두체

퍼스펙티브 카메라 ! perspective camera : frustum (모든걸 그릴 수 없으므로 한정된 공ㅇ간에 있는것만 그려냄)

아무튼,

World - View - Projection Transform 이 모여 하나의 행렬을 이루게 됨. 변환이 이뤄짐.

줄여서 WVP

이 변환은 버텍스 쉐이더에서 이뤄지게 됨.

//———-

메쉬를 어떤 형태로 설명하게 되는데, GPU 입장에선 그냥 데이터일 뿐이다.

버텍스 버퍼, 인덱스 버퍼 등등 데이터로 이루어져 있음.

버텍스 버퍼 - 버텍스 정보를 담는 버퍼. 사각형 하나를 그린다면

ㅇ ㅇ

ㅇ ㅇ 이렇게 그리므로 4개인데. 사각형을 삼각형 두개로 표현해서 그릴거임.

삼각형 그리는 순서를 정의해주는 게 인덱스 버퍼.

1ㅇ ㅇ0 이렇게 있을 때, 인덱스 버퍼엔 012230 으로 정의된다. 삼각형을 어떻게 그려줄지 순서.

2ㅇ ㅇ3

그리고 Render State

그런데 면이 시계방향인지, 반시계 방향인지도 고려해야 함.

어떤 도형이 있을 때 앞면만 그리면 되는데, 앞 면을 표현하려고 삼각형을 그리려고 할 때 시계방향 순서가 앞면인지 반시계 방향 순서가 앞면인지 정보가 필요.

counter clocwise ccw 반시계방향

clockwise 시계방향 cw

cw 인지 ccw 인지에 따라서 앞면을 컬링할건지 말건지도 중요. 픽셀 처리 자원 낭비 줄일 수 있음 버텍스 생성 줄일 수 있음

Vertex Decl 버텍스 디클러레이션

지피유에게 버텍스는 데이터 덩어리… 지피유가 어떻게 나눠서 분석해야 하는지, 버텍스가 어떤식으로 구성되어 있는지 정의되있는 게 필요.

어디서부터 어디까지가 uv고 어디까지가 position인지 끊어서 분석할 수 있도록 정의해준 것

////////

우리가 Update 에서 게임 로직을 작성하면 →

본격적으로 렌더링 하기 위해 Cull 컬링을 함 (화면 안(frustum)에 들어오는 것들만 골라서 렌더링을 해야하므) →

그다음 Scene Rendering 근데 이 때 오브젝트마다 Vertex Shader→ Fragment Shader 를 거쳐서 화면에 그려주고, 다 그려지고 나면 →

최종적으로 Post Processing 을 거쳐 화면에 표시를 함

그런데 화면에 표시를 할 때 Buffer 가 있음.

씬 렌더링 할 때, 화면에 하나하나 그리는 과정을 하나하나 보여주면 화면이 울렁거리는 느낌이 있음. 그래서 지피유가 오브젝트를 하나하나 그릴 때 마다 디스플레이에 바로 쏘는게 아니라 버퍼를 가져서 미리 담아두고 있음. 이걸 Back Buffer 라고 함.

그래서 한 프레임 끝나면 이걸 Front Buffer 로 올려준다.

무대가 Front Stage, Back Stage 가 있는 것과 같은 개념. (대기 하고 있다가 앞무대로 등장하는 것)

이후 Front Buffer 에 있던건 다시 Back Buffer 로 돌아오고, 이 과정을 계속 거쳐서 화면에 표시되는 것.

이 과정을 Rendering Loop 라고 한다.

//////

Material ≠ Shader

셰이더는 메터리얼을 구성하는 한 요소일 뿐이고,

메터리얼은 재질을 표현하기 위한 여러 파라미터의 묶음이다.

(이 재질을 사용할 땐 어떤 셰이더를 사용해야 하는지, 어떤 컬러를 사용해야 하는지 등…

//////

  1. CPU가 먼저 데이터를 로딩하고(HD나 SSD에 있던 데이터들을),
  2. CPU 에서 사용하는 RAM 에 데이터를 담는다.
  3. 그리고나서 GPU에서 사용하는 VRAM (video RAM) 에 텍스쳐, 메쉬 같은 정보들을 넘겨준다. 그리고 RAM에서 삭제한다. (메쉬는 남김)

— Unity 에서 Read/Write Enable 이라는 옵션이 있음. 이걸 켜주면 RAM에서 지워지지 않고 계쏙 남겨둠. → 최적화와 관련되어 있는 옵션. 예쩐엔 기본적으로 켜져있었는데 메모리 이슈 때문에 요즘은 디폴트값이 off임.

  1. 그리고 GPU는 GPU 메모리(VRAM)에 있는 데이터들로 그려준다. 그런데 이 때 GPU가 VRAM에서 바로 데이터들을 가져오진 못한다. 중간에 캐싱하는 과정을 거친다.
  2. 캐시 (L1, L2)에 담겼다가 레지스터에 옮겨지고, 이후 GPU 에서 접근할 수 있다.

/////

오브젝트를 그릴 때 Render State 라는게 있따.

하나의 오브젝트를 그리기 위해선 텍스쳐를 뭘 써야 하는지, 셰이더는 뭘 써야 하는지 이런 정보가 필요하다.

이런 상태를 테이블에 저장하는데, 이게 Render State 이다.

오브젝트를 하나하나 그릴 때 마다 Render State 를 갱신하고 그리고, 갱신하고 그리는 것이다.

///

Draw Call

CPU 가 GPU 에게 그려라! 라고 하는 것이다.

이 그려라! 해서 거치는 과정이 렌더파이프라인인 것이다.

  1. 버텍스 정보들을 받아온다. (위에 말한 버텍스 디클라레이션~ 인덱스 버퍼~ 이런 정보들을 GPU가 받아들임)
  2. Transform (오브젝트를 월드스페이스로 변환하고 뷰스페이스로 변환하고… 이런 변환 과정)
  3. 버텍스 보간
  4. Create Triangles) 삼각형 생성
  5. Create Fragments 버텍스 정보를 Display 의 픽셀에 매칭시켜 주는 것 (레스터화 시킨다라기도 함)
  6. Shade Fragments (Fragment 에 셰이더 뿌리기)
  7. Output to Frame Buffer
  8. Show Frame BUffer (display 에 표시)

///////

커맨드버퍼 → 씨피유가 지피유에게 그려라! 라고 하기 위해선 커맨드버퍼가 필요함.

커맨드버퍼에 쌓아두면 지피유가 커맨드버퍼에 있는걸 순차적으로 가져와서 그리게 되는 것.

그래서 커맨드 큐 라고도 함.

커맨드 버퍼에 명령들을 쌓아놓고 , 이 커맨드버퍼는 어떤게 필요한지도 지피유램에 있는걸 가리키고 있음.

그래서 지피유가 가져와서 그릴 수 있는 거임.

이 때 너무 많은 커맨드버퍼가 쌓이게 되면 병목현상이 일어날 수 있는데,

이걸 방지하기 위해서 같은 메터리얼 이용하는 것끼리는 렌더 순서를 같이 묶어서 한꺼번에 출력하기도 한다.

메쉬는 다르더라도 메터리얼은 같다면… 걔네를 묶어서 그릴 수 있다.

//////

근데 여기서 한 발 더 나아가 배칭 이라는 개념이 있음

스태틱 배칭?

스태틱 배칭을 키면 이게 하나의 드로우콜로 처리가ㅣ 됨. 이게 무넌 의미냐면 원이 있고 , 피라미드가 있을 때 이것들을 하나하나 그리라고 명령을 날리는 게 아니라

아예 하나로 묶어서 (씨피유 메모리에서 여러 오브젝트를 하나로 만들어 지피유에 이걸 그리라고 넘김)

이러헥 하면 커맨드 버퍼가 간결해져서 드로우콜 병목현상이 줄어들 수 있음

그렇지만 그만큼 메모리를 많이 먹음

드로우콜이 중요한지, 메모리가 중요한지 따져보면서 써야 함.

/////////

인스턴싱이라는 개념도 있음 배칭하곤 조금 다른게…. 음….

배칭의 경우 정보를 씨피유가 묶어서 지피유에 던지는데

인스턴싱은 지피유가 알아서 씨피유의 데이터를 스캔한 다음 알아서 가져와서 알아서 그림

///////

  • 씨피유랑 지피유랑 조건문 분기 처리 방식이 다름

씨피유는 조건문에 맞는 분기만 타고 가지만

지피유는 모두 다 실행한 다음(코어가 나뉘어져서 실행함), 이후 조건에 맞는걸 화면에 표현해줌

그래서 셰이더에선 동적 분기 나누는 걸 지양해야 함 (특히 모바일)

//////

버텍스 쉐이더

버텍스 쉐이더에선 트랜스폼을 한다.

예전엔 조명 연산도 버텍스 쉐이더에서 하기도 했지만..

뭐 요즘도 잡몹 쉐이딩은 버텍스 쉐이더에서 하기도 하지만…

최근엔 버텍스 쉐이더에선 버텍스 변환. 위치 변환.. 이런거. 변환만.

pos, uv…

/////₩

테셀레이션

주어진 버텍스에서 추가로 버텍스를 만들어서…….

어저고저쩌고

모바일에선 활성화된 단계가 아님

///////\


이슈 및 공부한 것을 기록해두는 개인 블로그 입니다. 댓글, 피드백 환영합니다 🙂

Update:

댓글남기기