Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Ebb <matt@mke3.net>2008-10-20 11:08:06 +0400
committerMatt Ebb <matt@mke3.net>2008-10-20 11:08:06 +0400
commit9d2fc97827e2b94eb436081185108db9043ae54e (patch)
tree7e7ff77f146839a4fc6f20c7c2ecad7fe92179cc
parent49aa7edb7708fcc0119d8251fa423903b022e706 (diff)
New volume rendering feature: Light Cache
This was a bit complicated to do, but is working pretty well now, and can make shading significantly faster to render. This option pre-calculates self-shading information into a 3d voxel grid before rendering, then uses and interpolates that data during the main rendering phase, rather than calculating shading for each sample. It's an approximation and isn't as accurate as getting the lighting directly, but in many cases it looks very similar and renders much faster. The voxel grid covers the object's 3D screen-aligned bounding box so this may not be that useful for large volume regions like a big range of cloud cover, since you'll need a lot of resolution. The render time speaks for itself here: http://mke3.net/blender/devel/rendering/volumetrics/vol_light_cache_interpolation.jpg The resolution is set in the volume panel - it's the resolution of one edge of the voxel grid. Keep in mind that the higher the resolution, the more memory needed, like in fluid sim. The memory requirements increase with the cube of the edge resolution so be careful. I might try and add a little memory calculator thing like fluid sim has there later. The voxels are interpolated using trilinear interpolation - here's a comparison image I made during testing: http://mke3.net/blender/devel/rendering/volumetrics/vol_light_cache_compare.jpg There might still be a couple of little tweaks I can do to improve the visual quality, I'll see.
-rw-r--r--source/blender/blenkernel/intern/material.c1
-rw-r--r--source/blender/blenloader/intern/readfile.c2
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h1
-rw-r--r--source/blender/render/intern/source/shadeinput.c1
-rw-r--r--source/blender/render/intern/source/volumetric.c299
-rw-r--r--source/blender/src/buttons_shading.c47
6 files changed, 274 insertions, 77 deletions
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 3fcc76bf058..b47e4d2ebaa 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -173,6 +173,7 @@ void init_material(Material *ma)
ma->vol_absorption = 1.0f;
ma->vol_scattering = 1.0f;
ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f;
+ ma->vol_precache_resolution = 50;
ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RADIO|MA_RAYBIAS|MA_TANGENT_STR;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index a3e6a21dd0b..4af54832221 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -7895,6 +7895,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
if (ma->vol_density_scale < 0.0001f)
ma->vol_density_scale = 1.0f;
+ if (ma->vol_precache_resolution == 0)
+ ma->vol_precache_resolution = 50;
}
for(tex=main->tex.first; tex; tex= tex->id.next) {
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 112a1e9929d..5a320da522f 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -100,6 +100,7 @@ typedef struct ShadeInput
struct StrandRen *strand;
struct ObjectInstanceRen *obi;
struct ObjectRen *obr;
+ struct Render *re; /* link back to the Render */
int facenr;
float facenor[3]; /* copy from face */
short flippednor; /* is facenor flipped? */
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index aa11e3d75dd..6989fe66b67 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -1270,6 +1270,7 @@ void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, in
shi->combinedflag= ~rl->pass_xor;
shi->mat_override= rl->mat_override;
shi->light_override= rl->light_override;
+ shi->re = &R;
// shi->rl= rl;
/* note shi.depth==0 means first hit, not raytracing */
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
index fc2e4a630b1..0f6e7591ece 100644
--- a/source/blender/render/intern/source/volumetric.c
+++ b/source/blender/render/intern/source/volumetric.c
@@ -51,6 +51,7 @@
#include "BKE_main.h"
#include "render_types.h"
+#include "renderdatabase.h"
#include "pixelshading.h"
#include "shading.h"
#include "texture.h"
@@ -61,8 +62,6 @@
extern struct Render R;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-#define PRECACHE_RES 5
-
static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face)
{
VlakRen *vlr = (VlakRen *)face;
@@ -96,7 +95,7 @@ static int vol_always_intersect_check(Isect *is, int ob, RayFace *face)
/* TODO: Box or sphere intersection types could speed things up */
static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type, int checkfunc)
{
- float maxsize = RE_ray_tree_max_size(R.raytree);
+ float maxsize = RE_ray_tree_max_size(shi->re->raytree);
int intersected=0;
/* TODO: use object's bounding box to calculate max size */
@@ -115,9 +114,9 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco,
else if (intersect_type == VOL_BOUNDS_SS) isect->faceorig= NULL;
if (checkfunc==VOL_IS_BACKFACE)
- intersected = RE_ray_tree_intersect_check(R.raytree, isect, vol_backface_intersect_check);
+ intersected = RE_ray_tree_intersect_check(shi->re->raytree, isect, vol_backface_intersect_check);
else
- intersected = RE_ray_tree_intersect(R.raytree, isect);
+ intersected = RE_ray_tree_intersect(shi->re->raytree, isect);
if(intersected)
{
@@ -240,6 +239,82 @@ void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co)
absorb_col[2] = (1.0f - absorb_col[2]) * absorption;
}
+
+static float D(ShadeInput *shi, int rgb, int x, int y, int z)
+{
+ const int res = shi->mat->vol_precache_resolution;
+ CLAMP(x, 0, res-1);
+ CLAMP(y, 0, res-1);
+ CLAMP(y, 0, res-1);
+ return shi->obi->volume_precache[rgb*res*res*res + x*res*res + y*res + z];
+}
+
+inline float lerp(float t, float v1, float v2) {
+ return (1.f - t) * v1 + t * v2;
+}
+
+/* trilinear interpolation */
+static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co)
+{
+ const int res = shi->mat->vol_precache_resolution;
+ float voxx, voxy, voxz;
+ int vx, vy, vz;
+ float dx, dy, dz;
+ float d00, d10, d01, d11, d0, d1, d_final;
+ float bbmin[3], bbmax[3], dim[3];
+ int rgb;
+
+ if (!shi->obi->volume_precache) return;
+
+ VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
+ VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
+ VecSubf(dim, bbmax, bbmin);
+
+ voxx = ((co[0] - bbmin[0]) / dim[0]) * res - 0.5f;
+ voxy = ((co[1] - bbmin[1]) / dim[1]) * res - 0.5f;
+ voxz = ((co[2] - bbmin[2]) / dim[2]) * res - 0.5f;
+
+ vx = (int)voxx; vy = (int)voxy; vz = (int)voxz;
+
+ dx = voxx - vx; dy = voxy - vy; dz = voxz - vz;
+
+ for (rgb=0; rgb < 3; rgb++) {
+ d00 = lerp(dx, D(shi, rgb, vx, vy, vz), D(shi, rgb, vx+1, vy, vz));
+ d10 = lerp(dx, D(shi, rgb, vx, vy+1, vz), D(shi, rgb, vx+1, vy+1, vz));
+ d01 = lerp(dx, D(shi, rgb, vx, vy, vz+1), D(shi, rgb, vx+1, vy, vz+1));
+ d11 = lerp(dx, D(shi, rgb, vx, vy+1, vz+1), D(shi, rgb, vx+1, vy+1, vz+1));
+ d0 = lerp(dy, d00, d10);
+ d1 = lerp(dy, d01, d11);
+ d_final = lerp(dz, d0, d1);
+
+ scatter_col[rgb] = d_final;
+ }
+}
+
+#if 0
+/* no interpolation, not used */
+static void vol_get_precached_scattering_nearest(ShadeInput *shi, float *scatter_col, float *co)
+{
+ const int res = shi->mat->vol_precache_resolution;
+ int x,y,z;
+ float bbmin[3], bbmax[3], dim[3];
+
+ if (!shi->obi->volume_precache) return;
+
+ VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
+ VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
+ VecSubf(dim, bbmax, bbmin);
+
+ x = (int)(((co[0] - bbmin[0]) / dim[0]) * res);
+ y = (int)(((co[1] - bbmin[1]) / dim[1]) * res);
+ z = (int)(((co[2] - bbmin[2]) / dim[2]) * res);
+
+ scatter_col[0] = shi->obi->volume_precache[0*res*res*res + x*res*res + y*res + z];
+ scatter_col[1] = shi->obi->volume_precache[1*res*res*res + x*res*res + y*res + z];
+ scatter_col[2] = shi->obi->volume_precache[2*res*res*res + x*res*res + y*res + z];
+}
+#endif
+
/* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau.
* Used in the relationship Transmittance = e^(-attenuation)
*/
@@ -276,7 +351,6 @@ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, f
VecAddf(step_end, step_sta, step_vec);
for (s = 0; s < nsteps; s++) {
-
if (s > 0)
density = vol_get_density(shi, step_sta);
@@ -317,9 +391,9 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *
shi->osatex= 0;
do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
}
-
+
VecMulf(lacol, visifac*lar->energy);
-
+
if (ELEM(lar->type, LA_SUN, LA_HEMI))
VECCOPY(lv, lar->vec);
VecMulf(lv, -1.0f);
@@ -364,27 +438,27 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *
vol_get_scattering_fac(shi, &scatter_fac, co, density);
VecMulf(lacol, scatter_fac);
-
}
/* single scattering only for now */
-void vol_get_scattering(Render *re, ShadeInput *shi, float *scatter, float *co, float stepsize, float density)
+void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsize, float density)
{
GroupObject *go;
ListBase *lights;
LampRen *lar;
float col[3] = {0.f, 0.f, 0.f};
-
- lights= get_lights(shi);
- for(go=lights->first; go; go= go->next)
+ int i=0;
+
+ for(go=shi->re->lights.first; go; go= go->next)
{
float lacol[3] = {0.f, 0.f, 0.f};
+ i++;
+
lar= go->lampren;
if (lar) {
-
vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density);
-
+
VecMulf(lacol, density);
VecAddf(col, col, lacol);
@@ -415,7 +489,6 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float
VecMulVecf(radiance, tr, col);
tr[0] = tr[1] = tr[2] = 1.0f;
-
/* ray marching */
nsteps = (int)ceil(VecLenf(co, endco) / stepsize);
@@ -447,23 +520,12 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float
/* incoming light via emission or scattering (additive) */
vol_get_emission(shi, emit_col, step_mid, density);
- if ((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) && shi->obi->volume_precache) {
- const int res = shi->mat->vol_precache_resolution;
- int x,y,z;
- float bbmin[3], bbmax[3], dim[3];
-
- VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
- VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
- VecSubf(dim, bbmax, bbmin);
-
- x = (int)(((step_mid[0] - bbmin[0]) / dim[0]) * res);
- y = (int)(((step_mid[1] - bbmin[1]) / dim[1]) * res);
- z = (int)(((step_mid[2] - bbmin[2]) / dim[2]) * res);
-
- scatter_col[0] = scatter_col[1] = scatter_col[2] = shi->obi->volume_precache[x*res*res + y*res + z];
- }
- else
- vol_get_scattering(&R, shi, scatter_col, step_mid, stepsize, density);
+
+ if ((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) &&
+ (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED)) {
+ vol_get_precached_scattering(shi, scatter_col, step_mid);
+ } else
+ vol_get_scattering(shi, scatter_col, step_mid, stepsize, density);
VecAddf(d_radiance, emit_col, scatter_col);
@@ -544,7 +606,7 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is)
static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *col)
{
Isect isect;
- float maxsize = RE_ray_tree_max_size(R.raytree);
+ float maxsize = RE_ray_tree_max_size(shi->re->raytree);
VECCOPY(isect.start, co);
isect.end[0] = isect.start[0] + shi->view[0] * maxsize;
@@ -560,7 +622,7 @@ static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *co
isect.lay= -1;
/* check to see if there's anything behind the volume, otherwise shade the sky */
- if(RE_ray_tree_intersect(R.raytree, &isect)) {
+ if(RE_ray_tree_intersect(shi->re->raytree, &isect)) {
shade_intersection(shi, col, &isect);
} else {
shadeSkyView(col, co, shi->view, NULL);
@@ -568,6 +630,7 @@ static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *co
}
}
+/* the main entry point for volume shading */
void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr)
{
float hitco[3], col[4] = {0.f,0.f,0.f,0.f};
@@ -629,6 +692,8 @@ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr)
}
}
+/* Traces a shadow through the object,
+ * pretty much gets the transmission over a ray path */
void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
{
float hitco[3];
@@ -678,26 +743,125 @@ void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct
shr->combined[2] = 0.0f;
shr->combined[3] = shr->alpha = 0.0f;
}
+}
+
+
+/* Recursive test for intersections, from a point inside the mesh, to outside
+ * Number of intersections (depth) determine if a point is inside or outside the mesh */
+int intersect_outside_volume(RayTree *tree, Isect *isect, float *offset, int limit, int depth)
+{
+ if (limit == 0) return depth;
+
+ if (RE_ray_tree_intersect(tree, isect)) {
+ float hitco[3];
+
+ hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
+ hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
+ hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
+ VecAddf(isect->start, hitco, offset);
+
+ return intersect_outside_volume(tree, isect, offset, limit-1, depth+1);
+ } else {
+ return depth;
+ }
+}
+/* Uses ray tracing to check if a point is inside or outside an ObjectInstanceRen */
+int point_inside_obi(RayTree *tree, ObjectInstanceRen *obi, float *co)
+{
+ float maxsize = RE_ray_tree_max_size(tree);
+ int intersected;
+ Isect isect;
+ float vec[3] = {0.0f,0.0f,1.0f};
+ int final_depth=0, depth=0, limit=20;
+
+ /* set up the isect */
+ memset(&isect, 0, sizeof(isect));
+ 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;
+
+ /* and give it a little offset to prevent self-intersections */
+ VecMulf(vec, 1e-5);
+ VecAddf(isect.start, isect.start, vec);
+
+ isect.mode= RE_RAY_MIRROR;
+ isect.face_last= NULL;
+ isect.lay= -1;
+
+ final_depth = intersect_outside_volume(tree, &isect, vec, limit, depth);
+
+ /* even number of intersections: point is outside
+ * odd number: point is inside */
+ if (final_depth % 2 == 0) return 0;
+ else return 1;
+}
+
+static int inside_check_func(Isect *is, int ob, RayFace *face)
+{
+ return 1;
+}
+static void vlr_face_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4)
+{
+ VlakRen *vlr= (VlakRen*)face;
+
+ *v1 = (vlr->v1)? vlr->v1->co: NULL;
+ *v2 = (vlr->v2)? vlr->v2->co: NULL;
+ *v3 = (vlr->v3)? vlr->v3->co: NULL;
+ *v4 = (vlr->v4)? vlr->v4->co: NULL;
+}
+
+RayTree *create_raytree_obi(ObjectInstanceRen *obi, float *bbmin, float *bbmax)
+{
+ int v;
+ VlakRen *vlr= NULL;
+
+ /* create empty raytree */
+ RayTree *tree = RE_ray_tree_create(64, obi->obr->totvlak, bbmin, bbmax,
+ vlr_face_coords, inside_check_func, NULL, NULL);
+
+ /* fill it with faces */
+ for(v=0; v<obi->obr->totvlak; v++) {
+ if((v & 255)==0)
+ vlr= obi->obr->vlaknodes[v>>8].vlak;
+ else
+ vlr++;
+
+ RE_ray_tree_add_face(tree, 0, vlr);
+ }
+
+ RE_ray_tree_done(tree);
}
+/* Precache a volume into a 3D voxel grid.
+ * The voxel grid is stored in the ObjectInstanceRen,
+ * in camera space, aligned with the ObjectRen's bounding box.
+ * Resolution is defined by the user.
+ */
void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *ma, float *bbmin, float *bbmax)
{
int x, y, z;
float co[3], voxel[3], scatter_col[3];
ShadeInput shi;
+ float view[3] = {0.0,0.0,1.0};
float density;
float stepsize;
- float resf;
- int res_2;
- float res_3;
+ float resf, res_3f;
+ int res_2, res_3;
float i = 1.0f;
- double lasttime= PIL_check_seconds_timer();
+ double time, lasttime= PIL_check_seconds_timer();
const int res = ma->vol_precache_resolution;
+ /* create a raytree with just the faces of the instanced ObjectRen,
+ * used for checking if the cached point is inside or outside. */
+ RayTree *tree = create_raytree_obi(obi, bbmin, bbmax);
+ if (!tree) return;
+
+ /* Need a shadeinput to calculate scattering */
memset(&shi, 0, sizeof(ShadeInput));
shi.depth= 1;
shi.mask= 1;
@@ -707,18 +871,28 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m
shi.har= shi.mat->har;
shi.obi= obi;
shi.obr= obi->obr;
+ shi.lay = re->scene->lay;
+ shi.re = re;
+ VECCOPY(shi.view, view);
stepsize = vol_get_stepsize(&shi, STEPSIZE_VIEW);
- resf = (float) res;
+ resf = (float)res;
res_2 = res*res;
res_3 = res*res*res;
+ res_3f = (float)res_3;
VecSubf(voxel, bbmax, bbmin);
VecMulf(voxel, 1.0f/res);
- obi->volume_precache = MEM_mallocN(sizeof(float)*res*res*res, "volume light cache");
+ obi->volume_precache = MEM_callocN(sizeof(float)*res_3*3, "volume light cache");
+ /* Iterate over the 3d voxel grid, and fill the voxels with scattering information
+ *
+ * It's stored in memory as 3 big float grids next to each other, one for each RGB channel.
+ * I'm guessing the memory alignment may work out better this way for the purposes
+ * of doing linear interpolation, but I haven't actually tested this theory! :)
+ */
for (x=0; x < res; x++) {
co[0] = bbmin[0] + (voxel[0] * x);
@@ -726,47 +900,54 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m
co[1] = bbmin[1] + (voxel[1] * y);
for (z=0; z < res; z++) {
- double time= PIL_check_seconds_timer();
-
co[2] = bbmin[2] + (voxel[2] * z);
-
- density = vol_get_density(&shi, co);
- vol_get_scattering(re, &shi, scatter_col, co, stepsize, density);
- obi->volume_precache[x*res_2 + y*res + z] = (scatter_col[0] + scatter_col[1] + scatter_col[2]) / 3.0f;
-
+ time= PIL_check_seconds_timer();
+ i++;
+
/* display progress every second */
if(re->test_break())
return;
if(time-lasttime>1.0f) {
char str[64];
- sprintf(str, "Precaching volume: %d%%", (int)(100.0f * (i / res_3)));
+ sprintf(str, "Precaching volume: %d%%", (int)(100.0f * (i / res_3f)));
re->i.infostr= str;
re->stats_draw(&re->i);
re->i.infostr= NULL;
lasttime= time;
}
- i++;
+ /* don't bother if the point is not inside the volume mesh */
+ if (!point_inside_obi(tree, obi, co))
+ continue;
+
+ density = vol_get_density(&shi, co);
+ vol_get_scattering(&shi, scatter_col, co, stepsize, density);
+
+ obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = scatter_col[0];
+ obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = scatter_col[1];
+ obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = scatter_col[2];
}
}
}
+
+ if(tree) {
+ RE_ray_tree_free(tree);
+ tree= NULL;
+ }
}
+/* loop through all objects (and their associated materials)
+ * marked for pre-caching in convertblender.c, and pre-cache them */
void volume_precache(Render *re)
{
ObjectInstanceRen *obi;
VolPrecache *vp;
- int i=1;
-
- printf("Precaching %d volumes... \n", BLI_countlist(&re->vol_precache_obs));
-
+
for(vp= re->vol_precache_obs.first; vp; vp= vp->next) {
for(obi= re->instancetable.first; obi; obi= obi->next) {
- if (obi->obr == vp->obr) {
- printf("Precaching Object: %s with Material: %s \n", vp->obr->ob->id.name+2, vp->ma->id.name+2);
+ if (obi->obr == vp->obr)
vol_precache_objectinstance(re, obi, vp->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]);
- }
}
}
@@ -779,10 +960,8 @@ void free_volume_precache(Render *re)
ObjectInstanceRen *obi;
for(obi= re->instancetable.first; obi; obi= obi->next) {
- if (obi->volume_precache) {
+ if (obi->volume_precache)
MEM_freeN(obi->volume_precache);
- printf("freed volume precache of object: %s \n", obi->obr->ob->id.name+2);
- }
}
BLI_freelistN(&re->vol_precache_obs);
diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c
index 8ad4078b90e..72a396d63be 100644
--- a/source/blender/src/buttons_shading.c
+++ b/source/blender/src/buttons_shading.c
@@ -4357,7 +4357,7 @@ static void material_panel_material_volume(Material *ma)
short yco=PANEL_YMAX;
block= uiNewBlock(&curarea->uiblocks, "material_panel_material_volume", UI_EMBOSS, UI_HELV, curarea->win);
- if(uiNewPanel(curarea, block, "Volume", "Material", PANELX, PANELY, PANELW, PANELH)==0) return;
+ if(uiNewPanel(curarea, block, "Volume", "Material", PANELX, PANELY, PANELW, PANELH+40)==0) return;
uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
@@ -4365,32 +4365,28 @@ static void material_panel_material_volume(Material *ma)
uiDefButF(block, NUM, B_MATPRV, "Step Size: ",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_stepsize), 0.001, 100.0, 10, 2, "Ray marching step size");
uiDefButS(block, MENU, B_TEXREDR_PRV, "Step Size Calculation %t|Randomized %x0|Constant %x1",
- X2CLM1, yco-=BUTH, BUTW2, BUTH, &ma->vol_stepsize_type, 0.0, 0.0, 0, 0, "Step size calculation, replace banding with jittering");
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &ma->vol_stepsize_type, 0.0, 0.0, 0, 0, "Step size calculation, randomized replaces banding with jittering");
uiBlockEndAlign(block);
yco -= YSPACE;
-
+
uiBlockBeginAlign(block);
uiDefButBitS(block, TOG, MA_VOL_ATTENUATED, B_MATPRV, "Self Shading",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shadeflag), 0, 0, 0, 0, "Uses absorption for light attenuation");
uiDefButF(block, NUM, B_MATPRV, "Step Size: ",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shade_stepsize), 0.001, 100.0, 10, 2, "Step");
- uiDefButBitS(block, TOG, MA_VOL_PRECACHESHADING, B_MATPRV, "Precache",
- X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shadeflag), 0, 0, 0, 0, "precache");
- uiDefButS(block, NUM, B_MATPRV, "Resolution: ",
- X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_precache_resolution), 0.0, 1024.0, 10, 2, "precache voxel resolution");
uiBlockEndAlign(block);
yco -= YSPACE;
- uiBlockBeginAlign(block);
- uiDefButS(block, MENU, B_TEXREDR_PRV, "Scattering Direction %t|Isotropic %x0|Mie Hazy %x1|Mie Murky %x2|Rayleigh %x3|Henyey-Greenstein %x4|Schlick %x5",
- X2CLM1, yco-=BUTH, BUTW2, BUTH, &ma->vol_phasefunc_type, 0.0, 0.0, 0, 0, "Scattering Direction (Phase Function)");
- if (ELEM(ma->vol_phasefunc_type, MA_VOL_PH_HG, MA_VOL_PH_SCHLICK)) {
- uiDefButF(block, NUM, B_MATPRV, "Asymmetry: ",
- X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_phasefunc_g), -1.0, 1.0, 0, 0, "> 0 is forward scattering, < 0 is back scattering");
+ if (ma->vol_shadeflag & MA_VOL_ATTENUATED) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, MA_VOL_PRECACHESHADING, B_MATPRV, "Light Cache",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shadeflag), 0, 0, 0, 0, "Pre-cache the shading information into a voxel grid");
+ uiDefButS(block, NUM, B_MATPRV, "Resolution: ",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_precache_resolution), 0.0, 1024.0, 10, 2, "Resolution of the voxel grid, low resolutions are faster, high resolutions use more memory (res ^3)");
+ uiBlockEndAlign(block);
}
- uiBlockEndAlign(block);
/*uiDefButBitS(block, TOG, MA_VOL_RECVSHADOW, B_MATPRV, "Receive Shadows",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shadeflag), 0, 0, 0, 0, "Receive shadows from external objects");
@@ -4409,7 +4405,7 @@ static void material_panel_material_volume(Material *ma)
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_MATPRV, "Absorption: ",
- X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 100.0, 10, 0, "Multiplier for absorption");
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 100.0, 10, 0, "Amount of light absorbed by the volume");
uiDefButF(block, COL, B_MATPRV, "",
X2CLM2, yco-=BUTH, BUTW2, BUTH, ma->vol_absorption_col, 0, 0, 0, B_MATCOL, "");
uiBlockEndAlign(block);
@@ -4418,7 +4414,7 @@ static void material_panel_material_volume(Material *ma)
uiBlockBeginAlign(block);
uiDefButF(block, NUMSLI, B_MATPRV, "Emit: ",
- X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->emit), 0.0, 2.0, 0, 0, "Emission component");
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->emit), 0.0, 2.0, 0, 0, "Amount of light emitted from the volume");
uiDefButF(block, COL, B_MATPRV, "",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->r), 0, 0, 0, B_MATCOL, "");
uiBlockEndAlign(block);
@@ -4426,7 +4422,24 @@ static void material_panel_material_volume(Material *ma)
yco -= YSPACE;
uiDefButF(block, NUM, B_MATPRV, "Scattering: ",
- X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_scattering), 0.0, 100.0, 10, 0, "Multiplier for scattering");
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_scattering), 0.0, 100.0, 10, 0, "Amount of light scattered through the volume from lamps");
+
+ yco -= YSPACE;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, MENU, B_TEXREDR_PRV, "Scattering Direction %t|Isotropic %x0|Mie Hazy %x1|Mie Murky %x2|Rayleigh %x3|Henyey-Greenstein %x4|Schlick %x5",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &ma->vol_phasefunc_type, 0.0, 0.0, 0, 0, "Scattering Direction (Phase Function)");
+ if (ELEM(ma->vol_phasefunc_type, MA_VOL_PH_HG, MA_VOL_PH_SCHLICK)) {
+ uiDefButF(block, NUM, B_MATPRV, "Asymmetry: ",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_phasefunc_g), -1.0, 1.0, 0, 0, "> 0 is forward scattering, < 0 is back scattering");
+ uiBlockEndAlign(block);
+ } else {
+ uiBlockEndAlign(block);
+ /* spacer */
+ uiDefBut(block, LABEL, B_NOP, "",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, "");
+ }
+
}
static void material_panel_nodes(Material *ma)