Jump to content
  • Advertisement
Sign in to follow this  
Murmur79

Beginner help for a simple shader mod

This topic is 1068 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Good day all,

 

the following is a shader found in a flight simulator software, whose task is to draw clouds using a series of 2D puffs (billboards).

 

What I'm trying to do, is to modify the altitude (height) at which the puffs are drawn. Would it be possible to do that?

 

Here's the shader:

 

 

#include "prefix.glsl"

// This would turn on per-pixel tone mapping - we do that for glass cockpit objs but not for clouds.  Clouds are massivel fill rate bound and
// it costs us about 10-15% fill rate on my 4870...don't risk it.  We want fast fast fast fast fast.
#define EXPENSIVE_TONE 0
#if HDR
    #define WANT_LIGHTMETER 0
    #if !EXPENSIVE_TONE
        #define VSHADER_TONE_ONLY 1
    #endif
    #include "tone_map.glsl"
#endif

#line 14


#if PASS == 0
    #define SHAD 1
    #define PLOT 0
#else
    #define PLOT 1
    #define SHAD 0
#endif

#define SPIN_FLAT 0
#define SPIN_MIX 1
#define SPIN_UP 2

/************************************************************************************************************************************************************************
 * TUNING CONSTANTS
 ************************************************************************************************************************************************************************/

// Debugging - set to 1 to color code which billboarding scheme we are using.
#define COLOR_SPIN_MIX 0


#define PLANET_RAD            6378145.0        // 1/12192 meters, gives us 0-40 k feet
#define SCALE_CLOUD_TOPS    0.0000820209

uniform float u_rad_plot    ;    // Radius multiplier when we plot the puffs - I only have this because recompiling the app to change the puff size sucks.
uniform float u_rad_shad    ;    // Radius multiplier when we build the shadow map - if this is bigger than the plot radius, we can get thicker, less "leaky" shadows without having the actual render have mofo huge puffs.
uniform float u_spec_gain    ;    // Gain control on specularity - more means hilites look more blown out.
uniform float u_alpha_plot    ;    // Alpha modulators on the puffs for both plotting and shadows.  Easier for a programmer than editing the PNG.  
uniform float u_alpha_shad    ;    // In the case of the shadow, we really want the puffs to be VERY translucent, because we want a lot of scattering before we reach full darkness.

#if PLOT
    #define RAD_MOD u_rad_plot
#else
    #define RAD_MOD u_rad_shad
#endif

uniform sampler2D    u_tex_side;
uniform sampler2D    u_tex_tops;
uniform vec4        u_cell_params;                                // cell params: xy = 1/cell_size, zw = 0.5/cell_size

uniform mat4        u_modelview_matrix;
uniform mat4        u_projection_matrix;

#if PLOT
    #if NUM_EXTRA_LIGHTS
    uniform    vec3        u_amb_dir[NUM_EXTRA_LIGHTS];
    uniform vec3        u_amb_rgb[NUM_EXTRA_LIGHTS];
    #endif

    #if USE_TEXTURED_SUN
    uniform sampler2D    u_diffuse_lookup;
    uniform sampler2D    u_ambient_lookup;
    uniform vec2        u_tex_the_scale;
    #endif
    uniform float        u_diffuse_gain;
    uniform float        u_ambient_gain;
    
    uniform vec4        u_strike_axis;
    uniform float        u_strike_axis_sqr_len;
    uniform vec3        u_strike_bottom;
    uniform    float        u_strike_brightness;
    uniform    vec2        u_gamma;
    uniform vec3        u_light_curve;

    uniform sampler2D    u_zbuf;    
    uniform vec4        u_clip_params;                            // clipping params in_start, in_end, out_start, out_end

    uniform vec3        u_direct_rgb;
    uniform vec3        u_ambient_rgb;

    uniform vec2        u_alpha_cut;
    
    varying vec2        sprite_st;                                // Sprite billboard vectors, for sphere projection from sprite

    #if SPIN == SPIN_MIX
        uniform    float    u_spin_mix;                            // Mix between textures
        varying vec2    v_texcoord1;
    #endif
    
    #if !KILL_PUFFS
        varying vec3        v_pos_eye;                        // Linear distance from cam (positive is in front of us) for per-pixel fog on 2-d clouds.
        varying    vec2        v_bot_top;                        // Contains (1,0) for bottoms and (0,1) for tops.
    #endif
