[ Unity Shader ]
[ Unity Shader Structure ]
GPU를 다루기 위해 Unity에서는 별도의 쉐이더랩(ShaderLab)이라는 추상 스크립트 언어를 사용하여, 멀티플랫폼 쉐이더를 만들 수 있도록 설계되어 있음
Shader Script(Shader Lab)
멀티 플랫폼 시스템을 위한 추상화된 스크립트 언어 레이어
지원 Device
Old moblie hardwares(DX 7/8)
modren mobile hardware(DX9, Shader Model 2)
PC / Consol hardware(Shader Mode 3)
Extreme PC hardware(DX11, Shader Model 5)
지원 Library
OpendGL, OpenGL E/S, DirectX
지원 Language
GLSL, Cg, HLSL
특징
60개 이상의 기본 쉐이더를 제공하고 있으며, 계속 추가중
사이트에서 기본 쉐이더 소스를 다운 받을 수 있음
[ Unity Shader Programming (세가지 방식 지원) ]
Fixed Function Program(고정 함수 프로그램)
Vertex Lit 랜더링 방식에 적합 (Shader Model 1.x로 가정 : 고급 랜더링 불가)
그러나, "SetTexture"를 통해 간단한 다양한 효과 구현이 가능
모바일 퀄리티에만 문제가 없다면 가장 좋은 성능을 발휘함
Vertex / Fragment Program(버텍스 프래그먼트 프로그램)
가장 일반적인 쉐이더 프로그래밍
Pass 구문에 쉐이더 코드를 넣을 수 있게 설계되어 있음
명확히 어떤 언어를 사용할 것인지 알려 주어야 함(CGPROGRAM/GLSLPROGRAM)
CG vs GLSL
Unity는 두가지 언어를 다 지원하지만, 멀티플랫폼 환경에서의 쉐이더를 위해서는 Cg를 사용해야 함
CG/HLSL to GLSL Shader Parser
Cg/HLSL Code Snippet >> HLSL Shader Code >> Full HLSL Code >> Converted GLSL Code >> Optimized GLSL Shader Code >> Final GLSL Shader Code
문제점
멀티플랫폼 쉐이더 코드를 작성하기 위해서는 다양한 light에 대한 세팅 값을 예상해서 넣어야 함
일반적인(범용적인) 쉐이더를 만드는데도 132줄이나 사용됨
Surface Shader Program(서피스 쉐이더 프로그램)
위의 문제점을 해결하기 위해 유니티에서 고안한 방식 (위의 132줄이 12줄로 줄일 수 있음)
프로그램 코드 측면에서는 Vertex Fragment Program과 유사해 보이나 동작 방식을 다름
픽셀에서 면의 다양한 정보를 수집하는 서피스 함수와 빛을 계산하는 라이팅 함수를 분리해 디퍼드라이팅에도 활용될 수 있도록 설계됨
SSE 셰이더( Strumpy Shader Editor)를 통해 제작된 결과는 자동으로 서피스 프로그램으로 변환됨
Surface Shader Program을 Unity는 Vertex / Fragment Program으로 자동 변환 시킴
Surface Shader Program 구조
Shader Programimg = Surface Cdoe + Light Code
#pragma surface surf LightModel [optionalparams] (sur / Lamber는 함수 이름)
surf : 표면을 처리하는 함수 이름
void surf(Input IN, inout SurfaceOutput OUT)와 같은 프로토타입 함수로 선언해야 함
LightModel : 빛을 처리하는 함수 이름
Lambert(diffuse)
BlinnPhong(specular)
optinalparams
alpha - 알파 블랜딩 모드로 작동
alphatest:varialbeName - 알파 테스트 모드로 Cutoff값을 외부에서 지정할 수 있음 / 알파를 어느 정도 레벨까지 지정할지를 지정하는 값
vertex:vertexFunction - 정점을 변경하기 위한 함수를 지정 / 정점을 동적으로 변경할 수 있음
exclude_path:prepass or exclude_path:forward - 랜더링 패스를 생성하지 않도록 함
addshadow - caster & collector를 쉐도우에 추가
등 등
Surface Shader Program 1st Step
표면을 설정하는 방법은 유니티가 제공하는 SurfaceOutput라는 구조에 적절한 값을 넣어 주면 됨(아티스트들이 사용하는 ShaderFX 같은 노드 기반의 그래픽 쉐이더 프로그래밍 툴과 유사)
Surface Shader Program 2st Step
Lighting Model의 적용
Unity에서 제공하는 Blinn-Phong이나 Rambert 공식을 쓰고 싶다면 단순히 이름만 적어주면 됨
직접 Light Model을 만들고 싶다면 Lighting으로 시작하는 함수를 만들고 입력값과 출력값을 맞추어 주면 됨
위의 세가지 방식의 어떤 타입을 선택해도 다음과 같은 ShaderLab의 구조를 가지고 있어야 함
#pragma debug
Surface Shader Program이 어떻게 Vertex/Fragment Program으로 변화하는지 볼 수 있다고 함(?)
Shader Keywords
이미 정의된 키워드
DIRECTIONAL, POINT, SPOT
LIGHTMAP_(ON/OFF), DIRLIGHTMAP_(ON/OFF), VERTLIGHT_(ON/OFF)
SHADOW_(ON/OFF), POINT_COOKIE, DIRECTIONAL_COOKIE ...
#pragma를 이용해서 사용자 정의 키워드를 만들 수도 있음
[ ShaderLab Syntax ]
[ 개요 ]
플랫폼과 무관하게 설계된 셰이더랩은 한단계 높은 추상화된 셰이더 시스템으로 셰이더를 관리하며, 빌드 과정을 통해 플랫폼에서 동작하는 셰이더 코드를 자동을 생성
스크립트처럼 간단한 문법으로 구성된 텍스트 파일
전문가를 위해서는 셰이더 언어인 Cg와 GLSL 구문을 중간에 직접 사용해 복잡한 기능의 셰이더도 제작할 수 있도록 설계되어 있음
< 유니티 통합 셰이더 시스템 그림 넣을 것 >
셰이더 랩(Cg 구문)
HLSL(윈도우)
GLSL(Mac)
GLSL/ES(아이폰/안드로이드)
HLSL(XBox360)
Cg(Playstation3)
Shader "MyShader" { Properties { _MyTexture ("My Texture", 2D) = "white" { } // other properties like colors or vectors go here as well } SubShader { // here goes the 'meat' of your // - surface shader or // - vertex and fragment shader or // - fixed function shader
} SubShader { // here goes a simpler version of the SubShader above that can run on older graphics cards } Fallback "Diffuse" }
Shader(키워드) : 쉐이드 이름을 결정
'/'를 사용하여 이름을 구분하고 쉐이더를 설정할 때 다단계로 표시됨
Properties(키워드) : 쉐이더의 속성들을 Unity 내부의 재료 Inspector에서 보여줌
Unity에서 쉐이더에 전달할 다양한 값을 사용자가 편리하게 설정할 수 있도록 하는 다양한 인터페이스를 제공
아티스트들을 위한 다양한 파라미터 리스트를 결정
Float Textbox / Float Rang Sliders / Vector4 Textboxes / Color Picker / 2D Texture( POT ) / 2D Texture( NPOT ) / Cube Texture
SubShader(키워드)
복수개의 SubShader를 제공
랜더링을 담당하는 우리가 일반적으로 생각하는 쉐이더
가장 위에 정의된 쉐이더 부터 실행되며, 위에 있는 서브쉐이더가 하드웨어와의 호환 문제가 발생하면 다음 쉐이더가 실행됨
다양한 하드웨어와 호환될 수 있도록 하기 위해 다수의 SubShader를 구성해서 사용
FallBack
모든 서브쉐이더의 구동이 실패하면, 풀백(Fallback)에 정의된 쉐이더가 실행됨
SubShader
태그(Tag)
Tag에 사용되는 키워드
Queue : 셰이더의 렌더링 순서를 지정
IgnoreProjector : 셰이더가 프로젝터의 영향을 받는지 유무 결정
RenderType : 셰이더의 종류를 분류하기 위해 사용 / 특정 카메라에 지정한 셰이더 종류만 보이게 하는 셰이더 리플레이스먼트(Shader Replacement) 기능을 사용할 수 있게 됨
Queue
유니티는 0 ~5000까지 랜더링 순서를 지정 구성할 수 있으며, 숫자 대신에 이름을 기반으로 지정함
Backgroud = 1000 : 스카이 박스 같이 가장 먼저 랜더링 되는 것들
Geometry = 2000 : 불투명한 Geometry들 / 기본 값
AlphaTest = 2450 : AlpaTest가 필요한 Geometry 들 / 유리나 파티클 등
Transparent = 3000 : Geometry와 AlpaTest 이후에 순서적으로 알파 블랜딩이 필요한 것들
Overlay = 4000 : 마지막에 적용되어야 하는 overlay 들 / 렌즈플레어 효과나 GUI 등
위의 지정된 값에 '+', '-'를 지정해서 순서를 디테일하게 결정
예> Tags { "Queue" = "Geometry+1" }
2001 번째 순서로 수행
깊이 정보와 상관없이 2000번을 가지는 모든 불투명한 물체를 랜더링한 이후에 덮어서 랜더링 함
패스(Pass)
랜더링 방법을 지정
패스의 동작 순서 [ Unity Shading Pipeline ]
1. 기본 데이터 설정 (Transform/ TexGen/Lighting & Vertex Shader )
렌더링을 위한 기본 데이터를 준비
메쉬의 정점을 변경하고 싶은 경우, 정점 셰이더 프로그램이 이 단계에서 실행됨
각 버텍스당 주어진 정보를 이용한 Vertex Shading 단계
Pixel Shading(Fragment Shader) 단계에서 pixel 당 light를 사용하는 경우에는 Vertex light가 필요하지 않을 수 있음
2. 깊이 판별 (Culling Depth Test)
Culling
View에 보이지 않는 부분을 제거하는 단계 (Backface Culling)
Depth
Z 버퍼에 깊이 정보를 저장하고 물체가 그려져야 하는지를 판단
3. 픽셀 설정 (Texturing / Fog & Fragment Shader )
픽셀 셰이더를 통해 면을 구성하는 픽셀들의 색상 정보를 계산
픽셀 셰이더 프로그램이 여기서 실행
Texturing : vertex light 처리 이후에 SetTexture에 의해서 Texture를 입히는 단계 ( fragment program을 사용할 경우 shader에서 처리 되므로 의미가 없음)
Fog : Fog를 위한 처리 단계
4. 알파 테스팅
지정한 값과 알파값을 비교하여 각 픽셀을 보존할지 제거할지를 결정
5. 알파 블렌딩
반투명 물체의 경우 뒤의 물체와 혼합해 최종 픽셀로 표현
패스 태그(Pass Tag)
랜더링 설정을 지정
랜더 스테이트(Render State)
GPU의 랜더 상태를 설정하는 다양한 키워드
Culling / Depth Test / Alpha Test / Blending
쉐이더 코드(Shader Code)
실제 쉐이더 코드의 조각
SubSahder에 대한 자세한 reference
http://docs.unity3d.com/Documentation/Components/SL-SubshaderTags.html
[ Unity Rendering Pipeline ]
Pass 구문을 통해 물체의 랜더링이 수행
랜더링 패스(Path)
랜더링은 카메라에서 지정한 랜더링 방법을 통해 수행되며, 이런 랜더링 방법을 유니티에서 랜더링 패스라고 함
Unity에서 현재 제공하는 3가지 Rendering 방식
Vertex Lit
Forward
Deferred Lighting
[Vertex Lit]
오래된 하드웨어 방식에서 동작되도록 설계됨(주로 예전 스마트 폰 / 아이폰 3G 세대용)
Vertex별로 라이팅을 계산하고 이를 보간하여 최종 픽셀 값을 산출하는 방식
장점 : 랜더링 방식이 간단하여 CPU에 별도의 작업이 들지 않기 때문에 저사양의 모바일에서의 라이트 매핑에 효과적임
단점 : 유니티가 제공하는 실시간 랜더링 기능(노멀 매핑 및 복수개의 빛 처리, 쿠키<Cookie>, 라이트프로브<LightProbe>, 그림자<Shadow> 등 pixel 단위의 Effect)을 상당수 지원하지 않음
조명을 설치하고 (VertexLit의 Shader가 적용된)평면 위에 물체를 올려 놓고 그림자가 생성되는지를 확인해 보면 됨
Vertex Lit의 3가지 옵션
Vertex Pass
라이트맵이 적용되지 않는 물체에 버텍스를 기반으로 랜더링
VertexLM Pass
라이트맵을 Double LDR 포맷으로 근사하여 인코딩하는 방식의 랜더링 (오래된 스마트폰용)
VertexLMGBM pass
라이트맵을 RGBM으로 인코딩하여 사용하는 방식의 랜더링 (최신 스마트폰용)
Unity가 자동으로 해주기 때문에 신경을 쓸 필요는 없음
[Forward Pipeline]
픽셀당 라이팅을 계산하해 화면의 최종 값을 결정하는 방식
DirectX9에 대응하는 가장 일반적인 랜더링 방식
유니티에서 제공하는 대부분의 랜더링 기능을 사용할 수 있음
노멀 매핑 및 복수개의 빛 처리, 쿠키<Cookie>, 라이트프로브<LightProbe>, 그림자<Shadow> 등
그러나 빛과 물체의 수 만큼 계산량이 많아짐
단지 Directional Light에 대한 그림자 지원(독립적인 라이트에 대한 랜더링이 가능하여 다른 빛에 의한 그림자도 지원할 수는 있음)
Light Setting in Forward Pipeline
포워드 방식에서 가장 중요한 점은 Important / Not Important Light를 구분해서 세팅하는 것
Important Ligth의 경우에는 빛을 공들여서 랜더링하지만, Not Improtant Light의 경우에는 대출 랜더링 함
Important Light
가장 Intensity가 높은 Directional Light
4개 까지 설정이 가능
픽셀당 계산함
Not Important Light
Important Light를 제외한 빛으로 SH(Spherical Hamonics)로 래더일을 수행
Forwad Pipelint Pass
2 pass에 의해서 구현됨
ForwordBase
Most Important Light / Not Important Light를 묶어서 처리
1 pass (1 Draw call)
ForwordAdd
Important Lights들을 처리
Important Lights의 수에 따라 각 1 pass( 수 Draw call)
[Deferred Lighting Pipeline]
Morden 한 랜더링 지원
물체의 빛에 관련된 여러 정보를 모아 버퍼에 저장하고, 빛의 계산은 나중에 한 번에 수행하는 렌더링 기법
장점
Light의 제한이 없음
복잡한 Scene 구현에 적합
단점
모바일에서는 아직 지원 안함
블린퐁(Blinn-Phong)에서만 지원
반 투명한 물체에 대한 지원을 하고 있지는 않음
Deferred Lighting Pipeline Pass
Unity에서는 3번의 랜더링 pass를 거침
PrePassBase(1단계) : 카메라에 비춰지는 Scene의 Geometry 정보를 수집하여 G버퍼에 저장
PrePassLighting(2단계) : G버퍼를 활용하여 Scene에 배치된 라이팅별로 계산
PrePassFinal(3단계) : 라이트맵을 적용하여 다양한 빛의 효과를 냄