Skip to content

Instantly share code, notes, and snippets.

@ChristophHaag
Created November 28, 2016 12:04
Show Gist options
  • Save ChristophHaag/2f21290e8a61b90b2b3c2a53c164ccda to your computer and use it in GitHub Desktop.
Save ChristophHaag/2f21290e8a61b90b2b3c2a53c164ccda to your computer and use it in GitHub Desktop.
X-Plane 11 shaders link failure
#include "prefix.glsl"
#include "terrain_common.glsl"
#include "new_scattering.glsl"
#if 1
#define WANT_LIGHTMETER 0
#include "tone_map.glsl"
#endif
#include "srgb.glsl"
#line 11
#define SPECULAR_GAIN 2.0
#define MATERIAL_BASED_WATER 0
#if USE_SCAT
uniform float u_fog_scale;
uniform float u_sky_gain;
#endif
#if RENDERING_MODE == MODE_RENDERING_EXTERIOR || RENDERING_MODE == MODE_RENDERING_GBUFFER
#define WATER_PLANET_RGB water_deep2
#define WATER_FAR_RGB water_deep2
#else
#define WATER_PLANET_RGB (vec3(70.0/255.0,122.0/255.0,170.0/255.0)*0.5)
#define WATER_FAR_RGB vec3(70.0/255.0,122.0/255.0,170.0/255.0)
//#define WATER_PLANET_RGB vec3(0.109803921568627,0.419607843137255,0.627450980392157)
//#define WATER_FAR_RGB vec3(0.109803921568627,0.419607843137255,0.627450980392157)
#endif
#define SHOW_WHICH_SHADERS 0
#define SHOW_SHADOW_SPLITS 0
/*
PERF NOTES from the r500:
pow usually beats unrolling for integer exponents - compile must unroll too.
sqrt beats pow near but not 0.5 by about 50%.
sqrt with linear blend (e.g. 1.2sqrt(x) - 0.2x) beats pow by about 25%
surprisingly, we had to cut our taylor series down to ONE term (e.g. x, 1-x^2) to beat sin/cos. Maybe revisit this later?
*/
#define data_out0 gl_FragData[0]
#define data_out1 gl_FragData[1]
#define data_out2 gl_FragData[2]
#define data_out3 gl_FragData[3]
#define data_out4 gl_FragData[4]
#define dynamic_reflection_tex tex_base
// #define water_st v_texcoord_base
// #define water_prop v_texcoord_water
// TEX COORDS:
// 0: ST of base texture
// 1: ST of composite texture
// 4: ST of borders
// 5: ST of cloud shadows
// 6: ST of landing light
#include "terrain_waves.glsl"
#line 70
// This is the number of projections of cliffs PER RADIAN. So parts = 1 means about 6 projections.
#define PARTS 1.047197551196598
// When this is 1, we use the cheap 4-way projection...when this is 0, we use trig.
#define CHEAP_DIRECTIONAL 0
#define AUTO_HILL_DITHER_RATIO 0.125
// These parameters define how we convert a normal vector into a blending factor in 3 zones of terrain.
#define GND_OFFSET tex_params.x
#define GND_SCALE tex_params.y
#define CLIFF_OFFSET tex_params.z
#define CLIFF_SCALE tex_params.w
#define WANT_PCF_4TAP 0
#define JITTER (1.0 / 4096.0)
float interp(float x1, float y1, float x2, float y2, float x)
{
float r = clamp((x-x1)/(x2-x1),0.0,1.0);
return y1 + r * (y2 - y1);
}
float focus_rat(float r)
{
// To increase blur, use the first line instead.
// return r;
return clamp(r * 2.0 - 0.25,0.0,1.0);
}
// Dither function. Nominally it attempst to return 1 if blend > alpha, and 0 if blend < alpha.
// Nominally it should always return 1 if blend = 1 and 0 if blend is 0. This converts a ramped
// alpha blend (passed in blend) to a pixelated dithering mask if alpha is a randomly modulated dither
// pattern.
//
// Softening: really we don't just want to select pixels, it looks bad. So we attempt to "soften"
// the transition by providing intermediate values when blend is _near_ alpha. Soften is the range
// near alpha to soften. So for example, soften = 0.1, alpha = 0.5 then blend will return 0 if it is < 0.4
// then ramp from 0.4 to 0.6 in a linear or smooth-step blend, then return 1.0 for any input > 0.6.
//
// Note that the alpha levels are SQUEEZED, e.g. if our alpha dither was going from 0-1 it now goes from 0.1 to
// 0.9. This is needed to guarantee that AFTER softening, blend 0->0 and blend 1->1. The clients of this function
// require this to ensure that fully opaque and fully transparent areas don't become translucent due to soft dither.
// (In other words, if dithering out a cliff, we need the cliff 100% GONE, never coming back, by 0% alpha, so that we
// don't see an artifact when the cliff triangle ENDS!)
float dither(float blend, float alpha, float soften)
{
// return step(alpha, blend);
alpha = alpha * (1.0 - soften - soften) + soften;
return smoothstep(alpha-soften,alpha+soften, blend);
}
/************************************************************************************************************************
* CSM SHADOW MAPPING ROUTINES
************************************************************************************************************************/
#if SHOW_SHADOW_SPLITS
vec3 csm_debug_tint(vec3 in_color, float eye_z)
{
vec3 tint;
#if CSM_COUNT > 0
tint = vec3(1,0,0);
if(-eye_z < shadow.shadow_d0.x)
return tint;
#endif
#if CSM_COUNT > 1
tint = mix(in_color, vec3(1,0.5,0), 0.5);
if(-eye_z < shadow.shadow_d0.y && -eye_z > shadow.shadow_d1.x)
return tint;
#endif
#if CSM_COUNT > 0
tint = mix(in_color, vec3(1,0,0), 0.5);
if(-eye_z < shadow.shadow_d0.y)
return tint;
#endif
#if CSM_COUNT > 2
tint = mix(in_color, vec3(0.5,1,0), 0.5);
if(-eye_z < shadow.shadow_d1.y && -eye_z > shadow.shadow_d2.x)
return tint;
#endif
#if CSM_COUNT > 1
tint = mix(in_color, vec3(1,1,0), 0.5);
if(-eye_z < shadow.shadow_d1.y)
return tint;
#endif
#if CSM_COUNT > 3
tint = mix(in_color, vec3(0,1,0.5), 0.5);
if(-eye_z < shadow.shadow_d2.y && -eye_z > shadow.shadow_d3.x)
return tint;
#endif
#if CSM_COUNT > 2
tint = mix(in_color, vec3(0,1,0), 0.5);
if(-eye_z < shadow.shadow_d2.y)
return tint;
#endif
#if CSM_COUNT > 3
tint = mix(in_color, vec3(0,1,1), 0.5);
if(-eye_z < shadow.shadow_d3.y)
return tint;
#endif
#if CSM_COUNT > 0
tint = mix(in_color, vec3(1,1,1), 0.5);
#endif
return tint;
}
#endif
#if HAS_ARRAY_TEX
#define smap_type sampler2DArrayShadow
#else
#define smap_type sampler2DShadow
#endif
float pcf_sample(smap_type map, float idx, vec3 coords, vec2 ddx, vec2 ddy)
{
#if WANT_PCF_4TAP
return dot(vec4(
shadow2D(map,coords+vec3(-JITTER,-JITTER,0.0)).r,
shadow2D(map,coords+vec3(-JITTER, JITTER,0.0)).r,
shadow2D(map,coords+vec3( JITTER,-JITTER,0.0)).r,
shadow2D(map,coords+vec3( JITTER, JITTER,0.0)).r),
vec4(0.25));
#else
#if HAS_ARRAY_TEX
vec4 coords4 = vec4(coords.xy, idx+tex_smap_offset, coords.z);
return shadow2DArrayGradARB(map,coords4, ddx, ddy).r;
#else
return shadow2DGradARB(map,coords, ddx, ddy).r;
#endif
#endif
}
float csm_shadow_level(float ao_level, float eye_z_dist)
{
#if CSM_COUNT == 0
return ao_level;
#else
float shadow_result;
vec2 ddx0 = dFdx(v_shadow_str0.xy);
vec2 ddy0 = dFdy(v_shadow_str0.xy);
float shadow_result0 = pcf_sample(tex_smap0,0.0,v_shadow_str0.xyz,ddx0,ddy0);
#if CSM_COUNT > 1
vec2 ddx1 = dFdx(v_shadow_str1.xy);
vec2 ddy1 = dFdy(v_shadow_str1.xy);
float shadow_result1 = pcf_sample(tex_smap1,1.0,v_shadow_str1.xyz,ddx1,ddy1);
#endif
#if CSM_COUNT > 2
vec2 ddx2 = dFdx(v_shadow_str2.xy);
vec2 ddy2 = dFdy(v_shadow_str2.xy);
float shadow_result2 = pcf_sample(tex_smap2,2.0,v_shadow_str2.xyz,ddx2,ddy2);
#endif
#if CSM_COUNT > 3
vec2 ddx3 = dFdx(v_shadow_str3.xy);
vec2 ddy3 = dFdy(v_shadow_str3.xy);
float shadow_result3 = pcf_sample(tex_smap3,3.0,v_shadow_str3.xyz,ddx3,ddy3);
#endif
#if CSM_COUNT > 1
// 0+1
if(eye_z_dist > shadow.shadow_d1.x && eye_z_dist < shadow.shadow_d0.y)
{
shadow_result = mix(shadow_result0,shadow_result1,eye_z_dist * shadow.shadow_d0.z + shadow.shadow_d0.w);
} else
#endif
#if CSM_COUNT > 0
// 0
if(eye_z_dist < shadow.shadow_d0.y)
{
shadow_result = shadow_result0;
} else
#endif
#if CSM_COUNT > 2
// 1+2
if(eye_z_dist > shadow.shadow_d2.x && eye_z_dist < shadow.shadow_d1.y)
{
shadow_result = mix(shadow_result1,shadow_result2,eye_z_dist * shadow.shadow_d1.z + shadow.shadow_d1.w);
} else
#endif
#if CSM_COUNT > 1
// 1
if(eye_z_dist < shadow.shadow_d1.y)
{
shadow_result = shadow_result1;
} else
#endif
#if CSM_COUNT > 3
// 2+3
if(eye_z_dist > shadow.shadow_d3.x && eye_z_dist < shadow.shadow_d2.y)
{
shadow_result = mix(shadow_result2,shadow_result3,eye_z_dist * shadow.shadow_d2.z + shadow.shadow_d2.w);
} else
#endif
#if CSM_COUNT > 2
// 2
if(eye_z_dist < shadow.shadow_d2.y)
{
shadow_result = shadow_result2;
} else
#endif
#if CSM_COUNT > 3
// 3
if(eye_z_dist < shadow.shadow_d3.y)
{
shadow_result = shadow_result3;
} else
#endif
shadow_result = 1.0;
float shadow_rat = clamp(eye_z_dist * shadow_fade.x +shadow_fade.y,0.0,1.0);
float ao_rat = clamp(eye_z_dist * shadow_fade.z +shadow_fade.w,0.0,1.0);
return min(
mix(shadow_result,1.0,shadow_rat),
mix(1.0,ao_level,ao_rat));
#endif
}
#if RENDERING_MODE != MODE_RENDERING_DEPTH && RENDERING_MODE != MODE_RENDERING_GBUFFER
float calc_total_shadow_level(in float static_ao)
{
//----------------------------------------------------------------------------------------------------------------------------------------
// BURNED IN SHADOWS
//----------------------------------------------------------------------------------------------------------------------------------------
float shadow_level = static_ao;
//----------------------------------------------------------------------------------------------------------------------------------------
// CSM SHADOW MAPPING
//----------------------------------------------------------------------------------------------------------------------------------------
#if CSM_COUNT > 0
shadow_level = csm_shadow_level(shadow_level, -v_position_eye.z);
#endif
//----------------------------------------------------------------------------------------------------------------------------------------
// CLOUD SHADOWS
//----------------------------------------------------------------------------------------------------------------------------------------
#if USE_SHAD
shadow_level = min(shadow_level,texture2D(tex_shad, v_texcoord_shadow).r*shadow_master.z+shadow_master.w);
#endif
//----------------------------------------------------------------------------------------------------------------------------------------
// FINAL SHADOW SCALE
//----------------------------------------------------------------------------------------------------------------------------------------
shadow_level = shadow_level*shadow_master.x+shadow_master.y;
return shadow_level;
}
#endif
/************************************************************************************************************************
* DECAL ROUTINES
************************************************************************************************************************/
vec3 apply_decal_rgb(vec3 albedo, vec3 decal, vec3 decal_base, float ratio)
{
return albedo + (decal - decal_base) * ratio;
}
vec3 apply_decal_alpha(vec3 albedo, float decal, float ratio)
{
float decal_v = mix(0.5,decal,ratio);
// 2x decal ('plutonium' decal)
// return albedo * 2.0 * decal_v;
// Hard light
return decal_v > 0.5 ? 1.0 - (1.0 - 2.0 * (decal_v - 0.5))*(1.0 - albedo) : 2.0 * albedo * decal_v;
// "Overlay"
// return albedo * (albedo + 2.0 * decal_v * (1.0 - albedo));
// "Soft light" blend mode:
// vec3 screen_blend = 1.0 - (1.0 - albedo) * (1.0 - decal_v);
// return ((1.0 - albedo) * decal_v + screen_blend) * albedo;
}
/************************************************************************************************************************
* NORMAL MAP ROUTINES
************************************************************************************************************************/
#define WANT_NORMAL ((RENDERING_MODE != MODE_RENDERING_DEPTH) && NORMAL_MODE != MODE_NORMAL_NONE)
vec3 calculate_normals(out vec4 per_pixel_normal)
{
#if MATERIAL_BASED_WATER && TEXTURE_MODE == MODE_WATER_REFLECTION
vec3 V;
vec3 Vc;
vec3 R;
vec4 reflection_sample;
vec4 disp;
vec2 src_dxdz = calc_water_grad();
// Conversion of a gradient to a normal is the normalization of dx,dy,-1. So this is sort of an approximation I think.
vec3 water_normal = normalize(vec3(src_dxdz.r,1.0,src_dxdz.g));
water_normal = reflect_plane_x * water_normal.x +
reflect_plane_y * water_normal.y +
reflect_plane_z * water_normal.z;
per_pixel_normal.b = 0.02005931219952;
per_pixel_normal.a = 0.99 - 0.01 * log(-v_position_eye.z);
return water_normal;
#endif
#if !WANT_NORMAL
per_pixel_normal = vec4(0,1,0,1.0);
return normalize(v_normal_eye);
#elif NORMAL_MODE == MODE_NORMAL_SPEC
per_pixel_normal = texture2D(tex_bump, v_texcoord_base * u_bump_scale.x);
per_pixel_normal.b = 0.04;
return normalize(v_normal_eye);
#else
// When we use projected textures, there are two important things to know about our texture map:
// 1. We know exactly what our basis vectors are when we start our batch - it's just the tex-coord projection
// vectors transformed into eye space. (The basis vector maps obj->UV so since we want st->UV and since a
// transform is the dest coord's basis "in" source, we are transforming obj-space vectors into eye space.
// 2. We don't wnat to use the more expensive per pixel derivative-based basis generation because for very large
// model-view coords, the precision of the UV map is low. Normally with a sampler, we would never notice a 1/1000000000th
// of a pixel res limit, but when running the derivative, th derivative goes inconsistent when zoomed in, making
// fugly spatter. In other words, we get bump map spatter when the max res of the generated UV map coordinates is greater than
// one screen pixel.
// Fix both at once: let x-plane pass in our basis vectors in eye space...which of course makes the bump map case quite brief!
per_pixel_normal = texture2D(tex_bump, v_texcoord_base * u_bump_scale.x);
if(per_pixel_normal == vec4(0.0))
per_pixel_normal = vec4(0.5,0.5,1.0,0.0);
vec3 shuffled = vec3(per_pixel_normal.r * 2.0 - 1.0,
per_pixel_normal.g * 2.0 - 1.0,
per_pixel_normal.b );
#if NORMAL_MODE != MODE_NORMAL_METALNESS && NORMAL_MODE != MODE_NORMAL_ALPHA
per_pixel_normal.b = 0.04;
#endif
#if NORMAL_MODE == MODE_NORMAL_HDEF
shuffled.rg *= shuffled.b;
#endif
shuffled.rg *= u_bump_scale.y;
shuffled.z = sqrt(max(0.0,1.0-length(shuffled.xy)));
#if PROJ_BASE
vec3 S = basis_S;
vec3 T = basis_T;
float sgn = 1.0;
#else
vec3 q0 = dFdx(v_position_eye.xyz);
vec3 q1 = dFdy(v_position_eye.xyz);
vec2 st0 = dFdx(v_texcoord_base);
vec2 st1 = dFdy(v_texcoord_base);
// Where did THAT come from? Well... S and T are "basis" vectors, that is:
// dx = ds * Sx + dt * Tx
// dy = ds * Sy + dt * Ty
// dz = ds * Sz + dt * Tz
// For EACH of these equations, we have two unknowns. For example, JUST take the X axis. WE want to solve for Sx and Tx where
// dx = ds * Sx + dt * Tx
// If we only had two "samples" where we map a pair of s and t vectors into eye space, we could find Sx and Tx.
// Wait - we do...
// q0.x = st0.s * Sx + st0.t * Tx
// q1.x = st1.s * Sx + st1.t * Tx
// Two eqs, two unknowns - the solution is "static". In fact
// Sx = ( q0.x * st1.t - q1.x * st0.t) / (st1.t * st0.s - st0.t * st1.s)
// Tx = (-Q0.x * st1.s + q1.x * st0.s) / (st1.t * st0.s - st0.t * st1.s)
// As it happens to work out, the DENOMINATOR isn't going to change as we apply this same formula over
// all 3 axes (x, y, z). Thus we can just take the numerator to get a vector of the same direction but different magnitude.
// Since we want to normalize anyway, this is not a problem.
// STN are the axis of the tangent coordinate system expressed in EYE SPACE.
vec3 S = normalize( q0 * st1.t - q1 * st0.t);
vec3 T = normalize(-q0 * st1.s + q1 * st0.s);
float sgn = sign(dot(cross(S,T),v_normal_eye));
#endif
return normalize(S * sgn * shuffled.x + T * sgn * shuffled.y + v_normal_eye * shuffled.z);
#endif
}
/************************************************************************************************************************
* SUN LIGHTING
************************************************************************************************************************/
void apply_fog(
inout vec4 tex_color)
{
#if FOG_MODE == MODE_FOG_TEXTURE
// This block is the planet -> DSF cross-fade! The big use_scat is just a convoluted way to
// back-match what we SHOULD be blending to. The fade_dist uniform is where we fade our DSF
// out- without this we get a 'hard' DSF->planet cut over.
vec2 screen_rat = gl_FragCoord.xy * screen_dims_inv.xy;
#if USE_SCAT
vec4 tfog_color = texture2DArrayLod(tex_tfog, vec3(screen_rat,1.0),0);
vec4 sfog_color = texture2DArrayLod(tex_tfog, vec3(screen_rat,0.0),0) * u_sky_gain;
#if TONE_MODE == MODE_TONE_FIXED
tone_map_uncharted(sfog_color.rgb,1.0);
#endif
tfog_color.rgb += sfog_color.rgb * (1.0 - tfog_color.a);
#else
vec4 tfog_color = texture2DLod(tex_tfog, screen_rat,0);
#endif
float tfog_rat = clamp(v_position_eye.z * fade_dist.x + fade_dist.y,0.0,1.0);
// tfog_rat *= tfog_rat;
// Fog is in sRGB space always! Why? Light accums between albedo and emmissive
// are in sRGB in deferred, so deferred fog is sRGB, so fwd is the same way to match.
tex_color.rgb = mix(tex_color.rgb,tfog_color.rgb,tfog_rat);
#elif FOG_MODE == MODE_FOG_VERTEX
float fog = clamp((gl_Fog.end + v_position_eye.z) * gl_Fog.scale,0.0,1.0);
tex_color.rgb =mix(gl_Fog.color.rgb,tex_color.rgb, fog);
#endif
}
#if MATERIAL_BASED_WATER && TEXTURE_MODE == MODE_WATER_REFLECTION
#undef HAS_SPEC
#define HAS_SPEC 1
#undef NORMAL_MODE
#define NORMAL_MODE MODE_NORMAL_METALNESS
#endif
#include "experimental.glsl"
#line 519
/************************************************************************************************************************
* ALBEDO/TEXTURE/MATERIAL FROM MODEL
************************************************************************************************************************/
void calculate_albedo(out vec4 tex_color, out vec4 lit_color, out float static_ao, in vec3 v_normal_eye_use)
{
float modulator1 = 1.0, modulator2 = 1.0;
#if TEXTURE_MODE == MODE_TEXTURE
tex_color = texture2D(tex_base, v_texcoord_base);
#endif
#if TEXTURE_MODE == MODE_DETAIL
tex_color = texture2D(tex_base, v_texcoord_base);
vec4 modulator = texture2D(tex_comp, v_texcoord_base);
vec4 terrain = vec4(texture2D(tex_comp2, v_position_object.xz * tex_params.xy).rgb, modulator.g);
float total_alpha = tex_color.a + (1.0 - tex_color.a) * modulator.g;
tex_color.rgb = total_alpha == 0.0 ? tex_color.rgb : (tex_color.rgb * tex_color.a + terrain.rgb * (1.0 - tex_color.a) * modulator.g) / total_alpha;
tex_color.a = total_alpha;
modulator1 = modulator.b;
modulator2 = modulator.r;
#endif
#if TEXTURE_MODE == MODE_SWIZZLE
// The offset is how far into each tile we are - we find this by doing a clamp-to-grid via fract.
vec2 offset = fract(v_texcoord_base * tex_params.xy) * tex_params.zw;
// The "virtual" texture (where one page table = 1 repeat) comes from scaling from the UV map. We scale UP by the page table
// size but DOWN by the tile granularity. If we have a 4x4 tile grid and an 8x8 page tile, then the virtual texture repeats once
// for every TWO real repeats.
vec2 uv_virtual = (v_texcoord_base - offset) * tex_params.xy * tex_params2.zw;
// Now: fetch the "page address" - that is, a fractional offset into the tiled texture. The scale-and-round corrects for the
// fact that the page table is tored in RG8 format, and thus isn't "exact" in its powers of 2. I'm not sure exactly how many
// bits we can use before the rounding fails, but since the addressed pages (e.g. tiles in the texture aren't going to be a whole
// lot more than, like, 16x16, I think we'll be okay.
vec2 page_address = floor(texture2D(tex_noise,uv_virtual).rg * tex_params.xy + 0.5) * tex_params.zw;
// Finally, look up the actual texture based on the page + offset, using the original UV map for derivatives to avoid mipmap blur
// at the tile edges.
tex_color = texture2DGradARB(tex_base, page_address + offset, dFdx(v_texcoord_base),dFdy(v_texcoord_base));
#endif
#if TEXTURE_MODE == MODE_SWIZZLE2
vec2 offset = fract(v_texcoord_base * tex_params.xy) * tex_params.zw;
vec2 uv_virtual = (v_texcoord_base - offset) * tex_params.xy * tex_params2.zw;
// We treat the tile table as being 2x as wide and jump to the second texture for the right-half tiles.
vec2 page_address = floor(texture2D(tex_noise,uv_virtual).rg * tex_params.xy * vec2(2.0,1.0) + 0.5) * tex_params.zw;
tex_color = (page_address.x >= 1.0) ? texture2DGradARB(tex_comp, page_address + offset, dFdx(v_texcoord_base),dFdy(v_texcoord_base)) :
texture2DGradARB(tex_base, page_address + offset, dFdx(v_texcoord_base),dFdy(v_texcoord_base));
#endif
#if TEXTURE_MODE == MODE_AUTO_VARY && 1
float blend_level = texture2D(tex_base, v_texcoord_base * vec2(0.004,0.002)).a;
float ac = abs(fract(blend_level * 4.0) - mod(floor(blend_level * 4.0),2.0));
float off1=step(0.25,blend_level) * (1.0-step(0.75,blend_level));
float off2=step(0.5,blend_level); //* (1.0-step(1.0,blend_level));
vec4 tex_color1 = texture2D(tex_base, v_texcoord_base + vec2(0.1,0.7) * off1);
vec4 tex_color2 = texture2D(tex_base, v_texcoord_base + vec2(0.3,0.6) * off2 + vec2(0.6, 0.1));
tex_color = vec4(mix(tex_color1.rgb,tex_color2.rgb, smoothstep(0.0,0.1,ac - tex_color2.a)),tex_color2.a);
#endif
#if TEXTURE_MODE == MODE_AUTO_VARY && 0
vec4 tex_color1 = texture2D(tex_base, v_texcoord_base);
vec4 tex_color2 = texture2D(tex_base, v_texcoord_base + vec2(0.3,0.6));
float ac = smoothstep(0.4,0.6,texture2D(tex_base, v_texcoord_base * vec2(0.02,0.01)).a);
tex_color = vec4(mix(tex_color1.rgb,tex_color2.rgb, smoothstep(0.0,0.1,ac - tex_color2.a)),tex_color2.a);
#endif
#if TEXTURE_MODE == MODE_COMPOSITE
// These are our two basic albedo flavors, which are mixed by noise.
tex_color = texture2D(tex_base, v_texcoord_base);
vec4 comp_color = texture2D(tex_comp, v_position_object.xz * tex_params.xy);
vec4 far_color = texture2D(tex_comp2, v_texcoord_base * tex_params3.ww);
// Noise generation. 4 octaves of noise with various scales and amplitudes.
vec4 noise = (texture2D(tex_noise, v_texcoord_base * tex_params2.x )-0.5) * 2.0 * tex_params2.z +
(texture2D(tex_noise, v_texcoord_base * tex_params2.x * tex_params2.y )-0.5) * 2.0 * tex_params2.z * tex_params2.w +
(texture2D(tex_noise, v_texcoord_base * tex_params2.x * tex_params2.y * tex_params2.y )-0.5) * 2.0 * tex_params2.z * tex_params2.w * tex_params2.w +
(texture2D(tex_noise, v_texcoord_base * tex_params2.x * tex_params2.y * tex_params2.y * tex_params2.y)-0.5) * 2.0 * tex_params2.z * tex_params2.w * tex_params2.w * tex_params2.w;
// I tried buildng the control level from the noise in like, 8 different ways.
// noise.b has the noise level, and comp_color.a has the dither pattern for the
// top texture. The best I came up with was the last one: a narrow range in the middle
// of the noise (the 'water level' cuts between them. Make the range wider for softer
// transitions. Mix in a litttle bit of the albedo's alpha (dither) to shape it with
// the terrain.
float control_level = smoothstep(
-tex_params.z + tex_params3.x,
tex_params.z + tex_params3.x,
noise.b - tex_params.w * 2.0 * (comp_color.a-0.5));
// Mix the albedos, top albedo provides alpha for borders.
tex_color.rgb = mix(comp_color.rgb,tex_color.rgb,control_level);
tex_color.a = comp_color.a;
float far_level = clamp(tex_params3.y * -v_position_eye.z + tex_params3.z,0.0,1.0);
tex_color = mix(tex_color, far_color, far_level);
// Decal application based on control level and fade-out with far-view texture fade-in.
modulator1 = control_level * (1.0 - far_level);
modulator2 = (1.0-control_level) * (1.0 - far_level);
#endif
#if TEXTURE_MODE == MODE_AUTO_VARY2 && 1
// Ben says: go to KCHD to see this case!
float blend_level = smoothstep(0.4,0.6,texture2D(tex_base, v_texcoord_base * vec2(0.004,0.002)).a);
float ac = abs(fract(blend_level * 4.0) - mod(floor(blend_level * 4.0),2.0));
float off1=step(0.25,blend_level) * (1.0-step(0.75,blend_level));
float off2=step(0.5,blend_level); //* (1.0-step(1.0,blend_level));
// APPLE BUG?!?! on NV8800 these lines cause artifacts on the mesh. WEIRD! Should be the same as
// above.
// NOPE! Ben-is-stupid bug! ? : introduces non-uniform code flow, screws up derivative calculation when off1/off2
// are part of the tex coordinates. manual gradient application is necessary; probably there is a mip-chain-change artifact
// where step is applied.
// off1=(blend_level < 0.25 ? 0.0 : 1.0) * (1.0-(blend_level < 0.75 ? 0.0 : 1.0));
// off2=blend_level < 0.5 ? 0.0 : 1.0;
vec4 tex_color1 = texture2D(tex_base, v_texcoord_base + vec2(0.1,0.7) * off1);
vec4 tex_color2 = texture2D(tex_comp, v_texcoord_base + vec2(0.3,0.6) * off2);
tex_color = vec4(mix(tex_color1.rgb,tex_color2.rgb, smoothstep(0.0,0.1,ac - tex_color2.a)),tex_color2.a);
#endif
#if TEXTURE_MODE == MODE_AUTO_VARY2 && 0
vec4 tex_color1 = texture2D(tex_base, v_texcoord_base);
vec4 tex_color2 = texture2D(tex_comp, v_texcoord_base + vec2(0.3,0.6));
float ac = smoothstep(0.4,0.6,texture2D(tex_base, v_texcoord_base * vec2(0.02,0.01)).a);
tex_color = vec4(mix(tex_color1.rgb,tex_color2.rgb, smoothstep(0.0,0.1,ac - tex_color2.a)),tex_color2.a);
#endif
#if TEXTURE_MODE == MODE_AUTO_HILL
#if !CHEAP_DIRECTIONAL
vec2 st_wrl = v_position_object.xz;
vec3 st_cliff = (v_position_object.xyz * tex_params2.zwz);
float rot = v_normal_object.z == 0.0 ? -1.570796326794897 : -atan(v_normal_object.x, v_normal_object.z);
float rot_lo = floor(rot / PARTS) * PARTS;
float rot_hi = ceil (rot / PARTS) * PARTS;
float rat = focus_rat((rot - rot_lo) / PARTS);
float cs1 = cos(rot_lo);
float sn1 = sin(rot_lo);
float cs2 = cos(rot_hi);
float sn2 = sin(rot_hi);
vec2 st_rot1 = vec2( st_wrl.x * cs1 + st_wrl.y * sn1,
-st_wrl.x * sn1 + st_wrl.y * cs1);
vec2 st_rot2 = vec2( st_wrl.x * cs2 + st_wrl.y * sn2,
-st_wrl.x * sn2 + st_wrl.y * cs2);
vec2 st_rot1_ = vec2( st_cliff.x * cs1 + st_cliff.z * sn1,
st_cliff.y);
vec2 st_rot2_ = vec2( st_cliff.x * cs2 + st_cliff.z * sn2,
st_cliff.y);
vec2 ddx = dFdx(v_texcoord_base);
vec2 ddy = dFdy(v_texcoord_base);
vec3 nda = abs(v_normal_object);
float gnd_in = clamp(GND_SCALE * v_normal_object.y + GND_OFFSET, 0.0, 1.0);
float cliff_in = clamp(CLIFF_SCALE * v_normal_object.y + CLIFF_OFFSET,0.0,1.0);
vec4 hill_color= vec4(1.0, 1.0, 0.0, 0.5);
if(cliff_in < 1.0 || gnd_in < 1.0)
{
hill_color = mix(
texture2DGradARB(tex_comp, st_rot1 * tex_params2.xy, ddx, ddy),
texture2DGradARB(tex_comp, st_rot2 * tex_params2.xy, ddx, ddy),
rat);
}
vec4 cliff_color = vec4(0.0, 0.0, 1.0, 0.5);
vec3 proj_both = (v_position_object.xyz * tex_params2.zwz);
if(cliff_in > 0.0)
{
cliff_color = mix(
texture2DGradARB(tex_comp2, st_rot1_, ddx, ddy),
texture2DGradARB(tex_comp2, st_rot2_, ddx, ddy),
rat);
cliff_in = dither(cliff_in, hill_color.a, AUTO_HILL_DITHER_RATIO);
}
vec4 gnd_color = vec4(1.0, 0.0, 1.0, 1.0);
if(gnd_in > 0.0)
{
gnd_color = texture2D(tex_base, v_texcoord_base);
gnd_in = 1.0 - dither(1.0 - gnd_in, gnd_color.a, AUTO_HILL_DITHER_RATIO);
}
tex_color = mix(
mix(
hill_color,
cliff_color,
cliff_in),
gnd_color,
gnd_in);
#else
vec3 nda = abs(v_normal_object);
float ew_blend = smoothstep(0.9, 1.1, (nda.x + 0.01) / (nda.z + 0.01));
float gnd_in = clamp(GND_SCALE * v_normal_object.y + GND_OFFSET, 0.0, 1.0);
float cliff_in = clamp(CLIFF_SCALE * v_normal_object.y + CLIFF_OFFSET,0.0,1.0);
vec4 hill_color= vec4(1.0, 1.0, 0.0, 0.5);
vec2 proj_ns = v_position_object.xz;
vec2 proj_ew = vec2(-proj_ns.t, proj_ns.s);
proj_ns *= tex_params2.xy;
proj_ew *= tex_params2.xy;
if(cliff_in < 1.0 || gnd_in < 1.0)
{
hill_color = mix(texture2D(tex_comp, proj_ns * sign( v_normal_object.z)), texture2D(tex_comp, proj_ew * sign( v_normal_object.x)), ew_blend);
}
vec4 cliff_color = vec4(0.0, 0.0, 1.0, 0.5);
vec3 proj_both = (v_position_object.xyz * tex_params2.zwz);
if(cliff_in > 0.0)
{
cliff_color=
mix(texture2D(tex_comp2, proj_both.xy), texture2D(tex_comp2, proj_both.zy), ew_blend);
cliff_in = dither(cliff_in, hill_color.a, AUTO_HILL_DITHER_RATIO);
}
vec4 gnd_color = vec4(1.0, 0.0, 1.0, 1.0);
if(gnd_in > 0.0)
{
gnd_color = texture2D(tex_base, v_texcoord_base);
gnd_in = 1.0 - dither(1.0 - gnd_in, gnd_color.a, AUTO_HILL_DITHER_RATIO);
}
tex_color = mix(
mix(
hill_color,
cliff_color,
cliff_in),
gnd_color,
gnd_in);
#endif
#endif
#if TEXTURE_MODE == MODE_AUTO_HILL_HEADING
#if !CHEAP_DIRECTIONAL
vec2 st_wrl = v_position_object.xz;
vec3 st_cliff = (v_position_object.xyz * tex_params2.zwz);
float rot = v_normal_object.z == 0.0 ? -1.570796326794897 : -atan(v_normal_object.x, v_normal_object.z);
float rot_lo = floor(rot / PARTS) * PARTS;
float rot_hi = ceil (rot / PARTS) * PARTS;
float rat = focus_rat((rot - rot_lo) / PARTS);
float cs1 = cos(rot_lo);
float sn1 = sin(rot_lo);
float cs2 = cos(rot_hi);
float sn2 = sin(rot_hi);
vec2 st_rot1 = vec2( st_wrl.x * cs1 + st_wrl.y * sn1,
-st_wrl.x * sn1 + st_wrl.y * cs1);
vec2 st_rot2 = vec2( st_wrl.x * cs2 + st_wrl.y * sn2,
-st_wrl.x * sn2 + st_wrl.y * cs2);
vec2 st_rot1_ = vec2( st_cliff.x * cs1 + st_cliff.z * sn1,
st_cliff.y);
vec2 st_rot2_ = vec2( st_cliff.x * cs2 + st_cliff.z * sn2,
st_cliff.y);
vec2 st_rot1_c = vec2( st_wrl.x * cs1 + st_wrl.y * sn1,
-st_wrl.x * sn1 + st_wrl.y * cs1);
vec2 st_rot2_c = vec2( st_wrl.x * cs2 + st_wrl.y * sn2,
-st_wrl.x * sn2 + st_wrl.y * cs2);
vec2 ddx = dFdx(v_texcoord_base);
vec2 ddy = dFdy(v_texcoord_base);
vec3 nda = abs(v_normal_object);
float gnd_in = clamp(GND_SCALE * v_normal_object.y + GND_OFFSET, 0.0, 1.0);
float cliff_in = clamp(CLIFF_SCALE * v_normal_object.y + CLIFF_OFFSET,0.0,1.0);
vec4 hill_color= vec4(1.0, 1.0, 0.0, 0.5);
if(cliff_in < 1.0 || gnd_in < 1.0)
{
hill_color = mix(
texture2DGradARB(tex_comp, st_rot1 * tex_params2.xy, ddx, ddy),
texture2DGradARB(tex_comp, st_rot2 * tex_params2.xy, ddx, ddy),
rat);
}
vec4 cliff_color = vec4(0.0, 0.0, 1.0, 0.5);
vec3 proj_both = (v_position_object.xyz * tex_params2.zwz);
if(cliff_in > 0.0)
{
cliff_color = mix(
texture2DGradARB(tex_comp2, st_rot1_, ddx, ddy),
texture2DGradARB(tex_comp2, st_rot2_, ddx, ddy),
rat);
cliff_in = dither(cliff_in, hill_color.a, AUTO_HILL_DITHER_RATIO);
}
vec4 gnd_color = vec4(1.0, 0.0, 1.0, 1.0);
if(gnd_in > 0.0)
{
gnd_color = mix(
texture2DGradARB(tex_base, st_rot1_c * vec2(gl_ObjectPlaneS[0].x,gl_ObjectPlaneT[0].z), ddx, ddy),
texture2DGradARB(tex_base, st_rot2_c * vec2(gl_ObjectPlaneS[0].x,gl_ObjectPlaneT[0].z), ddx, ddy),
rat);
gnd_in = 1.0 - dither(1.0 - gnd_in, gnd_color.a, AUTO_HILL_DITHER_RATIO);
}
tex_color = mix(
mix(
hill_color,
cliff_color,
cliff_in),
gnd_color,
gnd_in);
#else
vec3 nda = abs(v_normal_object);
float ew_blend = smoothstep(0.9, 1.1, (nda.x + 0.01) / (nda.z + 0.01));
float gnd_in = clamp(GND_SCALE * v_normal_object.y + GND_OFFSET, 0.0, 1.0);
float cliff_in = clamp(CLIFF_SCALE * v_normal_object.y + CLIFF_OFFSET,0.0,1.0);
vec4 hill_color= vec4(1.0, 1.0, 0.0, 0.5);
vec2 proj_ns = v_position_object.xz;
vec2 proj_ew = vec2(-proj_ns.t, proj_ns.s);
proj_ns *= tex_params2.xy;
proj_ew *= tex_params2.xy;
if(cliff_in < 1.0 || gnd_in < 1.0)
{
hill_color = mix(texture2D(tex_comp, proj_ns * sign( v_normal_object.z)), texture2D(tex_comp, proj_ew * sign( v_normal_object.x)), ew_blend);
}
vec4 cliff_color = vec4(0.0, 0.0, 1.0, 0.5);
vec3 proj_both = (v_position_object.xyz * tex_params2.zwz);
if(cliff_in > 0.0)
{
cliff_color=
mix(texture2D(tex_comp2, proj_both.xy), texture2D(tex_comp2, proj_both.zy), ew_blend);
cliff_in = dither(cliff_in, hill_color.a, AUTO_HILL_DITHER_RATIO);
}
proj_ns = v_position_object.xz;
proj_ew = vec2(-proj_ns.t, proj_ns.s);
proj_ns *= vec2(gl_ObjectPlaneS[0].x,gl_ObjectPlaneT[0].z);
proj_ew *= vec2(gl_ObjectPlaneS[0].x,gl_ObjectPlaneT[0].z);
vec4 gnd_color = vec4(1.0, 0.0, 1.0, 1.0);
if(gnd_in > 0.0)
{
gnd_color = mix(texture2D(tex_base, proj_ns * sign( v_normal_object.z)), texture2D(tex_base, proj_ew * sign( v_normal_object.x)), ew_blend);
gnd_in = 1.0 - dither(1.0 - gnd_in, gnd_color.a, AUTO_HILL_DITHER_RATIO);
}
tex_color = mix(
mix(
hill_color,
cliff_color,
cliff_in),
gnd_color,
gnd_in);
#endif
#endif
#if TEXTURE_MODE == MODE_HEADING
#if CHEAP_DIRECTIONAL
vec2 proj_ns = v_position_object.xz;
vec2 proj_ew = vec2(-proj_ns.t, proj_ns.s);
proj_ns *= vec2(gl_ObjectPlaneS[0].x,gl_ObjectPlaneT[0].z);
proj_ew *= vec2(gl_ObjectPlaneS[0].x,gl_ObjectPlaneT[0].z);
vec3 nda = abs(v_normal_object);
float ew_blend = smoothstep(0.9, 1.1, (nda.x + 0.01) / (nda.z + 0.01));
tex_color = mix(
texture2D(tex_base, proj_ns * sign( v_normal_object.z)),
texture2D(tex_base, proj_ew * sign( v_normal_object.x)), ew_blend);
#else
vec2 st_wrl = v_position_object.xz;
float rot = v_normal_object.z == 0.0 ? -1.570796326794897 : -atan(v_normal_object.x, v_normal_object.z);
float rot_lo = floor(rot / PARTS) * PARTS;
float rot_hi = ceil (rot / PARTS) * PARTS;
float rat = focus_rat((rot - rot_lo) / PARTS);
float cs1 = cos(rot_lo);
float sn1 = sin(rot_lo);
vec2 st_rot1 = vec2( st_wrl.x * cs1 + st_wrl.y * sn1,
-st_wrl.x * sn1 + st_wrl.y * cs1);
float cs2 = cos(rot_hi);
float sn2 = sin(rot_hi);
vec2 st_rot2 = vec2( st_wrl.x * cs2 + st_wrl.y * sn2,
-st_wrl.x * sn2 + st_wrl.y * cs2);
vec2 ddx = dFdx(v_texcoord_base);
vec2 ddy = dFdy(v_texcoord_base);
tex_color = mix(
texture2DGradARB(tex_base, st_rot1 * vec2(gl_ObjectPlaneS[0].x,gl_ObjectPlaneT[0].z), ddx, ddy),
texture2DGradARB(tex_base, st_rot2 * vec2(gl_ObjectPlaneS[0].x,gl_ObjectPlaneT[0].z), ddx, ddy),
rat);
#endif /* CHEAP_DIRECTIONAL */
#endif
#if TEXTURE_MODE == MODE_RUNWAY
tex_color = texture2D(tex_base, v_texcoord_base);
tex_color.rgb *= texture2D(tex_comp, v_texcoord_comp).rgb;
tex_color.a *= v_color.a;
#endif
#if TEXTURE_MODE == MODE_SHOULDER
tex_color = texture2D(tex_base, v_texcoord_base);
vec4 com_color = texture2D(tex_comp, v_texcoord_comp);
tex_color.rgb = mix(tex_color.rgb,com_color.rgb,com_color.a);
#endif
#if TEXTURE_MODE == MODE_COLOR
tex_color = vec4(1.0);
#endif
#if TEXTURE_MODE == MODE_WATER_PLANET
tex_color = texture2D(tex_base, v_texcoord_base);
vec3 wet = WATER_PLANET_RGB;
float spec_exp = 512.0;
vec3 half_angle = normalize(gl_LightSource[0].position.xyz + normalize(-v_position_eye.xyz));
vec3 grad_delt = (half_angle - v_normal_eye_use);
wet += gl_LightSource[0].specular.rgb * 2.0 * exp(-dot(grad_delt,grad_delt) * spec_exp);
tex_color.rgb = mix(wet,tex_color.rgb,tex_color.a);
tex_color.a = 1.0;
#endif
#if TEXTURE_MODE == MODE_WATER_REFLECTION
vec3 V;
vec3 Vc;
vec3 R;
vec4 reflection_sample;
vec4 disp;
/************************************************************************************************************************************************
* PROCEDURAL WATER NORMAL MAP
************************************************************************************************************************************************
The gradient function is the derivative of a height field in both directions. In other words, given a height map of a surface, the gradient
gives us the deltas to the next cell up and over. Calculus says that the gradient of a constant surface is the normal...ignoring the
derivation, basically the normal vector is (dx,dy,-1). (Of course that needs to be normalized.)
What we need is a normal map, that is, a mapping from XZ surface positions to XYZ normal vectors, that tell which way the water faces at any
point.
We want to create our water by adding together multiple amplitude-scaled height-maps. That is, we want to superimpose tall slow waves on
fast short ones.
Here's the cool part: because we can get our normals from gradients, and derivatives are additive, we don't have to build a finished height
map and then take derivatives. (Such a technique really wouldn't look good...the pixelation of the points chosen to calculate the derivatives
would make obvious "blocks" in the water.) Instead we can simply add up the derivativse of each height field, and the sum is the derivative
of the sum of the height fields (that we never calculated).
So in fact, X-Plane works entirely in terms of gradients for the water...we pass in a texture where R = dx and G = dz (where -1 to 1 are
scaled to 0..1) and we just sample it multiple times and add them together.
*/
vec2 src_dxdz = calc_water_grad();
// Conversion of a gradient to a normal is the normalization of dx,dy,-1. So this is sort of an approximation I think.
vec3 water_normal = normalize(vec3(src_dxdz.r,1.0,src_dxdz.g));
water_normal = reflect_plane_x * water_normal.x +
reflect_plane_y * water_normal.y +
reflect_plane_z * water_normal.z;
/************************************************************************************************************************************************
* REFLECTION CALCULATION
************************************************************************************************************************************************
Now figure out where the normal reflects to. We've been passed the location of this pixel and the camera in world-coordinatse. Given the
normal vector we can reflect and then shoot that ray into a projection plane from when we took a pic of the world.
*/
V = v_position_eye.xyz; // Find "V" - this is the vector to the water droplet from the camera.
R = reflect(V,water_normal); // Find "R" - this is the vector from the water droplet to, well, whatever we see in it, e.g. the mountain.
reflection_sample = vec4(R * (-back_plane.w - // This finds the location in modelview space of the intersection of our "back plane" with the
dot(back_plane.xyz, v_position_eye.xyz)) / dot(back_plane.xyz,R) // line from our water pixel out via the reflection vector.
+ v_position_eye.xyz, 1.0); // Note that we force 1.0 into "w" - we need a good w coord or the camera matrix will not work right.
vec3 reflect_color_lin = texture2DProj(dynamic_reflection_tex, water_camera * reflection_sample).rgb; // Projective texture based on our point...
/************************************************************************************************************************************************
* FRESNEL EQUATION
************************************************************************************************************************************************
*/
float mip_level = length(fwidth(v_texcoord_base * water_waves1.st * 256.0));
float fresnel = 0.020373188 + 0.979626812 * pow(1.0 - max(-dot(water_normal,normalize(V)),0.0),5.0);
vec3 deep_water = texture2D(tex_comp,v_texcoord_comp.st).rgb;
vec3 far_water = WATER_FAR_RGB;
float mix_far = 0.0;
float mix_deep = (1.0 - fresnel) * (1.0 - mix_far);
float mix_refl = (fresnel);
tex_color = vec4((mix_deep * (deep_water)) + mix_far * far_water,1.0);
lit_color = vec4((mix_refl * reflect_color_lin),0.0);
float spec_exp = 4096.0 / clamp(mip_level,1.0,4.0);
vec3 half_angle = normalize(gl_LightSource[0].position.xyz + normalize(-v_position_eye.xyz));
vec3 grad_delt = (half_angle - water_normal);
lit_color.rgb += gl_LightSource[0].specular.rgb * 350.0 * exp(-dot(grad_delt,grad_delt) * spec_exp) * (fresnel);
#if MATERIAL_BASED_WATER
// tex_color = vec4(to_linear(deep_water),1.0);
tex_color = vec4((deep_water),1.0);
lit_color = vec4(0.0);
#endif
// tex_color.rgb = to_linear(deep_water);
// lit_color.rgb = vec3(0.0);
#endif
#define identify_shader(r,g,b,a) tex_color=vec4(r,g,b,a)
#if SHOW_WHICH_SHADERS
#if TEXTURE_MODE == MODE_AUTO_VARY
identify_shader(1,0,1,1);
#elif TEXTURE_MODE == MODE_AUTO_VARY2
identify_shader(1,0.5,1,1);
#elif TEXTURE_MODE == MODE_SWIZZLE
identify_shader(0.5,0.5,1,1);
#elif TEXTURE_MODE == MODE_SWIZZLE2
identify_shader(0,0,1,1);
#elif TEXTURE_MODE == MODE_HEADING
identify_shader(0,0.5,0,1);
#elif TEXTURE_MODE == MODE_AUTO_HILL
identify_shader(0,1,0,1);
#elif TEXTURE_MODE == MODE_AUTO_HILL_HEADING
identify_shader(0.5,1,0.5,1);
#elif TEXTURE_MODE == MODE_COMPOSITE
identify_shader(1,1,0,1);
#elif TEXTURE_MODE == MODE_DETAIL
identify_shader(1,0,0,1);
#endif
#endif
#if DECAL1 == 1
vec4 decal1_rgba = texture2D(tex_deca, v_texcoord_base * decal1_scale.xy);
vec4 decal1_rgba_bias = texture2D(tex_deca, v_texcoord_base * decal1_scale.xy,16.0);
#endif
#if DECAL1 == 2
vec4 decal1_rgba = texture2D(tex_deca, v_position_object.xz * decal1_scale.xy);
vec4 decal1_rgba_bias = texture2D(tex_deca, v_position_object.xz * decal1_scale.xy,16.0);
#endif
#if DECAL2 == 1
vec4 decal2_rgba = texture2D(tex_dec2, v_texcoord_base * decal2_scale.xy);
vec4 decal2_rgba_bias = texture2D(tex_dec2, v_texcoord_base * decal2_scale.xy,16.0);
#endif
#if DECAL2 == 2
vec4 decal2_rgba = texture2D(tex_dec2, v_position_object.xz * decal2_scale.xy);
vec4 decal2_rgba_bias = texture2D(tex_dec2, v_position_object.xz * decal2_scale.xy,16.0);
#endif
#if DECAL1 > 0
float rgb1_mix = clamp(dot(tex_color,decal1_rgb_key) + modulator1 * decal1_km_key.r + decal1_km_key.g,0.0,1.0);
float a1_mix = clamp(dot(tex_color,decal1_a_key) + modulator2 * decal1_km_key.b + decal1_km_key.a,0.0,1.0);
#endif
#if DECAL2 > 0
float rgb2_mix = clamp(dot(tex_color,decal2_rgb_key) + modulator2 * decal2_km_key.r + decal2_km_key.g,0.0,1.0);
float a2_mix = clamp(dot(tex_color,decal2_a_key) + modulator1 * decal2_km_key.b + decal2_km_key.a,0.0,1.0);
#endif
float non_munged_alpha = tex_color.a;
#if DECAL1 > 0
tex_color.rgb = apply_decal_rgb(tex_color.rgb,decal1_rgba.rgb,decal1_rgba_bias.rgb,rgb1_mix);
tex_color.rgb = apply_decal_alpha(tex_color.rgb,decal1_rgba.a,a1_mix);
tex_color.a = clamp(tex_color.a - (decal1_rgba.a - 0.5) * decal1_scale.z, 0.0, 1.0);
#endif
#if DECAL2 > 0
tex_color.rgb = apply_decal_rgb(tex_color.rgb,decal2_rgba.rgb,decal2_rgba_bias.rgb,rgb2_mix);
tex_color.rgb = apply_decal_alpha(tex_color.rgb,decal2_rgba.a, a2_mix);
tex_color.a = clamp(tex_color.a - (decal2_rgba.a - 0.5) * decal2_scale.z, 0.0, 1.0);
#endif
//----------------------------------------------------------------------------------------------------------------------------------------
// ALPHA MIX-DOWN
//----------------------------------------------------------------------------------------------------------------------------------------
#if ALPHA_MODE == MODE_ALPHA_NONE
tex_color.a = 1.0;
#endif
#if ALPHA_MODE == MODE_ALPHA_COMPOSITE
tex_color.a = max(smoothstep(0.5 - u_alpha_width.x * 0.5,0.5 + u_alpha_width.x * 0.5,tex_color.a),u_alpha_width.y * non_munged_alpha);
#endif
#if BORDER_MODE == MODE_BORDER_ALPHA
// FOR ENV scenery - yes. For runways - NO! shit!
tex_color.a = texture2D(tex_bord, v_texcoord_border).a;
#endif
#if BORDER_MODE == MODE_BORDER_COMPOSITE
// Composite border - the difference between the alpha of the base terrain and the border
// selects whether we keep this pixel.
tex_color.a = clamp((texture2D(tex_bord, v_texcoord_border).a - tex_color.a)*4.0,0.0,1.0);
#endif
#if GEOM_MODE != MODE_GEOM_INSTANCE
float v_lit_level = 1.0;
#endif
#if NITE_MODE == MODE_NIGHT_RGB && RENDERING_MODE != MODE_RENDERING_DEPTH
lit_color = v_lit_level*night_level*vec4(texture2D(tex_nite, v_texcoord_base).rgb,0.0);
#elif NITE_MODE == MODE_NIGHT_RGBA && RENDERING_MODE != MODE_RENDERING_DEPTH
#if 0
vec4 night_raw = texture2D(tex_nite, v_texcoord_base);
float edge_uv = fract(193.0 * (night_raw.a + night_level + v_instance_seed * 55.0));
float edge = texture2D(tex_nite,vec2(0.0839, edge_uv)).r;
float window_on = smoothstep(edge,edge+0.05, night_level);
lit_color = v_lit_level*window_on*night_raw;
#else
lit_color = v_lit_level*night_level*texture2D(tex_nite, v_texcoord_base).rgba;
#endif
#elif TEXTURE_MODE != MODE_WATER_REFLECTION
lit_color = vec4(0.0);
#endif
#if NIGHT_VISION
lit_color.g = clamp(lit_color.r + lit_color.g + lit_color.b,0.0,1.0);
lit_color.r = 0.0;
lit_color.b = 0.0;
#endif
#if TEXTURE_MODE == MODE_DETAIL
static_ao = modulator.a;
#endif
#if TEXTURE_MODE != MODE_DETAIL
static_ao = 1.0;
#endif
tex_color.rgb = to_linear(tex_color.rgb);
lit_color.rgb = to_linear(lit_color.rgb);
lit_color.rgb += tex_color.rgb * to_linear(gl_FrontLightModelProduct.sceneColor.rgb);
tex_color.rgb *= v_color.rgb;
}
/************************************************************************************************************************
* BACKEND OUTPUT
************************************************************************************************************************/
// These must be conditionalized so that the compiler doens't see writes to both outputs.
#if RENDERING_MODE == MODE_RENDERING_DEPTH
void output_depth(in vec4 tex_color)
{
if (tex_color.a <= u_alpha_cut.x)
discard;
gl_FragColor = tex_color;
}
#elif RENDERING_MODE == MODE_RENDERING_GBUFFER
void output_gbuffer(
in vec4 tex_color,
in vec4 lit_color,
in float static_ao,
in vec4 per_pixel_normal,
in vec3 v_normal_eye_use)
{
// This is the master "cut" for position and all other boolean parameters. We need a definite value for depth/position, as
// well as specularity and AO. (Well, AO and spec could be blened if we were willing to blend depth.
float cut_pos_3d = ((tex_color.a + lit_color.a) > u_alpha_cut.z) ? 1.0 : 0.0;
// We encode shiny level and shadow-AO into a single channel. The encoding here is tricky: we don't have enough precision to
// encode both at full 8-bit. So: we make AO 1.0 at max shadow and put it higher in the bit pattern. The result:
// - without shadows, it isn't there, the specularity gets full precision.
// - when shadwos are in place, they 'rob' the specularity of precision, but who cares, we're in shadow, the specularity will be
// nuked.
// So we are encoded AO 0...256 into the integer part (256 = max shadow) and specular level into the fractions, 0..0.5. (We have to
// use 0.5 so we can use fract/floor to separate later.
//
// Note that we could recover ONE more bit by using the sign, e.g. shiny_ao * 2.0 - 1.0. But...so far my test material shows that
// by the time shininess gets too ugly, we're way in th shadow.
#if MATERIAL_BASED_WATER && TEXTURE_MODE == MODE_WATER_REFLECTION
float specular = per_pixel_normal.a;
float shiny_ao = floor((1.0 - static_ao) * 256.0) + specular * 0.5;
#elif NORMAL_MODE != MODE_NORMAL_NONE
float specular = clamp(gl_FrontMaterial.specular.r * per_pixel_normal.a,0.0,1.0);
float shiny_ao = floor((1.0 - static_ao) * 256.0) + specular * 0.5;
#else
float specular = clamp(gl_FrontMaterial.specular.r,0.0,1.0);
float shiny_ao = floor((1.0 - static_ao) * 256.0) + specular * 0.5;
#endif
// Ben says: WHY is term 0 multiplide by v_color? This must have been on purpose, but I have no idea what it does.
// Answer: diffuse_rgb TINT is passed into v_color...thus we perma-tint the albedo on the way into the g-buffer.
// Why pre-multiplication? We want a correct build-up of our alpha channel...by using 1,1-SA, we get correct alpha buildup
// which means more accurate rendering of translucent g-buffered stuff over the sky dome. For a test, try the B47 at LOWI.
// Note that the g-buffer should be premultiplied anyway so that it could be composited back over a sky dome when we are
// finished.
// Finally, Z has been shifted to the right 10 bits because float-16 has limited mantissa range; we don't care THAT much about
// sub-metric placement (our units are meters). F16 normally gives us a smallest exponent of 2^-14, and then gives us 10 bits
// of mantissa on top of that. Even with 2^-4 (after the 10-bit shift) we get good placement from the mantissa for close things.
// BUT...for far things, 2^14 isn't nearly enough, that's less than 60 km. The planet is huge. We need the 10-bit shift to not
// max out our half-floats in the planet render.
// R G B A
// Our final scheme: 0 albedo_r albedo_g albedo_b albedo_a
// 1 ao shiny empty unusable
// 2 normal_x normal_y - -
// 3 emissive_r emissive_g emissive_b emissive_a
// 4 unused depth - -
//
// Not using BA of the middle two channels is intentional! We can use RGBA_F16 on these while using RGBA8888 on the albedo/emissive.
// This squeezes everybody down to 16 bytes. The alpha channel of the position and normal vectors was dead to us anyway, as it had to be
// hard cut to be "in" or "out".
float effective_a = clamp(tex_color.a + lit_color.a,0.0,1.0);
// Our alpha test is modeled via a pair of "noise gates" that saturate up and down. This lets the shader config in X-Plane emulate blend,
// test, or both. "Real" testing levels will be at zero (so when we cut to zero we get no depth write). This way we have full control
// of things like fading in the shader.
if (effective_a > u_alpha_cut.y)
effective_a = 1.0;
#if ALPHA_MODE != MODE_ALPHA_NONE
if (effective_a <= u_alpha_cut.x)
discard;
#endif
// Special insanity: right now the spec alpha is a temporary holder for whether the blue channel detaches to control levels on normal
// map mix-down. Normal maps do blend nicely in our RG encoded scheme.
#if NORMAL_MODE == MODE_NORMAL_ALPHA
float nrml_a = per_pixel_normal.b;
float metalness = 0.04f;
#else
float nrml_a = effective_a;
float metalness = per_pixel_normal.b;
#endif
// And...alpha fade with distance if we want it. Note we want to fade normals - otherwise an in-shadow building wall turns into a big
// dark spot on the terrain as it fades!
#if USE_CRAZY_ALPHA
effective_a *= v_crazy_alpha_fade;
nrml_a *= v_crazy_alpha_fade;
#endif
// Lambertian azimuthal equal-area projection:
// http://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection
// http://aras-p.info/texts/CompactNormalStorage.html
// We used to simply dump the normal dx, dy into R & G and reconstruct dz, but this is wasteful of our 'space'. (The more the surface faces us,
// the less of Dx and Dz we use!)
// frag channel 3 is the "lit" channel. I think we want an alpha term here only because: it will "darken" the existing
// back buffer. So if we put an opaque thing on top of a lit thing (e.g. plane on top of water) we need this to be right.
// To see this: put the Cirrus over water with the sun in a form to make visible waves. The water will 'add through' the tail
// if alpha in channel 3 isn't set right.
// channel 5 MUST be hard cut, not blended - otherwise our eye depth for shadows will be completely fubar...even the tiniest blend
// is a huge screw-up in terms of needed shadow precision.
data_out0 = vec4(tex_color.rgb * /*v_color.rgb * */ effective_a,effective_a);
data_out1 = vec4(static_ao * effective_a, specular * effective_a, metalness * effective_a, effective_a);
data_out2 = vec4(sqrt(2.0 / (1.0 + v_normal_eye_use.z)) * v_normal_eye_use.xy * nrml_a, 0.0, nrml_a);
data_out3 = vec4((lit_color.rgb)*effective_a, effective_a);
data_out4 = vec4(-cut_pos_3d*v_position_eye.z,cut_pos_3d*v_position_eye.z/-1024.0, 0.0, cut_pos_3d);
}
#else
void output_normal(in vec4 tex_color)
{
apply_fog(tex_color);
#if USE_CRAZY_ALPHA
// In fwd render with crazy alpha, we implement the alpha test as a pair of noise gates FIRST, then apply the fade.
// That way the fade doens't "pixel out" the edges of trees.
if (tex_color.a > u_alpha_cut.y)
tex_color.a = 1.0;
#if ALPHA_MODE != MODE_ALPHA_NONE
if (tex_color.a <= u_alpha_cut.x)
discard;
#endif
#if USE_CRAZY_ALPHA
tex_color.a *= v_crazy_alpha_fade;
#endif
gl_FragColor = tex_color;
#else
#if ALPHA_MODE != MODE_ALPHA_NONE
if (tex_color.a <= u_alpha_cut.x)
discard;
#endif
gl_FragColor = tex_color;
#endif
}
#endif
/************************************************************************************************************************
* MAIN SHADER
************************************************************************************************************************/
void main (void)
{
//----------------------------------------------------------------------------------------------------------------------------------------
// NORMAL CALCULATIONS
//----------------------------------------------------------------------------------------------------------------------------------------
vec4 per_pixel_normal;
vec3 normal_eye = calculate_normals(per_pixel_normal);
//----------------------------------------------------------------------------------------------------------------------------------------
// TEXTURE CALCULATIONS
//----------------------------------------------------------------------------------------------------------------------------------------
vec4 albedo_lin, emissive_lin;
float static_ao;
calculate_albedo(albedo_lin,emissive_lin,static_ao,normal_eye);
//----------------------------------------------------------------------------------------------------------------------------------------
// SHADOW
//----------------------------------------------------------------------------------------------------------------------------------------
#if RENDERING_MODE != MODE_RENDERING_DEPTH && RENDERING_MODE != MODE_RENDERING_GBUFFER
float shadow_level = calc_total_shadow_level(static_ao);
#else
float shadow_level = 1.0;
#endif
//----------------------------------------------------------------------------------------------------------------------------------------
// LIGHTING CALCULATIONS
//----------------------------------------------------------------------------------------------------------------------------------------
#if RENDERING_MODE != MODE_RENDERING_DEPTH && RENDERING_MODE != MODE_RENDERING_GBUFFER
vec4 final_color_lin = do_all_lighting(
albedo_lin,
emissive_lin,
normal_eye,
v_position_eye,
shadow_level,
per_pixel_normal,
1.0); // assume no AO
#if TONE_MODE == MODE_TONE_FIXED
tone_map_uncharted(final_color_lin.rgb,1.0);
#endif
#endif
//----------------------------------------------------------------------------------------------------------------------------------------
// BACK-END
//----------------------------------------------------------------------------------------------------------------------------------------
#if RENDERING_MODE == MODE_RENDERING_DEPTH
output_depth(albedo_lin);
#elif RENDERING_MODE == MODE_RENDERING_GBUFFER
output_gbuffer(
albedo_lin,
emissive_lin,
static_ao,
per_pixel_normal,
normal_eye) ;
#else
output_normal(final_color_lin);
#endif
#if TONE_MODE == MODE_TONE_DYNAMIC
tone_map(gl_FragColor.rgb);
#endif
//----------------------------------------------------------------------------------------------------------------------------------------
// DEBUGGING CRAP!
//----------------------------------------------------------------------------------------------------------------------------------------
#if SHOW_SHADOW_SPLITS && CSM_COUNT > 0
gl_FragColor.rgb = csm_debug_tint(gl_FragColor.rgb, v_position_eye.z);
#endif
}
#include "prefix.glsl"
#include "terrain_common.glsl"
#include "srgb.glsl"
#if TONE_MODE != MODE_TONE_NONE
#define WANT_LIGHTMETER 0
#include "tone_map.glsl"
#endif
#line 10
// Texture coord units.
// PASSED IN:
// 0 base ST
// 1 comp ST
// 4 border ST
// 5 cloud shadow ST
// 6 lan light 1
#if VSHADER
attribute vec4 a_vertex;
attribute vec3 a_normal;
attribute vec4 a_color;
// Instancing attributes - X,Y, and Z basis vectors (with offset) come in via attributes.
attribute vec4 a_instance_x;
attribute vec4 a_instance_y;
attribute vec4 a_instance_z;
attribute vec4 a_instance_tint;
attribute vec2 a_lod_fade;
attribute vec2 a_texcoord0;
attribute vec2 a_texcoord1;
attribute vec2 a_texcoord2;
#endif
#include "terrain_waves.glsl"
#if VSHADER
#include "terrain_lights.glsl"
#endif
#line 47
float hack_wave_height(vec2 uv)
{
uv *= 0.01;
return sin(uv.x) * 20.0 + sin(uv.y) * 20.0;
}
//============================================================================================================================================
// VERTEX SHADER
//============================================================================================================================================
#if VSHADER
void main (void)
{
//----------------------------------------------------------------------------------------------------------------------------------------
// GEOMETRY TRANSFORM
//----------------------------------------------------------------------------------------------------------------------------------------
float instance_tint = 1.0;
#if GEOM_MODE == MODE_GEOM_BILLBOARD
float eye_dist = clamp((-(u_modelview_matrix * a_vertex).z-200.0)*0.0005,0.0, 1.0);
float w = sign(a_texcoord1.s) * sqrt(a_texcoord1.s * a_texcoord1.s + a_texcoord1.t * a_texcoord1.t);
v_position_object = a_vertex + mix(vec4(a_texcoord1.s,0.0,a_texcoord1.t,0.0),w * billboard, eye_dist);
gl_Position = u_mvp_matrix * v_position_object;
v_position_eye = u_modelview_matrix * v_position_object;
v_normal_object = a_normal;
#endif
#if GEOM_MODE == MODE_GEOM_SEAFLOOR
// vec2 uv = a_texcoord1;
// vec3 abc = vec3(1.0 - uv.x - uv.y, uv);
// v_position_object.xyz = a_vertex.xyz * abc.x + a_normal * abc.y + a_color.rgb * abc.z;
// v_position_object.w = 1.0;
v_position_object = a_vertex;
v_position_object.y -= a_texcoord0.t * 50.0;
gl_Position = u_mvp_matrix * v_position_object;
v_position_eye = u_modelview_matrix * v_position_object;
v_normal_object = a_normal;
#endif
#if GEOM_MODE == MODE_GEOM_WAVES
// vec2 uv = (a_texcoord1 * a_instance_x.xy + a_instance_x.zw) * a_instance_y.x;
//
// vec3 abc = vec3(1.0 - uv.x - uv.y, uv);
// v_position_object.xyz = a_vertex.xyz * abc.x + a_normal * abc.y + a_color.rgb * abc.z;
// v_position_object.w = 1.0;
v_position_object = a_vertex;
#if !HAS_TESS
vec2 water_st = vec2(dot( v_position_object, gl_ObjectPlaneS[0] ),
dot( v_position_object, gl_ObjectPlaneT[0] ));
float src_z = calc_water_h(a_texcoord0, water_st);
v_position_object.y += src_z;
#endif
v_normal_object = a_normal;
v_position_eye = u_modelview_matrix * v_position_object;
gl_Position = u_mvp_matrix * v_position_object;
#endif
#if GEOM_MODE == MODE_GEOM_NORMAL && NORMAL_MODE == MODE_NORMAL_DISPLACE
v_position_object = a_vertex;
vec3 up = normalize(vec3(v_position_object.x, v_position_object.y + 6000000.0, v_position_object.z));
vec4 ppn = texture2D(tex_bump, a_texcoord0.st);
v_position_object.xyz += (((1.0-ppn.a) * 9266.0 - 418.0) * up);
gl_Position = u_mvp_matrix * v_position_object;
v_position_eye = u_modelview_matrix * v_position_object;
v_normal_object = a_normal;
#endif
#if GEOM_MODE == MODE_GEOM_NORMAL && NORMAL_MODE != MODE_NORMAL_DISPLACE
v_position_object = a_vertex;
gl_Position = u_mvp_matrix * v_position_object;
v_position_eye = u_modelview_matrix * v_position_object;
v_normal_object = a_normal;
#endif
#if GEOM_MODE == MODE_GEOM_PROJ_GRID
vec3 water_props = texture2D(tex_pgrd,a_vertex.xy).rgb;
vec3 vec_to_me_t = mix(corner_eye_tl,corner_eye_tr,a_vertex.x);
vec3 vec_to_me_b = mix(corner_eye_bl,corner_eye_br,a_vertex.x);
vec3 vec_to_me = mix(vec_to_me_b,vec_to_me_t,a_vertex.y);
v_position_eye = vec4(vec_to_me * water_props.z * far_plane.y,1.0);
v_position_object = u_modelview_inverse * v_position_eye;
vec2 water_st = vec2(dot( v_position_object, gl_ObjectPlaneS[0] ),
dot( v_position_object, gl_ObjectPlaneT[0] ));
float src_z = calc_water_h(water_props, water_st);
v_position_object.y += (src_z);// * clamp(water_props.t / 100.0, 0.0, 1.0));
gl_Position = u_mvp_matrix * v_position_object;
v_normal_object = a_normal;
#endif
#if GEOM_MODE == MODE_GEOM_INSTANCE
v_position_object = vec4(
dot(a_vertex, a_instance_x),
dot(a_vertex, a_instance_y),
dot(a_vertex, a_instance_z), 1.0);
gl_Position = u_mvp_matrix * v_position_object;
v_position_eye = u_modelview_matrix * v_position_object;
v_normal_object = vec3(
dot(a_normal, a_instance_x.xyz),
dot(a_normal, a_instance_y.xyz),
dot(a_normal, a_instance_z.xyz));
float instance_seed = fract(abs(a_instance_x.w + a_instance_y.w + a_instance_z.w));
// a_instance_tint contains:
// day static, day instance, night static, night_instance
instance_tint = 1.0 - a_instance_tint.x - a_instance_tint.y * instance_seed;
v_lit_level = 1.0 - a_instance_tint.z - a_instance_tint.w * instance_seed;
v_instance_seed = instance_seed;
#endif
#if GEOM_MODE == MODE_GEOM_INSTANCE_COMP
// WTF is this? Well, normally we'd do a 3 basis + origin reconstruction, based
// on vectors applied to xyz of the obj, plus a constant. (We can transpose this 'matrix'
// and write it as 3 dot products for speed since the w coord of our vertex is 1.)
// This mess starts like that, then includes 3 scalars, e.g. the basis comes from shader,
// the scale from instance.
//
// But....the artists need the trees to be asymmetric, and each one has a different center.
// So we form separate +x and -x vectors with their own scaling factors, and we use min/max
// to extract negative and positive coordinates.
v_position_object.xyz = a_instance_x.xyz +
vec3( 0,1, 0) * a_instance_x.w * a_vertex.y +
vec3( 1,0, 0) * a_instance_y.x * min(a_vertex.x,0.0) +
vec3( 1,0, 0) * a_instance_y.y * max(a_vertex.x,0.0) +
vec3( 0,0, 1) * a_instance_y.z * min(a_vertex.z,0.0) +
vec3( 0,0, 1) * a_instance_y.w * max(a_vertex.z,0.0);
v_position_object.w = 1.0;
gl_Position = u_mvp_matrix * v_position_object;
v_position_eye = u_modelview_matrix * v_position_object;
v_normal_object = a_normal;
#endif
//----------------------------------------------------------------------------------------------------------------------------------------
// LIGHTING CALCULATIONS
//----------------------------------------------------------------------------------------------------------------------------------------
v_normal_object = normalize(v_normal_object);
// Normalize here should not be necessary - but in plane-maker we haev a giant gl-scale which hozes us. :-(
v_normal_eye = normalize(mat3(u_modelview_matrix) * v_normal_object);
v_color = a_color * instance_tint;
// Extra ST coords, needed for some of our special tricks.
#if USE_SHAD
// INTENTIONAL: multiply eye position by "object" plane - we are abusing the GL semantics - the
// gl_ObjectPlaneS is stuffed with an eye-coordinate matrix. We use the obj plane so GL won't
// molest it.
v_texcoord_shadow = vec2(dot( v_position_eye, gl_ObjectPlaneS[5] ),
dot( v_position_eye, gl_ObjectPlaneT[5] ));
#endif
//----------------------------------------------------------------------------------------------------------------------------------------
// TEXTURE COORD COPMUTATIONS
//----------------------------------------------------------------------------------------------------------------------------------------
#if TEXTURE_MODE <= MODE_SHOULDER && PROJ_BASE
v_texcoord_base = vec2(dot( v_position_object, gl_ObjectPlaneS[0] ),
dot( v_position_object, gl_ObjectPlaneT[0] ));
#endif
#if TEXTURE_MODE <= MODE_SHOULDER && !PROJ_BASE
v_texcoord_base = a_texcoord0.st;
#endif
#if TEXTURE_MODE == MODE_RUNWAY || TEXTURE_MODE == MODE_SHOULDER
v_texcoord_comp = a_texcoord1.st;
#endif
#if TEXTURE_MODE == MODE_WATER_PLANET
v_texcoord_base = a_texcoord0.st;
#endif
#if TEXTURE_MODE == MODE_WATER_REFLECTION
v_texcoord_base = vec2(dot( v_position_object, gl_ObjectPlaneS[0] ),
dot( v_position_object, gl_ObjectPlaneT[0] ));
v_texcoord_comp = a_texcoord1;
// v_texcoord_comp = vec2(dot( v_position_object, gl_ObjectPlaneS[1] ),
// dot( v_position_object, gl_ObjectPlaneT[1] ));
#endif
#if TEXTURE_MODE == MODE_WATER_REFLECTION && GEOM_MODE == MODE_GEOM_PROJ_GRID
v_texcoord_water = water_props.x;
#endif
#if TEXTURE_MODE == MODE_WATER_REFLECTION && GEOM_MODE != MODE_GEOM_PROJ_GRID
v_texcoord_water = mix(0.1,1.0,a_texcoord0.s);
#endif
#if BORDER_MODE != MODE_BORDER_NONE
v_texcoord_border = a_texcoord1.st;
#endif
#if GEOM_MODE == MODE_GEOM_INSTANCE_COMP
// Arbitrary UV map rescale - needed for trees.
v_texcoord_base = a_instance_z.xy * texcoord_base + a_instance_z.zw;
#endif
#if CSM_COUNT > 0
v_shadow_str0 = vec3(dot( v_position_eye, shadow.shadow_s0 ),
dot( v_position_eye, shadow.shadow_t0 ),
dot( v_position_eye, shadow.shadow_r0 ));
#endif
#if CSM_COUNT > 1
v_shadow_str1 = vec3(dot( v_position_eye, shadow.shadow_s1 ),
dot( v_position_eye, shadow.shadow_t1 ),
dot( v_position_eye, shadow.shadow_r1 ));
#endif
#if CSM_COUNT > 2
v_shadow_str2 = vec3(dot( v_position_eye, shadow.shadow_s2 ),
dot( v_position_eye, shadow.shadow_t2 ),
dot( v_position_eye, shadow.shadow_r2 ));
#endif
#if CSM_COUNT > 3
v_shadow_str3 = vec3(dot( v_position_eye, shadow.shadow_s3 ),
dot( v_position_eye, shadow.shadow_t3 ),
dot( v_position_eye, shadow.shadow_r3 ));
#endif
#if USE_CRAZY_ALPHA
v_crazy_alpha_fade = 1.0 - clamp(-v_position_eye.z * a_lod_fade.x + a_lod_fade.y,0.0,1.0);
#endif
#if TONE_MODE == MODE_TONE_DYNAMIC
calc_light_meter();
#endif
// This code attempts to use a logarithmic depth buffer, but...it isn't production ready.
// The problem is that somes geometry will be behind the viewer, and the log function goes undefined. I can think
// of two bandaids for this, both of which fail:
// 1. Piece-wise use a second function for close or behind geometry. The problem is that the function discontinuity causes
// clipping to fail because the near plane intersection isn't at the mathetical clip_z=-1 point when a polygon spans the two
// projections.
// 2. Push Z space away from the near clip plane. This is really bad though - we use our most coveted Z precision for geometry we
// don't even see. For a large enough offset to protect from clip-plane nuttiness, we are out in the fugly part of the Z buffer.
// The recommended cure (run the depth coord transform in the fragment shader) is no cure at all, as it will bypass early Z, and we do
// _not_ want to eat that fill rate hit! We need early Z for fast fill optimizations all over the sim. I don't know how anyone can ship
// with early Z not functioning!
// #define C 1.0
// #define OFFSET 0.0
// #define FAR 200000.0
// gl_Position.z = (2.0 * log(C * -v_position_eye.z + 1.0 + OFFSET) / log(C * FAR + 1.0) - 1.0) * gl_Position.w;
}
#endif /* VSHADER */
//============================================================================================================================================
// TESSELLATION
//============================================================================================================================================
#if TCSHADER
layout(vertices = 3) out;
#undef VARYING
#define VARYING(t,v) v##_tess[gl_InvocationID] = v[gl_InvocationID];
float calc_tess_level(vec2 p0, vec2 p1)
{
p0.x *= 512.0;
p0.y *= 384.0;
p1.x *= 512.0;
p1.y *= 384.0;
precise float len = distance(p0,p1);
float split = len / 5.0;
return clamp(split,1.0,64.0);
}
/*
float calc_tess_level(float z1, float z2)
{
precise float z = (z1 + z2) * -0.5;
z = max(z,5.0);
return clamp(64.0 * 5.0 / z, 1.0, 64.0);
}
*/
void main()
{
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
if (gl_InvocationID == 0)
{
#if GEOM_MODE == MODE_GEOM_WAVES
precise vec2 p0 = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w;
precise vec2 p1 = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w;
precise vec2 p2 = gl_in[2].gl_Position.xy / gl_in[2].gl_Position.w;
precise float e0 = calc_tess_level(p1,p2);
precise float e1 = calc_tess_level(p2,p0);
precise float e2 = calc_tess_level(p0,p1);
// float e0 = calc_tess_level(v_position_eye[1].z, v_position_eye[2].z);
// float e1 = calc_tess_level(v_position_eye[2].z, v_position_eye[0].z);
// float e2 = calc_tess_level(v_position_eye[0].z, v_position_eye[1].z);
gl_TessLevelInner[0] = min(min(e1,e2),e0); //(e1 + e2 + e0) / 3.0;
gl_TessLevelOuter[0] = e0;
gl_TessLevelOuter[1] = e1;
gl_TessLevelOuter[2] = e2;
#else
gl_TessLevelInner[0] = 2;
gl_TessLevelOuter[0] = 2;
gl_TessLevelOuter[1] = 2;
gl_TessLevelOuter[2] = 2;
#endif
}
#if USE_CRAZY_ALPHA
VARYING(float,v_crazy_alpha_fade)
#endif
#if GEOM_MODE == MODE_GEOM_INSTANCE
VARYING(float,v_lit_level)
VARYING(float,v_instance_seed)
#endif
// 12 varyings for CSM
#if CSM_COUNT > 0
VARYING(vec3,v_shadow_str0)
#endif
#if CSM_COUNT > 1
VARYING(vec3,v_shadow_str1)
#endif
#if CSM_COUNT > 2
VARYING(vec3,v_shadow_str2)
#endif
#if CSM_COUNT > 3
VARYING(vec3,v_shadow_str3)
#endif
// 18 varyings for objs
VARYING(vec4,v_position_object)
VARYING(vec4,v_position_eye)
VARYING(vec3,v_normal_eye)
VARYING(vec3,v_normal_object)
VARYING(vec4,v_color)
// 10 varyings for tex coords, not all used at once though.
#if TEXTURE_MODE != MODE_COLOR
VARYING(vec2,v_texcoord_base)
#endif
#if TEXTURE_MODE == MODE_RUNWAY || TEXTURE_MODE == MODE_SHOULDER || TEXTURE_MODE == MODE_WATER_PLANET || TEXTURE_MODE == MODE_WATER_REFLECTION
VARYING(vec2,v_texcoord_comp)
#endif
#if TEXTURE_MODE == MODE_WATER_REFLECTION
VARYING(float,v_texcoord_water) // wave depth
#endif
#if BORDER_MODE != MODE_BORDER_NONE
VARYING(vec2,v_texcoord_border)
#endif
#if USE_SHAD
VARYING(vec2,v_texcoord_shadow)
#endif
#if TONE_MODE == MODE_TONE_DYNAMIC
VARYING(float,v_tonemap_gain);
#endif
}
#endif
#if TESHADER
layout(triangles, fractional_odd_spacing, ccw) in;
#undef VARYING
#define VARYING(t,v) v = gl_TessCoord.x * v##_tess[0] + gl_TessCoord.y * v##_tess[1] + gl_TessCoord.z * v##_tess[2];
void main()
{
// 18 varyings for objs
VARYING(vec3,v_normal_eye)
VARYING(vec3,v_normal_object)
VARYING(vec4,v_color)
#if TEXTURE_MODE == MODE_WATER_REFLECTION
VARYING(float,v_texcoord_water) // wave depth
#endif
#if GEOM_MODE == MODE_GEOM_WAVES
v_position_object = gl_TessCoord.x * v_position_object_tess[0] +
gl_TessCoord.y * v_position_object_tess[1] +
gl_TessCoord.z * v_position_object_tess[2];
vec2 water_st = vec2(dot( v_position_object, gl_ObjectPlaneS[0] ),
dot( v_position_object, gl_ObjectPlaneT[0] ));
float src_z = calc_water_h(vec2(v_texcoord_water,0.0), water_st);
// v_position_object.xyz += v_normal_object * src_z;
v_position_object.y += src_z;
gl_Position = u_mvp_matrix * v_position_object;
v_position_eye = u_modelview_matrix * v_position_object;
#else
VARYING(vec4,v_position_object)
VARYING(vec4,v_position_eye)
gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position +
gl_TessCoord.y * gl_in[1].gl_Position +
gl_TessCoord.z * gl_in[2].gl_Position);
#endif
#if USE_CRAZY_ALPHA
VARYING(float,v_crazy_alpha_fade)
#endif
#if GEOM_MODE == MODE_GEOM_INSTANCE
VARYING(float,v_lit_level)
VARYING(float,v_instance_seed)
#endif
// 12 varyings for CSM
#if CSM_COUNT > 0
VARYING(vec3,v_shadow_str0)
#endif
#if CSM_COUNT > 1
VARYING(vec3,v_shadow_str1)
#endif
#if CSM_COUNT > 2
VARYING(vec3,v_shadow_str2)
#endif
#if CSM_COUNT > 3
VARYING(vec3,v_shadow_str3)
#endif
// 10 varyings for tex coords, not all used at once though.
#if TEXTURE_MODE != MODE_COLOR
VARYING(vec2,v_texcoord_base)
#endif
#if TEXTURE_MODE == MODE_RUNWAY || TEXTURE_MODE == MODE_SHOULDER || TEXTURE_MODE == MODE_WATER_PLANET || TEXTURE_MODE == MODE_WATER_REFLECTION
VARYING(vec2,v_texcoord_comp)
#endif
#if BORDER_MODE != MODE_BORDER_NONE
VARYING(vec2,v_texcoord_border)
#endif
#if USE_SHAD
VARYING(vec2,v_texcoord_shadow)
#endif
#if TONE_MODE == MODE_TONE_DYNAMIC
VARYING(float,v_tonemap_gain);
#endif
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment