UnityCG.cginc 함수 설명

  유니티 내장 셰이더 함수들 (tistory.com)


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;
    return UnityWorldSpaceViewDir(worldPos);

float3 ObjSpaceViewDir (float4 v)

오브젝트 공간 방향(정규화되지 않음)을 주어진 오브젝트 공간 버텍스 포지션에서 카메라 쪽으로 되돌립니다.

로컬 공간에 있는 것을 뷰 방향으로 변환합니다.

float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
    return objSpaceCameraPos - v.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 )
{
    h = h * height - height/2.0;
    float3 v = normalize(viewDir);
    v.z += 0.42;
    return h * (v.xy / v.z);
}

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)
    return DecodeLightmapDoubleLDR(color, decodeInstructions);
#elif defined(UNITY_LIGHTMAP_RGBM_ENCODING)
    return DecodeLightmapRGBM(color, decodeInstructions);

 

float4 EncodeFloatRGBA (float v)

정밀도가 낮은 렌더링 타겟에 저장하기 위해 [01) 범위 플로트를 RGBA 컬러로 인코딩합니다

 

8비트 체널로 인코딩합니다. 안써봐서 모르겠음. 

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;
}

 

float DecodeFloatRGBA (float4 enc)

RGBA 컬러를 플로트로 디코딩합니다.

위 것과 반대 작용을 하는 것 같은데, 재미있는건 xyzw가 플롯, 8비트, 16비트, 24비트 칼라라는 것이네요. 

inline float DecodeFloatRGBA( float4 enc )
{
    float4 kDecodeDot = float4(1.0, 1/255.0, 1/65025.0, 1/16581375.0);
    return dot( enc, kDecodeDot );
}

 

float2 EncodeFloatRG (float v)

[0–1) 범위 플로트를 float2로 인코딩합니다.

 

위의위의 것과 동일합니다. 단 여기는 플롯과 8비트만 연산하네요 

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;
}

 

 

float DecodeFloatRG (float2 enc)

이전에 인코딩된 RG 플로트를 디코딩합니다.

 

설명생략

inline float DecodeFloatRG( float2 enc )
{
    float2 kDecodeDot = float2(1.0, 1/255.0);
    return dot( enc, kDecodeDot );
}

 

float2 EncodeViewNormalStereo (float3 n)

뷰 공간 노멀을 범위가 01인 숫자 2개로 인코딩합니다.

 

이 부분은 안써봐서 모르는 거군요 

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;
}

 

float3 DecodeViewNormalStereo (float4 enc4)

뷰 공간 노멀을 enc4.xy에서 디코딩합니다.

 

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;
}

 

 

UnityCG.cginc의 포워드 렌더링 헬퍼 함수

이 함수는 포워드 렌더링(ForwardBase 또는 ForwardAdd 패스 타입)을 사용하는 경우에만 유용합니다.

 

디퍼드 렌더링에서는 안되고 포워드에서만 된다는 말이겠군요. 주로 라이트에 관계된 부분이겠지요. 

 

float3 WorldSpaceLightDir (float4 v)

광원을 향한 월드 공간 방향(정규화되지 않음)을 주어진 오브젝트 공간 버텍스 포지션에 대해 계산합니다.

 

오브젝트(로컬) 좌표계의 버텍스 위치를 집어 넣으면, 월드 좌표계 에서의 라이트 디렉션이 나옵니다. ForwardBase 인 경우에는 디렉셔널 라이트 또는 가장 밝은 라이트가 선택될테고, 라이트가 추가되면 ForwardAdd가 실행되니 그때에는 다음 라이트가 이걸 실행하겠죠 

inline float3 WorldSpaceLightDir( in float4 localPos )
{
    float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
    return UnityWorldSpaceLightDir(worldPos);
}

 

float3 ObjSpaceLightDir (float4 v)

광원을 향한 오브젝트 공간 방향(정규화되지 않음)을 주어진 오브젝트 공간 버텍스 포지션에 대해 계산합니다.

 

위와 같습니다만, 리턴이 오브젝트(로컬) 좌표계입니다. 

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
}

 

float3 Shade4PointLights (...)

벡터에 조밀하게 채워진 광원 데이터를 사용해 점 광원 4개의 조명을 연산합니다. 포워드 렌더링에서 버텍스당 조명을 연산하는 데 사용됩니다.

 

이쪽은 코드가 좀 기네요. 4개까지 연산되는 포인트 라이트 연산입니다. 사용 예를 좀 찾아보고 싶군요 

 

 

 

UnityCG.cginc의 스크린 공간 헬퍼 함수

다음은 스크린 공간 텍스처 샘플링에 사용되는 좌표를 계산하는 헬퍼 함수입니다. 텍스처를 샘플링할 최종 좌표를 원근 나누기(예: xy/w)를 통해 계산할 수 있는float4를 반환합니다.

함수는 렌더 텍스처 좌표의 플랫폼 차이도 처리합니다.

 

댑스값에 관련된 부분에 사용할때 많이 쓰는 녀석들입니다. 스크린 스페이스에서의 좌표계부분입니다. 

 

float4 ComputeScreenPos (float4 clipPos)

Screenspace 매핑된 텍스처 샘플링을 수행하기 위한 텍스처 좌표를 계산합니다. 입력은 클립 공간 포지션입니다.

 

그다지 설명할게 없습니다. 클립 스페이스를 집어 넣으면 스크린 좌표계에서의 텍스쳐 좌표계 값이 나옵니다. 

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;
}

 

 

float4 ComputeGrabScreenPos (float4 clipPos)

GrabPass 텍스처를 샘플링하는 텍스처 좌표를 계산합니다. 입력은 클립 공간 포지션입니다.

 

마찬가지 연산을 합니다. OpenGl이냐 DirectX냐에 따라 위아래가 바뀌는 연산이 들어가 있습니다. 

 

 

UnityCG.cginc의 버텍스 릿 헬퍼 함수

함수는 버텍스당 릿 셰이더(“Vertex” 패스 타입)를 사용하는 경우에만 유용합니다.

 

간단하게 버텍스 라이트 연산을 위한 함수입니다. 픽셀라이트에서는 이루어지지 않는 연산임을 주의

 

float3 ShadeVertexLights (float4 vertex, float3 normal)

버텍스당 광원 및 앰비언트 4개의 조명을 주어진 오브젝트 공간 포지션 및 노멀에 대해 계산합니다.

버텍스 라이트 연산을 하는 함수입니다. 당연히 픽셀라이트 연산으로 작동되지 않습니다. 

 

 



 2 contributors
@Valeour@MattOstgard
1212 lines (1020 sloc)  43.1 KB
   
// 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

댓글

이 블로그의 인기 게시물

About AActor!!! "UObject" has no member "BeginPlay"

UNREAL Android build information

Shader informations nice blog ~ ~