Sign in to follow this  
Followers 0
Enalis

Atmospheric Shader

0 posts in this topic

I started working on an atmospheric shader. I don't want it to look exactly like the earth everytime, so I looked for more configurable scattering algorithms. I came across this [url="http://petrocket.blogspot.com/2010/04/atmosphere-shader-update-and-treegrass.html"]http://petrocket.blo...-treegrass.html[/url]. This looks more like what I was looking for so I converted it to glsl and tried to convert it to world space calculations as this is done in my deferred renderer which all happens in world space. The only issue I'm thinking is that I get odd results when I'm less than the distance of the light away from the planet. The shader seems to think I'm inside the atmosphere or something already. It looks great far away, and great inside the atmosphere, but just terrible in the middle ground.
I'll post screenshots and shaders for analysis...

Good far away screenshot!
[img]http://www.palodequeso.net/good_atmosphere.png[/img]
Good Inside Atmosphere Screenshot
[img]http://www.palodequeso.net/good_atmosphere2.png[/img]

Bad Middle Ground Screenshot:
[img]http://www.palodequeso.net/bad_atmosphere.png[/img]

Here is my shader, remember, all incoming positions, normals, etc, are in object space, and I output to my deferred renderer in world space. In the fragment you'll notice I'm using MRTs. I only write to the last one in the case of a translucent forward shaded object like this. Any thoughts on this would surely be appreciated!

Vertex Shader
[CODE]
#version 130
uniform mat4 projection_matrix;
uniform mat4 model_matrix;
uniform mat4 view_matrix;
uniform mat4 normal_matrix;
in vec4 vertex_position;
in vec4 vertex_normal;
in vec4 vertex_texcoord;
in vec4 vertex_binormal;
in vec4 vertex_bitangent;
in vec4 vertex_weights;
in ivec4 vertex_weight_indices;
smooth out vec3 object_position;
smooth out vec3 world_position;
smooth out vec3 normal;
void main() {
object_position = vertex_position.xyz;
world_position = (model_matrix * vertex_position).xyz;
normal = normalize(object_position);
gl_Position = projection_matrix * view_matrix * model_matrix * vertex_position;
}
[/CODE]

Fragment Shader
[CODE]
#version 130
smooth in vec3 object_position;
smooth in vec3 world_position;
smooth in vec3 normal;
uniform vec3 camera_position;
uniform float material_specularity;
uniform vec4 material_color;
uniform int normal_mapping_enabled;
uniform int receives_lighting;
uniform sampler2D decal_map;
uniform vec4 light_position;
uniform float inner_radius;
uniform float outer_radius;
out vec4 fragment0;
out vec4 fragment1;
out vec4 fragment2;
out vec4 fragment3;
void main() {
// constants
float stretch_amount = 0.001;
float exposure = 0.5;
float g = -0.990;
float g2 = g * g;
float tweak_amount = 0.025;
float outer_radius2 = outer_radius * outer_radius;
float camera_height = length(camera_position);
vec3 camera_to_position = world_position - camera_position;
float far_distance = length(camera_to_position);
vec3 light_direction = normalize(light_position.xyz - camera_position);
vec3 ray_direction = camera_to_position / far_distance;
float camera_height2 = camera_height * camera_height;
float B = 2.0 * dot(camera_position.xyz, ray_direction);
float C = camera_height2 - outer_radius2;
float det = max(00, B*B - 4.0 * C);
float near_distance = 0.5 * (-B - sqrt(det));
vec3 near_position = camera_position.xyz + (ray_direction * near_distance);
vec3 near_normal = normalize(near_position);
float lc = dot(light_direction, camera_position / camera_height);
float ln = dot(light_direction, normal);
float lnn = dot(light_direction, near_normal);
float altitude = camera_height - inner_radius;
float horizon_distance = sqrt((altitude * altitude) + (2.0 * inner_radius * altitude));
float max_dot = horizon_distance / camera_height;
altitude = max(0.0, camera_height - outer_radius);
horizon_distance = sqrt((altitude * altitude) + (2.0 * outer_radius * altitude));
float min_dot = max(tweak_amount, horizon_distance / camera_height);
float min_dot2 = ((camera_height - inner_radius) * (1.0 / outer_radius - inner_radius)) - (1.0 - tweak_amount);
min_dot = min(min_dot, min_dot2);
float pos_dot = dot(camera_to_position / far_distance, -camera_position.xyz / camera_height) - min_dot;
float height = pos_dot * (1.0 / (max_dot - min_dot));
ln = max(0.0, ln + stretch_amount);
lnn = max(0.0, lnn + stretch_amount);
float brightness = clamp(ln + (lnn * lc), 0.0, 1.0);
vec2 uv = vec2(brightness * clamp(lc + 1.0 + stretch_amount, 0.0, 1.0), height);
height -= min(0.0, min_dot2 + (ln * min_dot2));
float alpha = height * brightness;
vec3 negative_ray_dir = -ray_direction;
vec3 new_light_direction = normalize(light_position.xyz - world_position.xyz);
vec4 diffuse = texture(decal_map, uv);
vec4 diffuse2 = texture(decal_map, vec2(min(0.5, uv.x), 1.0));
float cosine = dot(normalize(new_light_direction.xyz), normalize(negative_ray_dir));
float cosine2 = cosine * cosine;
vec4 diffuse_color = diffuse * alpha;
float mie_phase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + cosine2) /(1.0 + g2 - 2.0 * g * cosine);
vec4 mie_color = diffuse2 * mie_phase * alpha;
vec4 color_out = vec4(1.0) - exp((diffuse_color * (1.0 + uv.y) + mie_color) * -exposure);
if (color_out.a < 0.0001) {
discard;
}
fragment0 = vec4(0.0, 0.0, 0.0, color_out.a);
fragment1 = vec4(0.0, 0.0, 0.0, color_out.a);
fragment2 = vec4(0.0, 0.0, 0.0, color_out.a);
fragment3 = vec4(color_out);
}
[/CODE]
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0