* Volume Rendering: Voxel data
authorMatt Ebb <matt@mke3.net>
Sat, 13 Dec 2008 05:41:34 +0000 (05:41 +0000)
committerMatt Ebb <matt@mke3.net>
Sat, 13 Dec 2008 05:41:34 +0000 (05:41 +0000)
This commit introduces a new texture ('Voxel Data'), used to load up saved voxel
data sets for rendering, contributed by Raúl 'farsthary' Fernández Hernández
with some additional tweaks. Thanks, Raúl!

The texture works similar to the existing point density texture, currently it
only provides intensity information, which can then be mapped (for example) to
density in a volume material. This is an early version, intended to read the
voxel format saved by Raúl's command line simulators, in future revisions
there's potential for making a more full-featured 'Blender voxel file format',
and also for supporting other formats too.

Note: Due to some subtleties in Raúl's existing released simulators, in  order
to load them correctly the voxel data texture, you'll need to raise the
'resolution' value by 2. So if you baked out the simulation at resolution 50,
enter 52 for the resolution in the texture panel. This can possibly be fixed in
the simulator later on.

Right now, the way the texture is mapped is just in the space 0,0,0 <-> 1,1,1
and it can appear rotated 90 degrees incorrectly. This will be tackled, for now,
probably the easiest way to map it is with and empty, using Map Input -> Object.

Smoke test: http://www.vimeo.com/2449270

One more note, trilinear interpolation seems a bit slow at the moment, we'll
look into this.

For curiosity, while testing/debugging this, I made a script that exports a mesh
to voxel data. Here's a test of grogan (www.kajimba.com) converted to voxels,
rendered as a volume: http://www.vimeo.com/2512028

The script is available here: http://mke3.net/projects/bpython/export_object_voxeldata.py

* Another smaller thing, brought back early ray termination (was disabled
previously for debugging) and made it user configurable. It now appears as a new
value in the volume material: 'Depth Cutoff'. For some background info on what
this does, check:
http://farsthary.wordpress.com/2008/12/11/cutting-down-render-times/

* Also some disabled work-in-progess code for light cache

15 files changed:
source/blender/blenkernel/BKE_texture.h
source/blender/blenkernel/intern/texture.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/include/butspace.h
source/blender/makesdna/DNA_material_types.h
source/blender/makesdna/DNA_texture_types.h
source/blender/render/intern/include/render_types.h
source/blender/render/intern/include/volume_precache.h
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/texture.c
source/blender/render/intern/source/volume_precache.c
source/blender/render/intern/source/volumetric.c
source/blender/src/butspace.c
source/blender/src/buttons_shading.c

index e16ac2d369b029d3c7f4c69b06be31336d538dcd..985094a7e622a458d4514e03a93b0cfda3a874e7 100644 (file)
@@ -40,6 +40,7 @@ struct HaloRen;
 struct TexMapping;
 struct EnvMap;
 struct PointDensity;
+struct VoxelData;
 
 /*  in ColorBand struct */
 #define MAXCOLORBAND 32
@@ -80,6 +81,11 @@ void    BKE_free_pointdensity(struct PointDensity *pd);
 struct PointDensity *BKE_add_pointdensity(void);
 struct PointDensity *BKE_copy_pointdensity(struct PointDensity *pd);
 
+void BKE_free_voxeldatadata(struct VoxelData *vd);
+void BKE_free_voxeldata(struct VoxelData *vd);
+struct VoxelData *BKE_add_voxeldata(void);
+struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd);
+
 int     BKE_texture_dependsOnTime(const struct Tex *texture);
 
 #endif
index c972d70d92793dc4e07f6fbd796d9fb3bb504be0..c9cae91da6fd7326ac93364f641803492c2b16cc 100644 (file)
@@ -420,6 +420,7 @@ void free_texture(Tex *tex)
        if(tex->coba) MEM_freeN(tex->coba);
        if(tex->env) BKE_free_envmap(tex->env);
        if(tex->pd) BKE_free_pointdensity(tex->pd);
