|
쉐이더란?
- 컴퓨터 그래픽스 분야에서 셰이더(shader)는 소프트웨어 명령의 집합으로 주로 그래픽 하드웨어의 렌더링 효과를 계산하는 데 쓰인다. 셰이더는 그래픽 처리 장치(GPU)의 프로그래밍이 가능한 렌더링 파이프라인을 프로그래밍하는 데 쓰인다.
(위키백과에서 서술된 정의)
-> 사실 굉장히...무슨소린지 모르겠다. 그래서 좀 더 찾아보기로 함.
- 쉐이더란 화면에 출력할 픽셀의 위치와 색상을 계산하는 함수입니다.
(포프님 글 [포프의 쉐이더 입문강좌] 01. 쉐이더란 무엇이죠? Part 1에서)
-> 굉장히 간략하게 요약해주셨다.
쉐이더는 여러 종류로,
- 각 정점의 공간을 변환시키는 정점쉐이더(Vertex Shader)
- 쉐이더(shader)란 이름 뜻 그대로 색에 농담, 색조, 명암효과를 줘서 최종적으로 색상을 계산하여 픽셀로 나타내는 픽셀쉐이더(Pixel Shader)
- 정점쉐이더 수행 후 정점쉐이더에서 할 수 없던 점이나 선, 삼각형 등의 도형을 생성하는 지오메트리 쉐이더(Geometry Shader)
가 있다.
이 모든 쉐이더의 역할을 통틀어서 화면에 출력할 픽셀의 위치와 색상을 계산하는 함수라고 정의하는 것.
- 정의는 알았지만, 이걸 왜 그래픽 아티스트들이 다뤄야하는지?
프로그래머들의 영역이라고 생각했으나, 최종적으로 결과물을 더 예쁘게 뽑으려면 그래픽 아티스트들의 능력이 필요했고, 이를 위해 그래픽 아티스트들이 이를 제어하게 해달라고 요청했다. 이후 프로그래머들이 그래픽 아티스트들이 쉽게 제어할 수 있도록 3d 파이프라인 과정에서 해당 내용만 쉽게 만들어 빼줬고, 이것을 그래픽 아티스트들이 다루게 된 것이 쉐이더의 시초이다.
(엄밀히 보면 포토샵 등도 쉐이더이다. / 시초는 1988년경 픽사의 랜더맨)
쉽게 만들어줬다고는 하지만 그래픽 아티스트들에겐 그저 어려운 코딩으로 보이기 때문에 다루려면 공부를 해야한다...이 수업을 배우는 이유이기도 함.
-
디지털 텍스쳐 포맷이론
컴퓨터는 모든 정보를 0과 1로밖에 처리하지 못한다.(=2진법)
컴퓨터가 나타내는 0과 1에는 색상 정보가 없지만, 그럼에도 색을 표현할 수 있는 것은 컴퓨터가 출력한 결과물(0과 1의 무수한 조합이겠죠?) 위에 색을 얹음으로써(ex. 셀로판지) 그 차이로 색상을 표현할 수 있는 것.
수학이나 컴퓨터 분야에서 쓰이는 2진법의 최소 단위는 bit(binary digit)이고, 컴퓨터가 나타낼 수 있는 색 역시 이 bit수와 연관이 있다. 즉, 컴퓨터가 발전하며 모니터의 1pixel당 나타낼 수 있는 bit수(즉 나타낼 수 있는 값(0 혹은 1)의 갯수)가 커짐에 따라, 컴퓨터가 표현할 수 있는 색상범위 역시 발전해왔다.
bit가 2진법의 최소단위이기 때문에 컴퓨터가 표현가능 한 색의 수 역시 2의 제곱수로 커져왔고, 이때문에 bit는 2의 제곱수의 승의 값과 동일하다.
(ex '1'bit-> 2의 '1'승=2색)
-
* 1bit(-> 2의 '1'승=2색)
- 1pixel당 하나의 값을 나타낼 수 있다. 1pixel당 0 혹은 1의 2가지 값을 나타낼 수 있고, 따라서 총 2가지 색이 표현 가능하다.
- 초창기의 컴퓨터와 핸드폰 화면에 쓰였다. 현재도 스톱워치나 일부 게임기(녹색 화면에 검은 색으로 그림이 나타나는 그것)에 쓰이고 있다.
* 2bit(-> 2의 '2'승=4색)
- 1pixel당 2개의 값을 나타낼 수 있다. 1pixel당 00, 01, 10, 11의 4가지 값 중 하나를 나타낼 수 있고, 따라서 총 4가지 색이 표현 가능하다.
- 이 시기에 표현할 수 있었던 색상 범위는 일명 4gray 컬러라고 불리었다.
* 4bit(-> 2의 '4'승=16색)
- 1pixel당 4개의 값을 나타낼 수 있다. 1pixel당 0000~1111의 16가지 값 중 하나를 나타낼 수 있고, 따라서 총 16가지 색을 표현할 수 있다.
- 이 시기부터 컬러를 표현하는 것이 가능해졌다.( 사실 1bit 시절부터 가능했지만 보편적으로, 다양하게 표현된 것은 이 시기부터)
- 보다 다양한 색을 표현하기 위해 디더링 기법(Dithering, 병치혼합)을 사용하였다.
- 팔레트가 사용되기 시작한 시기기도 하다.
* 8bit(-> 2의 '8'승=256색)
- 1pixel당 8개의 값을 나타낼 수 있다. 1pixel당 00000000~11111111의 256가지 값 중 하나를 나타낼 수 있고, 따라서 총 256가지 색을 표현할 수 있다.
- 8비트 팔레트 사용. 팔레트를 이용해 애니메이션을 하기도 했다.
- 여전히 디더링 기법을 많이 사용했다.
- 색을 0부터 255까지의 숫자값으로 표현한다.
(※포토샵에서 Image->Mode->Indexed Color로 256색 이미지를 만들 수 있고, 팔레트를 불러오는 것도 가능하다. 당연하지만 색이 깨진다..!)
* 16bit(-> 2의 '16'승=65,536색)
- 1pixel당 16개의 값을 나타낼 수 있다. 1pixel당 0000000000000000~1111111111111111의 65,536가지 값 중 하나를 나타낼 수 있고, 따라서 총 65,563가지 색(!)을 표현할 수 있다.
- 이 시기부터 RGB개념이 등장했으며, 팔레트가 사라졌다.(아마 필요가 없어진 것 같다.)
- 16bit를 5bit, 6bit, 5bit로 나누어 각각 R(ed),G(reen),B(lue)를 나타냈으며, 이 때 G에 해당하는 bit값이 하나 더 많은 이유는 사람의 시신경세포가 녹색을 더 민감하게 인식하기 때문이다. 이때문에 16bit를 R5 G6 B5(565칼라)라고 표현하기도 한다.
(16bit : 32*64*32=65,536)
(※4:4:4:4도 만들면 되서 존재 가능하다. (R:G:B:A))
- 표현할 수 있는 색상범위는 압도적으로 넓어졌지만, 여전히 사람 눈으로 보기에는 그라데이션이 보일 정도로 부족했다.
* 24bit(-> 2의 '24'승=16,777,216색)
- 1pixel당 24개의 값을 나타낼 수 있다. 1pixel당 0000000000000000000000000~1111111111111111111111111의 16,777,216가지 값 중 하나를 나타낼 수 있고, 따라서 총 16,777,216가지 색을 표현할 수 있다.
- 24bit를 8bit씩 나누어 각각 RGB 채널을 나타냈다. 이때문에 24bit를 R8 G8 B8(888칼라)으로 표현하기도 한다.(24bit : 256*256*256 = 16,777,216)
- TGA(알파X)
* 32bit(-> 2의 '32'승=4,294,967,296색)
- 1pixel당 32개의 값을 나타낼 수 있다. 1pixel당 000000000000000000000000000000000~111111111111111111111111111111111의 4,294,967,296가지 값 중 하나를 나타낼 수 있고, 따라서 총 4,294,967,296가지 색을 표현할 수 있다.
- 32bit를 8bit씩 나누어 각각 RGB 채널을 나타내고, 남은 8bit로는 알파(A)채널을 나타냈다.
이때문에 32bit를 R8 G8 B8 A8으로 표현하기도 한다. (32bit : 256*256*256*256=4,294,967,296)
- 알파를 이용해 투명한 부분을 표현할 수 있게 되었다.
* 64비트나 그 이상의 비트 이미지도 존재할 수 있을까? -> 있다! TIF 기법(채널당 16비트 / 32비트도 지원가능한 초고화질 기법)으로 만들어지는 이미지이며, 인쇄용 원본 / Displacement Map / Lightmap 등 고급 정보가 필요한 곳에서 사용한다.
비슷한 개념으로 RAW 파일이나 HDR에 쓰인다.
(※ 다만 초고화질이기 때문에 당연히 용량이 어마어마해진다. 또한 포토샵 등에서 잘못 건드려서 채널당 16비트나 32비트 이미지를 만들어버릴 경우 TIFF 등의 특수한 확장자로만 저장이 되며, 편집 기능 역시 극히 제한된다.)
-> 최근 채널당 12bit 이상의 HDR TV가 출시되었다.
-
깨알팁
RGB와 XYZ값은 동일하다.(ex. 3ds max의 pivot)
-> 노말맵이 파란 이유. 노말맵은 높이값이 담겨있는 맵이고, 높이값은 Z값=B(lue)이기 때문에!
-
FLOAT
FLOAT란?
- 프로그래밍에서 계산할 때의 단위. 부동 소수점이라는 뜻이며, 소수점 아래 6번째까지 유효...하지만 이렇게 표현해버리면 너무 어렵게 느껴지는 용어다.. 그냥 대강 '소수점 있는 일반적인 수'로 알고 있어도 OK라고 하셨다.(어느정도 한계는 있다.)
- 32bit = 4바이트(1바이트 = 8비트 . 즉 4바이트 = 32비트. 즉 float = 32 비트 = 4바이트.)
- 색상을 float으로 계산할 때는, 3개의 float를 이용하여 나타낸다. -> (float,float,float)
- float으로 색상을 표현하기
* Float3(1.0,1.0,1.0) = 24bit (255,255,255) -> 흰색
* Float3(0.0,0.0,0.0) = 24bit (0,0,0) => 검정
* Float4(0.5,0.5,0.5,0.5) = 32bit (128,128,128,128) -> 회색 반투명
* Float값 = 8bit Color값 / 255
bit수에 따라 색상을 표현하는 채널당 수치가 달라지기 때문에 이를 통일하여 표현하고자 프로그래머 측에서는 해당 색상의 수치값을 %값=소수 형태값으로 표현하게 되었고 이걸 float값으로 나타낸다. 이것이 프로그래머가 사용하는 색상값이다.
Unity shader에서 사용하는 단위
* Float -> 32비트
* Half=float/2 -> 16비트
* Fixed -> 11비트
-
게임 전용 텍스쳐 포맷
DDS란?
- 유니티에서 사용되는 파일 포맷이 아닌, DirectX의 Texture Format과 일대일로 대응하는 File Format
(*Direct X - 마이크로소프트 사가 개발한 멀티미디어 응용 프로그램 인터페이스(API)의 집합. 직접 하드웨어를 컨트롤하기에 속도가 빠르며, 모든 그래픽 카드를 지원한다.(이른바 표준인 셈!) Direct X의 개발로 하드웨어에 맞춰 일일히 그래픽 사양을 다르게 개발할 필요가 없어졌다. 다만 윈도우 개발사인 마이크로 소프트 사 에서 개발한 것이기 때문에 윈도우 운영체제의 PC와 XBOX에서만 돌아간다.
+) OPEN GL - Direct X와 비슷한 API. 오픈 소스이며, 모든 운영체제에서 돌아간다.)
- Direct X를 지원하는 모든 비디오카드에서 굉장히 빠르게 사용가능하다.
- 일반적으로 손실 포맷 사용..즉 압축을 한다.
- 2의 승수 사이즈로만 가능하다. 텍스쳐 제작 시 2의 승수 사이즈로만 만드는 이유이기도 함.
- Mipmap / Cubemap 등 게임을 위한 기술들을 사용 가능하다.
- 픽셀 포맷
- DXT1 RGB(No Alpha) : R5G6B5
- DXT5 ARGB(Interpolated) : A8R5G6B5
- 무슨 포맷을 가져다 넣어도 변환되면서 압축되므로, 가장 고화질인(=가장 깨지지 않는) TGA를 주로 사용한다.
(다만 TGA의 경우 프로그래머들은 포토샵이 깔려있지 않으면 바로 확인할 수가 없기 때문에 비압축포맷이면서 바로 이미지가 보이는 PNG 형식을 이용하기도 함)
-
그럼 유니티에서는 ?
- 유니티에서는 일반적으로 DDS와 같다고 생각하면 된다.
- 일반적으로 압축 포맷을 사용한다 : 어떤 포맷을 넣어도 자체 압축한다.
- 자세한 점은 메뉴얼을 적극 활용하자! (Platfom Specific 항목)
* Desktop texture Format
- RGB Compressed DXT1 / RGBA Compressed DXT5 같이 Compressed가 들어간 포맷은 압축 포맷으로, 당연히 깨진다.
깨지지 않게 하기 위해서는 RGBA Compressed DXT5 -> RGBA 32 bit 형식으로 바꾸는 등 수동으로 바꿔줘야 함.
* IOS texture Format
- PVRTC
* Android texture Format
(안드로이드 기반 개발사가 다양해서 포맷 통일이 쉽지 않다 그래서 가장 골때린다)
- PVRTC -> IOS와 같은 칩셋 사용
- RGB Compressed ETC 4 bits -> 모든 안드로이드에서 돌아가는 공통포맷. 단 알파가 되지 않는다....
- RGBA 16 bit -> ↑의 이유때문에 알파를 표현하려면 써야하는 포맷. 단 노압축 포맷이기때문에 용량이 어마어마함
- ↑↑,↑의 단점 때문에 RGB Compressed ETC 2 포맷 형식이 새로 나왔다! Unity 5.2 버전부터 지원함. 그러나 갤럭시 3 이하는 지원하지 않는다(...)
(※ 3d max -> Direct X 좌표 / unity -> 오픈GL 좌표 사용해서 max 오브젝트를 유니티로 갖고가면 눕는다(..))
-
Unity Shader
* Unity Shader 문법 : shaderLab (->자체문법 사용)
- 멀티 플랫폼을 위한 문법
- 이 문법을 바탕으로 3가지 종류의 작성법이 일반적
* ShaderLab - 할 수 있는 것이 너무 적다.
* Surface Shader - 가장 쉽고 멀티플랫폼에 잘 대응됨
* Fragment Shader - 처음부터 전부 짜야함
Surface Shader
- 가장 쉽고 멀티 플랫폼에 잘 대응되는 Shader
- 프로그래머가 아니어도 배우기 쉬운 개념
*Matrix 연산 등이 없음
*Visual Shader Editor와 상당히 개념적으로 비슷
*고급 기술은 아쉽지만 자동이라는 장점
*그래도 C 문법은 ‘매우 조금’ 필요
ㄴ기초문법 ( // , = , ; )
-> // 주석
= ex. A=B라는 소리는 B를 A에 넣는다는 뜻
; enter대신
ㄴ변수
ㄴ함수
ㄴ조건문 (->if문)
-
Surface Shader 만들기
유니티에서 쉐이더 생성 시 (enter 누르기 전에) 미리 이름을 지어서 바꿔야 한다. 나중에 바꿔도 되긴 되지만 따로 또 수정해줘야한다.
(변경 후)
-> 첫째줄의 주황색 글씨부분, 즉 " "안에 들어가는 부분은 쉐이더의 이름. 해당부분으로 쉐이더의 이름을 바꿀수 있으며, /를 이용해 분류를 추가할 수 있다.(폴더의 개념) 코드에서 이름을 수정해도 파일명은 그대로 유지되며 둘이 관계가 없기에 최대한 맞춰주는 것이 편하다.
-> {}는 방의 개념. 특정 {나 }에 커서를 이동하면 해당 괄호와 세트인 식구괄호를 주황색으로 표시해준다.
-> CGPROGRAM 해당 아래부분부터 쉐이더의 핵심적인 내용을 담고 있다. 작성 시 대소문자를 주의하여 작성해야한다.
Properties
프로퍼티의 블록을 정의합니다. (이게 무슨 소리일까요?) -> 메터리얼에 쓰일 인터페이스를 만든다는 뜻!, 즉 쉐이더를 조작하는 껍데기(버튼)같은 개념에 해당한다
(예시로 범위 지정 버튼을 만들어 보았다.)
종류는 다음과 같다.
_Name ("display name", Range (min, max)) = number -> 범위 지정
_Name ("display name", Float) = number -> 직접 값 입력(소수점 입력 가능)
_Name ("display name", int) = number -> 직접 값 입력(소수점 입력 불가능)
_Name ("display name", Color) = (number,number,number,number) -> 색 관련 인터페이스
_Name ("display name", Vector) = (number,number,number,number) -> ↑랑 비슷한데 정확히 뭐가 다른지 모르겠다. 일단 수치를 입력하는 칸이 생긴다.
_Name ("display name", 2D) = "name" { options }
_Name ("display name", Rect) = "name" { options }
_Name ("display name", Cube) = "name" { options }
_Name ("display name", 3D) = "name" { options }
-> 텍스쳐 인터페이스, { options }의 경우 아무것도 넣지 않는다. 안을 비우고 {}로 쓰면 된다.
-> 이상 4개는 똑같이 텍스쳐 인터페이스이나, 연두색으로 표시한 부분에 따라 뭔가 달라지는 것 같다. 생성될 인터페이스를 통해 불러오는 텍스쳐의 종류가 달라지는 걸까..?
Color 조작
(여기서부터 대소문자를 주의해야한다.)
struct SurfaceOutputStandard
{
fixed3 Albedo; -> (정확히 맞는 건 아니지만 일단은) 빛의 영향을 받는다
fixed3 Normal; -> 노말
fixed3 Emission; -> 빛의 영향을 받지 않는다. 그림자가 지지 않기 때문에 Albedo에 비해 밝아보이며 색을 보기 가장 편하다
half Metallic; -> 1이면 메탈값이 주어지고, 0이면 x
half Smoothness; -> 부드러움의 정도
half Occlusion; -> 구석진 부분의 음영
half Alpha; -> 알파
};
-
o = SurfaceOutputStandard의 줄임말이다.
o. ~ - o안에 들어있는 ~라는 뜻.
ex1) o.Albedo는 o(SurfaceOutputStandard)안에 있는 Albedo라는 뜻
ex 응용) o.Albedo = c. rgb의 경우 o(SurfaceOutputStandard) 안에 있는 Albedo에 c.rgb를 넣겠다는 뜻.
(여기서 c.rgb의 c는 채널(channel)일까요?)
-
o.Albedo = float3(1,0,0)
-> Albedo에 float값을 이용해 색을 넣어본 것 빛의 영향을 받는 빨간색을 띄게 되었다.
o.Emission = float3(1,0,0)
-> Emission에 색을 넣어본 것. 빛의 영향을 받지 않는 빨간색을 띄게 되었다. 사실 혼동을 피하기 위해선 Emission에 색을 넣어보는 것이 좋다.
이미지 연산
사칙연산을 이용하여 같은 자릿수, 또는 float과 연산이 가능하다!
1. 더하면? (포토샵의 Linear Dodge(Add) 레이어 느낌, 공식은 전혀 다르다.)
float3 (0.5,0.5,0.5) + float3 (0.5,0.5,0.5) = float3 (1.0,1.0,1.0)이므로
회색 + 회색 = 흰색이 되었다.
2. 곱하면? (포토샵의 곱하기(Multiply) 레이어 느낌)
float3 (0.5,0.5,0.5) * float3 (0.5,0.5,0.5) = float3 (0.25,0.25,0.25) 이므로
회색 * 회색 = 더 어두운 회색이 되었다.
-----
어두운 글씨는 이전처럼 궁금한 내용입니다.
|
첫댓글 - 32bit = 4바이트(이거 1float=32bit=4바이트라는 뜻인가요?)
-> 1바이트 = 8비트 . 즉 4바이트 = 32비트.
즉 float = 32 비트 = 4바이트.
근데 바이트는 몰라도 됨 ㅋ
아하 이해했어요 감사합니다!
음 아직 뒷 부분은 부족하므로 정리중이라고 생각하고 채점 보류
수정완료했습니다!
@201413002 조예지 오케이