diff options
author | Tavian Barnes <tavianator@gmail.com> | 2011-05-20 18:59:18 -0600 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2011-05-20 18:59:18 -0600 |
commit | 18b89c6edc29a009b1419e6d34bc3eef2dd911b9 (patch) | |
tree | 02f36651220fbd0821c94d6c13848bd9beb59098 /libdimension | |
parent | 250b980002419746fc099c7633b9600a15afb1c6 (diff) | |
download | dimension-18b89c6edc29a009b1419e6d34bc3eef2dd911b9.tar.xz |
Switch to Blender model of filtered transparency.
Diffstat (limited to 'libdimension')
-rw-r--r-- | libdimension/ambient.c | 2 | ||||
-rw-r--r-- | libdimension/color.c | 67 | ||||
-rw-r--r-- | libdimension/dimension/color.h | 10 | ||||
-rw-r--r-- | libdimension/gl.c | 18 | ||||
-rw-r--r-- | libdimension/png.c | 14 | ||||
-rw-r--r-- | libdimension/raytrace.c | 9 | ||||
-rw-r--r-- | libdimension/tests/render.c | 6 |
7 files changed, 71 insertions, 55 deletions
diff --git a/libdimension/ambient.c b/libdimension/ambient.c index 45dca3f..180889b 100644 --- a/libdimension/ambient.c +++ b/libdimension/ambient.c @@ -33,8 +33,8 @@ dmnsn_ambient_finish_fn(const dmnsn_finish *finish, dmnsn_color pigment) { dmnsn_color *ambient = finish->ptr; dmnsn_color ret = dmnsn_color_illuminate(*ambient, pigment); - ret.filter = 0.0; ret.trans = 0.0; + ret.filter = 0.0; return ret; } diff --git a/libdimension/color.c b/libdimension/color.c index 24a4574..07d8ed8 100644 --- a/libdimension/color.c +++ b/libdimension/color.c @@ -30,71 +30,71 @@ const dmnsn_color dmnsn_black = { .R = 0.0, .G = 0.0, .B = 0.0, + .trans = 0.0, .filter = 0.0, - .trans = 0.0 }; const dmnsn_color dmnsn_white = { .R = 1.0, .G = 1.0, .B = 1.0, + .trans = 0.0, .filter = 0.0, - .trans = 0.0 }; const dmnsn_color dmnsn_clear = { .R = 0.0, .G = 0.0, .B = 0.0, + .trans = 1.0, .filter = 0.0, - .trans = 1.0 }; const dmnsn_color dmnsn_red = { .R = 1.0, .G = 0.0, .B = 0.0, + .trans = 0.0, .filter = 0.0, - .trans = 0.0 }; const dmnsn_color dmnsn_green = { .R = 0.0, .G = 1.0, .B = 0.0, + .trans = 0.0, .filter = 0.0, - .trans = 0.0 }; const dmnsn_color dmnsn_blue = { .R = 0.0, .G = 0.0, .B = 1.0, + .trans = 0.0, .filter = 0.0, - .trans = 0.0 }; const dmnsn_color dmnsn_magenta = { .R = 1.0, .G = 0.0, .B = 1.0, + .trans = 0.0, .filter = 0.0, - .trans = 0.0 }; const dmnsn_color dmnsn_orange = { .R = 1.0, .G = 0.5, .B = 0.0, + .trans = 0.0, .filter = 0.0, - .trans = 0.0 }; const dmnsn_color dmnsn_yellow = { .R = 1.0, .G = 1.0, .B = 0.0, + .trans = 0.0, .filter = 0.0, - .trans = 0.0 }; const dmnsn_color dmnsn_cyan = { .R = 0.0, .G = 1.0, .B = 1.0, .filter = 0.0, - .trans = 0.0 + .trans = 0.0, }; /* Greyscale color intensity */ @@ -111,11 +111,19 @@ dmnsn_color_add(dmnsn_color c1, dmnsn_color c2) { dmnsn_color ret = dmnsn_new_color(c1.R + c2.R, c1.G + c2.G, c1.B + c2.B); + /* Switch back into absolute filter and transmittance space */ double n1 = dmnsn_color_intensity(c1), n2 = dmnsn_color_intensity(c2); - if (n1 + n2 != 0.0) { - ret.filter = (n1*c1.filter + n2*c2.filter)/(n1 + n2); - } - ret.trans = c1.trans + c2.trans; + double f1 = c1.filter*c1.trans, f2 = c2.filter*c2.trans; + double t1 = c1.trans - f1, t2 = c2.trans - f2; + double f = 0.0; + if (n1 + n2 >= dmnsn_epsilon) + f = (n1*f1 + n2*f2)/(n1 + n2); + double t = t1 + t2; + + /* Switch back */ + ret.trans = f + t; + if (ret.trans >= dmnsn_epsilon) + ret.filter = f/ret.trans; return ret; } @@ -138,8 +146,8 @@ dmnsn_color_gradient(dmnsn_color c1, dmnsn_color c2, double n) n*(c2.R - c1.R) + c1.R, n*(c2.G - c1.G) + c1.G, n*(c2.B - c1.B) + c1.B, - n*(c2.filter - c1.filter) + c1.filter, - n*(c2.trans - c1.trans) + c1.trans + n*(c2.trans - c1.trans) + c1.trans, + n*(c2.filter - c1.filter) + c1.filter ); } @@ -147,15 +155,28 @@ dmnsn_color_gradient(dmnsn_color c1, dmnsn_color c2, double n) dmnsn_color dmnsn_filter_light(dmnsn_color light, dmnsn_color filter) { - dmnsn_color transmitted = dmnsn_color_mul(filter.trans, light); + dmnsn_color transmitted = dmnsn_color_mul( + (1.0 - filter.filter)*filter.trans, + light + ); dmnsn_color filtered = dmnsn_color_mul( - filter.filter, + filter.filter*filter.trans, dmnsn_color_illuminate(filter, light) ); dmnsn_color ret = dmnsn_color_add(transmitted, filtered); - ret.filter = light.filter*dmnsn_color_intensity(filtered) - + filter.filter*light.trans + filter.trans*light.filter; - ret.trans = filter.trans*light.trans; + + /* Switch back into absolute filter and transmittance space */ + double lf = light.filter*light.trans, ff = filter.filter*filter.trans; + double lt = light.trans - lf, ft = filter.trans - ff; + double f = lf*(dmnsn_color_intensity(filtered) + ft) + lt*ff; + double t = ft*lt; + + /* Switch back */ + ret.trans = f + t; + ret.filter = 0.0; + if (ret.trans >= dmnsn_epsilon) + ret.filter = f/ret.trans; + return ret; } @@ -164,11 +185,11 @@ dmnsn_color dmnsn_apply_translucency(dmnsn_color filtered, dmnsn_color filter) { dmnsn_color ret = dmnsn_color_add( - dmnsn_color_mul(1.0 - (filter.filter + filter.trans), filter), + dmnsn_color_mul(1.0 - filter.trans, filter), filtered ); - ret.filter = filtered.filter; ret.trans = filtered.trans; + ret.filter = filtered.filter; return ret; } diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h index 504ec47..be5dc3d 100644 --- a/libdimension/dimension/color.h +++ b/libdimension/dimension/color.h @@ -31,10 +31,8 @@ typedef struct { double G; /**< sRGB green value. */ double B; /**< sRGB blue value. */ - /** Filtered transparency. */ - double filter; - /** Unfiltered transparency; <tt>filter + trans</tt> should be <= 1. */ - double trans; + double trans; /**< Translucency. */ + double filter; /**< Degree of filtering. */ } dmnsn_color; /* Standard colors */ @@ -61,9 +59,9 @@ dmnsn_new_color(double R, double G, double B) /** Construct a new color with transparent components. */ DMNSN_INLINE dmnsn_color -dmnsn_new_color5(double R, double G, double B, double filter, double trans) +dmnsn_new_color5(double R, double G, double B, double trans, double filter) { - dmnsn_color ret = { R, G, B, filter, trans }; + dmnsn_color ret = { R, G, B, trans, filter }; return ret; } diff --git a/libdimension/gl.c b/libdimension/gl.c index 587038f..7fd3cb9 100644 --- a/libdimension/gl.c +++ b/libdimension/gl.c @@ -110,13 +110,12 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas) pixel[2] = color.B*UINT16_MAX; } - double alpha = dmnsn_color_intensity(color)*color.filter + color.trans; - if (alpha <= 0.0) { + if (color.trans <= 0.0) { pixel[3] = 0; - } else if (alpha >= 1.0) { + } else if (color.trans >= 1.0) { pixel[3] = UINT16_MAX; } else { - pixel[3] = alpha*UINT16_MAX; + pixel[3] = color.trans*UINT16_MAX; } } } @@ -152,8 +151,8 @@ dmnsn_gl_read_canvas(size_t x0, size_t y0, dmnsn_color color = dmnsn_new_color5((double)pixel[0]/UINT16_MAX, (double)pixel[1]/UINT16_MAX, (double)pixel[2]/UINT16_MAX, - 0.0, - (double)pixel[3]/UINT16_MAX); + (double)pixel[3]/UINT16_MAX, + 0.0); dmnsn_set_pixel(canvas, x, y, color); } } @@ -196,12 +195,11 @@ dmnsn_gl_optimizer_fn(const dmnsn_canvas *canvas, pixel[2] = color.B*UINT16_MAX; } - double alpha = dmnsn_color_intensity(color)*color.filter + color.trans; - if (alpha <= 0.0) { + if (color.trans <= 0.0) { pixel[3] = 0; - } else if (alpha >= 1.0) { + } else if (color.trans >= 1.0) { pixel[3] = UINT16_MAX; } else { - pixel[3] = alpha*UINT16_MAX; + pixel[3] = color.trans*UINT16_MAX; } } diff --git a/libdimension/png.c b/libdimension/png.c index d80ecc0..3920e7e 100644 --- a/libdimension/png.c +++ b/libdimension/png.c @@ -92,13 +92,12 @@ dmnsn_png_optimizer_fn(const dmnsn_canvas *canvas, pixel[2] = color.B*UINT16_MAX; } - double alpha = dmnsn_color_intensity(color)*color.filter + color.trans; - if (alpha <= 0.0) { + if (color.trans <= 0.0) { pixel[3] = 0; - } else if (alpha >= 1.0) { + } else if (color.trans >= 1.0) { pixel[3] = UINT16_MAX; } else { - pixel[3] = alpha*UINT16_MAX; + pixel[3] = color.trans*UINT16_MAX; } } @@ -299,13 +298,12 @@ dmnsn_png_write_canvas_thread(void *ptr) row[4*x + 2] = color.B*UINT16_MAX; } - double alpha = color.filter + color.trans; - if (alpha <= 0.0) { + if (color.trans <= 0.0) { row[4*x + 3] = 0; - } else if (alpha >= 1.0) { + } else if (color.trans >= 1.0) { row[4*x + 3] = UINT16_MAX; } else { - row[4*x + 3] = alpha*UINT16_MAX; + row[4*x + 3] = color.trans*UINT16_MAX; } } diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c index 87e0b8f..deb0080 100644 --- a/libdimension/raytrace.c +++ b/libdimension/raytrace.c @@ -273,7 +273,7 @@ dmnsn_raytrace_light_ray(const dmnsn_raytrace_state *state, dmnsn_raytrace_pigment(&shadow_state); if ((state->scene->quality & DMNSN_RENDER_TRANSLUCENCY) - && (shadow_state.pigment.filter || shadow_state.pigment.trans)) + && shadow_state.pigment.trans >= dmnsn_epsilon) { color = dmnsn_filter_light(color, shadow_state.pigment); shadow_ray.x0 = dmnsn_line_point(shadow_ray, shadow_caster.t); @@ -328,7 +328,8 @@ dmnsn_raytrace_lighting(dmnsn_raytrace_state *state) state->additional = dmnsn_color_add(specular, state->additional); } else { state->diffuse = state->pigment; - state->diffuse.filter = state->diffuse.trans = 0.0; + state->diffuse.trans = 0.0; + state->diffuse.filter = 0.0; } } } @@ -355,8 +356,8 @@ dmnsn_raytrace_reflection(const dmnsn_raytrace_state *state) state, finish, reflection_fn, dmnsn_black, rec, state->pigment, state->reflected, state->intersection->normal ); - reflected.filter = 0.0; reflected.trans = 0.0; + reflected.filter = 0.0; } return reflected; @@ -366,7 +367,7 @@ dmnsn_raytrace_reflection(const dmnsn_raytrace_state *state) static void dmnsn_raytrace_translucency(dmnsn_raytrace_state *state) { - if (state->pigment.filter || state->pigment.trans) { + if (state->pigment.trans >= dmnsn_epsilon) { dmnsn_line trans_ray = dmnsn_new_line(state->r, state->intersection->ray.n); trans_ray = dmnsn_line_add_epsilon(trans_ray); diff --git a/libdimension/tests/render.c b/libdimension/tests/render.c index f35f5bb..a84ba63 100644 --- a/libdimension/tests/render.c +++ b/libdimension/tests/render.c @@ -73,7 +73,7 @@ dmnsn_new_test_scene(void) dmnsn_pattern *sky_gradient = dmnsn_new_gradient_pattern(dmnsn_y); dmnsn_map *sky_gradient_color_map = dmnsn_new_color_map(); dmnsn_add_map_entry(sky_gradient_color_map, 0.0, &dmnsn_orange); - dmnsn_color background = dmnsn_new_color5(0.0, 0.1, 0.2, 0.1, 0.0); + dmnsn_color background = dmnsn_new_color5(0.0, 0.1, 0.2, 0.1, 1.0); dmnsn_add_map_entry(sky_gradient_color_map, 0.35, &background); dmnsn_pigment *sky_pigment = dmnsn_new_color_map_pigment(sky_gradient, sky_gradient_color_map); @@ -95,8 +95,8 @@ dmnsn_new_test_scene(void) cube->texture = dmnsn_new_texture(); dmnsn_color cube_color = dmnsn_blue; - cube_color.filter = 0.25; - cube_color.trans = 0.5; + cube_color.trans = 0.75; + cube_color.filter = 1.0/3.0; cube->texture->pigment = dmnsn_new_solid_pigment(cube_color); dmnsn_color reflect = dmnsn_color_mul(0.5, dmnsn_white); |