+       if(tex->vd) BKE_free_voxeldata(tex->vd);
        BKE_previewimg_free(&tex->preview);
        BKE_icon_delete((struct ID*)tex);
        tex->id.icon_id = 0;
@@ -490,6 +491,11 @@ void default_tex(Tex *tex)
                tex->pd->radius = 0.3f;
                tex->pd->falloff_type = TEX_PD_FALLOFF_STD;
        }
+       
+       if (tex->vd) {
+               tex->vd->resolX=50;
+               tex->vd->interp_type=0;
+       }
 
        pit = tex->plugin;
        if (pit) {
@@ -588,6 +594,7 @@ Tex *copy_texture(Tex *tex)
        if(texn->coba) texn->coba= MEM_dupallocN(texn->coba);
        if(texn->env) texn->env= BKE_copy_envmap(texn->env);
        if(texn->pd) texn->pd= BKE_copy_pointdensity(texn->pd);
+       if(texn->vd) texn->vd=BKE_copy_voxeldata(texn->vd);
        
        if(tex->preview) texn->preview = BKE_previewimg_copy(tex->preview);
 
@@ -945,6 +952,48 @@ void BKE_free_pointdensity(PointDensity *pd)
        MEM_freeN(pd);
 }
 
+
+void BKE_free_voxeldatadata(struct VoxelData *vd)
+{
+       if (vd->dataset) {
+               MEM_freeN(vd->dataset);
+               vd->dataset = NULL;
+       }
+
+}
+void BKE_free_voxeldata(struct VoxelData *vd)
+{
+       BKE_free_voxeldatadata(vd);
+       MEM_freeN(vd);
+}
+struct VoxelData *BKE_add_voxeldata(void)
+{
+       VoxelData *vd;
+
+       vd= MEM_callocN(sizeof(struct VoxelData), "voxeldata");
+       vd->dataset = NULL;
+       vd->resolX = 1;
+       vd->resolY = 1;
+       vd->resolZ = 1;
+       vd->interp_type= TEX_VD_NEARESTNEIGHBOR;
+       vd->int_multiplier = 1.0;
+       
+       return vd;
+ }
+struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd)
+{
+       VoxelData *vdn;
+
+       vdn= MEM_dupallocN(vd); 
+       vdn->dataset = NULL;
+
+       return vdn;
+}
+
+
 /* ------------------------------------------------------------------------- */
 int BKE_texture_dependsOnTime(const struct Tex *texture)
 {
index 1fd766be256e1691a0c3f36b4fdff99fdf9a6ac0..8347920319a9380fccbee6e801753f4009656c75 100644 (file)
@@ -2535,6 +2535,11 @@ static void direct_link_texture(FileData *fd, Tex *tex)
                tex->pd->coba= newdataadr(fd, tex->pd->coba);
        }
        
+       tex->vd= newdataadr(fd, tex->vd);
+       if(tex->vd) {
+               tex->vd->dataset = NULL;
+       }
+       
        tex->nodetree= newdataadr(fd, tex->nodetree);
        if(tex->nodetree)
                direct_link_nodetree(fd, tex->nodetree);
@@ -7939,6 +7944,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                                ma->vol_density_scale = 1.0f;
                        if (ma->vol_precache_resolution == 0)
                                ma->vol_precache_resolution = 50;
+                       if (ma->vol_depth_cutoff < 0.0001)
+                               ma->vol_depth_cutoff = 0.05;
                }
                
                for(tex=main->tex.first; tex; tex= tex->id.next) {
@@ -7956,6 +7963,17 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                                tex->pd->coba = add_colorband(1);
                                tex->pd->speed_scale = 1.0f;
                        }
+                       
+                       if (tex->vd == NULL) {
+                               tex->vd = BKE_add_voxeldata();
+                       } else if (tex->vd->resolX == 0) {
+                               tex->vd->dataset = NULL;
+                               tex->vd->resolX = 1;
+                               tex->vd->resolY = 1;
+                               tex->vd->resolZ = 1;
+                               tex->vd->interp_type= TEX_VD_NEARESTNEIGHBOR;
+                               tex->vd->int_multiplier = 1.0;
+                       }
                }
                
        }
