이 블로그 검색

2015년 5월 27일 수요일

[ Unity ] Per - Pixel Specular Lighting Shader

Shader "Cg normal mapping" {
   Properties {
      _BumpMap ("Normal Map", 2D) = "bump" {}
      _Color ("Diffuse Material Color", Color) = (1,1,1,1) 
      _SpecColor ("Specular Material Color", Color) = (1,1,1,1) 
      _Shininess ("Shininess", Float) = 10
   }
   SubShader {
      Pass {      
         Tags { "LightMode" = "ForwardBase" } 
            // pass for ambient light and first light source
 
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag  
 
         #include "UnityCG.cginc"
         uniform float4 _LightColor0; 
            // color of light source (from "Lighting.cginc")
 
         // User-specified properties
         uniform sampler2D _BumpMap; 
         uniform float4 _BumpMap_ST;
         uniform float4 _Color; 
         uniform float4 _SpecColor; 
         uniform float _Shininess;
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
            float3 normal : NORMAL;
            float4 tangent : TANGENT;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 posWorld : TEXCOORD0;
               // position of the vertex (and fragment) in world space 
            float4 tex : TEXCOORD1;
            float3 tangentWorld : TEXCOORD2;  
            float3 normalWorld : TEXCOORD3;
            float3 binormalWorld : TEXCOORD4;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            float4x4 modelMatrix = _Object2World;
            float4x4 modelMatrixInverse = _World2Object; 
               // unity_Scale.w is unnecessary 
 
            output.tangentWorld = normalize(
               mul(modelMatrix, float4(input.tangent.xyz, 0.0)).xyz);
            output.normalWorld = normalize(
               mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
            output.binormalWorld = normalize(
               cross(output.normalWorld, output.tangentWorld) 
               * input.tangent.w); // tangent.w is specific to Unity
 
            output.posWorld = mul(modelMatrix, input.vertex);
            output.tex = input.texcoord;
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            // in principle we have to normalize tangentWorld,
            // binormalWorld, and normalWorld again; however, the 
            // potential problems are small since we use this 
            // matrix only to compute "normalDirection", 
            // which we normalize anyways
 
            float4 encodedNormal = tex2D(_BumpMap, 
               _BumpMap_ST.xy * input.tex.xy + _BumpMap_ST.zw);
            float3 localCoords = float3(2.0 * encodedNormal.a - 1.0, 
                2.0 * encodedNormal.g - 1.0, 0.0);
            localCoords.z = sqrt(1.0 - dot(localCoords, localCoords));
               // approximation without sqrt:  localCoords.z = 
               // 1.0 - 0.5 * dot(localCoords, localCoords);
 
            float3x3 local2WorldTranspose = float3x3(
               input.tangentWorld, 
               input.binormalWorld, 
               input.normalWorld);
            float3 normalDirection = 
               normalize(mul(localCoords, local2WorldTranspose));
 
            float3 viewDirection = normalize(
               _WorldSpaceCameraPos - input.posWorld.xyz);
            float3 lightDirection;
            float attenuation;
 
            if (0.0 == _WorldSpaceLightPos0.w) // directional light?
            {
               attenuation = 1.0; // no attenuation
               lightDirection = normalize(_WorldSpaceLightPos0.xyz);
            } 
            else // point or spot light
            {
               float3 vertexToLightSource = 
                  _WorldSpaceLightPos0.xyz - input.posWorld.xyz;
               float distance = length(vertexToLightSource);
               attenuation = 1.0 / distance; // linear attenuation 
               lightDirection = normalize(vertexToLightSource);
            }
 
            float3 ambientLighting = 
               UNITY_LIGHTMODEL_AMBIENT.rgb * _Color.rgb;
 
            float3 diffuseReflection = 
               attenuation * _LightColor0.rgb * _Color.rgb
               * max(0.0, dot(normalDirection, lightDirection));
 
            float3 specularReflection;
            if (dot(normalDirection, lightDirection) < 0.0) 
               // light source on the wrong side?
            {
               specularReflection = float3(0.0, 0.0, 0.0); 
                  // no specular reflection
            }
            else // light source on the right side
            {
               specularReflection = attenuation * _LightColor0.rgb 
                  * _SpecColor.rgb * pow(max(0.0, dot(
                  reflect(-lightDirection, normalDirection), 
                  viewDirection)), _Shininess);
            }
            return float4(ambientLighting + diffuseReflection 
               + specularReflection, 1.0);
         }
         ENDCG
      }
 
      Pass {      
         Tags { "LightMode" = "ForwardAdd" } 
            // pass for additional light sources
         Blend One One // additive blending 
 
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag  
 
         #include "UnityCG.cginc"
         uniform float4 _LightColor0; 
            // color of light source (from "Lighting.cginc")
 
         // User-specified properties
         uniform sampler2D _BumpMap; 
         uniform float4 _BumpMap_ST;
         uniform float4 _Color; 
         uniform float4 _SpecColor; 
         uniform float _Shininess;
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
            float3 normal : NORMAL;
            float4 tangent : TANGENT;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 posWorld : TEXCOORD0;
               // position of the vertex (and fragment) in world space 
            float4 tex : TEXCOORD1;
            float3 tangentWorld : TEXCOORD2;  
            float3 normalWorld : TEXCOORD3;
            float3 binormalWorld : TEXCOORD4;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            float4x4 modelMatrix = _Object2World;
            float4x4 modelMatrixInverse = _World2Object; 
               // unity_Scale.w is unnecessary 
 
            output.tangentWorld = normalize(
               mul(modelMatrix, float4(input.tangent.xyz, 0.0)).xyz);
            output.normalWorld = normalize(
               mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
            output.binormalWorld = normalize(
               cross(output.normalWorld, output.tangentWorld) 
               * input.tangent.w); // tangent.w is specific to Unity
 
            output.posWorld = mul(modelMatrix, input.vertex);
            output.tex = input.texcoord;
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            // in principle we have to normalize tangentWorld,
            // binormalWorld, and normalWorld again; however, the  
            // potential problems are small since we use this 
            // matrix only to compute "normalDirection", 
            // which we normalize anyways
 
            float4 encodedNormal = tex2D(_BumpMap, 
               _BumpMap_ST.xy * input.tex.xy + _BumpMap_ST.zw);
            float3 localCoords = float3(2.0 * encodedNormal.a - 1.0, 
                2.0 * encodedNormal.g - 1.0, 0.0);
            localCoords.z = sqrt(1.0 - dot(localCoords, localCoords));
               // approximation without sqrt:  localCoords.z = 
               // 1.0 - 0.5 * dot(localCoords, localCoords);
 
            float3x3 local2WorldTranspose = float3x3(
               input.tangentWorld,
               input.binormalWorld, 
               input.normalWorld);
            float3 normalDirection = 
               normalize(mul(localCoords, local2WorldTranspose));
 
            float3 viewDirection = normalize(
               _WorldSpaceCameraPos - input.posWorld.xyz);
            float3 lightDirection;
            float attenuation;
 
            if (0.0 == _WorldSpaceLightPos0.w) // directional light?
            {
               attenuation = 1.0; // no attenuation
               lightDirection = normalize(_WorldSpaceLightPos0.xyz);
            } 
            else // point or spot light
            {
               float3 vertexToLightSource = 
                  _WorldSpaceLightPos0.xyz - input.posWorld.xyz;
               float distance = length(vertexToLightSource);
               attenuation = 1.0 / distance; // linear attenuation 
               lightDirection = normalize(vertexToLightSource);
            }
 
            float3 diffuseReflection = 
               attenuation * _LightColor0.rgb * _Color.rgb
               * max(0.0, dot(normalDirection, lightDirection));
 
            float3 specularReflection;
            if (dot(normalDirection, lightDirection) < 0.0) 
               // light source on the wrong side?
            {
               specularReflection = float3(0.0, 0.0, 0.0); 
                  // no specular reflection
            }
            else // light source on the right side
            {
               specularReflection = attenuation * _LightColor0.rgb 
                  * _SpecColor.rgb * pow(max(0.0, dot(
                  reflect(-lightDirection, normalDirection), 
                  viewDirection)), _Shininess);
            }
            return float4(diffuseReflection + specularReflection, 1.0);
         }
         ENDCG
      }
   }
}

