volopt = [ >= (strstr $volumetrictype $arg1) 0 ] volumetricvariantshader = [ local volumetrictype volumetrictype = $arg3 maxsteps = $arg4 spotlight = (>= $arg2 1) variantshader 0 $arg1 $arg2 (? (< $arg2 0) [ in vec4 vvertex; uniform mat4 lightmatrix; void main(void) { gl_Position = lightmatrix * vvertex; } ]) [ @(gfetchdefs tex3) @(if (volopt "p") [ if (|| (volopt "g") (volopt "G")) [if (> $usetexgather 1) [result [ uniform sampler2DShadow tex4; ]] [result [ uniform sampler2D tex4; ]]] [result [ uniform sampler2DRectShadow tex4; ]] ]) uniform vec4 lightpos; uniform vec3 lightcolor; @(? $spotlight [ uniform vec4 spotparams; ]) @(? (volopt "p") [ uniform vec4 shadowparams; uniform vec2 shadowoffset; ]) uniform vec3 camera; uniform mat4 worldmatrix; uniform vec4 fogdir; uniform vec3 fogcolor; uniform vec2 fogdensity; uniform vec4 radialfogscale; uniform vec2 shadowatlasscale; uniform vec4 volscale; uniform float volminstep; uniform float voldistclamp; uniform float volprefilter; layout(location = 0) out vec4 fragcolor; @(if (volopt "p") [ ? $spotlight [ vec3 getspottc(vec3 dir, float spotdist) { vec2 mparams = shadowparams.xy / max(spotdist, 1e-5); return vec3((dir.xy - spotparams.xy*(spotdist + (spotparams.z < 0.0 ? -1.0 : 1.0)*dir.z)*shadowparams.z) * mparams.x + shadowoffset, mparams.y + shadowparams.w); } ] [ vec3 getshadowtc(vec3 dir) { vec3 adir = abs(dir); float m = max(adir.x, adir.y), mz = max(adir.z, m); vec2 mparams = shadowparams.xy / max(mz, 1e-5); vec4 proj; if(adir.x > adir.y) proj = vec4(dir.zyx, 0.0); else proj = vec4(dir.xzy, 1.0); if(adir.z > m) proj = vec4(dir, 2.0); return vec3(proj.xy * mparams.x + vec2(proj.w, step(proj.z, 0.0)) * shadowparams.z + shadowoffset, mparams.y + shadowparams.w); } ] ]) @(if (volopt "p") [ if (|| (volopt "g") (volopt "G")) [ ? (> $usetexgather 1) [ #define filtershadow(shadowtc) float(shadow(tex4, vec3(shadowtc.xy*shadowatlasscale, shadowtc.z))) ] [ #define filtershadow(shadowtc) step(shadowtc.z, float(texture(tex4, shadowtc.xy*shadowatlasscale))) ] ] [result [ #define filtershadow(shadowtc) float(textureRect(tex4, shadowtc)) ]] ]) void main(void) { vec2 tc = gl_FragCoord.xy * volscale.xy; @(gdepthunpack depth [gfetch(tex3, tc)] [ vec3 pos = (worldmatrix * vec4(depth*tc, depth, 1.0)).xyz; ] [ vec4 pos = worldmatrix * vec4(tc, depth, 1.0); pos.xyz /= pos.w; ]) vec3 ray = pos.xyz - camera; float dist2 = dot(ray, ray), invdist = inversesqrt(dist2), radialdist = min(dist2 * invdist, voldistclamp); ray *= invdist; vec3 camlight = lightpos.xyz - camera * lightpos.w; float camlight2 = dot(camlight, camlight), v = dot(camlight, ray), d = v*v + 1.0 - camlight2; float light = 0.0; if(d > 0) { d = sqrt(d); float front = v - d, back = v + d; @(? $spotlight [ float spotangle = 1.0 - 1.0/spotparams.w, spotangle2 = spotangle*spotangle, rayspot = dot(ray, spotparams.xyz), camspot = dot(camlight, spotparams.xyz), qa = spotangle2 - rayspot*rayspot, qb = rayspot*camspot - spotangle2*v, qc = spotangle2*camlight2 - camspot*camspot, disc = qb*qb - qa*qc; if(disc > 0) { disc = abs(sqrt(disc)/qa); float t = -qb/qa, t0 = t - disc, t1 = t + disc; if(t0*rayspot < camspot) front = max(front, t1); else if(t1*rayspot < camspot) back = min(back, t0); else { front = max(front, t0); back = min(back, t1); } ]) float maxspace = back - front, stepdist = maxspace * @(divf 1.0 $maxsteps); front = max(front, 0.0); back = min(back, radialdist * lightpos.w); float space = back - front; if(space > volminstep*stepdist) { float dither = dot(fract((gl_FragCoord.xy - 0.5).xyxy*vec4(0.5, 0.5, 0.25, 0.25)), vec4(0.375, 0.9375, 0.25, 0.125)); vec3 lightdir = ray * (back + stepdist*dither) - camlight; vec3 raystep = ray * -stepdist; for(int i = 0; i < @maxsteps; i++) { lightdir += raystep; @(if $spotlight [result [ float lightdist2 = dot(lightdir, lightdir); float lightinvdist = inversesqrt(lightdist2); float spotdist = dot(lightdir, spotparams.xyz); float spotatten = 1.0 - (1.0 - lightinvdist * spotdist) * spotparams.w; if(spotatten > 0.0) { float lightatten = clamp(1.0 - lightdist2 * lightinvdist, 0.0, 1.0) * spotatten; @(? (volopt "p") [ vec3 spottc = getspottc(lightdir, spotdist); lightatten *= filtershadow(spottc); ]) light += lightatten; } ]] [result [ float lightatten = clamp(1.0 - length(lightdir), 0.0, 1.0); @(? (volopt "p") [ vec3 shadowtc = getshadowtc(lightdir); lightatten *= filtershadow(shadowtc); ]) light += lightatten; ]]) space -= stepdist; if(space <= 0) break; } float fogcoord = front/lightpos.w; float foglerp = clamp(exp2(fogcoord*fogdensity.x)*fogdensity.y, 0.0, 1.0); light *= foglerp * stepdist; @(? $spotlight [ light /= min(maxspace, 1.0); ]) } @(? $spotlight [}]) } vec2 weights = step(fwidth(radialdist), volprefilter) * (2.0*fract((gl_FragCoord.xy - 0.5)*0.5) - 0.5); light -= dFdx(light) * weights.x; light -= dFdy(light) * weights.y; fragcolor.rgb = light * lightcolor; fragcolor.a = 0.0; } ] ] volumetricshader = [ volumetrictype = (concatword $arg1 $arg2) shadername = (concatword "volumetric" $volumetrictype $arg3) volumetricvariantshader $shadername -1 $arg1 $arg3 volumetricvariantshader $shadername 0 (concatword $arg1 $arg2) $arg3 if (volopt "s") [ volumetricvariantshader $shadername 1 $arg1 $arg3 volumetricvariantshader $shadername 2 (concatword $arg1 $arg2) $arg3 ] ] volumetricbilateralvariantshader = [ numtaps = $arg2 reduced = $arg3 filterdir = $arg4 shader 0 $arg1 [ in vec4 vvertex; @(if $reduced [result [ @(screentexcoord 0) out vec2 texcoord0; ]]) void main(void) { gl_Position = vvertex; @(? $reduced [texcoord0 = vtexcoord0;]) } ] [ @(gfetchdefs tex3) uniform sampler2DRect tex0; uniform vec2 bilateralparams; @(? $reduced [in vec2 texcoord0;]) layout(location = 0) out vec4 fragcolor; void main(void) { #define tc gl_FragCoord.xy #define depthtc @(? $reduced [texcoord0] [gl_FragCoord.xy]) #define tapvec(type, i) @(? (=s $filterdir "x") [type(i, 0.0)] [type(0.0, i)]) #define texval(i) textureRect(tex0, tc + tapvec(vec2, i)) #define texvaloffset(i) textureRectOffset(tex0, tc, tapvec(ivec2, i)) #define depthval(i) gfetch(tex3, depthtc + tapvec(vec2, i)) #define depthvaloffset(i) gfetchoffset(tex3, depthtc, tapvec(ivec2, i)) vec3 color = textureRect(tex0, tc).rgb; @(gdepthunpack depth [gfetch(tex3, depthtc)]) float weights = 1.0; @(loopconcat i (* 2 $numtaps) [ curtap = (- $i $numtaps) if (>= $curtap 0) [curtap = (+ $curtap 1)] curtapoffset = (* $curtap 2) curdepthoffset = (<< $curtapoffset $reduced) curtexval = [texval@(? (<= $mintexrectoffset $curtapoffset $maxtexrectoffset) "offset")(@(+f $curtapoffset))] curdepthval = [depthval@(? (<= $mintexrectoffset $curdepthoffset $maxtexrectoffset) "offset")(@(+f $curdepthoffset))] result [ vec3 color@[i] = @[curtexval].rgb; @(gdepthunpack [depth@[i]] $curdepthval) depth@[i] -= depth; float weight@[i] = exp2(@(-f 0 (* $curtap $curtap))*bilateralparams.x - depth@[i]*depth@[i]*bilateralparams.y); weights += weight@[i]; color += weight@[i] * color@[i]; ] ]) fragcolor = vec4(color / weights, 0.0); } ] ] volumetricbilateralshader = [ volumetricbilateralvariantshader (concatword "volumetricbilateralx" $arg1 $arg2) $arg1 $arg2 x volumetricbilateralvariantshader (concatword "volumetricbilateraly" $arg1 $arg2) $arg1 $arg2 y ]