// Set by the asset automatically #define FORCE_GLES_COMPATIBILITY 0 #define LIQUID_VOLUME_SCATTERING #define LIQUID_VOLUME_SMOKE #define LIQUID_VOLUME_BUBBLES #define LIQUID_VOLUME_FP_RENDER_TEXTURES //#define LIQUID_VOLUME_ORTHO #define LIQUID_VOLUME_USE_NOISE3D #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareOpaqueTexture.hlsl" struct appdata_base { float4 vertex : POSITION; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float4 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Input { float4 positionCS : SV_POSITION; float3 realPos : TEXCOORD0; float4 vertex : TEXCOORD1; float3 camPos : TEXCOORD2; float4 screenPos : TEXCOORD3; float3 normalWS : TEXCOORD5; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; struct SurfaceOutput { half3 Albedo; // diffuse color half3 Normal; // tangent space normal, if written half3 Emission; half Specular; // specular power in 0..1 range half Gloss; // specular intensity half Alpha; // alpha for transparencies }; sampler2D _NoiseTex2D; float _DepthAwareOffset; #if LIQUID_VOLUME_DEPTH_AWARE_PASS TEXTURE2D_X_FLOAT(_VLFrontBufferTexture); #endif #if LIQUID_VOLUME_IRREGULAR TEXTURE2D_X_FLOAT(_VLBackBufferTexture); #endif float3 _VertexOffset; half4 _Color1; half4 _Color2; half4 _FoamColor; float _FoamMaxPos; int _FoamRaySteps; float _FoamDensity; float _FoamBottom; float _FoamTurbulence; float _LevelPos; float3 _FlaskThickness; float4 _Size; float3 _Center; float _Muddy; float4 _Turbulence; float _DeepAtten; half4 _SmokeColor; float _SmokeAtten; int _SmokeRaySteps; float _SmokeSpeed; float _SmokeHeightAtten; int _LiquidRaySteps; half4 _GlossinessInt; float _FoamWeight; float4 _Scale; float _UpperLimit; float _LowerLimit; float3 wsCameraPos; half3 _EmissionColor; float _DoubleSidedBias; float _BackDepthBias; float4x4 _Rot; float _TurbulenceSpeed; float _FlaskBlurIntensity; half _Glossiness; half4 _FlaskTint; half4 _FlaskColor; half3 _LightColor; #if defined(LIQUID_VOLUME_SCATTERING) float4 _PointLightPosition[6]; half4 _PointLightColor[6]; float _PointLightInsideAtten; #endif int _LVForcedInvisible; // Open GL 2.0 / WebGL support #if SHADER_API_GLES || FORCE_GLES_COMPATIBILITY #define WEBGL_OR_LEGACY #endif #if defined(WEBGL_OR_LEGACY) sampler2D _Noise2Tex; inline float noise3D(float3 x) { x *= 100.0; float3 f = frac(x); float3 p = x - f; f = f*f*(3.0-2.0*f); float4 xy = float4(p.xy + float2(37.0,17.0)*p.z + f.xy, 0, 0); xy.xy = (xy.xy + 0.5) / 256.0; float2 zz = tex2Dlod(_Noise2Tex, xy).yx; return lerp( zz.x, zz.y, f.z ); } #define SAMPLE_NOISE_3D(tex,pos) noise3D( (pos).xyz) #define BEGIN_LOOP(k,iterations,defaultIterations) for(int k=0;k0) { float rdl = dot(rd.xz / rd.y, rd.xz / rd.y); float tc = h * sqrt (1.0 + rdl); t0 = max(t0, tc); } h = sign(rd.y) * -d.y + sy; if (h>0) { float rdl = dot(rd.xz / rd.y, rd.xz / rd.y); float tc = h * sqrt (1.0 + rdl); t1 = min(t1, tc); } } void intBox(float3 rd, out float t0, out float t1) { #if LIQUID_VOLUME_NON_AABB rd = mul((float3x3)_Rot, rd); #endif float3 ro = wsCameraPos - _Center; #if LIQUID_VOLUME_NON_AABB ro = mul((float3x3)_Rot, ro); #endif float3 invR = 1.0 / rd; float3 boxmin = - _Size.w; float3 boxmax = + _Size.w; float3 tbot = invR * (boxmin - ro); float3 ttop = invR * (boxmax - ro); float3 tmin = min (ttop, tbot); float3 tmax = max (ttop, tbot); float2 tt0 = max (tmin.xx, tmin.yz); t0 = max(tt0.x, tt0.y); tt0 = min (tmax.xx, tmax.yz); t1 = min(tt0.x, tt0.y); } void vert(appdata_base v, out Input o) { o = (Input)0; UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.vertex = v.vertex; o.vertex.w = dot(o.vertex.xz, _Turbulence.zw) + _TurbulenceSpeed; o.vertex.xz *= 0.1.xx * _Turbulence.xx; // extracted from frag o.vertex.xz += _Time.xx; v.vertex.xyz *= _FlaskThickness; VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz); VertexNormalInputs normalInput = GetVertexNormalInputs(v.normalOS, v.tangentOS); o.normalWS = normalInput.normalWS; o.realPos = vertexInput.positionWS; #if LIQUID_VOLUME_IGNORE_GRAVITY o.realPos = mul((float3x3)_Rot, o.realPos - _Center) + _Center; o.camPos = mul((float3x3)_Rot, _WorldSpaceCameraPos - _Center) + _Center; #else o.camPos = _WorldSpaceCameraPos; #endif o.positionCS = vertexInput.positionCS; #if LIQUID_VOLUME_IRREGULAR if (_LVForcedInvisible == 1) { o.positionCS.xy = -10000; } #endif o.screenPos = ComputeScreenPos(o.positionCS); } half4 raymarch(float4 vertex, float3 rd, float t0, float t1); // forward declaration SAMPLER(sampler_point_clamp); #if defined(LIQUID_VOLUME_FP_RENDER_TEXTURES) #define texDistance(tex, uv) SAMPLE_TEXTURE2D_X(tex, sampler_point_clamp, uv).r #else inline float DecodeFloatRGBA( float4 enc ) { float4 kDecodeDot = float4(1.0, 1/255.0, 1/65025.0, 1/16581375.0); return dot( enc, kDecodeDot ); } #define texDistance(tex, uv) ( (1.0 / DecodeFloatRGBA(SAMPLE_TEXTURE2D_X(tex, sampler_point_clamp, uv))) - 1.0 ) #endif float minimum_distance_sqr(float rayLengthSqr, float3 w, float3 p) { // Return minimum distance between line segment vw and point p float t = saturate(dot(p, w) / rayLengthSqr); float3 projection = t * w; return dot(p - projection, p - projection); } inline float3 ProjectOnPlane(float3 v, float3 planeNormal) { float sqrMag = dot(planeNormal, planeNormal); float dt = dot(v, planeNormal); return v - planeNormal * dt / sqrMag; } float GetLightAttenuation(float3 wpos) { float4 shadowCoord = TransformWorldToShadowCoord(wpos); float atten = MainLightRealtimeShadow(shadowCoord); return atten; } half3 boxBlur(float2 uv) { const int BOXRADIUS = 5; int kernel_window_size = BOXRADIUS*2+1; half3 color = 0.0.xxx; UNITY_UNROLL for (int ry = -BOXRADIUS; ry <= BOXRADIUS; ++ry) { UNITY_UNROLL for (int rx = -BOXRADIUS; rx <= BOXRADIUS; ++rx) { color += SampleSceneColor(uv + float2(rx,ry)/_ScreenParams.xy); } } half w = (BOXRADIUS * 2 + 1) * (BOXRADIUS * 2 + 1); return (color/w); } half4 frag (Input IN) : SV_Target { UNITY_SETUP_INSTANCE_ID(IN); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN); if (IN.vertex.y > _UpperLimit || IN.vertex.y < _LowerLimit) return 0.0.xxxx; wsCameraPos = IN.camPos; #if defined(LIQUID_VOLUME_ORTHO) float3 cameraForward = UNITY_MATRIX_V[2].xyz; float3 orthoCameraPos = ProjectOnPlane(IN.realPos - wsCameraPos, cameraForward) + wsCameraPos; wsCameraPos = lerp(wsCameraPos, orthoCameraPos, unity_OrthoParams.w); #endif float t0, t1; float3 rd = IN.realPos - wsCameraPos; float dist = length(rd); rd /= dist; #if LIQUID_VOLUME_SPHERE intSphere(rd, t0, t1); #elif LIQUID_VOLUME_CUBE intBox(rd, t0, t1); #elif LIQUID_VOLUME_CYLINDER intCylinder(rd, t0, t1); #else t0 = dist; t1 = dist + _Size.x + _BackDepthBias; #endif t0 = max(0,t0); // needed if camera is inside container #if LIQUID_VOLUME_DEPTH_AWARE || LIQUID_VOLUME_DEPTH_AWARE_PASS || LIQUID_VOLUME_IRREGULAR float2 uv = IN.screenPos.xy / IN.screenPos.w; #endif #if LIQUID_VOLUME_DEPTH_AWARE #if defined(LIQUID_VOLUME_ORTHO) float vz = SampleSceneDepth(uv); #if UNITY_REVERSED_Z vz = 1.0 - vz; #endif float z = vz * _ProjectionParams.z; #else float depth = SampleSceneDepth(uv); float4 raw = mul(UNITY_MATRIX_I_VP, float4(uv * 2.0 - 1.0, depth, 1.0)); float3 wpos = raw.xyz / raw.w; float z = distance(wsCameraPos, wpos.xyz) + _DepthAwareOffset; #endif t1 = min(t1, z); #endif #if LIQUID_VOLUME_DEPTH_AWARE_PASS float frontDist = texDistance(_VLFrontBufferTexture, UnityStereoTransformScreenSpaceTex(uv)); t1 = min(t1, frontDist); #endif #if LIQUID_VOLUME_IRREGULAR float backDist = texDistance(_VLBackBufferTexture, UnityStereoTransformScreenSpaceTex(uv)); t1 = min(t1, backDist); clip(t1-t0-_DoubleSidedBias); #endif half4 co = raymarch(IN.vertex,rd,t0,t1); #if defined(LIQUID_VOLUME_SCATTERING) float3 rayStart = wsCameraPos + rd * t0; float rayLength = t1 - t0; rayStart += rd * _PointLightInsideAtten; rayLength -= _PointLightInsideAtten; float3 ray = rd * rayLength; float rayLengthSqr = rayLength * rayLength; for (int k=0;k<6;k++) { half pointLightInfluence = minimum_distance_sqr(rayLengthSqr, ray, _PointLightPosition[k].xyz - rayStart) / _PointLightColor[k].w; co.rgb += _PointLightColor[k].rgb * (co.a / (1.0 + pointLightInfluence)); } #endif SurfaceOutput s = (SurfaceOutput)0; s.Albedo = co.rgb; s.Emission = co.rgb * _EmissionColor; s.Alpha = co.a; s.Normal = IN.normalWS; half atten = 1.0; //GetLightAttenuation(IN.realPos); // uncomment if shadow support is required co = LIGHTING(s, _MainLightPosition.xyz, -rd, atten); #if !UNITY_COLORSPACE_GAMMA co.rgb = SRGBToLinear(co.rgb); #endif #if LIQUID_VOLUME_USE_REFRACTION float4 uvgrab = IN.screenPos; half4 bgColor = half4(boxBlur(uvgrab.xy/uvgrab.w), _FlaskBlurIntensity); co = lerp(bgColor, co, co.a); #endif return co; }