2015년 5월 21일 목요일

[ Report ] Digital Lighting & Rendering

Chapter 1. 라이팅 디자인의 기초

  • 라이팅 : Off Screen Space. 장면밖의 공간을 설명할 수 있다.
    라이팅으로 온도, 날씨 등을 느낄수 있다.
  • Penumbra : SpotLight의 Falloff 영역을 말한다.
  • Footage : 짧은 실사 소스 영상
  • KeyLight = Dominant Light = 주광
  • CG처럼 보인다면 그건 좋은 CG가 아니다.

Chater 2. 라이팅의 기초와 올바른 연습

  • Point, Spot, Directional, Area, Fill Light
  • Distance Attenuation ( 거리 감쇄 )
Out[11]:
거리가 2배가 되었을때 빛이 닿는 면적은
πr2=>4πr2
즉, 4배가 된다.
d:xd=1:1x2

  • 안개와 같이 어둑한 느낌을 위해서는 1/x^3도 좋은 방법이다.
  • 분위기 조성을 위해 Specular 없이 Fill Light를 배치하기도 한다.
  • 라이트에 이름 붙이기는 좋은 습관이다.
    • ex) Spot_GateFront_Fill

Chapter 3. Shadow & Occlusion

  • Shadow Color : 암부에 색을 드리운다.
    • 직접 Shadow Color를 수정하는 것은 옳은 방법이 아니다.
    • Color Correction, Post Process 등을 통해 전체적인 암부의 색을 바꾸거나 넓은 범위의 Fill Light를 통해 암부와 그림자에 색을 드리우는 것이 좋다.
  • 또한, Key Light의 색상은 Shadow Color와 보색이 되도록 해주어야 빛을 받는 부분의 색이 올바르게 보정이 된다.
  • Shadow - Depth map bias와 artifact...
