summaryrefslogtreecommitdiffstats
path: root/libdimension
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2011-05-20 18:59:18 -0600
committerTavian Barnes <tavianator@gmail.com>2011-05-20 18:59:18 -0600
commit18b89c6edc29a009b1419e6d34bc3eef2dd911b9 (patch)
tree02f36651220fbd0821c94d6c13848bd9beb59098 /libdimension
parent250b980002419746fc099c7633b9600a15afb1c6 (diff)
downloaddimension-18b89c6edc29a009b1419e6d34bc3eef2dd911b9.tar.xz
Switch to Blender model of filtered transparency.
Diffstat (limited to 'libdimension')
-rw-r--r--libdimension/ambient.c2
-rw-r--r--libdimension/color.c67
-rw-r--r--libdimension/dimension/color.h10
-rw-r--r--libdimension/gl.c18
-rw-r--r--libdimension/png.c14
-rw-r--r--libdimension/raytrace.c9
-rw-r--r--libdimension/tests/render.c6
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);