#version 330 core layout(location = 0) in vec4 pos; layout(location = 2) in vec4 vertex_color; layout(location = 3) in vec4 multitexcoord0; layout(location = 10) in vec4 usrAttr1; layout(location = 11) in vec4 usrAttr2; out vec2 texcoord; out vec4 cloud_color; uniform float range; uniform float detail_range; uniform mat4 osg_ModelViewMatrix; uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ViewMatrixInverse; uniform vec3 fg_SunDirectionWorld; // sun.glsl vec3 get_sun_radiance(vec3 p); void cloud_common_vert(out vec4 vs_pos, out vec4 ws_pos) { float alpha_factor = usrAttr1.r; float shade_factor = usrAttr1.g; float cloud_height = usrAttr1.b; float bottom_factor = usrAttr2.r; float middle_factor = usrAttr2.g; float top_factor = usrAttr2.b; texcoord = multitexcoord0.st; // XXX: Should be sent as an uniform mat4 inverseModelViewMatrix = inverse(osg_ModelViewMatrix); vec4 ep = inverseModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0); vec4 l = inverseModelViewMatrix * vec4(0.0, 0.0, 1.0, 1.0); vec3 u = normalize(ep.xyz - l.xyz); // Find a rotation matrix that rotates 1,0,0 into u. u, r and w are // the columns of that matrix. vec3 absu = abs(u); vec3 r = normalize(vec3(-u.y, u.x, 0.0)); vec3 w = cross(u, r); // Do the matrix multiplication by [ u r w pos]. Assume no // scaling in the homogeneous component of pos. vec4 final_pos = vec4(0.0, 0.0, 0.0, 1.0); final_pos.xyz = pos.x * u; final_pos.xyz += pos.y * r; final_pos.xyz += pos.z * w; // Apply Z scaling to allow sprites to be squashed in the z-axis final_pos.z = final_pos.z * vertex_color.w; // Now shift the sprite to the correct position in the cloud. final_pos.xyz += vertex_color.xyz; // Determine the position - used for fog and shading calculations float fogCoord = length(vec3(osg_ModelViewMatrix * vec4(vertex_color.xyz, 1.0))); float center_dist = length(vec3(osg_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0))); if ((fogCoord > detail_range) && (fogCoord > center_dist) && (shade_factor < 0.7)) { // More than detail_range away, so discard all sprites on opposite side of // cloud center by shifting them beyond the view fustrum gl_Position = vec4(0.0, 0.0, 10.0, 1.0); cloud_color = vec4(0.0); } else { gl_Position = osg_ModelViewProjectionMatrix * final_pos; vs_pos = osg_ModelViewMatrix * final_pos; ws_pos = osg_ViewMatrixInverse * vs_pos; // Determine a lighting normal based on the vertex position from the // center of the cloud, so that sprite on the opposite side of the cloud // to the sun are darker. vec3 n = normalize(vec3(osg_ViewMatrixInverse * osg_ModelViewMatrix * vec4(-final_pos.xyz, 0.0))); float NdotL = dot(-fg_SunDirectionWorld, n); // Determine the shading of the vertex. We shade it based on it's position // in the cloud relative to the sun, and it's vertical position in the cloud. float shade = mix(shade_factor, top_factor, smoothstep(-0.3, 0.3, NdotL)); if (final_pos.z < 0.5 * cloud_height) { shade = min(shade, mix(bottom_factor, middle_factor, final_pos.z * 2.0 / cloud_height)); } else { shade = min(shade, mix(middle_factor, top_factor, final_pos.z * 2.0 / cloud_height - 1.0)); } cloud_color.rgb = shade * get_sun_radiance(ws_pos.xyz); if ((fogCoord > (0.9 * detail_range)) && (fogCoord > center_dist) && (shade_factor < 0.7)) { // cloudlet is almost at the detail range, so fade it out. cloud_color.a = 1.0 - smoothstep(0.9 * detail_range, detail_range, fogCoord); } else { // As we get within 100m of the sprite, it is faded out. // Equally at large distances it also fades out. cloud_color.a = min(smoothstep(10.0, 100.0, fogCoord), 1.0 - smoothstep(0.9 * range, range, fogCoord)); } cloud_color.a *= alpha_factor; } }