index 93bf8111c98a61d41fd1976d05719fb3eff4ed16..fd87080d0ee0577c50824918155447e0f4792918 100644 (file)
@@ -1339,6 +1339,7 @@ static void write_textures(WriteData *wd, ListBase *idbase)
                                writestruct(wd, DATA, "PointDensity", 1, tex->pd);
                                if(tex->pd->coba) writestruct(wd, DATA, "ColorBand", 1, tex->pd->coba);
                        }
+                       if(tex->vd) writestruct(wd, DATA, "VoxelData", 1, tex->vd);
                        
                        /* nodetree is integral part of texture, no libdata */
                        if(tex->nodetree) {
index fd3f6e926b9ec98badc464205632c5fc30dd6169..a3cd9d1875bc489ecd3f60bece1bf1c07a4c2025 100644 (file)
@@ -260,6 +260,8 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
 #define B_ENV_FREE_ALL 1357
 #define B_TEX_USENODES         1358
 
+#define B_VOXELDATA_LOAD       1359
+
 
 /* **************** animbuts = object buttons ******* */
 #define B_ANIMBUTS             1500
index f332537e9a89c87a265473a0ec14a4e8d8183e52..5172f6a970cb455edf0e8b0f5bfa92b0730dcac8 100644 (file)
@@ -69,6 +69,8 @@ typedef struct Material {
        short vol_stepsize_type;
        short vol_precache_resolution;
        float vol_stepsize, vol_shade_stepsize;
+       float vol_depth_cutoff;
+       float vpad;
        float vol_density_scale;
        float vol_absorption, vol_scattering;
        float vol_absorption_col[3];
index b4fcb5efe40b7f64008c5d29d2b293f25506f61a..e90df908c2ba65ea3cf8bcd3899dc99d6e228436 100644 (file)
@@ -154,7 +154,7 @@ typedef struct PointDensity {
        short noise_depth;
        short noise_influence;
        short noise_basis;
-       short pdpad3[3];
+    short pdpad3[3];
        float noise_fac;
        
        float speed_scale;
@@ -162,6 +162,18 @@ typedef struct PointDensity {
        
 } PointDensity;
 
+typedef struct VoxelData {
+       int resolX, resolY, resolZ;
+       int interp_type;
+
+       float int_multiplier;
+       float vxpad;
+       
+       char source_path[240];
+       float *dataset;
+} VoxelData;
+
 typedef struct Tex {
        ID id;
        
@@ -209,6 +221,7 @@ typedef struct Tex {
        struct EnvMap *env;
        struct PreviewImage * preview;
        struct PointDensity *pd;
+       struct VoxelData *vd;
        
        char use_nodes;
        char pad[7];
@@ -250,6 +263,7 @@ typedef struct TexMapping {
 #define TEX_DISTNOISE  13
 /* predicting ocean texture for 14 */
 #define TEX_POINTDENSITY       15
+#define TEX_VOXELDATA          16
 
 /* musgrave stype */
 #define TEX_MFRACTAL           0
@@ -465,5 +479,13 @@ typedef struct TexMapping {
 #define POINT_DATA_VEL         1
 #define POINT_DATA_LIFE                2
 
+/******************** Voxel Data *****************************/ 
+#define TEX_VD_CUBIC              0
+#define TEX_VD_PARALLELOGRAM      1
+#define TEX_VD_NEARESTNEIGHBOR         0
+#define TEX_VD_LINEAR                  1
+#define TEX_VD_TRICUBIC                                2
+
 #endif
 
index 6f4537d84fbb9ac43f74341554056bd2e4dc5a83..65bb12e059da74e9f767432250a14c0b1bcf7ed0 100644 (file)
@@ -203,6 +203,8 @@ struct Render
        struct Object *excludeob;
        
        ListBase vol_precache_obs;
+       ListBase render_volumes_inside;
+       ListBase volumes;
 
        /* arena for allocating data for use during render, for
                * example dynamic TFaces to go in the VlakRen structure.
@@ -409,6 +411,18 @@ typedef struct VolPrecache
        struct ObjectRen *obr;
 } VolPrecache;
 
+typedef struct VolumeOb
+{
+       struct VolumeOb *next, *prev;
+       struct Material *ma;
+       struct ObjectRen *obr;
+} VolumeOb;
+
+typedef struct MatInside {
+       struct MatInside *next, *prev;
+       struct Material *ma;
+} MatInside;
+
 /* ------------------------------------------------------------------------- */
 
 struct LampRen;
index 7a719840f48cc18b83f739c5b30b6cc512800153..78409e4c64698877849d318d2f28416e3e9cfdbc 100644 (file)
@@ -27,4 +27,5 @@
  */
  
 void volume_precache(Render *re);
-void free_volume_precache(Render *re);
\ No newline at end of file
+void free_volume_precache(Render *re);
+int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co);
\ No newline at end of file
index 09f2d1275f4e4e167ef743a1c1e61609db1cb008..d87ee65c42c07ac68043fa9f75699b4ce4775cee 100644 (file)
 #include "multires.h"
 #include "occlusion.h"
 #include "pointdensity.h"
+#include "voxeldata.h"
 #include "render_types.h"
 #include "rendercore.h"
 #include "renderdatabase.h"
@@ -3028,16 +3029,51 @@ static void use_mesh_edge_lookup(ObjectRen *obr, DerivedMesh *dm, MEdge *medge,
        }
 }
 
-static void add_vol_precache(Render *re, ObjectRen *obr, Material *ma)
+static void free_camera_inside_volumes(Render *re)
 {
-       struct VolPrecache *vp;
+       BLI_freelistN(&re->render_volumes_inside);
+}
+
+static void init_camera_inside_volumes(Render *re)
+{
+       ObjectInstanceRen *obi;
+       VolumeOb *vo;
+       float co[3] = {0.f, 0.f, 0.f};
+
+       for(vo= re->volumes.first; vo; vo= vo->next) {
+               for(obi= re->instancetable.first; obi; obi= obi->next) {
+                       if (obi->obr == vo->obr) {
+                               if (point_inside_volume_objectinstance(obi, co)) {
+                                       MatInside *mi;
+                                       
+                                       mi = MEM_mallocN(sizeof(MatInside), "camera inside material");
+                                       mi->ma = vo->ma;
+                                       
+                                       BLI_addtail(&(re->render_volumes_inside), mi);
+                               }
+                       }
+               }
+       }
+       
+       {
+       MatInside *m;
+       for (m=re->render_volumes_inside.first; m; m=m->next) {
+               printf("matinside: ma: %s \n", m->ma->id.name+2);
+       }
        
-       vp = MEM_mallocN(sizeof(VolPrecache), "volume precache object");
+       }
+}
+
+static void add_volume(Render *re, ObjectRen *obr, Material *ma)
+{
+       struct VolumeOb *vo;
        
-       vp->ma = ma;
-       vp->obr = obr;
+       vo = MEM_mallocN(sizeof(VolumeOb), "volume object");
        
-       BLI_addtail(&re->vol_precache_obs, vp);
+       vo->ma = ma;
+       vo->obr = obr;
+       
+       BLI_addtail(&re->volumes, vo);
 }
 
 static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
@@ -3095,9 +3131,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                                if(ma->mode & MA_RADIO) 
                                        do_autosmooth= 1;
                        
-                       if ((ma->material_type == MA_VOLUME) && (ma->vol_shadeflag & MA_VOL_PRECACHESHADING)) {
-                               add_vol_precache(re, obr, ma);
-                       }
+                       if (ma->material_type == MA_VOLUME)
+                               add_volume(re, obr, ma);
                }
        }
 
@@ -4457,6 +4492,9 @@ void RE_Database_Free(Render *re)
        end_render_textures();
        
        free_pointdensities(re);
+       free_voxeldata(re);
+       
+       free_camera_inside_volumes(re);
        
        if(re->wrld.aosphere) {
                MEM_freeN(re->wrld.aosphere);
@@ -4861,6 +4899,8 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
 
        /* MAKE RENDER DATA */
        database_init_objects(re, lay, 0, 0, 0, 0);
+       
+       init_camera_inside_volumes(re);
 
        if(!re->test_break()) {
                int tothalo;
@@ -4912,6 +4952,9 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
                        /* point density texture */
                        if(!re->test_break())
                                make_pointdensities(re);
+                       /* voxel data texture */
+                       if(!re->test_break())
+                               make_voxeldata(re);//Volumetrics
                }
                
                if(!re->test_break())
index d7d4d124b18978e917bc34789876f4790fa72e6c..d7b41d7cc2c26828f0e6f99432c4d1be8aab77f9 100644 (file)
@@ -65,6 +65,7 @@
 
 #include "envmap.h"
 #include "pointdensity.h"
+#include "voxeldata.h"
 #include "renderpipeline.h"
 #include "render_types.h"
 #include "rendercore.h"
@@ -1257,6 +1258,10 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex,
        case TEX_POINTDENSITY:
                retval= pointdensitytex(tex, texvec, texres);
                break;
+       case TEX_VOXELDATA:
+               retval= voxeldatatex(tex, texvec, texres);  
+               break;
+
        }
 
        if (tex->flag & TEX_COLORBAND) {
index 246f9bc6d695ea09064f7783ff21f1b3ae4750b5..89f997f4b99ebad03937a665c57ea13ebae05361 100644 (file)
@@ -400,7 +400,7 @@ static void *vol_precache_part(void *data)
        return 0;
 }
 
-void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi)
+static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi)
 {
        float view[3] = {0.0,0.0,-1.0};
        
@@ -417,6 +417,34 @@ void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma,
        VECCOPY(shi->view, view);
 }
 
+static void precache_init_parts(ListBase *precache_parts, RayTree *tree, ShadeInput *shi, ObjectInstanceRen *obi, float *bbmin, float *bbmax, int res)
+{
+       int i;
+       float voxel[3];
+
+       VecSubf(voxel, bbmax, bbmin);
+       if ((voxel[0] < FLT_EPSILON) || (voxel[1] < FLT_EPSILON) || (voxel[2] < FLT_EPSILON))
+               return;
+       VecMulf(voxel, 1.0f/res);
+
+       for(i=0; i < totparts; i++) {
+               VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part");
+       
+               pa->done = 0;
+               pa->num = i;
+               
+               pa->res = res;
+               VECCOPY(pa->bbmin, bbmin);
+               VECCOPY(precache_parts[j].voxel, voxel);
+               precache_parts[j].tree = tree;
+               precache_parts[j].shi = shi;
+               precache_parts[j].obi = obi;
+               
+               BLI_addtail(precache_parts, pa);
+       }
+       
+}
+
 void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma, float *bbmin, float *bbmax)
 {
        int x, y, z;
@@ -431,13 +459,12 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat
        int res_2, res_3;
        
        int edgeparts=2;
-       int totparts;
-       ListBase threads;
+       ListBase threads, precache_parts;
        int cont= 1;
        int xparts, yparts, zparts;
        float part[3];
        int totthread = re->r.threads;
-       ListBase precache_parts;
+       int totparts = edgeparts*edgeparts*edgeparts;
        VolPrecachePart *nextpa;
        int j;
        
@@ -452,41 +479,13 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat
         * used for checking if the cached point is inside or outside. */
        tree = create_raytree_obi(obi, bbmin, bbmax);
        if (!tree) return;
-
-       /* Need a shadeinput to calculate scattering */
-       precache_setup_shadeinput(re, obi, ma, &shi);
-
-       VecSubf(voxel, bbmax, bbmin);
-       if ((voxel[0] < FLT_EPSILON) || (voxel[1] < FLT_EPSILON) || (voxel[2] < FLT_EPSILON))
-               return;
-       VecMulf(voxel, 1.0f/res);
-       
-       part[0] = ceil(res/(float)xparts); 
-       part[1] = ceil(res/(float)yparts);
-       part[2] = ceil(res/(float)zparts);
        
        obi->volume_precache = MEM_callocN(sizeof(float)*res_3*3, "volume light cache");
-       
-       totparts = edgeparts*edgeparts*edgeparts;
-       precache_parts= MEM_callocN(sizeof(VolPrecachePart)*totparts, "VolPrecachePart");
-       memset(precache_parts, 0, sizeof(VolPrecachePart)*totparts);
 
-       precache_init_parts(precache_parts);
+       /* Need a shadeinput to calculate scattering */
+       precache_setup_shadeinput(re, obi, ma, &shi);
+       precache_init_parts(&precache_parts, tree, shi, obi, bbmin, bbmax, res);
 
-       for(j=0; j < totparts; j++) {
-               VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part");
-       
-               pa->done = 0;
-               pa->num = j;
-               
-               pa->res = res;
-               VECCOPY(pa->bbmin, bbmin);
-               VECCOPY(precache_parts[j].voxel, voxel);
-               precache_parts[j].tree = tree;
-               precache_parts[j].shi = shi;
-               precache_parts[j].obi = obi;
-       }
-       
        BLI_init_threads(&threads, vol_precache_part, totthread);
        
        nextpa = precache_get_new_part(precache_threads);
@@ -600,12 +599,15 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat
 void volume_precache(Render *re)
 {
        ObjectInstanceRen *obi;
-       VolPrecache *vp;
+       VolumeOb *vo;
 
-       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) 
-                               vol_precache_objectinstance(re, obi, vp->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]);
+       for(vo= re->volumes.first; vo; vo= vo->next) {
+               if (vo->ma->vol_shadeflag & MA_VOL_PRECACHESHADING) {
+                       for(obi= re->instancetable.first; obi; obi= obi->next) {
+                               if (obi->obr == vo->obr) {
+                                       vol_precache_objectinstance(re, obi, vo->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]);
+                               }
+                       }
                }
        }
        
