[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [16711] branches/sim_physics/source/ blender/render/intern: * Volumetrics scene integration
Matt Ebb
matt at mke3.net
Wed Sep 24 04:52:48 CEST 2008
Revision: 16711
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16711
Author: broken
Date: 2008-09-24 04:52:47 +0200 (Wed, 24 Sep 2008)
Log Message:
-----------
* Volumetrics scene integration
Now other objects (and sky) correctly render if they're partially
inside or behind a volume. Previously all other objects were ignored,
and volumes just rendered on black. The colour of surfaces inside or
behind the volume gets correctly attenuated by the density of the
volume in between - i.e. thicker volumes will block the light coming
from behind. However, other solid objects don't receive volume shadows
yet, this is to be worked on later.
http://mke3.net/blender/devel/rendering/volumetrics/vol_inside_behind.png
Currently this uses raytracing to find intersections within the volume,
and rays are also traced from the volume, heading behind into the
scene, to see what's behind it (similar effect to ray transp with IOR
1). Because of this, objects inside or behind the volume will not be
antialiased. Perhaps I can come up with a solution for this, but until
then, for antialiasing, you can turn on Full OSA (warning, this will
incur a slowdown). Of course you can always avoid this by rendering
volumes on a separate renderlayer, and compositing in post, too.
Another idea I've started thinking about is to calculate an alpha
value, then use ztransp to overlay on top of other objects. This won't
accurately attenuate and absorb light coming from objects behind the
volume, but for some situations it may be fine, and faster too.
Modified Paths:
--------------
branches/sim_physics/source/blender/render/intern/include/shading.h
branches/sim_physics/source/blender/render/intern/source/rayshade.c
branches/sim_physics/source/blender/render/intern/source/volumetric.c
Modified: branches/sim_physics/source/blender/render/intern/include/shading.h
===================================================================
--- branches/sim_physics/source/blender/render/intern/include/shading.h 2008-09-24 01:39:55 UTC (rev 16710)
+++ branches/sim_physics/source/blender/render/intern/include/shading.h 2008-09-24 02:52:47 UTC (rev 16711)
@@ -91,3 +91,6 @@
void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real);
float fresnel_fac(float *view, float *vn, float fresnel, float fac);
+
+/* rayshade.c */
+extern void shade_ray(struct Isect *is, struct ShadeInput *shi, struct ShadeResult *shr);
Modified: branches/sim_physics/source/blender/render/intern/source/rayshade.c
===================================================================
--- branches/sim_physics/source/blender/render/intern/source/rayshade.c 2008-09-24 01:39:55 UTC (rev 16710)
+++ branches/sim_physics/source/blender/render/intern/source/rayshade.c 2008-09-24 02:52:47 UTC (rev 16711)
@@ -205,7 +205,7 @@
re->stats_draw(&re->i);
}
-static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
+void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
{
VlakRen *vlr= (VlakRen*)is->face;
ObjectInstanceRen *obi= RAY_OBJECT_GET(&R, is->ob);
Modified: branches/sim_physics/source/blender/render/intern/source/volumetric.c
===================================================================
--- branches/sim_physics/source/blender/render/intern/source/volumetric.c 2008-09-24 01:39:55 UTC (rev 16710)
+++ branches/sim_physics/source/blender/render/intern/source/volumetric.c 2008-09-24 02:52:47 UTC (rev 16711)
@@ -45,6 +45,7 @@
#include "BKE_global.h"
#include "render_types.h"
+#include "pixelshading.h"
#include "shading.h"
#include "texture.h"
@@ -72,37 +73,36 @@
#define VOL_BOUNDS_DEPTH 0
#define VOL_BOUNDS_SS 1
-int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, int intersect_type)
+static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type)
{
/* TODO: Box or sphere intersection types could speed things up */
/* raytrace method */
- Isect isect;
float maxsize = RE_ray_tree_max_size(R.raytree);
/* TODO: use object's bounding box to calculate max size */
- VECCOPY(isect.start, co);
- isect.end[0] = co[0] + vec[0] * maxsize;
- isect.end[1] = co[1] + vec[1] * maxsize;
- isect.end[2] = co[2] + vec[2] * maxsize;
+ VECCOPY(isect->start, co);
+ isect->end[0] = co[0] + vec[0] * maxsize;
+ isect->end[1] = co[1] + vec[1] * maxsize;
+ isect->end[2] = co[2] + vec[2] * maxsize;
- if (intersect_type == VOL_BOUNDS_DEPTH) isect.faceorig= (RayFace*)shi->vlr;
- else if (intersect_type == VOL_BOUNDS_SS) isect.faceorig= NULL;
+ if (intersect_type == VOL_BOUNDS_DEPTH) isect->faceorig= (RayFace*)shi->vlr;
+ else if (intersect_type == VOL_BOUNDS_SS) isect->faceorig= NULL;
- isect.mode= RE_RAY_MIRROR;
- isect.oborig= RAY_OBJECT_SET(&R, shi->obi);
- isect.face_last= NULL;
- isect.ob_last= 0;
- isect.lay= -1;
+ isect->mode= RE_RAY_MIRROR;
+ isect->oborig= RAY_OBJECT_SET(&R, shi->obi);
+ isect->face_last= NULL;
+ isect->ob_last= 0;
+ isect->lay= -1;
- if(RE_ray_tree_intersect(R.raytree, &isect))
+ if(RE_ray_tree_intersect(R.raytree, isect))
{
float isvec[3];
- VECCOPY(isvec, isect.vec);
- hitco[0] = isect.start[0] + isect.labda*isvec[0];
- hitco[1] = isect.start[1] + isect.labda*isvec[1];
- hitco[2] = isect.start[2] + isect.labda*isvec[2];
+ VECCOPY(isvec, isect->vec);
+ hitco[0] = isect->start[0] + isect->labda*isvec[0];
+ hitco[1] = isect->start[1] + isect->labda*isvec[1];
+ hitco[2] = isect->start[2] + isect->labda*isvec[2];
return 1;
} else {
@@ -229,13 +229,14 @@
if (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED) {
+ Isect is;
if (ELEM(lar->type, LA_SUN, LA_HEMI))
VECCOPY(lv, lar->vec);
VecMulf(lv, -1.0f);
/* find minimum of volume bounds, or lamp coord */
- if (vol_get_bounds(shi, co, lv, hitco, VOL_BOUNDS_SS)) {
+ if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
float dist = VecLenf(co, hitco);
if (ELEM(lar->type, LA_SUN, LA_HEMI))
@@ -298,31 +299,101 @@
VECCOPY(scatter, col);
}
+static void shade_intersection(ShadeInput *shi, float *col, Isect *is)
+{
+ ShadeInput shi_new;
+ ShadeResult shr_new;
+
+ memset(&shi_new, 0, sizeof(ShadeInput));
+
+ shi_new.mask= shi->mask;
+ shi_new.osatex= shi->osatex;
+ shi_new.depth= 1; /* only used to indicate tracing */
+ shi_new.thread= shi->thread;
+ shi_new.xs= shi->xs;
+ shi_new.ys= shi->ys;
+ shi_new.lay= shi->lay;
+ shi_new.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
+ shi_new.combinedflag= 0xFFFFFF; /* ray trace does all options */
+ shi_new.light_override= shi->light_override;
+ shi_new.mat_override= shi->mat_override;
+
+ memset(&shr_new, 0, sizeof(ShadeResult));
+
+ shade_ray(is, &shi_new, &shr_new);
+
+ col[0]= shr_new.diff[0] + shr_new.spec[0];
+ col[1]= shr_new.diff[1] + shr_new.spec[1];
+ col[2]= shr_new.diff[2] + shr_new.spec[2];
+}
-static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco)
+static void vol_trace_behind(ShadeInput *shi, float *co, Isect *isect_first, float *col)
{
- float tr[3] = {1.f, 1.f, 1.f}; /* total transmittance */
+ if (isect_first != NULL) {
+ /* found an intersection,
+ * either back of volume object or another object */
+ ObjectInstanceRen *obi= RAY_OBJECT_GET(&R, isect_first->ob);
+
+ if (obi != shi->obi) {
+ /* already intersected with another object, so shade it */
+ shade_intersection(shi, col, isect_first);
+ return;
+ } else {
+ /* trace a new ray onwards behind the volume */
+ Isect isect;
+ float maxsize = RE_ray_tree_max_size(R.raytree);
+
+ VECCOPY(isect.start, co);
+ isect.end[0] = co[0] + shi->view[0] * maxsize;
+ isect.end[1] = co[1] + shi->view[1] * maxsize;
+ isect.end[2] = co[2] + shi->view[2] * maxsize;
+
+ isect.faceorig= isect_first->face;
+ isect.mode= RE_RAY_MIRROR;
+ isect.oborig= RAY_OBJECT_SET(&R, shi->obi);
+ isect.face_last= NULL;
+ isect.ob_last= 0;
+ isect.lay= -1;
+
+ if(RE_ray_tree_intersect(R.raytree, &isect))
+ shade_intersection(shi, col, &isect);
+ else
+ shadeSkyView(col, co, shi->view, NULL);
+
+ return;
+ }
+ }
+
+ col[0] = col[1] = col[2] = 0.0f;
+}
+
+static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco, Isect *isect)
+{
+ float tr[3] = {1.0f, 1.0f, 1.0f}; /* total transmittance */
float radiance[3] = {0.f, 0.f, 0.f}, d_radiance[3] = {0.f, 0.f, 0.f};
float stepsize = shi->mat->vol_stepsize;
int nsteps;
float vec[3], stepvec[3] = {0.0, 0.0, 0.0};
- float step_tau[3], step_emit[3], step_scatter[3] = {0.0, 0.0, 0.0};
+ float tau[3], step_emit[3], step_scatter[3] = {0.0, 0.0, 0.0};
int s;
float step_sta[3], step_end[3];
+ float col_behind[3];
+ float total_density = 0.f;
+ float density = vol_get_density(shi, co);
+
/* multiply col_behind with beam transmittance over entire distance */
-/*
- // get col_behind
-
- // get total transmittance
- vol_get_attenuation(shi, total_tau, start, dist, stepsize);
- total_tr[0] = exp(-total_tau[0]);
- total_tr[1] = exp(-total_tau[1]);
- total_tr[2] = exp(-total_tau[2]);
- VecMulVecf(radiance, total_tr, col_behind);
-*/
-
+ vol_trace_behind(shi, endco, isect, col_behind);
+ vol_get_attenuation(shi, tau, co, endco, density, stepsize);
+ tr[0] *= exp(-tau[0]);
+ tr[1] *= exp(-tau[1]);
+ tr[2] *= exp(-tau[2]);
+ VecMulVecf(radiance, tr, col_behind);
+ tr[0] = tr[1] = tr[2] = 1.0f;
+
+
+
/* ray marching */
nsteps = (int)ceil(VecLenf(co, endco) / stepsize);
@@ -333,18 +404,17 @@
VECCOPY(step_sta, co);
VecAddf(step_end, step_sta, stepvec);
-
/* get radiance from all points along the ray due to participating media */
for (s = 0; s < nsteps; s++) {
- float density = vol_get_density(shi, step_sta);
+ if (s > 0) density = vol_get_density(shi, step_sta);
/* *** transmittance and emission *** */
/* transmittance component (alpha) */
- vol_get_attenuation(shi, step_tau, step_sta, step_end, density, stepsize);
- tr[0] *= exp(-step_tau[0]);
- tr[1] *= exp(-step_tau[1]);
- tr[2] *= exp(-step_tau[2]);
+ vol_get_attenuation(shi, tau, step_sta, step_end, density, stepsize);
+ tr[0] *= exp(-tau[0]);
+ tr[1] *= exp(-tau[1]);
+ tr[2] *= exp(-tau[2]);
/* Terminate raymarching if transmittance is small */
//if (rgb_to_luminance(tr[0], tr[1], tr[2]) < 1e-3) break;
@@ -357,15 +427,25 @@
/* Lv += Tr * (Lve() + Ld) */
VecMulVecf(d_radiance, tr, d_radiance);
+ VecMulf(d_radiance, stepsize);
+
VecAddf(radiance, radiance, d_radiance);
VECCOPY(step_sta, step_end);
VecAddf(step_end, step_end, stepvec);
+
+ total_density += density;
}
- VecMulf(radiance, stepsize);
- VECCOPY(col, radiance);
+
+ col[0] = radiance[0];
+ col[1] = radiance[1];
+ col[2] = radiance[2];
+
+ col[3] = 1.0f;
+ //col[3] = total_density * stepsize;
+
/*
Incoming radiance =
outgoing radiance from behind surface * beam transmittance/attenuation
@@ -394,21 +474,23 @@
void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr)
{
- float hitco[3], col[3];
+ float hitco[3], col[4];
+ Isect is;
memset(shr, 0, sizeof(ShadeResult));
- if (vol_get_bounds(shi, shi->co, shi->view, hitco, VOL_BOUNDS_DEPTH)) {
+ if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
- volumeintegrate(shi, col, shi->co, hitco);
+ volumeintegrate(shi, col, shi->co, hitco, &is);
/* hit */
- shr->alpha = 1.0f;
shr->combined[0] = col[0];
shr->combined[1] = col[1];
shr->combined[2] = col[2];
+ shr->combined[3] = 0.0f;
+ shr->alpha = col[3];
- QUATCOPY(shr->diff, shr->combined);
+ VECCOPY(shr->diff, shr->combined);
}
else {
/* no hit */
More information about the Bf-blender-cvs
mailing list