#endif

    varying vec4        v_color;
    varying vec2        v_texcoord0;

#if CHECK_Z
    varying float    v_eye_pos_z_minus_rad;                        // This is the Z coordinate of the front of the puff if it is treated as a cylinder
    varying vec3    v_screen_pos;                                // This is really the clip coords of the pixel - needed
    varying    float    v_radius_recip;                                // 1.0 / puff rad, passed down to per-pixel
#endif

/************************************************************************************************************************************************************************
 ************************************************************************************************************************************************************************
 * VERTEX SHADER
 ************************************************************************************************************************************************************************
 ************************************************************************************************************************************************************************/

#if VSHADER

#if PLOT
float light_curve(float cos_theta)
{
    return pow(max(u_light_curve.x * cos_theta + u_light_curve.y,0.0),u_light_curve.z);
}
#endif

attribute vec4    a_vertex;
attribute vec2    a_texcoord0;    // uv map (within cell)
attribute vec3    a_normal   ;    // billboarding info
attribute vec4    a_texcoord1;    // xy is squish/alpha/rand/amb encode; zw and
attribute vec4    a_color       ;    // all four of these are direction vectors

attribute vec4    a_texcoord3;    // debug tinting! -- from immediate mode

void main()
{
    /************************************************************************************************************************************************************************
     * BILLBOARD CALCULATIONS
     ************************************************************************************************************************************************************************/

    // Note: eye pos becomes the 'look vector' for specular reflections; it is to the center of the puff.
    // In theory it might be better to point to the pixel IN the puff, but
    vec4 position_eye4 = u_modelview_matrix * a_vertex;

    //        a_texcoord1.x is squish + amb
    //        a_texcoord1.y is rand + alpha
    
    float    amb        =        mod(a_texcoord1.x,2.0);
    float    squish    =        (a_texcoord1.x - amb) / 512.0;
    float    nsquish =        1.0 - squish;
    float    alpha    =        mod(a_texcoord1.y,2.0);
    float    rand_rat=        (a_texcoord1.y - alpha) / 512.0;

#if PLOT

    float eye_dist = length(position_eye4.xyz);                                // Use radial distance, otherwise turning our heads changes LODs!
        
    vec3    eye_up_gimbal = (u_modelview_matrix * vec4(0,0,1,0)).xyz;    
    vec3    eye_up_normal = (u_modelview_matrix * vec4(0,1,0,0)).xyz;    
    vec3    eye_back = normalize(position_eye4.xyz);
    
    // Semi vectors billboarding above us, used to texture when in gimble lock.
    vec3    h_semi_g = normalize(cross(eye_back, eye_up_gimbal));
    vec3    v_semi_g = normalize(cross(h_semi_g, eye_back));

    // Semi vectors billboarding forward, the "normal" case".
    vec3    h_semi_n = normalize(cross(eye_back, eye_up_normal));
    vec3    v_semi_n = normalize(cross(h_semi_n, eye_back));

    // Real semi vectors used to form the physical billboard.
    vec3 h_semi = h_semi_n;
    vec3 v_semi = v_semi_n;
    
    // Puff squishing: squish_params tells how much of our vertical height we get to keep based on view angle.
    // To get a vector TO the puff in WORLD coordinates, we convert back from eye coordinates.
    // The ratio of up to length is sin theta, which is what we use to squish.  Smaller sin theta means more squished.
    // IMPORTANT that we calc this PER PUFF and not based on the GLOBAL camera theta.  At high FOV we want the puffs above
    // us flat and the puffs in front of us squished.  If we used the camera angle, all puffs would be the same.    
    vec3    to_puff_mv = position_eye4.xyz * mat3(u_modelview_matrix);
    float    look_rat = abs(to_puff_mv.y / length(to_puff_mv.xyz));    
    v_semi *= (squish + nsquish * look_rat);
    
    vec4    position_object = position_eye4;

    position_object.xyz += a_normal.x * h_semi * RAD_MOD * a_normal.z;
    position_object.xyz += a_normal.y * v_semi * RAD_MOD * a_normal.z;

#if CHECK_Z
    v_eye_pos_z_minus_rad = position_object.z - a_normal.z * RAD_MOD;
#endif

    gl_Position = u_projection_matrix * position_object;    
#else    
    vec4    position_object = position_eye4;
    position_object.xyz += vec3(a_normal.xy, 0) * RAD_MOD * a_normal.z;
    gl_Position = u_projection_matrix * position_object;    
#endif    

#if CHECK_Z
    v_screen_pos = gl_Position.xyw;
    v_radius_recip = 1.0 / (a_normal.z * RAD_MOD);
#endif

    v_texcoord0.st = a_texcoord0.st * u_cell_params.xy + (a_normal.xy) * u_cell_params.zw + u_cell_params.zw;


#if PLOT
    /************************************************************************************************************************************************************************
     * BACK FACE CULLING
     ************************************************************************************************************************************************************************/

    vec3 shading_pos = vec3(a_texcoord1.z,a_color.xz);
    vec3 shading_neg = vec3(a_texcoord1.w,a_color.yw);

    /************************************************************************************************************************************************************************
     * INTER-RESOLUTION FADING
     ************************************************************************************************************************************************************************/

    sprite_st = a_normal.xy;

    #if KILL_PUFFS
        float in_cut = smoothstep(u_clip_params.x, u_clip_params.y, eye_dist);
        float out_cut = 1.0 - smoothstep(u_clip_params.z, u_clip_params.w, eye_dist);
        float fade = in_cut * out_cut;
        
        float cutout_level = u_alpha_cut.y + u_alpha_cut.x * look_rat;
        cutout_level = 1.0 - cutout_level;
        float kill_rat = smoothstep(cutout_level - 0.1, cutout_level + 0.1, rand_rat);
        fade *= kill_rat;
        
        if(fade <= 0.0) gl_Position = vec4(0,0,0,0);
    #else
//        float in_cut = smoothstep(u_clip_params.x, u_clip_params.y, -position_eye4.z);
//        float out_cut = 1.0 - smoothstep(u_clip_params.z, u_clip_params.w, -position_eye4.z);
//        float fade = in_cut * out_cut;

        v_pos_eye = position_eye4.xyz;
        float fade = 1.0;

        v_bot_top = vec2(0.0,1.0);
        
        if(a_texcoord0.s < 0.0)
        {
            v_texcoord0.s += 2.0;
            v_bot_top=vec2(1.0,0.0);
        }
        
    #endif

    /************************************************************************************************************************************************************************
     * LIGHTNING
     ************************************************************************************************************************************************************************/
    
    float t = clamp(dot(u_strike_axis,vec4(a_vertex.xyz - u_strike_bottom,1.0)) / u_strike_axis_sqr_len,0.0,1.0);    
    float dist = distance(a_vertex.xyz, u_strike_bottom + t * u_strike_axis.xyz);    
//    float lightning = pow(u_strike_brightness / (dist*dist + 1.0), u_strike_gamma);
    float lightning = u_strike_brightness / (dist*dist + 1.0);                        // DO NOT gamma correct this - calc in LINEAR units, then go home happy!

    /************************************************************************************************************************************************************************
     * BLENDED BILLBOARDS
     ************************************************************************************************************************************************************************/

    #if SPIN==SPIN_MIX

        v_texcoord1.st = a_texcoord0.st * u_cell_params.xy +
                        vec2(
                            dot(a_normal.x * h_semi_n + a_normal.y * v_semi_n , h_semi_g),
                            dot(a_normal.x * h_semi_n + a_normal.y * v_semi_n , v_semi_g)
                        ) * u_cell_params.zw + u_cell_params.zw;
    #elif SPIN == SPIN_UP

        v_texcoord0.st = a_texcoord0.st * u_cell_params.xy +
                        vec2(
                            dot(a_normal.x * h_semi_n + a_normal.y * v_semi_n , h_semi_g),
                            dot(a_normal.x * h_semi_n + a_normal.y * v_semi_n , v_semi_g)
                        ) * u_cell_params.zw + u_cell_params.zw;
    
    #endif

    /************************************************************************************************************************************************************************
     * LIGHTING CALCS - PER PUFF TO KEEP FILL RATE HIGH
     ************************************************************************************************************************************************************************/

    vec3 eye_pos_norm = normalize(position_eye4.xyz);
    float hdot = max(0.0, dot(eye_pos_norm, gl_LightSource[0].position.xyz));
    hdot *= hdot;
    hdot *= hdot;
    hdot *= hdot;
    hdot *= hdot;
    hdot *= hdot;
    hdot *= hdot;
    hdot *= hdot;

    vec3 N = gl_LightSource[0].position.xyz * mat3(u_modelview_matrix);
//    vec3 I = vec3(0,0,-1) * mat3(u_modelview_matrix);
    
    #if USE_TEXTURED_SUN
        vec3 p_global = vec3(a_vertex.x, a_vertex.y + PLANET_RAD, a_vertex.z);
        float H = length(p_global) - PLANET_RAD;
        float sun_zenith = clamp(dot(normalize(p_global), N) * u_tex_the_scale.x + u_tex_the_scale.y,0.0,1.0);
        H = clamp(H * SCALE_CLOUD_TOPS, 0.0, 1.0);    // calibrate to 20 km cloud-ma-sphere
    #endif

    float shad = light_curve( N.x * shading_pos.x) +
                 light_curve( N.y * shading_pos.y) +
                 light_curve( N.z * shading_pos.z) +
                 light_curve(-N.x * shading_neg.x) +
                 light_curve(-N.y * shading_neg.y) +
                 light_curve(-N.z * shading_neg.z);
//    float shad = dot(max(N,0.0),shading_pos) + dot(max(-N,0.0),shading_neg);

    hdot *= shad;

//    shad = light_curve(shad);

    #if USE_TEXTURED_SUN
        vec3 sun_diffuse = pow(texture2D(u_diffuse_lookup, vec2(1.0 - sun_zenith, H)).rgb,u_gamma.xxx);
        vec3 sun_ambient = pow(texture2D(u_ambient_lookup, vec2(1.0 - sun_zenith, H)).rgb,u_gamma.xxx);
    #else
        vec3 sun_diffuse = pow(u_direct_rgb,u_gamma.xxx);
        vec3 sun_ambient = pow(u_ambient_rgb,u_gamma.xxx);
    #endif
    
    vec3 light_color =
            (hdot * u_spec_gain + u_diffuse_gain) * sun_diffuse * shad +
                                  u_ambient_gain  * sun_ambient * amb;
            
    #if NUM_EXTRA_LIGHTS
        int i;
        for(i = 0; i < NUM_EXTRA_LIGHTS; ++i)
        {
            vec3    d = u_amb_dir * mat3(u_modelview_matrix);
            float    s = dot(max(d,0.0),shading_pos) + dot(max(-d,0.0),shading_neg);
            light_color += (s * u_amb_rgb);
        }

    #endif            

//    #if HDR
//        v_color.rgb = a_texcoord3.rgb * max(vec3(lightning), light_color);
//    #else
        v_color.rgb = a_texcoord3.rgb * pow(max(vec3(lightning), light_color),u_gamma.yyy);
//    #endif    

    #if KILL_PUFFS
        v_color.a = fade * alpha; // u_alpha_plot;// * a_texcoord1.y;
    #else
        v_color.a = fade * alpha; // u_alpha_plot * a_texcoord1.y;
    #endif

#else
    // Shadow case
    v_color = vec4(1,1,1,u_alpha_shad);
#endif    

    #if HDR && EXPENSIVE_TONE
        calc_light_meter();
    #endif

#if HDR && !EXPENSIVE_TONE
    vshader_tone_map(v_color.rgb);
#endif

}

