Variables
Summary After making clear how the shader stages are put together and the rough outline of shaderlab outside of the actual shader code, lets talk about what variables our shader needs to function and how we add them to our code. This includes the variables
www.ronja-tutorials.com
Ronja 님의 허락을 받고 번역한 튜토리얼입니다. 원문은 위 링크에서 확인하실 수 있습니다.
몇몇 부분은 생략·추가하였습니다.
의역과 오역이 넘쳐날 수 있으니 편하게 봐주시고 잘못된 부분은 알려주시면 감사하겠습니다!
목차
- 개요
- 오브젝트 데이터
- 보간자
- 출력 색상
- 유니폼 데이터
- 공간 (Spaces)
개요
셰이더 스테이지가 어떻게 구성되는지와 셰이더 코드 외부 셰이더랩의 개략적인 개요를 이해했다면, 셰이더가 작동하기 위해 필요한 변수와, 코드에 이 변수들을 어떻게 추가하는지에 대해 이야기해 보겠습니다.
이는 메테리얼별로 설정하는 변수, 메쉬 데이터의 일부인 변수, 그리고 버텍스에서 프래그먼트로 전달되는 데이터들에 대한 이야기입니다.
오브젝트 데이터
셰이더 플로우를 설명할 때 오브젝트 데이터라고 부른 것은 실제로 메쉬 데이터일 필요는 없습니다. 낮은 프로그램 레벨에서는 오브젝트 데이터는 무엇이 렌더될지 정의하는 데이터 스트림이지만, 메쉬로 상상한다면 더 이해하기 쉬워집니다.
대부분의 경우에선 오브젝트 데이터에는 버텍스 포지션과 그 사이의 삼각형이 포함되어야 합니다. 버텍스 노말, UV좌표와 버텍스 컬러와 같은 다른 데이터들도 오브젝트 데이터를 통해 자주 전달되고는 합니다. 버텍스 데이터(삼각형을 제외한 모든 것)는 렌더링되기 전에 버텍스 스테이지에서 처리됩니다. 포지션과 방향은 모두 로컬 공간에 있으므로, 오브젝트가 어떻게 스케일되거나 이동하는지에 관계없이 추가 작업 없이 동일한 버텍스 데이터를 사용할 수 있습니다.
유니티 셰이더에서 오브젝트 데이터는 보통 'appdata' 라는 이름의 구조체로 버텍스 셰이더로 전달됩니다. 데이터의 이름은 마음대로 정해도 되지만, 유니티에게 어떤 변수가 어떤 데이터로 채워져야 하는지 알려주는 식별자를 추가해야 합니다. 예시는 아래와 같습니다.
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
여기에서 일반적인 버텍스 스트림의 목록을 확인할 수 있습니다.
Unity - 버텍스 프로그램에 버텍스 데이터 제공하기 ↗
보간자
데이터가 버텍스 스테이지에서 수정된 후에는, 래스터라이저에서 그려질 픽셀들을 생성하기 위해 사용됩니다. 이를 위해서 화면에서의 로컬 포지션(클립 공간 상의)을 설정해서 래스터라이저가 이 위치를 어디에 그려야 하는지 알 수 있도록 하고, 해당 변수에 SV_POSITION 태그를 지정합니다.
다른 데이터들은 선택적이며, 프래그먼트 스테이지에서 텍스처 값과 빛을 포함해 색상을 생성하는데 사용될 수 있습니다. 데이터로 생성된 버텍스 사이의 픽셀의 경우에 데이터는 보간되며, 따라서 이를 보간자(Interpolator)라고 합니다. '버텍스에서 프래그먼트로' 라는 뜻의 v2f 라는 일반적인 디스크립터도 있습니다.
간단한 보간자 구조체의 예시는 다음과 같습니다.
// 버텍스에서 프래그먼트 셰이더로 전달되는 데이터. 래스터라이저에 의해 보간됩니다.
struct v2f
{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
출력 색상
출력 값으로는 일반적으로 RGBA 채널의 4차원 벡터를 사용합니다. 출력이 색상으로 사용된다는 것을 컴파일러에게 알려주기 위해 프래그먼트 함수를 SV_Target 으로 태그하는 것이 중요합니다.
유니폼 데이터
렌더링된 메쉬의 일부인 셰이더 내 데이터 외에도, 메테리얼별로 설정하는 데이터가 있습니다. 이러한 종류의 데이터는 메쉬 데이터와 다르게, 그려지는 과정에서 그 값이 변하지 않기 때문에 유니폼 데이터라고 불립니다. 이는 숫자, 텍스처, 벡터, 무엇이든 될 수 있습니다. 현재 렌더링중인 카메라와 렌더링 대상 객체의 변환을 정의하는 행렬도 이러한 데이터의 일부분입니다. 다행히 걱정할 필요 없이, 이 모든 것들은 유니티에서 자동으로 설정해줍니다.
새로운 유니폼 데이터를 정의하기 위해서는, 작성하고 있는 셰이더 프로그램의 구조체와 함수 외부에 변수를 추가하기만 하면 됩니다.
이러한 변수들이 존재하면 코드를 통해 그 값을 설정할 수 있습니다. (Unity C# - Material.SetType)
이 변수들을 인스펙터상에서 표시하려면 셰이더 파일에서 이들을 프로퍼티로 선언해야 합니다. 프로퍼티들은 항상 '_변수 ("인스펙터상에서 표시될 이름", 형) = 기본값' 구조를 따르며, 프로퍼티 Drawers가 그 앞에 위치합니다.
텍스처는 특별한 케이스로, 타일링과 오프셋 값도 동일한 변수에 텍스처와 함께 값을 적용할 수 있습니다. 다만, 변수명 뒤에 '_ST' 를 붙여줘야 합니다. (ST는 Scaling과 Transform의 약자이며, 이전 유니티 버전에서는 타일링과 오프셋 대신 사용되었습니다.)
('_ST'를 붙이는 부분은 유니티 포럼 글을 참고하시면 이해하시기 좋을 것 같습니다.)
프로퍼티 부분의 예는 다음과 같습니다.
Properties
{
_Color ("Tint", Color) = (0, 0, 0, 1)
_MainTex ("Texture", 2D) = "white" {}
}
공간 (Spaces)
셰이더에서 위치를 다룰 때는, 오브젝트(로컬) / 월드 / 뷰 / 스크린 / 클립 스페이스에 대해 자주 다루게 됩니다. 이때, 공간이란 좌표가 속하는 곳을 나타냅니다.
오브젝트 스페이스 좌표는 오브젝트 내에서의 좌표(로컬 좌표계)입니다.
오브젝트 스페이스에서의 0,0은 오브젝트의 원점을 나타냅니다. 만약 오브젝트가 회전하거나 스케일된다면 오브젝트 스페이스의 좌표도 같이 회전되거나 스케일됩니다. (주로 가장 '가까운' 공간인 월드 스페이스과 관련되어 있습니다.)
버텍스의 좌표는 파일에서 오브젝트 공간에 저장되며, GPU에 업로드됩니다.
월드 스페이스 좌표는 모든 다른 것들과 연관된 좌표입니다.
월드 좌표에도 0,0 원점은 있지만, 크게 의미는 없습니다. (실생활에서 위치를 이야기 할 때 특정 지점을 기준으로 이야기하지 않고 상대좌표로 이야기하듯이, 집 앞의 편의점을 위도와 경도로 표현하지 않듯이요)
뷰 스페이스는 오브젝트의 위치를 카메라를 기준으로 변환한 좌표계입니다.
클립 스페이스는 투영 행렬이 적용된 좌표로, 카메라에 따라 좌표들이 조정됩니다. 만약 원근 투영을 사용할 경우, 월드 스페이스에서 카메라와 오브젝트간의 거리가 멀어질수록 클립 스페이스에서 작게 표시됩니다.
스크린 스페이스는 렌더링에 필요한 몇몇 트릭들이 적용된 이후의 좌표입니다. 대부분의 경우 뷰와 클립 스페이스를 무시하고, 스크린 스페이스 상의 좌표를 구해도 됩니다. (행렬 연산을 이해하지 못하더라도 사용할 수 있는 좋은 유틸리티 함수들이 있습니다.)
'Graphics > Ronja's Unity Shader tutorials' 카테고리의 다른 글
기본 투명 셰이더 (0) | 2024.01.21 |
---|---|
유니티 서피스 셰이더 기본 (0) | 2023.11.19 |
기본 셰이더 (0) | 2023.08.06 |
HLSL (0) | 2022.11.09 |
유니티 셰이더 구조 (0) | 2022.11.09 |