Out[11]:

  • Hard Shadow
    • 집중된 조명, 실루엣, 활량하고 거친 환경, 악당의 표현
  • Soft Shadow
    • 구름낀 날씨, GI, Indirect Light, 호의적인 or 여성캐릭터 느낌
  • GI : global illumination ( Indirect light + occlusion )

Chapter 4. 환경과 건출물의 라이팅

  • Sun Light ( R, G, B )
    • 일출, 일몰 : 182, 126, 91
    • 정오의 직사광선 : 192, 191, 173
    • 안개, 흐린날씨 : 189, 190, 192
  • Sky Light
    • IBL로 표현하기도 한다.
  • Practical Light : Area Light와 같이 특별한 모양의 라이팅을 말한다.
  • Throw Pattern : 손전등에서 나오는 빛과 같이 일정한 모양, 형상을 띄는 빛
    • ex) spot ligjt의 fall off 부근에서 채도가 높아지고 붉은 기운이 도는 현상을 표현할 수 있다.
  • 실내 라이팅시 Sky Light와 Sun Light간의 배분이 매우 중요하다.
    • 맑은날 : Sun > Sky, 그림자 날카로움
    • 흐린날 : Sun < Sky, 그림자 부드러움
  • GI를 흉내내기위한 Bounce Light ( 참고로 알아두라. )
    • Indirect Light(간접광) : Ambient Occlusion을 표현하기 위해 fill light를 활용하기도 한다.
    • Negative Light를 배치하여 AO를 표현하기도 하지만 음수로 인해 아티팩트가 발생될 수 있으므로 충분히 고려하여야 한다.
    • 좋은 라이팅이 되었다면 조화롭게 라이팅이 섞이게 되고 light circle이 보이지 않아야 한다.
  • Local illumination : Surface간 상호반사를 배제한 상태. 즉, No indirectlight global illumination
  • Radiosity : geometry 정보를 분할해 렌더링 정보를 저장한다. 메모리 문제가 있다.
  • Photon Map : radius를 가진 입자를 방출하여 렌더링
  • Final Gathering : 렌더링 옵션으로 포톤맵과 연계하여 사용. 얼룩제거, 필터 역활을 한다.
  • Caustics : 넓게 방사되는 Indirect Light와 다르게 돋보기등으로 인한 빛의 집중을 말한다.

Chapter 5. 크리처와 캐릭터 라이팅 그리고 에니메이션

  • 빛으로 모델링 하기 : 라이팅으로 어떤 부위를 명확히 할 것이냐!
  • Three Point Lighting : Key, Rim, Fill Light의 구성으로 이루어진 가장 기본적인 캐릭터 라이팅

