* changes/additions to volume lighting

Volumes can now receive shadows from external objects, either raytraced shadows or shadow maps.

To use external shadows, enable 'external shadows' in volume material 'lighting' panel. This an extra toggle since it causes a performance hit, but this can probably be revisited/optimised when the new raytrace accelerator is integrated. For shadow maps at least, it's still very quick.

Renamed 'scattering mode' to 'lighting mode' (a bit simpler to understand), and the options inside. Now there's:

- Shadeless
  takes light contribution, but without shadowing or self-shading (fast)
  good for fog-like volumes, such as mist, or underwater effects
  
- Shadowed (new)
  takes light contribution with shadows, but no self-shading. (medium)
  good for mist etc. with directional light sources
  eg. http://vimeo.com/6901636
  
- Shaded
  takes light contribution with internal/external shadows, and self shading (slower)
  good for thicker/textured volumes like smoke
  
- Multiple scattering etc (still doesn't work properly, on the todo).
This commit is contained in:
Matt Ebb 2009-10-05 02:59:47 +00:00
parent 89df4a46fc
commit af522abf33
8 changed files with 99 additions and 24 deletions

@ -665,16 +665,17 @@ class MATERIAL_PT_volume_lighting(VolumeButtonsPanel):
split = layout.split()
col = split.column()
col.itemR(vol, "scattering_mode", text="")
col.itemR(vol, "lighting_mode", text="")
col = split.column()
if vol.scattering_mode == 'SINGLE_SCATTERING':
if vol.lighting_mode == 'SHADED':
col.itemR(vol, "external_shadows")
col.itemR(vol, "light_cache")
sub = col.column()
sub.active = vol.light_cache
sub.itemR(vol, "cache_resolution")
elif vol.scattering_mode in ('MULTIPLE_SCATTERING', 'SINGLE_PLUS_MULTIPLE_SCATTERING'):
elif vol.lighting_mode in ('MULTIPLE_SCATTERING', 'SHADED_PLUS_MULTIPLE_SCATTERING'):
sub = col.column()
sub.enabled = True
sub.active = False

@ -181,7 +181,7 @@ void init_material(Material *ma)
ma->vol.depth_cutoff = 0.01f;
ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED;
ma->vol.stepsize = 0.2f;
ma->vol.shade_type = MA_VOL_SHADE_SINGLE;
ma->vol.shade_type = MA_VOL_SHADE_SHADED;
ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
ma->vol.precache_resolution = 50;

@ -9680,7 +9680,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
ma->vol.depth_cutoff = 0.01f;
ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED;
ma->vol.stepsize = 0.2f;
ma->vol.shade_type = MA_VOL_SHADE_SINGLE;
ma->vol.shade_type = MA_VOL_SHADE_SHADED;
ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
ma->vol.precache_resolution = 50;
}