@@ -624,3 +626,19 @@ void free_volume_precache(Render *re)
        
        BLI_freelistN(&re->vol_precache_obs);
 }
+
+int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co)
+{
+       RayTree *tree;
+       int inside=0;
+       
+       tree = create_raytree_obi(obi, obi->obr->boundbox[0], obi->obr->boundbox[1]);
+       if (!tree) return 0;
+       
+       inside = point_inside_obi(tree, obi, co);
+       
+       RE_ray_tree_free(tree);
+       tree= NULL;
+       
+       return inside;
+}
index 45d54d40fa1554cb41aab94bd59d9ee7ed07c3f3..fba847da2adeffb387c1823167c1c6480ac56ce5 100644 (file)
@@ -21,7 +21,7 @@
  *
  * The Original Code is: all of this file.
  *
- * Contributor(s): Matt Ebb, Raul Hernandez.
+ * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary)
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -134,6 +134,11 @@ float vol_get_stepsize(struct ShadeInput *shi, int context)
        return shi->mat->vol_stepsize;
 }
 
+static float vol_get_depth_cutoff(struct ShadeInput *shi)
+{
+       return shi->mat->vol_depth_cutoff;
+}
+
 /* SHADING */
 
 static float D(ShadeInput *shi, int rgb, int x, int y, int z)
