summaryrefslogtreecommitdiffstats
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
parent250b980002419746fc099c7633b9600a15afb1c6 (diff)
downloaddimension-18b89c6edc29a009b1419e6d34bc3eef2dd911b9.tar.xz
Switch to Blender model of filtered transparency.
-rw-r--r--libdimension-python/Color.c46
-rwxr-xr-xlibdimension-python/tests/color.py10
-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
9 files changed, 99 insertions, 83 deletions
diff --git a/libdimension-python/Color.c b/libdimension-python/Color.c
index ae8de2f..c147603 100644
--- a/libdimension-python/Color.c
+++ b/libdimension-python/Color.c
@@ -23,12 +23,12 @@
bool
dmnsn_py_Color_args(dmnsn_color *c, PyObject *args, PyObject *kwds)
{
- c->filter = 0.0;
c->trans = 0.0;
+ c->filter = 0.0;
- static char *kwlist[] = { "red", "green", "blue", "filter", "trans", NULL };
+ static char *kwlist[] = { "red", "green", "blue", "trans", "filter", NULL };
if (PyArg_ParseTupleAndKeywords(args, kwds, "ddd|dd", kwlist,
- &c->R, &c->G, &c->B, &c->filter, &c->trans)) {
+ &c->R, &c->G, &c->B, &c->trans, &c->filter)) {
return true;
} else {
if (kwds)
@@ -57,12 +57,12 @@ dmnsn_py_Color_repr(dmnsn_py_Color *self)
PyObject *R = PyFloat_FromDouble(self->c.R);
PyObject *G = PyFloat_FromDouble(self->c.G);
PyObject *B = PyFloat_FromDouble(self->c.B);
- PyObject *filter = PyFloat_FromDouble(self->c.filter);
PyObject *trans = PyFloat_FromDouble(self->c.trans);
+ PyObject *filter = PyFloat_FromDouble(self->c.filter);
- if (!R || !G || !B || !filter || !trans) {
- Py_XDECREF(trans);
+ if (!R || !G || !B || !trans || !filter) {
Py_XDECREF(filter);
+ Py_XDECREF(trans);
Py_XDECREF(B);
Py_XDECREF(G);
Py_XDECREF(R);
@@ -70,9 +70,9 @@ dmnsn_py_Color_repr(dmnsn_py_Color *self)
}
PyObject *repr = PyUnicode_FromFormat("dimension.Color(%R, %R, %R, %R, %R)",
- R, G, B, filter, trans);
- Py_XDECREF(trans);
+ R, G, B, trans, filter);
Py_XDECREF(filter);
+ Py_XDECREF(trans);
Py_XDECREF(B);
Py_XDECREF(G);
Py_XDECREF(R);
@@ -85,12 +85,12 @@ dmnsn_py_Color_str(dmnsn_py_Color *self)
PyObject *R = PyFloat_FromDouble(self->c.R);
PyObject *G = PyFloat_FromDouble(self->c.G);
PyObject *B = PyFloat_FromDouble(self->c.B);
- PyObject *filter = PyFloat_FromDouble(self->c.filter);
PyObject *trans = PyFloat_FromDouble(self->c.trans);
+ PyObject *filter = PyFloat_FromDouble(self->c.filter);
- if (!R || !G || !B || !filter || !trans) {
- Py_XDECREF(trans);
+ if (!R || !G || !B || !trans || !filter) {
Py_XDECREF(filter);
+ Py_XDECREF(trans);
Py_XDECREF(B);
Py_XDECREF(G);
Py_XDECREF(R);
@@ -103,11 +103,11 @@ dmnsn_py_Color_str(dmnsn_py_Color *self)
R, G, B);
} else {
str = PyUnicode_FromFormat("<red = %S, green = %S, blue = %S,"
- " filter = %S, trans = %S>",
- R, G, B, filter, trans);
+ " trans = %S, filter = %S>",
+ R, G, B, trans, filter);
}
- Py_XDECREF(trans);
Py_XDECREF(filter);
+ Py_XDECREF(trans);
Py_XDECREF(B);
Py_XDECREF(G);
Py_XDECREF(R);
@@ -131,11 +131,11 @@ dmnsn_py_Color_richcompare(PyObject *lhs, PyObject *rhs, int op)
double rdiff = (clhs->c.R - crhs->c.R)*(clhs->c.R - crhs->c.R);
double gdiff = (clhs->c.G - crhs->c.G)*(clhs->c.G - crhs->c.G);
double bdiff = (clhs->c.B - crhs->c.B)*(clhs->c.B - crhs->c.B);
- double fdiff = (clhs->c.filter - crhs->c.filter)
- * (clhs->c.filter - crhs->c.filter);
double tdiff = (clhs->c.trans - crhs->c.trans)
* (clhs->c.trans - crhs->c.trans);
- bool equal = sqrt(rdiff + gdiff + bdiff + fdiff + tdiff) < dmnsn_epsilon;
+ double fdiff = (clhs->c.filter - crhs->c.filter)
+ * (clhs->c.filter - crhs->c.filter);
+ bool equal = sqrt(rdiff + gdiff + bdiff + tdiff + fdiff) < dmnsn_epsilon;
PyObject *result;
switch (op) {
@@ -235,15 +235,15 @@ dmnsn_py_Color_get_blue(dmnsn_py_Color *self, void *closure)
}
static PyObject *
-dmnsn_py_Color_get_filter(dmnsn_py_Color *self, void *closure)
+dmnsn_py_Color_get_trans(dmnsn_py_Color *self, void *closure)
{
- return PyFloat_FromDouble(self->c.filter);
+ return PyFloat_FromDouble(self->c.trans);
}
static PyObject *
-dmnsn_py_Color_get_trans(dmnsn_py_Color *self, void *closure)
+dmnsn_py_Color_get_filter(dmnsn_py_Color *self, void *closure)
{
- return PyFloat_FromDouble(self->c.trans);
+ return PyFloat_FromDouble(self->c.filter);
}
static PyGetSetDef dmnsn_py_Color_getsetters[] = {
@@ -253,10 +253,10 @@ static PyGetSetDef dmnsn_py_Color_getsetters[] = {
"Green componant", NULL },
{ "blue", (getter)dmnsn_py_Color_get_blue, NULL,
"Blue componant", NULL },
- { "filter", (getter)dmnsn_py_Color_get_filter, NULL,
- "Filter component", NULL },
{ "trans", (getter)dmnsn_py_Color_get_trans, NULL,
"Transmittance component", NULL },
+ { "filter", (getter)dmnsn_py_Color_get_filter, NULL,
+ "Filter component", NULL },
{ NULL }
};
diff --git a/libdimension-python/tests/color.py b/libdimension-python/tests/color.py
index 72056d1..2d8545d 100755
--- a/libdimension-python/tests/color.py
+++ b/libdimension-python/tests/color.py
@@ -24,15 +24,15 @@ from dimension import *
# Treat warnings as errors for tests
dieOnWarnings(True)
-c = Color(0, 0.5, 1, filter = 0.25, trans = 0.35)
-assert repr(c) == 'dimension.Color(0.0, 0.5, 1.0, 0.25, 0.35)', repr(c)
+c = Color(0, 0.5, 1, trans = 0.5, filter = 0.35)
+assert repr(c) == 'dimension.Color(0.0, 0.5, 1.0, 0.5, 0.35)', repr(c)
assert str(c) == '<red = 0.0, green = 0.5, blue = 1.0, \
-filter = 0.25, trans = 0.35>', str(c)
+trans = 0.5, filter = 0.35>', str(c)
assert c.red == 0, c.red
assert c.green == 0.5, c.green
assert c.blue == 1, c.blue
-assert c.filter == 0.25, c.filter
-assert c.trans == 0.35, c.trans
+assert c.trans == 0.5, c.filter
+assert c.filter == 0.35, c.trans
c = Color(1, 0.5, 0)
assert str(c) == '<red = 1.0, green = 0.5, blue = 0.0>', str(c)
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);