Chapter 6. 카메라와 노출

  • Depth Of Field : f-stop(조리개) 조절로 인한 blurring 효과. f-stop이 커질수록 조리개는 작아지고 빛의 양은 줄어든다. 이 상태를 deep focus라하고 모든 물체에 초점이 맞는다.
  • 초점거리 (d)
Out[14]:
평행으로 들어온 빛이 상이 맻히는 거리를 초점거리라 한다.
  • Focal Length(초점거리)와 FOV(화각)은 반비례 한다.
  • Focal Length(초점거리)와 DOF(피사계심도)는 반비례 한다. ( 초점거리가 길면 낮은 피사계심도가 생기고 초점이 잘 맞지 않는다. )
  • 2/3 법칙 : 1/3은 전경, 2/3은 배경(초점거리 밖)의 영역으로 생각해도 좋다는 법칙
  • 결상거리 : 필름에 이미지가 선명하게 맺히는 거리 ( Hyper Focal Distance )
  • 모션블러 : 등속운동을 하는 물체의 모션블러는 앞, 뒤 모두 동일한 블로효과가 일어난다. 즉, 물체의 운동방향을 알수없다.
  • f-stop(조리개), 셔터속도, 감광속도(빛에 대한 민감도) 세가지는 모두 빛의 양조절과 관계가 있고 상호교환이 가능하다.
    • ex) f-stop으로 조리개를 넓혀 인물은 유지하고 배경을 날릴경우 빛의 양이 늘게 되므로 셔터스피드를 높혀서 빛의 양을 상쇄한다.
  • Histogram : 장면밝기의 분포도. 아무리 어두운 장면이라도 무조건 어둡게 표현하기 보다는 높은 콘트라스트와 어두운 그림자를 이용해 표현하자.
  • Distortion : 렌즈로 인한 굴곡
    • Barrel Distortion : 어안렌즈등에서 처럼 외곽으로 왜곡
    • Pincushion Distortion : 안쪽으로 왜곡
  • Chromatic Aberration(색수차) : 빛의 파장에 따라 굴절률이 다르므로 distortion으로 인해 빛이 분리되는 것을 말한다. ( ex: 프리즘을 통과한 빛 ). depth of field 적용시 채널별로 세기를 달리하면 비슷한 효과를 낼 수 있다.

Chapter 7. 구도와 연출

  • ECU, CU, MCU, MS, WS : Extrem Close Up, Close Up, Medium Close Up, Medium Shot, Wide Shot ( 구도의 종류 )
  • POV : Point Of View ( 1인칭 시점 ), Two Shot
  • Over Shoulder Shot(OSS) : 투샷의 일종. 한명은 카메라를 등진다.
  • Line Of Action : 동작선. 연출시 카메라의 회전으로 인해 관객에게 왼쪽, 오른쪽에 대한 혼란을 주어서는 안된다.
  • Perspective(원근감) : 렌즈의 종류나 Zoom에 의해서 변하는 것이 아니다. 초점거리(Focal Length)에 의해 결정된다. 단, 렌즈의 변화는 초점거리의 변화를 의미하며 perspective와 반비례 관계이다. ( FOV : 시야각, 화각 )
  • 카메라의 움직임
    • Pan : 좌우회전 ( Yaw )
    • Tilt : 상하회전 ( Pitch )
    • Dolly : dolly in, dolly out 물체에 다가가거나 멀어진다.
    • Zoom : 카메라는 고정한채로 zoom in, zoom out
    • Rack Focus : 초점의 변화를 말한다. ( = full focus )
  • 구도향상 - 3분할 법칙
    • 물체를 3등된 선에 맞추어 배치하면 훨씬 좋다.
Out[35]:

  • Positive Space, Negative Space를 잘 배분한다.
    • Positive Space : 캐릭터와 같은 전경
    • Negative Space : 빈공간 or 배경
  • 균형있는 구도를 위해서 캐릭터가 바라보는 방향에 negative space를 일부러 만들기도 하며 이것을 lock space or nose room이라 한다.
  • 구도선 : 화면 전체를 지배하는 구도를 선으로 표현해보자
  • Tangency : 물체들의 구도선이 겹치는 것을 말하며 피해야할 부분이다.
    • ex) 지붕구도선과 수평선이 겹칠때 어색할 수 있다.