#endif

/************************************************************************************************************************************************************************
 ************************************************************************************************************************************************************************
 * FRAGMENT SHADER
 ************************************************************************************************************************************************************************
 ************************************************************************************************************************************************************************/

#if FSHADER

void main()
{    
    /************************************************************************************************************************************************************************
     * TEXTURE SAMPLE
     ************************************************************************************************************************************************************************/

#if PLOT && SPIN==SPIN_MIX
    vec4 texel = mix(texture2D(u_tex_side, v_texcoord0.st),texture2D(u_tex_tops, v_texcoord1.st),u_spin_mix);
    if(length(sprite_st) > 1.0)
        discard;
#elif PLOT && SPIN==SPIN_UP
    vec4 texel = texture2D(u_tex_tops, v_texcoord0.st);
    if(length(sprite_st) > 1.0)
        discard;
#elif PLOT                                
    vec4 texel = texture2D(u_tex_side, v_texcoord0.st);
#else
    vec4 texel = texture2D(u_tex_tops, v_texcoord0.st);
#endif    

    // Ben says: X-Plane _only_ uses alpha data to color the pixel, so using a full 4-channel texel in theory wastes
    // VRAM, GPU bus bandwidth, and ALU ops.
    // But here's the thing: I've tested the hell out of this on a wide range of hardware and at no point do we seem to
    // pay anything for this color tint.  Pretty much all machines have enough ALU and texture bandwidth relative to
    // fully blended raster ops that the tint is free.
    //
    // Since we shipped tint in 10.25, let's NOT kill it now.
    gl_FragColor = v_color * texel;

#if COLOR_SPIN_MIX
#if PLOT && SPIN==SPIN_MIX
    gl_FragColor.r *= u_spin_mix;
#elif PLOT && SPIN==SPIN_UP
    gl_FragColor.rg = vec2(0);
#elif PLOT                                
    gl_FragColor.b = 0;
#endif    
#endif

    /************************************************************************************************************************************************************************
     * Z CHECK FOR SOFT HDR CLOUDS
     ************************************************************************************************************************************************************************/

#if CHECK_Z

    // Ben says: I am not making this up: if I do an early discard based on a z mismatch,
    // it makes the shader 5% slower.  (It does eliminate a tiny number of pixels that will be alpha zero
    // that the early-Z misses.)  Perhaps the cost of the conditional logic is worse than the few pixels we
    // kill.
    
    // Screen ratio MUST be computed per fragment - varying interp isn't per pixel accurate - a depth mismatch
    // causes lines of clouds being forced out at the edge of mountains - very bad!
    vec2 screen_rat = (v_screen_pos.xy / v_screen_pos.z) * 0.5 + vec2(0.5);

    vec4 gbuf = texture2D(u_zbuf, screen_rat.xy);
    float depth = -1024.0 * gbuf.y;        

    float delta = v_eye_pos_z_minus_rad - depth;
    float z_fade = clamp(delta * v_radius_recip,0.0,1.0);
    if(depth == 0.0) z_fade = 1.0;                        // This handles the case where the g-buffer is uninited - it contains "0" as a flag value.
    gl_FragColor.a *= z_fade;

//    gl_FragColor.r = z_fade;
#endif

#if PLOT && !KILL_PUFFS
    float dist = length(v_pos_eye);
    float in_cut = smoothstep(u_clip_params.x, u_clip_params.y, dist);
    float out_cut = 1.0 - smoothstep(u_clip_params.z, u_clip_params.w, dist);
    gl_FragColor.a *= in_cut * out_cut;
#endif

#if HDR && EXPENSIVE_TONE
    tone_map(gl_FragColor.rgb);
#endif


#if DEBUG_MODE == 1 && PLOT
    gl_FragColor = vec4(1.0 / 10.0, 1.0 / 100.0, 1.0 / 255.0,1.0);
#endif
#if DEBUG_MODE == 2 && PLOT
    if(length(sprite_st) > 1.0)
        discard;
    gl_FragColor = vec4(sprite_st,1.0,0.5);
#endif
}

#endif
 

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!