UnityCG.cginc 함수 설명
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
Unity-Built-in-Shaders/UnityCG.cginc at master · TwoTailsGames/Unity-Built-in-Shaders · GitHub
UnityCG.cginc의 버텍스 트랜스폼 함수
유니티 안에는 UnityCG.cginc 라고 하는, 셰이더를 위한 내장함수들이 존재합니다. 버텍스&프레그먼트 셰이더(이하 프레그먼트 셰이더) 에서 #include "UnityCG.cginc" 라고 선언하면 쓸 수 있는 명령어죠. 서피스 셰이더에서도 선언후에 버텍스 셰이더 영역에서 사용 가능합니다.
| float4 UnityObjectToClipPos(float3 pos) | 오브젝트 공간의 한 점을 동질적인 좌표에 있는 카메라의 클립 공간으로 변환합니다. mul(UNITY_MATRIX_MVP, float4(pos, 1.0))과 같으며, 이를 대신하여 사용해야 합니다. 로컬 공간(오브젝트 공간) 의 버텍스를 클립공간으로 변환합니다. 기본적으로 공간변환은 로컬 - 월드 - 뷰 - 프러스텀인데, 이걸 모델-뷰-프러스텀이라고 부르면서 MVP라고 부릅니다. 그런데 프러스텀은 니어와 파로 잘라지죠? 그러면 절두체 모양이 됩니다. 일종의 찌그러진 큐브죠. 이 큐브 영역을 0~ 1사이로 변환한 것이 클립 포지션이라 합니다. 즉 최종 영역까지 한 번에 변환하는 함수입니다. |
| float3 UnityObjectToViewPos(float3 pos) | 오브젝트 공간의 한 점을 뷰 공간으로 변환합니다. __mul(UNITY_MATRIX_MV, float4(pos, 1.0)).xyz__와 같으며, 이를 대신하여 사용해야 합니다. 로컬 공간(오브젝트 공간) 의 버텍스를 뷰 공간으로 변환합니다. 예전엔 mul 명령으로 , 모델-뷰를 곱했던 것을 그냥 한 번에 처리하는 겁니다. |
UnityCG.cginc의 일반 헬퍼 함수
버텍스 전용이 아닌, 어디서나 쓸 수 있는 함수입니다.
| float3 WorldSpaceViewDir (float4 v) | 월드 공간 방향(정규화되지 않음)을 주어진 오브젝트 공간 버텍스 포지션에서 카메라 쪽으로 되돌립니다. 월드 공간에 있는 것을 뷰 방향으로 변환합니다. float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz; |
| float3 ObjSpaceViewDir (float4 v) | 오브젝트 공간 방향(정규화되지 않음)을 주어진 오브젝트 공간 버텍스 포지션에서 카메라 쪽으로 되돌립니다. 로컬 공간에 있는 것을 뷰 방향으로 변환합니다. float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz; |
| float2 ParallaxOffset (half h, half height, half3 viewDir) | 패럴랙스 노멀 매핑의 UV 오프셋을 계산합니다. 패럴랙스 노멀을 위한 UV 계산 함수네요. 일종의 아이폰 입체 사진 같은 느낌을 말합니다. 보통 h 는 높이값이고, height는 흑백음영의 하이트맵이고 (둘이 바뀌었을지도 모르겠습니다) 뷰 디렉션을 넣어줍니다. https://chulin28ho.tistory.com/520 이 내용인데, 이 함수로 한 번 써서 해 봐야겠어요 inline float2 ParallaxOffset( half h, half height, half3 viewDir ) |
| fixed Luminance (fixed3 c) | 컬러를 휘도(그레이스케일)로 변환합니다. return dot(rgb, unity_ColorSpaceLuminance.rgb); 이렇게 되어 있는데요 unity_ColorSpaceLuminance half4(0.0396819152, 0.458021790, 0.00609653955, 1.0) 인걸로 보아서 그레이 스케일 상수를 곱해서 더해주는 방식입니다. |
| fixed3 DecodeLightmap (fixed4 color) | Unity 라이트맵에서 컬러를 디코딩합니다(플랫폼에 따라 RGBM 또는 dLDR). 모바일이냐 아니냐에 따라 달랐던걸로 기억합니다 #if defined(UNITY_LIGHTMAP_DLDR_ENCODING)
|
| float4 EncodeFloatRGBA (float v) | 정밀도가 낮은 렌더링 타겟에 저장하기 위해 [01) 범위 플로트를 RGBA 컬러로 인코딩합니다
8비트 체널로 인코딩합니다. 안써봐서 모르겠음. inline float4 EncodeFloatRGBA( float v )
|
| float DecodeFloatRGBA (float4 enc) | RGBA 컬러를 플로트로 디코딩합니다. 위 것과 반대 작용을 하는 것 같은데, 재미있는건 xyzw가 플롯, 8비트, 16비트, 24비트 칼라라는 것이네요. inline float DecodeFloatRGBA( float4 enc )
|
| float2 EncodeFloatRG (float v) | [0–1) 범위 플로트를 float2로 인코딩합니다.
위의위의 것과 동일합니다. 단 여기는 플롯과 8비트만 연산하네요 inline float2 EncodeFloatRG( float v )
|
| float DecodeFloatRG (float2 enc) | 이전에 인코딩된 RG 플로트를 디코딩합니다.
설명생략 inline float DecodeFloatRG( float2 enc )
|
| float2 EncodeViewNormalStereo (float3 n) | 뷰 공간 노멀을 범위가 01인 숫자 2개로 인코딩합니다.
이 부분은 안써봐서 모르는 거군요 inline float2 EncodeViewNormalStereo( float3 n )
|
| float3 DecodeViewNormalStereo (float4 enc4) | 뷰 공간 노멀을 enc4.xy에서 디코딩합니다.
inline float3 DecodeViewNormalStereo( float4 enc4 )
|
UnityCG.cginc의 포워드 렌더링 헬퍼 함수
이 함수는 포워드 렌더링(ForwardBase 또는 ForwardAdd 패스 타입)을 사용하는 경우에만 유용합니다.
디퍼드 렌더링에서는 안되고 포워드에서만 된다는 말이겠군요. 주로 라이트에 관계된 부분이겠지요.
| float3 WorldSpaceLightDir (float4 v) | 광원을 향한 월드 공간 방향(정규화되지 않음)을 주어진 오브젝트 공간 버텍스 포지션에 대해 계산합니다.
오브젝트(로컬) 좌표계의 버텍스 위치를 집어 넣으면, 월드 좌표계 에서의 라이트 디렉션이 나옵니다. ForwardBase 인 경우에는 디렉셔널 라이트 또는 가장 밝은 라이트가 선택될테고, 라이트가 추가되면 ForwardAdd가 실행되니 그때에는 다음 라이트가 이걸 실행하겠죠 inline float3 WorldSpaceLightDir( in float4 localPos )
|
| float3 ObjSpaceLightDir (float4 v) | 광원을 향한 오브젝트 공간 방향(정규화되지 않음)을 주어진 오브젝트 공간 버텍스 포지션에 대해 계산합니다.
위와 같습니다만, 리턴이 오브젝트(로컬) 좌표계입니다. inline float3 ObjSpaceLightDir( in float4 v )
|
| float3 Shade4PointLights (...) | 벡터에 조밀하게 채워진 광원 데이터를 사용해 점 광원 4개의 조명을 연산합니다. 포워드 렌더링에서 버텍스당 조명을 연산하는 데 사용됩니다.
이쪽은 코드가 좀 기네요. 4개까지 연산되는 포인트 라이트 연산입니다. 사용 예를 좀 찾아보고 싶군요
|
UnityCG.cginc의 스크린 공간 헬퍼 함수
다음은 스크린 공간 텍스처 샘플링에 사용되는 좌표를 계산하는 헬퍼 함수입니다. 텍스처를 샘플링할 최종 좌표를 원근 나누기(예: xy/w)를 통해 계산할 수 있는float4를 반환합니다.
함수는 렌더 텍스처 좌표의 플랫폼 차이도 처리합니다.
댑스값에 관련된 부분에 사용할때 많이 쓰는 녀석들입니다. 스크린 스페이스에서의 좌표계부분입니다.
| float4 ComputeScreenPos (float4 clipPos) | Screenspace 매핑된 텍스처 샘플링을 수행하기 위한 텍스처 좌표를 계산합니다. 입력은 클립 공간 포지션입니다.
그다지 설명할게 없습니다. 클립 스페이스를 집어 넣으면 스크린 좌표계에서의 텍스쳐 좌표계 값이 나옵니다. inline float4 ComputeScreenPos(float4 pos) {
|
| float4 ComputeGrabScreenPos (float4 clipPos) | GrabPass 텍스처를 샘플링하는 텍스처 좌표를 계산합니다. 입력은 클립 공간 포지션입니다.
마찬가지 연산을 합니다. OpenGl이냐 DirectX냐에 따라 위아래가 바뀌는 연산이 들어가 있습니다.
|
UnityCG.cginc의 버텍스 릿 헬퍼 함수
함수는 버텍스당 릿 셰이더(“Vertex” 패스 타입)를 사용하는 경우에만 유용합니다.
간단하게 버텍스 라이트 연산을 위한 함수입니다. 픽셀라이트에서는 이루어지지 않는 연산임을 주의
| float3 ShadeVertexLights (float4 vertex, float3 normal) | 버텍스당 광원 및 앰비언트 4개의 조명을 주어진 오브젝트 공간 포지션 및 노멀에 대해 계산합니다. 버텍스 라이트 연산을 하는 함수입니다. 당연히 픽셀라이트 연산으로 작동되지 않습니다.
|
| // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) | |
| #ifndef UNITY_CG_INCLUDED | |
| #define UNITY_CG_INCLUDED | |
| #define UNITY_PI 3.14159265359f | |
| #define UNITY_TWO_PI 6.28318530718f | |
| #define UNITY_FOUR_PI 12.56637061436f | |
| #define UNITY_INV_PI 0.31830988618f | |
| #define UNITY_INV_TWO_PI 0.15915494309f | |
| #define UNITY_INV_FOUR_PI 0.07957747155f | |
| #define UNITY_HALF_PI 1.57079632679f | |
| #define UNITY_INV_HALF_PI 0.636619772367f | |
| // Should SH (light probe / ambient) calculations be performed? | |
| // - When both static and dynamic lightmaps are available, no SH evaluation is performed | |
| // - When static and dynamic lightmaps are not available, SH evaluation is always performed | |
| // - For low level LODs, static lightmap and real-time GI from light probes can be combined together | |
| // - Passes that don't do ambient (additive, shadowcaster etc.) should not do SH either. | |
| #define UNITY_SHOULD_SAMPLE_SH (defined(LIGHTPROBE_SH) && !defined(UNITY_PASS_FORWARDADD) && !defined(UNITY_PASS_PREPASSBASE) && !defined(UNITY_PASS_SHADOWCASTER) && !defined(UNITY_PASS_META)) | |
| #include "UnityShaderVariables.cginc" | |
| #include "UnityShaderUtilities.cginc" | |
| #include "UnityInstancing.cginc" | |
| #ifdef UNITY_COLORSPACE_GAMMA | |
| #define unity_ColorSpaceGrey fixed4(0.5, 0.5, 0.5, 0.5) | |
| #define unity_ColorSpaceDouble fixed4(2.0, 2.0, 2.0, 2.0) | |
| #define unity_ColorSpaceDielectricSpec half4(0.220916301, 0.220916301, 0.220916301, 1.0 - 0.220916301) | |
| #define unity_ColorSpaceLuminance half4(0.22, 0.707, 0.071, 0.0) // Legacy: alpha is set to 0.0 to specify gamma mode | |
| #else // Linear values | |
| #define unity_ColorSpaceGrey fixed4(0.214041144, 0.214041144, 0.214041144, 0.5) | |
| #define unity_ColorSpaceDouble fixed4(4.59479380, 4.59479380, 4.59479380, 2.0) | |
| #define unity_ColorSpaceDielectricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%) | |
| #define unity_ColorSpaceLuminance half4(0.0396819152, 0.458021790, 0.00609653955, 1.0) // Legacy: alpha is set to 1.0 to specify linear mode | |
| #endif | |
| // ------------------------------------------------------------------- | |
| // helper functions and macros used in many standard shaders | |
| #if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE) || defined (POINT) || defined (SPOT) || defined (POINT_NOATT) || defined (POINT_COOKIE) | |
| #define USING_LIGHT_MULTI_COMPILE | |
| #endif | |
| #if defined(SHADER_API_D3D11) || defined(SHADER_API_PSSL) || defined(SHADER_API_METAL) || defined(SHADER_API_GLCORE) || defined(SHADER_API_GLES3) || defined(SHADER_API_VULKAN) || defined(SHADER_API_SWITCH) // D3D11, D3D12, XB1, PS4, iOS, macOS, tvOS, glcore, gles3, webgl2.0, Switch | |
| // Real-support for depth-format cube shadow map. | |
| #define SHADOWS_CUBE_IN_DEPTH_TEX | |
| #endif | |
| #define SCALED_NORMAL v.normal | |
| // These constants must be kept in sync with RGBMRanges.h | |
| #define LIGHTMAP_RGBM_SCALE 5.0 | |
| #define EMISSIVE_RGBM_SCALE 97.0 | |
| struct appdata_base { | |
| float4 vertex : POSITION; | |
| float3 normal : NORMAL; | |
| float4 texcoord : TEXCOORD0; | |
| UNITY_VERTEX_INPUT_INSTANCE_ID | |
| }; | |
| struct appdata_tan { | |
| float4 vertex : POSITION; | |
| float4 tangent : TANGENT; | |
| float3 normal : NORMAL; | |
| float4 texcoord : TEXCOORD0; | |
| UNITY_VERTEX_INPUT_INSTANCE_ID | |
| }; | |
| struct appdata_full { | |
| float4 vertex : POSITION; | |
| float4 tangent : TANGENT; | |
| float3 normal : NORMAL; | |
| float4 texcoord : TEXCOORD0; | |
| float4 texcoord1 : TEXCOORD1; | |
| float4 texcoord2 : TEXCOORD2; | |
| float4 texcoord3 : TEXCOORD3; | |
| fixed4 color : COLOR; | |
| UNITY_VERTEX_INPUT_INSTANCE_ID | |
| }; | |
| // Legacy for compatibility with existing shaders | |
| inline bool IsGammaSpace() | |
| { | |
| #ifdef UNITY_COLORSPACE_GAMMA | |
| return true; | |
| #else | |
| return false; | |
| #endif | |
| } | |
| inline float GammaToLinearSpaceExact (float value) | |
| { | |
| if (value <= 0.04045F) | |
| return value / 12.92F; | |
| else if (value < 1.0F) | |
| return pow((value + 0.055F)/1.055F, 2.4F); | |
| else | |
| return pow(value, 2.2F); | |
| } | |
| inline half3 GammaToLinearSpace (half3 sRGB) | |
| { | |
| // Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1 | |
| return sRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.012522878h); | |
| // Precise version, useful for debugging. | |
| //return half3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b)); | |
| } | |
| inline float LinearToGammaSpaceExact (float value) | |
| { | |
| if (value <= 0.0F) | |
| return 0.0F; | |
| else if (value <= 0.0031308F) | |
| return 12.92F * value; | |
| else if (value < 1.0F) | |
| return 1.055F * pow(value, 0.4166667F) - 0.055F; | |
| else | |
| return pow(value, 0.45454545F); | |
| } | |
| inline half3 LinearToGammaSpace (half3 linRGB) | |
| { | |
| linRGB = max(linRGB, half3(0.h, 0.h, 0.h)); | |
| // An almost-perfect approximation from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1 | |
| return max(1.055h * pow(linRGB, 0.416666667h) - 0.055h, 0.h); | |
| // Exact version, useful for debugging. | |
| //return half3(LinearToGammaSpaceExact(linRGB.r), LinearToGammaSpaceExact(linRGB.g), LinearToGammaSpaceExact(linRGB.b)); | |
| } | |
| // Tranforms position from world to homogenous space | |
| inline float4 UnityWorldToClipPos( in float3 pos ) | |
| { | |
| return mul(UNITY_MATRIX_VP, float4(pos, 1.0)); | |
| } | |
| // Tranforms position from view to homogenous space | |
| inline float4 UnityViewToClipPos( in float3 pos ) | |
| { | |
| return mul(UNITY_MATRIX_P, float4(pos, 1.0)); | |
| } | |
| // Tranforms position from object to camera space | |
| inline float3 UnityObjectToViewPos( in float3 pos ) | |
| { | |
| return mul(UNITY_MATRIX_V, mul(unity_ObjectToWorld, float4(pos, 1.0))).xyz; | |
| } | |
| inline float3 UnityObjectToViewPos(float4 pos) // overload for float4; avoids "implicit truncation" warning for existing shaders | |
| { | |
| return UnityObjectToViewPos(pos.xyz); | |
| } | |
| // Tranforms position from world to camera space | |
| inline float3 UnityWorldToViewPos( in float3 pos ) | |
| { | |
| return mul(UNITY_MATRIX_V, float4(pos, 1.0)).xyz; | |
| } | |
| // Transforms direction from object to world space | |
| inline float3 UnityObjectToWorldDir( in float3 dir ) | |
| { | |
| return normalize(mul((float3x3)unity_ObjectToWorld, dir)); | |
| } | |
| // Transforms direction from world to object space | |
| inline float3 UnityWorldToObjectDir( in float3 dir ) | |
| { | |
| return normalize(mul((float3x3)unity_WorldToObject, dir)); | |
| } | |
| // Transforms normal from object to world space | |
| inline float3 UnityObjectToWorldNormal( in float3 norm ) | |
| { | |
| #ifdef UNITY_ASSUME_UNIFORM_SCALING | |
| return UnityObjectToWorldDir(norm); | |
| #else | |
| // mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)} | |
| return normalize(mul(norm, (float3x3)unity_WorldToObject)); | |
| #endif | |
| } | |
| // Computes world space light direction, from world space position | |
| inline float3 UnityWorldSpaceLightDir( in float3 worldPos ) | |
| { | |
| #ifndef USING_LIGHT_MULTI_COMPILE | |
| return _WorldSpaceLightPos0.xyz - worldPos * _WorldSpaceLightPos0.w; | |
| #else | |
| #ifndef USING_DIRECTIONAL_LIGHT | |
| return _WorldSpaceLightPos0.xyz - worldPos; | |
| #else | |
| return _WorldSpaceLightPos0.xyz; | |
| #endif | |
| #endif | |
| } | |
| // Computes world space light direction, from object space position | |
| // *Legacy* Please use UnityWorldSpaceLightDir instead | |
| inline float3 WorldSpaceLightDir( in float4 localPos ) | |
| { | |
| float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz; | |
| return UnityWorldSpaceLightDir(worldPos); | |
| } | |
| // Computes object space light direction | |
| inline float3 ObjSpaceLightDir( in float4 v ) | |
| { | |
| float3 objSpaceLightPos = mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz; | |
| #ifndef USING_LIGHT_MULTI_COMPILE | |
| return objSpaceLightPos.xyz - v.xyz * _WorldSpaceLightPos0.w; | |
| #else | |
| #ifndef USING_DIRECTIONAL_LIGHT | |
| return objSpaceLightPos.xyz - v.xyz; | |
| #else | |
| return objSpaceLightPos.xyz; | |
| #endif | |
| #endif | |
| } | |
| // Computes world space view direction, from object space position | |
| inline float3 UnityWorldSpaceViewDir( in float3 worldPos ) | |
| { | |
| return _WorldSpaceCameraPos.xyz - worldPos; | |
| } | |
| // Computes world space view direction, from object space position | |
| // *Legacy* Please use UnityWorldSpaceViewDir instead | |
| inline float3 WorldSpaceViewDir( in float4 localPos ) | |
| { | |
| float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz; | |
| return UnityWorldSpaceViewDir(worldPos); | |
| } | |
| // Computes object space view direction | |
| inline float3 ObjSpaceViewDir( in float4 v ) | |
| { | |
| float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz; | |
| return objSpaceCameraPos - v.xyz; | |
| } | |
| // Declares 3x3 matrix 'rotation', filled with tangent space basis | |
| #define TANGENT_SPACE_ROTATION \ | |
| float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; \ | |
| float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal ) | |
| // Used in ForwardBase pass: Calculates diffuse lighting from 4 point lights, with data packed in a special way. | |
| float3 Shade4PointLights ( | |
| float4 lightPosX, float4 lightPosY, float4 lightPosZ, | |
| float3 lightColor0, float3 lightColor1, float3 lightColor2, float3 lightColor3, | |
| float4 lightAttenSq, | |
| float3 pos, float3 normal) | |
| { | |
| // to light vectors | |
| float4 toLightX = lightPosX - pos.x; | |
| float4 toLightY = lightPosY - pos.y; | |
| float4 toLightZ = lightPosZ - pos.z; | |
| // squared lengths | |
| float4 lengthSq = 0; | |
| lengthSq += toLightX * toLightX; | |
| lengthSq += toLightY * toLightY; | |
| lengthSq += toLightZ * toLightZ; | |
| // don't produce NaNs if some vertex position overlaps with the light | |
| lengthSq = max(lengthSq, 0.000001); | |
| // NdotL | |
| float4 ndotl = 0; | |
| ndotl += toLightX * normal.x; | |
| ndotl += toLightY * normal.y; | |
| ndotl += toLightZ * normal.z; | |
| // correct NdotL | |
| float4 corr = rsqrt(lengthSq); | |
| ndotl = max (float4(0,0,0,0), ndotl * corr); | |
| // attenuation | |
| float4 atten = 1.0 / (1.0 + lengthSq * lightAttenSq); | |
| float4 diff = ndotl * atten; | |
| // final color | |
| float3 col = 0; | |
| col += lightColor0 * diff.x; | |
| col += lightColor1 * diff.y; | |
| col += lightColor2 * diff.z; | |
| col += lightColor3 * diff.w; | |
| return col; | |
| } | |
| // Used in Vertex pass: Calculates diffuse lighting from lightCount lights. Specifying true to spotLight is more expensive | |
| // to calculate but lights are treated as spot lights otherwise they are treated as point lights. | |
| float3 ShadeVertexLightsFull (float4 vertex, float3 normal, int lightCount, bool spotLight) | |
| { | |
| float3 viewpos = UnityObjectToViewPos (vertex.xyz); | |
| float3 viewN = normalize (mul ((float3x3)UNITY_MATRIX_IT_MV, normal)); | |
| float3 lightColor = UNITY_LIGHTMODEL_AMBIENT.xyz; | |
| for (int i = 0; i < lightCount; i++) { | |
| float3 toLight = unity_LightPosition[i].xyz - viewpos.xyz * unity_LightPosition[i].w; | |
| float lengthSq = dot(toLight, toLight); | |
| // don't produce NaNs if some vertex position overlaps with the light | |
| lengthSq = max(lengthSq, 0.000001); | |
| toLight *= rsqrt(lengthSq); | |
| float atten = 1.0 / (1.0 + lengthSq * unity_LightAtten[i].z); | |
| if (spotLight) | |
| { | |
| float rho = max (0, dot(toLight, unity_SpotDirection[i].xyz)); | |
| float spotAtt = (rho - unity_LightAtten[i].x) * unity_LightAtten[i].y; | |
| atten *= saturate(spotAtt); | |
| } | |
| float diff = max (0, dot (viewN, toLight)); | |
| lightColor += unity_LightColor[i].rgb * (diff * atten); | |
| } | |
| return lightColor; | |
| } | |
| float3 ShadeVertexLights (float4 vertex, float3 normal) | |
| { | |
| return ShadeVertexLightsFull (vertex, normal, 4, false); | |
| } | |
| // normal should be normalized, w=1.0 | |
| half3 SHEvalLinearL0L1 (half4 normal) | |
| { | |
| half3 x; | |
| // Linear (L1) + constant (L0) polynomial terms | |
| x.r = dot(unity_SHAr,normal); | |
| x.g = dot(unity_SHAg,normal); | |
| x.b = dot(unity_SHAb,normal); | |
| return x; | |
| } | |
| // normal should be normalized, w=1.0 | |
| half3 SHEvalLinearL2 (half4 normal) | |
| { | |
| half3 x1, x2; | |
| // 4 of the quadratic (L2) polynomials | |
| half4 vB = normal.xyzz * normal.yzzx; | |
| x1.r = dot(unity_SHBr,vB); | |
| x1.g = dot(unity_SHBg,vB); | |
| x1.b = dot(unity_SHBb,vB); | |
| // Final (5th) quadratic (L2) polynomial | |
| half vC = normal.x*normal.x - normal.y*normal.y; | |
| x2 = unity_SHC.rgb * vC; | |
| return x1 + x2; | |
| } | |
| // normal should be normalized, w=1.0 | |
| // output in active color space | |
| half3 ShadeSH9 (half4 normal) | |
| { | |
| // Linear + constant polynomial terms | |
| half3 res = SHEvalLinearL0L1 (normal); | |
| // Quadratic polynomials | |
| res += SHEvalLinearL2 (normal); | |
| # ifdef UNITY_COLORSPACE_GAMMA | |
| res = LinearToGammaSpace (res); | |
| # endif | |
| return res; | |
| } | |
| // OBSOLETE: for backwards compatibility with 5.0 | |
| half3 ShadeSH3Order(half4 normal) | |
| { | |
| // Quadratic polynomials | |
| half3 res = SHEvalLinearL2 (normal); | |
| # ifdef UNITY_COLORSPACE_GAMMA | |
| res = LinearToGammaSpace (res); | |
| # endif | |
| return res; | |
| } | |
| #if UNITY_LIGHT_PROBE_PROXY_VOLUME | |
| // normal should be normalized, w=1.0 | |
| half3 SHEvalLinearL0L1_SampleProbeVolume (half4 normal, float3 worldPos) | |
| { | |
| const float transformToLocal = unity_ProbeVolumeParams.y; | |
| const float texelSizeX = unity_ProbeVolumeParams.z; | |
| //The SH coefficients textures and probe occlusion are packed into 1 atlas. | |
| //------------------------- | |
| //| ShR | ShG | ShB | Occ | | |
| //------------------------- | |
| float3 position = (transformToLocal == 1.0f) ? mul(unity_ProbeVolumeWorldToObject, float4(worldPos, 1.0)).xyz : worldPos; | |
| float3 texCoord = (position - unity_ProbeVolumeMin.xyz) * unity_ProbeVolumeSizeInv.xyz; | |
| texCoord.x = texCoord.x * 0.25f; | |
| // We need to compute proper X coordinate to sample. | |
| // Clamp the coordinate otherwize we'll have leaking between RGB coefficients | |
| float texCoordX = clamp(texCoord.x, 0.5f * texelSizeX, 0.25f - 0.5f * texelSizeX); | |
| // sampler state comes from SHr (all SH textures share the same sampler) | |
| texCoord.x = texCoordX; | |
| half4 SHAr = UNITY_SAMPLE_TEX3D_SAMPLER(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord); | |
| texCoord.x = texCoordX + 0.25f; | |
| half4 SHAg = UNITY_SAMPLE_TEX3D_SAMPLER(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord); | |
| texCoord.x = texCoordX + 0.5f; | |
| half4 SHAb = UNITY_SAMPLE_TEX3D_SAMPLER(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord); | |
| // Linear + constant polynomial terms | |
| half3 x1; | |
| x1.r = dot(SHAr, normal); | |
| x1.g = dot(SHAg, normal); | |
| x1.b = dot(SHAb, normal); | |
| return x1; | |
| } | |
| #endif | |
| // normal should be normalized, w=1.0 | |
| half3 ShadeSH12Order (half4 normal) | |
| { | |
| // Linear + constant polynomial terms | |
| half3 res = SHEvalLinearL0L1 (normal); | |
| # ifdef UNITY_COLORSPACE_GAMMA | |
| res = LinearToGammaSpace (res); | |
| # endif | |
| return res; | |
| } | |
| // Transforms 2D UV by scale/bias property | |
| #define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw) | |
| // Deprecated. Used to transform 4D UV by a fixed function texture matrix. Now just returns the passed UV. | |
| #define TRANSFORM_UV(idx) v.texcoord.xy | |
| struct v2f_vertex_lit { | |
| float2 uv : TEXCOORD0; | |
| fixed4 diff : COLOR0; | |
| fixed4 spec : COLOR1; | |
| }; | |
| inline fixed4 VertexLight( v2f_vertex_lit i, sampler2D mainTex ) | |
| { | |
| fixed4 texcol = tex2D( mainTex, i.uv ); | |
| fixed4 c; | |
| c.xyz = ( texcol.xyz * i.diff.xyz + i.spec.xyz * texcol.a ); | |
| c.w = texcol.w * i.diff.w; | |
| return c; | |
| } | |
| // Calculates UV offset for parallax bump mapping | |
| inline float2 ParallaxOffset( half h, half height, half3 viewDir ) | |
| { | |
| h = h * height - height/2.0; | |
| float3 v = normalize(viewDir); | |
| v.z += 0.42; | |
| return h * (v.xy / v.z); | |
| } | |
| // Converts color to luminance (grayscale) | |
| inline half Luminance(half3 rgb) | |
| { | |
| return dot(rgb, unity_ColorSpaceLuminance.rgb); | |
| } | |
| // Convert rgb to luminance | |
| // with rgb in linear space with sRGB primaries and D65 white point | |
| half LinearRgbToLuminance(half3 linearRgb) | |
| { | |
| return dot(linearRgb, half3(0.2126729f, 0.7151522f, 0.0721750f)); | |
| } | |
| half4 UnityEncodeRGBM (half3 color, float maxRGBM) | |
| { | |
| float kOneOverRGBMMaxRange = 1.0 / maxRGBM; | |
| const float kMinMultiplier = 2.0 * 1e-2; | |
| float3 rgb = color * kOneOverRGBMMaxRange; | |
| float alpha = max(max(rgb.r, rgb.g), max(rgb.b, kMinMultiplier)); | |
| alpha = ceil(alpha * 255.0) / 255.0; | |
| // Division-by-zero warning from d3d9, so make compiler happy. | |
| alpha = max(alpha, kMinMultiplier); | |
| return half4(rgb / alpha, alpha); | |
| } | |
| // Decodes HDR textures | |
| // handles dLDR, RGBM formats | |
| inline half3 DecodeHDR (half4 data, half4 decodeInstructions) | |
| { | |
| // Take into account texture alpha if decodeInstructions.w is true(the alpha value affects the RGB channels) | |
| half alpha = decodeInstructions.w * (data.a - 1.0) + 1.0; | |
| // If Linear mode is not supported we can skip exponent part | |
| #if defined(UNITY_COLORSPACE_GAMMA) | |
| return (decodeInstructions.x * alpha) * data.rgb; | |
| #else | |
| # if defined(UNITY_USE_NATIVE_HDR) | |
| return decodeInstructions.x * data.rgb; // Multiplier for future HDRI relative to absolute conversion. | |
| # else | |
| return (decodeInstructions.x * pow(alpha, decodeInstructions.y)) * data.rgb; | |
| # endif | |
| #endif | |
| } | |
| // Decodes HDR textures | |
| // handles dLDR, RGBM formats | |
| inline half3 DecodeLightmapRGBM (half4 data, half4 decodeInstructions) | |
| { | |
| // If Linear mode is not supported we can skip exponent part | |
| #if defined(UNITY_COLORSPACE_GAMMA) | |
| # if defined(UNITY_FORCE_LINEAR_READ_FOR_RGBM) | |
| return (decodeInstructions.x * data.a) * sqrt(data.rgb); | |
| # else | |
| return (decodeInstructions.x * data.a) * data.rgb; | |
| # endif | |
| #else | |
| return (decodeInstructions.x * pow(data.a, decodeInstructions.y)) * data.rgb; | |
| #endif | |
| } | |
| // Decodes doubleLDR encoded lightmaps. | |
| inline half3 DecodeLightmapDoubleLDR( fixed4 color, half4 decodeInstructions) | |
| { | |
| // decodeInstructions.x contains 2.0 when gamma color space is used or pow(2.0, 2.2) = 4.59 when linear color space is used on mobile platforms | |
| return decodeInstructions.x * color.rgb; | |
| } | |
| inline half3 DecodeLightmap( fixed4 color, half4 decodeInstructions) | |
| { | |
| #if defined(UNITY_LIGHTMAP_DLDR_ENCODING) | |
| return DecodeLightmapDoubleLDR(color, decodeInstructions); | |
| #elif defined(UNITY_LIGHTMAP_RGBM_ENCODING) | |
| return DecodeLightmapRGBM(color, decodeInstructions); | |
| #else //defined(UNITY_LIGHTMAP_FULL_HDR) | |
| return color.rgb; | |
| #endif | |
| } | |
| half4 unity_Lightmap_HDR; | |
| inline half3 DecodeLightmap( fixed4 color ) | |
| { | |
| return DecodeLightmap( color, unity_Lightmap_HDR ); | |
| } | |
| half4 unity_DynamicLightmap_HDR; | |
| // Decodes Enlighten RGBM encoded lightmaps | |
| // NOTE: Enlighten dynamic texture RGBM format is _different_ from standard Unity HDR textures | |
| // (such as Baked Lightmaps, Reflection Probes and IBL images) | |
| // Instead Enlighten provides RGBM texture in _Linear_ color space with _different_ exponent. | |
| // WARNING: 3 pow operations, might be very expensive for mobiles! | |
| inline half3 DecodeRealtimeLightmap( fixed4 color ) | |
| { | |
| //@TODO: Temporary until Geomerics gives us an API to convert lightmaps to RGBM in gamma space on the enlighten thread before we upload the textures. | |
| #if defined(UNITY_FORCE_LINEAR_READ_FOR_RGBM) | |
| return pow ((unity_DynamicLightmap_HDR.x * color.a) * sqrt(color.rgb), unity_DynamicLightmap_HDR.y); | |
| #else | |
| return pow ((unity_DynamicLightmap_HDR.x * color.a) * color.rgb, unity_DynamicLightmap_HDR.y); | |
| #endif | |
| } | |
| inline half3 DecodeDirectionalLightmap (half3 color, fixed4 dirTex, half3 normalWorld) | |
| { | |
| // In directional (non-specular) mode Enlighten bakes dominant light direction | |
| // in a way, that using it for half Lambert and then dividing by a "rebalancing coefficient" | |
| // gives a result close to plain diffuse response lightmaps, but normalmapped. | |
| // Note that dir is not unit length on purpose. Its length is "directionality", like | |
| // for the directional specular lightmaps. | |
| half halfLambert = dot(normalWorld, dirTex.xyz - 0.5) + 0.5; | |
| return color * halfLambert / max(1e-4h, dirTex.w); | |
| } | |
| // Encoding/decoding [0..1) floats into 8 bit/channel RGBA. Note that 1.0 will not be encoded properly. | |
| inline float4 EncodeFloatRGBA( float v ) | |
| { | |
| float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 16581375.0); | |
| float kEncodeBit = 1.0/255.0; | |
| float4 enc = kEncodeMul * v; | |
| enc = frac (enc); | |
| enc -= enc.yzww * kEncodeBit; | |
| return enc; | |
| } | |
| inline float DecodeFloatRGBA( float4 enc ) | |
| { | |
| float4 kDecodeDot = float4(1.0, 1/255.0, 1/65025.0, 1/16581375.0); | |
| return dot( enc, kDecodeDot ); | |
| } | |
| // Encoding/decoding [0..1) floats into 8 bit/channel RG. Note that 1.0 will not be encoded properly. | |
| inline float2 EncodeFloatRG( float v ) | |
| { | |
| float2 kEncodeMul = float2(1.0, 255.0); | |
| float kEncodeBit = 1.0/255.0; | |
| float2 enc = kEncodeMul * v; | |
| enc = frac (enc); | |
| enc.x -= enc.y * kEncodeBit; | |
| return enc; | |
| } | |
| inline float DecodeFloatRG( float2 enc ) | |
| { | |
| float2 kDecodeDot = float2(1.0, 1/255.0); | |
| return dot( enc, kDecodeDot ); | |
| } | |
| // Encoding/decoding view space normals into 2D 0..1 vector | |
| inline float2 EncodeViewNormalStereo( float3 n ) | |
| { | |
| float kScale = 1.7777; | |
| float2 enc; | |
| enc = n.xy / (n.z+1); | |
| enc /= kScale; | |
| enc = enc*0.5+0.5; | |
| return enc; | |
| } | |
| inline float3 DecodeViewNormalStereo( float4 enc4 ) | |
| { | |
| float kScale = 1.7777; | |
| float3 nn = enc4.xyz*float3(2*kScale,2*kScale,0) + float3(-kScale,-kScale,1); | |
| float g = 2.0 / dot(nn.xyz,nn.xyz); | |
| float3 n; | |
| n.xy = g*nn.xy; | |
| n.z = g-1; | |
| return n; | |
| } | |
| inline float4 EncodeDepthNormal( float depth, float3 normal ) | |
| { | |
| float4 enc; | |
| enc.xy = EncodeViewNormalStereo (normal); | |
| enc.zw = EncodeFloatRG (depth); | |
| return enc; | |
| } | |
| inline void DecodeDepthNormal( float4 enc, out float depth, out float3 normal ) | |
| { | |
| depth = DecodeFloatRG (enc.zw); | |
| normal = DecodeViewNormalStereo (enc); | |
| } | |
| inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal) | |
| { | |
| fixed3 normal; | |
| normal.xy = packednormal.wy * 2 - 1; | |
| normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy))); | |
| return normal; | |
| } | |
| // Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1) | |
| // Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5 | |
| fixed3 UnpackNormalmapRGorAG(fixed4 packednormal) | |
| { | |
| // This do the trick | |
| packednormal.x *= packednormal.w; | |
| fixed3 normal; | |
| normal.xy = packednormal.xy * 2 - 1; | |
| normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy))); | |
| return normal; | |
| } | |
| inline fixed3 UnpackNormal(fixed4 packednormal) | |
| { | |
| #if defined(UNITY_NO_DXT5nm) | |
| return packednormal.xyz * 2 - 1; | |
| #else | |
| return UnpackNormalmapRGorAG(packednormal); | |
| #endif | |
| } | |
| fixed3 UnpackNormalWithScale(fixed4 packednormal, float scale) | |
| { | |
| #ifndef UNITY_NO_DXT5nm | |
| // Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1) | |
| // Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5 | |
| packednormal.x *= packednormal.w; | |
| #endif | |
| fixed3 normal; | |
| normal.xy = (packednormal.xy * 2 - 1) * scale; | |
| normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy))); | |
| return normal; | |
| } | |
| // Z buffer to linear 0..1 depth | |
| inline float Linear01Depth( float z ) | |
| { | |
| return 1.0 / (_ZBufferParams.x * z + _ZBufferParams.y); | |
| } | |
| // Z buffer to linear depth | |
| inline float LinearEyeDepth( float z ) | |
| { | |
| return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w); | |
| } | |
| inline float2 UnityStereoScreenSpaceUVAdjustInternal(float2 uv, float4 scaleAndOffset) | |
| { | |
| return uv.xy * scaleAndOffset.xy + scaleAndOffset.zw; | |
| } | |
| inline float4 UnityStereoScreenSpaceUVAdjustInternal(float4 uv, float4 scaleAndOffset) | |
| { | |
| return float4(UnityStereoScreenSpaceUVAdjustInternal(uv.xy, scaleAndOffset), UnityStereoScreenSpaceUVAdjustInternal(uv.zw, scaleAndOffset)); | |
| } | |
| #define UnityStereoScreenSpaceUVAdjust(x, y) UnityStereoScreenSpaceUVAdjustInternal(x, y) | |
| #if defined(UNITY_SINGLE_PASS_STEREO) | |
| float2 TransformStereoScreenSpaceTex(float2 uv, float w) | |
| { | |
| float4 scaleOffset = unity_StereoScaleOffset[unity_StereoEyeIndex]; | |
| return uv.xy * scaleOffset.xy + scaleOffset.zw * w; | |
| } | |
| inline float2 UnityStereoTransformScreenSpaceTex(float2 uv) | |
| { | |
| return TransformStereoScreenSpaceTex(saturate(uv), 1.0); | |
| } | |
| inline float4 UnityStereoTransformScreenSpaceTex(float4 uv) | |
| { | |
| return float4(UnityStereoTransformScreenSpaceTex(uv.xy), UnityStereoTransformScreenSpaceTex(uv.zw)); | |
| } | |
| inline float2 UnityStereoClamp(float2 uv, float4 scaleAndOffset) | |
| { | |
| return float2(clamp(uv.x, scaleAndOffset.z, scaleAndOffset.z + scaleAndOffset.x), uv.y); | |
| } | |
| #else | |
| #define TransformStereoScreenSpaceTex(uv, w) uv | |
| #define UnityStereoTransformScreenSpaceTex(uv) uv | |
| #define UnityStereoClamp(uv, scaleAndOffset) uv | |
| #endif | |
| // Depth render texture helpers | |
| #define DECODE_EYEDEPTH(i) LinearEyeDepth(i) | |
| #define COMPUTE_EYEDEPTH(o) o = -UnityObjectToViewPos( v.vertex ).z | |
| #define COMPUTE_DEPTH_01 -(UnityObjectToViewPos( v.vertex ).z * _ProjectionParams.w) | |
| #define COMPUTE_VIEW_NORMAL normalize(mul((float3x3)UNITY_MATRIX_IT_MV, v.normal)) | |
| // Helpers used in image effects. Most image effects use the same | |
| // minimal vertex shader (vert_img). | |
| struct appdata_img | |
| { | |
| float4 vertex : POSITION; | |
| half2 texcoord : TEXCOORD0; | |
| UNITY_VERTEX_INPUT_INSTANCE_ID | |
| }; | |
| struct v2f_img | |
| { | |
| float4 pos : SV_POSITION; | |
| half2 uv : TEXCOORD0; | |
| UNITY_VERTEX_INPUT_INSTANCE_ID | |
| UNITY_VERTEX_OUTPUT_STEREO | |
| }; | |
| float2 MultiplyUV (float4x4 mat, float2 inUV) { | |
| float4 temp = float4 (inUV.x, inUV.y, 0, 0); | |
| temp = mul (mat, temp); | |
| return temp.xy; | |
| } | |
| v2f_img vert_img( appdata_img v ) | |
| { | |
| v2f_img o; | |
| UNITY_INITIALIZE_OUTPUT(v2f_img, o); | |
| UNITY_SETUP_INSTANCE_ID(v); | |
| UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); | |
| o.pos = UnityObjectToClipPos (v.vertex); | |
| o.uv = v.texcoord; | |
| return o; | |
| } | |
| // Projected screen position helpers | |
| #define V2F_SCREEN_TYPE float4 | |
| inline float4 ComputeNonStereoScreenPos(float4 pos) { | |
| float4 o = pos * 0.5f; | |
| o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w; | |
| o.zw = pos.zw; | |
| return o; | |
| } | |
| inline float4 ComputeScreenPos(float4 pos) { | |
| float4 o = ComputeNonStereoScreenPos(pos); | |
| #if defined(UNITY_SINGLE_PASS_STEREO) | |
| o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w); | |
| #endif | |
| return o; | |
| } | |
| inline float4 ComputeGrabScreenPos (float4 pos) { | |
| #if UNITY_UV_STARTS_AT_TOP | |
| float scale = -1.0; | |
| #else | |
| float scale = 1.0; | |
| #endif | |
| float4 o = pos * 0.5f; | |
| o.xy = float2(o.x, o.y*scale) + o.w; | |
| #ifdef UNITY_SINGLE_PASS_STEREO | |
| o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w); | |
| #endif | |
| o.zw = pos.zw; | |
| return o; | |
| } | |
| // snaps post-transformed position to screen pixels | |
| inline float4 UnityPixelSnap (float4 pos) | |
| { | |
| float2 hpc = _ScreenParams.xy * 0.5f; | |
| #if SHADER_API_PSSL | |
| // An old sdk used to implement round() as floor(x+0.5) current sdks use the round to even method so we manually use the old method here for compatabilty. | |
| float2 temp = ((pos.xy / pos.w) * hpc) + float2(0.5f,0.5f); | |
| float2 pixelPos = float2(floor(temp.x), floor(temp.y)); | |
| #else | |
| float2 pixelPos = round ((pos.xy / pos.w) * hpc); | |
| #endif | |
| pos.xy = pixelPos / hpc * pos.w; | |
| return pos; | |
| } | |
| inline float2 TransformViewToProjection (float2 v) { | |
| return mul((float2x2)UNITY_MATRIX_P, v); | |
| } | |
| inline float3 TransformViewToProjection (float3 v) { | |
| return mul((float3x3)UNITY_MATRIX_P, v); | |
| } | |
| // Shadow caster pass helpers | |
| float4 UnityEncodeCubeShadowDepth (float z) | |
| { | |
| #ifdef UNITY_USE_RGBA_FOR_POINT_SHADOWS | |
| return EncodeFloatRGBA (min(z, 0.999)); | |
| #else | |
| return z; | |
| #endif | |
| } | |
| float UnityDecodeCubeShadowDepth (float4 vals) | |
| { | |
| #ifdef UNITY_USE_RGBA_FOR_POINT_SHADOWS | |
| return DecodeFloatRGBA (vals); | |
| #else | |
| return vals.r; | |
| #endif | |
| } | |
| float4 UnityClipSpaceShadowCasterPos(float4 vertex, float3 normal) | |
| { | |
| float4 wPos = mul(unity_ObjectToWorld, vertex); | |
| if (unity_LightShadowBias.z != 0.0) | |
| { | |
| float3 wNormal = UnityObjectToWorldNormal(normal); | |
| float3 wLight = normalize(UnityWorldSpaceLightDir(wPos.xyz)); | |
| // apply normal offset bias (inset position along the normal) | |
| // bias needs to be scaled by sine between normal and light direction | |
| // (http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/) | |
| // | |
| // unity_LightShadowBias.z contains user-specified normal offset amount | |
| // scaled by world space texel size. | |
| float shadowCos = dot(wNormal, wLight); | |
| float shadowSine = sqrt(1-shadowCos*shadowCos); | |
| float normalBias = unity_LightShadowBias.z * shadowSine; | |
| wPos.xyz -= wNormal * normalBias; | |
| } | |
| return mul(UNITY_MATRIX_VP, wPos); | |
| } | |
| // Legacy, not used anymore; kept around to not break existing user shaders | |
| float4 UnityClipSpaceShadowCasterPos(float3 vertex, float3 normal) | |
| { | |
| return UnityClipSpaceShadowCasterPos(float4(vertex, 1), normal); | |
| } | |
| float4 UnityApplyLinearShadowBias(float4 clipPos) | |
| { | |
| // For point lights that support depth cube map, the bias is applied in the fragment shader sampling the shadow map. | |
| // This is because the legacy behaviour for point light shadow map cannot be implemented by offseting the vertex position | |
| // in the vertex shader generating the shadow map. | |
| #if !(defined(SHADOWS_CUBE) && defined(SHADOWS_CUBE_IN_DEPTH_TEX)) | |
| #if defined(UNITY_REVERSED_Z) | |
| // We use max/min instead of clamp to ensure proper handling of the rare case | |
| // where both numerator and denominator are zero and the fraction becomes NaN. | |
| clipPos.z += max(-1, min(unity_LightShadowBias.x / clipPos.w, 0)); | |
| #else | |
| clipPos.z += saturate(unity_LightShadowBias.x/clipPos.w); | |
| #endif | |
| #endif | |
| #if defined(UNITY_REVERSED_Z) | |
| float clamped = min(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE); | |
| #else | |
| float clamped = max(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE); | |
| #endif | |
| clipPos.z = lerp(clipPos.z, clamped, unity_LightShadowBias.y); | |
| return clipPos; | |
| } | |
| #if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX) | |
| // Rendering into point light (cubemap) shadows | |
| #define V2F_SHADOW_CASTER_NOPOS float3 vec : TEXCOORD0; | |
| #define TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,opos) o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz; opos = UnityObjectToClipPos(v.vertex); | |
| #define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz; opos = UnityObjectToClipPos(v.vertex); | |
| #define SHADOW_CASTER_FRAGMENT(i) return UnityEncodeCubeShadowDepth ((length(i.vec) + unity_LightShadowBias.x) * _LightPositionRange.w); | |
| #else | |
| // Rendering into directional or spot light shadows | |
| #define V2F_SHADOW_CASTER_NOPOS | |
| // Let embedding code know that V2F_SHADOW_CASTER_NOPOS is empty; so that it can workaround | |
| // empty structs that could possibly be produced. | |
| #define V2F_SHADOW_CASTER_NOPOS_IS_EMPTY | |
| #define TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,opos) \ | |
| opos = UnityObjectToClipPos(v.vertex.xyz); \ | |
| opos = UnityApplyLinearShadowBias(opos); | |
| #define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) \ | |
| opos = UnityClipSpaceShadowCasterPos(v.vertex, v.normal); \ | |
| opos = UnityApplyLinearShadowBias(opos); | |
| #define SHADOW_CASTER_FRAGMENT(i) return 0; | |
| #endif | |
| // Declare all data needed for shadow caster pass output (any shadow directions/depths/distances as needed), | |
| // plus clip space position. | |
| #define V2F_SHADOW_CASTER V2F_SHADOW_CASTER_NOPOS UNITY_POSITION(pos) | |
| // Vertex shader part, with support for normal offset shadows. Requires | |
| // position and normal to be present in the vertex input. | |
| #define TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) TRANSFER_SHADOW_CASTER_NOPOS(o,o.pos) | |
| // Vertex shader part, legacy. No support for normal offset shadows - because | |
| // that would require vertex normals, which might not be present in user-written shaders. | |
| #define TRANSFER_SHADOW_CASTER(o) TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,o.pos) | |
| // ------------------------------------------------------------------ | |
| // Alpha helper | |
| #define UNITY_OPAQUE_ALPHA(outputAlpha) outputAlpha = 1.0 | |
| // ------------------------------------------------------------------ | |
| // Fog helpers | |
| // | |
| // multi_compile_fog Will compile fog variants. | |
| // UNITY_FOG_COORDS(texcoordindex) Declares the fog data interpolator. | |
| // UNITY_TRANSFER_FOG(outputStruct,clipspacePos) Outputs fog data from the vertex shader. | |
| // UNITY_APPLY_FOG(fogData,col) Applies fog to color "col". Automatically applies black fog when in forward-additive pass. | |
| // Can also use UNITY_APPLY_FOG_COLOR to supply your own fog color. | |
| // In case someone by accident tries to compile fog code in one of the g-buffer or shadow passes: | |
| // treat it as fog is off. | |
| #if defined(UNITY_PASS_PREPASSBASE) || defined(UNITY_PASS_DEFERRED) || defined(UNITY_PASS_SHADOWCASTER) | |
| #undef FOG_LINEAR | |
| #undef FOG_EXP | |
| #undef FOG_EXP2 | |
| #endif | |
| #if defined(UNITY_REVERSED_Z) | |
| #if UNITY_REVERSED_Z == 1 | |
| //D3d with reversed Z => z clip range is [near, 0] -> remapping to [0, far] | |
| //max is required to protect ourselves from near plane not being correct/meaningfull in case of oblique matrices. | |
| #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(((1.0-(coord)/_ProjectionParams.y)*_ProjectionParams.z),0) | |
| #else | |
| //GL with reversed z => z clip range is [near, -far] -> should remap in theory but dont do it in practice to save some perf (range is close enough) | |
| #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(-(coord), 0) | |
| #endif | |
| #elif UNITY_UV_STARTS_AT_TOP | |
| //D3d without reversed z => z clip range is [0, far] -> nothing to do | |
| #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord) | |
| #else | |
| //Opengl => z clip range is [-near, far] -> should remap in theory but dont do it in practice to save some perf (range is close enough) | |
| #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord) | |
| #endif | |
| #if defined(FOG_LINEAR) | |
| // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start)) | |
| #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = (coord) * unity_FogParams.z + unity_FogParams.w | |
| #elif defined(FOG_EXP) | |
| // factor = exp(-density*z) | |
| #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.y * (coord); unityFogFactor = exp2(-unityFogFactor) | |
| #elif defined(FOG_EXP2) | |
| // factor = exp(-(density*z)^2) | |
| #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.x * (coord); unityFogFactor = exp2(-unityFogFactor*unityFogFactor) | |
| #else | |
| #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = 0.0 | |
| #endif | |
| #define UNITY_CALC_FOG_FACTOR(coord) UNITY_CALC_FOG_FACTOR_RAW(UNITY_Z_0_FAR_FROM_CLIPSPACE(coord)) | |
| #define UNITY_FOG_COORDS_PACKED(idx, vectype) vectype fogCoord : TEXCOORD##idx; | |
| #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) | |
| #define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1) | |
| #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE) | |
| // mobile or SM2.0: calculate fog factor per-vertex | |
| #define UNITY_TRANSFER_FOG(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.fogCoord.x = unityFogFactor | |
| #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.tSpace1.y = tangentSign; o.tSpace2.y = unityFogFactor | |
| #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.worldPos.w = unityFogFactor | |
| #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.eyeVec.w = unityFogFactor | |
| #else | |
| // SM3.0 and PC/console: calculate fog distance per-vertex, and fog factor per-pixel | |
| #define UNITY_TRANSFER_FOG(o,outpos) o.fogCoord.x = (outpos).z | |
| #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) o.tSpace2.y = (outpos).z | |
| #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) o.worldPos.w = (outpos).z | |
| #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) o.eyeVec.w = (outpos).z | |
| #endif | |
| #else | |
| #define UNITY_FOG_COORDS(idx) | |
| #define UNITY_TRANSFER_FOG(o,outpos) | |
| #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) | |
| #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) | |
| #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) | |
| #endif | |
| #define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) col.rgb = lerp((fogCol).rgb, (col).rgb, saturate(fogFac)) | |
| #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) | |
| #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE) | |
| // mobile or SM2.0: fog factor was already calculated per-vertex, so just lerp the color | |
| #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_FOG_LERP_COLOR(col,fogCol,(coord).x) | |
| #else | |
| // SM3.0 and PC/console: calculate fog factor and lerp fog color | |
| #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_CALC_FOG_FACTOR((coord).x); UNITY_FOG_LERP_COLOR(col,fogCol,unityFogFactor) | |
| #endif | |
| #define UNITY_EXTRACT_FOG(name) float _unity_fogCoord = name.fogCoord | |
| #define UNITY_EXTRACT_FOG_FROM_TSPACE(name) float _unity_fogCoord = name.tSpace2.y | |
| #define UNITY_EXTRACT_FOG_FROM_WORLD_POS(name) float _unity_fogCoord = name.worldPos.w | |
| #define UNITY_EXTRACT_FOG_FROM_EYE_VEC(name) float _unity_fogCoord = name.eyeVec.w | |
| #else | |
| #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) | |
| #define UNITY_EXTRACT_FOG(name) | |
| #define UNITY_EXTRACT_FOG_FROM_TSPACE(name) | |
| #define UNITY_EXTRACT_FOG_FROM_WORLD_POS(name) | |
| #define UNITY_EXTRACT_FOG_FROM_EYE_VEC(name) | |
| #endif | |
| #ifdef UNITY_PASS_FORWARDADD | |
| #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,fixed4(0,0,0,0)) | |
| #else | |
| #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,unity_FogColor) | |
| #endif | |
| // ------------------------------------------------------------------ | |
| // TBN helpers | |
| #define UNITY_EXTRACT_TBN_0(name) fixed3 _unity_tbn_0 = name.tSpace0.xyz | |
| #define UNITY_EXTRACT_TBN_1(name) fixed3 _unity_tbn_1 = name.tSpace1.xyz | |
| #define UNITY_EXTRACT_TBN_2(name) fixed3 _unity_tbn_2 = name.tSpace2.xyz | |
| #define UNITY_EXTRACT_TBN(name) UNITY_EXTRACT_TBN_0(name); UNITY_EXTRACT_TBN_1(name); UNITY_EXTRACT_TBN_2(name) | |
| #define UNITY_EXTRACT_TBN_T(name) fixed3 _unity_tangent = fixed3(name.tSpace0.x, name.tSpace1.x, name.tSpace2.x) | |
| #define UNITY_EXTRACT_TBN_N(name) fixed3 _unity_normal = fixed3(name.tSpace0.z, name.tSpace1.z, name.tSpace2.z) | |
| #define UNITY_EXTRACT_TBN_B(name) fixed3 _unity_binormal = cross(_unity_normal, _unity_tangent) | |
| #define UNITY_CORRECT_TBN_B_SIGN(name) _unity_binormal *= name.tSpace1.y; | |
| #define UNITY_RECONSTRUCT_TBN_0 fixed3 _unity_tbn_0 = fixed3(_unity_tangent.x, _unity_binormal.x, _unity_normal.x) | |
| #define UNITY_RECONSTRUCT_TBN_1 fixed3 _unity_tbn_1 = fixed3(_unity_tangent.y, _unity_binormal.y, _unity_normal.y) | |
| #define UNITY_RECONSTRUCT_TBN_2 fixed3 _unity_tbn_2 = fixed3(_unity_tangent.z, _unity_binormal.z, _unity_normal.z) | |
| #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) | |
| #define UNITY_RECONSTRUCT_TBN(name) UNITY_EXTRACT_TBN_T(name); UNITY_EXTRACT_TBN_N(name); UNITY_EXTRACT_TBN_B(name); UNITY_CORRECT_TBN_B_SIGN(name); UNITY_RECONSTRUCT_TBN_0; UNITY_RECONSTRUCT_TBN_1; UNITY_RECONSTRUCT_TBN_2 | |
| #else | |
| #define UNITY_RECONSTRUCT_TBN(name) UNITY_EXTRACT_TBN(name) | |
| #endif | |
| // LOD cross fade helpers | |
| // keep all the old macros | |
| #define UNITY_DITHER_CROSSFADE_COORDS | |
| #define UNITY_DITHER_CROSSFADE_COORDS_IDX(idx) | |
| #define UNITY_TRANSFER_DITHER_CROSSFADE(o,v) | |
| #define UNITY_TRANSFER_DITHER_CROSSFADE_HPOS(o,hpos) | |
| #ifdef LOD_FADE_CROSSFADE | |
| #define UNITY_APPLY_DITHER_CROSSFADE(vpos) UnityApplyDitherCrossFade(vpos) | |
| sampler2D unity_DitherMask; | |
| void UnityApplyDitherCrossFade(float2 vpos) | |
| { | |
| vpos /= 4; // the dither mask texture is 4x4 | |
| float mask = tex2D(unity_DitherMask, vpos).a; | |
| float sgn = unity_LODFade.x > 0 ? 1.0f : -1.0f; | |
| clip(unity_LODFade.x - mask * sgn); | |
| } | |
| #else | |
| #define UNITY_APPLY_DITHER_CROSSFADE(vpos) | |
| #endif | |
| // ------------------------------------------------------------------ | |
| // Deprecated things: these aren't used; kept here | |
| // just so that various existing shaders still compile, more or less. | |
| // Note: deprecated shadow collector pass helpers | |
| #ifdef SHADOW_COLLECTOR_PASS | |
| #if !defined(SHADOWMAPSAMPLER_DEFINED) | |
| UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture); | |
| #endif | |
| // Note: V2F_SHADOW_COLLECTOR and TRANSFER_SHADOW_COLLECTOR are deprecated | |
| #define V2F_SHADOW_COLLECTOR float4 pos : SV_POSITION; float3 _ShadowCoord0 : TEXCOORD0; float3 _ShadowCoord1 : TEXCOORD1; float3 _ShadowCoord2 : TEXCOORD2; float3 _ShadowCoord3 : TEXCOORD3; float4 _WorldPosViewZ : TEXCOORD4 | |
| #define TRANSFER_SHADOW_COLLECTOR(o) \ | |
| o.pos = UnityObjectToClipPos(v.vertex); \ | |
| float4 wpos = mul(unity_ObjectToWorld, v.vertex); \ | |
| o._WorldPosViewZ.xyz = wpos; \ | |
| o._WorldPosViewZ.w = -UnityObjectToViewPos(v.vertex).z; \ | |
| o._ShadowCoord0 = mul(unity_WorldToShadow[0], wpos).xyz; \ | |
| o._ShadowCoord1 = mul(unity_WorldToShadow[1], wpos).xyz; \ | |
| o._ShadowCoord2 = mul(unity_WorldToShadow[2], wpos).xyz; \ | |
| o._ShadowCoord3 = mul(unity_WorldToShadow[3], wpos).xyz; | |
| // Note: SAMPLE_SHADOW_COLLECTOR_SHADOW is deprecated | |
| #define SAMPLE_SHADOW_COLLECTOR_SHADOW(coord) \ | |
| half shadow = UNITY_SAMPLE_SHADOW(_ShadowMapTexture,coord); \ | |
| shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r); | |
| // Note: COMPUTE_SHADOW_COLLECTOR_SHADOW is deprecated | |
| #define COMPUTE_SHADOW_COLLECTOR_SHADOW(i, weights, shadowFade) \ | |
| float4 coord = float4(i._ShadowCoord0 * weights[0] + i._ShadowCoord1 * weights[1] + i._ShadowCoord2 * weights[2] + i._ShadowCoord3 * weights[3], 1); \ | |
| SAMPLE_SHADOW_COLLECTOR_SHADOW(coord) \ | |
| float4 res; \ | |
| res.x = saturate(shadow + shadowFade); \ | |
| res.y = 1.0; \ | |
| res.zw = EncodeFloatRG (1 - i._WorldPosViewZ.w * _ProjectionParams.w); \ | |
| return res; | |
| // Note: deprecated | |
| #if defined (SHADOWS_SPLIT_SPHERES) | |
| #define SHADOW_COLLECTOR_FRAGMENT(i) \ | |
| float3 fromCenter0 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[0].xyz; \ | |
| float3 fromCenter1 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[1].xyz; \ | |
| float3 fromCenter2 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[2].xyz; \ | |
| float3 fromCenter3 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[3].xyz; \ | |
| float4 distances2 = float4(dot(fromCenter0,fromCenter0), dot(fromCenter1,fromCenter1), dot(fromCenter2,fromCenter2), dot(fromCenter3,fromCenter3)); \ | |
| float4 cascadeWeights = float4(distances2 < unity_ShadowSplitSqRadii); \ | |
| cascadeWeights.yzw = saturate(cascadeWeights.yzw - cascadeWeights.xyz); \ | |
| float sphereDist = distance(i._WorldPosViewZ.xyz, unity_ShadowFadeCenterAndType.xyz); \ | |
| float shadowFade = saturate(sphereDist * _LightShadowData.z + _LightShadowData.w); \ | |
| COMPUTE_SHADOW_COLLECTOR_SHADOW(i, cascadeWeights, shadowFade) | |
| #else | |
| #define SHADOW_COLLECTOR_FRAGMENT(i) \ | |
| float4 viewZ = i._WorldPosViewZ.w; \ | |
| float4 zNear = float4( viewZ >= _LightSplitsNear ); \ | |
| float4 zFar = float4( viewZ < _LightSplitsFar ); \ | |
| float4 cascadeWeights = zNear * zFar; \ | |
| float shadowFade = saturate(i._WorldPosViewZ.w * _LightShadowData.z + _LightShadowData.w); \ | |
| COMPUTE_SHADOW_COLLECTOR_SHADOW(i, cascadeWeights, shadowFade) | |
| #endif | |
| #endif // #ifdef SHADOW_COLLECTOR_PASS | |
| // Legacy; used to do something on platforms that had to emulate depth textures manually. Now all platforms have native depth textures. | |
| #define UNITY_TRANSFER_DEPTH(oo) | |
| // Legacy; used to do something on platforms that had to emulate depth textures manually. Now all platforms have native depth textures. | |
| #define UNITY_OUTPUT_DEPTH(i) return 0 | |
| #define API_HAS_GUARANTEED_R16_SUPPORT !(SHADER_API_VULKAN || SHADER_API_GLES || SHADER_API_GLES3) | |
| float4 PackHeightmap(float height) | |
| { | |
| #if (API_HAS_GUARANTEED_R16_SUPPORT) | |
| return height; | |
| #else | |
| uint a = (uint)(65535.0f * height); | |
| return float4((a >> 0) & 0xFF, (a >> 8) & 0xFF, 0, 0) / 255.0f; | |
| #endif | |
| } | |
| float UnpackHeightmap(float4 height) | |
| { | |
| #if (API_HAS_GUARANTEED_R16_SUPPORT) | |
| return height.r; | |
| #else | |
| return (height.r + height.g * 256.0f) / 257.0f; // (255.0f * height.r + 255.0f * 256.0f * height.g) / 65535.0f | |
| #endif | |
| } | |
| #endif // UNITY_CG_INCLUDED |
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
댓글 쓰기