Felipe Lira
7 年前
当前提交
a5dbc063
共有 43 个文件被更改,包括 2143 次插入 和 1307 次删除
-
2ScriptableRenderPipeline/Core/ShaderLibrary/Common.hlsl
-
42ScriptableRenderPipeline/Core/ShaderLibrary/EntityLighting.hlsl
-
34ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandard.shader
-
73ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardParticles.shader
-
30ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardSimpleLighting.shader
-
25ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightUnlit.shader
-
98ScriptableRenderPipeline/Core/ShaderLibrary/API/GLES3.hlsl
-
10ScriptableRenderPipeline/Core/ShaderLibrary/API/GLES3.hlsl.meta
-
8ScriptableRenderPipeline/Core/ShaderLibrary/ShaderVariables.meta
-
199ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCore.hlsl
-
69ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightInput.hlsl
-
425ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightLighting.hlsl
-
214ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightParticle.hlsl
-
9ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightParticle.hlsl.meta
-
133ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassLit.hlsl
-
123ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassMeta.hlsl
-
22ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassShadow.hlsl
-
149ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShadows.hlsl
-
168ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightSurfaceInput.hlsl
-
8ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables.meta
-
252ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariables.hlsl
-
9ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariables.hlsl.meta
-
21ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariablesCamera.hlsl
-
9ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariablesCamera.hlsl.meta
-
114ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariablesFunctions.hlsl
-
9ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariablesFunctions.hlsl.meta
-
20ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassShadow.cginc
-
166ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCore.cginc
-
137ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassLit.cginc
-
70ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassMeta.cginc
-
142ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShadows.cginc
-
69ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightInput.cginc
-
425ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightLighting.cginc
-
166ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightSurfaceInput.cginc
-
0/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCore.hlsl.meta
-
0/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightInput.hlsl.meta
-
0/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightLighting.hlsl.meta
-
0/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassLit.hlsl.meta
-
0/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassMeta.hlsl.meta
-
0/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassShadow.hlsl.meta
-
0/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShadows.hlsl.meta
-
0/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightSurfaceInput.hlsl.meta
|
|||
// This file assume SHADER_API_GLES3 is defined |
|||
|
|||
#define UNITY_UV_STARTS_AT_TOP 0 |
|||
#define UNITY_REVERSED_Z 0 |
|||
#define UNITY_GATHER_SUPPORTED 0 |
|||
#define UNITY_NEAR_CLIP_VALUE (-1.0) |
|||
|
|||
// This value will not go through any matrix projection convertion |
|||
#define UNITY_RAW_FAR_CLIP_VALUE (1.0) |
|||
#define FRONT_FACE_SEMATIC VFACE |
|||
#define FRONT_FACE_TYPE float |
|||
#define IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL > 0.0) ? (FRONT) : (BACK)) |
|||
|
|||
#define CBUFFER_START(name) |
|||
#define CBUFFER_END |
|||
|
|||
// Initialize arbitrary structure with zero values. |
|||
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 |
|||
#define ZERO_INITIALIZE(type, name) name = (type)0; |
|||
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } |
|||
|
|||
// Texture util abstraction |
|||
|
|||
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) // TODO: |
|||
|
|||
// Texture abstraction |
|||
|
|||
#define TEXTURE2D(textureName) sampler2D textureName |
|||
#define TEXTURE2D_ARRAY(textureName) sampler2DArray textureName |
|||
#define TEXTURECUBE(textureName) samplerCUBE textureName |
|||
#define TEXTURECUBE_ARRAY(textureName) samplerCUBEArray textureName |
|||
#define TEXTURE3D(textureName) sampler3D textureName |
|||
#define TEXTURE2D_SHADOW(textureName) sampler2DShadow textureName |
|||
#define RW_TEXTURE2D(type, textureNam) |
|||
|
|||
#define SAMPLER2D(samplerName) |
|||
#define SAMPLERCUBE(samplerName) |
|||
#define SAMPLER3D(samplerName) |
|||
#define SAMPLER2D_SHADOW(samplerName) |
|||
#define SAMPLERCUBE_SHADOW(samplerName) |
|||
|
|||
#define TEXTURE2D_ARGS(textureName, samplerName) sampler2D textureName |
|||
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) sampler2DArray textureName |
|||
#define TEXTURECUBE_ARGS(textureName, samplerName) samplerCUBE textureName |
|||
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) samplerCUBEArray textureName |
|||
#define TEXTURE3D_ARGS(textureName, samplerName) sampler3D textureName |
|||
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) sampler2DShadow textureName |
|||
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) sampler2DArrayShadow textureName |
|||
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) samplerCUBEArrayShadow textureName |
|||
|
|||
#define TEXTURE2D_PARAM(textureName, samplerName) textureName |
|||
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) textureName |
|||
#define TEXTURECUBE_PARAM(textureName, samplerName) textureName |
|||
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) textureName |
|||
#define TEXTURE3D_PARAM(textureName, samplerName) textureName |
|||
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) textureName |
|||
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) textureName |
|||
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) textureName |
|||
|
|||
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) tex2D(textureName, coord2) |
|||
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) tex2Dlod(textureName, float4(coord2, 0, lod)) |
|||
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) tex2Dbias(textureName, float4(coord2, 0, bias)) |
|||
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) tex2Dgrad(coord2.x, coord2.y, ddx, ddy) |
|||
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) tex2DArray(textureName, float3(coord2, index)) |
|||
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) tex2DArraylod(textureName, float4(coord2, index, lod)) |
|||
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) tex2DArraybias(textureName, float4(coord2, index, bias)) |
|||
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) texCUBE(textureName, coord3) |
|||
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) texCUBElod(textureName, float4(coord3, lod)) |
|||
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) texCUBEbias(textureName, float4(coord3, bias)) |
|||
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) // TODO: |
|||
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) // TODO: |
|||
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) // TODO: |
|||
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) tex3D(textureName, coord3) |
|||
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) shadow2D(textureName, coord3) |
|||
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) // TODO: |
|||
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) ((texCUBE(tex,(coord).xyz) < (coord).w) ? 0.0 : 1.0) |
|||
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) // TODO: |
|||
|
|||
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r |
|||
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r |
|||
|
|||
#define TEXTURE2D_HALF TEXTURE2D |
|||
#define TEXTURE2D_FLOAT TEXTURE2D |
|||
#define TEXTURE3D_HALF TEXTURE3D |
|||
#define TEXTURE3D_FLOAT TEXTURE3D |
|||
#define SAMPLER2D_HALF SAMPLER2D |
|||
#define SAMPLER2D_FLOAT SAMPLER2D |
|||
|
|||
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0)) |
|||
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod)) |
|||
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex) |
|||
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0)) |
|||
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod)) |
|||
|
|||
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) |
|||
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) |
|||
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) |
|||
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) |
|
|||
fileFormatVersion: 2 |
|||
guid: 14a46e0dac04a0245b3f95359167b663 |
|||
timeCreated: 1506072929 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
externalObjects: {} |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 6eee18abaa96cb24ba0065ccb3d2ba98 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef LIGHTWEIGHT_PIPELINE_CORE_INCLUDED |
|||
#define LIGHTWEIGHT_PIPELINE_CORE_INCLUDED |
|||
|
|||
#include "ShaderVariables\LightweightShaderVariables.hlsl" |
|||
#include "ShaderLibrary\Common.hlsl" |
|||
#include "ShaderLibrary\EntityLighting.hlsl" |
|||
|
|||
#ifdef _NORMALMAP |
|||
#define OUTPUT_NORMAL(IN, OUT) OutputTangentToWorld(IN.tangent, IN.normal, OUT.tangent, OUT.binormal, OUT.normal) |
|||
#else |
|||
#define OUTPUT_NORMAL(IN, OUT) OUT.normal = TransformObjectToWorldNormal(IN.normal) |
|||
#endif |
|||
|
|||
#ifdef LIGHTMAP_ON |
|||
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) OUT.xy = lightmapUV.xy * lightmapScaleOffset.xy + lightmapScaleOffset.zw; |
|||
#define OUTPUT_SH(normalWS, OUT) |
|||
#else |
|||
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) |
|||
#define OUTPUT_SH(normalWS, OUT) OUT.xyz = EvaluateSHPerVertex(normalWS) |
|||
#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 |
|||
|
|||
half Pow4(half x) |
|||
{ |
|||
return x * x * x * x; |
|||
} |
|||
|
|||
half LerpOneTo(half b, half t) |
|||
{ |
|||
half oneMinusT = 1 - t; |
|||
return oneMinusT + b * t; |
|||
} |
|||
|
|||
void AlphaDiscard(half alpha, half cutoff) |
|||
{ |
|||
#ifdef _ALPHATEST_ON |
|||
clip(alpha - cutoff); |
|||
#endif |
|||
} |
|||
|
|||
half3 SafeNormalize(half3 inVec) |
|||
{ |
|||
half dp3 = max(1.e-4h, dot(inVec, inVec)); |
|||
return inVec * rsqrt(dp3); |
|||
} |
|||
|
|||
half3 UnpackNormalScale(half4 packednormal, half bumpScale) |
|||
{ |
|||
#if defined(UNITY_NO_DXT5nm) |
|||
half3 normal = packednormal.xyz * 2 - 1; |
|||
#if (SHADER_TARGET >= 30) |
|||
// SM2.0: instruction count limitation |
|||
// SM2.0: normal scaler is not supported |
|||
normal.xy *= bumpScale; |
|||
#endif |
|||
return normal; |
|||
#else |
|||
// This do the trick |
|||
packednormal.x *= packednormal.w; |
|||
|
|||
half3 normal; |
|||
normal.xy = (packednormal.xy * 2 - 1); |
|||
#if (SHADER_TARGET >= 30) |
|||
// SM2.0: instruction count limitation |
|||
// SM2.0: normal scaler is not supported |
|||
normal.xy *= bumpScale; |
|||
#endif |
|||
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy))); |
|||
return normal; |
|||
#endif |
|||
} |
|||
|
|||
half3 SampleSH(half3 normalWS) |
|||
{ |
|||
// LPPV is not supported in Ligthweight Pipeline |
|||
float4 SHCoefficients[7]; |
|||
SHCoefficients[0] = unity_SHAr; |
|||
SHCoefficients[1] = unity_SHAg; |
|||
SHCoefficients[2] = unity_SHAb; |
|||
SHCoefficients[3] = unity_SHBr; |
|||
SHCoefficients[4] = unity_SHBg; |
|||
SHCoefficients[5] = unity_SHBb; |
|||
SHCoefficients[6] = unity_SHC; |
|||
|
|||
return SampleSH9(SHCoefficients, normalWS); |
|||
} |
|||
|
|||
half3 EvaluateSHPerVertex(half3 normalWS) |
|||
{ |
|||
#if defined(EVALUATE_SH_VERTEX) |
|||
return max(half3(0, 0, 0), SampleSH(normalWS)); |
|||
#elif defined(EVALUATE_SH_MIXED) |
|||
// no max since this is only L2 contribution |
|||
return SHEvalLinearL2(normalWS, unity_SHBr, unity_SHBg, unity_SHBb, unity_SHC); |
|||
#endif |
|||
|
|||
// Fully per-pixel. Nothing to compute. |
|||
return half3(0.0, 0.0, 0.0); |
|||
} |
|||
|
|||
half3 EvaluateSHPerPixel(half3 L2Term, half3 normalWS) |
|||
{ |
|||
#ifdef EVALUATE_SH_MIXED |
|||
half3 L0L1Term = SHEvalLinearL0L1(normalWS, unity_SHAr, unity_SHAg, unity_SHAb); |
|||
return max(half3(0, 0, 0), L2Term + L0L1Term); |
|||
#endif |
|||
|
|||
// Default: Evaluate SH fully per-pixel |
|||
return max(half3(0, 0, 0), SampleSH(normalWS)); |
|||
} |
|||
|
|||
half3 SampleGI(float4 sampleData, half3 normalWS) |
|||
{ |
|||
#ifdef LIGHTMAP_ON |
|||
|
|||
// Only baked GI is sample as dynamic GI is not supported in Lightweight |
|||
#ifdef UNITY_LIGHTMAP_FULL_HDR |
|||
bool encodedLightmap = false; |
|||
#else |
|||
bool encodedLightmap = true; |
|||
#endif |
|||
|
|||
// The shader library sample lightmap functions transform the lightmap uv coords to apply bias and scale. |
|||
// However, lightweight pipeline already transformed those coords in vertex. We pass half4(1, 1, 0, 0) and |
|||
// the compiler will optimize the transform away. |
|||
half4 transformCoords = half4(1, 1, 0, 0); |
|||
|
|||
#ifdef DIRLIGHTMAP_COMBINED |
|||
return SampleDirectionalLightmap(TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap), |
|||
TEXTURE2D_PARAM(unity_LightmapInd, samplerunity_Lightmap), |
|||
sampleData.xy, transformCoords, normalWS, encodedLightmap); |
|||
#else |
|||
return SampleSingleLightmap(TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap), sampleData.xy, transformCoords, encodedLightmap); |
|||
#endif |
|||
|
|||
#endif // LIGHTMAP_ON |
|||
|
|||
// If lightmap is not enabled we sample GI from SH |
|||
return EvaluateSHPerPixel(sampleData.xyz, normalWS); |
|||
} |
|||
|
|||
void OutputTangentToWorld(half4 vertexTangent, half3 vertexNormal, out half3 tangentWS, out half3 binormalWS, out half3 normalWS) |
|||
{ |
|||
half sign = vertexTangent.w * GetOddNegativeScale(); |
|||
normalWS = TransformObjectToWorldNormal(vertexNormal); |
|||
tangentWS = normalize(mul((half3x3)unity_ObjectToWorld, vertexTangent.xyz)); |
|||
binormalWS = cross(normalWS, tangentWS) * sign; |
|||
} |
|||
|
|||
half3 TangentToWorldNormal(half3 normalTangent, half3 tangent, half3 binormal, half3 normal) |
|||
{ |
|||
half3x3 tangentToWorld = half3x3(tangent, binormal, normal); |
|||
return normalize(mul(normalTangent, tangentToWorld)); |
|||
} |
|||
|
|||
float ComputeFogFactor(float z) |
|||
{ |
|||
float clipZ_01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(z); |
|||
|
|||
#if defined(FOG_LINEAR) |
|||
// factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start)) |
|||
float fogFactor = saturate(clipZ_01 * unity_FogParams.z + unity_FogParams.w); |
|||
return half(fogFactor); |
|||
#elif defined(FOG_EXP) |
|||
// factor = exp(-density*z) |
|||
float unityFogFactor = unity_FogParams.y * clipZ_01; |
|||
return half(saturate(exp2(-unityFogFactor))); |
|||
#elif defined(FOG_EXP2) |
|||
// factor = exp(-(density*z)^2) |
|||
float unityFogFactor = unity_FogParams.x * clipZ_01; |
|||
return half(saturate(exp2(-unityFogFactor*unityFogFactor))); |
|||
#else |
|||
return 0.0h; |
|||
#endif |
|||
} |
|||
|
|||
void ApplyFog(inout half3 color, half fogFactor) |
|||
{ |
|||
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) |
|||
color = lerp(unity_FogColor, color, fogFactor); |
|||
#endif |
|||
} |
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_INPUT_INCLUDED |
|||
#define LIGHTWEIGHT_INPUT_INCLUDED |
|||
|
|||
#define MAX_VISIBLE_LIGHTS 16 |
|||
|
|||
struct LightInput |
|||
{ |
|||
float4 pos; |
|||
half3 color; |
|||
half4 distanceAttenuation; |
|||
half4 spotDirection; |
|||
half4 spotAttenuation; |
|||
}; |
|||
|
|||
// Main light initialized without indexing |
|||
#define INITIALIZE_MAIN_LIGHT(light) \ |
|||
light.pos = _MainLightPosition; \ |
|||
light.color = _MainLightColor.rgb; \ |
|||
light.distanceAttenuation = _MainLightDistanceAttenuation; \ |
|||
light.spotDirection = _MainLightSpotDir; \ |
|||
light.spotAttenuation = _MainLightSpotAttenuation |
|||
|
|||
// Indexing might have a performance hit for old mobile hardware |
|||
#define INITIALIZE_LIGHT(light, i) \ |
|||
half4 indices = (i < 4) ? unity_4LightIndices0 : unity_4LightIndices1; \ |
|||
int index = (i < 4) ? i : i - 4; \ |
|||
int lightIndex = indices[index]; \ |
|||
light.pos = _AdditionalLightPosition[lightIndex]; \ |
|||
light.color = _AdditionalLightColor[lightIndex].rgb; \ |
|||
light.distanceAttenuation = _AdditionalLightDistanceAttenuation[lightIndex]; \ |
|||
light.spotDirection = _AdditionalLightSpotDir[lightIndex]; \ |
|||
light.spotAttenuation = _AdditionalLightSpotAttenuation[lightIndex] |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Constant Buffers // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
|
|||
CBUFFER_START(_PerFrame) |
|||
half4 _GlossyEnvironmentColor; |
|||
half4 _SubtractiveShadowColor; |
|||
CBUFFER_END |
|||
|
|||
CBUFFER_START(_PerCamera) |
|||
float4 _MainLightPosition; |
|||
half4 _MainLightColor; |
|||
half4 _MainLightDistanceAttenuation; |
|||
half4 _MainLightSpotDir; |
|||
half4 _MainLightSpotAttenuation; |
|||
float4x4 _WorldToLight; |
|||
|
|||
half4 _AdditionalLightCount; |
|||
float4 _AdditionalLightPosition[MAX_VISIBLE_LIGHTS]; |
|||
half4 _AdditionalLightColor[MAX_VISIBLE_LIGHTS]; |
|||
half4 _AdditionalLightDistanceAttenuation[MAX_VISIBLE_LIGHTS]; |
|||
half4 _AdditionalLightSpotDir[MAX_VISIBLE_LIGHTS]; |
|||
half4 _AdditionalLightSpotAttenuation[MAX_VISIBLE_LIGHTS]; |
|||
CBUFFER_END |
|||
|
|||
sampler2D _MainLightCookie; |
|||
|
|||
// These are set internally by the engine upon request by RendererConfiguration. |
|||
// Check GetRendererSettings in LightweightPipeline.cs |
|||
CBUFFER_START(_PerObject) |
|||
half4 unity_LightIndicesOffsetAndCount; |
|||
half4 unity_4LightIndices0; |
|||
half4 unity_4LightIndices1; |
|||
CBUFFER_END |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_LIGHTING_INCLUDED |
|||
#define LIGHTWEIGHT_LIGHTING_INCLUDED |
|||
|
|||
#include "LightweightCore.hlsl" |
|||
#include "LightweightShadows.hlsl" |
|||
#include "ShaderLibrary\ImageBasedLighting.hlsl" |
|||
|
|||
#define kDieletricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%) |
|||
|
|||
#ifdef NO_ADDITIONAL_LIGHTS |
|||
#undef _ADDITIONAL_LIGHTS |
|||
#endif |
|||
|
|||
// If lightmap is not defined than we evaluate GI (ambient + probes) from SH |
|||
// We might do it fully or partially in vertex to save shader ALU |
|||
#if !defined(LIGHTMAP_ON) |
|||
#if SHADER_TARGET < 30 |
|||
// Evaluates SH fully in vertex |
|||
#define EVALUATE_SH_VERTEX |
|||
#else |
|||
// Evaluates L2 SH in vertex and L0L1 in pixel |
|||
#define EVALUATE_SH_MIXED |
|||
#endif |
|||
#endif |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// BRDF Functions // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
struct BRDFData |
|||
{ |
|||
half3 diffuse; |
|||
half3 specular; |
|||
half perceptualRoughness; |
|||
half roughness; |
|||
half grazingTerm; |
|||
}; |
|||
|
|||
half ReflectivitySpecular(half3 specular) |
|||
{ |
|||
#if (SHADER_TARGET < 30) |
|||
// SM2.0: instruction count limitation |
|||
return specular.r; // Red channel - because most metals are either monocrhome or with redish/yellowish tint |
|||
#else |
|||
return max(max(specular.r, specular.g), specular.b); |
|||
#endif |
|||
} |
|||
|
|||
half OneMinusReflectivityMetallic(half metallic) |
|||
{ |
|||
// We'll need oneMinusReflectivity, so |
|||
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic) |
|||
// store (1-dielectricSpec) in kDieletricSpec.a, then |
|||
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) = |
|||
// = alpha - metallic * alpha |
|||
half oneMinusDielectricSpec = kDieletricSpec.a; |
|||
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec; |
|||
} |
|||
|
|||
inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData) |
|||
{ |
|||
#ifdef _SPECULAR_SETUP |
|||
half reflectivity = ReflectivitySpecular(specular); |
|||
half oneMinusReflectivity = 1.0 - reflectivity; |
|||
|
|||
outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular); |
|||
outBRDFData.specular = specular; |
|||
#else |
|||
|
|||
half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic); |
|||
half reflectivity = 1.0 - oneMinusReflectivity; |
|||
|
|||
outBRDFData.diffuse = albedo * oneMinusReflectivity; |
|||
outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic); |
|||
#endif |
|||
|
|||
outBRDFData.grazingTerm = saturate(smoothness + reflectivity); |
|||
outBRDFData.perceptualRoughness = 1.0h - smoothness; |
|||
outBRDFData.roughness = outBRDFData.perceptualRoughness * outBRDFData.perceptualRoughness; |
|||
|
|||
#ifdef _ALPHAPREMULTIPLY_ON |
|||
outBRDFData.diffuse *= alpha; |
|||
alpha = alpha * oneMinusReflectivity + reflectivity; |
|||
#endif |
|||
} |
|||
|
|||
half3 LightweightEnvironmentBRDF(BRDFData brdfData, half3 indirectDiffuse, half3 indirectSpecular, half roughness2, half fresnelTerm) |
|||
{ |
|||
half3 c = indirectDiffuse * brdfData.diffuse; |
|||
float surfaceReduction = 1.0 / (roughness2 + 1.0); |
|||
c += surfaceReduction * indirectSpecular * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm); |
|||
return c; |
|||
} |
|||
|
|||
// Based on Minimalist CookTorrance BRDF |
|||
// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255 |
|||
// |
|||
// * NDF [Modified] GGX |
|||
// * Modified Kelemen and Szirmay-Kalos for Visibility term |
|||
// * Fresnel approximated with 1/LdotH |
|||
half3 LightweightDirectBDRF(BRDFData brdfData, half roughness2, half3 normal, half3 lightDirection, half3 viewDir) |
|||
{ |
|||
#ifndef _SPECULARHIGHLIGHTS_OFF |
|||
half3 halfDir = SafeNormalize(lightDirection + viewDir); |
|||
|
|||
half NoH = saturate(dot(normal, halfDir)); |
|||
half LoH = saturate(dot(lightDirection, halfDir)); |
|||
|
|||
// GGX Distribution multiplied by combined approximation of Visibility and Fresnel |
|||
// See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course |
|||
// https://community.arm.com/events/1155 |
|||
half d = NoH * NoH * (roughness2 - 1.h) + 1.00001h; |
|||
|
|||
half LoH2 = LoH * LoH; |
|||
half specularTerm = roughness2 / ((d * d) * max(0.1h, LoH2) * (brdfData.roughness + 0.5h) * 4); |
|||
|
|||
// on mobiles (where half actually means something) denominator have risk of overflow |
|||
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles) |
|||
// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...)) |
|||
#if defined (SHADER_API_MOBILE) |
|||
specularTerm = specularTerm - 1e-4h; |
|||
#endif |
|||
|
|||
#if defined (SHADER_API_MOBILE) |
|||
specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles |
|||
#endif |
|||
|
|||
half3 color = specularTerm * brdfData.specular + brdfData.diffuse; |
|||
return color; |
|||
#else |
|||
return brdfData.diffuse; |
|||
#endif |
|||
} |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Attenuation Functions / |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
half CookieAttenuation(float3 worldPos) |
|||
{ |
|||
#ifdef _MAIN_LIGHT_COOKIE |
|||
#ifdef _MAIN_DIRECTIONAL_LIGHT |
|||
float2 cookieUV = mul(_WorldToLight, float4(worldPos, 1.0)).xy; |
|||
return tex2D(_MainLightCookie, cookieUV).a; |
|||
#elif defined(_MAIN_SPOT_LIGHT) |
|||
float4 projPos = mul(_WorldToLight, float4(worldPos, 1.0)); |
|||
float2 cookieUV = projPos.xy / projPos.w + 0.5; |
|||
return tex2D(_MainLightCookie, cookieUV).a; |
|||
#endif // POINT LIGHT cookie not supported |
|||
#endif |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
// Matches Unity Vanila attenuation |
|||
// Attenuation smoothly decreases to light range. |
|||
half DistanceAttenuation(half distanceSqr, half4 distanceAttenuation) |
|||
{ |
|||
// We use a shared distance attenuation for additional directional and puctual lights |
|||
// for directional lights attenuation will be 1 |
|||
half quadFalloff = distanceAttenuation.x; |
|||
half denom = distanceSqr * quadFalloff + 1.0; |
|||
half lightAtten = 1.0 / denom; |
|||
|
|||
// We need to smoothly fade attenuation to light range. We start fading linearly at 80% of light range |
|||
// Therefore: |
|||
// fadeDistance = (0.8 * 0.8 * lightRangeSq) |
|||
// smoothFactor = (lightRangeSqr - distanceSqr) / (lightRangeSqr - fadeDistance) |
|||
// We can rewrite that to fit a MAD by doing |
|||
// distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr) |
|||
// distanceSqr * distanceAttenuation.y + distanceAttenuation.z |
|||
half smoothFactor = saturate(distanceSqr * distanceAttenuation.y + distanceAttenuation.z); |
|||
return lightAtten * smoothFactor; |
|||
} |
|||
|
|||
half SpotAttenuation(half3 spotDirection, half3 lightDirection, half4 spotAttenuation) |
|||
{ |
|||
// Spot Attenuation with a linear falloff can be defined as |
|||
// (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle) |
|||
// This can be rewritten as |
|||
// invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle) |
|||
// SdotL * invAngleRange + (-cosOuterAngle * invAngleRange) |
|||
// SdotL * spotAttenuation.x + spotAttenuation.y |
|||
|
|||
// If we precompute the terms in a MAD instruction |
|||
half SdotL = dot(spotDirection, lightDirection); |
|||
return saturate(SdotL * spotAttenuation.x + spotAttenuation.y); |
|||
} |
|||
|
|||
inline half GetLightDirectionAndRealtimeAttenuation(LightInput lightInput, half3 normal, float3 worldPos, out half3 lightDirection) |
|||
{ |
|||
float3 posToLightVec = lightInput.pos.xyz - worldPos * lightInput.pos.w; |
|||
float distanceSqr = max(dot(posToLightVec, posToLightVec), 0.001); |
|||
|
|||
// normalized light dir |
|||
lightDirection = half3(posToLightVec * rsqrt(distanceSqr)); |
|||
half lightAtten = DistanceAttenuation(distanceSqr, lightInput.distanceAttenuation); |
|||
lightAtten *= SpotAttenuation(lightInput.spotDirection.xyz, lightDirection, lightInput.spotAttenuation); |
|||
return lightAtten; |
|||
} |
|||
|
|||
inline half GetMainLightDirectionAndRealtimeAttenuation(LightInput lightInput, half3 normalWS, float3 positionWS, out half3 lightDirection) |
|||
{ |
|||
#ifdef _MAIN_DIRECTIONAL_LIGHT |
|||
// Light pos holds normalized light dir |
|||
lightDirection = lightInput.pos.xyz; |
|||
half attenuation = 1.0; |
|||
#else |
|||
half attenuation = GetLightDirectionAndRealtimeAttenuation(lightInput, normalWS, positionWS, lightDirection); |
|||
#endif |
|||
|
|||
// Cookies and shadows are only computed for main light |
|||
attenuation *= CookieAttenuation(positionWS); |
|||
attenuation *= LIGHTWEIGHT_SHADOW_ATTENUATION(positionWS, normalWS, lightDirection); |
|||
|
|||
return attenuation; |
|||
} |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Lighting Functions // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal) |
|||
{ |
|||
half NdotL = saturate(dot(normal, lightDir)); |
|||
return lightColor * NdotL; |
|||
} |
|||
|
|||
half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specularGloss, half shininess) |
|||
{ |
|||
half3 halfVec = SafeNormalize(lightDir + viewDir); |
|||
half NdotH = saturate(dot(normal, halfVec)); |
|||
half3 specularReflection = specularGloss.rgb * pow(NdotH, shininess) * specularGloss.a; |
|||
return lightColor * specularReflection; |
|||
} |
|||
|
|||
half3 VertexLighting(float3 positionWS, half3 normalWS) |
|||
{ |
|||
half3 vertexLightColor = half3(0.0, 0.0, 0.0); |
|||
|
|||
#if defined(_VERTEX_LIGHTS) |
|||
int vertexLightStart = _AdditionalLightCount.x; |
|||
int vertexLightEnd = min(_AdditionalLightCount.y, unity_LightIndicesOffsetAndCount.y); |
|||
for (int lightIter = vertexLightStart; lightIter < vertexLightEnd; ++lightIter) |
|||
{ |
|||
LightInput light; |
|||
INITIALIZE_LIGHT(light, lightIter); |
|||
|
|||
half3 lightDirection; |
|||
half atten = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection); |
|||
half3 lightColor = light.color * atten; |
|||
vertexLightColor += LightingLambert(lightColor, lightDirection, normalWS); |
|||
} |
|||
#endif |
|||
|
|||
return vertexLightColor; |
|||
} |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Global Illumination // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
half3 DiffuseGI(half3 indirectDiffuse, half3 lambert, half mainLightRealtimeAttenuation, half occlusion) |
|||
{ |
|||
// If shadows and mixed subtractive mode is enabled we need to remove direct |
|||
// light contribution from lightmap from occluded pixels so we can have dynamic objects |
|||
// casting shadows onto static correctly. |
|||
#if defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_ON) && defined(_SHADOWS) |
|||
indirectDiffuse = SubtractDirectMainLightFromLightmap(indirectDiffuse, mainLightRealtimeAttenuation, lambert); |
|||
#endif |
|||
|
|||
return indirectDiffuse * occlusion; |
|||
} |
|||
|
|||
half3 GlossyEnvironmentReflection(half3 viewDirectionWS, half3 normalWS, half perceptualRoughness, half occlusion) |
|||
{ |
|||
half3 reflectVector = reflect(-viewDirectionWS, normalWS); |
|||
|
|||
#if !defined(_GLOSSYREFLECTIONS_OFF) |
|||
half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness); |
|||
half4 encodedIrradiance = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip); |
|||
|
|||
#if !defined(UNITY_USE_NATIVE_HDR) |
|||
half3 irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR); |
|||
#else |
|||
half3 irradiance = encodedIrradiance.rbg; |
|||
#endif |
|||
|
|||
return irradiance * occlusion; |
|||
#endif |
|||
|
|||
return _GlossyEnvironmentColor.rgb * occlusion; |
|||
} |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Fragment Functions // |
|||
// Used by ShaderGraph and others builtin renderers // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
half4 LightweightFragmentPBR(float3 positionWS, half3 normalWS, half3 viewDirectionWS, |
|||
half3 bakedGI, half3 vertexLighting, half3 albedo, half metallic, half3 specular, |
|||
half smoothness, half occlusion, half3 emission, half alpha) |
|||
{ |
|||
half4 bakedOcclusion = half4(0, 0, 0, 0); |
|||
BRDFData brdfData; |
|||
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData); |
|||
|
|||
half3 lightDirectionWS; |
|||
|
|||
LightInput mainLight; |
|||
INITIALIZE_MAIN_LIGHT(mainLight); |
|||
|
|||
// No distance fade. |
|||
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirectionWS); |
|||
half NdotL = saturate(dot(normalWS, lightDirectionWS)); |
|||
half3 radiance = mainLight.color * NdotL; |
|||
|
|||
half3 indirectDiffuse = DiffuseGI(bakedGI, radiance, realtimeMainLightAtten, occlusion); |
|||
half3 indirectSpecular = GlossyEnvironmentReflection(viewDirectionWS, normalWS, brdfData.perceptualRoughness, occlusion); |
|||
|
|||
half roughness2 = brdfData.roughness * brdfData.roughness; |
|||
half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS))); |
|||
half3 color = LightweightEnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, roughness2, fresnelTerm); |
|||
|
|||
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation); |
|||
radiance *= mainLightAtten; |
|||
|
|||
color += LightweightDirectBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance; |
|||
color += vertexLighting * brdfData.diffuse; |
|||
|
|||
#ifdef _ADDITIONAL_LIGHTS |
|||
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y); |
|||
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter) |
|||
{ |
|||
LightInput light; |
|||
INITIALIZE_LIGHT(light, lightIter); |
|||
|
|||
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirectionWS); |
|||
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation); |
|||
|
|||
half NdotL = saturate(dot(normalWS, lightDirectionWS)); |
|||
half3 radiance = light.color * (lightAttenuation * NdotL); |
|||
color += LightweightDirectBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance; |
|||
} |
|||
#endif |
|||
|
|||
color += emission; |
|||
return half4(color, alpha); |
|||
} |
|||
|
|||
half4 LightweightFragmentLambert(float3 positionWS, half3 normalWS, half3 viewDirectionWS, |
|||
half fogFactor, half3 diffuseGI, half3 diffuse, half3 emission, half alpha) |
|||
{ |
|||
half4 bakedOcclusion = half4(0, 0, 0, 0); |
|||
half3 lightDirection; |
|||
|
|||
LightInput mainLight; |
|||
INITIALIZE_MAIN_LIGHT(mainLight); |
|||
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirection); |
|||
half3 NdotL = saturate(dot(normalWS, lightDirection)); |
|||
half3 lambert = mainLight.color * NdotL; |
|||
|
|||
half3 indirectDiffuse = DiffuseGI(diffuseGI, lambert, realtimeMainLightAtten, 1.0); |
|||
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation); |
|||
|
|||
half3 diffuseColor = lambert * mainLightAtten + indirectDiffuse; |
|||
|
|||
#ifdef _ADDITIONAL_LIGHTS |
|||
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y); |
|||
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter) |
|||
{ |
|||
LightInput light; |
|||
INITIALIZE_LIGHT(light, lightIter); |
|||
|
|||
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection); |
|||
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation); |
|||
|
|||
half3 attenuatedLightColor = light.color * lightAttenuation; |
|||
diffuseColor += LightingLambert(attenuatedLightColor, lightDirection, normalWS); |
|||
} |
|||
#endif |
|||
|
|||
half3 finalColor = diffuseColor * diffuse + emission; |
|||
|
|||
// Computes Fog Factor per vextex |
|||
ApplyFog(finalColor, fogFactor); |
|||
return half4(finalColor, alpha); |
|||
} |
|||
|
|||
half4 LightweightFragmentBlinnPhong(float3 positionWS, half3 normalWS, half3 viewDirectionWS, |
|||
half fogFactor, half3 diffuseGI, half3 diffuse, half4 specularGloss, half shininess, half3 emission, half alpha) |
|||
{ |
|||
half4 bakedOcclusion = half4(0, 0, 0, 0); |
|||
half3 lightDirection; |
|||
|
|||
LightInput mainLight; |
|||
INITIALIZE_MAIN_LIGHT(mainLight); |
|||
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirection); |
|||
half3 NdotL = saturate(dot(normalWS, lightDirection)); |
|||
half3 lambert = mainLight.color * NdotL; |
|||
|
|||
half3 indirectDiffuse = DiffuseGI(diffuseGI, lambert, realtimeMainLightAtten, 1.0); |
|||
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation); |
|||
|
|||
half3 diffuseColor = lambert * mainLightAtten + indirectDiffuse; |
|||
half3 specularColor = LightingSpecular(mainLight.color * mainLightAtten, lightDirection, normalWS, viewDirectionWS, specularGloss, shininess); |
|||
|
|||
#ifdef _ADDITIONAL_LIGHTS |
|||
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y); |
|||
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter) |
|||
{ |
|||
LightInput light; |
|||
INITIALIZE_LIGHT(light, lightIter); |
|||
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection); |
|||
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation); |
|||
|
|||
half3 attenuatedLightColor = light.color * lightAttenuation; |
|||
diffuseColor += LightingLambert(attenuatedLightColor, lightDirection, normalWS); |
|||
specularColor += LightingSpecular(attenuatedLightColor, lightDirection, normalWS, viewDirectionWS, specularGloss, shininess); |
|||
} |
|||
#endif |
|||
|
|||
half3 finalColor = diffuseColor * diffuse + emission; |
|||
finalColor += specularColor; |
|||
|
|||
// Computes Fog Factor per vextex |
|||
ApplyFog(finalColor, fogFactor); |
|||
return half4(finalColor, alpha); |
|||
} |
|||
#endif |
|
|||
#include "LightweightCore.hlsl" |
|||
#include "LightweightSurfaceInput.hlsl" |
|||
|
|||
#if defined (_COLORADDSUBDIFF_ON) |
|||
half4 _ColorAddSubDiff; |
|||
#endif |
|||
|
|||
#if defined(_COLORCOLOR_ON) |
|||
half3 RGBtoHSV(half3 arg1) |
|||
{ |
|||
half4 K = half4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); |
|||
half4 P = lerp(half4(arg1.bg, K.wz), half4(arg1.gb, K.xy), step(arg1.b, arg1.g)); |
|||
half4 Q = lerp(half4(P.xyw, arg1.r), half4(arg1.r, P.yzx), step(P.x, arg1.r)); |
|||
half D = Q.x - min(Q.w, Q.y); |
|||
half E = 1e-10; |
|||
return half3(abs(Q.z + (Q.w - Q.y) / (6.0 * D + E)), D / (Q.x + E), Q.x); |
|||
} |
|||
|
|||
half3 HSVtoRGB(half3 arg1) |
|||
{ |
|||
half4 K = half4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); |
|||
half3 P = abs(frac(arg1.xxx + K.xyz) * 6.0 - K.www); |
|||
return arg1.z * lerp(K.xxx, saturate(P - K.xxx), arg1.y); |
|||
} |
|||
#endif |
|||
|
|||
// Color function |
|||
#if defined(UNITY_PARTICLE_INSTANCING_ENABLED) |
|||
#define vertColor(c) \ |
|||
vertInstancingColor(c); |
|||
#else |
|||
#define vertColor(c) |
|||
#endif |
|||
|
|||
// Flipbook vertex function |
|||
#if defined(UNITY_PARTICLE_INSTANCING_ENABLED) |
|||
#if defined(_FLIPBOOK_BLENDING) |
|||
#define vertTexcoord(v, o) \ |
|||
vertInstancingUVs(v.texcoords.xy, o.texcoord, o.texcoord2AndBlend); |
|||
#else |
|||
#define vertTexcoord(v, o) \ |
|||
vertInstancingUVs(v.texcoords.xy, o.texcoord); \ |
|||
o.texcoord = TRANSFORM_TEX(o.texcoord, _MainTex); |
|||
#endif |
|||
#else |
|||
#if defined(_FLIPBOOK_BLENDING) |
|||
#define vertTexcoord(v, o) \ |
|||
o.texcoord = v.texcoords.xy; \ |
|||
o.texcoord2AndBlend.xy = v.texcoords.zw; \ |
|||
o.texcoord2AndBlend.z = v.texcoordBlend; |
|||
#else |
|||
#define vertTexcoord(v, o) \ |
|||
o.texcoord = TRANSFORM_TEX(v.texcoords.xy, _MainTex); |
|||
#endif |
|||
#endif |
|||
|
|||
// Fading vertex function |
|||
#if defined(SOFTPARTICLES_ON) || defined(_FADING_ON) |
|||
#define vertFading(o) \ |
|||
o.projectedPosition = ComputeScreenPos (clipPosition); \ |
|||
COMPUTE_EYEDEPTH(o.projectedPosition.z); |
|||
#else |
|||
#define vertFading(o) |
|||
#endif |
|||
|
|||
// Color blending fragment function |
|||
#if defined(_COLOROVERLAY_ON) |
|||
#define fragColorMode(albedo, color) \ |
|||
albedo.rgb = lerp(1 - 2 * (1 - albedo.rgb) * (1 - i.color.rgb), 2 * albedo.rgb * i.color.rgb, step(albedo.rgb, 0.5)); \ |
|||
albedo.a *= i.color.a; |
|||
#elif defined(_COLORCOLOR_ON) |
|||
#define fragColorMode(i) \ |
|||
half3 aHSL = RGBtoHSV(albedo.rgb); \ |
|||
half3 bHSL = RGBtoHSV(i.color.rgb); \ |
|||
half3 rHSL = half3(bHSL.x, bHSL.y, aHSL.z); \ |
|||
albedo = half4(HSVtoRGB(rHSL), albedo.a * i.color.a); |
|||
#elif defined(_COLORADDSUBDIFF_ON) |
|||
#define fragColorMode(i) \ |
|||
albedo.rgb = albedo.rgb + i.color.rgb * _ColorAddSubDiff.x; \ |
|||
albedo.rgb = lerp(albedo.rgb, abs(albedo.rgb), _ColorAddSubDiff.y); \ |
|||
albedo.a *= i.color.a; |
|||
#else |
|||
#define fragColorMode(i) \ |
|||
albedo *= i.color; |
|||
#endif |
|||
|
|||
// Pre-multiplied alpha helper |
|||
#if defined(_ALPHAPREMULTIPLY_ON) |
|||
#define ALBEDO_MUL albedo |
|||
#else |
|||
#define ALBEDO_MUL albedo.a |
|||
#endif |
|||
|
|||
// Soft particles fragment function |
|||
#if defined(SOFTPARTICLES_ON) && defined(_FADING_ON) |
|||
#define fragSoftParticles(i) \ |
|||
if (SOFT_PARTICLE_NEAR_FADE > 0.0 || SOFT_PARTICLE_INV_FADE_DISTANCE > 0.0) \ |
|||
{ \ |
|||
float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projectedPosition))); \ |
|||
float fade = saturate (SOFT_PARTICLE_INV_FADE_DISTANCE * ((sceneZ - SOFT_PARTICLE_NEAR_FADE) - i.projectedPosition.z)); \ |
|||
ALBEDO_MUL *= fade; \ |
|||
} |
|||
#else |
|||
#define fragSoftParticles(i) |
|||
#endif |
|||
|
|||
// Camera fading fragment function |
|||
#if defined(_FADING_ON) |
|||
#define fragCameraFading(i) \ |
|||
float cameraFade = saturate((i.projectedPosition.z - CAMERA_NEAR_FADE) * CAMERA_INV_FADE_DISTANCE); \ |
|||
ALBEDO_MUL *= cameraFade; |
|||
#else |
|||
#define fragCameraFading(i) |
|||
#endif |
|||
|
|||
// Vertex shader input |
|||
struct appdata_particles |
|||
{ |
|||
float4 vertex : POSITION; |
|||
float3 normal : NORMAL; |
|||
half4 color : COLOR; |
|||
#if defined(_FLIPBOOK_BLENDING) && !defined(UNITY_PARTICLE_INSTANCING_ENABLED) |
|||
float4 texcoords : TEXCOORD0; |
|||
float texcoordBlend : TEXCOORD1; |
|||
#else |
|||
float2 texcoords : TEXCOORD0; |
|||
#endif |
|||
#if defined(_NORMALMAP) |
|||
float4 tangent : TANGENT; |
|||
#endif |
|||
}; |
|||
|
|||
struct VertexOutputLit |
|||
{ |
|||
half4 color : COLOR; |
|||
float2 texcoord : TEXCOORD0; |
|||
#if _NORMALMAP |
|||
half3 tangent : TEXCOORD1; |
|||
half3 binormal : TEXCOORD2; |
|||
half3 normal : TEXCOORD3; |
|||
#else |
|||
half3 normal : TEXCOORD1; |
|||
#endif |
|||
|
|||
#if defined(_FLIPBOOK_BLENDING) |
|||
float3 texcoord2AndBlend : TEXCOORD4; |
|||
#endif |
|||
#if defined(SOFTPARTICLES_ON) || defined(_FADING_ON) |
|||
float4 projectedPosition : TEXCOORD5; |
|||
#endif |
|||
float4 posWS : TEXCOORD6; // xyz: position; w = fogFactor; |
|||
float4 clipPos : SV_POSITION; |
|||
}; |
|||
|
|||
half4 readTexture(TEXTURE2D_ARGS(_Texture, sampler_Texture), VertexOutputLit IN) |
|||
{ |
|||
half4 color = SAMPLE_TEXTURE2D(_Texture, sampler_Texture, IN.texcoord); |
|||
#ifdef _FLIPBOOK_BLENDING |
|||
half4 color2 = SAMPLE_TEXTURE2D(_Texture, sampler_Texture, IN.texcoord2AndBlend.xy); |
|||
color = lerp(color, color2, IN.texcoord2AndBlend.z); |
|||
#endif |
|||
return color; |
|||
} |
|||
|
|||
void InitializeSurfaceData(VertexOutputLit IN, out SurfaceData surfaceData) |
|||
{ |
|||
half4 albedo = readTexture(_MainTex, sampler_MainTex, IN) * IN.color; |
|||
|
|||
// No distortion Support |
|||
fragColorMode(IN); |
|||
fragSoftParticles(IN); |
|||
fragCameraFading(IN); |
|||
|
|||
#if defined(_METALLICGLOSSMAP) |
|||
half2 metallicGloss = readTexture(_MetallicGlossMap, sampler_MetallicGlossMap, IN).ra * half2(1.0, _Glossiness); |
|||
#else |
|||
half2 metallicGloss = half2(_Metallic, _Glossiness); |
|||
#endif |
|||
|
|||
#if defined(_NORMALMAP) |
|||
float3 normal = normalize(UnpackNormalScale(readTexture(_BumpMap, sampler_BumpMap, IN), _BumpScale)); |
|||
#else |
|||
float3 normal = float3(0, 0, 1); |
|||
#endif |
|||
|
|||
#if defined(_EMISSION) |
|||
half3 emission = readTexture(_EmissionMap, sampler_EmissionMap, IN).rgb; |
|||
#else |
|||
half3 emission = 0; |
|||
#endif |
|||
|
|||
surfaceData.albedo = albedo.rbg; |
|||
surfaceData.specular = half3(0, 0, 0); |
|||
surfaceData.normal = normal; |
|||
surfaceData.emission = emission * _EmissionColor.rgb; |
|||
surfaceData.metallic = metallicGloss.r; |
|||
surfaceData.smoothness = metallicGloss.g; |
|||
surfaceData.occlusion = 1.0; |
|||
|
|||
#if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON) || defined(_ALPHAOVERLAY_ON) |
|||
surfaceData.alpha = albedo.a; |
|||
#else |
|||
surfaceData.alpha = 1; |
|||
#endif |
|||
|
|||
#if defined(_ALPHAMODULATE_ON) |
|||
surfaceData.albedo = lerp(half3(1.0, 1.0, 1.0), surfaceData.albedo, surfaceData.alpha); |
|||
#endif |
|||
|
|||
#if defined(_ALPHATEST_ON) |
|||
clip(surfaceData.alpha - _Cutoff + 0.0001); |
|||
#endif |
|||
|
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 58997c4bd657ad848919e91029ee01eb |
|||
timeCreated: 1488965025 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef LIGHTWEIGHT_PASS_LIT_INCLUDED |
|||
#define LIGHTWEIGHT_PASS_LIT_INCLUDED |
|||
|
|||
#include "LightweightSurfaceInput.hlsl" |
|||
#include "LightweightLighting.hlsl" |
|||
|
|||
struct LightweightVertexInput |
|||
{ |
|||
float4 vertex : POSITION; |
|||
float3 normal : NORMAL; |
|||
float4 tangent : TANGENT; |
|||
float2 texcoord : TEXCOORD0; |
|||
float2 lightmapUV : TEXCOORD1; |
|||
}; |
|||
|
|||
struct LightweightVertexOutput |
|||
{ |
|||
float2 uv : TEXCOORD0; |
|||
float4 lightmapUVOrVertexSH : TEXCOORD1; // holds either lightmapUV or vertex SH. depending on LIGHTMAP_ON |
|||
float3 posWS : TEXCOORD2; |
|||
half3 normal : TEXCOORD3; |
|||
|
|||
#if _NORMALMAP |
|||
half3 tangent : TEXCOORD4; |
|||
half3 binormal : TEXCOORD5; |
|||
#endif |
|||
|
|||
half3 viewDir : TEXCOORD6; |
|||
half4 fogFactorAndVertexLight : TEXCOORD7; // x: fogFactor, yzw: vertex light |
|||
|
|||
float4 clipPos : SV_POSITION; |
|||
//UNITY_VERTEX_OUTPUT_STEREO |
|||
}; |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Vertex and Fragment functions // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
|
|||
// Vertex: Used for Standard and StandardSimpleLighting shaders |
|||
LightweightVertexOutput LitPassVertex(LightweightVertexInput v) |
|||
{ |
|||
LightweightVertexOutput o = (LightweightVertexOutput)0; |
|||
|
|||
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); |
|||
|
|||
o.posWS = TransformObjectToWorld(v.vertex.xyz); |
|||
o.clipPos = TransformWorldToHClip(o.posWS); |
|||
o.viewDir = SafeNormalize(_WorldSpaceCameraPos - o.posWS); |
|||
|
|||
// initializes o.normal and if _NORMALMAP also o.tangent and o.binormal |
|||
OUTPUT_NORMAL(v, o); |
|||
|
|||
// We either sample GI from lightmap or SH. lightmap UV and vertex SH coefficients |
|||
// are packed in lightmapUVOrVertexSH to save interpolator. |
|||
// The following funcions initialize |
|||
OUTPUT_LIGHTMAP_UV(v.lightmapUV, unity_LightmapST, o.lightmapUVOrVertexSH); |
|||
OUTPUT_SH(o.normal, o.lightmapUVOrVertexSH); |
|||
|
|||
half3 vertexLight = VertexLighting(o.posWS, o.normal); |
|||
half fogFactor = ComputeFogFactor(o.clipPos.z); |
|||
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight); |
|||
|
|||
return o; |
|||
} |
|||
|
|||
// Used for Standard shader |
|||
half4 LitPassFragment(LightweightVertexOutput IN) : SV_Target |
|||
{ |
|||
SurfaceData surfaceData; |
|||
InitializeStandardLitSurfaceData(IN.uv, surfaceData); |
|||
|
|||
#if _NORMALMAP |
|||
half3 normalWS = TangentToWorldNormal(surfaceData.normal, IN.tangent, IN.binormal, IN.normal); |
|||
#else |
|||
half3 normalWS = normalize(IN.normal); |
|||
#endif |
|||
|
|||
half3 indirectDiffuse = SampleGI(IN.lightmapUVOrVertexSH, normalWS); |
|||
float fogFactor = IN.fogFactorAndVertexLight.x; |
|||
|
|||
half4 color = LightweightFragmentPBR(IN.posWS.xyz, normalWS, IN.viewDir, indirectDiffuse, IN.fogFactorAndVertexLight.yzw, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha); |
|||
|
|||
// Computes fog factor per-vertex |
|||
ApplyFog(color.rgb, fogFactor); |
|||
return color; |
|||
} |
|||
|
|||
// Used for StandardSimpleLighting shader |
|||
half4 LitPassFragmentSimple(LightweightVertexOutput IN) : SV_Target |
|||
{ |
|||
float2 uv = IN.uv; |
|||
|
|||
half4 diffuseAlpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv); |
|||
half3 diffuse = diffuseAlpha.rgb * _Color.rgb; |
|||
|
|||
#ifdef _GLOSSINESS_FROM_BASE_ALPHA |
|||
half alpha = _Color.a; |
|||
#else |
|||
half alpha = diffuseAlpha.a * _Color.a; |
|||
#endif |
|||
|
|||
AlphaDiscard(alpha, _Cutoff); |
|||
|
|||
#if _NORMALMAP |
|||
half3 normalTangent = Normal(uv); |
|||
half3 normalWS = TangentToWorldNormal(normalTangent, IN.tangent, IN.binormal, IN.normal); |
|||
#else |
|||
half3 normalWS = normalize(IN.normal); |
|||
#endif |
|||
|
|||
half3 emission = Emission(uv); |
|||
|
|||
half3 viewDirectionWS = SafeNormalize(IN.viewDir.xyz); |
|||
float3 positionWS = IN.posWS.xyz; |
|||
|
|||
half3 diffuseGI = SampleGI(IN.lightmapUVOrVertexSH, normalWS); |
|||
|
|||
#if _VERTEX_LIGHTS |
|||
diffuseGI += IN.fogFactorAndVertexLight.yzw; |
|||
#endif |
|||
|
|||
half shininess = _Shininess * 128.0h; |
|||
half fogFactor = IN.fogFactorAndVertexLight.x; |
|||
|
|||
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR) |
|||
half4 specularGloss = SpecularGloss(uv, diffuseAlpha.a); |
|||
return LightweightFragmentBlinnPhong(positionWS, normalWS, viewDirectionWS, fogFactor, diffuseGI, diffuse, specularGloss, shininess, emission, alpha); |
|||
#else |
|||
return LightweightFragmentLambert(positionWS, normalWS, viewDirectionWS, fogFactor, diffuseGI, diffuse, emission, alpha); |
|||
#endif |
|||
}; |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_PASS_META_INCLUDED |
|||
#define LIGHTWEIGHT_PASS_META_INCLUDED |
|||
|
|||
#include "LightweightSurfaceInput.hlsl" |
|||
#include "LightweightLighting.hlsl" |
|||
|
|||
CBUFFER_START(UnityMetaPass) |
|||
// x = use uv1 as raster position |
|||
// y = use uv2 as raster position |
|||
bool4 unity_MetaVertexControl; |
|||
|
|||
// x = return albedo |
|||
// y = return normal |
|||
bool4 unity_MetaFragmentControl; |
|||
CBUFFER_END |
|||
|
|||
float unity_OneOverOutputBoost; |
|||
float unity_MaxOutputValue; |
|||
float unity_UseLinearSpace; |
|||
|
|||
struct MetaInput |
|||
{ |
|||
half3 Albedo; |
|||
half3 Emission; |
|||
half3 SpecularColor; |
|||
}; |
|||
|
|||
struct MetaVertexInput |
|||
{ |
|||
float4 vertex : POSITION; |
|||
half3 normal : NORMAL; |
|||
float2 uv0 : TEXCOORD0; |
|||
float2 uv1 : TEXCOORD1; |
|||
float2 uv2 : TEXCOORD2; |
|||
#ifdef _TANGENT_TO_WORLD |
|||
half4 tangent : TANGENT; |
|||
#endif |
|||
}; |
|||
|
|||
struct MetaVertexOuput |
|||
{ |
|||
float4 pos : SV_POSITION; |
|||
float2 uv : TEXCOORD0; |
|||
}; |
|||
|
|||
float4 MetaVertexPosition(float4 vertex, float2 uv1, float2 uv2, float4 lightmapST, float4 dynlightmapST) |
|||
{ |
|||
if (unity_MetaVertexControl.x) |
|||
{ |
|||
vertex.xy = uv1 * lightmapST.xy + lightmapST.zw; |
|||
// OpenGL right now needs to actually use incoming vertex position, |
|||
// so use it in a very dummy way |
|||
vertex.z = vertex.z > 0 ? 1.0e-4f : 0.0f; |
|||
} |
|||
if (unity_MetaVertexControl.y) |
|||
{ |
|||
vertex.xy = uv2 * dynlightmapST.xy + dynlightmapST.zw; |
|||
// OpenGL right now needs to actually use incoming vertex position, |
|||
// so use it in a very dummy way |
|||
vertex.z = vertex.z > 0 ? 1.0e-4f : 0.0f; |
|||
} |
|||
return TransformObjectToHClip(vertex.xyz); |
|||
} |
|||
|
|||
half4 MetaFragment(MetaInput IN) |
|||
{ |
|||
half4 res = 0; |
|||
if (unity_MetaFragmentControl.x) |
|||
{ |
|||
res = half4(IN.Albedo, 1); |
|||
|
|||
// d3d9 shader compiler doesn't like NaNs and infinity. |
|||
unity_OneOverOutputBoost = saturate(unity_OneOverOutputBoost); |
|||
|
|||
// Disable pow(f, e) warning will not work with negative values |
|||
#pragma warning (disable : 3571) |
|||
// Apply Albedo Boost from LightmapSettings. |
|||
res.rgb = clamp(pow(res.rgb, unity_OneOverOutputBoost), 0, unity_MaxOutputValue); |
|||
#pragma warning (enable : 3571) |
|||
} |
|||
if (unity_MetaFragmentControl.y) |
|||
{ |
|||
res = half4(IN.Emission, 1.0); |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
MetaVertexOuput LightweightVertexMeta(MetaVertexInput v) |
|||
{ |
|||
MetaVertexOuput o; |
|||
o.pos = MetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST); |
|||
o.uv = TRANSFORM_TEX(v.uv0, _MainTex); |
|||
return o; |
|||
} |
|||
|
|||
half4 LightweightFragmentMeta(MetaVertexOuput i) : SV_Target |
|||
{ |
|||
SurfaceData surfaceData; |
|||
InitializeStandardLitSurfaceData(i.uv, surfaceData); |
|||
|
|||
BRDFData brdfData; |
|||
InitializeBRDFData(surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.alpha, brdfData); |
|||
|
|||
MetaInput o; |
|||
o.Albedo = brdfData.diffuse + brdfData.specular * brdfData.roughness * 0.5; |
|||
o.SpecularColor = surfaceData.specular; |
|||
o.Emission = surfaceData.emission; |
|||
|
|||
return MetaFragment(o); |
|||
} |
|||
|
|||
half4 LightweightFragmentMetaSimple(MetaVertexOuput i) : SV_Target |
|||
{ |
|||
float2 uv = i.uv; |
|||
MetaInput o; |
|||
o.Albedo = _Color.rgb * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv).rgb; |
|||
o.SpecularColor = SpecularGloss(uv, 1.0).xyz; |
|||
o.Emission = Emission(uv); |
|||
|
|||
return MetaFragment(o); |
|||
} |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_PASS_SHADOW_INCLUDED |
|||
#define LIGHTWEIGHT_PASS_SHADOW_INCLUDED |
|||
|
|||
#include "LightweightCore.hlsl" |
|||
|
|||
float4 ShadowPassVertex(float4 pos : POSITION) : SV_POSITION |
|||
{ |
|||
float4 clipPos = TransformObjectToHClip(pos.xyz); |
|||
#if defined(UNITY_REVERSED_Z) |
|||
clipPos.z = min(clipPos.z, UNITY_NEAR_CLIP_VALUE); |
|||
#else |
|||
clipPos.z = max(clipPos.z, UNITY_NEAR_CLIP_VALUE); |
|||
#endif |
|||
return clipPos; |
|||
} |
|||
|
|||
half4 ShadowPassFragment() : SV_TARGET |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_SHADOWS_INCLUDED |
|||
#define LIGHTWEIGHT_SHADOWS_INCLUDED |
|||
|
|||
#include "LightweightInput.hlsl" |
|||
#include "ShaderLibrary\Common.hlsl" |
|||
|
|||
#define MAX_SHADOW_CASCADES 4 |
|||
|
|||
#if defined(_HARD_SHADOWS) || defined(_SOFT_SHADOWS) || defined(_HARD_SHADOWS_CASCADES) || defined(_SOFT_SHADOWS_CASCADES) |
|||
#define _SHADOWS |
|||
#endif |
|||
|
|||
#if defined(_HARD_SHADOWS_CASCADES) || defined(_SOFT_SHADOWS_CASCADES) |
|||
#define _SHADOW_CASCADES |
|||
#endif |
|||
|
|||
#ifdef _SHADOWS |
|||
#define LIGHTWEIGHT_SHADOW_ATTENUATION(posWorld, vertexNormal, shadowDir) ComputeShadowAttenuation(posWorld, vertexNormal, shadowDir) |
|||
#else |
|||
#define LIGHTWEIGHT_SHADOW_ATTENUATION(posWorld, vertexNormal, shadowDir) 1.0h |
|||
#endif |
|||
|
|||
// TODO: replace with TEXTURE2D_SHADOW as soon as all APIs defined it. |
|||
#if !defined(SHADER_API_GLES) && !defined(SHADER_API_GLES3) |
|||
#define TEXTURE2D_SHADOW(tex) TEXTURE2D(tex); |
|||
#endif |
|||
|
|||
TEXTURE2D_SHADOW(_ShadowMap); |
|||
SAMPLER2D_SHADOW(sampler_ShadowMap); |
|||
float4x4 _WorldToShadow[MAX_SHADOW_CASCADES]; |
|||
float4 _DirShadowSplitSpheres[MAX_SHADOW_CASCADES]; |
|||
half4 _ShadowOffset0; |
|||
half4 _ShadowOffset1; |
|||
half4 _ShadowOffset2; |
|||
half4 _ShadowOffset3; |
|||
half4 _ShadowData; // (x: 1.0 - shadowStrength, y: bias, z: normal bias, w: near plane offset) |
|||
|
|||
float ApplyDepthBias(float clipZ) |
|||
{ |
|||
#ifdef UNITY_REVERSED_Z |
|||
return clipZ + _ShadowData.y; |
|||
#endif |
|||
|
|||
return clipZ - _ShadowData.y; |
|||
} |
|||
|
|||
inline half SampleShadowmap(float4 shadowCoord) |
|||
{ |
|||
float3 coord = shadowCoord.xyz /= shadowCoord.w; |
|||
coord.z = saturate(ApplyDepthBias(coord.z)); |
|||
if (coord.x <= 0 || coord.x >= 1 || coord.y <= 0 || coord.y >= 1) |
|||
return 1; |
|||
|
|||
#if defined(_SOFT_SHADOWS) || defined(_SOFT_SHADOWS_CASCADES) |
|||
// 4-tap hardware comparison |
|||
half4 attenuation; |
|||
attenuation.x = SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, coord + _ShadowOffset0.xyz); |
|||
attenuation.y = SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, coord + _ShadowOffset1.xyz); |
|||
attenuation.z = SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, coord + _ShadowOffset2.xyz); |
|||
attenuation.w = SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, coord + _ShadowOffset3.xyz); |
|||
lerp(attenuation, 1.0, _ShadowData.xxxx); |
|||
return dot(attenuation, 0.25); |
|||
#else |
|||
// 1-tap hardware comparison |
|||
half attenuation = SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, coord); |
|||
return lerp(attenuation, 1.0, _ShadowData.x); |
|||
#endif |
|||
} |
|||
|
|||
inline half ComputeCascadeIndex(float3 wpos) |
|||
{ |
|||
float3 fromCenter0 = wpos.xyz - _DirShadowSplitSpheres[0].xyz; |
|||
float3 fromCenter1 = wpos.xyz - _DirShadowSplitSpheres[1].xyz; |
|||
float3 fromCenter2 = wpos.xyz - _DirShadowSplitSpheres[2].xyz; |
|||
float3 fromCenter3 = wpos.xyz - _DirShadowSplitSpheres[3].xyz; |
|||
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3)); |
|||
|
|||
float4 vDirShadowSplitSphereSqRadii; |
|||
vDirShadowSplitSphereSqRadii.x = _DirShadowSplitSpheres[0].w; |
|||
vDirShadowSplitSphereSqRadii.y = _DirShadowSplitSpheres[1].w; |
|||
vDirShadowSplitSphereSqRadii.z = _DirShadowSplitSpheres[2].w; |
|||
vDirShadowSplitSphereSqRadii.w = _DirShadowSplitSpheres[3].w; |
|||
half4 weights = half4(distances2 < vDirShadowSplitSphereSqRadii); |
|||
weights.yzw = saturate(weights.yzw - weights.xyz); |
|||
return 4 - dot(weights, half4(4, 3, 2, 1)); |
|||
} |
|||
|
|||
inline half ComputeShadowAttenuation(float3 posWorld, half3 vertexNormal, half3 shadowDir) |
|||
{ |
|||
half NdotL = dot(vertexNormal, shadowDir); |
|||
half bias = saturate(1.0 - NdotL) * _ShadowData.z; |
|||
|
|||
float3 posWorldOffsetNormal = posWorld + vertexNormal * bias; |
|||
|
|||
int cascadeIndex = 0; |
|||
#ifdef _SHADOW_CASCADES |
|||
cascadeIndex = ComputeCascadeIndex(posWorldOffsetNormal); |
|||
if (cascadeIndex >= MAX_SHADOW_CASCADES) |
|||
return 1.0; |
|||
#endif |
|||
|
|||
float4 shadowCoord = mul(_WorldToShadow[cascadeIndex], float4(posWorldOffsetNormal, 1.0)); |
|||
return SampleShadowmap(shadowCoord); |
|||
} |
|||
|
|||
half MixRealtimeAndBakedOcclusion(half realtimeAttenuation, half4 bakedOcclusion, half4 distanceAttenuation) |
|||
{ |
|||
#if defined(LIGHTMAP_ON) |
|||
#if defined(_MIXED_LIGHTING_SHADOWMASK) |
|||
// TODO: |
|||
#elif defined(_MIXED_LIGHTING_SUBTRACTIVE) |
|||
// Subtractive Light mode has direct light contribution baked into lightmap for mixed lights. |
|||
// We need to remove direct realtime contribution from mixed lights |
|||
// distanceAttenuation.w is set 0.0 if this light is mixed, 1.0 otherwise. |
|||
return realtimeAttenuation * distanceAttenuation.w; |
|||
#endif |
|||
#endif |
|||
|
|||
return realtimeAttenuation; |
|||
} |
|||
|
|||
inline half3 SubtractDirectMainLightFromLightmap(half3 lightmap, half attenuation, half3 lambert) |
|||
{ |
|||
// Let's try to make realtime shadows work on a surface, which already contains |
|||
// baked lighting and shadowing from the main sun light. |
|||
// Summary: |
|||
// 1) Calculate possible value in the shadow by subtracting estimated light contribution from the places occluded by realtime shadow: |
|||
// a) preserves other baked lights and light bounces |
|||
// b) eliminates shadows on the geometry facing away from the light |
|||
// 2) Clamp against user defined ShadowColor. |
|||
// 3) Pick original lightmap value, if it is the darkest one. |
|||
|
|||
|
|||
// 1) Gives good estimate of illumination as if light would've been shadowed during the bake. |
|||
// Preserves bounce and other baked lights |
|||
// No shadows on the geometry facing away from the light |
|||
half shadowStrength = _ShadowData.x; |
|||
half3 estimatedLightContributionMaskedByInverseOfShadow = lambert * (1.0 - attenuation); |
|||
half3 subtractedLightmap = lightmap - estimatedLightContributionMaskedByInverseOfShadow; |
|||
|
|||
// 2) Allows user to define overall ambient of the scene and control situation when realtime shadow becomes too dark. |
|||
half3 realtimeShadow = max(subtractedLightmap, _SubtractiveShadowColor.xyz); |
|||
realtimeShadow = lerp(realtimeShadow, lightmap, shadowStrength); |
|||
|
|||
// 3) Pick darkest color |
|||
return min(lightmap, realtimeShadow); |
|||
} |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_SURFACE_INPUT_INCLUDED |
|||
#define LIGHTWEIGHT_SURFACE_INPUT_INCLUDED |
|||
|
|||
#include "LightweightCore.hlsl" |
|||
#include "ShaderLibrary/Packing.hlsl" |
|||
#include "ShaderLibrary/SampleUVMapping.hlsl" |
|||
|
|||
#ifdef _SPECULAR_SETUP |
|||
#define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_SpecGlossMap, sampler_SpecGlossMap, uv) |
|||
#else |
|||
#define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_MetallicGlossMap, sampler_MetallicGlossMap, uv) |
|||
#endif |
|||
|
|||
CBUFFER_START(MaterialProperties) |
|||
half4 _MainTex_ST; |
|||
half4 _Color; |
|||
half _Cutoff; |
|||
half _Glossiness; |
|||
half _GlossMapScale; |
|||
half _SmoothnessTextureChannel; |
|||
half _Metallic; |
|||
half4 _SpecColor; |
|||
half _BumpScale; |
|||
half _OcclusionStrength; |
|||
half4 _EmissionColor; |
|||
half _Shininess; |
|||
CBUFFER_END |
|||
|
|||
TEXTURE2D(_MainTex); SAMPLER2D(sampler_MainTex); |
|||
TEXTURE2D(_MetallicGlossMap); SAMPLER2D(sampler_MetallicGlossMap); |
|||
TEXTURE2D(_SpecGlossMap); SAMPLER2D(sampler_SpecGlossMap); |
|||
TEXTURE2D(_BumpMap); SAMPLER2D(sampler_BumpMap); |
|||
TEXTURE2D(_OcclusionMap); SAMPLER2D(sampler_OcclusionMap); |
|||
TEXTURE2D(_EmissionMap); SAMPLER2D(sampler_EmissionMap); |
|||
|
|||
// Must match Lightweigth ShaderGraph master node |
|||
struct SurfaceData |
|||
{ |
|||
half3 albedo; |
|||
half3 specular; |
|||
half metallic; |
|||
half smoothness; |
|||
half3 normal; |
|||
half3 emission; |
|||
half occlusion; |
|||
half alpha; |
|||
}; |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Material Property Helpers // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
inline half Alpha(half albedoAlpha) |
|||
{ |
|||
#if defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A) |
|||
half alpha = _Color.a; |
|||
#else |
|||
half alpha = albedoAlpha * _Color.a; |
|||
#endif |
|||
|
|||
#if defined(_ALPHATEST_ON) |
|||
clip(alpha - _Cutoff); |
|||
#endif |
|||
|
|||
return alpha; |
|||
} |
|||
|
|||
half3 Normal(float2 uv) |
|||
{ |
|||
#if _NORMALMAP |
|||
return UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, uv), _BumpScale); |
|||
#else |
|||
return half3(0.0h, 0.0h, 1.0h); |
|||
#endif |
|||
} |
|||
|
|||
half4 SpecularGloss(half2 uv, half alpha) |
|||
{ |
|||
half4 specularGloss = half4(0, 0, 0, 1); |
|||
#ifdef _SPECGLOSSMAP |
|||
specularGloss = SAMPLE_TEXTURE2D(_SpecGlossMap, sampler_SpecGlossMap, uv); |
|||
specularGloss.rgb = specularGloss.rgb; |
|||
#elif defined(_SPECULAR_COLOR) |
|||
specularGloss = _SpecColor; |
|||
#endif |
|||
|
|||
#ifdef _GLOSSINESS_FROM_BASE_ALPHA |
|||
specularGloss.a = alpha; |
|||
#endif |
|||
return specularGloss; |
|||
} |
|||
|
|||
half4 MetallicSpecGloss(float2 uv, half albedoAlpha) |
|||
{ |
|||
half4 specGloss; |
|||
|
|||
#ifdef _METALLICSPECGLOSSMAP |
|||
specGloss = specGloss = SAMPLE_METALLICSPECULAR(uv); |
|||
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A |
|||
specGloss.a = albedoAlpha * _GlossMapScale; |
|||
#else |
|||
specGloss.a *= _GlossMapScale; |
|||
#endif |
|||
|
|||
#else // _METALLICSPECGLOSSMAP |
|||
#if _SPECULAR_SETUP |
|||
specGloss.rgb = _SpecColor.rgb; |
|||
#else |
|||
specGloss.rgb = _Metallic.rrr; |
|||
#endif |
|||
|
|||
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A |
|||
specGloss.a = albedoAlpha * _GlossMapScale; |
|||
#else |
|||
specGloss.a = _Glossiness; |
|||
#endif |
|||
#endif |
|||
|
|||
return specGloss; |
|||
} |
|||
|
|||
half Occlusion(float2 uv) |
|||
{ |
|||
#ifdef _OCCLUSIONMAP |
|||
#if (SHADER_TARGET < 30) |
|||
// SM20: instruction count limitation |
|||
// SM20: simpler occlusion |
|||
return SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g; |
|||
#else |
|||
half occ = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g; |
|||
return LerpOneTo(occ, _OcclusionStrength); |
|||
#endif |
|||
#else |
|||
return 1.0; |
|||
#endif |
|||
} |
|||
|
|||
half3 Emission(float2 uv) |
|||
{ |
|||
#ifndef _EMISSION |
|||
return 0; |
|||
#else |
|||
return SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, uv).rgb * _EmissionColor.rgb; |
|||
#endif |
|||
} |
|||
|
|||
inline void InitializeStandardLitSurfaceData(float2 uv, out SurfaceData outSurfaceData) |
|||
{ |
|||
half4 albedoAlpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv); |
|||
|
|||
half4 specGloss = MetallicSpecGloss(uv, albedoAlpha.a); |
|||
outSurfaceData.albedo = albedoAlpha.rgb * _Color.rgb; |
|||
|
|||
#if _SPECULAR_SETUP |
|||
outSurfaceData.metallic = 1.0h; |
|||
outSurfaceData.specular = specGloss.rgb; |
|||
#else |
|||
outSurfaceData.metallic = specGloss.r; |
|||
outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h); |
|||
#endif |
|||
|
|||
outSurfaceData.smoothness = specGloss.a; |
|||
outSurfaceData.normal = Normal(uv); |
|||
outSurfaceData.occlusion = Occlusion(uv); |
|||
outSurfaceData.emission = Emission(uv); |
|||
outSurfaceData.alpha = Alpha(albedoAlpha.a); |
|||
} |
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 37244f7798708ba449e9893ad27f77f5 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
// UNITY_SHADER_NO_UPGRADE |
|||
|
|||
#ifndef LIGHTWEIGHT_SHADER_VARIABLES_INCLUDED |
|||
#define LIGHTWEIGHT_SHADER_VARIABLES_INCLUDED |
|||
|
|||
#include "ShaderLibrary/Common.hlsl" |
|||
|
|||
// CAUTION: |
|||
// Currently the shaders compiler always include regualr Unity shaderVariables, so I get a conflict here were UNITY_SHADER_VARIABLES_INCLUDED is already define, this need to be fixed. |
|||
// As I haven't change the variables name yet, I simply don't define anything, and I put the transform function at the end of the file outside the guard header. |
|||
// This need to be fixed. |
|||
|
|||
#if defined (DIRECTIONAL_COOKIE) || defined (DIRECTIONAL) |
|||
#define USING_DIRECTIONAL_LIGHT |
|||
#endif |
|||
|
|||
#if defined(UNITY_SINGLE_PASS_STEREO) || defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED) |
|||
#define USING_STEREO_MATRICES |
|||
#endif |
|||
|
|||
#if defined(USING_STEREO_MATRICES) |
|||
#define glstate_matrix_projection unity_StereoMatrixP[unity_StereoEyeIndex] |
|||
#define unity_MatrixV unity_StereoMatrixV[unity_StereoEyeIndex] |
|||
#define unity_MatrixInvV unity_StereoMatrixInvV[unity_StereoEyeIndex] |
|||
#define unity_MatrixVP unity_StereoMatrixVP[unity_StereoEyeIndex] |
|||
|
|||
#define unity_CameraProjection unity_StereoCameraProjection[unity_StereoEyeIndex] |
|||
#define unity_CameraInvProjection unity_StereoCameraInvProjection[unity_StereoEyeIndex] |
|||
#define unity_WorldToCamera unity_StereoWorldToCamera[unity_StereoEyeIndex] |
|||
#define unity_CameraToWorld unity_StereoCameraToWorld[unity_StereoEyeIndex] |
|||
#define _WorldSpaceCameraPos unity_StereoWorldSpaceCameraPos[unity_StereoEyeIndex] |
|||
#endif |
|||
|
|||
#define UNITY_LIGHTMODEL_AMBIENT (glstate_lightmodel_ambient * 2) |
|||
|
|||
// ---------------------------------------------------------------------------- |
|||
|
|||
CBUFFER_START(UnityPerCamera) |
|||
// Time (t = time since current level load) values from Unity |
|||
float4 _Time; // (t/20, t, t*2, t*3) |
|||
float4 _SinTime; // sin(t/8), sin(t/4), sin(t/2), sin(t) |
|||
float4 _CosTime; // cos(t/8), cos(t/4), cos(t/2), cos(t) |
|||
float4 unity_DeltaTime; // dt, 1/dt, smoothdt, 1/smoothdt |
|||
|
|||
#if !defined(USING_STEREO_MATRICES) |
|||
float3 _WorldSpaceCameraPos; |
|||
#endif |
|||
|
|||
// x = 1 or -1 (-1 if projection is flipped) |
|||
// y = near plane |
|||
// z = far plane |
|||
// w = 1/far plane |
|||
float4 _ProjectionParams; |
|||
|
|||
// x = width |
|||
// y = height |
|||
// z = 1 + 1.0/width |
|||
// w = 1 + 1.0/height |
|||
float4 _ScreenParams; |
|||
|
|||
// Values used to linearize the Z buffer (http://www.humus.name/temp/Linearize%20depth.txt) |
|||
// x = 1-far/near |
|||
// y = far/near |
|||
// z = x/far |
|||
// w = y/far |
|||
// or in case of a reversed depth buffer (UNITY_REVERSED_Z is 1) |
|||
// x = -1+far/near |
|||
// y = 1 |
|||
// z = x/far |
|||
// w = 1/far |
|||
float4 _ZBufferParams; |
|||
|
|||
// x = orthographic camera's width |
|||
// y = orthographic camera's height |
|||
// z = unused |
|||
// w = 1.0 if camera is ortho, 0.0 if perspective |
|||
float4 unity_OrthoParams; |
|||
CBUFFER_END |
|||
|
|||
|
|||
CBUFFER_START(UnityPerCameraRare) |
|||
float4 unity_CameraWorldClipPlanes[6]; |
|||
|
|||
#if !defined(USING_STEREO_MATRICES) |
|||
// Projection matrices of the camera. Note that this might be different from projection matrix |
|||
// that is set right now, e.g. while rendering shadows the matrices below are still the projection |
|||
// of original camera. |
|||
float4x4 unity_CameraProjection; |
|||
float4x4 unity_CameraInvProjection; |
|||
float4x4 unity_WorldToCamera; |
|||
float4x4 unity_CameraToWorld; |
|||
#endif |
|||
CBUFFER_END |
|||
|
|||
// ---------------------------------------------------------------------------- |
|||
|
|||
CBUFFER_START(UnityPerDraw : register(b0)) |
|||
#ifdef UNITY_USE_PREMULTIPLIED_MATRICES |
|||
float4x4 glstate_matrix_mvp; |
|||
float4x4 glstate_matrix_modelview0; |
|||
float4x4 glstate_matrix_invtrans_modelview0; |
|||
#endif |
|||
|
|||
float4x4 unity_ObjectToWorld; |
|||
float4x4 unity_WorldToObject; |
|||
float4 unity_LODFade; // x is the fade value ranging within [0,1]. y is x quantized into 16 levels |
|||
float4 unity_WorldTransformParams; // w is usually 1.0, or -1.0 for odd-negative scale transforms |
|||
|
|||
float4 unity_LightmapST; |
|||
float4 unity_DynamicLightmapST; |
|||
|
|||
// SH lighting environment |
|||
float4 unity_SHAr; |
|||
float4 unity_SHAg; |
|||
float4 unity_SHAb; |
|||
float4 unity_SHBr; |
|||
float4 unity_SHBg; |
|||
float4 unity_SHBb; |
|||
float4 unity_SHC; |
|||
|
|||
// x = Disabled(0)/Enabled(1) |
|||
// y = Computation are done in global space(0) or local space(1) |
|||
// z = Texel size on U texture coordinate |
|||
float4 unity_ProbeVolumeParams; |
|||
float4x4 unity_ProbeVolumeWorldToObject; |
|||
float3 unity_ProbeVolumeSizeInv; |
|||
float3 unity_ProbeVolumeMin; |
|||
|
|||
// This contain occlusion factor from 0 to 1 for dynamic objects (no SH here) |
|||
float4 unity_ProbesOcclusion; |
|||
|
|||
// HDR environment map decode instructions |
|||
half4 unity_SpecCube0_HDR; |
|||
|
|||
CBUFFER_END |
|||
|
|||
#if defined(USING_STEREO_MATRICES) |
|||
CBUFFER_START(UnityStereoGlobals) |
|||
float4x4 unity_StereoMatrixP[2]; |
|||
float4x4 unity_StereoMatrixV[2]; |
|||
float4x4 unity_StereoMatrixInvV[2]; |
|||
float4x4 unity_StereoMatrixVP[2]; |
|||
|
|||
float4x4 unity_StereoCameraProjection[2]; |
|||
float4x4 unity_StereoCameraInvProjection[2]; |
|||
float4x4 unity_StereoWorldToCamera[2]; |
|||
float4x4 unity_StereoCameraToWorld[2]; |
|||
|
|||
float3 unity_StereoWorldSpaceCameraPos[2]; |
|||
float4 unity_StereoScaleOffset[2]; |
|||
CBUFFER_END |
|||
#endif |
|||
|
|||
#if defined(USING_STEREO_MATRICES) && defined(UNITY_STEREO_MULTIVIEW_ENABLED) |
|||
CBUFFER_START(UnityStereoEyeIndices) |
|||
float4 unity_StereoEyeIndices[2]; |
|||
CBUFFER_END |
|||
#endif |
|||
|
|||
#if defined(UNITY_STEREO_MULTIVIEW_ENABLED) && defined(SHADER_STAGE_VERTEX) |
|||
#define unity_StereoEyeIndex UNITY_VIEWID |
|||
UNITY_DECLARE_MULTIVIEW(2); |
|||
#elif defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED) |
|||
static uint unity_StereoEyeIndex; |
|||
#elif defined(UNITY_SINGLE_PASS_STEREO) |
|||
CBUFFER_START(UnityStereoEyeIndex) |
|||
int unity_StereoEyeIndex; |
|||
CBUFFER_END |
|||
#endif |
|||
|
|||
CBUFFER_START(UnityPerDrawRare) |
|||
float4x4 glstate_matrix_transpose_modelview0; |
|||
CBUFFER_END |
|||
|
|||
// ---------------------------------------------------------------------------- |
|||
|
|||
CBUFFER_START(UnityPerFrame) |
|||
float4 glstate_lightmodel_ambient; |
|||
float4 unity_AmbientSky; |
|||
float4 unity_AmbientEquator; |
|||
float4 unity_AmbientGround; |
|||
float4 unity_IndirectSpecColor; |
|||
float4 unity_FogParams; |
|||
half4 unity_FogColor; |
|||
|
|||
#if !defined(USING_STEREO_MATRICES) |
|||
float4x4 glstate_matrix_projection; |
|||
float4x4 unity_MatrixV; |
|||
float4x4 unity_MatrixInvV; |
|||
float4x4 unity_MatrixVP; |
|||
float4 unity_StereoScaleOffset; |
|||
int unity_StereoEyeIndex; |
|||
#endif |
|||
|
|||
float4 unity_ShadowColor; |
|||
CBUFFER_END |
|||
|
|||
// ---------------------------------------------------------------------------- |
|||
|
|||
TEXTURE2D_FLOAT(_MainDepthTexture); |
|||
SAMPLER2D(sampler_MainDepthTexture); |
|||
|
|||
TEXTURECUBE(unity_SpecCube0); |
|||
SAMPLERCUBE(samplerunity_SpecCube0); |
|||
|
|||
// Main lightmap |
|||
TEXTURE2D(unity_Lightmap); |
|||
SAMPLER2D(samplerunity_Lightmap); |
|||
// Dual or directional lightmap (always used with unity_Lightmap, so can share sampler) |
|||
TEXTURE2D(unity_LightmapInd); |
|||
|
|||
// We can have shadowMask only if we have lightmap, so no sampler |
|||
TEXTURE2D(unity_ShadowMask); |
|||
|
|||
// ---------------------------------------------------------------------------- |
|||
|
|||
// TODO: all affine matrices should be 3x4. |
|||
// TODO: sort these vars by the frequency of use (descending), and put commonly used vars together. |
|||
// Note: please use UNITY_MATRIX_X macros instead of referencing matrix variables directly. |
|||
CBUFFER_START(UnityPerPass) |
|||
float4x4 _PrevViewProjMatrix; |
|||
float4x4 _ViewProjMatrix; |
|||
float4x4 _NonJitteredViewProjMatrix; |
|||
float4x4 _ViewMatrix; |
|||
float4x4 _ProjMatrix; |
|||
float4x4 _InvViewProjMatrix; |
|||
float4x4 _InvViewMatrix; |
|||
float4x4 _InvProjMatrix; |
|||
float4 _InvProjParam; |
|||
float4 _ScreenSize; // {w, h, 1/w, 1/h} |
|||
float4 _FrustumPlanes[6]; // {(a, b, c) = N, d = -dot(N, P)} [L, R, T, B, N, F] |
|||
CBUFFER_END |
|||
|
|||
float4x4 OptimizeProjectionMatrix(float4x4 M) |
|||
{ |
|||
// Matrix format (x = non-constant value). |
|||
// Orthographic Perspective Combined(OR) |
|||
// | x 0 0 x | | x 0 x 0 | | x 0 x x | |
|||
// | 0 x 0 x | | 0 x x 0 | | 0 x x x | |
|||
// | x x x x | | x x x x | | x x x x | <- oblique projection row |
|||
// | 0 0 0 1 | | 0 0 x 0 | | 0 0 x x | |
|||
// Notice that some values are always 0. |
|||
// We can avoid loading and doing math with constants. |
|||
M._21_41 = 0; |
|||
M._12_42 = 0; |
|||
return M; |
|||
} |
|||
|
|||
#include "ShaderVariables/LightweightShaderVariablesCamera.hlsl" |
|||
#include "ShaderVariables/LightweightShaderVariablesFunctions.hlsl" |
|||
|
|||
#endif // LIGHTWEIGHT_SHADER_VARIABLES_INCLUDED |
|
|||
fileFormatVersion: 2 |
|||
guid: 6564342aa7c6ca44a86b97323a311d74 |
|||
ShaderImporter: |
|||
externalObjects: {} |
|||
defaultTextures: [] |
|||
nonModifiableTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifdef UNITY_SHADER_VARIABLES_MATRIX_DEFS_LEGACY_UNITY_INCLUDED |
|||
#error Mixing LightweightCamera and legacy Unity matrix definitions |
|||
#endif |
|||
|
|||
#ifndef UNITY_SHADER_VARIABLES_MATRIX_DEFS_LIGHTWEIGHT_INCLUDED |
|||
#define UNITY_SHADER_VARIABLES_MATRIX_DEFS_LIGHTWEIGHT_INCLUDED |
|||
|
|||
#define UNITY_MATRIX_M unity_ObjectToWorld |
|||
#define UNITY_MATRIX_I_M unity_WorldToObject |
|||
#define UNITY_MATRIX_V unity_MatrixV |
|||
#define UNITY_MATRIX_I_V unity_MatrixInvV |
|||
#define UNITY_MATRIX_P OptimizeProjectionMatrix(glstate_matrix_projection) |
|||
#define UNITY_MATRIX_I_P ERROR_UNITY_MATRIX_I_P_IS_NOT_DEFINED |
|||
#define UNITY_MATRIX_VP unity_MatrixVP |
|||
#define UNITY_MATRIX_I_VP ERROR_UNITY_MATRIX_I_VP_IS_NOT_DEFINED |
|||
#define UNITY_MATRIX_MV mul(UNITY_MATRIX_V, UNITY_MATRIX_M) |
|||
#define UNITY_MATRIX_T_MV transpose(UNITY_MATRIX_MV) |
|||
#define UNITY_MATRIX_IT_MV transpose(mul(UNITY_MATRIX_I_M, UNITY_MATRIX_I_V)) |
|||
#define UNITY_MATRIX_MVP mul(UNITY_MATRIX_VP, UNITY_MATRIX_M) |
|||
|
|||
#endif // UNITY_SHADER_VARIABLES_MATRIX_DEFS_LIGHTWEIGHT_INCLUDED |
|
|||
fileFormatVersion: 2 |
|||
guid: 034efa35d41944e41a5ac36341ffd9c7 |
|||
ShaderImporter: |
|||
externalObjects: {} |
|||
defaultTextures: [] |
|||
nonModifiableTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef UNITY_SHADER_VARIABLES_FUNCTIONS_INCLUDED |
|||
#define UNITY_SHADER_VARIABLES_FUNCTIONS_INCLUDED |
|||
|
|||
float4x4 GetWorldToViewMatrix() |
|||
{ |
|||
return UNITY_MATRIX_V; |
|||
} |
|||
|
|||
float4x4 GetObjectToWorldMatrix() |
|||
{ |
|||
return UNITY_MATRIX_M; |
|||
} |
|||
|
|||
float4x4 GetWorldToObjectMatrix() |
|||
{ |
|||
return UNITY_MATRIX_I_M; |
|||
} |
|||
|
|||
// Transform to homogenous clip space |
|||
float4x4 GetWorldToHClipMatrix() |
|||
{ |
|||
return UNITY_MATRIX_VP; |
|||
} |
|||
|
|||
float GetOddNegativeScale() |
|||
{ |
|||
return unity_WorldTransformParams.w; |
|||
} |
|||
|
|||
float3 TransformWorldToView(float3 positionWS) |
|||
{ |
|||
return mul(GetWorldToViewMatrix(), float4(positionWS, 1.0)).xyz; |
|||
} |
|||
|
|||
float3 TransformObjectToWorld(float3 positionOS) |
|||
{ |
|||
return mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)).xyz; |
|||
} |
|||
|
|||
float3 TransformWorldToObject(float3 positionWS) |
|||
{ |
|||
return mul(GetWorldToObjectMatrix(), float4(positionWS, 1.0)).xyz; |
|||
} |
|||
|
|||
float3 TransformObjectToWorldDir(float3 dirOS) |
|||
{ |
|||
// Normalize to support uniform scaling |
|||
return normalize(mul((float3x3)GetObjectToWorldMatrix(), dirOS)); |
|||
} |
|||
|
|||
float3 TransformWorldToObjectDir(float3 dirWS) |
|||
{ |
|||
// Normalize to support uniform scaling |
|||
return normalize(mul((float3x3)GetWorldToObjectMatrix(), dirWS)); |
|||
} |
|||
|
|||
// Transforms normal from object to world space |
|||
float3 TransformObjectToWorldNormal(float3 normalOS) |
|||
{ |
|||
#ifdef UNITY_ASSUME_UNIFORM_SCALING |
|||
return UnityObjectToWorldDir(normalOS); |
|||
#else |
|||
// Normal need to be multiply by inverse transpose |
|||
// 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(normalOS, (float3x3)GetWorldToObjectMatrix())); |
|||
#endif |
|||
} |
|||
|
|||
// Transforms position from object space to homogenous space |
|||
float4 TransformObjectToHClip(float3 positionWS) |
|||
{ |
|||
// More efficient than computing M*VP matrix product |
|||
return mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), float4(positionWS, 1.0))); |
|||
} |
|||
|
|||
// Tranforms position from world space to homogenous space |
|||
float4 TransformWorldToHClip(float3 positionWS) |
|||
{ |
|||
return mul(GetWorldToHClipMatrix(), float4(positionWS, 1.0)); |
|||
} |
|||
|
|||
float3x3 CreateWorldToTangent(float3 normal, float3 tangent, float flipSign) |
|||
{ |
|||
// For odd-negative scale transforms we need to flip the sign |
|||
float sgn = flipSign * GetOddNegativeScale(); |
|||
float3 bitangent = cross(normal, tangent) * sgn; |
|||
|
|||
return float3x3(tangent, bitangent, normal); |
|||
} |
|||
|
|||
float3 TransformTangentToWorld(float3 dirTS, float3x3 worldToTangent) |
|||
{ |
|||
// Use transpose transformation to go from tangent to world as the matrix is orthogonal |
|||
return mul(dirTS, worldToTangent); |
|||
} |
|||
|
|||
float3 TransformWorldToTangent(float3 dirWS, float3x3 worldToTangent) |
|||
{ |
|||
return mul(worldToTangent, dirWS); |
|||
} |
|||
|
|||
float3 TransformTangentToObject(float3 dirTS, float3x3 worldToTangent) |
|||
{ |
|||
// Use transpose transformation to go from tangent to world as the matrix is orthogonal |
|||
float3 normalWS = mul(dirTS, worldToTangent); |
|||
return mul((float3x3)GetWorldToObjectMatrix(), normalWS); |
|||
} |
|||
|
|||
float3 TransformObjectToTangent(float3 dirOS, float3x3 worldToTangent) |
|||
{ |
|||
return mul(worldToTangent, TransformObjectToWorldDir(dirOS)); |
|||
} |
|||
|
|||
#endif // UNITY_SHADER_VARIABLES_FUNCTIONS_INCLUDED |
|
|||
fileFormatVersion: 2 |
|||
guid: 20914acf41b53ba42bf665e94496a288 |
|||
ShaderImporter: |
|||
externalObjects: {} |
|||
defaultTextures: [] |
|||
nonModifiableTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef LIGHTWEIGHT_PASS_SHADOW_INCLUDED |
|||
#define LIGHTWEIGHT_PASS_SHADOW_INCLUDED |
|||
|
|||
float4 ShadowPassVertex(float4 pos : POSITION) : SV_POSITION |
|||
{ |
|||
float4 clipPos = UnityObjectToClipPos(pos); |
|||
#if defined(UNITY_REVERSED_Z) |
|||
clipPos.z = min(clipPos.z, UNITY_NEAR_CLIP_VALUE); |
|||
#else |
|||
clipPos.z = max(clipPos.z, UNITY_NEAR_CLIP_VALUE); |
|||
#endif |
|||
return clipPos; |
|||
} |
|||
|
|||
half4 ShadowPassFragment() : SV_TARGET |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_PIPELINE_CORE_INCLUDED |
|||
#define LIGHTWEIGHT_PIPELINE_CORE_INCLUDED |
|||
|
|||
#include "UnityCG.cginc" |
|||
|
|||
#if defined(UNITY_COLORSPACE_GAMMA) |
|||
#define LIGHTWEIGHT_GAMMA_TO_LINEAR(gammaColor) gammaColor * gammaColor |
|||
#define LIGHTWEIGHT_LINEAR_TO_GAMMA(linColor) sqrt(linColor) |
|||
#define OUTPUT_COLOR(color) half4(LIGHTWEIGHT_LINEAR_TO_GAMMA(color.rgb), color.a) |
|||
#else |
|||
#define LIGHTWEIGHT_GAMMA_TO_LINEAR(color) color |
|||
#define LIGHTWEIGHT_LINEAR_TO_GAMMA(color) color |
|||
#define OUTPUT_COLOR(color) color |
|||
#endif |
|||
|
|||
#ifdef _NORMALMAP |
|||
#define OUTPUT_NORMAL(IN, OUT) OutputTangentToWorld(IN.tangent, IN.normal, OUT.tangent, OUT.binormal, OUT.normal) |
|||
#else |
|||
#define OUTPUT_NORMAL(IN, OUT) OUT.normal = UnityObjectToWorldNormal(IN.normal) |
|||
#endif |
|||
|
|||
#ifdef LIGHTMAP_ON |
|||
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) OUT.xy = lightmapUV.xy * lightmapScaleOffset.xy + lightmapScaleOffset.zw; |
|||
#define OUTPUT_SH(normalWS, OUT) |
|||
#else |
|||
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) |
|||
#define OUTPUT_SH(normalWS, OUT) OUT.xyz = EvaluateSHPerVertex(normalWS) |
|||
#endif |
|||
|
|||
half _Pow4(half x) |
|||
{ |
|||
return x * x * x * x; |
|||
} |
|||
|
|||
half _LerpOneTo(half b, half t) |
|||
{ |
|||
half oneMinusT = 1 - t; |
|||
return oneMinusT + b * t; |
|||
} |
|||
|
|||
void AlphaDiscard(half alpha, half cutoff) |
|||
{ |
|||
#ifdef _ALPHATEST_ON |
|||
clip(alpha - cutoff); |
|||
#endif |
|||
} |
|||
|
|||
half3 SafeNormalize(half3 inVec) |
|||
{ |
|||
half dp3 = max(1.e-4h, dot(inVec, inVec)); |
|||
return inVec * rsqrt(dp3); |
|||
} |
|||
|
|||
half3 UnpackNormalScale(half4 packednormal, half bumpScale) |
|||
{ |
|||
#if defined(UNITY_NO_DXT5nm) |
|||
half3 normal = packednormal.xyz * 2 - 1; |
|||
#if (SHADER_TARGET >= 30) |
|||
// SM2.0: instruction count limitation |
|||
// SM2.0: normal scaler is not supported |
|||
normal.xy *= bumpScale; |
|||
#endif |
|||
return normal; |
|||
#else |
|||
// This do the trick |
|||
packednormal.x *= packednormal.w; |
|||
|
|||
half3 normal; |
|||
normal.xy = (packednormal.xy * 2 - 1); |
|||
#if (SHADER_TARGET >= 30) |
|||
// SM2.0: instruction count limitation |
|||
// SM2.0: normal scaler is not supported |
|||
normal.xy *= bumpScale; |
|||
#endif |
|||
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy))); |
|||
return normal; |
|||
#endif |
|||
} |
|||
|
|||
half3 EvaluateSHPerVertex(half3 normalWS) |
|||
{ |
|||
#if defined(EVALUATE_SH_VERTEX) |
|||
return max(half3(0, 0, 0), ShadeSH9(half4(normalWS, 1.0))); |
|||
#elif defined(EVALUATE_SH_MIXED) |
|||
// no max since this is only L2 contribution |
|||
return SHEvalLinearL2(half4(normalWS, 1.0)); |
|||
#endif |
|||
|
|||
// Fully per-pixel. Nothing to compute. |
|||
return half3(0.0, 0.0, 0.0); |
|||
} |
|||
|
|||
half3 EvaluateSHPerPixel(half3 L2Term, half3 normalWS) |
|||
{ |
|||
#ifdef EVALUATE_SH_MIXED |
|||
return max(half3(0, 0, 0), L2Term + SHEvalLinearL0L1(half4(normalWS, 1.0))); |
|||
#endif |
|||
|
|||
// Default: Evaluate SH fully per-pixel |
|||
return max(half3(0, 0, 0), ShadeSH9(half4(normalWS, 1.0))); |
|||
} |
|||
|
|||
half3 SampleLightmap(float2 lightmapUV, half3 normalWS) |
|||
{ |
|||
half4 encodedBakedColor = UNITY_SAMPLE_TEX2D(unity_Lightmap, lightmapUV); |
|||
half3 bakedColor = DecodeLightmap(encodedBakedColor); |
|||
|
|||
#if DIRLIGHTMAP_COMBINED |
|||
half4 bakedDirection = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lightmapUV); |
|||
bakedColor = DecodeDirectionalLightmap(bakedColor, bakedDirection, normalWS); |
|||
#endif |
|||
|
|||
return bakedColor; |
|||
} |
|||
|
|||
half3 SampleGI(float4 sampleData, half3 normalWS) |
|||
{ |
|||
#if LIGHTMAP_ON |
|||
return SampleLightmap(sampleData.xy, normalWS); |
|||
#endif |
|||
|
|||
return EvaluateSHPerPixel(sampleData.xyz, normalWS); |
|||
} |
|||
|
|||
void OutputTangentToWorld(half4 vertexTangent, half3 vertexNormal, out half3 tangentWS, out half3 binormalWS, out half3 normalWS) |
|||
{ |
|||
half sign = vertexTangent.w * unity_WorldTransformParams.w; |
|||
normalWS = normalize(UnityObjectToWorldNormal(vertexNormal)); |
|||
tangentWS = normalize(mul((half3x3)unity_ObjectToWorld, vertexTangent.xyz)); |
|||
binormalWS = cross(normalWS, tangentWS) * sign; |
|||
} |
|||
|
|||
half3 TangentToWorldNormal(half3 normalTangent, half3 tangent, half3 binormal, half3 normal) |
|||
{ |
|||
half3x3 tangentToWorld = half3x3(tangent, binormal, normal); |
|||
return normalize(mul(normalTangent, tangentToWorld)); |
|||
} |
|||
|
|||
float ComputeFogFactor(float z) |
|||
{ |
|||
float clipZ_01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(z); |
|||
|
|||
#if defined(FOG_LINEAR) |
|||
// factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start)) |
|||
float fogFactor = saturate(clipZ_01 * unity_FogParams.z + unity_FogParams.w); |
|||
return half(fogFactor); |
|||
#elif defined(FOG_EXP) |
|||
// factor = exp(-density*z) |
|||
float unityFogFactor = unity_FogParams.y * clipZ_01; |
|||
return half(saturate(exp2(-unityFogFactor))); |
|||
#elif defined(FOG_EXP2) |
|||
// factor = exp(-(density*z)^2) |
|||
float unityFogFactor = unity_FogParams.x * clipZ_01; |
|||
return half(saturate(exp2(-unityFogFactor*unityFogFactor))); |
|||
#else |
|||
return 0.0h; |
|||
#endif |
|||
} |
|||
|
|||
void ApplyFog(inout half3 color, half fogFactor) |
|||
{ |
|||
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) |
|||
color = lerp(unity_FogColor, color, fogFactor); |
|||
#endif |
|||
} |
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_PASS_LIT_INCLUDED |
|||
#define LIGHTWEIGHT_PASS_LIT_INCLUDED |
|||
|
|||
#include "LightweightSurfaceInput.cginc" |
|||
#include "LightweightLighting.cginc" |
|||
|
|||
struct LightweightVertexInput |
|||
{ |
|||
float4 vertex : POSITION; |
|||
float3 normal : NORMAL; |
|||
float4 tangent : TANGENT; |
|||
float2 texcoord : TEXCOORD0; |
|||
float2 lightmapUV : TEXCOORD1; |
|||
UNITY_VERTEX_INPUT_INSTANCE_ID |
|||
}; |
|||
|
|||
struct LightweightVertexOutput |
|||
{ |
|||
float2 uv : TEXCOORD0; |
|||
float4 lightmapUVOrVertexSH : TEXCOORD1; // holds either lightmapUV or vertex SH. depending on LIGHTMAP_ON |
|||
float4 posWS : TEXCOORD2; |
|||
half3 normal : TEXCOORD3; |
|||
|
|||
#if _NORMALMAP |
|||
half3 tangent : TEXCOORD4; |
|||
half3 binormal : TEXCOORD5; |
|||
#endif |
|||
|
|||
half3 viewDir : TEXCOORD6; |
|||
half4 fogFactorAndVertexLight : TEXCOORD7; // x: fogFactor, yzw: vertex light |
|||
|
|||
float4 clipPos : SV_POSITION; |
|||
UNITY_VERTEX_OUTPUT_STEREO |
|||
}; |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Vertex and Fragment functions // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
|
|||
// Vertex: Used for Standard and StandardSimpleLighting shaders |
|||
LightweightVertexOutput LitPassVertex(LightweightVertexInput v) |
|||
{ |
|||
LightweightVertexOutput o = (LightweightVertexOutput)0; |
|||
|
|||
UNITY_SETUP_INSTANCE_ID(v); |
|||
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); |
|||
|
|||
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); |
|||
|
|||
o.posWS = mul(unity_ObjectToWorld, v.vertex); |
|||
o.clipPos = mul(UNITY_MATRIX_VP, o.posWS); |
|||
o.viewDir = SafeNormalize(_WorldSpaceCameraPos - o.posWS.xyz); |
|||
|
|||
// initializes o.normal and if _NORMALMAP also o.tangent and o.binormal |
|||
OUTPUT_NORMAL(v, o); |
|||
|
|||
// We either sample GI from lightmap or SH. lightmap UV and vertex SH coefficients |
|||
// are packed in lightmapUVOrVertexSH to save interpolator. |
|||
// The following funcions initialize |
|||
OUTPUT_LIGHTMAP_UV(v.lightmapUV, unity_LightmapST, o.lightmapUVOrVertexSH); |
|||
OUTPUT_SH(o.normal, o.lightmapUVOrVertexSH); |
|||
|
|||
half3 vertexLight = VertexLighting(o.posWS.xyz, o.normal); |
|||
half fogFactor = ComputeFogFactor(o.clipPos.z); |
|||
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight); |
|||
|
|||
return o; |
|||
} |
|||
|
|||
// Used for Standard shader |
|||
half4 LitPassFragment(LightweightVertexOutput IN) : SV_Target |
|||
{ |
|||
SurfaceData surfaceData; |
|||
InitializeStandardLitSurfaceData(IN.uv, surfaceData); |
|||
|
|||
#if _NORMALMAP |
|||
half3 normalWS = TangentToWorldNormal(surfaceData.normal, IN.tangent, IN.binormal, IN.normal); |
|||
#else |
|||
half3 normalWS = normalize(IN.normal); |
|||
#endif |
|||
|
|||
half3 indirectDiffuse = SampleGI(IN.lightmapUVOrVertexSH, normalWS); |
|||
float fogFactor = IN.fogFactorAndVertexLight.x; |
|||
|
|||
half4 color = LightweightFragmentPBR(IN.posWS, normalWS, IN.viewDir, indirectDiffuse, IN.fogFactorAndVertexLight.yzw, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha); |
|||
|
|||
// Computes fog factor per-vertex |
|||
ApplyFog(color.rgb, fogFactor); |
|||
return OUTPUT_COLOR(color); |
|||
} |
|||
|
|||
// Used for StandardSimpleLighting shader |
|||
half4 LitPassFragmentSimple(LightweightVertexOutput IN) : SV_Target |
|||
{ |
|||
float2 uv = IN.uv; |
|||
|
|||
half4 diffuseAlpha = tex2D(_MainTex, uv); |
|||
half3 diffuse = LIGHTWEIGHT_GAMMA_TO_LINEAR(diffuseAlpha.rgb) * _Color.rgb; |
|||
|
|||
#ifdef _GLOSSINESS_FROM_BASE_ALPHA |
|||
half alpha = _Color.a; |
|||
#else |
|||
half alpha = diffuseAlpha.a * _Color.a; |
|||
#endif |
|||
|
|||
AlphaDiscard(alpha, _Cutoff); |
|||
|
|||
#if _NORMALMAP |
|||
half3 normalTangent = Normal(uv); |
|||
half3 normalWS = TangentToWorldNormal(normalTangent, IN.tangent, IN.binormal, IN.normal); |
|||
#else |
|||
half3 normalWS = normalize(IN.normal); |
|||
#endif |
|||
|
|||
half3 emission = Emission(uv); |
|||
|
|||
half3 viewDirectionWS = SafeNormalize(IN.viewDir.xyz); |
|||
float3 positionWS = IN.posWS.xyz; |
|||
|
|||
half3 diffuseGI = SampleGI(IN.lightmapUVOrVertexSH, normalWS); |
|||
|
|||
#if _VERTEX_LIGHTS |
|||
diffuseGI += IN.fogFactorAndVertexLight.yzw; |
|||
#endif |
|||
|
|||
half shininess = _Shininess * 128.0h; |
|||
half fogFactor = IN.fogFactorAndVertexLight.x; |
|||
|
|||
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR) |
|||
half4 specularGloss = SpecularGloss(uv, diffuseAlpha.a); |
|||
return LightweightFragmentBlinnPhong(positionWS, normalWS, viewDirectionWS, fogFactor, diffuseGI, diffuse, specularGloss, shininess, emission, alpha); |
|||
#else |
|||
return LightweightFragmentLambert(positionWS, normalWS, viewDirectionWS, fogFactor, diffuseGI, diffuse, emission, alpha); |
|||
#endif |
|||
}; |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_PASS_META_INCLUDED |
|||
#define LIGHTWEIGHT_PASS_META_INCLUDED |
|||
|
|||
#include "LightweightSurfaceInput.cginc" |
|||
#include "LightweightLighting.cginc" |
|||
#include "UnityMetaPass.cginc" |
|||
|
|||
struct MetaVertexInput |
|||
{ |
|||
float4 vertex : POSITION; |
|||
half3 normal : NORMAL; |
|||
float2 uv0 : TEXCOORD0; |
|||
float2 uv1 : TEXCOORD1; |
|||
float2 uv2 : TEXCOORD2; |
|||
#ifdef _TANGENT_TO_WORLD |
|||
half4 tangent : TANGENT; |
|||
#endif |
|||
UNITY_VERTEX_INPUT_INSTANCE_ID |
|||
}; |
|||
|
|||
struct MetaVertexOuput |
|||
{ |
|||
float4 pos : SV_POSITION; |
|||
float2 uv : TEXCOORD0; |
|||
}; |
|||
|
|||
MetaVertexOuput LightweightVertexMeta(MetaVertexInput v) |
|||
{ |
|||
MetaVertexOuput o; |
|||
o.pos = UnityMetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST); |
|||
o.uv = TRANSFORM_TEX(v.uv0, _MainTex); |
|||
return o; |
|||
} |
|||
|
|||
fixed4 LightweightFragmentMeta(MetaVertexOuput i) : SV_Target |
|||
{ |
|||
SurfaceData surfaceData; |
|||
InitializeStandardLitSurfaceData(i.uv, surfaceData); |
|||
|
|||
BRDFData brdfData; |
|||
InitializeBRDFData(surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.alpha, brdfData); |
|||
|
|||
UnityMetaInput o; |
|||
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, o); |
|||
|
|||
#if defined(EDITOR_VISUALIZATION) |
|||
o.Albedo = brdfData.diffuse; |
|||
#else |
|||
o.Albedo = brdfData.diffuse + brdfData.specular * brdfData.roughness * 0.5; |
|||
#endif |
|||
o.SpecularColor = surfaceData.specular; |
|||
o.Emission = surfaceData.emission; |
|||
|
|||
return UnityMetaFragment(o); |
|||
} |
|||
|
|||
fixed4 LightweightFragmentMetaSimple(MetaVertexOuput i) : SV_Target |
|||
{ |
|||
UnityMetaInput o; |
|||
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, o); |
|||
|
|||
float2 uv = i.uv; |
|||
o.Albedo = _Color.rgb * tex2D(_MainTex, uv).rgb; |
|||
o.SpecularColor = SpecularGloss(uv, 1.0); |
|||
o.Emission = Emission(uv); |
|||
|
|||
return UnityMetaFragment(o); |
|||
} |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_SHADOWS_INCLUDED |
|||
#define LIGHTWEIGHT_SHADOWS_INCLUDED |
|||
|
|||
#include "LightweightInput.cginc" |
|||
|
|||
#define MAX_SHADOW_CASCADES 4 |
|||
|
|||
#if defined(_HARD_SHADOWS) || defined(_SOFT_SHADOWS) || defined(_HARD_SHADOWS_CASCADES) || defined(_SOFT_SHADOWS_CASCADES) |
|||
#define _SHADOWS |
|||
#endif |
|||
|
|||
#if defined(_HARD_SHADOWS_CASCADES) || defined(_SOFT_SHADOWS_CASCADES) |
|||
#define _SHADOW_CASCADES |
|||
#endif |
|||
|
|||
#ifdef _SHADOWS |
|||
#define LIGHTWEIGHT_SHADOW_ATTENUATION(posWorld, vertexNormal, shadowDir) ComputeShadowAttenuation(posWorld, vertexNormal, shadowDir) |
|||
#else |
|||
#define LIGHTWEIGHT_SHADOW_ATTENUATION(posWorld, vertexNormal, shadowDir) 1.0h |
|||
#endif |
|||
|
|||
UNITY_DECLARE_SHADOWMAP(_ShadowMap); |
|||
float4x4 _WorldToShadow[MAX_SHADOW_CASCADES]; |
|||
float4 _DirShadowSplitSpheres[MAX_SHADOW_CASCADES]; |
|||
half4 _ShadowOffset0; |
|||
half4 _ShadowOffset1; |
|||
half4 _ShadowOffset2; |
|||
half4 _ShadowOffset3; |
|||
half4 _ShadowData; // (x: 1.0 - shadowStrength, y: bias, z: normal bias, w: near plane offset) |
|||
|
|||
float ApplyDepthBias(float clipZ) |
|||
{ |
|||
#ifdef UNITY_REVERSED_Z |
|||
return clipZ + _ShadowData.y; |
|||
#endif |
|||
|
|||
return clipZ - _ShadowData.y; |
|||
} |
|||
|
|||
inline half SampleShadowmap(float4 shadowCoord) |
|||
{ |
|||
float3 coord = shadowCoord.xyz /= shadowCoord.w; |
|||
coord.z = saturate(ApplyDepthBias(coord.z)); |
|||
if (coord.x <= 0 || coord.x >= 1 || coord.y <= 0 || coord.y >= 1) |
|||
return 1; |
|||
|
|||
#if defined(_SOFT_SHADOWS) || defined(_SOFT_SHADOWS_CASCADES) |
|||
// 4-tap hardware comparison |
|||
half4 attenuation; |
|||
attenuation.x = UNITY_SAMPLE_SHADOW(_ShadowMap, coord + _ShadowOffset0.xyz); |
|||
attenuation.y = UNITY_SAMPLE_SHADOW(_ShadowMap, coord + _ShadowOffset1.xyz); |
|||
attenuation.z = UNITY_SAMPLE_SHADOW(_ShadowMap, coord + _ShadowOffset2.xyz); |
|||
attenuation.w = UNITY_SAMPLE_SHADOW(_ShadowMap, coord + _ShadowOffset3.xyz); |
|||
lerp(attenuation, 1.0, _ShadowData.xxxx); |
|||
return dot(attenuation, 0.25); |
|||
#else |
|||
// 1-tap hardware comparison |
|||
half attenuation = UNITY_SAMPLE_SHADOW(_ShadowMap, coord); |
|||
return lerp(attenuation, 1.0, _ShadowData.x); |
|||
#endif |
|||
} |
|||
|
|||
inline half ComputeCascadeIndex(float3 wpos) |
|||
{ |
|||
float3 fromCenter0 = wpos.xyz - _DirShadowSplitSpheres[0].xyz; |
|||
float3 fromCenter1 = wpos.xyz - _DirShadowSplitSpheres[1].xyz; |
|||
float3 fromCenter2 = wpos.xyz - _DirShadowSplitSpheres[2].xyz; |
|||
float3 fromCenter3 = wpos.xyz - _DirShadowSplitSpheres[3].xyz; |
|||
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3)); |
|||
|
|||
float4 vDirShadowSplitSphereSqRadii; |
|||
vDirShadowSplitSphereSqRadii.x = _DirShadowSplitSpheres[0].w; |
|||
vDirShadowSplitSphereSqRadii.y = _DirShadowSplitSpheres[1].w; |
|||
vDirShadowSplitSphereSqRadii.z = _DirShadowSplitSpheres[2].w; |
|||
vDirShadowSplitSphereSqRadii.w = _DirShadowSplitSpheres[3].w; |
|||
fixed4 weights = fixed4(distances2 < vDirShadowSplitSphereSqRadii); |
|||
weights.yzw = saturate(weights.yzw - weights.xyz); |
|||
return 4 - dot(weights, fixed4(4, 3, 2, 1)); |
|||
} |
|||
|
|||
inline half ComputeShadowAttenuation(float3 posWorld, half3 vertexNormal, half3 shadowDir) |
|||
{ |
|||
half NdotL = dot(vertexNormal, shadowDir); |
|||
half bias = saturate(1.0 - NdotL) * _ShadowData.z; |
|||
|
|||
float3 posWorldOffsetNormal = posWorld + vertexNormal * bias; |
|||
|
|||
int cascadeIndex = 0; |
|||
#ifdef _SHADOW_CASCADES |
|||
cascadeIndex = ComputeCascadeIndex(posWorldOffsetNormal); |
|||
if (cascadeIndex >= MAX_SHADOW_CASCADES) |
|||
return 1.0; |
|||
#endif |
|||
|
|||
float4 shadowCoord = mul(_WorldToShadow[cascadeIndex], float4(posWorldOffsetNormal, 1.0)); |
|||
return SampleShadowmap(shadowCoord); |
|||
} |
|||
|
|||
half MixRealtimeAndBakedOcclusion(half realtimeAttenuation, half4 bakedOcclusion, half4 distanceAttenuation) |
|||
{ |
|||
#if defined(LIGHTMAP_ON) |
|||
#if defined(_MIXED_LIGHTING_SHADOWMASK) |
|||
// TODO: |
|||
#elif defined(_MIXED_LIGHTING_SUBTRACTIVE) |
|||
// Subtractive Light mode has direct light contribution baked into lightmap for mixed lights. |
|||
// We need to remove direct realtime contribution from mixed lights |
|||
// distanceAttenuation.w is set 0.0 if this light is mixed, 1.0 otherwise. |
|||
return realtimeAttenuation * distanceAttenuation.w; |
|||
#endif |
|||
#endif |
|||
|
|||
return realtimeAttenuation; |
|||
} |
|||
|
|||
inline half3 SubtractDirectMainLightFromLightmap(half3 lightmap, half attenuation, half3 lambert) |
|||
{ |
|||
// Let's try to make realtime shadows work on a surface, which already contains |
|||
// baked lighting and shadowing from the main sun light. |
|||
// Summary: |
|||
// 1) Calculate possible value in the shadow by subtracting estimated light contribution from the places occluded by realtime shadow: |
|||
// a) preserves other baked lights and light bounces |
|||
// b) eliminates shadows on the geometry facing away from the light |
|||
// 2) Clamp against user defined ShadowColor. |
|||
// 3) Pick original lightmap value, if it is the darkest one. |
|||
|
|||
|
|||
// 1) Gives good estimate of illumination as if light would've been shadowed during the bake. |
|||
// Preserves bounce and other baked lights |
|||
// No shadows on the geometry facing away from the light |
|||
half shadowStrength = _ShadowData.x; |
|||
half3 estimatedLightContributionMaskedByInverseOfShadow = lambert * (1.0 - attenuation); |
|||
half3 subtractedLightmap = lightmap - estimatedLightContributionMaskedByInverseOfShadow; |
|||
|
|||
// 2) Allows user to define overall ambient of the scene and control situation when realtime shadow becomes too dark. |
|||
half3 realtimeShadow = max(subtractedLightmap, _SubtractiveShadowColor.xyz); |
|||
realtimeShadow = lerp(realtimeShadow, lightmap, shadowStrength); |
|||
|
|||
// 3) Pick darkest color |
|||
return min(lightmap, realtimeShadow); |
|||
} |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_INPUT_INCLUDED |
|||
#define LIGHTWEIGHT_INPUT_INCLUDED |
|||
|
|||
#define MAX_VISIBLE_LIGHTS 16 |
|||
|
|||
struct LightInput |
|||
{ |
|||
float4 pos; |
|||
half4 color; |
|||
half4 distanceAttenuation; |
|||
half4 spotDirection; |
|||
half4 spotAttenuation; |
|||
}; |
|||
|
|||
// Main light initialized without indexing |
|||
#define INITIALIZE_MAIN_LIGHT(light) \ |
|||
light.pos = _MainLightPosition; \ |
|||
light.color = _MainLightColor; \ |
|||
light.distanceAttenuation = _MainLightDistanceAttenuation; \ |
|||
light.spotDirection = _MainLightSpotDir; \ |
|||
light.spotAttenuation = _MainLightSpotAttenuation |
|||
|
|||
// Indexing might have a performance hit for old mobile hardware |
|||
#define INITIALIZE_LIGHT(light, i) \ |
|||
half4 indices = (i < 4) ? unity_4LightIndices0 : unity_4LightIndices1; \ |
|||
int index = (i < 4) ? i : i - 4; \ |
|||
int lightIndex = indices[index]; \ |
|||
light.pos = _AdditionalLightPosition[lightIndex]; \ |
|||
light.color = _AdditionalLightColor[lightIndex]; \ |
|||
light.distanceAttenuation = _AdditionalLightDistanceAttenuation[lightIndex]; \ |
|||
light.spotDirection = _AdditionalLightSpotDir[lightIndex]; \ |
|||
light.spotAttenuation = _AdditionalLightSpotAttenuation[lightIndex] |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Constant Buffers // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
|
|||
CBUFFER_START(_PerFrame) |
|||
half4 _GlossyEnvironmentColor; |
|||
half4 _SubtractiveShadowColor; |
|||
CBUFFER_END |
|||
|
|||
CBUFFER_START(_PerCamera) |
|||
float4 _MainLightPosition; |
|||
half4 _MainLightColor; |
|||
half4 _MainLightDistanceAttenuation; |
|||
half4 _MainLightSpotDir; |
|||
half4 _MainLightSpotAttenuation; |
|||
float4x4 _WorldToLight; |
|||
|
|||
half4 _AdditionalLightCount; |
|||
float4 _AdditionalLightPosition[MAX_VISIBLE_LIGHTS]; |
|||
half4 _AdditionalLightColor[MAX_VISIBLE_LIGHTS]; |
|||
half4 _AdditionalLightDistanceAttenuation[MAX_VISIBLE_LIGHTS]; |
|||
half4 _AdditionalLightSpotDir[MAX_VISIBLE_LIGHTS]; |
|||
half4 _AdditionalLightSpotAttenuation[MAX_VISIBLE_LIGHTS]; |
|||
CBUFFER_END |
|||
|
|||
sampler2D _MainLightCookie; |
|||
|
|||
// These are set internally by the engine upon request by RendererConfiguration. |
|||
// Check GetRendererSettings in LightweightPipeline.cs |
|||
CBUFFER_START(_PerObject) |
|||
half4 unity_LightIndicesOffsetAndCount; |
|||
half4 unity_4LightIndices0; |
|||
half4 unity_4LightIndices1; |
|||
CBUFFER_END |
|||
|
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_LIGHTING_INCLUDED |
|||
#define LIGHTWEIGHT_LIGHTING_INCLUDED |
|||
|
|||
#include "LightweightCore.cginc" |
|||
#include "LightweightShadows.cginc" |
|||
|
|||
#define PI 3.14159265359f |
|||
#define kDieletricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%) |
|||
|
|||
#ifndef UNITY_SPECCUBE_LOD_STEPS |
|||
#define UNITY_SPECCUBE_LOD_STEPS 6 |
|||
#endif |
|||
|
|||
#ifdef NO_ADDITIONAL_LIGHTS |
|||
#undef _ADDITIONAL_LIGHTS |
|||
#endif |
|||
|
|||
// If lightmap is not defined than we evaluate GI (ambient + probes) from SH |
|||
// We might do it fully or partially in vertex to save shader ALU |
|||
#if !defined(LIGHTMAP_ON) |
|||
#if SHADER_TARGET < 30 |
|||
// Evaluates SH fully in vertex |
|||
#define EVALUATE_SH_VERTEX |
|||
#else |
|||
// Evaluates L2 SH in vertex and L0L1 in pixel |
|||
#define EVALUATE_SH_MIXED |
|||
#endif |
|||
#endif |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// BRDF Functions // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
struct BRDFData |
|||
{ |
|||
half3 diffuse; |
|||
half3 specular; |
|||
half perceptualRoughness; |
|||
half roughness; |
|||
half grazingTerm; |
|||
}; |
|||
|
|||
half ReflectivitySpecular(half3 specular) |
|||
{ |
|||
#if (SHADER_TARGET < 30) |
|||
// SM2.0: instruction count limitation |
|||
return specular.r; // Red channel - because most metals are either monocrhome or with redish/yellowish tint |
|||
#else |
|||
return max(max(specular.r, specular.g), specular.b); |
|||
#endif |
|||
} |
|||
|
|||
half OneMinusReflectivityMetallic(half metallic) |
|||
{ |
|||
// We'll need oneMinusReflectivity, so |
|||
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic) |
|||
// store (1-dielectricSpec) in kDieletricSpec.a, then |
|||
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) = |
|||
// = alpha - metallic * alpha |
|||
half oneMinusDielectricSpec = kDieletricSpec.a; |
|||
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec; |
|||
} |
|||
|
|||
inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData) |
|||
{ |
|||
#ifdef _SPECULAR_SETUP |
|||
half reflectivity = ReflectivitySpecular(specular); |
|||
half oneMinusReflectivity = 1.0 - reflectivity; |
|||
|
|||
outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular); |
|||
outBRDFData.specular = specular; |
|||
#else |
|||
|
|||
half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic); |
|||
half reflectivity = 1.0 - oneMinusReflectivity; |
|||
|
|||
outBRDFData.diffuse = albedo * oneMinusReflectivity; |
|||
outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic); |
|||
#endif |
|||
|
|||
outBRDFData.grazingTerm = saturate(smoothness + reflectivity); |
|||
outBRDFData.perceptualRoughness = 1.0h - smoothness; |
|||
outBRDFData.roughness = outBRDFData.perceptualRoughness * outBRDFData.perceptualRoughness; |
|||
|
|||
#ifdef _ALPHAPREMULTIPLY_ON |
|||
outBRDFData.diffuse *= alpha; |
|||
alpha = alpha * oneMinusReflectivity + reflectivity; |
|||
#endif |
|||
} |
|||
|
|||
half3 LightweightEnvironmentBRDF(BRDFData brdfData, half3 indirectDiffuse, half3 indirectSpecular, half roughness2, half fresnelTerm) |
|||
{ |
|||
half3 c = indirectDiffuse * brdfData.diffuse; |
|||
float surfaceReduction = 1.0 / (roughness2 + 1.0); |
|||
c += surfaceReduction * indirectSpecular * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm); |
|||
return c; |
|||
} |
|||
|
|||
// Based on Minimalist CookTorrance BRDF |
|||
// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255 |
|||
// |
|||
// * NDF [Modified] GGX |
|||
// * Modified Kelemen and Szirmay-Kalos for Visibility term |
|||
// * Fresnel approximated with 1/LdotH |
|||
half3 LightweightDirectBDRF(BRDFData brdfData, half roughness2, half3 normal, half3 lightDirection, half3 viewDir) |
|||
{ |
|||
#ifndef _SPECULARHIGHLIGHTS_OFF |
|||
half3 halfDir = SafeNormalize(lightDirection + viewDir); |
|||
|
|||
half NoH = saturate(dot(normal, halfDir)); |
|||
half LoH = saturate(dot(lightDirection, halfDir)); |
|||
|
|||
// GGX Distribution multiplied by combined approximation of Visibility and Fresnel |
|||
// See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course |
|||
// https://community.arm.com/events/1155 |
|||
half d = NoH * NoH * (roughness2 - 1.h) + 1.00001h; |
|||
|
|||
half LoH2 = LoH * LoH; |
|||
half specularTerm = roughness2 / ((d * d) * max(0.1h, LoH2) * (brdfData.roughness + 0.5h) * 4); |
|||
|
|||
// on mobiles (where half actually means something) denominator have risk of overflow |
|||
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles) |
|||
// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...)) |
|||
#if defined (SHADER_API_MOBILE) |
|||
specularTerm = specularTerm - 1e-4h; |
|||
#endif |
|||
|
|||
#if defined (SHADER_API_MOBILE) |
|||
specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles |
|||
#endif |
|||
|
|||
half3 color = specularTerm * brdfData.specular + brdfData.diffuse; |
|||
return color; |
|||
#else |
|||
return brdfData.diffuse; |
|||
#endif |
|||
} |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Attenuation Functions / |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
half CookieAttenuation(float3 worldPos) |
|||
{ |
|||
#ifdef _MAIN_LIGHT_COOKIE |
|||
#ifdef _MAIN_DIRECTIONAL_LIGHT |
|||
float2 cookieUV = mul(_WorldToLight, float4(worldPos, 1.0)).xy; |
|||
return tex2D(_MainLightCookie, cookieUV).a; |
|||
#elif defined(_MAIN_SPOT_LIGHT) |
|||
float4 projPos = mul(_WorldToLight, float4(worldPos, 1.0)); |
|||
float2 cookieUV = projPos.xy / projPos.w + 0.5; |
|||
return tex2D(_MainLightCookie, cookieUV).a; |
|||
#endif // POINT LIGHT cookie not supported |
|||
#endif |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
// Matches Unity Vanila attenuation |
|||
// Attenuation smoothly decreases to light range. |
|||
half DistanceAttenuation(half3 distanceSqr, half4 distanceAttenuation) |
|||
{ |
|||
// We use a shared distance attenuation for additional directional and puctual lights |
|||
// for directional lights attenuation will be 1 |
|||
half quadFalloff = distanceAttenuation.x; |
|||
half denom = distanceSqr * quadFalloff + 1.0; |
|||
half lightAtten = 1.0 / denom; |
|||
|
|||
// We need to smoothly fade attenuation to light range. We start fading linearly at 80% of light range |
|||
// Therefore: |
|||
// fadeDistance = (0.8 * 0.8 * lightRangeSq) |
|||
// smoothFactor = (lightRangeSqr - distanceSqr) / (lightRangeSqr - fadeDistance) |
|||
// We can rewrite that to fit a MAD by doing |
|||
// distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr) |
|||
// distanceSqr * distanceAttenuation.y + distanceAttenuation.z |
|||
half smoothFactor = saturate(distanceSqr * distanceAttenuation.y + distanceAttenuation.z); |
|||
return lightAtten * smoothFactor; |
|||
} |
|||
|
|||
half SpotAttenuation(half3 spotDirection, half3 lightDirection, half4 spotAttenuation) |
|||
{ |
|||
// Spot Attenuation with a linear falloff can be defined as |
|||
// (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle) |
|||
// This can be rewritten as |
|||
// invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle) |
|||
// SdotL * invAngleRange + (-cosOuterAngle * invAngleRange) |
|||
// SdotL * spotAttenuation.x + spotAttenuation.y |
|||
|
|||
// If we precompute the terms in a MAD instruction |
|||
half SdotL = dot(spotDirection, lightDirection); |
|||
return saturate(SdotL * spotAttenuation.x + spotAttenuation.y); |
|||
} |
|||
|
|||
inline half GetLightDirectionAndRealtimeAttenuation(LightInput lightInput, half3 normal, float3 worldPos, out half3 lightDirection) |
|||
{ |
|||
float3 posToLightVec = lightInput.pos.xyz - worldPos * lightInput.pos.w; |
|||
float distanceSqr = max(dot(posToLightVec, posToLightVec), 0.001); |
|||
|
|||
// normalized light dir |
|||
lightDirection = half3(posToLightVec * rsqrt(distanceSqr)); |
|||
half lightAtten = DistanceAttenuation(distanceSqr, lightInput.distanceAttenuation); |
|||
lightAtten *= SpotAttenuation(lightInput.spotDirection.xyz, lightDirection, lightInput.spotAttenuation); |
|||
return lightAtten; |
|||
} |
|||
|
|||
inline half GetMainLightDirectionAndRealtimeAttenuation(LightInput lightInput, half3 normalWS, float3 positionWS, out half3 lightDirection) |
|||
{ |
|||
#ifdef _MAIN_DIRECTIONAL_LIGHT |
|||
// Light pos holds normalized light dir |
|||
lightDirection = lightInput.pos; |
|||
half attenuation = 1.0; |
|||
#else |
|||
half attenuation = GetLightDirectionAndRealtimeAttenuation(lightInput, normalWS, positionWS, lightDirection); |
|||
#endif |
|||
|
|||
// Cookies and shadows are only computed for main light |
|||
attenuation *= CookieAttenuation(positionWS); |
|||
attenuation *= LIGHTWEIGHT_SHADOW_ATTENUATION(positionWS, normalWS, lightDirection); |
|||
|
|||
return attenuation; |
|||
} |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Lighting Functions // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal) |
|||
{ |
|||
half NdotL = saturate(dot(normal, lightDir)); |
|||
return lightColor * NdotL; |
|||
} |
|||
|
|||
half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specularGloss, half shininess) |
|||
{ |
|||
half3 halfVec = SafeNormalize(lightDir + viewDir); |
|||
half NdotH = saturate(dot(normal, halfVec)); |
|||
half3 specularReflection = specularGloss.rgb * pow(NdotH, shininess) * specularGloss.a; |
|||
return lightColor * specularReflection; |
|||
} |
|||
|
|||
half3 VertexLighting(float3 positionWS, half3 normalWS) |
|||
{ |
|||
half3 vertexLightColor = half3(0.0, 0.0, 0.0); |
|||
|
|||
#if defined(_VERTEX_LIGHTS) |
|||
int vertexLightStart = _AdditionalLightCount.x; |
|||
int vertexLightEnd = min(_AdditionalLightCount.y, unity_LightIndicesOffsetAndCount.y); |
|||
for (int lightIter = vertexLightStart; lightIter < vertexLightEnd; ++lightIter) |
|||
{ |
|||
LightInput light; |
|||
INITIALIZE_LIGHT(light, lightIter); |
|||
|
|||
half3 lightDirection; |
|||
half atten = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection); |
|||
half3 lightColor = light.color * atten; |
|||
vertexLightColor += LightingLambert(lightColor, lightDirection, normalWS); |
|||
} |
|||
#endif |
|||
|
|||
return vertexLightColor; |
|||
} |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Global Illumination // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
half3 DiffuseGI(half3 indirectDiffuse, half3 lambert, half mainLightRealtimeAttenuation, half occlusion) |
|||
{ |
|||
// If shadows and mixed subtractive mode is enabled we need to remove direct |
|||
// light contribution from lightmap from occluded pixels so we can have dynamic objects |
|||
// casting shadows onto static correctly. |
|||
#if defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_ON) && defined(_SHADOWS) |
|||
indirectDiffuse = SubtractDirectMainLightFromLightmap(indirectDiffuse, mainLightRealtimeAttenuation, lambert); |
|||
#endif |
|||
|
|||
return indirectDiffuse * occlusion; |
|||
} |
|||
|
|||
half3 GlossyEnvironmentReflection(half3 viewDirectionWS, half3 normalWS, half perceptualRoughness, half occlusion) |
|||
{ |
|||
half3 reflectVector = reflect(-viewDirectionWS, normalWS); |
|||
|
|||
#if !defined(_GLOSSYREFLECTIONS_OFF) |
|||
half roughness = perceptualRoughness * (1.7 - 0.7 * perceptualRoughness); |
|||
half mip = roughness * UNITY_SPECCUBE_LOD_STEPS; |
|||
half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectVector, mip); |
|||
return DecodeHDR(rgbm, unity_SpecCube0_HDR) * occlusion; |
|||
#endif |
|||
|
|||
return _GlossyEnvironmentColor * occlusion; |
|||
} |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Fragment Functions // |
|||
// Used by ShaderGraph and others builtin renderers // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
half4 LightweightFragmentPBR(float3 positionWS, half3 normalWS, half3 viewDirectionWS, |
|||
half3 bakedGI, half3 vertexLighting, half3 albedo, half metallic, half3 specular, |
|||
half smoothness, half occlusion, half3 emission, half alpha) |
|||
{ |
|||
half4 bakedOcclusion = half4(0, 0, 0, 0); |
|||
BRDFData brdfData; |
|||
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData); |
|||
|
|||
half3 lightDirectionWS; |
|||
|
|||
LightInput mainLight; |
|||
INITIALIZE_MAIN_LIGHT(mainLight); |
|||
|
|||
// No distance fade. |
|||
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirectionWS); |
|||
half NdotL = saturate(dot(normalWS, lightDirectionWS)); |
|||
half3 radiance = mainLight.color * NdotL; |
|||
|
|||
half3 indirectDiffuse = DiffuseGI(bakedGI, radiance, realtimeMainLightAtten, occlusion); |
|||
half3 indirectSpecular = GlossyEnvironmentReflection(viewDirectionWS, normalWS, brdfData.perceptualRoughness, occlusion); |
|||
|
|||
half roughness2 = brdfData.roughness * brdfData.roughness; |
|||
half fresnelTerm = _Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS))); |
|||
half3 color = LightweightEnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, roughness2, fresnelTerm); |
|||
|
|||
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation); |
|||
radiance *= mainLightAtten; |
|||
|
|||
color += LightweightDirectBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance; |
|||
color += vertexLighting * brdfData.diffuse; |
|||
|
|||
#ifdef _ADDITIONAL_LIGHTS |
|||
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y); |
|||
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter) |
|||
{ |
|||
LightInput light; |
|||
INITIALIZE_LIGHT(light, lightIter); |
|||
|
|||
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirectionWS); |
|||
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation); |
|||
|
|||
half NdotL = saturate(dot(normalWS, lightDirectionWS)); |
|||
half3 radiance = light.color * (lightAttenuation * NdotL); |
|||
color += LightweightDirectBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance; |
|||
} |
|||
#endif |
|||
|
|||
color += emission; |
|||
return half4(color, alpha); |
|||
} |
|||
|
|||
half4 LightweightFragmentLambert(float3 positionWS, half3 normalWS, half3 viewDirectionWS, |
|||
half fogFactor, half3 diffuseGI, half3 diffuse, half3 emission, half alpha) |
|||
{ |
|||
half4 bakedOcclusion = half4(0, 0, 0, 0); |
|||
half3 lightDirection; |
|||
|
|||
LightInput mainLight; |
|||
INITIALIZE_MAIN_LIGHT(mainLight); |
|||
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirection); |
|||
half3 NdotL = saturate(dot(normalWS, lightDirection)); |
|||
half3 lambert = mainLight.color * NdotL; |
|||
|
|||
half3 indirectDiffuse = DiffuseGI(diffuseGI, lambert, realtimeMainLightAtten, 1.0); |
|||
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation); |
|||
|
|||
half3 diffuseColor = lambert * mainLightAtten + indirectDiffuse; |
|||
|
|||
#ifdef _ADDITIONAL_LIGHTS |
|||
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y); |
|||
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter) |
|||
{ |
|||
LightInput light; |
|||
INITIALIZE_LIGHT(light, lightIter); |
|||
|
|||
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection); |
|||
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation); |
|||
|
|||
half3 attenuatedLightColor = light.color * lightAttenuation; |
|||
diffuseColor += LightingLambert(attenuatedLightColor, lightDirection, normalWS); |
|||
} |
|||
#endif |
|||
|
|||
half3 finalColor = diffuseColor * diffuse + emission; |
|||
|
|||
// Computes Fog Factor per vextex |
|||
ApplyFog(finalColor, fogFactor); |
|||
half4 color = half4(finalColor, alpha); |
|||
return OUTPUT_COLOR(color); |
|||
} |
|||
|
|||
half4 LightweightFragmentBlinnPhong(float3 positionWS, half3 normalWS, half3 viewDirectionWS, |
|||
half fogFactor, half3 diffuseGI, half3 diffuse, half4 specularGloss, half shininess, half3 emission, half alpha) |
|||
{ |
|||
half4 bakedOcclusion = half4(0, 0, 0, 0); |
|||
half3 lightDirection; |
|||
|
|||
LightInput mainLight; |
|||
INITIALIZE_MAIN_LIGHT(mainLight); |
|||
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirection); |
|||
half3 NdotL = saturate(dot(normalWS, lightDirection)); |
|||
half3 lambert = mainLight.color * NdotL; |
|||
|
|||
half3 indirectDiffuse = DiffuseGI(diffuseGI, lambert, realtimeMainLightAtten, 1.0); |
|||
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation); |
|||
|
|||
half3 diffuseColor = lambert * mainLightAtten + indirectDiffuse; |
|||
half3 specularColor = LightingSpecular(mainLight.color * mainLightAtten, lightDirection, normalWS, viewDirectionWS, specularGloss, shininess); |
|||
|
|||
#ifdef _ADDITIONAL_LIGHTS |
|||
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y); |
|||
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter) |
|||
{ |
|||
LightInput light; |
|||
INITIALIZE_LIGHT(light, lightIter); |
|||
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection); |
|||
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation); |
|||
|
|||
half3 attenuatedLightColor = light.color * lightAttenuation; |
|||
diffuseColor += LightingLambert(attenuatedLightColor, lightDirection, normalWS); |
|||
specularColor += LightingSpecular(attenuatedLightColor, lightDirection, normalWS, viewDirectionWS, specularGloss, shininess); |
|||
} |
|||
#endif |
|||
|
|||
half3 finalColor = diffuseColor * diffuse + emission; |
|||
finalColor += specularColor; |
|||
|
|||
// Computes Fog Factor per vextex |
|||
ApplyFog(finalColor, fogFactor); |
|||
half4 color = half4(finalColor, alpha); |
|||
return OUTPUT_COLOR(color); |
|||
} |
|||
#endif |
|
|||
#ifndef LIGHTWEIGHT_SURFACE_INPUT_INCLUDED |
|||
#define LIGHTWEIGHT_SURFACE_INPUT_INCLUDED |
|||
|
|||
#include "LightweightCore.cginc" |
|||
|
|||
#ifdef _SPECULAR_SETUP |
|||
#define SAMPLE_METALLICSPECULAR(uv) tex2D(_SpecGlossMap, uv) |
|||
#else |
|||
#define SAMPLE_METALLICSPECULAR(uv) tex2D(_MetallicGlossMap, uv) |
|||
#endif |
|||
|
|||
CBUFFER_START(MaterialProperties) |
|||
half4 _MainTex_ST; |
|||
half4 _Color; |
|||
half _Cutoff; |
|||
half _Glossiness; |
|||
half _GlossMapScale; |
|||
half _SmoothnessTextureChannel; |
|||
half _Metallic; |
|||
half4 _SpecColor; |
|||
half _BumpScale; |
|||
half _OcclusionStrength; |
|||
half4 _EmissionColor; |
|||
half _Shininess; |
|||
CBUFFER_END |
|||
|
|||
sampler2D _MainTex; |
|||
sampler2D _MetallicGlossMap; |
|||
sampler2D _SpecGlossMap; |
|||
sampler2D _BumpMap; |
|||
sampler2D _OcclusionMap; |
|||
sampler2D _EmissionMap; |
|||
|
|||
// Must match Lightweigth ShaderGraph master node |
|||
struct SurfaceData |
|||
{ |
|||
half3 albedo; |
|||
half3 specular; |
|||
half metallic; |
|||
half smoothness; |
|||
half3 normal; |
|||
half3 emission; |
|||
half occlusion; |
|||
half alpha; |
|||
}; |
|||
|
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
// Material Property Helpers // |
|||
/////////////////////////////////////////////////////////////////////////////// |
|||
inline half Alpha(half albedoAlpha) |
|||
{ |
|||
#if defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A) |
|||
half alpha = _Color.a; |
|||
#else |
|||
half alpha = albedoAlpha * _Color.a; |
|||
#endif |
|||
|
|||
#if defined(_ALPHATEST_ON) |
|||
clip(alpha - _Cutoff); |
|||
#endif |
|||
|
|||
return alpha; |
|||
} |
|||
|
|||
half3 Normal(float2 uv) |
|||
{ |
|||
#if _NORMALMAP |
|||
return UnpackNormalScale(tex2D(_BumpMap, uv), _BumpScale); |
|||
#else |
|||
return half3(0.0h, 0.0h, 1.0h); |
|||
#endif |
|||
} |
|||
|
|||
half4 SpecularGloss(half2 uv, half alpha) |
|||
{ |
|||
half4 specularGloss = half4(0, 0, 0, 1); |
|||
#ifdef _SPECGLOSSMAP |
|||
specularGloss = tex2D(_SpecGlossMap, uv); |
|||
specularGloss.rgb = LIGHTWEIGHT_GAMMA_TO_LINEAR(specularGloss.rgb); |
|||
#elif defined(_SPECULAR_COLOR) |
|||
specularGloss = _SpecColor; |
|||
#endif |
|||
|
|||
#ifdef _GLOSSINESS_FROM_BASE_ALPHA |
|||
specularGloss.a = alpha; |
|||
#endif |
|||
return specularGloss; |
|||
} |
|||
|
|||
half4 MetallicSpecGloss(float2 uv, half albedoAlpha) |
|||
{ |
|||
half4 specGloss; |
|||
|
|||
#ifdef _METALLICSPECGLOSSMAP |
|||
specGloss = specGloss = SAMPLE_METALLICSPECULAR(uv); |
|||
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A |
|||
specGloss.a = albedoAlpha * _GlossMapScale; |
|||
#else |
|||
specGloss.a *= _GlossMapScale; |
|||
#endif |
|||
|
|||
#else // _METALLICSPECGLOSSMAP |
|||
#if _SPECULAR_SETUP |
|||
specGloss.rgb = _SpecColor.rgb; |
|||
#else |
|||
specGloss.rgb = _Metallic.rrr; |
|||
#endif |
|||
|
|||
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A |
|||
specGloss.a = albedoAlpha * _GlossMapScale; |
|||
#else |
|||
specGloss.a = _Glossiness; |
|||
#endif |
|||
#endif |
|||
|
|||
return specGloss; |
|||
} |
|||
|
|||
half Occlusion(float2 uv) |
|||
{ |
|||
#ifdef _OCCLUSIONMAP |
|||
#if (SHADER_TARGET < 30) |
|||
// SM20: instruction count limitation |
|||
// SM20: simpler occlusion |
|||
return tex2D(_OcclusionMap, uv).g; |
|||
#else |
|||
half occ = tex2D(_OcclusionMap, uv).g; |
|||
return _LerpOneTo(occ, _OcclusionStrength); |
|||
#endif |
|||
#else |
|||
return 1.0; |
|||
#endif |
|||
} |
|||
|
|||
half3 Emission(float2 uv) |
|||
{ |
|||
#ifndef _EMISSION |
|||
return 0; |
|||
#else |
|||
return LIGHTWEIGHT_GAMMA_TO_LINEAR(tex2D(_EmissionMap, uv).rgb) * _EmissionColor.rgb; |
|||
#endif |
|||
} |
|||
|
|||
inline void InitializeStandardLitSurfaceData(float2 uv, out SurfaceData outSurfaceData) |
|||
{ |
|||
half4 albedoAlpha = tex2D(_MainTex, uv); |
|||
|
|||
half4 specGloss = MetallicSpecGloss(uv, albedoAlpha); |
|||
outSurfaceData.albedo = LIGHTWEIGHT_GAMMA_TO_LINEAR(albedoAlpha.rgb) * _Color.rgb; |
|||
|
|||
#if _SPECULAR_SETUP |
|||
outSurfaceData.metallic = 1.0h; |
|||
outSurfaceData.specular = specGloss.rgb; |
|||
#else |
|||
outSurfaceData.metallic = specGloss.r; |
|||
outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h); |
|||
#endif |
|||
|
|||
outSurfaceData.smoothness = specGloss.a; |
|||
outSurfaceData.normal = Normal(uv); |
|||
outSurfaceData.occlusion = Occlusion(uv); |
|||
outSurfaceData.emission = Emission(uv); |
|||
outSurfaceData.alpha = Alpha(albedoAlpha.a); |
|||
} |
|||
|
|||
#endif |
撰写
预览
正在加载...
取消
保存
Reference in new issue