@@ -278,7 +283,7 @@ float vol_get_phasefunc(ShadeInput *shi, short phasefunc_type, float g, float *w
 void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co)
 {
        float dummy = 1.0f;
-       float absorption = shi->mat->vol_absorption;
+       const float absorption = shi->mat->vol_absorption;
        
        VECCOPY(absorb_col, shi->mat->vol_absorption_col);
        
@@ -296,14 +301,13 @@ void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co)
 void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, float density, float stepsize)
 {
        /* input density = density at co */
-       float dist;
        float absorb_col[3];
        int s, nsteps;
        float step_vec[3], step_sta[3], step_end[3];
+       const float dist = VecLenf(co, endco);
 
        vol_get_absorption(shi, absorb_col, co);
 
-       dist = VecLenf(co, endco);
        nsteps = (int)((dist / stepsize) + 0.5);
        
        /* trigger for recalculating density */
@@ -468,6 +472,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float
        float tau[3], emit_col[3], scatter_col[3] = {0.0, 0.0, 0.0};
        float stepvec[3], step_sta[3], step_end[3], step_mid[3];
        float density = vol_get_density(shi, co);
+       const float depth_cutoff = vol_get_depth_cutoff(shi);
        
        /* multiply col_behind with beam transmittance over entire distance */
        vol_get_attenuation(shi, tau, co, endco, density, stepsize);
@@ -524,6 +529,9 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float
 
                VecCopyf(step_sta, step_end);
                VecAddf(step_end, step_end, stepvec);
+               
+               /* luminance rec. 709 */
+               if ((0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]) < depth_cutoff) break; 
        }
        
        VecCopyf(col, radiance);