@ -374,15 +374,15 @@ typedef struct Material {
#define MA_VOL_STEP_ADAPTIVE 2
/* vol_shadeflag */
#define MA_VOL_SHADED 1
#define MA_VOL_RECVSHADOW 4
#define MA_VOL_RECV_EXT_SHADOW 1
#define MA_VOL_PRECACHESHADING 8
/* vol_shading_type */
#define MA_VOL_SHADE_NONE 0
#define MA_VOL_SHADE_SINGLE 1
#define MA_VOL_SHADE_MULTIPLE 2
#define MA_VOL_SHADE_SINGLEPLUSMULTIPLE 3
#define MA_VOL_SHADE_SHADELESS 0
#define MA_VOL_SHADE_SHADOWED 2
#define MA_VOL_SHADE_SHADED 1
#define MA_VOL_SHADE_MULTIPLE 3
#define MA_VOL_SHADE_SHADEDPLUSMULTIPLE 4
#endif

@ -953,11 +953,12 @@ static void rna_def_material_volume(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem prop_scattering_items[] = {
{MA_VOL_SHADE_NONE, "NONE", 0, "None", ""},
{MA_VOL_SHADE_SINGLE, "SINGLE_SCATTERING", 0, "Single Scattering", ""},
static EnumPropertyItem prop_lighting_items[] = {
{MA_VOL_SHADE_SHADELESS, "SHADELESS", 0, "Shadeless", ""},
{MA_VOL_SHADE_SHADOWED, "SHADOWED", 0, "Shadowed", ""},
{MA_VOL_SHADE_SHADED, "SHADED", 0, "Shaded", ""},
{MA_VOL_SHADE_MULTIPLE, "MULTIPLE_SCATTERING", 0, "Multiple Scattering", ""},
{MA_VOL_SHADE_SINGLEPLUSMULTIPLE, "SINGLE_PLUS_MULTIPLE_SCATTERING", 0, "Single + Multiple Scattering", ""},
{MA_VOL_SHADE_SHADEDPLUSMULTIPLE, "SHADED_PLUS_MULTIPLE_SCATTERING", 0, "Shaded + Multiple Scattering", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem prop_stepsize_items[] = {
@ -984,10 +985,15 @@ static void rna_def_material_volume(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Step Size", "Distance between subsequent volume depth samples.");
RNA_def_property_update(prop, 0, "rna_Material_update");
prop= RNA_def_property(srna, "scattering_mode", PROP_ENUM, PROP_NONE);
prop= RNA_def_property(srna, "lighting_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shade_type");
RNA_def_property_enum_items(prop, prop_scattering_items);
RNA_def_property_ui_text(prop, "Scattering Mode", "Method of shading, attenuating, and scattering light through the volume");
RNA_def_property_enum_items(prop, prop_lighting_items);
RNA_def_property_ui_text(prop, "Lighting Mode", "Method of shading, attenuating, and scattering light through the volume");
RNA_def_property_update(prop, 0, "rna_Material_update");
prop= RNA_def_property(srna, "external_shadows", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "shadeflag", MA_VOL_RECV_EXT_SHADOW); /* use bitflags */
RNA_def_property_ui_text(prop, "External Shadows", "Receive shadows from sources outside the volume (temporary)");
RNA_def_property_update(prop, 0, "rna_Material_update");
prop= RNA_def_property(srna, "light_cache", PROP_BOOLEAN, PROP_NONE);

@ -942,7 +942,10 @@ static Material *give_render_material(Render *re, Object *ob, int nr)
if(re->r.mode & R_SPEED) ma->texco |= NEED_UV;
if(ma->material_type == MA_TYPE_VOLUME) ma->mode |= MA_TRANSP;
if(ma->material_type == MA_TYPE_VOLUME) {
ma->mode |= MA_TRANSP;
ma->mode &= ~MA_SHADBUF;
}
if((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP))
re->flag |= R_ZTRA;

@ -401,7 +401,7 @@ void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
fac *= (energy_ss / energy_ms);
/* blend multiple scattering back in the light cache */
if (shade_type == MA_VOL_SHADE_SINGLEPLUSMULTIPLE) {
if (shade_type == MA_VOL_SHADE_SHADEDPLUSMULTIPLE) {
/* conserve energy - half single, half multiple */
origf = 0.5f;
fac *= 0.5f;
@ -713,7 +713,7 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat
lightcache_filter(obi->volume_precache);
if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE))
if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE))
{
multiple_scattering_diffusion(re, vp, ma);
}
@ -721,8 +721,8 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat
static int using_lightcache(Material *ma)
{
return (((ma->vol.shadeflag & MA_VOL_PRECACHESHADING) && (ma->vol.shade_type == MA_VOL_SHADE_SINGLE))
|| (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE)));
return (((ma->vol.shadeflag & MA_VOL_PRECACHESHADING) && (ma->vol.shade_type == MA_VOL_SHADE_SHADED))
|| (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)));
}
/* loop through all objects (and their associated materials)

@ -51,6 +51,7 @@
#include "render_types.h"
#include "pixelshading.h"
#include "shading.h"
#include "shadbuf.h"
#include "texture.h"
#include "volumetric.h"
#include "volume_precache.h"
@ -73,6 +74,61 @@ inline float luminance(float* col)
/* tracing */
static int vlr_check_intersect_solid(Isect *is, int ob, RayFace *face)
{
VlakRen *vlr = (VlakRen*)face;
/* solid material types only */
if (vlr->mat->material_type == MA_TYPE_SURFACE)
return 1;
else
return 0;
}
static float vol_get_shadow(ShadeInput *shi, LampRen *lar, float *co)
{
float visibility = 1.f;
if(lar->shb) {
float dot=1.f;
float dxco[3]={0.f, 0.f, 0.f}, dyco[3]={0.f, 0.f, 0.f};
visibility = testshadowbuf(&R, lar->shb, co, dxco, dyco, 1.0, 0.0);
} else if (lar->mode & LA_SHAD_RAY) {
/* trace shadow manually, no good lamp api atm */
Isect is;
const float maxsize = RE_ray_tree_max_size(R.raytree);
VecCopyf(is.start, co);
if(lar->type==LA_SUN || lar->type==LA_HEMI) {
is.end[0] = co[0] - lar->vec[0] * maxsize;
is.end[1] = co[1] - lar->vec[1] * maxsize;
is.end[2] = co[2] - lar->vec[2] * maxsize;
} else {
VecCopyf(is.end, lar->co);
}
is.mode= RE_RAY_MIRROR;
if(lar->mode & (LA_LAYER|LA_LAYER_SHADOW))
is.lay= lar->lay;
else
is.lay= -1;
is.face_last= (RayFace*)lar->vlr_last[shi->thread];
is.ob_last= RAY_OBJECT_SET(&R, lar->obi_last[shi->thread]);
is.faceorig= NULL;
is.oborig= RAY_OBJECT_SET(&R, shi->obi);
if(RE_ray_tree_intersect_check(R.raytree, &is, vlr_check_intersect_solid)) {
visibility = 0.f;
}
lar->vlr_last[shi->thread]= (VlakRen*)is.face_last;
lar->obi_last[shi->thread]= RAY_OBJECT_GET(&R, is.ob_last);
}
return visibility;
}
static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type)
{
float maxsize = RE_ray_tree_max_size(R.raytree);
@ -448,9 +504,18 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *
VECCOPY(lv, lar->vec);
VecMulf(lv, -1.0f);
if (shi->mat->vol.shade_type != MA_VOL_SHADE_NONE) {
if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) {
VecMulf(lacol, vol_get_shadow(shi, lar, co));
}
else if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADED)
{
Isect is;
if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
VecMulf(lacol, vol_get_shadow(shi, lar, co));
if (luminance(lacol) < 0.001f) return;
}
/* find minimum of volume bounds, or lamp coord */
if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
float dist = VecLenf(co, hitco);