#ifndef UNIVERSAL_PIPELINE_CORE_INCLUDED #define UNIVERSAL_PIPELINE_CORE_INCLUDED #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl" #if !defined(SHADER_HINT_NICE_QUALITY) #if defined(SHADER_API_MOBILE) || defined(SHADER_API_SWITCH) #define SHADER_HINT_NICE_QUALITY 0 #else #define SHADER_HINT_NICE_QUALITY 1 #endif #endif // Shader Quality Tiers in Universal. // SRP doesn't use Graphics Settings Quality Tiers. // We should expose shader quality tiers in the pipeline asset. // Meanwhile, it's forced to be: // High Quality: Non-mobile platforms or shader explicit defined SHADER_HINT_NICE_QUALITY // Medium: Mobile aside from GLES2 // Low: GLES2 #if SHADER_HINT_NICE_QUALITY #define SHADER_QUALITY_HIGH #elif defined(SHADER_API_GLES) #define SHADER_QUALITY_LOW #else #define SHADER_QUALITY_MEDIUM #endif #ifndef BUMP_SCALE_NOT_SUPPORTED #define BUMP_SCALE_NOT_SUPPORTED !SHADER_HINT_NICE_QUALITY #endif struct VertexPositionInputs { float3 positionWS; // World space position float3 positionVS; // View space position float4 positionCS; // Homogeneous clip space position float4 positionNDC;// Homogeneous normalized device coordinates }; struct VertexNormalInputs { real3 tangentWS; real3 bitangentWS; float3 normalWS; }; VertexPositionInputs GetVertexPositionInputs(float3 positionOS) { VertexPositionInputs input; input.positionWS = TransformObjectToWorld(positionOS); input.positionVS = TransformWorldToView(input.positionWS); input.positionCS = TransformWorldToHClip(input.positionWS); float4 ndc = input.positionCS * 0.5f; input.positionNDC.xy = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w; input.positionNDC.zw = input.positionCS.zw; return input; } VertexNormalInputs GetVertexNormalInputs(float3 normalOS) { VertexNormalInputs tbn; tbn.tangentWS = real3(1.0, 0.0, 0.0); tbn.bitangentWS = real3(0.0, 1.0, 0.0); tbn.normalWS = TransformObjectToWorldNormal(normalOS); return tbn; } VertexNormalInputs GetVertexNormalInputs(float3 normalOS, float4 tangentOS) { VertexNormalInputs tbn; // mikkts space compliant. only normalize when extracting normal at frag. real sign = tangentOS.w * GetOddNegativeScale(); tbn.normalWS = TransformObjectToWorldNormal(normalOS); tbn.tangentWS = TransformObjectToWorldDir(tangentOS.xyz); tbn.bitangentWS = cross(tbn.normalWS, tbn.tangentWS) * sign; return tbn; } #if UNITY_REVERSED_Z #if SHADER_API_OPENGL || SHADER_API_GLES || SHADER_API_GLES3 //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) #else //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) #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 float3 GetCameraPositionWS() { return _WorldSpaceCameraPos; } float4 GetScaledScreenParams() { return _ScaledScreenParams; } void AlphaDiscard(real alpha, real cutoff, real offset = 0.0h) { #ifdef _ALPHATEST_ON clip(alpha - cutoff + offset); #endif } // A word on normalization of normals: // For better quality normals should be normalized before and after // interpolation. // 1) In vertex, skinning or blend shapes might vary significantly the lenght of normal. // 2) In fragment, because even outputting unit-length normals interpolation can make it non-unit. // 3) In fragment when using normal map, because mikktspace sets up non orthonormal basis. // However we will try to balance performance vs quality here as also let users configure that as // shader quality tiers. // Low Quality Tier: Normalize either per-vertex or per-pixel depending if normalmap is sampled. // Medium Quality Tier: Always normalize per-vertex. Normalize per-pixel only if using normal map // High Quality Tier: Normalize in both vertex and pixel shaders. real3 NormalizeNormalPerVertex(real3 normalWS) { #if defined(SHADER_QUALITY_LOW) && defined(_NORMALMAP) return normalWS; #else return normalize(normalWS); #endif } real3 NormalizeNormalPerPixel(real3 normalWS) { #if defined(SHADER_QUALITY_HIGH) || defined(_NORMALMAP) return normalize(normalWS); #else return normalWS; #endif } // TODO: A similar function should be already available in SRP lib on master. Use that instead float4 ComputeScreenPos(float4 positionCS) { float4 o = positionCS * 0.5f; o.xy = float2(o.x, o.y * _ProjectionParams.x) + o.w; o.zw = positionCS.zw; return o; } real 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 real(fogFactor); #elif defined(FOG_EXP) || defined(FOG_EXP2) // factor = exp(-(density*z)^2) // -density * z computed at vertex return real(unity_FogParams.x * clipZ_01); #else return 0.0h; #endif } half3 MixFogColor(real3 fragColor, real3 fogColor, real fogFactor) { #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) #if defined(FOG_EXP) // factor = exp(-density*z) // fogFactor = density*z compute at vertex fogFactor = saturate(exp2(-fogFactor)); #elif defined(FOG_EXP2) // factor = exp(-(density*z)^2) // fogFactor = density*z compute at vertex fogFactor = saturate(exp2(-fogFactor*fogFactor)); #endif fragColor = lerp(fogColor, fragColor, fogFactor); #endif return fragColor; } half3 MixFog(real3 fragColor, real fogFactor) { return MixFogColor(fragColor, unity_FogColor.rgb, fogFactor); } // Stereo-related bits #if defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED) // Only single-pass stereo instancing uses array indexing #if defined(UNITY_STEREO_INSTANCING_ENABLED) #define SLICE_ARRAY_INDEX unity_StereoEyeIndex #else #define SLICE_ARRAY_INDEX 0 #endif #define TEXTURE2D_X TEXTURE2D_ARRAY #define TEXTURE2D_X_PARAM TEXTURE2D_ARRAY_PARAM #define TEXTURE2D_X_ARGS TEXTURE2D_ARRAY_ARGS #define TEXTURE2D_X_HALF TEXTURE2D_ARRAY_HALF #define TEXTURE2D_X_FLOAT TEXTURE2D_ARRAY_FLOAT #define LOAD_TEXTURE2D_X(textureName, unCoord2) LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, SLICE_ARRAY_INDEX) #define LOAD_TEXTURE2D_X_LOD(textureName, unCoord2, lod) LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, SLICE_ARRAY_INDEX, lod) #define SAMPLE_TEXTURE2D_X(textureName, samplerName, coord2) SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, SLICE_ARRAY_INDEX) #define SAMPLE_TEXTURE2D_X_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, SLICE_ARRAY_INDEX, lod) #define GATHER_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, SLICE_ARRAY_INDEX) #define GATHER_RED_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_RED_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX)) #define GATHER_GREEN_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_GREEN_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX)) #define GATHER_BLUE_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_BLUE_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX)) #else #define SLICE_ARRAY_INDEX 0 #define TEXTURE2D_X TEXTURE2D #define TEXTURE2D_X_PARAM TEXTURE2D_PARAM #define TEXTURE2D_X_ARGS TEXTURE2D_ARGS #define TEXTURE2D_X_HALF TEXTURE2D_HALF #define TEXTURE2D_X_FLOAT TEXTURE2D_FLOAT #define LOAD_TEXTURE2D_X LOAD_TEXTURE2D #define LOAD_TEXTURE2D_X_LOD LOAD_TEXTURE2D_LOD #define SAMPLE_TEXTURE2D_X SAMPLE_TEXTURE2D #define SAMPLE_TEXTURE2D_X_LOD SAMPLE_TEXTURE2D_LOD #define GATHER_TEXTURE2D_X GATHER_TEXTURE2D #define GATHER_RED_TEXTURE2D_X GATHER_RED_TEXTURE2D #define GATHER_GREEN_TEXTURE2D_X GATHER_GREEN_TEXTURE2D #define GATHER_BLUE_TEXTURE2D_X GATHER_BLUE_TEXTURE2D #endif #if defined(UNITY_SINGLE_PASS_STEREO) float2 TransformStereoScreenSpaceTex(float2 uv, float w) { // TODO: RVS support can be added here, if Universal decides to support it float4 scaleOffset = unity_StereoScaleOffset[unity_StereoEyeIndex]; return uv.xy * scaleOffset.xy + scaleOffset.zw * w; } float2 UnityStereoTransformScreenSpaceTex(float2 uv) { return TransformStereoScreenSpaceTex(saturate(uv), 1.0); } #else #define UnityStereoTransformScreenSpaceTex(uv) uv #endif // defined(UNITY_SINGLE_PASS_STEREO) #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Deprecated.hlsl" #endif