Chapter 8. 색의 예술과 과학

  • 보색관계
    • Red <=> Cyan, Greem <=> Magenta, Blue <=> Yellow
Out[22]:
  • CMYK : Cyan, Magenta, Yellow, Black
  • 표면에 빛이 닿았을때...
    • 컬러를 갖는 빛이 컬러를 가진 표면에 닿는다는 것은 Multiply를 의미한다. 표면이 붉다는 것은 Red만 반사하고 Green, Blue는 흡수하기 때문이며 빨간공에 파란불을 비추면 검정색이 되는 것이다.
  • Color Scheme : 색구성을 의미한다. 적절한 보색 배치로 색을 보완하고 주의를 끈다.
  • 색상의 의미 : 어두운 장면에서의 폭발으 더욱더 강렬하게 느껴진다.
    • Blue : 차가움, 무게감, 금융권, 믿음, 차가음, 멀어보임
    • Green : 자연, 질병, 불안한, 병원, 차분함
    • Red : 두려움, 사악함, 뜨거움, 차가워보임
  • 색상과 깊이 : 일반적으로 파한색은 멀어보이고 붉은색은 가까워 보인다. 하늘 물등 배경엔 파란색이 많고 사람, 동물에는 붉은색이 많다. 색수차에 의해 붉은계열은 더 큰굴절을 일으켜 가까워 보일수 있다. 라이팅 또한 배경은 푸른색, 전경은 붉은계열로 하는것이 자연스럽다. 왜냐하면 깊이감을 배가시키기 때문.
  • Color Balance = White Balance
    • 색보정을 통해 어떤색을 white로 보이게 할지를 조절한다.
    • 실내 ( 3200K ) : 일반적인 전구는 붉거나 오렌지색이므로 푸른색을 보강해야 한다.
    • 실외 ( 5500K ) : 실외는 푸른빛이 많으므로 붉은색을 보정한다.
  • 색온도 = Kelvin온도 ( 탄소가 가열될때의 색상 )
    • 붉은색(성냥불, 1700K) ~ 한낮의 직사광선(5500K) ~ 푸른하늘(8000K ~ 10000K)
  • RGB
    • 순수한 White의 RGB = R(35%), G(55%), B(15%)
    • 빛일 경우 실제로 Green, Blue를 GrayScale로 바꾸면 Green이 더 많다.

Chapter 9. 셰이더와 렌더링 알고리즘

  • Diffuse, Glossy, Specular
    • Diffuse : 시점에 관계없이 일정한 밝기
    • Glossy : Specular와 Diffuse의 혼합형태
    • Specular : 정반사
    • 사실상 Phong Shading의 스펙큘라 모델은 Glossy를 시뮬레이션 한 것이다.
Out[25]:

  • Microfacet model ( 마이크로 패시트 모델 )
    • 물체의 미세한 표면 재질을 고려한 쉐이딩 모델을 말한다. ( Roughness )
      • ex) Cook-torrance, Oren-Nayar shading model
  • BRDF ( Bidirectional Reflectance Distribution Function )
    • 양방향 반사율 분포 함수
  • BSSRDF ( Bidirectional Surface Scattering Reflectance Distribution Function )
  • Anti-Aliasing
    • 오버샘플링 : 필셀당 샘플링 횟수
    • 렌더링이 되기전 래스터라이즈된 폴리곤으로부터 컬러를 추출하여 혼합한다.
Out[31]:

  • Adaptive Over Sampling
    • Aliasing이 필요한 부분에선 샘플링 횟수를 높이고 필요하지 않은 부분은 횟수를 줄인다.
Out[34]:

  • 굴절지수 ( IOR - Index Of Refraction )
    • IOR : 0.5(축소됨) < 1.0(정상) < 1.5(확대됨)
    • 공기(1.0) => 얼음(1.3) => 유리(1.44) => 다이아몬드(2.44)
  • 색의 굴절 ( 색수차, Chromatic Aberration )
    • IOR : 붉은빛 < 파란빛