index 2ca709184c5118f1488687ee9c04580a6f5d42b8..6d8f806d8f97e3854399cab5faa6bb0eaf5c87a0 100644 (file)
@@ -92,7 +92,7 @@ MTex mtexcopybuf;
 
 char texstr[20][12]= {"None"  , "Clouds" , "Wood", "Marble", "Magic"  , "Blend",
                                         "Stucci", "Noise"  , "Image", "Plugin", "EnvMap" , "Musgrave",
-                                        "Voronoi", "DistNoise", "", "PointDensity", "", "", "", ""};
+                                        "Voronoi", "DistNoise", "", "PointDensity", "VoxelData", "", "", ""};
 /*  ---------------------------------------------------------------------- */
 
 void test_idbutton_cb(void *namev, void *arg2)
index a8aa00370d9fee25c87073cf8e454676b40d03cb..6e69414fbe0873f7c6e3a240ea15cb366d6c332b 100644 (file)
@@ -264,6 +264,19 @@ static int vergcband(const void *a1, const void *a2)
        return 0;
 }
 
+static void voxeldata_filename(char *str, void *tex_v, void *unused)   /* called from fileselect */
+{
+       Tex *tex= tex_v;
+       
+       if(tex->type!=TEX_VOXELDATA) return;
+       
+       strcpy(tex->vd->source_path, str);
+       
+       allqueue(REDRAWBUTSSHADING, 0);
+       BIF_preview_changed(ID_TE);
+       BIF_undo_push("Open voxel data source");
+}
+
 void do_texbuts(unsigned short event)
 {
        Tex *tex;
@@ -425,7 +438,25 @@ void do_texbuts(unsigned short event)
                allqueue(REDRAWBUTSSHADING, 0);
                allqueue(REDRAWIPO, 0);
                break;
+       
+       case B_VOXELDATA_LOAD:
+               if (tex->vd==NULL) {
+                       tex->vd= BKE_add_voxeldata();
+#ifdef _WIN32
+                       if (strcmp (U.textudir, "/") == 0)
+                               strcpy(str, G.sce);
+                       else
+                               strcpy(str, U.textudir);
+#else
+                       strcpy(str, U.textudir);
+#endif
+               }
+               else strcpy(str, tex->vd->source_path);
                
+               sa= closest_bigger_area();
+               areawinset(sa->win);
+               activate_fileselect_args(FILE_SPECIAL, "Open Voxel Data", str, voxeldata_filename, tex, NULL);
+               break;
        default:
                if(event>=B_PLUGBUT && event<=B_PLUGBUT+23) {
                        PluginTex *pit= tex->plugin;
@@ -1016,6 +1047,48 @@ static void texture_panel_pointdensity_modify(Tex *tex)
 
 }
 
+static void texture_panel_voxeldata(Tex *tex)
+{
+       uiBlock *block;
+       VoxelData *vd;
+       short yco=PANEL_YMAX;
+
+       block= uiNewBlock(&curarea->uiblocks, "texture_panel_voxeldata", UI_EMBOSS, UI_HELV, curarea->win);
+       if(uiNewPanel(curarea, block, "Voxel Data", "Texture", PANELX, PANELY, PANELW, PANELH)==0) return;
+       uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+       if(tex->vd==NULL) {
+               tex->vd= BKE_add_voxeldata();
+       }
+
+       if(tex->vd) {
+               vd= tex->vd;
+               
+               uiDefBut(block, LABEL, B_NOP, "Data source:",
+                       X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, "");
+                       
+               uiDefIconTextBut(block, BUT, B_VOXELDATA_LOAD, ICON_FILESEL, "Open",
+                       X4CLM1, yco-=BUTH, BUTW4, BUTH, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, TEX, 0, "",
+                       X4CLM2+XSPACE, yco, BUTW2+BUTW4+2*XSPACE, BUTH, &vd->source_path, 0.0, 79.0, 0, 0, "File path to the voxel data set");
+
+               yco -= YSPACE;
+               
+               uiDefBut(block, LABEL, B_NOP, "Interpolation:",
+                       X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, "");
+               uiDefButI(block, MENU, B_REDR, "None %x0|Linear %x1|Tricubic %x2",
+                       X2CLM1, yco-=BUTH, BUTW2, BUTH, &vd->interp_type, 0.0, 0.0, 0, 0, "Interpolation type");                
+               
+               uiDefButI(block, NUM, B_REDR, "Resolution: ",
+                       X2CLM2, yco, BUTW2, BUTH, &(vd->resolX), 1, 10000, 0, 0, "Resolution of the voxel data");
+                       
+               yco -= YSPACE;
+               
+               uiDefButF(block, NUM, B_REDR, "Intensity: ",
+                       X2CLM1, yco-=BUTH, BUTW2, BUTH, &(vd->int_multiplier), 0.0001, 10000.0, 0, 0, "Multiplier to scale up or down the texture's intensity");
+       }
+}
+
 static char *layer_menu(RenderResult *rr, short *curlay)
 {
        RenderLayer *rl;
@@ -1865,7 +1938,7 @@ static void texture_panel_texture(MTex *actmtex, Material *ma, World *wrld, Lamp
                /* newnoise: all texture types as menu, not enough room for more buttons.
                 * Can widen panel, but looks ugly when other panels overlap it */
                if( !tex->use_nodes ) {
-                       sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d|Point Density %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE, TEX_POINTDENSITY);
+                       sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d|Point Density %%x%d|Voxel Data %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE, TEX_POINTDENSITY, TEX_VOXELDATA);
                        uiDefBut(block, LABEL, 0, "Texture Type",               160, 150, 140, 20, 0, 0.0, 0.0, 0, 0, "");
                        uiDefButS(block, MENU, B_TEXTYPE, textypes,     160, 125, 140, 25, &tex->type, 0,0,0,0, "Select texture type");
                }
@@ -4449,6 +4522,8 @@ static void material_panel_material_volume(Material *ma)
                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, randomized replaces banding with jittering");
+       uiDefButF(block, NUM, B_MATPRV, "Depth Cutoff: ",
+               X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_depth_cutoff), 0.001, 1.0, 10, 2, "Stop ray marching early if transmission drops below this luminance - higher values give speedups in dense volumes at the expense of accuracy ");
        uiBlockEndAlign(block);
        
        yco -= YSPACE;
@@ -4921,6 +4996,9 @@ void texture_panels()
                                texture_panel_pointdensity(tex);
                                texture_panel_pointdensity_modify(tex);
                                break;
+                       case TEX_VOXELDATA:
+                               texture_panel_voxeldata(tex);
+                               break;
                        }
                }
        }