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
- 이메일
- 기타 앱
댓글
댓글 쓰기