From 7522f86d010e600e17e82f98364235e96df21c1e Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 22 Sep 2008 01:51:24 +0000 Subject: [PATCH 01/88] * Volume rendering This is an initial commit to get it in SVN and make it easier to work on. Don't expect it to work perfectly, it's still in development and there's plenty of work still needing to be done. And so no I'm not very interested in hearing bug reports or feature requests at this stage :) There's some info on this, and a todo list at: http://mke3.net/weblog/volume-rendering/ Right now I'm trying to focus on getting shading working correctly (there's currently a problem in which 'surfaces' of the volume facing towards or away from light sources are getting shaded differently to how they should be), then I'll work on integration issues, like taking materials behind the volume into account, blending with alpha, etc. You can do simple testing though, mapping textures to density or emission on a cube with volume material. --- source/blender/blenkernel/intern/material.c | 5 + source/blender/blenlib/BLI_arithb.h | 1 + source/blender/blenlib/intern/arithb.c | 13 + source/blender/blenloader/intern/readfile.c | 10 + source/blender/makesdna/DNA_material_types.h | 21 + .../blender/render/intern/include/shading.h | 2 + .../blender/render/intern/include/texture.h | 1 + .../render/intern/include/volumetric.h | 29 ++ .../render/intern/source/convertblender.c | 2 + .../blender/render/intern/source/shadeinput.c | 9 +- .../render/intern/source/shadeoutput.c | 2 +- source/blender/render/intern/source/texture.c | 135 ++++++ .../blender/render/intern/source/volumetric.c | 400 ++++++++++++++++++ source/blender/src/buttons_shading.c | 145 +++++-- source/blender/src/previewrender.c | 2 + 15 files changed, 730 insertions(+), 47 deletions(-) create mode 100644 source/blender/render/intern/include/volumetric.h create mode 100644 source/blender/render/intern/source/volumetric.c diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index f05b84f6e90..5c20858ec63 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -166,6 +166,11 @@ void init_material(Material *ma) ma->sss_texfac= 0.0f; ma->sss_front= 1.0f; ma->sss_back= 1.0f; + + ma->vol_stepsize = 0.2f; + ma->vol_shade_stepsize = 0.2f; + ma->vol_absorption = 1.0f; + ma->vol_scattering = 1.0f; ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RADIO|MA_RAYBIAS|MA_TANGENT_STR; diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h index 6e54fae58d0..0a9abc34608 100644 --- a/source/blender/blenlib/BLI_arithb.h +++ b/source/blender/blenlib/BLI_arithb.h @@ -250,6 +250,7 @@ void printvec4f(char *str, float v[4]); void VecAddf(float *v, float *v1, float *v2); void VecSubf(float *v, float *v1, float *v2); +void VecMulVecf(float *v, float *v1, float *v2); void VecLerpf(float *target, float *a, float *b, float t); void VecMidf(float *v, float *v1, float *v2); diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index f89f90f7045..f311c30e0c7 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -2126,6 +2126,13 @@ void VecSubf(float *v, float *v1, float *v2) v[2]= v1[2]- v2[2]; } +void VecMulVecf(float *v, float *v1, float *v2) +{ + v[0] = v1[0] * v2[0]; + v[1] = v1[1] * v2[1]; + v[2] = v1[2] * v2[2]; +} + void VecLerpf(float *target, float *a, float *b, float t) { float s = 1.0f-t; @@ -3269,6 +3276,12 @@ float Normalize2(float *n) return d; } +float rgb_to_luminance(float r, float g, float b) +{ + /* Rec. 709 HDTV */ + return (0.2126*r + 0.7152*g + 0.0722*b); +} + void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b) { int i; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f3f1a99cdbf..a1d50b618d1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7681,6 +7681,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 11)) { Object *ob; bActionStrip *strip; + /* nla-strips - scale */ for (ob= main->object.first; ob; ob= ob->id.next) { @@ -7704,12 +7705,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main) ob->soft->shearstiff = 1.0f; } } + } if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 14)) { Scene *sce= main->scene.first; Sequence *seq; Editing *ed; + Material *ma; while(sce) { ed= sce->ed; @@ -7724,6 +7727,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main) sce= sce->id.next; } + + for(ma=main->mat.first; ma; ma= ma->id.next) { + if (ma->vol_shade_stepsize < 0.001f) ma->vol_shade_stepsize = 0.2f; + if (ma->vol_stepsize < 0.001f) ma->vol_stepsize = 0.2f; + if (ma->vol_absorption < 0.001f) ma->vol_absorption = 1.0f; + if (ma->vol_scattering < 0.001f) ma->vol_scattering = 1.0f; + } } /*fix broken group lengths in id properties*/ diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index c92a33bbcbb..940f57c1ebc 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -62,6 +62,16 @@ typedef struct Material { float translucency; /* end synced with render_types.h */ + short material_type; /* solid, halo, volumetric */ + short pad5[3]; + + /* volumetrics */ + float vol_alphathresh; + float vol_stepsize, vol_shade_stepsize; + float vol_absorption, vol_scattering; + short vol_shadeflag; + short vpad; + float fresnel_mir, fresnel_mir_i; float fresnel_tra, fresnel_tra_i; float filter; /* filter added, for raytrace transparency and transmissivity */ @@ -154,6 +164,12 @@ typedef struct Material { /* for render */ #define MA_IS_USED 1 +/* material_type */ +#define MA_SOLID 0 +#define MA_PTHALO 1 +#define MA_VOLUME 2 +#define MA_VOLUMESOLID 3 + /* mode (is int) */ #define MA_TRACEBLE 1 #define MA_SHADOW 2 @@ -327,5 +343,10 @@ typedef struct Material { /* sss_flag */ #define MA_DIFF_SSS 1 +/* vol_shadeflag */ +#define MA_VOL_SHADED 1 +#define MA_VOL_ATTENUATED 2 +#define MA_VOL_SHADOWED 4 + #endif diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h index 6f1cb8dd7a9..9229e612337 100644 --- a/source/blender/render/intern/include/shading.h +++ b/source/blender/render/intern/include/shading.h @@ -52,6 +52,7 @@ typedef struct ShadeSample { /* also the node shader callback */ void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr); +void shade_volume_loop(struct ShadeInput *shi, struct ShadeResult *shr); void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3); void shade_input_set_triangle(struct ShadeInput *shi, volatile int obi, volatile int facenr, int normal_flip); @@ -85,6 +86,7 @@ void shade_color(struct ShadeInput *shi, ShadeResult *shr); void ambient_occlusion_to_diffuse(struct ShadeInput *shi, float *diff); void ambient_occlusion(struct ShadeInput *shi); +ListBase *get_lights(struct ShadeInput *shi); float lamp_get_visibility(struct LampRen *lar, float *co, float *lv, float *dist); void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real); diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h index 8e56c4a852f..08c4ee5df98 100644 --- a/source/blender/render/intern/include/texture.h +++ b/source/blender/render/intern/include/texture.h @@ -56,6 +56,7 @@ void do_halo_tex(struct HaloRen *har, float xn, float yn, float *colf); void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend, int skyflag); void do_material_tex(struct ShadeInput *shi); void do_lamp_tex(LampRen *la, float *lavec, struct ShadeInput *shi, float *colf); +void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *alpha, float *emit); void init_render_textures(Render *re); diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h new file mode 100644 index 00000000000..8db3fa63f98 --- /dev/null +++ b/source/blender/render/intern/include/volumetric.h @@ -0,0 +1,29 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Farsthary (Raul FHernandez), Matt Ebb. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr); \ No newline at end of file diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 322d2066a6c..48855246e87 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1029,6 +1029,8 @@ static Material *give_render_material(Render *re, Object *ob, int nr) if(ma->nodetree && ma->use_nodes) flag_render_node_material(re, ma->nodetree); + if (ma->material_type == MA_VOLUME) re->r.mode |= R_RAYTRACE; + return ma; } diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 7397d623264..cd5ecc413df 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -135,6 +135,12 @@ void shade_material_loop(ShadeInput *shi, ShadeResult *shr) } } +/* delivers a fully filled in ShadeResult, for all passes */ +void shade_volume_loop(ShadeInput *shi, ShadeResult *shr) +{ + if(R.r.mode & R_RAYTRACE) volume_trace(shi, shr); +} + /* do a shade, finish up some passes, apply mist */ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) @@ -151,7 +157,8 @@ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); shi->har= shi->mat->har; - shade_material_loop(shi, shr); + if (shi->mat->material_type == MA_SOLID) shade_material_loop(shi, shr); + else if (shi->mat->material_type == MA_VOLUME) shade_volume_loop(shi, shr); } /* copy additional passes */ diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index 5a80173d1f1..4f7c26614e9 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -58,7 +58,7 @@ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -static ListBase *get_lights(ShadeInput *shi) +ListBase *get_lights(ShadeInput *shi) { if(shi->light_override) diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 27628d91465..37778fafeb3 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1451,6 +1451,141 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen return in; } +void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *alpha, float *emit) +{ + MTex *mtex; + Tex *tex; + TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL}; + int tex_nr, rgbnor= 0; + float co[3], texvec[3]; + float fact, stencilTin=1.0; + + if (R.r.scemode & R_NO_TEX) return; + /* here: test flag if there's a tex (todo) */ + + for(tex_nr=0; tex_nrmat->septex & (1<mat->mtex[tex_nr]) { + mtex= shi->mat->mtex[tex_nr]; + tex= mtex->tex; + if(tex==0) continue; + + /* which coords */ + if(mtex->texco==TEXCO_OBJECT) { + Object *ob= mtex->object; + ob= mtex->object; + if(ob) { + VECCOPY(co, xyz); + if(mtex->texflag & MTEX_OB_DUPLI_ORIG) { + if(shi->obi && shi->obi->duplitexmat) + MTC_Mat4MulVecfl(shi->obi->duplitexmat, co); + } + MTC_Mat4MulVecfl(ob->imat, co); + } + } + else if(mtex->texco==TEXCO_GLOB) { + VECCOPY(co, xyz); + } + else continue; // can happen when texco defines disappear and it renders old files + + texres.nor= NULL; + + if(tex->type==TEX_IMAGE) { + continue; /* not supported yet */ + } + else { + /* placement */ + if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]); + else texvec[0]= mtex->size[0]*(mtex->ofs[0]); + + if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]); + else texvec[1]= mtex->size[1]*(mtex->ofs[1]); + + if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]); + else texvec[2]= mtex->size[2]*(mtex->ofs[2]); + } + + + rgbnor= multitex(tex, co, NULL, NULL, 0, &texres); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */ + + /* texture output */ + + if( (rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) { + texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb); + rgbnor-= TEX_RGB; + } + if(mtex->texflag & MTEX_NEGATIVE) { + if(rgbnor & TEX_RGB) { + texres.tr= 1.0-texres.tr; + texres.tg= 1.0-texres.tg; + texres.tb= 1.0-texres.tb; + } + texres.tin= 1.0-texres.tin; + } + if(mtex->texflag & MTEX_STENCIL) { + if(rgbnor & TEX_RGB) { + fact= texres.ta; + texres.ta*= stencilTin; + stencilTin*= fact; + } + else { + fact= texres.tin; + texres.tin*= stencilTin; + stencilTin*= fact; + } + } + + + if(mtex->mapto & (MAP_COL)) { + float tcol[3], colfac; + + /* stencil maps on the texture control slider, not texture intensity value */ + colfac= mtex->colfac*stencilTin; + + tcol[0]=texres.tr; tcol[1]=texres.tg; tcol[2]=texres.tb; + + if((rgbnor & TEX_RGB)==0) { + tcol[0]= mtex->r; + tcol[1]= mtex->g; + tcol[2]= mtex->b; + } + else if(mtex->mapto & MAP_ALPHA) { + texres.tin= stencilTin; + } + else texres.tin= texres.ta; + + if(mtex->mapto & MAP_COL) { + texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype); + } + } + + if(mtex->mapto & MAP_VARS) { + /* stencil maps on the texture control slider, not texture intensity value */ + float varfac= mtex->varfac*stencilTin; + + if(rgbnor & TEX_RGB) { + if(texres.talpha) texres.tin= texres.ta; + else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb); + } + + if(mtex->mapto & MAP_EMIT) { + int flip= mtex->maptoneg & MAP_EMIT; + + *emit = texture_value_blend(mtex->def_var, *emit, texres.tin, varfac, mtex->blendtype, flip); + if(*emit<0.0) *emit= 0.0; + } + if(mtex->mapto & MAP_ALPHA) { + int flip= mtex->maptoneg & MAP_ALPHA; + + *alpha = texture_value_blend(mtex->def_var, *alpha, texres.tin, varfac, mtex->blendtype, flip); + CLAMP(*alpha, 0.0, 1.0); + } + } + } + } +} void do_material_tex(ShadeInput *shi) { diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c new file mode 100644 index 00000000000..3ca8c0a0693 --- /dev/null +++ b/source/blender/render/intern/source/volumetric.c @@ -0,0 +1,400 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Farsthary (Raul FHernandez), Matt Ebb. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "RE_shader_ext.h" +#include "RE_raytrace.h" + +#include "DNA_material_types.h" +#include "DNA_group_types.h" +#include "DNA_lamp_types.h" + +#include "render_types.h" +#include "shading.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) +{ + VlakRen *vlr = (VlakRen *)face; + + /* only consider faces away, so overlapping layers + * of foward facing geometry don't cause the ray to stop */ + return (INPR(is->vec, vlr->n) < 0.0f); +} + +#define VOL_IS_SAMEOBJECT 1 +#define VOL_IS_SAMEMATERIAL 2 + +int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco) +{ + /* 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; + + isect.mode= RE_RAY_MIRROR; + isect.faceorig= (RayFace*)shi->vlr; + 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)) + { + 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]; + + return 1; + } else { + return 0; + } +} + +float vol_get_density(struct ShadeInput *shi, float *co) +{ + float density = shi->mat->alpha; + float emit_fac=0.0f; + float col[3] = {0.0, 0.0, 0.0}; + + /* do any density gain stuff here */ + + do_volume_tex(shi, co, col, &density, &emit_fac); + + return density; +} + + +/* compute emission component, amount of radiance to add per segment + * can be textured with 'emit' */ +void vol_get_emission(ShadeInput *shi, float *em, float *co, float *endco, float density) +{ + float emission = shi->mat->emit; + float col[3] = {0.0, 0.0, 0.0}; + float dens_dummy = 1.0f; + + do_volume_tex(shi, co, col, &dens_dummy, &emission); + + em[0] = em[1] = em[2] = emission; +} + + +/* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau. + * Used in the relationship Transmittance = e^(-attenuation) + * can be textured with 'alpha' */ +void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, float density, float stepsize) +{ + /* input density = density at co */ + + float dist; + float absorption = shi->mat->vol_absorption; + int s, nsteps; + float step_vec[3], step_sta[3], step_end[3]; + + dist = VecLenf(co, endco); + + nsteps = (int)ceil(dist / stepsize); + + if (nsteps == 1) { + /* homogenous volume within the sampled distance */ + tau[0] = tau[1] = tau[2] = dist * density; + VecMulf(tau, absorption); + return; + } else { + tau[0] = tau[1] = tau[2] = 0.0; + } + + VecSubf(step_vec, endco, co); + VecMulf(step_vec, 1.0f / nsteps); + + VECCOPY(step_sta, co); + VecAddf(step_end, step_sta, step_vec); + + for (s = 0; s < nsteps; s++) { + + if (s > 0) density = vol_get_density(shi, step_sta); + + tau[0] += stepsize * density; + tau[1] += stepsize * density; + tau[2] += stepsize * density; + + if (s < nsteps-1) { + VECCOPY(step_sta, step_end); + VecAddf(step_end, step_end, step_vec); + } + } + VecMulf(tau, absorption); +} + +void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *col, float stepsize, float density) +{ + float visifac, lv[3], lampdist; + float lacol[3]; + float tau[3], tr[3]={1.0,1.0,1.0}; + float hitco[3], *atten_co; + + if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; + if ((lar->lay & shi->lay)==0) return; + if (lar->energy == 0.0) return; + + visifac= lamp_get_visibility(lar, co, lv, &lampdist); + if(visifac==0.0f) return; + + lacol[0] = lar->r; + lacol[1] = lar->g; + lacol[2] = lar->b; + + if(lar->mode & LA_TEXTURE) { + shi->osatex= 0; + do_lamp_tex(lar, lv, shi, lacol); + } + + VecMulf(lacol, visifac*lar->energy); + + if (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED) { + /* find minimum of volume bounds, or lamp coord */ + + if (ELEM(lar->type, LA_SUN, LA_HEMI)) + VECCOPY(lv, lar->vec); + + VecMulf(lv, -1.0f); + + if (vol_get_bounds(shi, co, lv, hitco)) { + if (ELEM(lar->type, LA_SUN, LA_HEMI)) + atten_co = hitco; + else if ( lampdist < VecLenf(co, hitco) ) + atten_co = lar->co; + else + atten_co = hitco; + + atten_co = lar->co; + + vol_get_attenuation(shi, tau, co, atten_co, density, shi->mat->vol_shade_stepsize); + tr[0] = exp(-tau[0]); + tr[1] = exp(-tau[1]); + tr[2] = exp(-tau[2]); + + VecMulVecf(lacol, lacol, tr); + } + else { + /* point is on the outside edge of the volume, + * therefore no attenuation, full transmission + * radiance from lamp remains unchanged */ + } + } + + VecAddf(col, col, lacol); +} + +/* shadows -> trace a ray to find blocker geometry + - if blocker is outside the volume, use standard shadow functions + - if blocker is inside the volume, use raytracing + -- (deep shadow maps could potentially slot in here too I suppose) + - attenuate from current point, to blocked point or volume bounds +*/ + +/* single scattering only for now */ +void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float *endco, 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) + { + float lacol[3] = {0.f, 0.f, 0.f}; + + lar= go->lampren; + if (lar==NULL) continue; + + vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density); + + /* isotropic phase function */ + VecMulf(lacol, 1.0f / (4.f * M_PI)); + + VecMulf(lacol, density); + + VecAddf(col, col, lacol); + } + + + + VECCOPY(scatter, col); +} + + + +static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco) +{ + float total_tau; + float total_tr[3]; + float tr[3] = {1.f, 1.f, 1.f}; /* 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}; + int s; + float step_sta[3], step_end[3], step_offs[3] = {0.0, 0.0, 0.0}; + float alpha_fac, emit_fac=0.0f, tex_col[3]; + + /* 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); +*/ + + /* ray marching */ + nsteps = (int)ceil(VecLenf(co, endco) / stepsize); + + VecSubf(vec, endco, co); + VECCOPY(stepvec, vec); + VecMulf(stepvec, 1.0f / nsteps); + + 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); + + /* *** 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]); + + /* Terminate raymarching if transmittance is small */ + //if (rgb_to_luminance(tr[0], tr[1], tr[2]) < 1e-3) break; + + /* incoming light via emission or scattering (additive) */ + vol_get_emission(shi, step_emit, step_sta, step_end, density); + vol_get_scattering(shi, step_scatter, step_end, step_end, stepsize, density); + + VecAddf(d_radiance, step_emit, step_scatter); + + /* Lv += Tr * (Lve() + Ld) */ + VecMulVecf(d_radiance, tr, d_radiance); + VecAddf(radiance, radiance, d_radiance); + + if (s < nsteps-1) { + VECCOPY(step_sta, step_end); + VecAddf(step_end, step_end, stepvec); + } + } + + VecMulf(radiance, stepsize); + VECCOPY(col, radiance); + + /* + Incoming radiance = + outgoing radiance from behind surface * beam transmittance/attenuation + + + added radiance from all points along the ray due to participating media + --> radiance for each segment = + radiance added by scattering + + radiance added by emission + * beam transmittance/attenuation + + + -- To find transmittance: + compute optical thickness with tau (perhaps involving monte carlo integration) + return exp(-tau) + + -- To find radiance from segments along the way: + find radiance for one step: + - loop over lights and weight by phase function + + - single scattering + : integrate over sphere + + then multiply each step for final exit radiance + */ +} + +void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) +{ + Isect isect; + float hitco[3], col[3]; + + memset(shr, 0, sizeof(ShadeResult)); + + if (vol_get_bounds(shi, shi->co, shi->view, hitco)) { + + volumeintegrate(shi, col, shi->co, hitco); + + /* hit */ + shr->alpha = 1.0f; + shr->combined[0] = col[0]; + shr->combined[1] = col[1]; + shr->combined[2] = col[2]; + + QUATCOPY(shr->diff, shr->combined); + } + else { + /* no hit */ + shr->combined[0] = 0.0f; + shr->combined[1] = 0.0f; + shr->combined[2] = 0.0f; + shr->combined[3] = shr->alpha = 0.0f; + } +} \ No newline at end of file diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 6d5e1a62ad4..bdb2fe5a3f3 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -3383,6 +3383,10 @@ static void material_panel_map_to(Object *ob, Material *ma, int from_nodes) uiDefButBitS(block, TOG, 1, B_MATPRV, "PAttr", 250,160,60,19, &pattr, 0, 0, 0, 0, "Display settings for particle attributes"); uiBlockSetCol(block, TH_AUTO); } + else if (ma->material_type == MA_VOLUME) { + uiDefButBitS(block, TOG3, MAP_ALPHA, B_MATPRV, "Density", 10,180,60,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the alpha value"); + uiDefButBitS(block, TOG3, MAP_EMIT, B_MATPRV, "Emit", 70,180,45,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the emit value"); + } else { uiDefButBitS(block, TOG, MAP_COL, B_MATPRV, "Col", 10,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material"); uiDefButBitS(block, TOG3, MAP_NORM, B_MATPRV, "Nor", 50,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the rendered normal"); @@ -3499,37 +3503,43 @@ static void material_panel_map_input(Object *ob, Material *ma) /* TEXCO */ uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_MATPRV, "Glob", 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates"); - uiDefButS(block, ROW, B_MATPRV, "Object", 675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates"); - if(mtex->texco == TEXCO_UV && !(mtex->texflag & MTEX_DUPLI_MAPTO)) { - if(!verify_valid_uv_name(mtex->uvname)) - uiBlockSetCol(block, TH_REDALERT); - but=uiDefBut(block, TEX, B_MATPRV, "UV:", 750,180,158,18, mtex->uvname, 0, 31, 0, 0, "Set name of UV layer to use, default is active UV layer"); - uiButSetCompleteFunc(but, autocomplete_uv, NULL); - uiBlockSetCol(block, TH_AUTO); - } - else + + if (ma->material_type == MA_VOLUME) { + uiDefButS(block, ROW, B_MATPRV, "Glob", 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates"); + uiDefButS(block, ROW, B_MATPRV, "Object", 675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates"); uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_MATPRV, "Ob:",750,180,158,18, &(mtex->object), ""); - - uiDefButS(block, ROW, B_MATPRV, "UV", 630,160,40,18, &(mtex->texco), 4.0, (float)TEXCO_UV, 0, 0, "Uses UV coordinates for texture coordinates"); - uiDefButS(block, ROW, B_MATPRV, "Orco", 670,160,55,18, &(mtex->texco), 4.0, (float)TEXCO_ORCO, 0, 0, "Uses the original undeformed coordinates of the object"); - if( ob->particlesystem.first ) - uiDefButS(block, ROW, B_MATPRV, "Strand", 725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STRAND, 0, 0, "Uses normalized strand texture coordinate (1D)"); - else - uiDefButS(block, ROW, B_MATPRV, "Stick", 725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STICKY, 0, 0, "Uses mesh's sticky coordinates for the texture coordinates"); - uiDefButS(block, ROW, B_MATPRV, "Win", 775,160,45,18, &(mtex->texco), 4.0, (float)TEXCO_WINDOW, 0, 0, "Uses screen coordinates as texture coordinates"); - uiDefButS(block, ROW, B_MATPRV, "Nor", 820,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_NORM, 0, 0, "Uses normal vector as texture coordinates"); - uiDefButS(block, ROW, B_MATPRV, "Refl", 864,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_REFL, 0, 0, "Uses reflection vector as texture coordinates"); - - uiDefButS(block, ROW, B_MATPRV, "Stress", 630,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_STRESS, 0, 0, "Uses the difference of edge lengths compared to original coordinates of the mesh"); - uiDefButS(block, ROW, B_MATPRV, "Tangent", 700,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_TANGENT, 0, 0, "Uses the optional tangent vector as texture coordinates"); - uiBlockEndAlign(block); - - if(ELEM(mtex->texco, TEXCO_UV, TEXCO_ORCO)) - uiDefButBitS(block, TOG, MTEX_DUPLI_MAPTO, B_MATPRV, "From Dupli", 820,140,88,18, &(mtex->texflag), 0, 0, 0, 0, "Dupli's instanced from verts, faces or particles, inherit texture coordinate from their parent"); - else if(mtex->texco == TEXCO_OBJECT) - uiDefButBitS(block, TOG, MTEX_OB_DUPLI_ORIG, B_MATPRV, "From Original", 820,140,88,18, &(mtex->texflag), 0, 0, 0, 0, "Dupli's derive their object coordinates from the original objects transformation"); + } else { + uiDefButS(block, ROW, B_MATPRV, "Glob", 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates"); + uiDefButS(block, ROW, B_MATPRV, "Object", 675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates"); + if(mtex->texco == TEXCO_UV && !(mtex->texflag & MTEX_DUPLI_MAPTO)) { + if(!verify_valid_uv_name(mtex->uvname)) + uiBlockSetCol(block, TH_REDALERT); + but=uiDefBut(block, TEX, B_MATPRV, "UV:", 750,180,158,18, mtex->uvname, 0, 31, 0, 0, "Set name of UV layer to use, default is active UV layer"); + uiButSetCompleteFunc(but, autocomplete_uv, NULL); + uiBlockSetCol(block, TH_AUTO); + } + else + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_MATPRV, "Ob:",750,180,158,18, &(mtex->object), ""); + + uiDefButS(block, ROW, B_MATPRV, "UV", 630,160,40,18, &(mtex->texco), 4.0, (float)TEXCO_UV, 0, 0, "Uses UV coordinates for texture coordinates"); + uiDefButS(block, ROW, B_MATPRV, "Orco", 670,160,55,18, &(mtex->texco), 4.0, (float)TEXCO_ORCO, 0, 0, "Uses the original undeformed coordinates of the object"); + if( ob->particlesystem.first ) + uiDefButS(block, ROW, B_MATPRV, "Strand", 725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STRAND, 0, 0, "Uses normalized strand texture coordinate (1D)"); + else + uiDefButS(block, ROW, B_MATPRV, "Stick", 725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STICKY, 0, 0, "Uses mesh's sticky coordinates for the texture coordinates"); + uiDefButS(block, ROW, B_MATPRV, "Win", 775,160,45,18, &(mtex->texco), 4.0, (float)TEXCO_WINDOW, 0, 0, "Uses screen coordinates as texture coordinates"); + uiDefButS(block, ROW, B_MATPRV, "Nor", 820,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_NORM, 0, 0, "Uses normal vector as texture coordinates"); + uiDefButS(block, ROW, B_MATPRV, "Refl", 864,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_REFL, 0, 0, "Uses reflection vector as texture coordinates"); + + uiDefButS(block, ROW, B_MATPRV, "Stress", 630,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_STRESS, 0, 0, "Uses the difference of edge lengths compared to original coordinates of the mesh"); + uiDefButS(block, ROW, B_MATPRV, "Tangent", 700,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_TANGENT, 0, 0, "Uses the optional tangent vector as texture coordinates"); + uiBlockEndAlign(block); + if(ELEM(mtex->texco, TEXCO_UV, TEXCO_ORCO)) + uiDefButBitS(block, TOG, MTEX_DUPLI_MAPTO, B_MATPRV, "From Dupli", 820,140,88,18, &(mtex->texflag), 0, 0, 0, 0, "Dupli's instanced from verts, faces or particles, inherit texture coordinate from their parent"); + else if(mtex->texco == TEXCO_OBJECT) + uiDefButBitS(block, TOG, MTEX_OB_DUPLI_ORIG, B_MATPRV, "From Original", 820,140,88,18, &(mtex->texflag), 0, 0, 0, 0, "Dupli's derive their object coordinates from the original objects transformation"); + } /* COORDS */ uiBlockBeginAlign(block); @@ -4111,7 +4121,7 @@ static uiBlock *strand_menu(void *mat_v) } -static void material_panel_material(Material *ma) +static void material_panel_material_solid(Material *ma) { uiBlock *block; float *colpoin = NULL; @@ -4199,6 +4209,43 @@ static void material_panel_material(Material *ma) } +static void material_panel_material_volume(Material *ma) +{ + uiBlock *block; + 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; + + uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE); + + uiBlockBeginAlign(block); + 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"); + uiDefButF(block, NUMSLI, B_MATPRV, "Density: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->alpha), 0.0, 1.0, 0, 0, "Base opacity value"); + uiDefButF(block, NUM, B_MATPRV, "Absorption: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 5.0, 0, 0, "Multiplier for absorption"); + uiBlockEndAlign(block); + + yco -= YSPACE; + + uiDefButF(block, NUMSLI, B_MATPRV, "Emit: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->emit), 0.0, 2.0, 0, 0, "Emission component"); + + yco -= YSPACE; + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, MA_VOL_ATTENUATED, B_MATPRV, "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"); + uiBlockEndAlign(block); + + uiDefBut(block, LABEL, B_DIFF, "", + X2CLM2, yco, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); +} + static void material_panel_nodes(Material *ma) { bNode *node; @@ -4237,7 +4284,7 @@ static void material_panel_links(Object *ob, Material *ma) block= uiNewBlock(&curarea->uiblocks, "material_panel_links", UI_EMBOSS, UI_HELV, curarea->win); /* 310 makes sorting code to put it right after preview panel */ - if(uiNewPanel(curarea, block, "Links and Pipeline", "Material", 310, 0, 318, 204)==0) return; + if(uiNewPanel(curarea, block, "Links and Pipeline", "Material", 310, 0, 338, 204)==0) return; /* Links from object to material/nodes */ uiDefBut(block, ROUNDBOX, 0, "", 5, 90, 310, 110, NULL, 7.0, 0.0, 15 , 20, ""); @@ -4330,7 +4377,10 @@ static void material_panel_links(Object *ob, Material *ma) uiDefButBitI(block, TOG, MA_ONLYCAST, B_MATPRV,"OnlyCast", 85,10,75,19, &(ma->mode), 0, 0, 0, 0, "Makes faces cast shadows only, not rendered"); uiDefButBitI(block, TOG, MA_TRACEBLE, B_NOP,"Traceable", 160,10,75,19, &(ma->mode), 0, 0, 0, 0, "Makes material detectable by ray tracing"); uiDefButBitI(block, TOG, MA_SHADBUF, B_MATPRV, "Shadbuf", 235,10,75,19, &(ma->mode), 0, 0, 0, 0, "Makes material cast shadows from shadow buffer lamps"); - + uiBlockEndAlign(block); + + uiDefButS(block, MENU, B_MATPRV, "Material Type %t|Solid %x0|Halo %x1|Volume %x2", + 10, -15, 300, 20, &(ma->material_type), 0.0, 0.0, 0, 0, ""); } @@ -4388,21 +4438,26 @@ void material_panels() ma= editnode_get_active_material(ma); if(ma) { - material_panel_material(ma); - material_panel_ramps(ma); - material_panel_shading(ma); - - if (G.scene->r.renderer==R_INTERN) - material_panel_tramir(ma); - else { - if(ma->YF_ar==0.f) { - ma->YF_ar = ma->YF_ag = ma->YF_ab = 1; - ma->YF_dscale = 1; + if (ma->material_type == MA_SOLID) { + material_panel_material_solid(ma); + material_panel_ramps(ma); + material_panel_shading(ma); + + if (G.scene->r.renderer==R_INTERN) + material_panel_tramir(ma); + else { + if(ma->YF_ar==0.f) { + ma->YF_ar = ma->YF_ag = ma->YF_ab = 1; + ma->YF_dscale = 1; + } + material_panel_tramir_yafray(ma); } - material_panel_tramir_yafray(ma); - } - material_panel_sss(ma); + material_panel_sss(ma); + + } else if (ma->material_type == MA_VOLUME) { + material_panel_material_volume(ma); + } material_panel_texture(ob, ma); mtex= ma->mtex[ ma->texact ]; diff --git a/source/blender/src/previewrender.c b/source/blender/src/previewrender.c index 1730bb890bc..dacb26b99a4 100644 --- a/source/blender/src/previewrender.c +++ b/source/blender/src/previewrender.c @@ -315,6 +315,8 @@ static Scene *preview_prepare_scene(RenderInfo *ri, int id_type, ID *id, int pr_ /* turn on raytracing if needed */ if(mat->mode_l & (MA_RAYTRANSP|MA_RAYMIRROR)) sce->r.mode |= R_RAYTRACE; + if(mat->material_type == MA_VOLUME) + sce->r.mode |= R_RAYTRACE; if(mat->sss_flag & MA_DIFF_SSS) sce->r.mode |= R_SSS; From 50d0e1a988a55a7e7a59823c030ce9ac3413a9a2 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 23 Sep 2008 04:26:52 +0000 Subject: [PATCH 02/88] * Volumetrics update - Fixed a shading bug, due to issues in the raytrace engine where it would ignore intersections from the starting face (as it should). Disabled this for single scattering intersections, thanks to Brecht for a hint there. It still shows a little bit of noise, I think due to raytrace inaccuracy, which will have to be fixed up later. before: http://mke3.net/blender/devel/rendering/volumetrics/vol_shaded_old.png after: http://mke3.net/blender/devel/rendering/volumetrics/vol_shaded_correct.png Now single scatttering shading works very nicely and is capable of things like this: http://mke3.net/blender/devel/rendering/volumetrics/vol_shaded_clouds.mov - Added colour emission. Now as well as the overall 'Emit:' slider to control overall emission strength, there's also a colour swatch for the volume to emit that colour. This can also be textured, using 'Emit Col' in the map to panel. This animation was made using a clouds texture, with colour band, mapped to both emit colour and emit (strength): http://mke3.net/blender/devel/rendering/volumetrics/vol_col_emit.mov - Added 'Local' mapping to 'map input' - it's similar to Orco - Fixed texture 'map input', wasn't using the offsets or scale values. --- source/blender/makesdna/DNA_material_types.h | 3 + .../render/intern/source/convertblender.c | 24 +++++++ .../blender/render/intern/source/raytrace.c | 2 +- source/blender/render/intern/source/texture.c | 16 ++++- .../blender/render/intern/source/volumetric.c | 71 ++++++++++--------- source/blender/src/buttons_shading.c | 20 +++++- 6 files changed, 97 insertions(+), 39 deletions(-) diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index ee4779779ec..98ddc0aa7d3 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -69,6 +69,8 @@ typedef struct Material { float vol_alphathresh; float vol_stepsize, vol_shade_stepsize; float vol_absorption, vol_scattering; + float vol_absorption_col[3]; + float vpad2; short vol_shadeflag; short vpad; @@ -163,6 +165,7 @@ typedef struct Material { /* flag */ /* for render */ #define MA_IS_USED 1 +#define MA_IS_TEXTURED 2 /* material_type */ #define MA_SOLID 0 diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index a752561218c..17cd71ecb79 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -921,6 +921,28 @@ static void flag_render_node_material(Render *re, bNodeTree *ntree) } } +static void check_material_is_textured(Material *ma) +{ + MTex *mtex; + Tex *tex; + int tex_nr; + + for(tex_nr=0; tex_nrseptex & (1<mtex[tex_nr]) { + mtex= ma->mtex[tex_nr]; + tex= mtex->tex; + if(tex==NULL) + continue; + else + ma->flag |= MA_IS_TEXTURED; + return; + } + } +} + static Material *give_render_material(Render *re, Object *ob, int nr) { extern Material defmaterial; /* material.c */ @@ -943,6 +965,8 @@ static Material *give_render_material(Render *re, Object *ob, int nr) if (ma->material_type == MA_VOLUME) re->r.mode |= R_RAYTRACE; + check_material_is_textured(ma); + return ma; } diff --git a/source/blender/render/intern/source/raytrace.c b/source/blender/render/intern/source/raytrace.c index ec47df74d04..d14d221b099 100644 --- a/source/blender/render/intern/source/raytrace.c +++ b/source/blender/render/intern/source/raytrace.c @@ -931,7 +931,7 @@ int RE_ray_face_intersection(Isect *is, RayObjectTransformFunc transformfunc, Ra intersection to be detected in its neighbour face */ if(is->facecontr && is->faceisect); // optimizing, the tests below are not needed - else if(is->labda< .1) { + else if(is->labda< .1 && is->faceorig) { RayFace *face= is->faceorig; float *origv1, *origv2, *origv3, *origv4; short de= 0; diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index e874f98ede1..6d3cc57cd32 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1485,8 +1485,20 @@ void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *alpha, float MTC_Mat4MulVecfl(ob->imat, co); } } + /* not really orco, but 'local' */ + else if(mtex->texco==TEXCO_ORCO) { + + if(mtex->texflag & MTEX_DUPLI_MAPTO) { + VECCOPY(co, shi->duplilo); + } + else { + Object *ob= shi->obi->ob; + VECCOPY(co, xyz); + MTC_Mat4MulVecfl(ob->imat, co); + } + } else if(mtex->texco==TEXCO_GLOB) { - VECCOPY(co, xyz); + VECCOPY(co, xyz); } else continue; // can happen when texco defines disappear and it renders old files @@ -1508,7 +1520,7 @@ void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *alpha, float } - rgbnor= multitex(tex, co, NULL, NULL, 0, &texres); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */ + rgbnor= multitex(tex, texvec, NULL, NULL, 0, &texres); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */ /* texture output */ diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 3ca8c0a0693..298b08c3545 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -42,8 +42,11 @@ #include "DNA_group_types.h" #include "DNA_lamp_types.h" +#include "BKE_global.h" + #include "render_types.h" #include "shading.h" +#include "texture.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ @@ -51,6 +54,7 @@ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#if 0 static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) { VlakRen *vlr = (VlakRen *)face; @@ -59,11 +63,16 @@ static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) * of foward facing geometry don't cause the ray to stop */ return (INPR(is->vec, vlr->n) < 0.0f); } +#endif #define VOL_IS_SAMEOBJECT 1 #define VOL_IS_SAMEMATERIAL 2 -int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco) + +#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) { /* TODO: Box or sphere intersection types could speed things up */ @@ -77,8 +86,10 @@ int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco) 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; + isect.mode= RE_RAY_MIRROR; - isect.faceorig= (RayFace*)shi->vlr; isect.oborig= RAY_OBJECT_SET(&R, shi->obi); isect.face_last= NULL; isect.ob_last= 0; @@ -106,8 +117,8 @@ float vol_get_density(struct ShadeInput *shi, float *co) float col[3] = {0.0, 0.0, 0.0}; /* do any density gain stuff here */ - - do_volume_tex(shi, co, col, &density, &emit_fac); + if (shi->mat->flag & MA_IS_TEXTURED) + do_volume_tex(shi, co, col, &density, &emit_fac); return density; } @@ -115,15 +126,18 @@ float vol_get_density(struct ShadeInput *shi, float *co) /* compute emission component, amount of radiance to add per segment * can be textured with 'emit' */ -void vol_get_emission(ShadeInput *shi, float *em, float *co, float *endco, float density) +void vol_get_emission(ShadeInput *shi, float *em, float *co, float density) { float emission = shi->mat->emit; - float col[3] = {0.0, 0.0, 0.0}; + float col[3]; float dens_dummy = 1.0f; + VECCOPY(col, &shi->mat->r); + do_volume_tex(shi, co, col, &dens_dummy, &emission); em[0] = em[1] = em[2] = emission; + VecMulVecf(em, em, col); } @@ -133,7 +147,6 @@ void vol_get_emission(ShadeInput *shi, float *em, float *co, float *endco, float void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, float density, float stepsize) { /* input density = density at co */ - float dist; float absorption = shi->mat->vol_absorption; int s, nsteps; @@ -194,29 +207,29 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * if(lar->mode & LA_TEXTURE) { shi->osatex= 0; - do_lamp_tex(lar, lv, shi, lacol); + do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE); } VecMulf(lacol, visifac*lar->energy); + if (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED) { - /* find minimum of volume bounds, or lamp coord */ if (ELEM(lar->type, LA_SUN, LA_HEMI)) VECCOPY(lv, lar->vec); - VecMulf(lv, -1.0f); - if (vol_get_bounds(shi, co, lv, hitco)) { + /* find minimum of volume bounds, or lamp coord */ + if (vol_get_bounds(shi, co, lv, hitco, VOL_BOUNDS_SS)) { + float dist = VecLenf(co, hitco); + if (ELEM(lar->type, LA_SUN, LA_HEMI)) atten_co = hitco; - else if ( lampdist < VecLenf(co, hitco) ) + else if ( lampdist < dist ) { atten_co = lar->co; - else + } else atten_co = hitco; - atten_co = lar->co; - vol_get_attenuation(shi, tau, co, atten_co, density, shi->mat->vol_shade_stepsize); tr[0] = exp(-tau[0]); tr[1] = exp(-tau[1]); @@ -232,7 +245,7 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * } VecAddf(col, col, lacol); -} +} /* shadows -> trace a ray to find blocker geometry - if blocker is outside the volume, use standard shadow functions @@ -242,7 +255,7 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * */ /* single scattering only for now */ -void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float *endco, float stepsize, float density) +void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsize, float density) { GroupObject *go; ListBase *lights; @@ -267,8 +280,6 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float *endco VecAddf(col, col, lacol); } - - VECCOPY(scatter, col); } @@ -276,8 +287,6 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float *endco static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco) { - float total_tau; - float total_tr[3]; float tr[3] = {1.f, 1.f, 1.f}; /* 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; @@ -285,8 +294,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float 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}; int s; - float step_sta[3], step_end[3], step_offs[3] = {0.0, 0.0, 0.0}; - float alpha_fac, emit_fac=0.0f, tex_col[3]; + float step_sta[3], step_end[3]; /* multiply col_behind with beam transmittance over entire distance */ /* @@ -314,7 +322,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float /* 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); - + /* *** transmittance and emission *** */ /* transmittance component (alpha) */ @@ -327,8 +335,8 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float //if (rgb_to_luminance(tr[0], tr[1], tr[2]) < 1e-3) break; /* incoming light via emission or scattering (additive) */ - vol_get_emission(shi, step_emit, step_sta, step_end, density); - vol_get_scattering(shi, step_scatter, step_end, step_end, stepsize, density); + vol_get_emission(shi, step_emit, step_sta, density); + vol_get_scattering(shi, step_scatter, step_end, stepsize, density); VecAddf(d_radiance, step_emit, step_scatter); @@ -336,10 +344,8 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float VecMulVecf(d_radiance, tr, d_radiance); VecAddf(radiance, radiance, d_radiance); - if (s < nsteps-1) { - VECCOPY(step_sta, step_end); - VecAddf(step_end, step_end, stepvec); - } + VECCOPY(step_sta, step_end); + VecAddf(step_end, step_end, stepvec); } VecMulf(radiance, stepsize); @@ -373,12 +379,11 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) { - Isect isect; float hitco[3], col[3]; memset(shr, 0, sizeof(ShadeResult)); - if (vol_get_bounds(shi, shi->co, shi->view, hitco)) { + if (vol_get_bounds(shi, shi->co, shi->view, hitco, VOL_BOUNDS_DEPTH)) { volumeintegrate(shi, col, shi->co, hitco); @@ -397,4 +402,4 @@ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) shr->combined[2] = 0.0f; shr->combined[3] = shr->alpha = 0.0f; } -} \ No newline at end of file +} diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 73ff5945d25..eaf432f2397 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -3402,7 +3402,8 @@ static void material_panel_map_to(Object *ob, Material *ma, int from_nodes) } else if (ma->material_type == MA_VOLUME) { uiDefButBitS(block, TOG3, MAP_ALPHA, B_MATPRV, "Density", 10,180,60,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the alpha value"); - uiDefButBitS(block, TOG3, MAP_EMIT, B_MATPRV, "Emit", 70,180,45,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the emit value"); + uiDefButBitS(block, TOG3, MAP_EMIT, B_MATPRV, "Emit", 70,180,50,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the emit value"); + uiDefButBitS(block, TOG, MAP_COL, B_MATPRV, "Emit Col", 120,180,80,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material"); } else { uiDefButBitS(block, TOG, MAP_COL, B_MATPRV, "Col", 10,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material"); @@ -3525,6 +3526,7 @@ static void material_panel_map_input(Object *ob, Material *ma) uiDefButS(block, ROW, B_MATPRV, "Glob", 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates"); uiDefButS(block, ROW, B_MATPRV, "Object", 675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates"); uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_MATPRV, "Ob:",750,180,158,18, &(mtex->object), ""); + uiDefButS(block, ROW, B_MATPRV, "Local", 630,160,55,18, &(mtex->texco), 4.0, (float)TEXCO_ORCO, 0, 0, "Uses the original undeformed coordinates of the object"); } else { uiDefButS(block, ROW, B_MATPRV, "Glob", 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates"); uiDefButS(block, ROW, B_MATPRV, "Object", 675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates"); @@ -4241,14 +4243,26 @@ 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"); uiDefButF(block, NUMSLI, B_MATPRV, "Density: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->alpha), 0.0, 1.0, 0, 0, "Base opacity value"); - uiDefButF(block, NUM, B_MATPRV, "Absorption: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 5.0, 0, 0, "Multiplier for absorption"); uiBlockEndAlign(block); yco -= YSPACE; + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_MATPRV, "Absorption: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 5.0, 0, 0, "Multiplier for absorption"); + /* uiDefButF(block, COL, B_MATPRV, "", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption_col), 0, 0, 0, B_MATCOL, ""); + */ + uiBlockEndAlign(block); + + yco -= YSPACE; + + uiBlockBeginAlign(block); uiDefButF(block, NUMSLI, B_MATPRV, "Emit: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->emit), 0.0, 2.0, 0, 0, "Emission component"); + uiDefButF(block, COL, B_MATPRV, "", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->r), 0, 0, 0, B_MATCOL, ""); + uiBlockEndAlign(block); yco -= YSPACE; From 6b4ac3e7def9e1b7e11398f483f2b64581939766 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 23 Sep 2008 07:05:06 +0000 Subject: [PATCH 03/88] * Volume colour absorption Rather than a single absorption value to control how much light is absorbed as it travels through a volume, there's now an additional absorption colour. This is used to absorb different R/G/B components of light at different amounts. For example, if a white light shines on a volume which absorbs green and blue components, the volume will appear red. To make it easier to use, the colour set in the UI is actually the inverse of the absorption colour, so the colour you set is the colour that the volume will appear as. Here's an example of how it works: http://mke3.net/blender/devel/rendering/volumetrics/vol_col_absorption.jpg And this can be textured too: http://mke3.net/blender/devel/rendering/volumetrics/vol_absorb_textured.png Keep in mind, this doesn't use accurate spectral light wavelength mixing (just R/G/B channels) so in cases where the absorption colour is fully red green or blue, you'll get non-physical results. Todo: refactor the volume texturing internal interface... --- source/blender/blenkernel/intern/material.c | 1 + source/blender/blenloader/intern/readfile.c | 12 ++++--- source/blender/makesdna/DNA_material_types.h | 2 +- .../blender/render/intern/include/texture.h | 2 +- source/blender/render/intern/source/texture.c | 9 +++-- .../blender/render/intern/source/volumetric.c | 35 +++++++++++++++---- source/blender/src/buttons_shading.c | 5 +-- 7 files changed, 49 insertions(+), 17 deletions(-) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 5c20858ec63..473a035ecce 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -171,6 +171,7 @@ void init_material(Material *ma) ma->vol_shade_stepsize = 0.2f; 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->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 63f3f88da50..41035b1c373 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7737,10 +7737,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } for(ma=main->mat.first; ma; ma= ma->id.next) { - if (ma->vol_shade_stepsize < 0.001f) ma->vol_shade_stepsize = 0.2f; - if (ma->vol_stepsize < 0.001f) ma->vol_stepsize = 0.2f; - if (ma->vol_absorption < 0.001f) ma->vol_absorption = 1.0f; - if (ma->vol_scattering < 0.001f) ma->vol_scattering = 1.0f; + /* trigger for non-volumetric file */ + if (ma->vol_shade_stepsize < 0.0001f) { + ma->vol_shade_stepsize = 0.2f; + ma->vol_stepsize = 0.2f; + 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; + } } } diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 98ddc0aa7d3..c322295fff9 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -302,7 +302,7 @@ typedef struct Material { #define MAP_AMB 2048 #define MAP_DISPLACE 4096 #define MAP_WARP 8192 -#define MAP_LAYER 16384 +#define MAP_LAYER 16384 /* mapto for halo */ //#define MAP_HA_COL 1 diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h index 64b88c050d2..eee4ad7069a 100644 --- a/source/blender/render/intern/include/texture.h +++ b/source/blender/render/intern/include/texture.h @@ -56,7 +56,7 @@ void do_halo_tex(struct HaloRen *har, float xn, float yn, float *colf); void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend, int skyflag); void do_material_tex(struct ShadeInput *shi); void do_lamp_tex(LampRen *la, float *lavec, struct ShadeInput *shi, float *colf, int effect); -void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *alpha, float *emit); +void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *absorb_col, float *alpha, float *emit); void init_render_textures(Render *re); diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 6d3cc57cd32..1bcefb049ae 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1451,7 +1451,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen return in; } -void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *alpha, float *emit) +void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *absorb_col, float *alpha, float *emit) { MTex *mtex; Tex *tex; @@ -1550,7 +1550,7 @@ void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *alpha, float } - if(mtex->mapto & (MAP_COL)) { + if(mtex->mapto & (MAP_COL+MAP_COLMIR)) { float tcol[3], colfac; /* stencil maps on the texture control slider, not texture intensity value */ @@ -1571,6 +1571,11 @@ void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *alpha, float if(mtex->mapto & MAP_COL) { texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype); } + + /* MAP_COLMIR is abused for absorption colour at the moment */ + if(mtex->mapto & MAP_COLMIR) { + texture_rgb_blend(absorb_col, tcol, absorb_col, texres.tin, colfac, mtex->blendtype); + } } if(mtex->mapto & MAP_VARS) { diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 298b08c3545..5966e10e1dd 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -115,10 +115,11 @@ float vol_get_density(struct ShadeInput *shi, float *co) float density = shi->mat->alpha; float emit_fac=0.0f; float col[3] = {0.0, 0.0, 0.0}; + float absorb_col[3] = {0.0, 0.0, 0.0}; /* do any density gain stuff here */ if (shi->mat->flag & MA_IS_TEXTURED) - do_volume_tex(shi, co, col, &density, &emit_fac); + do_volume_tex(shi, co, col, absorb_col, &density, &emit_fac); return density; } @@ -131,15 +132,32 @@ void vol_get_emission(ShadeInput *shi, float *em, float *co, float density) float emission = shi->mat->emit; float col[3]; float dens_dummy = 1.0f; + float absorb_col[3] = {0.0, 0.0, 0.0}; VECCOPY(col, &shi->mat->r); - do_volume_tex(shi, co, col, &dens_dummy, &emission); + do_volume_tex(shi, co, col, absorb_col, &dens_dummy, &emission); em[0] = em[1] = em[2] = emission; VecMulVecf(em, em, col); } +void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co) +{ + float col[3]; + float dummy = 1.0f; + float vec_one[3] = {1.0f, 1.0f, 1.0f}; + float absorption = shi->mat->vol_absorption; + + VECCOPY(absorb_col, shi->mat->vol_absorption_col); + + if (shi->mat->flag & MA_IS_TEXTURED) + do_volume_tex(shi, co, col, absorb_col, &dummy, &dummy); + + absorb_col[0] = (1.0f - absorb_col[0]) * absorption; + absorb_col[1] = (1.0f - absorb_col[1]) * absorption; + absorb_col[2] = (1.0f - absorb_col[2]) * absorption; +} /* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau. * Used in the relationship Transmittance = e^(-attenuation) @@ -148,18 +166,20 @@ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, f { /* input density = density at co */ float dist; - float absorption = shi->mat->vol_absorption; + float absorb_col[3]; int s, nsteps; float step_vec[3], step_sta[3], step_end[3]; - dist = VecLenf(co, endco); + vol_get_absorption(shi, absorb_col, co); + dist = VecLenf(co, endco); nsteps = (int)ceil(dist / stepsize); if (nsteps == 1) { /* homogenous volume within the sampled distance */ tau[0] = tau[1] = tau[2] = dist * density; - VecMulf(tau, absorption); + + VecMulVecf(tau, tau, absorb_col); return; } else { tau[0] = tau[1] = tau[2] = 0.0; @@ -173,7 +193,8 @@ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, f for (s = 0; s < nsteps; s++) { - if (s > 0) density = vol_get_density(shi, step_sta); + if (s > 0) + density = vol_get_density(shi, step_sta); tau[0] += stepsize * density; tau[1] += stepsize * density; @@ -184,7 +205,7 @@ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, f VecAddf(step_end, step_end, step_vec); } } - VecMulf(tau, absorption); + VecMulVecf(tau, tau, absorb_col); } void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *col, float stepsize, float density) diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index eaf432f2397..7db44e4c0eb 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -3404,6 +3404,7 @@ static void material_panel_map_to(Object *ob, Material *ma, int from_nodes) uiDefButBitS(block, TOG3, MAP_ALPHA, B_MATPRV, "Density", 10,180,60,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the alpha value"); uiDefButBitS(block, TOG3, MAP_EMIT, B_MATPRV, "Emit", 70,180,50,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the emit value"); uiDefButBitS(block, TOG, MAP_COL, B_MATPRV, "Emit Col", 120,180,80,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material"); + uiDefButBitS(block, TOG, MAP_COLMIR, B_MATPRV, "Absorb Col", 200,180,80,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material"); } else { uiDefButBitS(block, TOG, MAP_COL, B_MATPRV, "Col", 10,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material"); @@ -4250,9 +4251,9 @@ static void material_panel_material_volume(Material *ma) uiBlockBeginAlign(block); uiDefButF(block, NUM, B_MATPRV, "Absorption: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 5.0, 0, 0, "Multiplier for absorption"); - /* uiDefButF(block, COL, B_MATPRV, "", + uiDefButF(block, COL, B_MATPRV, "", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption_col), 0, 0, 0, B_MATCOL, ""); - */ + uiBlockEndAlign(block); yco -= YSPACE; From 340c3b945e5ac5ef0076f0006f8f2248bd2a327d Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 23 Sep 2008 07:44:25 +0000 Subject: [PATCH 04/88] * Refactored the volume texture code. Seems to go ok so far, stress tests and all my old files render fine, but anyone feel free to let me know if you find a bug in this :) Should be a bit faster too, this file renders in about 60% of the time it did before (http://mke3.net/blender/devel/rendering/volumetrics/vol_col_emit.mov) --- .../blender/render/intern/include/texture.h | 2 +- source/blender/render/intern/source/texture.c | 28 +++++++++++-------- .../blender/render/intern/source/volumetric.c | 16 ++++------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h index eee4ad7069a..6e1ad562c14 100644 --- a/source/blender/render/intern/include/texture.h +++ b/source/blender/render/intern/include/texture.h @@ -56,7 +56,7 @@ void do_halo_tex(struct HaloRen *har, float xn, float yn, float *colf); void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend, int skyflag); void do_material_tex(struct ShadeInput *shi); void do_lamp_tex(LampRen *la, float *lavec, struct ShadeInput *shi, float *colf, int effect); -void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *absorb_col, float *alpha, float *emit); +void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, float *val); void init_render_textures(Render *re); diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 1bcefb049ae..0fa8d2bf909 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1451,7 +1451,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen return in; } -void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *absorb_col, float *alpha, float *emit) +void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, float *val) { MTex *mtex; Tex *tex; @@ -1472,6 +1472,10 @@ void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *absorb_col, f tex= mtex->tex; if(tex==0) continue; + /* only process if this texture is mapped + * to one that we're interested in */ + if (!(mtex->mapto & mapto_flag)) continue; + /* which coords */ if(mtex->texco==TEXCO_OBJECT) { Object *ob= mtex->object; @@ -1550,7 +1554,7 @@ void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *absorb_col, f } - if(mtex->mapto & (MAP_COL+MAP_COLMIR)) { + if((mapto_flag & (MAP_COL+MAP_COLMIR)) && (mtex->mapto & (MAP_COL+MAP_COLMIR))) { float tcol[3], colfac; /* stencil maps on the texture control slider, not texture intensity value */ @@ -1568,17 +1572,17 @@ void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *absorb_col, f } else texres.tin= texres.ta; - if(mtex->mapto & MAP_COL) { + if((mapto_flag & MAP_COL) && (mtex->mapto & MAP_COL)) { texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype); } /* MAP_COLMIR is abused for absorption colour at the moment */ - if(mtex->mapto & MAP_COLMIR) { - texture_rgb_blend(absorb_col, tcol, absorb_col, texres.tin, colfac, mtex->blendtype); + if((mapto_flag & MAP_COLMIR) && (mtex->mapto & MAP_COLMIR)) { + texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype); } } - if(mtex->mapto & MAP_VARS) { + if((mapto_flag & MAP_VARS) && (mtex->mapto & MAP_VARS)) { /* stencil maps on the texture control slider, not texture intensity value */ float varfac= mtex->varfac*stencilTin; @@ -1587,17 +1591,17 @@ void do_volume_tex(ShadeInput *shi, float *xyz, float *col, float *absorb_col, f else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb); } - if(mtex->mapto & MAP_EMIT) { + if((mapto_flag & MAP_EMIT) && (mtex->mapto & MAP_EMIT)) { int flip= mtex->maptoneg & MAP_EMIT; - *emit = texture_value_blend(mtex->def_var, *emit, texres.tin, varfac, mtex->blendtype, flip); - if(*emit<0.0) *emit= 0.0; + *val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip); + if(*val<0.0) *val= 0.0; } - if(mtex->mapto & MAP_ALPHA) { + if((mapto_flag & MAP_ALPHA) && (mtex->mapto & MAP_ALPHA)) { int flip= mtex->maptoneg & MAP_ALPHA; - *alpha = texture_value_blend(mtex->def_var, *alpha, texres.tin, varfac, mtex->blendtype, flip); - CLAMP(*alpha, 0.0, 1.0); + *val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip); + CLAMP(*val, 0.0, 1.0); } } } diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 5966e10e1dd..f3ce9279225 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -113,13 +113,11 @@ int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, int int float vol_get_density(struct ShadeInput *shi, float *co) { float density = shi->mat->alpha; - float emit_fac=0.0f; float col[3] = {0.0, 0.0, 0.0}; - float absorb_col[3] = {0.0, 0.0, 0.0}; - + /* do any density gain stuff here */ if (shi->mat->flag & MA_IS_TEXTURED) - do_volume_tex(shi, co, col, absorb_col, &density, &emit_fac); + do_volume_tex(shi, co, MAP_ALPHA, col, &density); return density; } @@ -130,13 +128,11 @@ float vol_get_density(struct ShadeInput *shi, float *co) void vol_get_emission(ShadeInput *shi, float *em, float *co, float density) { float emission = shi->mat->emit; - float col[3]; - float dens_dummy = 1.0f; - float absorb_col[3] = {0.0, 0.0, 0.0}; + float col[3] = {0.0, 0.0, 0.0}; VECCOPY(col, &shi->mat->r); - do_volume_tex(shi, co, col, absorb_col, &dens_dummy, &emission); + do_volume_tex(shi, co, MAP_EMIT+MAP_COL, col, &emission); em[0] = em[1] = em[2] = emission; VecMulVecf(em, em, col); @@ -144,15 +140,13 @@ void vol_get_emission(ShadeInput *shi, float *em, float *co, float density) void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co) { - float col[3]; float dummy = 1.0f; - float vec_one[3] = {1.0f, 1.0f, 1.0f}; float absorption = shi->mat->vol_absorption; VECCOPY(absorb_col, shi->mat->vol_absorption_col); if (shi->mat->flag & MA_IS_TEXTURED) - do_volume_tex(shi, co, col, absorb_col, &dummy, &dummy); + do_volume_tex(shi, co, MAP_COLMIR, absorb_col, &dummy); absorb_col[0] = (1.0f - absorb_col[0]) * absorption; absorb_col[1] = (1.0f - absorb_col[1]) * absorption; From 45acf427a7352bbffffcec93d43b50220febbd04 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 23 Sep 2008 08:00:55 +0000 Subject: [PATCH 05/88] * bugfix, old files (including default cube) weren't loading up with correctly initialised volume settings --- source/blender/blenloader/intern/readfile.c | 28 ++++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 41035b1c373..e106dd6cb59 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7720,7 +7720,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) Scene *sce= main->scene.first; Sequence *seq; Editing *ed; - Material *ma; while(sce) { ed= sce->ed; @@ -7735,17 +7734,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) sce= sce->id.next; } - - for(ma=main->mat.first; ma; ma= ma->id.next) { - /* trigger for non-volumetric file */ - if (ma->vol_shade_stepsize < 0.0001f) { - ma->vol_shade_stepsize = 0.2f; - ma->vol_stepsize = 0.2f; - 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; - } - } } /*fix broken group lengths in id properties*/ @@ -7869,6 +7857,22 @@ static void do_versions(FileData *fd, Library *lib, Main *main) la->skyblendtype= MA_RAMP_ADD; la->skyblendfac= 1.0f; } + + } + + if (main->versionfile <= 247) { + Material *ma; + + for(ma=main->mat.first; ma; ma= ma->id.next) { + /* trigger for non-volumetric file */ + if (ma->vol_shade_stepsize < 0.0001f) { + ma->vol_shade_stepsize = 0.2f; + ma->vol_stepsize = 0.2f; + 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; + } + } } /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */ From aed107cf4a31f4b07d1f065d407e6ad55935afb2 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 24 Sep 2008 02:52:47 +0000 Subject: [PATCH 06/88] * 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. --- .../blender/render/intern/include/shading.h | 3 + .../blender/render/intern/source/rayshade.c | 2 +- .../blender/render/intern/source/volumetric.c | 178 +++++++++++++----- 3 files changed, 134 insertions(+), 49 deletions(-) diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h index 9229e612337..4e63d0f0d79 100644 --- a/source/blender/render/intern/include/shading.h +++ b/source/blender/render/intern/include/shading.h @@ -91,3 +91,6 @@ float lamp_get_visibility(struct LampRen *lar, float *co, float *lv, float *dist 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); diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 0fd9365477c..e000a55ece6 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -205,7 +205,7 @@ void makeraytree(Render *re) 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); diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index f3ce9279225..e3d21f2d2b0 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -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 @@ static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) #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 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * 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 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi VECCOPY(scatter, col); } - - -static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco) +static void shade_intersection(ShadeInput *shi, float *col, Isect *is) { - float tr[3] = {1.f, 1.f, 1.f}; /* total transmittance */ + 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 vol_trace_behind(ShadeInput *shi, float *co, Isect *isect_first, float *col) +{ + 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 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float 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,14 +427,24 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float /* 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 = @@ -394,21 +474,23 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float 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 */ From a0a5198a03ec705e6faf3a995315c8615336963a Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 24 Sep 2008 07:38:12 +0000 Subject: [PATCH 07/88] Volumetrics: * Now it's possible to render with the camera inside a volume. I'm not sure how this goes with overlapping volumes yet, will look at it. But it allows nice things like this :) http://mke3.net/blender/devel/rendering/volumetrics/clouds_sky.mov * Sped up shading significantly by not doing any shading if the density of the current sample is less than 0.01 (there's nothing to shade there anyway!) Speeds up around 200% on that clouds scene. * Fixed a bug in global texture coordinates for volume textures --- .../blender/render/intern/include/shading.h | 1 + .../blender/render/intern/source/rayshade.c | 7 +- source/blender/render/intern/source/texture.c | 1 + .../blender/render/intern/source/volumetric.c | 150 +++++++++++------- source/blender/src/buttons_shading.c | 7 +- 5 files changed, 108 insertions(+), 58 deletions(-) diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h index 4e63d0f0d79..54a8d4b0404 100644 --- a/source/blender/render/intern/include/shading.h +++ b/source/blender/render/intern/include/shading.h @@ -33,6 +33,7 @@ struct VlakRen; struct StrandSegment; struct StrandPoint; struct ObjectInstanceRen obi; +struct Isect; /* shadeinput.c */ diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index e000a55ece6..5e06b298bdb 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -274,9 +274,10 @@ void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) ntreeShaderExecTree(shi->mat->nodetree, shi, shr); shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ } - else - shade_material_loop(shi, shr); - + else { + if (shi->mat->material_type == MA_SOLID) shade_material_loop(shi, shr); + else if (shi->mat->material_type == MA_VOLUME) shade_volume_loop(shi, shr); + } /* raytrace likes to separate the spec color */ VECSUB(shr->diff, shr->combined, shr->spec); } diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 0fa8d2bf909..2c143986900 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1503,6 +1503,7 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa } else if(mtex->texco==TEXCO_GLOB) { VECCOPY(co, xyz); + MTC_Mat4MulVecfl(R.viewinv, co); } else continue; // can happen when texco defines disappear and it renders old files diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index e3d21f2d2b0..032175f522b 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -138,6 +138,15 @@ void vol_get_emission(ShadeInput *shi, float *em, float *co, float density) VecMulVecf(em, em, col); } +void vol_get_scattering_fac(ShadeInput *shi, float *scatter_fac, float *co, float density) +{ + //float col[3] = {0.0, 0.0, 0.0}; + //do_volume_tex(shi, co, MAP_EMIT+MAP_COL, col, &emission); + + *scatter_fac = shi->mat->vol_scattering; +} + + void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co) { float dummy = 1.0f; @@ -282,12 +291,16 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi for(go=lights->first; go; go= go->next) { float lacol[3] = {0.f, 0.f, 0.f}; + float scatter_fac; lar= go->lampren; if (lar==NULL) continue; vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density); + vol_get_scattering_fac(shi, &scatter_fac, co, density); + VecMulf(lacol, scatter_fac); + /* isotropic phase function */ VecMulf(lacol, 1.0f / (4.f * M_PI)); @@ -330,9 +343,13 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is) static void vol_trace_behind(ShadeInput *shi, float *co, Isect *isect_first, float *col) { + RayFace *rforig=NULL; + Isect isect; + float maxsize = RE_ray_tree_max_size(R.raytree); + if (isect_first != NULL) { - /* found an intersection, - * either back of volume object or another object */ + /* there was already a ray intersection - + * either the back of volume object or another object */ ObjectInstanceRen *obi= RAY_OBJECT_GET(&R, isect_first->ob); if (obi != shi->obi) { @@ -340,32 +357,39 @@ static void vol_trace_behind(ShadeInput *shi, float *co, Isect *isect_first, flo 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; + rforig = isect_first->face; } } - col[0] = col[1] = col[2] = 0.0f; + /* get ready to trace a new ray behind the volume */ + VECCOPY(isect.start, co) + + if (rforig == NULL) { + /* if there's no original ray intersection then the original + * shaded surface is the inside of the volume at the far bounds. + * We can use this face for the raytrace orig face */ + isect.faceorig= (RayFace *)shi->vlr; + } else { + isect.faceorig= rforig; + } + + isect.end[0] = isect.start[0] + shi->view[0] * maxsize; + isect.end[1] = isect.start[1] + shi->view[1] * maxsize; + isect.end[2] = isect.start[2] + shi->view[2] * maxsize; + + isect.mode= RE_RAY_MIRROR; + isect.oborig= RAY_OBJECT_SET(&R, shi->obi); + isect.face_last= NULL; + isect.ob_last= 0; + 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)) { + shade_intersection(shi, col, &isect); + } else { + shadeSkyView(col, co, shi->view, NULL); + } + } static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco, Isect *isect) @@ -392,8 +416,6 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float VecMulVecf(radiance, tr, col_behind); tr[0] = tr[1] = tr[2] = 1.0f; - - /* ray marching */ nsteps = (int)ceil(VecLenf(co, endco) / stepsize); @@ -408,28 +430,31 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float for (s = 0; s < nsteps; s++) { if (s > 0) density = vol_get_density(shi, step_sta); - /* *** transmittance and emission *** */ + /* there's only any point shading here + * if there's actually some density to shade! */ + if (density > 0.01f) { - /* transmittance component (alpha) */ - 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; - - /* incoming light via emission or scattering (additive) */ - vol_get_emission(shi, step_emit, step_sta, density); - vol_get_scattering(shi, step_scatter, step_end, stepsize, density); - - VecAddf(d_radiance, step_emit, step_scatter); - - /* Lv += Tr * (Lve() + Ld) */ - VecMulVecf(d_radiance, tr, d_radiance); - VecMulf(d_radiance, stepsize); - - VecAddf(radiance, radiance, d_radiance); + /* transmittance component (alpha) */ + 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; + + /* incoming light via emission or scattering (additive) */ + vol_get_emission(shi, step_emit, step_sta, density); + vol_get_scattering(shi, step_scatter, step_end, stepsize, density); + + VecAddf(d_radiance, step_emit, step_scatter); + + /* 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); @@ -479,15 +504,32 @@ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) memset(shr, 0, sizeof(ShadeResult)); - if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) { + /* if original normal is facing away from the camera, + * then we're inside the volume already. + * so integrate from the camera to the shading coord */ + //if (INPR(shi->orignor, shi->view) < 0.0f) { + if (shi->flippednor) { - volumeintegrate(shi, col, shi->co, hitco, &is); + const float co_cam[3] = {0.0, 0.0, 0.0}; + volumeintegrate(shi, col, co_cam, shi->co, NULL); - /* hit */ shr->combined[0] = col[0]; shr->combined[1] = col[1]; shr->combined[2] = col[2]; - shr->combined[3] = 0.0f; + shr->combined[3] = 1.0f; + shr->alpha = col[3]; + + VECCOPY(shr->diff, shr->combined); + + } + else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) { + volumeintegrate(shi, col, shi->co, hitco, &is); + + + shr->combined[0] = col[0]; + shr->combined[1] = col[1]; + shr->combined[2] = col[2]; + shr->combined[3] = 1.0f; shr->alpha = col[3]; VECCOPY(shr->diff, shr->combined); @@ -496,7 +538,7 @@ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) /* no hit */ shr->combined[0] = 0.0f; shr->combined[1] = 0.0f; - shr->combined[2] = 0.0f; - shr->combined[3] = shr->alpha = 0.0f; + shr->combined[2] = 1.0f; + shr->combined[3] = shr->alpha = 1.0f; } } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 7db44e4c0eb..3972e4c3338 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4250,7 +4250,7 @@ static void material_panel_material_volume(Material *ma) uiBlockBeginAlign(block); uiDefButF(block, NUM, B_MATPRV, "Absorption: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 5.0, 0, 0, "Multiplier for absorption"); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 10.0, 10, 0, "Multiplier for absorption"); uiDefButF(block, COL, B_MATPRV, "", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption_col), 0, 0, 0, B_MATCOL, ""); @@ -4266,6 +4266,11 @@ static void material_panel_material_volume(Material *ma) uiBlockEndAlign(block); yco -= YSPACE; + + uiDefButF(block, NUM, B_MATPRV, "Scattering: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_scattering), 0.0, 10.0, 10, 0, "Multiplier for scattering"); + + yco -= YSPACE; uiBlockBeginAlign(block); uiDefButBitS(block, TOG, MA_VOL_ATTENUATED, B_MATPRV, "Shading", From 0417e79586fd1857ac101d17cd6038bc4f2efe3f Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 24 Sep 2008 07:49:24 +0000 Subject: [PATCH 08/88] * Moved the sample location for shading to the middle of the volumetric step. This fixes a nagging bug that would cause noise/odd moire-ish patterns, due to raytrace numerical errors: http://mke3.net/blender/devel/rendering/volumetrics/vol_clouds_moire.jpg --- source/blender/render/intern/source/volumetric.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 032175f522b..d4c3f393a0e 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -401,7 +401,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float float vec[3], stepvec[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 step_sta[3], step_end[3], step_mid[3]; float col_behind[3]; float total_density = 0.f; @@ -433,6 +433,9 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float /* there's only any point shading here * if there's actually some density to shade! */ if (density > 0.01f) { + step_mid[0] = step_sta[0] + (stepvec[0] * 0.5); + step_mid[1] = step_sta[1] + (stepvec[1] * 0.5); + step_mid[2] = step_sta[2] + (stepvec[2] * 0.5); /* transmittance component (alpha) */ vol_get_attenuation(shi, tau, step_sta, step_end, density, stepsize); @@ -444,8 +447,8 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float //if (rgb_to_luminance(tr[0], tr[1], tr[2]) < 1e-3) break; /* incoming light via emission or scattering (additive) */ - vol_get_emission(shi, step_emit, step_sta, density); - vol_get_scattering(shi, step_scatter, step_end, stepsize, density); + vol_get_emission(shi, step_emit, step_mid, density); + vol_get_scattering(shi, step_scatter, step_mid, stepsize, density); VecAddf(d_radiance, step_emit, step_scatter); From 707f2e300cb44891210bf0168489a0cfb36b3c69 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 25 Sep 2008 06:08:41 +0000 Subject: [PATCH 09/88] * Worked a bit on cleaning up the code involving layering volumes on solids, in front of other volumes, etc. Now there's a 'layer depth' value that works similarly to refraction depth - a limit for how many times the view ray will penetrate different volumetric surfaces. I have it close to being able to return alpha, but it's still not 100% correct and needs a bit more work. Going to sit on this for a while. --- source/blender/blenkernel/intern/material.c | 1 + source/blender/blenloader/intern/readfile.c | 1 + source/blender/makesdna/DNA_material_types.h | 2 +- .../render/extern/include/RE_shader_ext.h | 2 +- .../blender/render/intern/source/shadeinput.c | 4 + .../blender/render/intern/source/volumetric.c | 248 +++++++++--------- source/blender/src/buttons_shading.c | 54 ++-- 7 files changed, 159 insertions(+), 153 deletions(-) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 473a035ecce..8f4e65576d8 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -172,6 +172,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_raydepth = 15; 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 e106dd6cb59..658c14f5876 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7871,6 +7871,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) 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; + if (ma->vol_raydepth == 0) ma->vol_raydepth = 15; } } } diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index c322295fff9..d20ea600fea 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -71,8 +71,8 @@ typedef struct Material { float vol_absorption, vol_scattering; float vol_absorption_col[3]; float vpad2; + short vol_raydepth; short vol_shadeflag; - short vpad; float fresnel_mir, fresnel_mir_i; float fresnel_tra, fresnel_tra_i; diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index e8403053e0b..5d74895f0c8 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -113,7 +113,7 @@ typedef struct ShadeInput /* internal face coordinates */ float u, v, dx_u, dx_v, dy_u, dy_v; - float co[3], view[3]; + float co[3], view[3], camera_co[3]; /* copy from material, keep synced so we can do memcopy */ /* current size: 23*4 */ diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index cd5ecc413df..8d4206a75ae 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -671,6 +671,10 @@ void shade_input_set_viewco(ShadeInput *shi, float x, float y, float z) } } + /* set camera coords - for scanline, it's always 0.0,0.0,0.0 (render is in camera space) + * however for raytrace it can be different - the position of the last intersection */ + shi->camera_co[0] = shi->camera_co[1] = shi->camera_co[2] = 0.0f; + /* cannot normalize earlier, code above needs it at viewplane level */ Normalize(shi->view); } diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index d4c3f393a0e..4baeabcfa7a 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -55,7 +55,7 @@ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#if 0 + static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) { VlakRen *vlr = (VlakRen *)face; @@ -64,21 +64,33 @@ static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) * of foward facing geometry don't cause the ray to stop */ return (INPR(is->vec, vlr->n) < 0.0f); } -#endif -#define VOL_IS_SAMEOBJECT 1 +static int vol_frontface_intersect_check(Isect *is, int ob, RayFace *face) +{ + VlakRen *vlr = (VlakRen *)face; + + /* only consider faces away, so overlapping layers + * of foward facing geometry don't cause the ray to stop */ + return (INPR(is->vec, vlr->n) > 0.0f); +} + +static int vol_always_intersect_check(Isect *is, int ob, RayFace *face) +{ + return 1; +} + +#define VOL_IS_BACKFACE 1 #define VOL_IS_SAMEMATERIAL 2 #define VOL_BOUNDS_DEPTH 0 #define VOL_BOUNDS_SS 1 -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 */ +static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type, int checkfunc) { - /* TODO: Box or sphere intersection types could speed things up */ - - /* raytrace method */ float maxsize = RE_ray_tree_max_size(R.raytree); + int intersected=0; /* TODO: use object's bounding box to calculate max size */ VECCOPY(isect->start, co); @@ -86,16 +98,21 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, 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; - 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 (intersect_type == VOL_BOUNDS_DEPTH) isect->faceorig= (RayFace*)shi->vlr; + 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); + else + intersected = RE_ray_tree_intersect(R.raytree, isect); + + if(intersected) { float isvec[3]; @@ -245,7 +262,7 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * VecMulf(lv, -1.0f); /* find minimum of volume bounds, or lamp coord */ - if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) { + if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS, 0)) { float dist = VecLenf(co, hitco); if (ELEM(lar->type, LA_SUN, LA_HEMI)) @@ -312,87 +329,7 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi 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 vol_trace_behind(ShadeInput *shi, float *co, Isect *isect_first, float *col) -{ - RayFace *rforig=NULL; - Isect isect; - float maxsize = RE_ray_tree_max_size(R.raytree); - - if (isect_first != NULL) { - /* there was already a ray intersection - - * either the 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 { - rforig = isect_first->face; - } - } - - /* get ready to trace a new ray behind the volume */ - VECCOPY(isect.start, co) - - if (rforig == NULL) { - /* if there's no original ray intersection then the original - * shaded surface is the inside of the volume at the far bounds. - * We can use this face for the raytrace orig face */ - isect.faceorig= (RayFace *)shi->vlr; - } else { - isect.faceorig= rforig; - } - - isect.end[0] = isect.start[0] + shi->view[0] * maxsize; - isect.end[1] = isect.start[1] + shi->view[1] * maxsize; - isect.end[2] = isect.start[2] + shi->view[2] * maxsize; - - isect.mode= RE_RAY_MIRROR; - isect.oborig= RAY_OBJECT_SET(&R, shi->obi); - isect.face_last= NULL; - isect.ob_last= 0; - 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)) { - shade_intersection(shi, col, &isect); - } else { - shadeSkyView(col, co, shi->view, NULL); - } - -} - -static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco, Isect *isect) +static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco) { 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}; @@ -403,18 +340,17 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float int s; float step_sta[3], step_end[3], step_mid[3]; float col_behind[3]; - float total_density = 0.f; - + float alpha; float density = vol_get_density(shi, co); /* multiply col_behind with beam transmittance over entire distance */ - 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); + VecMulVecf(radiance, tr, col); tr[0] = tr[1] = tr[2] = 1.0f; + /* ray marching */ nsteps = (int)ceil(VecLenf(co, endco) / stepsize); @@ -444,7 +380,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float tr[2] *= exp(-tau[2]); /* Terminate raymarching if transmittance is small */ - //if (rgb_to_luminance(tr[0], tr[1], tr[2]) < 1e-3) break; + //if ((tr[0] + tr[1] + tr[2] * 0.333f) < 0.01f) continue; /* incoming light via emission or scattering (additive) */ vol_get_emission(shi, step_emit, step_mid, density); @@ -461,18 +397,14 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float VECCOPY(step_sta, step_end); VecAddf(step_end, step_end, stepvec); - - total_density += density; } - - col[0] = radiance[0]; col[1] = radiance[1]; col[2] = radiance[2]; - col[3] = 1.0f; - //col[3] = total_density * stepsize; + alpha = 1.0f -(tr[0] + tr[1] + tr[2]) * 0.333f; + col[3] = alpha; /* Incoming radiance = @@ -492,56 +424,124 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float -- To find radiance from segments along the way: find radiance for one step: - loop over lights and weight by phase function - - - single scattering - : integrate over sphere - - then multiply each step for final exit radiance */ } +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= shi->depth + 1; + 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; + + VECCOPY(shi_new.camera_co, is->start); + + memset(&shr_new, 0, sizeof(ShadeResult)); + + if (shi->depth < shi->mat->vol_raydepth) + shade_ray(is, &shi_new, &shr_new); + + col[0] = shr_new.combined[0]; + col[1] = shr_new.combined[1]; + col[2] = shr_new.combined[2]; + col[3] = shr_new.alpha; +} + +static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *col) +{ + Isect isect; + float maxsize = RE_ray_tree_max_size(R.raytree); + + VECCOPY(isect.start, co); + isect.end[0] = isect.start[0] + shi->view[0] * maxsize; + isect.end[1] = isect.start[1] + shi->view[1] * maxsize; + isect.end[2] = isect.start[2] + shi->view[2] * maxsize; + + isect.faceorig= (RayFace *)vlr; + + isect.mode= RE_RAY_MIRROR; + isect.oborig= RAY_OBJECT_SET(&R, shi->obi); + isect.face_last= NULL; + isect.ob_last= 0; + 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)) { + shade_intersection(shi, col, &isect); + } else { + shadeSkyView(col, co, shi->view, NULL); + } +} + void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) { - float hitco[3], col[4]; + float hitco[3], col[4] = {0.f,0.f,0.f,0.f}; Isect is; memset(shr, 0, sizeof(ShadeResult)); - /* if original normal is facing away from the camera, - * then we're inside the volume already. - * so integrate from the camera to the shading coord */ - //if (INPR(shi->orignor, shi->view) < 0.0f) { + /* if 1st hit normal is facing away from the camera, + * then we're inside the volume already. */ if (shi->flippednor) { + /* trace behind the 1st hit point */ + vol_trace_behind(shi, shi->vlr, shi->co, col); - const float co_cam[3] = {0.0, 0.0, 0.0}; - volumeintegrate(shi, col, co_cam, shi->co, NULL); + /* shade volume from 'camera' to 1st hit point */ + volumeintegrate(shi, col, shi->camera_co, shi->co); shr->combined[0] = col[0]; shr->combined[1] = col[1]; shr->combined[2] = col[2]; - shr->combined[3] = 1.0f; + + if (col[3] > 1.0f) col[3] = 1.0f; + shr->combined[3] = col[3]; shr->alpha = col[3]; VECCOPY(shr->diff, shr->combined); - } - else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) { - volumeintegrate(shi, col, shi->co, hitco, &is); + /* trace to find a backface, the other side bounds of the volume */ + /* (ray intersect ignores front faces here) */ + else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH, 0)) { + VlakRen *vlr = (VlakRen *)is.face; + + /* if it's another face in the same material */ + if (vlr->mat == shi->mat) { + /* trace behind the 2nd (raytrace) hit point */ + vol_trace_behind(shi, (VlakRen *)is.face, hitco, col); + } else { + shade_intersection(shi, col, &is); + } + + /* shade volume from 1st hit point to 2nd hit point */ + volumeintegrate(shi, col, shi->co, hitco); - shr->combined[0] = col[0]; shr->combined[1] = col[1]; shr->combined[2] = col[2]; - shr->combined[3] = 1.0f; + + //if (col[3] > 1.0f) + col[3] = 1.0f; + shr->combined[3] = col[3]; shr->alpha = col[3]; VECCOPY(shr->diff, shr->combined); } else { - /* no hit */ shr->combined[0] = 0.0f; shr->combined[1] = 0.0f; - shr->combined[2] = 1.0f; + shr->combined[2] = 0.0f; shr->combined[3] = shr->alpha = 1.0f; } } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 3972e4c3338..a288845c39d 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -3528,6 +3528,8 @@ static void material_panel_map_input(Object *ob, Material *ma) uiDefButS(block, ROW, B_MATPRV, "Object", 675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates"); uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_MATPRV, "Ob:",750,180,158,18, &(mtex->object), ""); uiDefButS(block, ROW, B_MATPRV, "Local", 630,160,55,18, &(mtex->texco), 4.0, (float)TEXCO_ORCO, 0, 0, "Uses the original undeformed coordinates of the object"); + + } else { uiDefButS(block, ROW, B_MATPRV, "Glob", 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates"); uiDefButS(block, ROW, B_MATPRV, "Object", 675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates"); @@ -4244,43 +4246,41 @@ 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"); uiDefButF(block, NUMSLI, B_MATPRV, "Density: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->alpha), 0.0, 1.0, 0, 0, "Base opacity value"); + uiDefButS(block, NUM, B_MATPRV, "Layer Depth: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_raydepth), 0.0, 512.0, 10, 2, "Number of layered volume ray intersections allowed per pixel"); uiBlockEndAlign(block); yco -= YSPACE; - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_MATPRV, "Absorption: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 10.0, 10, 0, "Multiplier for absorption"); - uiDefButF(block, COL, B_MATPRV, "", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption_col), 0, 0, 0, B_MATCOL, ""); - - uiBlockEndAlign(block); - - yco -= YSPACE; - - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_MATPRV, "Emit: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->emit), 0.0, 2.0, 0, 0, "Emission component"); - uiDefButF(block, COL, B_MATPRV, "", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->r), 0, 0, 0, B_MATCOL, ""); - uiBlockEndAlign(block); - - yco -= YSPACE; - - uiDefButF(block, NUM, B_MATPRV, "Scattering: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_scattering), 0.0, 10.0, 10, 0, "Multiplier for scattering"); - - yco -= YSPACE; - + uiBlockBeginAlign(block); uiDefButBitS(block, TOG, MA_VOL_ATTENUATED, B_MATPRV, "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"); uiBlockEndAlign(block); + + yco = PANEL_YMAX; + + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_MATPRV, "Absorption: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 10.0, 10, 0, "Multiplier for absorption"); + uiDefButF(block, COL, B_MATPRV, "", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption_col), 0, 0, 0, B_MATCOL, ""); + uiBlockEndAlign(block); - uiDefBut(block, LABEL, B_DIFF, "", - X2CLM2, yco, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + yco -= YSPACE; + + uiBlockBeginAlign(block); + uiDefButF(block, NUMSLI, B_MATPRV, "Emit: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->emit), 0.0, 2.0, 0, 0, "Emission component"); + uiDefButF(block, COL, B_MATPRV, "", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->r), 0, 0, 0, B_MATCOL, ""); + uiBlockEndAlign(block); + + yco -= YSPACE; + + uiDefButF(block, NUM, B_MATPRV, "Scattering: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_scattering), 0.0, 10.0, 10, 0, "Multiplier for scattering"); } static void material_panel_nodes(Material *ma) From 78c50f7af1d694252984885e0eac87682647e2d2 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 26 Sep 2008 01:54:31 +0000 Subject: [PATCH 10/88] Wheee! Initial commit for supporting rendering particles directly as volume density. It works by looking up how many particles are within a specified radius of the currently shaded point and using that to calculate density (which is used just as any other measure of density would be). http://mke3.net/blender/devel/rendering/volumetrics/smoke_test01.mov http://mke3.net/blender/devel/rendering/volumetrics/smoke_test01.blend Right now it's an early implementation, just to see that it can work - it may end up changing quite a bit. Currently, it's just a single switch on the volume material - it looks up all particles in the scene for density at the current shaded point in world space (so the volume region must enclose the particles in order to render them. This will probably change - one idea I have is to make the particle density estimation a procedural texture with options for: * the object and particle system to use * the origin of the co-ordinate system, i.e. object center, world space, etc. This would allow you in a sense, to instance particle systems for render - you only need to bake one particle system, but you can render it anywhere. Anyway, plenty of work to do here, firstly on getting a nice density evaluation with falloff etc... --- source/blender/makesdna/DNA_material_types.h | 3 +- .../render/intern/include/render_types.h | 12 +++++++ .../render/intern/include/renderdatabase.h | 2 ++ .../render/intern/source/convertblender.c | 13 +++++-- .../render/intern/source/renderdatabase.c | 15 ++++++++ .../blender/render/intern/source/volumetric.c | 35 ++++++++++++++++--- source/blender/src/buttons_shading.c | 9 +++++ 7 files changed, 82 insertions(+), 7 deletions(-) diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index d20ea600fea..814e9b9ab66 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -70,7 +70,7 @@ typedef struct Material { float vol_stepsize, vol_shade_stepsize; float vol_absorption, vol_scattering; float vol_absorption_col[3]; - float vpad2; + float vol_part_searchradius; short vol_raydepth; short vol_shadeflag; @@ -351,6 +351,7 @@ typedef struct Material { #define MA_VOL_SHADED 1 #define MA_VOL_ATTENUATED 2 #define MA_VOL_SHADOWED 4 +#define MA_VOL_PARTICLES 8 #endif diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 1768b052b54..2db70c460f9 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -198,6 +198,8 @@ struct Render ListBase *sss_points; struct Material *sss_mat; + struct KDTree *particles_tree; + ListBase customdata_names; struct Object *excludeob; @@ -347,6 +349,16 @@ typedef struct HaloRen /* ------------------------------------------------------------------------- */ +typedef struct ParticleRen +{ + struct ParticleRen *next, *prev; + float co[3]; // location + // float col[3]; // colour + // float vec[3]; // direction +} ParticleRen; + +/* ------------------------------------------------------------------------- */ + typedef struct StrandVert { float co[3]; float strandco; diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h index dc28eae1cc2..6fcd8576ed9 100644 --- a/source/blender/render/intern/include/renderdatabase.h +++ b/source/blender/render/intern/include/renderdatabase.h @@ -98,6 +98,8 @@ struct HaloRen *RE_inithalo(struct Render *re, struct ObjectRen *obr, struct Mat struct HaloRen *RE_inithalo_particle(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, struct Material *ma, float *vec, float *vec1, float *orco, float *uvco, float hasize, float vectsize, int seed); struct StrandBuffer *RE_addStrandBuffer(struct ObjectRen *obr, int totvert); +struct ParticleRen *RE_cache_particle(Render *re, float *co, int index, float *vec); + struct ObjectRen *RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int psysindex, int lay); struct ObjectInstanceRen *RE_addRenderInstance(struct Render *re, struct ObjectRen *obr, struct Object *ob, struct Object *par, int index, int psysindex, float mat[][4], int lay); void RE_makeRenderInstances(struct Render *re); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 17cd71ecb79..5eac30bf3be 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -41,6 +41,7 @@ #include "BLI_rand.h" #include "BLI_memarena.h" #include "BLI_ghash.h" +#include "BLI_kdtree.h" #include "DNA_armature_types.h" #include "DNA_camera_types.h" @@ -1475,8 +1476,9 @@ static void render_new_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mat static_particle_strand(re, obr, ma, orco, surfnor, uvco, totuv, mcol, totcol, loc, loc1, time, first, line, adapt, adapt_angle, adapt_pix, override_uv); } else{ - har= RE_inithalo_particle(re, obr, dm, ma, loc, NULL, orco, uvco, size, 0.0, seed); - if(har) har->lay= obr->ob->lay; + //har= RE_inithalo_particle(re, obr, dm, ma, loc, NULL, orco, uvco, size, 0.0, seed); + //if(har) har->lay= obr->ob->lay; + RE_cache_particle(re, loc, 0, loc1); } } static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem *psys, int timeoffset) @@ -1703,6 +1705,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if(path_nbr==0) psys->lattice=psys_get_lattice(ob,psys); + re->particles_tree = BLI_kdtree_new(totpart+totchild); + /* 3. start creating renderable things */ for(a=0,pa=pars; asurface= cache_strand_surface(re, obr, psmd->dm, mat, timeoffset); /* 4. clean up */ + if (re->particles_tree) + BLI_kdtree_balance(re->particles_tree); + if(ma) do_mat_ipo(ma); if(orco1) @@ -4410,6 +4417,8 @@ void RE_Database_Free(Render *re) BLI_freelistN(&re->lampren); BLI_freelistN(&re->lights); + + BLI_kdtree_free(re->particles_tree); free_renderdata_tables(re); diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index d44b49cc706..7fc8dc05ec3 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -1041,6 +1041,21 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, float *vec, f return har; } +ParticleRen *RE_cache_particle(Render *re, float *co, int index, float *vec) +{ + /* + ParticleRen *pr; + + pr= (LampRen *)MEM_callocN(sizeof(ParticleRen),"particleren"); + VECCOPY(pr->co, co); + BLI_addtail(&re->vol_particles, pr); + */ + + BLI_kdtree_insert(re->particles_tree, index, co, vec); + + +} + HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, float *vec, float *vec1, float *orco, float *uvco, float hasize, float vectsize, int seed) { diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 4baeabcfa7a..83250ebfd36 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -34,6 +34,7 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_rand.h" +#include "BLI_kdtree.h" #include "RE_shader_ext.h" #include "RE_raytrace.h" @@ -127,14 +128,41 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, } } +/* need to figure out a good default here */ +#define MAX_PARTICLES_NEAREST 10 +float get_particle_density(float *co, float radius) +{ + KDTreeNearest nearest[MAX_PARTICLES_NEAREST]; + float density=0.0f; + int n, neighbours=0; + + /* no particles in preview for now - + * can check for existence of particle kdtree better later on */ + if(R.r.scemode & R_PREVIEWBUTS) return; + + neighbours = BLI_kdtree_find_n_nearest(R.particles_tree, MAX_PARTICLES_NEAREST, co, NULL, nearest); + + for(n=1; nmat->alpha; float col[3] = {0.0, 0.0, 0.0}; - - /* do any density gain stuff here */ - if (shi->mat->flag & MA_IS_TEXTURED) + + if (shi->mat->vol_shadeflag & MA_VOL_PARTICLES) { + density += get_particle_density(co, shi->mat->vol_part_searchradius); + } + else if (shi->mat->flag & MA_IS_TEXTURED) { do_volume_tex(shi, co, MAP_ALPHA, col, &density); + } return density; } @@ -339,7 +367,6 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float float tau[3], step_emit[3], step_scatter[3] = {0.0, 0.0, 0.0}; int s; float step_sta[3], step_end[3], step_mid[3]; - float col_behind[3]; float alpha; float density = vol_get_density(shi, co); diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index a288845c39d..50e5e69ea16 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4281,6 +4281,15 @@ static void material_panel_material_volume(Material *ma) uiDefButF(block, NUM, B_MATPRV, "Scattering: ", X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_scattering), 0.0, 10.0, 10, 0, "Multiplier for scattering"); + + yco -= YSPACE; + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, MA_VOL_PARTICLES, B_MATPRV, "Particles", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shadeflag), 0, 0, 0, 0, "Render global particle cache"); + uiDefButF(block, NUM, B_MATPRV, "Search Radius: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_part_searchradius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); + uiBlockEndAlign(block); } static void material_panel_nodes(Material *ma) From 5adff90b0868f88050e601092b35628fa3ae132b Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 26 Sep 2008 07:12:36 +0000 Subject: [PATCH 11/88] * Some more tweaks to particle density rendering. I'm not 100% sure if this is 'correct' but so far in testing it's been working pretty well. This also exposes a new 'Nearest' value, to determine how many nearby particles are taken into account when determining density. A greater number is more accurate, but slower. --- source/blender/blenkernel/intern/material.c | 4 +++- source/blender/blenloader/intern/readfile.c | 2 ++ source/blender/makesdna/DNA_material_types.h | 3 +++ .../render/intern/source/renderdatabase.c | 2 +- .../blender/render/intern/source/volumetric.c | 18 ++++++++++++------ source/blender/src/buttons_shading.c | 4 +++- 6 files changed, 24 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 8f4e65576d8..04a68d1b1e1 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -173,7 +173,9 @@ void init_material(Material *ma) ma->vol_scattering = 1.0f; ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f; ma->vol_raydepth = 15; - + ma->vol_part_maxnearest = 5; + ma->vol_part_searchradius = 0.2f; + ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RADIO|MA_RAYBIAS|MA_TANGENT_STR; ma->preview = NULL; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 658c14f5876..49ad3096957 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7872,6 +7872,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) ma->vol_scattering = 1.0f; ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f; if (ma->vol_raydepth == 0) ma->vol_raydepth = 15; + if (ma->vol_part_maxnearest == 0) ma->vol_part_maxnearest = 5; + if (ma->vol_part_searchradius < 0.001f) ma->vol_part_searchradius = 0.20; } } } diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 814e9b9ab66..dc23e7fcc6a 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -72,7 +72,10 @@ typedef struct Material { float vol_absorption_col[3]; float vol_part_searchradius; short vol_raydepth; + short vol_part_maxnearest; short vol_shadeflag; + short vol_pad[3]; + float fresnel_mir, fresnel_mir_i; float fresnel_tra, fresnel_tra_i; diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 7fc8dc05ec3..14288167c4a 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -1051,7 +1051,7 @@ ParticleRen *RE_cache_particle(Render *re, float *co, int index, float *vec) BLI_addtail(&re->vol_particles, pr); */ - BLI_kdtree_insert(re->particles_tree, index, co, vec); + BLI_kdtree_insert(re->particles_tree, index, co, NULL); } diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 83250ebfd36..543c89f6b96 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -129,8 +129,8 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, } /* need to figure out a good default here */ -#define MAX_PARTICLES_NEAREST 10 -float get_particle_density(float *co, float radius) +#define MAX_PARTICLES_NEAREST 50 +float get_particle_density(float *co, float radius, int max_nearest) { KDTreeNearest nearest[MAX_PARTICLES_NEAREST]; float density=0.0f; @@ -140,14 +140,20 @@ float get_particle_density(float *co, float radius) * can check for existence of particle kdtree better later on */ if(R.r.scemode & R_PREVIEWBUTS) return; - neighbours = BLI_kdtree_find_n_nearest(R.particles_tree, MAX_PARTICLES_NEAREST, co, NULL, nearest); + neighbours = BLI_kdtree_find_n_nearest(R.particles_tree, max_nearest, co, NULL, nearest); for(n=1; nmat->vol_shadeflag & MA_VOL_PARTICLES) { - density += get_particle_density(co, shi->mat->vol_part_searchradius); + density += get_particle_density(co, shi->mat->vol_part_searchradius, shi->mat->vol_part_maxnearest); } else if (shi->mat->flag & MA_IS_TEXTURED) { do_volume_tex(shi, co, MAP_ALPHA, col, &density); diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 50e5e69ea16..4e6560a035a 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4287,8 +4287,10 @@ static void material_panel_material_volume(Material *ma) uiBlockBeginAlign(block); uiDefButBitS(block, TOG, MA_VOL_PARTICLES, B_MATPRV, "Particles", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shadeflag), 0, 0, 0, 0, "Render global particle cache"); - uiDefButF(block, NUM, B_MATPRV, "Search Radius: ", + uiDefButF(block, NUM, B_MATPRV, "Radius: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_part_searchradius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); + uiDefButS(block, NUM, B_MATPRV, "Nearby: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_part_maxnearest), 2.0, 30.0, 10, 2, "The number of nearby particles to check for density"); uiBlockEndAlign(block); } From 8056705ae9b2467a013f2372c0579687d3723229 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sun, 28 Sep 2008 08:00:22 +0000 Subject: [PATCH 12/88] * Volumetrics Removed all the old particle rendering code and options I had in there before, in order to make way for... A new procedural texture: 'Point Density' Point Density is a 3d texture that find the density of a group of 'points' in space and returns that in the texture as an intensity value. Right now, its at an early stage and it's only enabled for particles, but it would be cool to extend it later for things like object vertices, or point cache files from disk - i.e. to import point cloud data into Blender for rendering volumetrically. Currently there are just options for an Object and its particle system number, this is the particle system that will get cached before rendering, and then used for the texture's density estimation. It works totally consistent with as any other procedural texture, so previously where I've mapped a clouds texture to volume density to make some of those test renders, now I just map a point density texture to volume density. Here's a version of the same particle smoke test file from before, updated to use the point density texture instead: http://mke3.net/blender/devel/rendering/volumetrics/smoke_test02.blend There are a few cool things about implementing this as a texture: - The one texture (and cache) can be instanced across many different materials: http://mke3.net/blender/devel/rendering/volumetrics/pointdensity_instanced.png This means you can calculate and bake one particle system, but render it multiple times across the scene, with different material settings, at no extra memory cost. Right now, the particles are cached in world space, so you have to map it globally, and if you want it offset, you have to do it in the material (as in the file above). I plan to add an option to bake in local space, so you can just map the texture to local and it just works. - It also works for solid surfaces too, it just gets the density at that particular point on the surface, eg: http://mke3.net/blender/devel/rendering/volumetrics/pointdensity_solid.mov - You can map it to whatever you want, not only density but the various emissions and colours as well. I'd like to investigate using the other outputs in the texture too (like the RGB or normal outputs), perhaps with options to colour by particle age, generating normals for making particle 'dents' in a surface, whatever! --- source/blender/blenkernel/BKE_texture.h | 6 + source/blender/blenkernel/intern/material.c | 2 - source/blender/blenkernel/intern/texture.c | 47 +++++ source/blender/blenloader/intern/readfile.c | 7 +- source/blender/blenloader/intern/writefile.c | 1 + source/blender/makesdna/DNA_material_types.h | 8 +- source/blender/makesdna/DNA_texture_types.h | 30 +++ .../render/intern/include/pointdensity.h | 43 ++++ .../render/intern/include/render_types.h | 11 - .../render/intern/include/renderdatabase.h | 2 - .../render/intern/source/convertblender.c | 18 +- .../render/intern/source/pointdensity.c | 195 ++++++++++++++++++ .../render/intern/source/renderdatabase.c | 15 -- source/blender/render/intern/source/texture.c | 4 + .../blender/render/intern/source/volumetric.c | 35 +--- source/blender/src/buttons_shading.c | 61 ++++-- 16 files changed, 391 insertions(+), 94 deletions(-) create mode 100644 source/blender/render/intern/include/pointdensity.h create mode 100644 source/blender/render/intern/source/pointdensity.c diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index cfcae3c44bc..e16ac2d369b 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -39,6 +39,7 @@ struct ColorBand; struct HaloRen; struct TexMapping; struct EnvMap; +struct PointDensity; /* in ColorBand struct */ #define MAXCOLORBAND 32 @@ -74,6 +75,11 @@ void BKE_free_envmap(struct EnvMap *env); struct EnvMap *BKE_add_envmap(void); struct EnvMap *BKE_copy_envmap(struct EnvMap *env); +void BKE_free_pointdensitydata(struct PointDensity *pd); +void BKE_free_pointdensity(struct PointDensity *pd); +struct PointDensity *BKE_add_pointdensity(void); +struct PointDensity *BKE_copy_pointdensity(struct PointDensity *pd); + int BKE_texture_dependsOnTime(const struct Tex *texture); #endif diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 04a68d1b1e1..64125d5834e 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -173,8 +173,6 @@ void init_material(Material *ma) ma->vol_scattering = 1.0f; ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f; ma->vol_raydepth = 15; - ma->vol_part_maxnearest = 5; - ma->vol_part_searchradius = 0.2f; ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RADIO|MA_RAYBIAS|MA_TANGENT_STR; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index bb726887d32..62bab45dd50 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -409,6 +409,7 @@ void free_texture(Tex *tex) free_plugin_tex(tex->plugin); if(tex->coba) MEM_freeN(tex->coba); if(tex->env) BKE_free_envmap(tex->env); + if(tex->pd) BKE_free_pointdensity(tex->pd); BKE_previewimg_free(&tex->preview); BKE_icon_delete((struct ID*)tex); tex->id.icon_id = 0; @@ -470,6 +471,11 @@ void default_tex(Tex *tex) tex->env->depth=0; } + if (tex->pd) { + tex->pd->radius = 0.3f; + tex->pd->nearest = 5; + } + pit = tex->plugin; if (pit) { varstr= pit->varstr; @@ -566,6 +572,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(tex->preview) texn->preview = BKE_previewimg_copy(tex->preview); @@ -858,6 +865,46 @@ void BKE_free_envmap(EnvMap *env) } +/* ------------------------------------------------------------------------- */ + +PointDensity *BKE_add_pointdensity(void) +{ + PointDensity *pd; + + pd= MEM_callocN(sizeof(PointDensity), "pointdensity"); + pd->radius = 0.3f; + pd->nearest = 5; + pd->type = TEX_PD_PSYS; + pd->point_tree = NULL; + + return pd; +} + +PointDensity *BKE_copy_pointdensity(PointDensity *pd) +{ + PointDensity *pdn; + int a; + + pdn= MEM_dupallocN(pd); + pdn->point_tree = NULL; + + return pd; +} + +void BKE_free_pointdensitydata(PointDensity *pd) +{ + if (pd->point_tree) { + BLI_kdtree_free(pd->point_tree); + pd->point_tree = NULL; + } +} + +void BKE_free_pointdensity(PointDensity *pd) +{ + BKE_free_pointdensitydata(pd); + MEM_freeN(pd); +} + /* ------------------------------------------------------------------------- */ int BKE_texture_dependsOnTime(const struct Tex *texture) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index e80d2c7ce67..8aa0c8c5d5e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2475,6 +2475,7 @@ static void lib_link_texture(FileData *fd, Main *main) tex->ima= newlibadr_us(fd, tex->id.lib, tex->ima); tex->ipo= newlibadr_us(fd, tex->id.lib, tex->ipo); if(tex->env) tex->env->object= newlibadr(fd, tex->id.lib, tex->env->object); + if(tex->pd) tex->pd->object= newlibadr(fd, tex->id.lib, tex->pd->object); tex->id.flag -= LIB_NEEDLINK; } @@ -2501,6 +2502,10 @@ static void direct_link_texture(FileData *fd, Tex *tex) memset(tex->env->cube, 0, 6*sizeof(void *)); tex->env->ok= 0; } + tex->pd= newdataadr(fd, tex->pd); + if(tex->pd) { + tex->pd->point_tree = NULL; + } tex->preview = direct_link_preview_image(fd, tex->preview); tex->iuser.ok= 1; @@ -7885,8 +7890,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) ma->vol_scattering = 1.0f; ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f; if (ma->vol_raydepth == 0) ma->vol_raydepth = 15; - if (ma->vol_part_maxnearest == 0) ma->vol_part_maxnearest = 5; - if (ma->vol_part_searchradius < 0.001f) ma->vol_part_searchradius = 0.20; } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index e53c725867a..c4ae6ef858b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1334,6 +1334,7 @@ static void write_textures(WriteData *wd, ListBase *idbase) if(tex->plugin) writestruct(wd, DATA, "PluginTex", 1, tex->plugin); if(tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba); if(tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env); + if(tex->pd) writestruct(wd, DATA, "PointDensity", 1, tex->pd); write_previews(wd, tex->preview); } diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index dc23e7fcc6a..5d5ae042950 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -70,13 +70,10 @@ typedef struct Material { float vol_stepsize, vol_shade_stepsize; float vol_absorption, vol_scattering; float vol_absorption_col[3]; - float vol_part_searchradius; short vol_raydepth; - short vol_part_maxnearest; short vol_shadeflag; - short vol_pad[3]; - - + int volpad; + float fresnel_mir, fresnel_mir_i; float fresnel_tra, fresnel_tra_i; float filter; /* filter added, for raytrace transparency and transmissivity */ @@ -354,7 +351,6 @@ typedef struct Material { #define MA_VOL_SHADED 1 #define MA_VOL_ATTENUATED 2 #define MA_VOL_SHADOWED 4 -#define MA_VOL_PARTICLES 8 #endif diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 111dc08ee02..ed172c24474 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -127,6 +127,22 @@ typedef struct EnvMap { short recalc, lastsize; } EnvMap; +typedef struct PointDensity { + short flag; + + short nearest; + float radius; + + short type; + short pdpad[3]; + + struct Object *object; /* for 'Particle system' type - source object */ + short psysindex; /* and object's psys number */ + short pdpad2[3]; + + void *point_tree; /* the kd-tree containing points */ +} PointDensity; + typedef struct Tex { ID id; @@ -172,6 +188,7 @@ typedef struct Tex { struct ColorBand *coba; struct EnvMap *env; struct PreviewImage * preview; + struct PointDensity *pd; } Tex; @@ -208,6 +225,8 @@ typedef struct TexMapping { #define TEX_MUSGRAVE 11 #define TEX_VORONOI 12 #define TEX_DISTNOISE 13 +/* predicting ocean texture for 14 */ +#define TEX_POINTDENSITY 15 /* musgrave stype */ #define TEX_MFRACTAL 0 @@ -385,5 +404,16 @@ typedef struct TexMapping { #define ENV_NORMAL 1 #define ENV_OSA 2 +/* **************** PointDensity ********************* */ + +/* type */ +#define TEX_PD_PSYS 0 +#define TEX_PD_OBJECT 1 +#define TEX_PD_FILE 2 + +/* psys_space */ +#define TEX_PD_PSYS_WORLDSPACE 0 +#define TEX_PD_PSYS_OBJECTSPACE 1 + #endif diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h new file mode 100644 index 00000000000..9c21cc0c253 --- /dev/null +++ b/source/blender/render/intern/include/pointdensity.h @@ -0,0 +1,43 @@ +/* + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Matt Ebb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef POINTDENSITY_H +#define POINTDENSITY_H + +/** + * Make point density kd-trees for all point density textures in the scene + */ + +struct Render; +struct TexResult; + +void make_pointdensities(struct Render *re); +int pointdensitytex(struct Tex *tex, float *texvec, struct TexResult *texres); + +#endif /* POINTDENSITY_H */ + diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 2db70c460f9..b0003cadb55 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -198,8 +198,6 @@ struct Render ListBase *sss_points; struct Material *sss_mat; - struct KDTree *particles_tree; - ListBase customdata_names; struct Object *excludeob; @@ -347,15 +345,6 @@ typedef struct HaloRen struct Material *mat; } HaloRen; -/* ------------------------------------------------------------------------- */ - -typedef struct ParticleRen -{ - struct ParticleRen *next, *prev; - float co[3]; // location - // float col[3]; // colour - // float vec[3]; // direction -} ParticleRen; /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h index 6fcd8576ed9..dc28eae1cc2 100644 --- a/source/blender/render/intern/include/renderdatabase.h +++ b/source/blender/render/intern/include/renderdatabase.h @@ -98,8 +98,6 @@ struct HaloRen *RE_inithalo(struct Render *re, struct ObjectRen *obr, struct Mat struct HaloRen *RE_inithalo_particle(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, struct Material *ma, float *vec, float *vec1, float *orco, float *uvco, float hasize, float vectsize, int seed); struct StrandBuffer *RE_addStrandBuffer(struct ObjectRen *obr, int totvert); -struct ParticleRen *RE_cache_particle(Render *re, float *co, int index, float *vec); - struct ObjectRen *RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int psysindex, int lay); struct ObjectInstanceRen *RE_addRenderInstance(struct Render *re, struct ObjectRen *obr, struct Object *ob, struct Object *par, int index, int psysindex, float mat[][4], int lay); void RE_makeRenderInstances(struct Render *re); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 5eac30bf3be..40e9a32d003 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -103,6 +103,7 @@ #include "envmap.h" #include "multires.h" #include "occlusion.h" +#include "pointdensity.h" #include "render_types.h" #include "rendercore.h" #include "renderdatabase.h" @@ -1476,9 +1477,8 @@ static void render_new_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mat static_particle_strand(re, obr, ma, orco, surfnor, uvco, totuv, mcol, totcol, loc, loc1, time, first, line, adapt, adapt_angle, adapt_pix, override_uv); } else{ - //har= RE_inithalo_particle(re, obr, dm, ma, loc, NULL, orco, uvco, size, 0.0, seed); - //if(har) har->lay= obr->ob->lay; - RE_cache_particle(re, loc, 0, loc1); + har= RE_inithalo_particle(re, obr, dm, ma, loc, NULL, orco, uvco, size, 0.0, seed); + if(har) har->lay= obr->ob->lay; } } static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem *psys, int timeoffset) @@ -1705,8 +1705,6 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if(path_nbr==0) psys->lattice=psys_get_lattice(ob,psys); - re->particles_tree = BLI_kdtree_new(totpart+totchild); - /* 3. start creating renderable things */ for(a=0,pa=pars; asurface= cache_strand_surface(re, obr, psmd->dm, mat, timeoffset); /* 4. clean up */ - if (re->particles_tree) - BLI_kdtree_balance(re->particles_tree); if(ma) do_mat_ipo(ma); @@ -4417,8 +4413,6 @@ void RE_Database_Free(Render *re) BLI_freelistN(&re->lampren); BLI_freelistN(&re->lights); - - BLI_kdtree_free(re->particles_tree); free_renderdata_tables(re); @@ -4441,6 +4435,8 @@ void RE_Database_Free(Render *re) end_radio_render(); end_render_materials(); + free_pointdensities(re); + if(re->wrld.aosphere) { MEM_freeN(re->wrld.aosphere); re->wrld.aosphere= NULL; @@ -4890,6 +4886,10 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) /* ENVIRONMENT MAPS */ if(!re->test_break()) make_envmaps(re); + + /* point density texture */ + if(!re->test_break()) + make_pointdensities(re); } if(!re->test_break()) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c new file mode 100644 index 00000000000..00dbbd34f96 --- /dev/null +++ b/source/blender/render/intern/source/pointdensity.c @@ -0,0 +1,195 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: Matt Ebb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include + +#include "BLI_kdtree.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_global.h" +#include "BKE_main.h" + +#include "DNA_texture_types.h" +#include "DNA_particle_types.h" + +#include "render_types.h" +#include "texture.h" + + +static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys) +{ + DerivedMesh* dm; + ParticleKey state; + float cfra=bsystem_time(ob,(float)G.scene->r.cfra,0.0); + int i, childexists; + + /* init crap */ + if (!psys || !ob || !pd) return; + + /* Just to create a valid rendering context */ + psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0); + + dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + dm->release(dm); + + if ( !psys_check_enabled(ob, psys) ){ + psys_render_restore(ob, psys); + return; + } + + /* finally do something */ + pd->point_tree = BLI_kdtree_new(psys->totpart+psys->totchild); + + if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) + childexists = 1; + + for (i = 0; i < psys->totpart + psys->totchild; i++) { + + state.time = cfra; + if(psys_get_particle_state(ob, psys, i, &state, 0)) { + BLI_kdtree_insert(pd->point_tree, 0, state.co, NULL); + } + } + + BLI_kdtree_balance(pd->point_tree); + psys_render_restore(ob, psys); +} + + +static void cache_pointdensity(Render *re, Tex *tex) +{ + PointDensity *pd = tex->pd; + + if (pd->point_tree) { + BLI_kdtree_free(pd->point_tree); + pd->point_tree = NULL; + } + + if (pd->type == TEX_PD_PSYS) { + ParticleSystem *psys; + Object *ob = pd->object; + int i; + + for(psys=ob->particlesystem.first, i=0; i< pd->psysindex-1; i++) + psys= psys->next; + + if (!ob || !psys) return; + + pointdensity_cache_psys(re, pd, ob, psys); + } +} + +static void free_pointdensity(Render *re, Tex *tex) +{ + PointDensity *pd = tex->pd; + + if (pd->point_tree) { + BLI_kdtree_free(pd->point_tree); + pd->point_tree = NULL; + } +} + + + +void make_pointdensities(Render *re) +{ + Tex *tex; + + if(re->scene->r.scemode & R_PREVIEWBUTS) + return; + + re->i.infostr= "Caching Point Densities"; + re->stats_draw(&re->i); + + for (tex= G.main->tex.first; tex; tex= tex->id.next) { + if(tex->id.us && tex->type==TEX_POINTDENSITY) { + cache_pointdensity(re, tex); + } + } +} + +void free_pointdensities(Render *re) +{ + Tex *tex; + + if(re->scene->r.scemode & R_PREVIEWBUTS) + return; + + for (tex= G.main->tex.first; tex; tex= tex->id.next) { + if(tex->id.us && tex->type==TEX_POINTDENSITY) { + free_pointdensity(re, tex); + } + } +} + +#define MAX_POINTS_NEAREST 25 +int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) +{ + int rv = TEX_INT; + + PointDensity *pd = tex->pd; + KDTreeNearest nearest[MAX_POINTS_NEAREST]; + float density=0.0f; + int n, neighbours=0; + + if ((!pd) || (!pd->point_tree)) { + texres->tin = 0.0f; + return 0; + } + + neighbours = BLI_kdtree_find_n_nearest(pd->point_tree, pd->nearest, texvec, NULL, nearest); + + for(n=1; nradius) { + float dist = 1.0 - (nearest[n].dist / pd->radius); + + density += 3.0f*dist*dist - 2.0f*dist*dist*dist; + } + } + + density /= neighbours; + density *= 1.0 / pd->radius; + + texres->tin = density; + + /* + texres->tr = 1.0f; + texres->tg = 1.0f; + texres->tb = 0.0f; + + BRICONTRGB; + + texres->ta = 1.0; + + if (texres->nor!=NULL) { + texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f; + } + */ + + BRICONT; + + return rv; +} \ No newline at end of file diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 14288167c4a..d44b49cc706 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -1041,21 +1041,6 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, float *vec, f return har; } -ParticleRen *RE_cache_particle(Render *re, float *co, int index, float *vec) -{ - /* - ParticleRen *pr; - - pr= (LampRen *)MEM_callocN(sizeof(ParticleRen),"particleren"); - VECCOPY(pr->co, co); - BLI_addtail(&re->vol_particles, pr); - */ - - BLI_kdtree_insert(re->particles_tree, index, co, NULL); - - -} - HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, float *vec, float *vec1, float *orco, float *uvco, float hasize, float vectsize, int seed) { diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 2c143986900..3df53f7041a 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -62,6 +62,7 @@ #include "BKE_ipo.h" #include "envmap.h" +#include "pointdensity.h" #include "renderpipeline.h" #include "render_types.h" #include "rendercore.h" @@ -1216,6 +1217,9 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, retval= mg_distNoiseTex(tex, tmpvec, texres); break; + case TEX_POINTDENSITY: + retval= pointdensitytex(tex, texvec, texres); + break; } if (tex->flag & TEX_COLORBAND) { diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 543c89f6b96..dcff34429b6 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -128,45 +128,12 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, } } -/* need to figure out a good default here */ -#define MAX_PARTICLES_NEAREST 50 -float get_particle_density(float *co, float radius, int max_nearest) -{ - KDTreeNearest nearest[MAX_PARTICLES_NEAREST]; - float density=0.0f; - int n, neighbours=0; - - /* no particles in preview for now - - * can check for existence of particle kdtree better later on */ - if(R.r.scemode & R_PREVIEWBUTS) return; - - neighbours = BLI_kdtree_find_n_nearest(R.particles_tree, max_nearest, co, NULL, nearest); - - for(n=1; nmat->alpha; float col[3] = {0.0, 0.0, 0.0}; - if (shi->mat->vol_shadeflag & MA_VOL_PARTICLES) { - density += get_particle_density(co, shi->mat->vol_part_searchradius, shi->mat->vol_part_maxnearest); - } - else if (shi->mat->flag & MA_IS_TEXTURED) { + if (shi->mat->flag & MA_IS_TEXTURED) { do_volume_tex(shi, co, MAP_ALPHA, col, &density); } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 0cfe469b7da..002c62c1a17 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -731,6 +731,49 @@ static void texture_panel_voronoi(Tex *tex) uiDefButF(block, NUMSLI, B_TEXPRV, "W4: ", 10, 10, 150, 19, &tex->vn_w4, -2.0, 2.0, 10, 0, "Sets feature weight 4"); } +static void texture_panel_pointdensity(Tex *tex) +{ + uiBlock *block; + PointDensity *pd; + short yco=PANEL_YMAX; + + block= uiNewBlock(&curarea->uiblocks, "texture_panel_pointdensity", UI_EMBOSS, UI_HELV, curarea->win); + if(uiNewPanel(curarea, block, "Point Density", "Texture", PANELX, PANELY, PANELW, PANELH)==0) return; + uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE); + + if(tex->pd==NULL) { + tex->pd= BKE_add_pointdensity(); + tex->pd->object= OBACT; + } + if(tex->pd) { + pd= tex->pd; + + uiBlockBeginAlign(block); + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object that has the particle system"); + + if (pd->object->particlesystem.first) { + uiDefButS(block, NUM, B_REDR, "PSys:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->psysindex), 1, 10, 10, 3, "Particle system number in the object"); + } + uiBlockEndAlign(block); + + yco -= YSPACE; + + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_REDR, "Radius: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->radius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); + uiDefButS(block, NUM, B_REDR, "Nearby: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->nearest), 2.0, 30.0, 10, 2, "The number of nearby particles to check for density"); + uiBlockEndAlign(block); + + uiDefBut(block, LABEL, B_NOP, " ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + } + + +} + static char *layer_menu(RenderResult *rr, short *curlay) { @@ -1688,7 +1731,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 */ - 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", 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); + 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); 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"); @@ -4272,7 +4315,7 @@ static void material_panel_material_volume(Material *ma) uiDefButF(block, NUM, B_MATPRV, "Absorption: ", X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 10.0, 10, 0, "Multiplier for absorption"); uiDefButF(block, COL, B_MATPRV, "", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption_col), 0, 0, 0, B_MATCOL, ""); + X2CLM2, yco-=BUTH, BUTW2, BUTH, ma->vol_absorption_col, 0, 0, 0, B_MATCOL, ""); uiBlockEndAlign(block); yco -= YSPACE; @@ -4288,17 +4331,6 @@ static void material_panel_material_volume(Material *ma) uiDefButF(block, NUM, B_MATPRV, "Scattering: ", X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_scattering), 0.0, 10.0, 10, 0, "Multiplier for scattering"); - - yco -= YSPACE; - - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, MA_VOL_PARTICLES, B_MATPRV, "Particles", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shadeflag), 0, 0, 0, 0, "Render global particle cache"); - uiDefButF(block, NUM, B_MATPRV, "Radius: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_part_searchradius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); - uiDefButS(block, NUM, B_MATPRV, "Nearby: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_part_maxnearest), 2.0, 30.0, 10, 2, "The number of nearby particles to check for density"); - uiBlockEndAlign(block); } static void material_panel_nodes(Material *ma) @@ -4683,6 +4715,9 @@ void texture_panels() case TEX_VORONOI: texture_panel_voronoi(tex); break; + case TEX_POINTDENSITY: + texture_panel_pointdensity(tex); + break; } } } From 345dc8eb9464efdf6cccac8dddc2cd24e1fe3dbb Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sun, 28 Sep 2008 23:40:36 +0000 Subject: [PATCH 13/88] Fix: point density texture now works with the 'auto name' button --- source/blender/src/butspace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/src/butspace.c b/source/blender/src/butspace.c index 5b5c7f2d5ba..f134e9a9650 100644 --- a/source/blender/src/butspace.c +++ b/source/blender/src/butspace.c @@ -92,7 +92,7 @@ MTex mtexcopybuf; char texstr[20][12]= {"None" , "Clouds" , "Wood", "Marble", "Magic" , "Blend", "Stucci", "Noise" , "Image", "Plugin", "EnvMap" , "Musgrave", - "Voronoi", "DistNoise", "", "", "", "", "", ""}; + "Voronoi", "DistNoise", "", "PointDensity", "", "", "", ""}; /* ---------------------------------------------------------------------- */ void test_idbutton_cb(void *namev, void *arg2) From bab94c46e07563c65e7a1b0392d70814ddf0de28 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 29 Sep 2008 04:19:24 +0000 Subject: [PATCH 14/88] Point Density texture The Point Density texture now has some additional options for how the point locations are cached. Previously it was all relative to worldspace, but there are now some other options that make things a lot more convenient for mapping the texture to Local (or Orco). Thanks to theeth for helping with the space conversions! The new Object space options allow this sort of thing to be possible - a particle system, instanced on a transformed renderable object: http://mke3.net/blender/devel/rendering/volumetrics/pd_objectspace.mov It's also a lot easier to use multiple instances, just duplicate the renderable objects and move them around. The new particle cache options are: * Emit Object space This caches the particles relative to the emitter object's coordinate space (i.e. relative to the emitter's object center). This makes it possible to map the Texture to Local or Orco easily, so you can easily move, rotate or scale the rendering object that has the Point Density texture. It's relative to the emitter's location, rotation and scale, so if the object you're rendering the texture on is aligned differently to the emitter, the results will be rotated etc. * Emit Object Location This offsets the particles to the emitter object's location in 3D space. It's similar to Emit Object Space, however the emitter object's rotation and scale are ignored. This is probably the easiest to use, since you don't need to worry about the rotation and scale of the emitter object (just the rendered object), so it's the default. * Global Space This is the same as previously, the particles are cached in global space, so to use this effectively you'll need to map the texture to Global, and have the rendered object in the right global location. --- source/blender/blenkernel/intern/texture.c | 6 +-- source/blender/makesdna/DNA_texture_types.h | 13 +++-- .../render/intern/source/pointdensity.c | 32 +++++++++++-- source/blender/src/buttons_shading.c | 48 ++++++++++++------- 4 files changed, 71 insertions(+), 28 deletions(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 62bab45dd50..45fd11faa32 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -43,6 +43,7 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_rand.h" +#include "BLI_kdtree.h" #include "DNA_texture_types.h" #include "DNA_key_types.h" @@ -874,7 +875,7 @@ PointDensity *BKE_add_pointdensity(void) pd= MEM_callocN(sizeof(PointDensity), "pointdensity"); pd->radius = 0.3f; pd->nearest = 5; - pd->type = TEX_PD_PSYS; + pd->source = TEX_PD_PSYS; pd->point_tree = NULL; return pd; @@ -883,8 +884,7 @@ PointDensity *BKE_add_pointdensity(void) PointDensity *BKE_copy_pointdensity(PointDensity *pd) { PointDensity *pdn; - int a; - + pdn= MEM_dupallocN(pd); pdn->point_tree = NULL; diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index ed172c24474..aef8bd95ee4 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -133,12 +133,14 @@ typedef struct PointDensity { short nearest; float radius; - short type; + short source; short pdpad[3]; struct Object *object; /* for 'Particle system' type - source object */ short psysindex; /* and object's psys number */ - short pdpad2[3]; + short psys_cache_space; /* cache particles in worldspace, object space, ... ? */ + + short pdpad2[2]; void *point_tree; /* the kd-tree containing points */ } PointDensity; @@ -406,14 +408,15 @@ typedef struct TexMapping { /* **************** PointDensity ********************* */ -/* type */ +/* source */ #define TEX_PD_PSYS 0 #define TEX_PD_OBJECT 1 #define TEX_PD_FILE 2 -/* psys_space */ -#define TEX_PD_PSYS_WORLDSPACE 0 +/* psys_cache_space */ +#define TEX_PD_PSYS_OBJECTLOC 0 #define TEX_PD_PSYS_OBJECTSPACE 1 +#define TEX_PD_PSYS_WORLDSPACE 2 #endif diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 00dbbd34f96..e589e579565 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -26,11 +26,14 @@ #include #include +#include "BLI_arithb.h" #include "BLI_kdtree.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_particle.h" #include "DNA_texture_types.h" #include "DNA_particle_types.h" @@ -45,10 +48,15 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa ParticleKey state; float cfra=bsystem_time(ob,(float)G.scene->r.cfra,0.0); int i, childexists; - + float partco[3]; + float obview[4][4]; + /* init crap */ if (!psys || !ob || !pd) return; + //Mat4CpyMat4(obview, ob->obmat); + Mat4MulMat4(obview, re->viewinv, ob->obmat); + /* Just to create a valid rendering context */ psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0); @@ -60,6 +68,9 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa return; } + /* in case ob->imat isn't up-to-date */ + Mat4Invert(ob->imat, ob->obmat); + /* finally do something */ pd->point_tree = BLI_kdtree_new(psys->totpart+psys->totchild); @@ -70,7 +81,20 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa state.time = cfra; if(psys_get_particle_state(ob, psys, i, &state, 0)) { - BLI_kdtree_insert(pd->point_tree, 0, state.co, NULL); + + VECCOPY(partco, state.co); + + if (pd->psys_cache_space == TEX_PD_PSYS_OBJECTSPACE) + Mat4MulVecfl(ob->imat, partco); + else if (pd->psys_cache_space == TEX_PD_PSYS_OBJECTLOC) { + float obloc[3]; + VECCOPY(obloc, ob->loc); + VecSubf(partco, partco, obloc); + } else { + /* TEX_PD_PSYS_WORLDSPACE */ + } + + BLI_kdtree_insert(pd->point_tree, 0, partco, NULL); } } @@ -88,7 +112,7 @@ static void cache_pointdensity(Render *re, Tex *tex) pd->point_tree = NULL; } - if (pd->type == TEX_PD_PSYS) { + if (pd->source == TEX_PD_PSYS) { ParticleSystem *psys; Object *ob = pd->object; int i; @@ -192,4 +216,4 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) BRICONT; return rv; -} \ No newline at end of file +} diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 002c62c1a17..5397ab84f1c 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -748,18 +748,9 @@ static void texture_panel_pointdensity(Tex *tex) if(tex->pd) { pd= tex->pd; - uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object that has the particle system"); - - if (pd->object->particlesystem.first) { - uiDefButS(block, NUM, B_REDR, "PSys:", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->psysindex), 1, 10, 10, 3, "Particle system number in the object"); - } - uiBlockEndAlign(block); - - yco -= YSPACE; - + uiDefBut(block, LABEL, B_NOP, "Density estimation:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); uiDefButF(block, NUM, B_REDR, "Radius: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->radius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); @@ -767,11 +758,36 @@ static void texture_panel_pointdensity(Tex *tex) X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->nearest), 2.0, 30.0, 10, 2, "The number of nearby particles to check for density"); uiBlockEndAlign(block); - uiDefBut(block, LABEL, B_NOP, " ", - X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + yco = PANEL_YMAX; + + uiDefBut(block, LABEL, B_NOP, "Point data source:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + + uiDefButS(block, MENU, B_TEXREDR_PRV, "Particle System %x0", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->source, 0.0, 0.0, 0, 0, "Source"); + + yco -= YSPACE; + + if (pd->source == TEX_PD_PSYS) { + uiBlockBeginAlign(block); + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object that has the particle system"); + + if (pd->object->particlesystem.first) { + uiDefButS(block, NUM, B_REDR, "PSys:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->psysindex), 1, 10, 10, 3, "Particle system number in the object"); + } + uiBlockEndAlign(block); + + yco -= YSPACE; + + uiDefBut(block, LABEL, B_NOP, "Cache particles in:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiDefButS(block, MENU, B_TEXREDR_PRV, "Emit Object Location %x0|Emit Object Space %x1|Global Space %x2", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->psys_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache particles in"); + } } - - + } From 31d6a6be68066cb0e084e0aa66e6eaf08e438851 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 29 Sep 2008 07:56:41 +0000 Subject: [PATCH 15/88] * New Point Density texture option: 'Object Vertices' This works very similarly to particles, it just uses the object's renderable vertices as the points instead. http://mke3.net/blender/devel/rendering/volumetrics/pd_objectvertices.png --- source/blender/makesdna/DNA_texture_types.h | 16 ++--- .../render/intern/source/pointdensity.c | 59 +++++++++++++++++-- source/blender/src/buttons_shading.c | 20 ++++++- 3 files changed, 79 insertions(+), 16 deletions(-) diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index aef8bd95ee4..52055f24f82 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -136,11 +136,13 @@ typedef struct PointDensity { short source; short pdpad[3]; - struct Object *object; /* for 'Particle system' type - source object */ - short psysindex; /* and object's psys number */ - short psys_cache_space; /* cache particles in worldspace, object space, ... ? */ + struct Object *object; /* for 'Object' or 'Particle system' type - source object */ + short psys_cache_space; /* cache points in worldspace, object space, ... ? */ + short psysindex; /* for 'Particle system' type - object's psys number */ - short pdpad2[2]; + short ob_cache_space; /* cache points in worldspace, object space, ... ? */ + + short pdpad2; void *point_tree; /* the kd-tree containing points */ } PointDensity; @@ -414,9 +416,9 @@ typedef struct TexMapping { #define TEX_PD_FILE 2 /* psys_cache_space */ -#define TEX_PD_PSYS_OBJECTLOC 0 -#define TEX_PD_PSYS_OBJECTSPACE 1 -#define TEX_PD_PSYS_WORLDSPACE 2 +#define TEX_PD_OBJECTLOC 0 +#define TEX_PD_OBJECTSPACE 1 +#define TEX_PD_WORLDSPACE 2 #endif diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index e589e579565..17bc6bb58cf 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -39,6 +39,7 @@ #include "DNA_particle_types.h" #include "render_types.h" +#include "renderdatabase.h" #include "texture.h" @@ -54,7 +55,6 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa /* init crap */ if (!psys || !ob || !pd) return; - //Mat4CpyMat4(obview, ob->obmat); Mat4MulMat4(obview, re->viewinv, ob->obmat); /* Just to create a valid rendering context */ @@ -71,7 +71,6 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa /* in case ob->imat isn't up-to-date */ Mat4Invert(ob->imat, ob->obmat); - /* finally do something */ pd->point_tree = BLI_kdtree_new(psys->totpart+psys->totchild); if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) @@ -84,17 +83,17 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa VECCOPY(partco, state.co); - if (pd->psys_cache_space == TEX_PD_PSYS_OBJECTSPACE) + if (pd->psys_cache_space == TEX_PD_OBJECTSPACE) Mat4MulVecfl(ob->imat, partco); - else if (pd->psys_cache_space == TEX_PD_PSYS_OBJECTLOC) { + else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { float obloc[3]; VECCOPY(obloc, ob->loc); VecSubf(partco, partco, obloc); } else { - /* TEX_PD_PSYS_WORLDSPACE */ + /* TEX_PD_WORLDSPACE */ } - BLI_kdtree_insert(pd->point_tree, 0, partco, NULL); + BLI_kdtree_insert(pd->point_tree, i, partco, NULL); } } @@ -103,6 +102,38 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa } +static void pointdensity_cache_object(Render *re, PointDensity *pd, ObjectRen *obr) +{ + int i; + + if (!obr || !pd) return; + if(!obr->vertnodes) return; + + /* in case ob->imat isn't up-to-date */ + Mat4Invert(obr->ob->imat, obr->ob->obmat); + + pd->point_tree = BLI_kdtree_new(obr->totvert); + + for(i=0; itotvert; i++) { + float ver_co[3]; + VertRen *ver= RE_findOrAddVert(obr, i); + + VECCOPY(ver_co, ver->co); + + if (pd->ob_cache_space == TEX_PD_OBJECTSPACE) { + Mat4MulVecfl(re->viewinv, ver_co); + Mat4MulVecfl(obr->ob->imat, ver_co); + } else { + /* TEX_PD_WORLDSPACE */ + Mat4MulVecfl(re->viewinv, ver_co); + } + + BLI_kdtree_insert(pd->point_tree, i, ver_co, NULL); + } + + BLI_kdtree_balance(pd->point_tree); + +} static void cache_pointdensity(Render *re, Tex *tex) { PointDensity *pd = tex->pd; @@ -124,6 +155,22 @@ static void cache_pointdensity(Render *re, Tex *tex) pointdensity_cache_psys(re, pd, ob, psys); } + else if (pd->source == TEX_PD_OBJECT) { + Object *ob = pd->object; + ObjectRen *obr; + int found=0; + + /* find the obren that corresponds to the object */ + for (obr=re->objecttable.first; obr; obr=obr->next) { + if (obr->ob == ob) { + found=1; + break; + } + } + if (!found) return; + + pointdensity_cache_object(re, pd, obr); + } } static void free_pointdensity(Render *re, Tex *tex) diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 5397ab84f1c..873b93fb4c4 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -763,7 +763,7 @@ static void texture_panel_pointdensity(Tex *tex) uiDefBut(block, LABEL, B_NOP, "Point data source:", X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - uiDefButS(block, MENU, B_TEXREDR_PRV, "Particle System %x0", + uiDefButS(block, MENU, B_TEXREDR_PRV, "Particle System %x0|Object Vertices %x1", X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->source, 0.0, 0.0, 0, 0, "Source"); yco -= YSPACE; @@ -786,6 +786,17 @@ static void texture_panel_pointdensity(Tex *tex) uiDefButS(block, MENU, B_TEXREDR_PRV, "Emit Object Location %x0|Emit Object Space %x1|Global Space %x2", X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->psys_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache particles in"); } + else if (pd->source == TEX_PD_OBJECT) { + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object to render as points"); + + yco -= YSPACE; + + uiDefBut(block, LABEL, B_NOP, "Cache vertices in:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiDefButS(block, MENU, B_TEXREDR_PRV, "Object Space %x1|Global Space %x2", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->ob_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache vertices in"); + } } } @@ -4310,8 +4321,6 @@ static void material_panel_material_volume(Material *ma) uiBlockBeginAlign(block); 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"); - uiDefButF(block, NUMSLI, B_MATPRV, "Density: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->alpha), 0.0, 1.0, 0, 0, "Base opacity value"); uiDefButS(block, NUM, B_MATPRV, "Layer Depth: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_raydepth), 0.0, 512.0, 10, 2, "Number of layered volume ray intersections allowed per pixel"); uiBlockEndAlign(block); @@ -4327,6 +4336,11 @@ static void material_panel_material_volume(Material *ma) yco = PANEL_YMAX; + uiDefButF(block, NUMSLI, B_MATPRV, "Density: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->alpha), 0.0, 1.0, 0, 0, "Base opacity value"); + + yco -= YSPACE; + uiBlockBeginAlign(block); uiDefButF(block, NUM, B_MATPRV, "Absorption: ", X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 10.0, 10, 0, "Multiplier for absorption"); From a667fc61d44ed35a8bfd13b062a3469a8aa88138 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 30 Sep 2008 10:41:47 +0000 Subject: [PATCH 16/88] * Removed the volume 'layer depth' control' (was used to limit ray intersections like as for ray transparency). It remains to be seen if it's even that useful, and was preventing refracting materials behind volumes from working easily. --- source/blender/blenkernel/intern/material.c | 1 - source/blender/blenloader/intern/readfile.c | 3 +-- source/blender/makesdna/DNA_material_types.h | 3 +-- source/blender/render/intern/source/volumetric.c | 4 +--- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 64125d5834e..f54c0ae7ab1 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -172,7 +172,6 @@ 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_raydepth = 15; 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 8aa0c8c5d5e..555a7455c60 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7888,8 +7888,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) ma->vol_stepsize = 0.2f; 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; - if (ma->vol_raydepth == 0) ma->vol_raydepth = 15; + ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f; } } } diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 5d5ae042950..8215f73d8ce 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -70,9 +70,8 @@ typedef struct Material { float vol_stepsize, vol_shade_stepsize; float vol_absorption, vol_scattering; float vol_absorption_col[3]; - short vol_raydepth; short vol_shadeflag; - int volpad; + short volpad[3]; float fresnel_mir, fresnel_mir_i; float fresnel_tra, fresnel_tra_i; diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index dcff34429b6..4d138ea8545 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -436,7 +436,6 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is) shi_new.mask= shi->mask; shi_new.osatex= shi->osatex; - shi_new.depth= shi->depth + 1; shi_new.thread= shi->thread; shi_new.xs= shi->xs; shi_new.ys= shi->ys; @@ -450,8 +449,7 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is) memset(&shr_new, 0, sizeof(ShadeResult)); - if (shi->depth < shi->mat->vol_raydepth) - shade_ray(is, &shi_new, &shr_new); + shade_ray(is, &shi_new, &shr_new); col[0] = shr_new.combined[0]; col[1] = shr_new.combined[1]; From 3c99a0f73539e5a3c8ceeb02e6c5a21ed4985f71 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 30 Sep 2008 23:58:48 +0000 Subject: [PATCH 17/88] Fix for build error, mustn't have committed this properly last night --- source/blender/src/buttons_shading.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 873b93fb4c4..85154682819 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -755,7 +755,7 @@ static void texture_panel_pointdensity(Tex *tex) uiDefButF(block, NUM, B_REDR, "Radius: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->radius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); uiDefButS(block, NUM, B_REDR, "Nearby: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->nearest), 2.0, 30.0, 10, 2, "The number of nearby particles to check for density"); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->nearest), 2.0, 25.0, 10, 2, "The number of nearby particles to check for density (higher is more accurate, but slower)"); uiBlockEndAlign(block); yco = PANEL_YMAX; @@ -4321,8 +4321,6 @@ static void material_panel_material_volume(Material *ma) uiBlockBeginAlign(block); 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, NUM, B_MATPRV, "Layer Depth: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_raydepth), 0.0, 512.0, 10, 2, "Number of layered volume ray intersections allowed per pixel"); uiBlockEndAlign(block); yco -= YSPACE; From 8622cbca359d77eb980250b42d0635c0dddfa48b Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 1 Oct 2008 03:35:53 +0000 Subject: [PATCH 18/88] * Point Density texture Replaced the previous KD-tree (for caching points) with a BVH-tree (thanks to Andre 'jaguarandi' Pinto for help here!). The bvh is quite a bit faster and doesn't suffer some of the artifacts that were apparent with the kd-tree. I've also added a choice of falloff types: Standard, Smooth, and Sharp. Standard gives a harder edge, easier to see individual particles, and when used with a larger radius, Smooth and Sharp falloffs make a much cloudier appearance possible. See the image below (note the settings and render times too) http://mke3.net/blender/devel/rendering/volumetrics/pointdensity_bvh.jpg --- source/blender/blenkernel/intern/texture.c | 16 ++- source/blender/blenlib/BLI_kdopbvh.h | 7 ++ source/blender/blenlib/intern/BLI_kdopbvh.c | 109 ++++++++++++++++-- source/blender/makesdna/DNA_texture_types.h | 13 ++- .../render/intern/source/pointdensity.c | 72 ++++++++---- source/blender/src/buttons_shading.c | 11 +- 6 files changed, 183 insertions(+), 45 deletions(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 45fd11faa32..ec34fcf4103 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -43,7 +43,7 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_rand.h" -#include "BLI_kdtree.h" +#include "BLI_kdopbvh.h" #include "DNA_texture_types.h" #include "DNA_key_types.h" @@ -474,7 +474,7 @@ void default_tex(Tex *tex) if (tex->pd) { tex->pd->radius = 0.3f; - tex->pd->nearest = 5; + tex->pd->falloff_type = TEX_PD_FALLOFF_STD; } pit = tex->plugin; @@ -874,9 +874,10 @@ PointDensity *BKE_add_pointdensity(void) pd= MEM_callocN(sizeof(PointDensity), "pointdensity"); pd->radius = 0.3f; - pd->nearest = 5; + pd->falloff_type = TEX_PD_FALLOFF_STD; pd->source = TEX_PD_PSYS; pd->point_tree = NULL; + //pd->point_data = NULL; return pd; } @@ -887,6 +888,7 @@ PointDensity *BKE_copy_pointdensity(PointDensity *pd) pdn= MEM_dupallocN(pd); pdn->point_tree = NULL; + //pdn->point_data = NULL; return pd; } @@ -894,9 +896,15 @@ PointDensity *BKE_copy_pointdensity(PointDensity *pd) void BKE_free_pointdensitydata(PointDensity *pd) { if (pd->point_tree) { - BLI_kdtree_free(pd->point_tree); + BLI_bvhtree_free(pd->point_tree); pd->point_tree = NULL; } + /* + if (pd->point_data) { + MEM_freeN(pd->point_data); + pd->point_data = NULL; + } + */ } void BKE_free_pointdensity(PointDensity *pd) diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index e3591a84e98..8912ac5bd13 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -71,6 +71,9 @@ typedef void (*BVHTree_NearestPointCallback) (void *userdata, int index, const f /* callback must update hit in case it finds a nearest successful hit */ typedef void (*BVHTree_RayCastCallback) (void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit); +/* callback to range search query */ +typedef void (*BVHTree_RangeQuery) (void *userdata, int index, float squared_dist, float radius); + BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis); void BLI_bvhtree_free(BVHTree *tree); @@ -93,5 +96,9 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nea int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); +/* range query */ +int BLI_bvhtree_range_query(BVHTree *tree, const float *co, float radius, BVHTree_RangeQuery callback, void *userdata); + + #endif // BLI_KDOPBVH_H diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 30472beb3e6..f82b6b7f162 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -1171,7 +1171,7 @@ static float squared_dist(const float *a, const float *b) } //Determines the nearest point of the given node BV. Returns the squared distance to that point. -static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *nearest) +static float calc_nearest_point(const float *proj, BVHNode *node, float *nearest) { int i; const float *bv = node->bv; @@ -1179,12 +1179,12 @@ static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *near //nearest on AABB hull for(i=0; i != 3; i++, bv += 2) { - if(bv[0] > data->proj[i]) + if(bv[0] > proj[i]) nearest[i] = bv[0]; - else if(bv[1] < data->proj[i]) + else if(bv[1] < proj[i]) nearest[i] = bv[1]; else - nearest[i] = data->proj[i]; + nearest[i] = proj[i]; } /* @@ -1206,7 +1206,7 @@ static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *near } } */ - return squared_dist(data->co, nearest); + return squared_dist(proj, nearest); } @@ -1229,7 +1229,7 @@ static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node) else { data->nearest.index = node->index; - data->nearest.dist = calc_nearest_point(data, node, data->nearest.co); + data->nearest.dist = calc_nearest_point(data->proj, node, data->nearest.co); } } else @@ -1243,7 +1243,7 @@ static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node) for(i=0; i != node->totnode; i++) { - if( calc_nearest_point(data, node->children[i], nearest) >= data->nearest.dist) continue; + if( calc_nearest_point(data->proj, node->children[i], nearest) >= data->nearest.dist) continue; dfs_find_nearest_dfs(data, node->children[i]); } } @@ -1251,7 +1251,7 @@ static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node) { for(i=node->totnode-1; i >= 0 ; i--) { - if( calc_nearest_point(data, node->children[i], nearest) >= data->nearest.dist) continue; + if( calc_nearest_point(data->proj, node->children[i], nearest) >= data->nearest.dist) continue; dfs_find_nearest_dfs(data, node->children[i]); } } @@ -1261,7 +1261,7 @@ static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node) static void dfs_find_nearest_begin(BVHNearestData *data, BVHNode *node) { float nearest[3], sdist; - sdist = calc_nearest_point(data, node, nearest); + sdist = calc_nearest_point(data->proj, node, nearest); if(sdist >= data->nearest.dist) return; dfs_find_nearest_dfs(data, node); } @@ -1298,7 +1298,7 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node) } current.node = node; - current.dist = calc_nearest_point(data, node, nearest); + current.dist = calc_nearest_point(data->proj, node, nearest); while(current.dist < data->nearest.dist) { @@ -1326,7 +1326,7 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node) } heap[heap_size].node = current.node->children[i]; - heap[heap_size].dist = calc_nearest_point(data, current.node->children[i], nearest); + heap[heap_size].dist = calc_nearest_point(data->proj, current.node->children[i], nearest); if(heap[heap_size].dist >= data->nearest.dist) continue; heap_size++; @@ -1524,3 +1524,90 @@ int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, float return data.hit.index; } +/* + * Range Query - as request by broken :P + * + * Allocs and fills an array with the indexs of node that are on the given spherical range (center, radius) + * Returns the size of the array. + */ +typedef struct RangeQueryData +{ + BVHTree *tree; + const float *center; + float radius; //squared radius + + int hits; + + BVHTree_RangeQuery callback; + void *userdata; + + +} RangeQueryData; + + +static void dfs_range_query(RangeQueryData *data, BVHNode *node) +{ + if(node->totnode == 0) + { + + //Calculate the node min-coords (if the node was a point then this is the point coordinates) + float co[3]; + co[0] = node->bv[0]; + co[1] = node->bv[2]; + co[2] = node->bv[4]; + + } + else + { + int i; + for(i=0; i != node->totnode; i++) + { + float nearest[3]; + float dist = calc_nearest_point(data->center, node->children[i], nearest); + if(dist < data->radius) + { + //Its a leaf.. call the callback + if(node->children[i]->totnode == 0) + { + data->hits++; + data->callback( data->userdata, node->children[i]->index, dist, data->radius ); + } + else + dfs_range_query( data, node->children[i] ); + } + } + } +} + +int BLI_bvhtree_range_query(BVHTree *tree, const float *co, float radius, BVHTree_RangeQuery callback, void *userdata) +{ + BVHNode * root = tree->nodes[tree->totleaf]; + + RangeQueryData data; + data.tree = tree; + data.center = co; + data.radius = radius*radius; + data.hits = 0; + + data.callback = callback; + data.userdata = userdata; + + if(root != NULL) + { + float nearest[3]; + float dist = calc_nearest_point(data.center, root, nearest); + if(dist < data.radius) + { + //Its a leaf.. call the callback + if(root->totnode == 0) + { + data.hits++; + data.callback( data.userdata, root->index, dist, data.radius ); + } + else + dfs_range_query( &data, root ); + } + } + + return data.hits; +} diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 52055f24f82..d23672f9284 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -130,7 +130,7 @@ typedef struct EnvMap { typedef struct PointDensity { short flag; - short nearest; + short falloff_type; float radius; short source; @@ -144,7 +144,10 @@ typedef struct PointDensity { short pdpad2; - void *point_tree; /* the kd-tree containing points */ + void *point_tree; /* the acceleration tree containing points */ + //void *point_data; /* dynamically allocated extra for extra information, like particle age */ + //int pdpad3; + } PointDensity; typedef struct Tex { @@ -415,10 +418,16 @@ typedef struct TexMapping { #define TEX_PD_OBJECT 1 #define TEX_PD_FILE 2 +/* falloff_type */ +#define TEX_PD_FALLOFF_STD 0 +#define TEX_PD_FALLOFF_SMOOTH 1 +#define TEX_PD_FALLOFF_SHARP 2 + /* psys_cache_space */ #define TEX_PD_OBJECTLOC 0 #define TEX_PD_OBJECTSPACE 1 #define TEX_PD_WORLDSPACE 2 + #endif diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 17bc6bb58cf..4422b9fbbdd 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -27,7 +27,7 @@ #include #include "BLI_arithb.h" -#include "BLI_kdtree.h" +#include "BLI_kdopbvh.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" @@ -71,7 +71,7 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa /* in case ob->imat isn't up-to-date */ Mat4Invert(ob->imat, ob->obmat); - pd->point_tree = BLI_kdtree_new(psys->totpart+psys->totchild); + pd->point_tree = BLI_bvhtree_new(psys->totpart+psys->totchild, 0.0, 2, 6); if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; @@ -93,11 +93,12 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa /* TEX_PD_WORLDSPACE */ } - BLI_kdtree_insert(pd->point_tree, i, partco, NULL); + BLI_bvhtree_insert(pd->point_tree, i, partco, 1); } } - BLI_kdtree_balance(pd->point_tree); + BLI_bvhtree_balance(pd->point_tree); + psys_render_restore(ob, psys); } @@ -112,7 +113,7 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, ObjectRen *o /* in case ob->imat isn't up-to-date */ Mat4Invert(obr->ob->imat, obr->ob->obmat); - pd->point_tree = BLI_kdtree_new(obr->totvert); + pd->point_tree = BLI_bvhtree_new(obr->totvert, 0.0, 2, 6); for(i=0; itotvert; i++) { float ver_co[3]; @@ -128,10 +129,10 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, ObjectRen *o Mat4MulVecfl(re->viewinv, ver_co); } - BLI_kdtree_insert(pd->point_tree, i, ver_co, NULL); + BLI_bvhtree_insert(pd->point_tree, i, ver_co, 1); } - BLI_kdtree_balance(pd->point_tree); + BLI_bvhtree_balance(pd->point_tree); } static void cache_pointdensity(Render *re, Tex *tex) @@ -139,7 +140,7 @@ static void cache_pointdensity(Render *re, Tex *tex) PointDensity *pd = tex->pd; if (pd->point_tree) { - BLI_kdtree_free(pd->point_tree); + BLI_bvhtree_free(pd->point_tree); pd->point_tree = NULL; } @@ -178,9 +179,16 @@ static void free_pointdensity(Render *re, Tex *tex) PointDensity *pd = tex->pd; if (pd->point_tree) { - BLI_kdtree_free(pd->point_tree); + BLI_bvhtree_free(pd->point_tree); pd->point_tree = NULL; } + + /* + if (pd->point_data) { + MEM_freeN(pd->point_data); + pd->point_data = NULL; + } + */ } @@ -216,33 +224,49 @@ void free_pointdensities(Render *re) } } + +void accum_density_std(void *userdata, int index, float squared_dist, float squared_radius) +{ + float *density = userdata; + const float dist = squared_radius - squared_dist; + + *density+= dist; +} + +void accum_density_smooth(void *userdata, int index, float squared_dist, float squared_radius) +{ + float *density = userdata; + const float dist = squared_radius - squared_dist; + + *density+= 3.0f*dist*dist - 2.0f*dist*dist*dist; +} + +void accum_density_sharp(void *userdata, int index, float squared_dist, float squared_radius) +{ + float *density = userdata; + const float dist = squared_radius - squared_dist; + + *density+= dist*dist; +} + #define MAX_POINTS_NEAREST 25 int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) { int rv = TEX_INT; - PointDensity *pd = tex->pd; - KDTreeNearest nearest[MAX_POINTS_NEAREST]; float density=0.0f; - int n, neighbours=0; if ((!pd) || (!pd->point_tree)) { texres->tin = 0.0f; return 0; } - neighbours = BLI_kdtree_find_n_nearest(pd->point_tree, pd->nearest, texvec, NULL, nearest); - - for(n=1; nradius) { - float dist = 1.0 - (nearest[n].dist / pd->radius); - - density += 3.0f*dist*dist - 2.0f*dist*dist*dist; - } - } - - density /= neighbours; - density *= 1.0 / pd->radius; + if (pd->falloff_type == TEX_PD_FALLOFF_STD) + BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_std, &density); + else if (pd->falloff_type == TEX_PD_FALLOFF_SMOOTH) + BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_smooth, &density); + else if (pd->falloff_type == TEX_PD_FALLOFF_SHARP) + BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_sharp, &density); texres->tin = density; diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 85154682819..050dae6026e 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -751,12 +751,15 @@ static void texture_panel_pointdensity(Tex *tex) uiDefBut(block, LABEL, B_NOP, "Density estimation:", X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - uiBlockBeginAlign(block); uiDefButF(block, NUM, B_REDR, "Radius: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->radius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); - uiDefButS(block, NUM, B_REDR, "Nearby: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->nearest), 2.0, 25.0, 10, 2, "The number of nearby particles to check for density (higher is more accurate, but slower)"); - uiBlockEndAlign(block); + + yco -= YSPACE; + + uiDefBut(block, LABEL, B_NOP, "Falloff:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiDefButS(block, MENU, B_REDR, "Standard %x0|Smooth %x1|Sharp %x2", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->falloff_type, 0.0, 0.0, 0, 0, "Falloff type"); yco = PANEL_YMAX; From 25236b56a6c8c5619a3a8d35841be7e413df1e5e Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 1 Oct 2008 07:13:28 +0000 Subject: [PATCH 19/88] * Fix for volumetric rendering. It previously wasn't multiplying the emission component by the density at the current point, which made the volume too bright in less dense areas. This made it look too rough, as opposed to smooth as it should be. This makes the particle rendering look *much* better, thanks a bunch to ZanQdo for complaining and kicking my butt to make me realise the error. Here's an example of how smooth it looks now: http://mke3.net/blender/devel/rendering/volumetrics/smoke_test03.mov http://mke3.net/blender/devel/rendering/volumetrics/smoke_test03.blend Settings in existing files will have to be tweaked a bit, since what they were set up for before, was incorrect. * Added two new interpolation types to Point Density: Constant and Root. These work similarly to in proportional edit for example, just gives a bit more choice over how hard-edged the particles should look. --- source/blender/makesdna/DNA_texture_types.h | 3 ++- .../render/intern/source/pointdensity.c | 23 +++++++++++++++++-- .../blender/render/intern/source/volumetric.c | 16 ++++++------- source/blender/src/buttons_shading.c | 4 ++-- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index d23672f9284..9c608302b22 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -132,7 +132,6 @@ typedef struct PointDensity { short falloff_type; float radius; - short source; short pdpad[3]; @@ -422,6 +421,8 @@ typedef struct TexMapping { #define TEX_PD_FALLOFF_STD 0 #define TEX_PD_FALLOFF_SMOOTH 1 #define TEX_PD_FALLOFF_SHARP 2 +#define TEX_PD_FALLOFF_CONSTANT 3 +#define TEX_PD_FALLOFF_ROOT 4 /* psys_cache_space */ #define TEX_PD_OBJECTLOC 0 diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 4422b9fbbdd..c4124fba8bb 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -224,7 +224,6 @@ void free_pointdensities(Render *re) } } - void accum_density_std(void *userdata, int index, float squared_dist, float squared_radius) { float *density = userdata; @@ -249,6 +248,22 @@ void accum_density_sharp(void *userdata, int index, float squared_dist, float sq *density+= dist*dist; } +void accum_density_constant(void *userdata, int index, float squared_dist, float squared_radius) +{ + float *density = userdata; + + *density+= squared_radius; +} + +void accum_density_root(void *userdata, int index, float squared_dist, float squared_radius) +{ + float *density = userdata; + const float dist = squared_radius - squared_dist; + + *density+= sqrt(dist); +} + + #define MAX_POINTS_NEAREST 25 int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) { @@ -267,7 +282,11 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_smooth, &density); else if (pd->falloff_type == TEX_PD_FALLOFF_SHARP) BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_sharp, &density); - + else if (pd->falloff_type == TEX_PD_FALLOFF_CONSTANT) + BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_constant, &density); + else if (pd->falloff_type == TEX_PD_FALLOFF_ROOT) + BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_root, &density); + texres->tin = density; /* diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 4d138ea8545..5d28540f17a 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -152,7 +152,7 @@ void vol_get_emission(ShadeInput *shi, float *em, float *co, float density) do_volume_tex(shi, co, MAP_EMIT+MAP_COL, col, &emission); - em[0] = em[1] = em[2] = emission; + em[0] = em[1] = em[2] = emission * density; VecMulVecf(em, em, col); } @@ -365,13 +365,10 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float /* get radiance from all points along the ray due to participating media */ for (s = 0; s < nsteps; s++) { if (s > 0) density = vol_get_density(shi, step_sta); - - /* there's only any point shading here + + /* there's only any use in shading here * if there's actually some density to shade! */ if (density > 0.01f) { - step_mid[0] = step_sta[0] + (stepvec[0] * 0.5); - step_mid[1] = step_sta[1] + (stepvec[1] * 0.5); - step_mid[2] = step_sta[2] + (stepvec[2] * 0.5); /* transmittance component (alpha) */ vol_get_attenuation(shi, tau, step_sta, step_end, density, stepsize); @@ -379,9 +376,10 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float tr[1] *= exp(-tau[1]); tr[2] *= exp(-tau[2]); - /* Terminate raymarching if transmittance is small */ - //if ((tr[0] + tr[1] + tr[2] * 0.333f) < 0.01f) continue; - + step_mid[0] = step_sta[0] + (stepvec[0] * 0.5); + step_mid[1] = step_sta[1] + (stepvec[1] * 0.5); + step_mid[2] = step_sta[2] + (stepvec[2] * 0.5); + /* incoming light via emission or scattering (additive) */ vol_get_emission(shi, step_emit, step_mid, density); vol_get_scattering(shi, step_scatter, step_mid, stepsize, density); diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 050dae6026e..7a154d084bc 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -758,7 +758,7 @@ static void texture_panel_pointdensity(Tex *tex) uiDefBut(block, LABEL, B_NOP, "Falloff:", X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - uiDefButS(block, MENU, B_REDR, "Standard %x0|Smooth %x1|Sharp %x2", + uiDefButS(block, MENU, B_REDR, "Standard %x0|Smooth %x1|Sharp %x2|Constant %x3|Root %x4", X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->falloff_type, 0.0, 0.0, 0, 0, "Falloff type"); yco = PANEL_YMAX; @@ -4334,7 +4334,7 @@ static void material_panel_material_volume(Material *ma) uiDefButF(block, NUM, B_MATPRV, "Step Size: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shade_stepsize), 0.001, 100.0, 10, 2, "Step"); uiBlockEndAlign(block); - + yco = PANEL_YMAX; uiDefButF(block, NUMSLI, B_MATPRV, "Density: ", From 2745517ecda2a72603fa7c8ec5a44f2b857c5782 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 1 Oct 2008 07:30:56 +0000 Subject: [PATCH 20/88] Added 'Object Location' option to 'object vertices' mode in Point Density. This brings it consistent with the 'particle system' mode, and allows silly things like this a bit easier (especially after the last fix and BVH improvements!): http://mke3.net/blender/devel/rendering/volumetrics/pd_objectloc.mov --- source/blender/render/intern/source/pointdensity.c | 6 ++++-- source/blender/src/buttons_shading.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index c4124fba8bb..a3f174be68b 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -120,13 +120,15 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, ObjectRen *o VertRen *ver= RE_findOrAddVert(obr, i); VECCOPY(ver_co, ver->co); + Mat4MulVecfl(re->viewinv, ver_co); if (pd->ob_cache_space == TEX_PD_OBJECTSPACE) { - Mat4MulVecfl(re->viewinv, ver_co); Mat4MulVecfl(obr->ob->imat, ver_co); + } else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { + VecSubf(ver_co, ver_co, obr->ob->loc); } else { /* TEX_PD_WORLDSPACE */ - Mat4MulVecfl(re->viewinv, ver_co); + } BLI_bvhtree_insert(pd->point_tree, i, ver_co, 1); diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 7a154d084bc..c9df2f6d833 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -797,7 +797,7 @@ static void texture_panel_pointdensity(Tex *tex) uiDefBut(block, LABEL, B_NOP, "Cache vertices in:", X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - uiDefButS(block, MENU, B_TEXREDR_PRV, "Object Space %x1|Global Space %x2", + uiDefButS(block, MENU, B_TEXREDR_PRV, "Object Location %x0|Object Space %x1|Global Space %x2", X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->ob_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache vertices in"); } } From e114d194ae44cb72aa52954f4fdeb67805a2c7c6 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 2 Oct 2008 01:38:12 +0000 Subject: [PATCH 21/88] * Re-coded the point density range checking to be a bit cleaner, and not necessary to modify the BVH functions. --- source/blender/blenkernel/intern/texture.c | 6 +- source/blender/blenlib/BLI_kdopbvh.h | 2 +- source/blender/blenlib/intern/BLI_kdopbvh.c | 4 +- source/blender/makesdna/DNA_texture_types.h | 4 +- .../render/intern/source/pointdensity.c | 79 ++++++++----------- 5 files changed, 38 insertions(+), 57 deletions(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index ec34fcf4103..7b558008a92 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -877,7 +877,7 @@ PointDensity *BKE_add_pointdensity(void) pd->falloff_type = TEX_PD_FALLOFF_STD; pd->source = TEX_PD_PSYS; pd->point_tree = NULL; - //pd->point_data = NULL; + pd->point_data = NULL; return pd; } @@ -888,7 +888,7 @@ PointDensity *BKE_copy_pointdensity(PointDensity *pd) pdn= MEM_dupallocN(pd); pdn->point_tree = NULL; - //pdn->point_data = NULL; + pdn->point_data = NULL; return pd; } @@ -899,12 +899,10 @@ void BKE_free_pointdensitydata(PointDensity *pd) BLI_bvhtree_free(pd->point_tree); pd->point_tree = NULL; } - /* if (pd->point_data) { MEM_freeN(pd->point_data); pd->point_data = NULL; } - */ } void BKE_free_pointdensity(PointDensity *pd) diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index 8912ac5bd13..dabf12d48d3 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -72,7 +72,7 @@ typedef void (*BVHTree_NearestPointCallback) (void *userdata, int index, const f typedef void (*BVHTree_RayCastCallback) (void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit); /* callback to range search query */ -typedef void (*BVHTree_RangeQuery) (void *userdata, int index, float squared_dist, float radius); +typedef void (*BVHTree_RangeQuery) (void *userdata, int index, float squared_dist); BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis); diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index f82b6b7f162..df37ff457f6 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -1570,7 +1570,7 @@ static void dfs_range_query(RangeQueryData *data, BVHNode *node) if(node->children[i]->totnode == 0) { data->hits++; - data->callback( data->userdata, node->children[i]->index, dist, data->radius ); + data->callback( data->userdata, node->children[i]->index, dist ); } else dfs_range_query( data, node->children[i] ); @@ -1602,7 +1602,7 @@ int BLI_bvhtree_range_query(BVHTree *tree, const float *co, float radius, BVHTre if(root->totnode == 0) { data.hits++; - data.callback( data.userdata, root->index, dist, data.radius ); + data.callback( data.userdata, root->index, dist ); } else dfs_range_query( &data, root ); diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 9c608302b22..95bacbbd4c6 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -144,8 +144,8 @@ typedef struct PointDensity { short pdpad2; void *point_tree; /* the acceleration tree containing points */ - //void *point_data; /* dynamically allocated extra for extra information, like particle age */ - //int pdpad3; + void *point_data; /* dynamically allocated extra for extra information, like particle age */ + int pdpad3[2]; } PointDensity; diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index a3f174be68b..7998fa82836 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -23,9 +23,12 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include #include #include +#include "MEM_guardedalloc.h" + #include "BLI_arithb.h" #include "BLI_kdopbvh.h" @@ -185,12 +188,10 @@ static void free_pointdensity(Render *re, Tex *tex) pd->point_tree = NULL; } - /* if (pd->point_data) { MEM_freeN(pd->point_data); pd->point_data = NULL; } - */ } @@ -226,51 +227,37 @@ void free_pointdensities(Render *re) } } -void accum_density_std(void *userdata, int index, float squared_dist, float squared_radius) +typedef struct PointDensityRangeData { - float *density = userdata; - const float dist = squared_radius - squared_dist; + float *density; + float squared_radius; + float *point_data; + short falloff_type; +} PointDensityRangeData; + +void accum_density(void *userdata, int index, float squared_dist) +{ + PointDensityRangeData *pdr = (PointDensityRangeData *)userdata; + const float dist = pdr->squared_radius - squared_dist; - *density+= dist; + if (pdr->falloff_type == TEX_PD_FALLOFF_STD) + *pdr->density += dist; + else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH) + *pdr->density+= 3.0f*dist*dist - 2.0f*dist*dist*dist; + else if (pdr->falloff_type == TEX_PD_FALLOFF_SHARP) + *pdr->density+= dist*dist; + else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT) + *pdr->density+= pdr->squared_radius; + else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT) + *pdr->density+= sqrt(dist); } -void accum_density_smooth(void *userdata, int index, float squared_dist, float squared_radius) -{ - float *density = userdata; - const float dist = squared_radius - squared_dist; - - *density+= 3.0f*dist*dist - 2.0f*dist*dist*dist; -} - -void accum_density_sharp(void *userdata, int index, float squared_dist, float squared_radius) -{ - float *density = userdata; - const float dist = squared_radius - squared_dist; - - *density+= dist*dist; -} - -void accum_density_constant(void *userdata, int index, float squared_dist, float squared_radius) -{ - float *density = userdata; - - *density+= squared_radius; -} - -void accum_density_root(void *userdata, int index, float squared_dist, float squared_radius) -{ - float *density = userdata; - const float dist = squared_radius - squared_dist; - - *density+= sqrt(dist); -} - - #define MAX_POINTS_NEAREST 25 int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) { int rv = TEX_INT; PointDensity *pd = tex->pd; + PointDensityRangeData pdr; float density=0.0f; if ((!pd) || (!pd->point_tree)) { @@ -278,16 +265,12 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) return 0; } - if (pd->falloff_type == TEX_PD_FALLOFF_STD) - BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_std, &density); - else if (pd->falloff_type == TEX_PD_FALLOFF_SMOOTH) - BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_smooth, &density); - else if (pd->falloff_type == TEX_PD_FALLOFF_SHARP) - BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_sharp, &density); - else if (pd->falloff_type == TEX_PD_FALLOFF_CONSTANT) - BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_constant, &density); - else if (pd->falloff_type == TEX_PD_FALLOFF_ROOT) - BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density_root, &density); + pdr.squared_radius = pd->radius*pd->radius; + pdr.density = &density; + pdr.point_data = pd->point_data; + pdr.falloff_type = pd->falloff_type; + + BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density, &pdr); texres->tin = density; From 67a9d4154d520a98e572e98f680995fca701f728 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sat, 4 Oct 2008 12:23:57 +0000 Subject: [PATCH 22/88] * New volumetrics feature: scattering types Otherwise known as a phase function, this determines in which directions the light is scattered in the volume. Until now it's been isotropic scattering, meaning that the light gets scattered equally in all directions. This adds some new types for anisotropic scattering, to scatter light more forwards or backwards towards the viewing direction, which can be more similar to how light is scattered by particles in nature. Here's a diagram of how light is scattered isotropically and anisotropically: http://mke3.net/blender/devel/rendering/volumetrics/phase_diagram.png The new additions are: - Rayleigh describes scattering by very small particles in the atmosphere. - Mie Hazy / Mie Murky more generalised, describes scattering from large particle sizes. - Henyey-Greenstein a very flexible formula, that can be used to simulate a wide range of scattering. It uses an additional 'Asymmetry' slider, ranging from -1.0 (backward scattering) to 1.0 (forward scattering) to control the direction of scattering. - Schlick an approximation of Henyey-Greenstein, working similarly but faster. And a description of how they look visually (just an omnidirectional lamp inside a volume box) http://mke3.net/blender/devel/rendering/volumetrics/phasefunctions.jpg * Sun/sky integration Volumes now correctly render in front of the new physical sky. Atmosphere still doesn't work correctly with volumes, due to something that i hope can be fixed in the atmosphere rendering, but the sky looks quite good. http://mke3.net/blender/devel/rendering/volumetrics/sky_clouds.png This also works very nicely with the anisotropic scattering, giving clouds their signature bright halos when the sun is behind them: http://mke3.net/blender/devel/rendering/volumetrics/phase_cloud.mov in comparison here's a render with isotropic scattering: http://mke3.net/blender/devel/rendering/volumetrics/phase_cloud_isotropic.png * Added back the max volume depth tracing limit, as a hard coded value - fixes crashes with weird geometry, like the overlapping faces around suzanne's eyes. As a general note, it's always best to use volume materials on airtight geometry, without intersecting or overlapping faces. --- source/blender/makesdna/DNA_material_types.h | 11 ++- .../render/extern/include/RE_shader_ext.h | 1 + .../blender/render/intern/source/volumetric.c | 73 ++++++++++++++----- source/blender/src/buttons_shading.c | 12 +++ 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 8215f73d8ce..4e006d17682 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -71,7 +71,8 @@ typedef struct Material { float vol_absorption, vol_scattering; float vol_absorption_col[3]; short vol_shadeflag; - short volpad[3]; + short vol_phasefunc_type; + float vol_phasefunc_g; float fresnel_mir, fresnel_mir_i; float fresnel_tra, fresnel_tra_i; @@ -351,5 +352,13 @@ typedef struct Material { #define MA_VOL_ATTENUATED 2 #define MA_VOL_SHADOWED 4 +/* vol_phasefunc_type */ +#define MA_VOL_PH_ISOTROPIC 0 +#define MA_VOL_PH_MIEHAZY 1 +#define MA_VOL_PH_MIEMURKY 2 +#define MA_VOL_PH_RAYLEIGH 3 +#define MA_VOL_PH_HG 4 +#define MA_VOL_PH_SCHLICK 5 + #endif diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 5d74895f0c8..16449df02b0 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -160,6 +160,7 @@ typedef struct ShadeInput int samplenr; /* sample counter, to detect if we should do shadow again */ int depth; /* 1 or larger on raytrace shading */ + int volume_depth; /* number of intersections through volumes */ /* stored copy of original face normal (facenor) * before flipping. Used in Front/back output on geometry node */ diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 5d28540f17a..9a6790976af 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -164,6 +164,33 @@ void vol_get_scattering_fac(ShadeInput *shi, float *scatter_fac, float *co, floa *scatter_fac = shi->mat->vol_scattering; } +float vol_get_phasefunc(ShadeInput *shi, short phasefunc_type, float g, float *w, float *wp) +{ + const float costheta = Inpf(w, wp); + + if (phasefunc_type == MA_VOL_PH_ISOTROPIC) { + return 1.f / (4.f * M_PI); + } + else if (phasefunc_type == MA_VOL_PH_MIEHAZY) { + return (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)) / (4.f*M_PI); + } + else if (phasefunc_type == MA_VOL_PH_MIEMURKY) { + return (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)) / (4.f*M_PI); + } + else if (phasefunc_type == MA_VOL_PH_RAYLEIGH) { + return 3.f/(16.f*M_PI) * (1 + costheta * costheta); + } + else if (phasefunc_type == MA_VOL_PH_HG) { + return 1.f / (4.f * M_PI) * (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f); + } + else if (phasefunc_type == MA_VOL_PH_SCHLICK) { + const float k = 1.55f * g - .55f * g * g * g; + const float kcostheta = k * costheta; + return 1.f / (4.f * M_PI) * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta)); + } else { + return 1.0f; + } +} void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co) { @@ -229,13 +256,14 @@ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, f VecMulVecf(tau, tau, absorb_col); } -void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *col, float stepsize, float density) +void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *lacol, float stepsize, float density) { float visifac, lv[3], lampdist; - float lacol[3]; float tau[3], tr[3]={1.0,1.0,1.0}; float hitco[3], *atten_co; - + float p; + float scatter_fac; + if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; if ((lar->lay & shi->lay)==0) return; if (lar->energy == 0.0) return; @@ -253,15 +281,17 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * } VecMulf(lacol, visifac*lar->energy); - - + + if (ELEM(lar->type, LA_SUN, LA_HEMI)) + VECCOPY(lv, lar->vec); + VecMulf(lv, -1.0f); + + p = vol_get_phasefunc(shi, shi->mat->vol_phasefunc_type, shi->mat->vol_phasefunc_g, shi->view, lv); + VecMulf(lacol, p); + 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, &is, VOL_BOUNDS_SS, 0)) { float dist = VecLenf(co, hitco); @@ -287,7 +317,11 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * } } - VecAddf(col, col, lacol); + vol_get_scattering_fac(shi, &scatter_fac, co, density); + VecMulf(lacol, scatter_fac); + + + } /* shadows -> trace a ray to find blocker geometry @@ -309,19 +343,12 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi for(go=lights->first; go; go= go->next) { float lacol[3] = {0.f, 0.f, 0.f}; - float scatter_fac; lar= go->lampren; if (lar==NULL) continue; vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density); - - vol_get_scattering_fac(shi, &scatter_fac, co, density); - VecMulf(lacol, scatter_fac); - - /* isotropic phase function */ - VecMulf(lacol, 1.0f / (4.f * M_PI)); - + VecMulf(lacol, density); VecAddf(col, col, lacol); @@ -435,6 +462,8 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is) shi_new.mask= shi->mask; shi_new.osatex= shi->osatex; shi_new.thread= shi->thread; + shi_new.depth= shi->depth; + shi_new.volume_depth= shi->volume_depth + 1; shi_new.xs= shi->xs; shi_new.ys= shi->ys; shi_new.lay= shi->lay; @@ -446,8 +475,11 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is) VECCOPY(shi_new.camera_co, is->start); memset(&shr_new, 0, sizeof(ShadeResult)); - - shade_ray(is, &shi_new, &shr_new); + + /* hardcoded limit of 100 for now - prevents problems in weird geometry */ + if (shi->volume_depth < 100) { + shade_ray(is, &shi_new, &shr_new); + } col[0] = shr_new.combined[0]; col[1] = shr_new.combined[1]; @@ -478,6 +510,7 @@ static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *co shade_intersection(shi, col, &isect); } else { shadeSkyView(col, co, shi->view, NULL); + shadeSunView(col, shi->view); } } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 949487fc06f..ec5419c1704 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4342,6 +4342,18 @@ static void material_panel_material_volume(Material *ma) uiDefButF(block, NUM, B_MATPRV, "Step Size: ", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shade_stepsize), 0.001, 100.0, 10, 2, "Step"); 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"); + } + uiBlockEndAlign(block); + yco = PANEL_YMAX; From 25ece3ba2f60ec4271828bb4ab1c083c6fa36761 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 6 Oct 2008 12:25:22 +0000 Subject: [PATCH 23/88] * New point density update: Turbulence This addition allows you to perturb the point density with noise, to give the impression of more resolution. It's a quick way to add detail, without having to use large, complex, and slower to render particle systems. Rather than just overlaying noise, like you might do by adding a secondary clouds texture, it uses noise to perturb the actual coordinate looked up in the density evaluation. This gives a much better looking result, as it actually alters the original density. Comparison of the particle cloud render without, and with added turbulence (the render with turbulence only renders slightly more slowly): http://mke3.net/blender/devel/rendering/volumetrics/pd_turbulence.jpg Using the same constant noise function/spatial coordinates will give a static appearance. This is fine (and quicker) if the particles aren't moving, but on animated particle systems, it looks bad, as if the particles are moving through a static noise field. To overcome this, there are additional options for particle systems, to influence the turbulence with the particles' average velocity, or average angular velocity. This information is only available for particle systems at the present. Here you can see the (dramatic) difference between no turbulence, static turbulence, and turbulence influenced by particle velocity: http://mke3.net/blender/devel/rendering/volumetrics/turbu_compare.mov --- source/blender/blenkernel/intern/texture.c | 4 + source/blender/blenloader/intern/readfile.c | 13 +++ source/blender/makesdna/DNA_texture_types.h | 18 +++- .../render/intern/source/pointdensity.c | 83 +++++++++++++++---- source/blender/src/buttons_shading.c | 34 +++++++- 5 files changed, 131 insertions(+), 21 deletions(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 7b558008a92..33b824623fa 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -878,6 +878,10 @@ PointDensity *BKE_add_pointdensity(void) pd->source = TEX_PD_PSYS; pd->point_tree = NULL; pd->point_data = NULL; + pd->noise_size = 0.5f; + pd->noise_depth = 1; + pd->noise_fac = 1.0f; + pd->noise_influence = TEX_PD_NOISE_STATIC; return pd; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 568513650e0..249459bf3a4 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7882,6 +7882,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) if (main->versionfile <= 247) { Material *ma; + Tex *tex; for(ma=main->mat.first; ma; ma= ma->id.next) { /* trigger for non-volumetric file */ @@ -7893,6 +7894,18 @@ static void do_versions(FileData *fd, Library *lib, Main *main) ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f; } } + + for(tex=main->tex.first; tex; tex= tex->id.next) { + if (tex->pd == NULL) + tex->pd = BKE_add_pointdensity(); + else if (tex->pd->noise_size < 0.0001f) { + tex->pd->noise_size = 0.5f; + tex->pd->noise_depth = 1; + tex->pd->noise_fac = 1.0f; + tex->pd->noise_influence = TEX_PD_NOISE_STATIC; + } + } + } /* set the curve radius interpolation to 2.47 default - easy */ diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 95bacbbd4c6..95f61e73c79 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -144,8 +144,13 @@ typedef struct PointDensity { short pdpad2; void *point_tree; /* the acceleration tree containing points */ - void *point_data; /* dynamically allocated extra for extra information, like particle age */ - int pdpad3[2]; + float *point_data; /* dynamically allocated extra for extra information, like particle age */ + + float noise_size; + short noise_depth; + short noise_influence; + float noise_fac; + float pdpad4; } PointDensity; @@ -429,6 +434,15 @@ typedef struct TexMapping { #define TEX_PD_OBJECTSPACE 1 #define TEX_PD_WORLDSPACE 2 +/* flag */ +#define TEX_PD_TURBULENCE 1 + + +/* noise_influence */ +#define TEX_PD_NOISE_STATIC 0 +#define TEX_PD_NOISE_VEL 1 +#define TEX_PD_NOISE_ANGVEL 2 +#define TEX_PD_NOISE_TIME 3 #endif diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 7998fa82836..e7e2d4fc26e 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -30,6 +30,7 @@ #include "MEM_guardedalloc.h" #include "BLI_arithb.h" +#include "BLI_blenlib.h" #include "BLI_kdopbvh.h" #include "BKE_DerivedMesh.h" @@ -45,13 +46,13 @@ #include "renderdatabase.h" #include "texture.h" - static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys) { DerivedMesh* dm; ParticleKey state; float cfra=bsystem_time(ob,(float)G.scene->r.cfra,0.0); int i, childexists; + int total_particles; float partco[3]; float obview[4][4]; @@ -74,12 +75,16 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa /* in case ob->imat isn't up-to-date */ Mat4Invert(ob->imat, ob->obmat); - pd->point_tree = BLI_bvhtree_new(psys->totpart+psys->totchild, 0.0, 2, 6); + total_particles = psys->totpart+psys->totchild; + + pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 2, 6); + if (pd->noise_influence != TEX_PD_NOISE_STATIC) + pd->point_data = MEM_mallocN(sizeof(float)*3*total_particles, "point_data"); if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; - for (i = 0; i < psys->totpart + psys->totchild; i++) { + for (i = 0; i < total_particles; i++) { state.time = cfra; if(psys_get_particle_state(ob, psys, i, &state, 0)) { @@ -97,6 +102,16 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa } BLI_bvhtree_insert(pd->point_tree, i, partco, 1); + + if (pd->noise_influence == TEX_PD_NOISE_VEL) { + pd->point_data[i*3 + 0] = state.vel[0]; + pd->point_data[i*3 + 1] = state.vel[1]; + pd->point_data[i*3 + 2] = state.vel[2]; + } else if (pd->noise_influence == TEX_PD_NOISE_ANGVEL) { + pd->point_data[i*3 + 0] = state.ave[0]; + pd->point_data[i*3 + 1] = state.ave[1]; + pd->point_data[i*3 + 2] = state.ave[2]; + } } } @@ -131,7 +146,6 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, ObjectRen *o VecSubf(ver_co, ver_co, obr->ob->loc); } else { /* TEX_PD_WORLDSPACE */ - } BLI_bvhtree_insert(pd->point_tree, i, ver_co, 1); @@ -232,6 +246,7 @@ typedef struct PointDensityRangeData float *density; float squared_radius; float *point_data; + float *vec; short falloff_type; } PointDensityRangeData; @@ -239,17 +254,26 @@ void accum_density(void *userdata, int index, float squared_dist) { PointDensityRangeData *pdr = (PointDensityRangeData *)userdata; const float dist = pdr->squared_radius - squared_dist; + float density; if (pdr->falloff_type == TEX_PD_FALLOFF_STD) - *pdr->density += dist; + density = dist; else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH) - *pdr->density+= 3.0f*dist*dist - 2.0f*dist*dist*dist; + density = 3.0f*dist*dist - 2.0f*dist*dist*dist; else if (pdr->falloff_type == TEX_PD_FALLOFF_SHARP) - *pdr->density+= dist*dist; + density = dist*dist; else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT) - *pdr->density+= pdr->squared_radius; + density = pdr->squared_radius; else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT) - *pdr->density+= sqrt(dist); + density = sqrt(dist); + + if (pdr->point_data) { + pdr->vec[0] += pdr->point_data[index*3 + 0];// * density; + pdr->vec[1] += pdr->point_data[index*3 + 1];// * density; + pdr->vec[2] += pdr->point_data[index*3 + 2];// * density; + } + + *pdr->density += density; } #define MAX_POINTS_NEAREST 25 @@ -259,6 +283,9 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) PointDensity *pd = tex->pd; PointDensityRangeData pdr; float density=0.0f; + float vec[3] = {0.0, 0.0, 0.0}; + float tv[3]; + float turb; if ((!pd) || (!pd->point_tree)) { texres->tin = 0.0f; @@ -269,16 +296,40 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) pdr.density = &density; pdr.point_data = pd->point_data; pdr.falloff_type = pd->falloff_type; + pdr.vec = vec; - BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density, &pdr); + if (pd->flag & TEX_PD_TURBULENCE) { + VECCOPY(tv, texvec); + + /* find the average speed vectors, for perturbing final density lookup with */ + BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density, &pdr); + + density = 0.0f; + Normalize(vec); + turb = BLI_turbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth); + + turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */ + + tv[0] = texvec[0] + pd->noise_fac * turb; + tv[1] = texvec[1] + pd->noise_fac * turb; + tv[2] = texvec[2] + pd->noise_fac * turb; + + /* do density lookup with altered coordinates */ + BLI_bvhtree_range_query(pd->point_tree, tv, pd->radius, accum_density, &pdr); + } + else + BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density, &pdr); + texres->tin = density; - /* - texres->tr = 1.0f; - texres->tg = 1.0f; - texres->tb = 0.0f; + //texres->tr = vec[0]; + //texres->tg = vec[1]; + //texres->tb = vec[2]; + return TEX_INT; + + /* BRICONTRGB; texres->ta = 1.0; @@ -288,7 +339,7 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) } */ - BRICONT; + //BRICONT; - return rv; + //return rv; } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index ec5419c1704..b6c3e39bac2 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -759,15 +759,42 @@ static void texture_panel_pointdensity(Tex *tex) uiDefBut(block, LABEL, B_NOP, "Falloff:", X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); uiDefButS(block, MENU, B_REDR, "Standard %x0|Smooth %x1|Sharp %x2|Constant %x3|Root %x4", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->falloff_type, 0.0, 0.0, 0, 0, "Falloff type"); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->falloff_type, 0.0, 0.0, 0, 0, "Falloff type"); + yco -= YSPACE; + + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, TEX_PD_TURBULENCE, B_REDR, "Turbulence", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->flag), 0, 0, 0, 0, "Add directed turbulence to the density estimation"); + + if (pd->flag & TEX_PD_TURBULENCE) { + + uiDefButF(block, NUM, B_REDR, "Size: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_size), 0.001, 100.0, 10, 2, "Turbulence size"); + uiDefButS(block, NUM, B_REDR, "Depth: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_depth), 0.0, 100.0, 10, 2, "Turbulence depth"); + uiDefButF(block, NUM, B_REDR, "Strength: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_fac), 0.001, 100.0, 10, 2, ""); + + uiBlockEndAlign(block); + + yco -= YSPACE; + + if (pd->source == TEX_PD_PSYS) { + uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1|Angular Velocity %x2", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); + } + } + uiBlockEndAlign(block); + yco = PANEL_YMAX; uiDefBut(block, LABEL, B_NOP, "Point data source:", - X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); uiDefButS(block, MENU, B_TEXREDR_PRV, "Particle System %x0|Object Vertices %x1", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->source, 0.0, 0.0, 0, 0, "Source"); + X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->source, 0.0, 0.0, 0, 0, "Source"); yco -= YSPACE; @@ -788,6 +815,7 @@ static void texture_panel_pointdensity(Tex *tex) X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); uiDefButS(block, MENU, B_TEXREDR_PRV, "Emit Object Location %x0|Emit Object Space %x1|Global Space %x2", X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->psys_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache particles in"); + } else if (pd->source == TEX_PD_OBJECT) { uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", From 8c3e960dd40cf36f8d4140fe545cb6e584d8900c Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 6 Oct 2008 22:39:06 +0000 Subject: [PATCH 24/88] * Fix for silly crash in point density UI, showed up in files with an existing empty texture. --- source/blender/src/buttons_shading.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index b6c3e39bac2..6ec8ce78e73 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -803,7 +803,7 @@ static void texture_panel_pointdensity(Tex *tex) uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object that has the particle system"); - if (pd->object->particlesystem.first) { + if (pd->object && pd->object->particlesystem.first) { uiDefButS(block, NUM, B_REDR, "PSys:", X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->psysindex), 1, 10, 10, 3, "Particle system number in the object"); } From 837211077ce17f17b946c46dde63555d56640aae Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 9 Oct 2008 01:15:54 +0000 Subject: [PATCH 25/88] * fix for silly bug in point density with no object in the object field --- source/blender/render/intern/source/pointdensity.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index e7e2d4fc26e..6ba9ace043d 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -168,10 +168,12 @@ static void cache_pointdensity(Render *re, Tex *tex) Object *ob = pd->object; int i; + if (!ob) return; + for(psys=ob->particlesystem.first, i=0; i< pd->psysindex-1; i++) psys= psys->next; - if (!ob || !psys) return; + if (!psys) return; pointdensity_cache_psys(re, pd, ob, psys); } From 21075b1a17b901a104efd1a8cb47241947942ffd Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Sun, 12 Oct 2008 11:38:28 +0000 Subject: [PATCH 26/88] Using quad trees instead of binary ones give another 10% speedup --- source/blender/render/intern/source/pointdensity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 6ba9ace043d..bdfb4d3b9d1 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -77,7 +77,7 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa total_particles = psys->totpart+psys->totchild; - pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 2, 6); + pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); if (pd->noise_influence != TEX_PD_NOISE_STATIC) pd->point_data = MEM_mallocN(sizeof(float)*3*total_particles, "point_data"); @@ -131,7 +131,7 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, ObjectRen *o /* in case ob->imat isn't up-to-date */ Mat4Invert(obr->ob->imat, obr->ob->obmat); - pd->point_tree = BLI_bvhtree_new(obr->totvert, 0.0, 2, 6); + pd->point_tree = BLI_bvhtree_new(obr->totvert, 0.0, 4, 6); for(i=0; itotvert; i++) { float ver_co[3]; From a6bd4480ee218d4e3885691262aed13abf4241b0 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sun, 12 Oct 2008 23:39:52 +0000 Subject: [PATCH 27/88] * A few volume rendering tweaks: - modified point density so that it returns a more consistent density with regards to search radius. Previously larger radii would give much higher density but this is equalised out now. - Added a new volume material option 'density scale'. This is an overall scale multiplier for density, allowing you to (for example) crank down the density to a more desirable range if you're working at a large physical scale. Volume rendering is fundamentally scale dependant so this lets you correct to get the right visual result. - Also tweaked a few constants, old files won't render exactly the same, just minor things though. --- source/blender/blenkernel/intern/material.c | 1 + source/blender/blenloader/intern/readfile.c | 2 ++ source/blender/makesdna/DNA_material_types.h | 2 +- source/blender/render/intern/source/pointdensity.c | 11 ++++++----- source/blender/render/intern/source/volumetric.c | 3 ++- source/blender/src/buttons_shading.c | 14 +++++++++----- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index f54c0ae7ab1..3fcc76bf058 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -167,6 +167,7 @@ void init_material(Material *ma) ma->sss_front= 1.0f; ma->sss_back= 1.0f; + ma->vol_density_scale = 1.0f; ma->vol_stepsize = 0.2f; ma->vol_shade_stepsize = 0.2f; ma->vol_absorption = 1.0f; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3cae5fe4972..a3e6a21dd0b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7893,6 +7893,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) ma->vol_scattering = 1.0f; ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f; } + if (ma->vol_density_scale < 0.0001f) + ma->vol_density_scale = 1.0f; } for(tex=main->tex.first; tex; tex= tex->id.next) { diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 4e006d17682..3efb8d9c116 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -66,7 +66,7 @@ typedef struct Material { short pad5[3]; /* volumetrics */ - float vol_alphathresh; + float vol_density_scale; float vol_stepsize, vol_shade_stepsize; float vol_absorption, vol_scattering; float vol_absorption_col[3]; diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index bdfb4d3b9d1..e7b6aedb894 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -255,7 +255,7 @@ typedef struct PointDensityRangeData void accum_density(void *userdata, int index, float squared_dist) { PointDensityRangeData *pdr = (PointDensityRangeData *)userdata; - const float dist = pdr->squared_radius - squared_dist; + const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f; float density; if (pdr->falloff_type == TEX_PD_FALLOFF_STD) @@ -287,7 +287,7 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) float density=0.0f; float vec[3] = {0.0, 0.0, 0.0}; float tv[3]; - float turb; + float turb, noise_fac; if ((!pd) || (!pd->point_tree)) { texres->tin = 0.0f; @@ -299,6 +299,7 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) pdr.point_data = pd->point_data; pdr.falloff_type = pd->falloff_type; pdr.vec = vec; + noise_fac = pd->noise_fac * 0.5f; /* better default */ if (pd->flag & TEX_PD_TURBULENCE) { VECCOPY(tv, texvec); @@ -313,9 +314,9 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */ - tv[0] = texvec[0] + pd->noise_fac * turb; - tv[1] = texvec[1] + pd->noise_fac * turb; - tv[2] = texvec[2] + pd->noise_fac * turb; + tv[0] = texvec[0] + noise_fac * turb; + tv[1] = texvec[1] + noise_fac * turb; + tv[2] = texvec[2] + noise_fac * turb; /* do density lookup with altered coordinates */ BLI_bvhtree_range_query(pd->point_tree, tv, pd->radius, accum_density, &pdr); diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 9a6790976af..ea661c42cff 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -131,13 +131,14 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, float vol_get_density(struct ShadeInput *shi, float *co) { float density = shi->mat->alpha; + float density_scale = shi->mat->vol_density_scale; float col[3] = {0.0, 0.0, 0.0}; if (shi->mat->flag & MA_IS_TEXTURED) { do_volume_tex(shi, co, MAP_ALPHA, col, &density); } - return density; + return density * density_scale; } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 7be862b0f15..8d94d5f1ea3 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4363,7 +4363,7 @@ static void material_panel_material_volume(Material *ma) uiBlockBeginAlign(block); 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"); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_stepsize), 0.001, 100.0, 100, 2, "Ray marching step size"); uiBlockEndAlign(block); yco -= YSPACE; @@ -4372,7 +4372,7 @@ static void material_panel_material_volume(Material *ma) uiDefButBitS(block, TOG, MA_VOL_ATTENUATED, B_MATPRV, "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"); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shade_stepsize), 0.001, 100.0, 100, 2, "Step"); uiBlockEndAlign(block); yco -= YSPACE; @@ -4389,14 +4389,18 @@ static void material_panel_material_volume(Material *ma) yco = PANEL_YMAX; + uiBlockBeginAlign(block); uiDefButF(block, NUMSLI, B_MATPRV, "Density: ", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->alpha), 0.0, 1.0, 0, 0, "Base opacity value"); + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->alpha), 0.0, 1.0, 0, 0, "Base density value - textured density is added on top"); + uiDefButF(block, NUM, B_MATPRV, "Density Scale: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_density_scale), 0.000001, 100.0, 100, 2, "Global density multiplier"); + uiBlockEndAlign(block); yco -= YSPACE; uiBlockBeginAlign(block); uiDefButF(block, NUM, B_MATPRV, "Absorption: ", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 10.0, 10, 0, "Multiplier for absorption"); + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 100.0, 10, 0, "Multiplier for absorption"); uiDefButF(block, COL, B_MATPRV, "", X2CLM2, yco-=BUTH, BUTW2, BUTH, ma->vol_absorption_col, 0, 0, 0, B_MATCOL, ""); uiBlockEndAlign(block); @@ -4413,7 +4417,7 @@ 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, 10.0, 10, 0, "Multiplier for scattering"); + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_scattering), 0.0, 100.0, 10, 0, "Multiplier for scattering"); } static void material_panel_nodes(Material *ma) From c0ddd5fd4914f7876cdf36225566d795e415bbf1 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 13 Oct 2008 00:35:58 +0000 Subject: [PATCH 28/88] * New option for step size: Randomized This is on by default, and trades random noise for banding. It jitters the step size from 75% to 125% of its original amount, and since it uses the threaded random seeds, shouldn't flicker during animation. These two images took roughly the same time to render: http://mke3.net/blender/devel/rendering/volumetrics/vol_stepsize_randomized.jpg --- source/blender/makesdna/DNA_material_types.h | 10 ++++-- .../blender/render/intern/source/volumetric.c | 32 ++++++++++++++++--- source/blender/src/buttons_shading.c | 8 +++-- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 3efb8d9c116..86de34e5d26 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -63,11 +63,12 @@ typedef struct Material { /* end synced with render_types.h */ short material_type; /* solid, halo, volumetric */ - short pad5[3]; + short pad5[2]; /* volumetrics */ - float vol_density_scale; + short vol_stepsize_type; float vol_stepsize, vol_shade_stepsize; + float vol_density_scale; float vol_absorption, vol_scattering; float vol_absorption_col[3]; short vol_shadeflag; @@ -347,6 +348,11 @@ typedef struct Material { /* sss_flag */ #define MA_DIFF_SSS 1 +/* vol_stepsize_type */ +#define MA_VOL_STEP_RANDOMIZED 0 +#define MA_VOL_STEP_CONSTANT 1 +#define MA_VOL_STEP_ADAPTIVE 2 + /* vol_shadeflag */ #define MA_VOL_SHADED 1 #define MA_VOL_ATTENUATED 2 diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index ea661c42cff..e0006a24fba 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -128,6 +128,29 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, } } +#define STEPSIZE_VIEW 0 +#define STEPSIZE_SHADE 1 +float vol_get_stepsize(struct ShadeInput *shi, int context) +{ + if (shi->mat->vol_stepsize_type == MA_VOL_STEP_RANDOMIZED) { + /* range between 0.75 and 1.25 */ + const float rnd = 0.5f * BLI_thread_frand(shi->thread) + 0.75f; + + if (context == STEPSIZE_VIEW) + return shi->mat->vol_stepsize * rnd; + else if (context == STEPSIZE_SHADE) + return shi->mat->vol_shade_stepsize * rnd; + } + else { + // MA_VOL_STEP_CONSTANT + + if (context == STEPSIZE_VIEW) + return shi->mat->vol_stepsize; + else if (context == STEPSIZE_SHADE) + return shi->mat->vol_shade_stepsize; + } +} + float vol_get_density(struct ShadeInput *shi, float *co) { float density = shi->mat->alpha; @@ -264,6 +287,7 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * float hitco[3], *atten_co; float p; float scatter_fac; + float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE); if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; if ((lar->lay & shi->lay)==0) return; @@ -303,8 +327,8 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * atten_co = lar->co; } else atten_co = hitco; - - vol_get_attenuation(shi, tau, co, atten_co, density, shi->mat->vol_shade_stepsize); + + vol_get_attenuation(shi, tau, co, atten_co, density, shade_stepsize); tr[0] = exp(-tau[0]); tr[1] = exp(-tau[1]); tr[2] = exp(-tau[2]); @@ -321,8 +345,6 @@ 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); - - } /* shadows -> trace a ray to find blocker geometry @@ -362,7 +384,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float { 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; + float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW); int nsteps; float vec[3], stepvec[3] = {0.0, 0.0, 0.0}; float tau[3], step_emit[3], step_scatter[3] = {0.0, 0.0, 0.0}; diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 8d94d5f1ea3..ac4f10cf214 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4363,7 +4363,9 @@ static void material_panel_material_volume(Material *ma) uiBlockBeginAlign(block); uiDefButF(block, NUM, B_MATPRV, "Step Size: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_stepsize), 0.001, 100.0, 100, 2, "Ray marching 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"); uiBlockEndAlign(block); yco -= YSPACE; @@ -4372,7 +4374,7 @@ static void material_panel_material_volume(Material *ma) uiDefButBitS(block, TOG, MA_VOL_ATTENUATED, B_MATPRV, "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, 100, 2, "Step"); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shade_stepsize), 0.001, 100.0, 10, 2, "Step"); uiBlockEndAlign(block); yco -= YSPACE; @@ -4393,7 +4395,7 @@ static void material_panel_material_volume(Material *ma) uiDefButF(block, NUMSLI, B_MATPRV, "Density: ", X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->alpha), 0.0, 1.0, 0, 0, "Base density value - textured density is added on top"); uiDefButF(block, NUM, B_MATPRV, "Density Scale: ", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_density_scale), 0.000001, 100.0, 100, 2, "Global density multiplier"); + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_density_scale), 0.000001, 100.0, 10, 2, "Global density multiplier"); uiBlockEndAlign(block); yco -= YSPACE; From d6808c2b4b9d53f5481e96d4041e67b20f1d56f0 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 13 Oct 2008 05:22:31 +0000 Subject: [PATCH 29/88] * Raytraced shadow casting for volumes This is a first version and still has a couple of things undefined or unimplemented, such as external objects casting shadows on or within volumes, however volume->solid shadows are going ok. http://mke3.net/blender/devel/rendering/volumetrics/shadows_test_02.mov http://mke3.net/blender/devel/rendering/volumetrics/vol_test_shad3.blend As with other transparent raytraced shadows in Blender ,in order to make it work, you must enable 'TraShad' on the material *receiving* the shadow. It would be nice to make this a bit easier to use, since there's not much chance you want a volume material to be casting solid shadows, but that's a bigger issue in the renderer outside this scope. The volume shadows are working from the same physical basis of absorption, and support coloured absorption: http://mke3.net/blender/devel/rendering/volumetrics/vol_shad_absorption.png They also work properly with multi-sampled (i.e. QMC) soft shadows: http://mke3.net/blender/devel/rendering/volumetrics/vol_shad_sharp.png http://mke3.net/blender/devel/rendering/volumetrics/vol_shad_soft.png And by popular request the test file: http://mke3.net/blender/devel/rendering/volumetrics/vol_test_shad_clouds.blend --- .../render/intern/include/pointdensity.h | 1 + .../render/intern/include/rendercore.h | 2 + .../render/intern/include/volumetric.h | 3 +- .../render/intern/source/convertblender.c | 2 - .../blender/render/intern/source/rayshade.c | 33 ++++++---- .../blender/render/intern/source/volumetric.c | 60 ++++++++++++++++++- 6 files changed, 87 insertions(+), 14 deletions(-) diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h index 9c21cc0c253..93cdef3b14e 100644 --- a/source/blender/render/intern/include/pointdensity.h +++ b/source/blender/render/intern/include/pointdensity.h @@ -37,6 +37,7 @@ struct Render; struct TexResult; void make_pointdensities(struct Render *re); +void free_pointdensities(struct Render *re); int pointdensitytex(struct Tex *tex, float *texvec, struct TexResult *texres); #endif /* POINTDENSITY_H */ diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index 4b28529a147..972071764d2 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -48,6 +48,7 @@ struct RenderPart; struct RenderLayer; struct ObjectRen; struct ListBase; +struct Isect; /* ------------------------------------------------------------------------- */ @@ -98,6 +99,7 @@ extern void makeraytree(Render *re); extern void ray_shadow(ShadeInput *, LampRen *, float *); extern void ray_trace(ShadeInput *, ShadeResult *); +extern void ray_trace_shadow_tra(struct Isect *is, int depth, int traflag); extern void ray_ao(ShadeInput *, float *); extern void init_jitter_plane(LampRen *lar); extern void init_ao_sphere(struct World *wrld); diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h index 8db3fa63f98..290be427f01 100644 --- a/source/blender/render/intern/include/volumetric.h +++ b/source/blender/render/intern/include/volumetric.h @@ -26,4 +26,5 @@ * ***** END GPL LICENSE BLOCK ***** */ -void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr); \ No newline at end of file +void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr); +void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is); \ No newline at end of file diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 4b663c6caa6..0660d9e0b24 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -965,8 +965,6 @@ static Material *give_render_material(Render *re, Object *ob, int nr) if(ma->nodetree && ma->use_nodes) flag_render_node_material(re, ma->nodetree); - if (ma->material_type == MA_VOLUME) re->r.mode |= R_RAYTRACE; - check_material_is_textured(ma); return ma; diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index c431340d770..d06bbcf3300 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -54,6 +54,7 @@ #include "pixelshading.h" #include "shading.h" #include "texture.h" +#include "volumetric.h" #include "RE_raytrace.h" @@ -262,21 +263,28 @@ void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) shade_input_set_shade_texco(shi); - if(is->mode==RE_RAY_SHADOW_TRA) + if (shi->mat->material_type == MA_VOLUME) { + if(ELEM(is->mode, RE_RAY_SHADOW, RE_RAY_SHADOW_TRA)) { + volume_trace_shadow(shi, shr, is); + } else { + shade_volume_loop(shi, shr); + } + } + else if(is->mode==RE_RAY_SHADOW_TRA) if(shi->mat->nodetree && shi->mat->use_nodes) { ntreeShaderExecTree(shi->mat->nodetree, shi, shr); shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ } - else + else { shade_color(shi, shr); + } else { if(shi->mat->nodetree && shi->mat->use_nodes) { ntreeShaderExecTree(shi->mat->nodetree, shi, shr); shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ } else { - if (shi->mat->material_type == MA_SOLID) shade_material_loop(shi, shr); - else if (shi->mat->material_type == MA_VOLUME) shade_volume_loop(shi, shr); + shade_material_loop(shi, shr); } /* raytrace likes to separate the spec color */ VECSUB(shr->diff, shr->combined, shr->spec); @@ -1274,7 +1282,7 @@ static void addAlphaLight(float *shadfac, float *col, float alpha, float filter) shadfac[3]= (1.0f-alpha)*shadfac[3]; } -static void ray_trace_shadow_tra(Isect *is, int depth, int traflag) +void ray_trace_shadow_tra(Isect *is, int depth, int traflag) { /* ray to lamp, find first face that intersects, check alpha properties, if it has col[3]>0.0f continue. so exit when alpha is full */ @@ -1303,11 +1311,16 @@ static void ray_trace_shadow_tra(Isect *is, int depth, int traflag) shi.mat_override= NULL;*/ shade_ray(is, &shi, &shr); - if (traflag & RAY_TRA) - d= shade_by_transmission(is, &shi, &shr); - - /* mix colors based on shadfac (rgb + amount of light factor) */ - addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter); + if (shi.mat->material_type == MA_SOLID) { + if (traflag & RAY_TRA) + d= shade_by_transmission(is, &shi, &shr); + + /* mix colors based on shadfac (rgb + amount of light factor) */ + addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter); + } else { + // MA_VOLUME + addAlphaLight(is->col, shr.combined, shr.alpha, 1.0f); + } if(depth>0 && is->col[3]>0.0f) { diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index e0006a24fba..3b44e1bb87f 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -149,6 +149,8 @@ float vol_get_stepsize(struct ShadeInput *shi, int context) else if (context == STEPSIZE_SHADE) return shi->mat->vol_shade_stepsize; } + + return shi->mat->vol_stepsize; } float vol_get_density(struct ShadeInput *shi, float *co) @@ -247,6 +249,8 @@ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, f dist = VecLenf(co, endco); nsteps = (int)ceil(dist / stepsize); + if (density < -0.001f) density = vol_get_density(shi, co); + if (nsteps == 1) { /* homogenous volume within the sampled distance */ tau[0] = tau[1] = tau[2] = dist * density; @@ -485,7 +489,7 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is) shi_new.mask= shi->mask; shi_new.osatex= shi->osatex; shi_new.thread= shi->thread; - shi_new.depth= shi->depth; + shi_new.depth= 1; shi_new.volume_depth= shi->volume_depth + 1; shi_new.xs= shi->xs; shi_new.ys= shi->ys; @@ -597,3 +601,57 @@ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) shr->combined[3] = shr->alpha = 1.0f; } } + +void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is) +{ + float hitco[3], col[4] = {0.f,0.f,0.f,0.f}; + float tr[3] = {1.0,1.0,1.0}; + float tau[3] = {0.0,0.0,0.0}; + Isect is; + float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE); + + memset(shr, 0, sizeof(ShadeResult)); + + /* if 1st hit normal is facing away from the camera, + * then we're inside the volume already. */ + if (shi->flippednor) { + + vol_get_attenuation(shi, tau, last_is->start, shi->co, -1.0f, shade_stepsize); + tr[0] = exp(-tau[0]); + tr[1] = exp(-tau[1]); + tr[2] = exp(-tau[2]); + + shr->combined[0] = tr[0]; + shr->combined[1] = tr[1]; + shr->combined[2] = tr[2]; + + shr->combined[3] = 1.0f -(tr[0] + tr[1] + tr[2]) * 0.333f; + shr->alpha = shr->combined[3]; + } + /* trace to find a backface, the other side bounds of the volume */ + /* (ray intersect ignores front faces here) */ + else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH, 0)) { + float dist = VecLenf(shi->co, hitco); + + vol_get_attenuation(shi, tau, shi->co, hitco, -1.0f, shade_stepsize); + tr[0] = exp(-tau[0]); + tr[1] = exp(-tau[1]); + tr[2] = exp(-tau[2]); + + shr->combined[0] = tr[0]; + shr->combined[1] = tr[1]; + shr->combined[2] = tr[2]; + + shr->combined[3] = 1.0f -(tr[0] + tr[1] + tr[2]) * 0.333f; + shr->alpha = shr->combined[3]; + + } + else { + shr->combined[0] = 0.0f; + shr->combined[1] = 0.0f; + shr->combined[2] = 0.0f; + shr->combined[3] = shr->alpha = 0.0f; + } + +} + From 51d51991e59f98e7cff3a035d5ba3a142f1ed7e0 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 13 Oct 2008 06:46:23 +0000 Subject: [PATCH 30/88] * Added support for solid objects casting shadows within a volume. Currently it only supports solid shadows - if it's a solid object, it will cast 100% shadow. Support for transparent shadows can potentially be added down the track. http://mke3.net/blender/devel/rendering/volumetrics/vol_shad_internal.jpg --- source/blender/makesdna/DNA_material_types.h | 2 +- source/blender/render/intern/source/volumetric.c | 12 +++++++++--- source/blender/src/buttons_shading.c | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 86de34e5d26..7b6e945dfbf 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -356,7 +356,7 @@ typedef struct Material { /* vol_shadeflag */ #define MA_VOL_SHADED 1 #define MA_VOL_ATTENUATED 2 -#define MA_VOL_SHADOWED 4 +#define MA_VOL_RECVSHADOW 4 /* vol_phasefunc_type */ #define MA_VOL_PH_ISOTROPIC 0 diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 3b44e1bb87f..6e2e817fc85 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -292,7 +292,8 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * float p; float scatter_fac; float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE); - + float shadfac[4]; + if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; if ((lar->lay & shi->lay)==0) return; if (lar->energy == 0.0) return; @@ -324,7 +325,13 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * /* find minimum of volume bounds, or lamp coord */ if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS, 0)) { float dist = VecLenf(co, hitco); + VlakRen *vlr = (VlakRen *)is.face; + if (vlr->mat->material_type == MA_SOLID) { + lacol[0] = lacol[1] = lacol[2] = 0.0f; + return; + } + if (ELEM(lar->type, LA_SUN, LA_HEMI)) atten_co = hitco; else if ( lampdist < dist ) { @@ -604,7 +611,7 @@ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is) { - float hitco[3], col[4] = {0.f,0.f,0.f,0.f}; + float hitco[3]; float tr[3] = {1.0,1.0,1.0}; float tau[3] = {0.0,0.0,0.0}; Isect is; @@ -631,7 +638,6 @@ void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct /* trace to find a backface, the other side bounds of the volume */ /* (ray intersect ignores front faces here) */ else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH, 0)) { - float dist = VecLenf(shi->co, hitco); vol_get_attenuation(shi, tau, shi->co, hitco, -1.0f, shade_stepsize); tr[0] = exp(-tau[0]); diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index ac4f10cf214..430b50717df 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4371,7 +4371,7 @@ static void material_panel_material_volume(Material *ma) yco -= YSPACE; uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, MA_VOL_ATTENUATED, B_MATPRV, "Shading", + 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"); @@ -4388,7 +4388,10 @@ static void material_panel_material_volume(Material *ma) } 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"); + */ + yco = PANEL_YMAX; uiBlockBeginAlign(block); From b3000c5529d10ae5002d25384c50d934b233a216 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 17 Oct 2008 05:54:42 +0000 Subject: [PATCH 31/88] non-working WIP commit to continue coding at home. nothing to see here, move along! --- source/blender/makesdna/DNA_material_types.h | 1 + .../render/intern/include/render_types.h | 14 ++ .../render/intern/include/volumetric.h | 4 +- .../render/intern/source/convertblender.c | 20 +++ .../render/intern/source/renderdatabase.c | 1 + .../blender/render/intern/source/volumetric.c | 126 +++++++++++++++--- source/blender/src/buttons_shading.c | 2 + 7 files changed, 150 insertions(+), 18 deletions(-) diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 7b6e945dfbf..3ceb267ce67 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -357,6 +357,7 @@ typedef struct Material { #define MA_VOL_SHADED 1 #define MA_VOL_ATTENUATED 2 #define MA_VOL_RECVSHADOW 4 +#define MA_VOL_PRECACHESHADING 8 /* vol_phasefunc_type */ #define MA_VOL_PH_ISOTROPIC 0 diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index b0003cadb55..6f4537d84fb 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -201,6 +201,8 @@ struct Render ListBase customdata_names; struct Object *excludeob; + + ListBase vol_precache_obs; /* arena for allocating data for use during render, for * example dynamic TFaces to go in the VlakRen structure. @@ -285,6 +287,8 @@ typedef struct ObjectInstanceRen { float dupliorco[3], dupliuv[2]; float (*duplitexmat)[4]; + + float *volume_precache; float *vectors; int totvector; @@ -396,6 +400,16 @@ typedef struct StrandRen { float orco[3]; } StrandRen; +/* ------------------------------------------------------------------------- */ + +typedef struct VolPrecache +{ + struct VolPrecache *next, *prev; + struct Material *ma; + struct ObjectRen *obr; +} VolPrecache; + +/* ------------------------------------------------------------------------- */ struct LampRen; struct MTex; diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h index 290be427f01..fb87035145f 100644 --- a/source/blender/render/intern/include/volumetric.h +++ b/source/blender/render/intern/include/volumetric.h @@ -27,4 +27,6 @@ */ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr); -void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is); \ No newline at end of file +void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is); +void volume_precache(Render *re); +void free_volume_precache(Render *re); \ No newline at end of file diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 0660d9e0b24..4c9914aa4d3 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3026,6 +3026,18 @@ static void use_mesh_edge_lookup(ObjectRen *obr, DerivedMesh *dm, MEdge *medge, } } +static void add_vol_precache(Render *re, ObjectRen *obr, Material *ma) +{ + struct VolPrecache *vp; + + vp = MEM_mallocN(sizeof(VolPrecache), "volume precache object"); + + vp->ma = ma; + vp->obr = obr; + + BLI_addtail(&re->vol_precache_obs, vp); +} + static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) { Object *ob= obr->ob; @@ -3080,6 +3092,10 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) if(re->r.mode & R_RADIO) if(ma->mode & MA_RADIO) do_autosmooth= 1; + + if (ma->vol_shadeflag & MA_VOL_PRECACHESHADING) { + add_vol_precache(re, obr, ma); + } } } @@ -4436,6 +4452,7 @@ void RE_Database_Free(Render *re) end_render_materials(); free_pointdensities(re); + free_volume_precache(re); if(re->wrld.aosphere) { MEM_freeN(re->wrld.aosphere); @@ -4891,6 +4908,9 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) /* point density texture */ if(!re->test_break()) make_pointdensities(re); + + if(!re->test_break()) + volume_precache(re); } if(!re->test_break()) diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index d44b49cc706..1bc1c1a712a 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -1323,6 +1323,7 @@ ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, obi->index= index; obi->psysindex= psysindex; obi->lay= lay; + obi->volume_precache = NULL; if(mat) { Mat4CpyMat4(obi->mat, mat); diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 6e2e817fc85..3128c67ee88 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -31,6 +31,8 @@ #include #include +#include "MEM_guardedalloc.h" + #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_rand.h" @@ -44,6 +46,7 @@ #include "DNA_lamp_types.h" #include "BKE_global.h" +#include "BKE_main.h" #include "render_types.h" #include "pixelshading.h" @@ -166,7 +169,6 @@ float vol_get_density(struct ShadeInput *shi, float *co) return density * density_scale; } - /* compute emission component, amount of radiance to add per segment * can be textured with 'emit' */ void vol_get_emission(ShadeInput *shi, float *em, float *co, float density) @@ -182,14 +184,16 @@ void vol_get_emission(ShadeInput *shi, float *em, float *co, float density) VecMulVecf(em, em, col); } +/* scattering multiplier, values above 1.0 are non-physical, + * but can be useful to tweak lighting */ void vol_get_scattering_fac(ShadeInput *shi, float *scatter_fac, float *co, float density) { - //float col[3] = {0.0, 0.0, 0.0}; - //do_volume_tex(shi, co, MAP_EMIT+MAP_COL, col, &emission); - *scatter_fac = shi->mat->vol_scattering; } +/* phase function - determines in which directions the light + * is scattered in the volume relative to incoming direction + * and view direction */ float vol_get_phasefunc(ShadeInput *shi, short phasefunc_type, float g, float *w, float *wp) { const float costheta = Inpf(w, wp); @@ -235,7 +239,7 @@ void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co) /* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau. * Used in the relationship Transmittance = e^(-attenuation) - * can be textured with 'alpha' */ + */ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, float density, float stepsize) { /* input density = density at co */ @@ -249,6 +253,7 @@ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, f dist = VecLenf(co, endco); nsteps = (int)ceil(dist / stepsize); + /* trigger for recalculating density */ if (density < -0.001f) density = vol_get_density(shi, co); if (nsteps == 1) { @@ -327,6 +332,7 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * float dist = VecLenf(co, hitco); VlakRen *vlr = (VlakRen *)is.face; + /* simple internal shadowing */ if (vlr->mat->material_type == MA_SOLID) { lacol[0] = lacol[1] = lacol[2] = 0.0f; return; @@ -347,9 +353,9 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * VecMulVecf(lacol, lacol, tr); } else { - /* point is on the outside edge of the volume, - * therefore no attenuation, full transmission - * radiance from lamp remains unchanged */ + /* Point is on the outside edge of the volume, + * therefore no attenuation, full transmission. + * Radiance from lamp remains unchanged */ } } @@ -358,13 +364,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * } -/* shadows -> trace a ray to find blocker geometry - - if blocker is outside the volume, use standard shadow functions - - if blocker is inside the volume, use raytracing - -- (deep shadow maps could potentially slot in here too I suppose) - - attenuate from current point, to blocked point or volume bounds -*/ - /* single scattering only for now */ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsize, float density) { @@ -382,7 +381,7 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi if (lar==NULL) continue; vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density); - + VecMulf(lacol, density); VecAddf(col, col, lacol); @@ -425,7 +424,28 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float /* get radiance from all points along the ray due to participating media */ for (s = 0; s < nsteps; s++) { - if (s > 0) density = vol_get_density(shi, step_sta); + + if (shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) { + int res = 10; + int x,y,z; + + step_mid[0] = step_sta[0] + (stepvec[0] * 0.5); + step_mid[1] = step_sta[1] + (stepvec[1] * 0.5); + step_mid[2] = step_sta[2] + (stepvec[2] * 0.5); + + //CLAMP(step_mid[0], 0.0f, 1.0f); + //CLAMP(step_mid[1], 0.0f, 1.0f); + //CLAMP(step_mid[2], 0.0f, 1.0f); + + MTC_Mat4MulVecfl(R.viewinv, step_mid); + + x = (int)step_mid[0] * res; + y = (int)step_mid[1] * res; + z = (int)step_mid[2] * res; + + density = shi->obi->volume_precache[x*res + y*res + z*res]; + } + else if (s > 0) density = vol_get_density(shi, step_sta); /* there's only any use in shading here * if there's actually some density to shade! */ @@ -661,3 +681,75 @@ void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct } +void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *ma) +{ + int x, y, z; + int res = 10; + float co[3]; + ShadeInput shi; + int foundma=0; + float density; + float resf; + int i; + + memset(&shi, 0, sizeof(ShadeInput)); + shi.depth= 1; + shi.mask= 1; + shi.mat = ma; + shi.vlr = NULL; + memcpy(&shi.r, &shi.mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h + shi.har= shi.mat->har; + + shi.obi= obi; + shi.obr= obi->obr; + + resf = (float) res; + + obi->volume_precache = MEM_mallocN(sizeof(float)*res*res*res, "volume light cache"); + + for (x=0; x < res; x++) { + co[0] = (float)x / resf; + + for (y=0; y < res; y++) { + co[1] = (float)y / resf; + + for (z=0; z < res; z++) { + co[2] = (float)z / resf; + + density = vol_get_density(&shi, co); + + obi->volume_precache[x*res + y*res + z*res] = density; + + printf("vol_light_cache[%d][%d][%d] = %f \n", x, y, z, obi->volume_precache[x*res + y*res + z*res]); + } + } + } +} + +void volume_precache(Render *re) +{ + ObjectInstanceRen *obi; + VolPrecache *vp; + + 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); + vol_precache_objectinstance(re, obi, vp->ma); + } + } +} + +void free_volume_precache(Render *re) +{ + ObjectInstanceRen *obi; + + for(obi= re->instancetable.first; obi; obi= obi->next) { + if (obi->volume_precache) + MEM_freeN(obi->volume_precache); + } + + BLI_freelistN(&re->vol_precache_obs); +} \ No newline at end of file diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 430b50717df..63fa127824a 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4375,6 +4375,8 @@ static void material_panel_material_volume(Material *ma) 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"); uiBlockEndAlign(block); yco -= YSPACE; From 49aa7edb7708fcc0119d8251fa423903b022e706 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sun, 19 Oct 2008 08:25:10 +0000 Subject: [PATCH 32/88] Another WIP commit, nothing to see yet. --- source/blender/makesdna/DNA_material_types.h | 3 +- .../render/intern/source/convertblender.c | 11 +- .../render/intern/source/pointdensity.c | 3 + .../blender/render/intern/source/volumetric.c | 128 +++++++++++------- source/blender/src/buttons_shading.c | 2 + 5 files changed, 94 insertions(+), 53 deletions(-) diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 3ceb267ce67..66f23c7905d 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -63,10 +63,11 @@ typedef struct Material { /* end synced with render_types.h */ short material_type; /* solid, halo, volumetric */ - short pad5[2]; + short pad5; /* volumetrics */ short vol_stepsize_type; + short vol_precache_resolution; float vol_stepsize, vol_shade_stepsize; float vol_density_scale; float vol_absorption, vol_scattering; diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 4c9914aa4d3..c58946bb64b 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3093,7 +3093,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) if(ma->mode & MA_RADIO) do_autosmooth= 1; - if (ma->vol_shadeflag & MA_VOL_PRECACHESHADING) { + if ((ma->material_type == MA_VOLUME) && (ma->vol_shadeflag & MA_VOL_PRECACHESHADING)) { add_vol_precache(re, obr, ma); } } @@ -4429,6 +4429,8 @@ void RE_Database_Free(Render *re) BLI_freelistN(&re->lampren); BLI_freelistN(&re->lights); + + free_volume_precache(re); free_renderdata_tables(re); @@ -4452,7 +4454,6 @@ void RE_Database_Free(Render *re) end_render_materials(); free_pointdensities(re); - free_volume_precache(re); if(re->wrld.aosphere) { MEM_freeN(re->wrld.aosphere); @@ -4908,9 +4909,6 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) /* point density texture */ if(!re->test_break()) make_pointdensities(re); - - if(!re->test_break()) - volume_precache(re); } if(!re->test_break()) @@ -4927,6 +4925,9 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) if((re->r.mode & R_SSS) && !re->test_break()) if(re->r.renderer==R_INTERN) make_sss_tree(re); + + if(!re->test_break()) + volume_precache(re); } if(re->test_break()) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index e7b6aedb894..f7c6767fcd8 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -227,6 +227,9 @@ void make_pointdensities(Render *re) cache_pointdensity(re, tex); } } + + re->i.infostr= NULL; + re->stats_draw(&re->i); } void free_pointdensities(Render *re) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 3128c67ee88..fc2e4a630b1 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -21,7 +21,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): Farsthary (Raul FHernandez), Matt Ebb. + * Contributor(s): Matt Ebb, Raul Hernandez. * * ***** END GPL LICENSE BLOCK ***** */ @@ -38,6 +38,8 @@ #include "BLI_rand.h" #include "BLI_kdtree.h" +#include "PIL_time.h" + #include "RE_shader_ext.h" #include "RE_raytrace.h" @@ -59,6 +61,7 @@ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#define PRECACHE_RES 5 static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) { @@ -365,7 +368,7 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * } /* single scattering only for now */ -void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsize, float density) +void vol_get_scattering(Render *re, ShadeInput *shi, float *scatter, float *co, float stepsize, float density) { GroupObject *go; ListBase *lights; @@ -378,13 +381,14 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi float lacol[3] = {0.f, 0.f, 0.f}; lar= go->lampren; - if (lar==NULL) continue; + if (lar) { - vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density); + vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density); - VecMulf(lacol, density); + VecMulf(lacol, density); - VecAddf(col, col, lacol); + VecAddf(col, col, lacol); + } } VECCOPY(scatter, col); @@ -397,7 +401,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW); int nsteps; float vec[3], stepvec[3] = {0.0, 0.0, 0.0}; - float tau[3], step_emit[3], step_scatter[3] = {0.0, 0.0, 0.0}; + float tau[3], emit_col[3], scatter_col[3] = {0.0, 0.0, 0.0}; int s; float step_sta[3], step_end[3], step_mid[3]; float alpha; @@ -425,27 +429,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float /* get radiance from all points along the ray due to participating media */ for (s = 0; s < nsteps; s++) { - if (shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) { - int res = 10; - int x,y,z; - - step_mid[0] = step_sta[0] + (stepvec[0] * 0.5); - step_mid[1] = step_sta[1] + (stepvec[1] * 0.5); - step_mid[2] = step_sta[2] + (stepvec[2] * 0.5); - - //CLAMP(step_mid[0], 0.0f, 1.0f); - //CLAMP(step_mid[1], 0.0f, 1.0f); - //CLAMP(step_mid[2], 0.0f, 1.0f); - - MTC_Mat4MulVecfl(R.viewinv, step_mid); - - x = (int)step_mid[0] * res; - y = (int)step_mid[1] * res; - z = (int)step_mid[2] * res; - - density = shi->obi->volume_precache[x*res + y*res + z*res]; - } - else if (s > 0) density = vol_get_density(shi, step_sta); + if (s > 0) density = vol_get_density(shi, step_sta); /* there's only any use in shading here * if there's actually some density to shade! */ @@ -462,10 +446,26 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float step_mid[2] = step_sta[2] + (stepvec[2] * 0.5); /* incoming light via emission or scattering (additive) */ - vol_get_emission(shi, step_emit, step_mid, density); - vol_get_scattering(shi, step_scatter, step_mid, stepsize, density); + 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); - VecAddf(d_radiance, step_emit, step_scatter); + VecAddf(d_radiance, emit_col, scatter_col); /* Lv += Tr * (Lve() + Ld) */ VecMulVecf(d_radiance, tr, d_radiance); @@ -681,17 +681,23 @@ void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct } -void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *ma) +void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *ma, float *bbmin, float *bbmax) { int x, y, z; - int res = 10; - float co[3]; + + float co[3], voxel[3], scatter_col[3]; ShadeInput shi; - int foundma=0; float density; - float resf; - int i; + float stepsize; + float resf; + int res_2; + float res_3; + + float i = 1.0f; + double lasttime= PIL_check_seconds_timer(); + const int res = ma->vol_precache_resolution; + memset(&shi, 0, sizeof(ShadeInput)); shi.depth= 1; shi.mask= 1; @@ -699,28 +705,49 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m shi.vlr = NULL; memcpy(&shi.r, &shi.mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h shi.har= shi.mat->har; - shi.obi= obi; shi.obr= obi->obr; + + stepsize = vol_get_stepsize(&shi, STEPSIZE_VIEW); resf = (float) res; + res_2 = res*res; + res_3 = res*res*res; + + VecSubf(voxel, bbmax, bbmin); + VecMulf(voxel, 1.0f/res); obi->volume_precache = MEM_mallocN(sizeof(float)*res*res*res, "volume light cache"); for (x=0; x < res; x++) { - co[0] = (float)x / resf; + co[0] = bbmin[0] + (voxel[0] * x); for (y=0; y < res; y++) { - co[1] = (float)y / resf; + co[1] = bbmin[1] + (voxel[1] * y); for (z=0; z < res; z++) { - co[2] = (float)z / resf; + 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 + y*res + z*res] = density; + obi->volume_precache[x*res_2 + y*res + z] = (scatter_col[0] + scatter_col[1] + scatter_col[2]) / 3.0f; - printf("vol_light_cache[%d][%d][%d] = %f \n", x, y, z, obi->volume_precache[x*res + y*res + z*res]); + /* 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))); + re->i.infostr= str; + re->stats_draw(&re->i); + re->i.infostr= NULL; + lasttime= time; + } + + i++; } } } @@ -730,16 +757,21 @@ 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); - vol_precache_objectinstance(re, obi, vp->ma); + if (obi->obr == vp->obr) { + printf("Precaching Object: %s with Material: %s \n", vp->obr->ob->id.name+2, vp->ma->id.name+2); + vol_precache_objectinstance(re, obi, vp->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]); + } } } + + re->i.infostr= NULL; + re->stats_draw(&re->i); } void free_volume_precache(Render *re) @@ -747,8 +779,10 @@ 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 63fa127824a..8ad4078b90e 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4377,6 +4377,8 @@ static void material_panel_material_volume(Material *ma) 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; From 9d2fc97827e2b94eb436081185108db9043ae54e Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 20 Oct 2008 07:08:06 +0000 Subject: [PATCH 33/88] 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. --- source/blender/blenkernel/intern/material.c | 1 + source/blender/blenloader/intern/readfile.c | 2 + .../render/extern/include/RE_shader_ext.h | 1 + .../blender/render/intern/source/shadeinput.c | 1 + .../blender/render/intern/source/volumetric.c | 301 ++++++++++++++---- source/blender/src/buttons_shading.c | 47 ++- 6 files changed, 275 insertions(+), 78 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; vobr->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) From 07f072457da87b1940970831422d3569ef069b7a Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 20 Oct 2008 23:12:42 +0000 Subject: [PATCH 34/88] * fix for crash after latest light cache commit --- source/blender/render/intern/source/convertblender.c | 3 ++- source/blender/render/intern/source/volumetric.c | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index c58946bb64b..74b03d1082f 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -4927,7 +4927,8 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) make_sss_tree(re); if(!re->test_break()) - volume_precache(re); + if(re->r.mode & R_RAYTRACE) + volume_precache(re); } if(re->test_break()) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 0f6e7591ece..6004442e4bc 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -253,6 +253,12 @@ inline float lerp(float t, float v1, float v2) { return (1.f - t) * v1 + t * v2; } +inline float do_lerp(float t, float a, float b) { + if (a > 0.f && b > 0.f) return lerp(t, a, b); + else if (a < 0.f) return b; + else if (b < 0.f) return a; +} + /* trilinear interpolation */ static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co) { @@ -587,6 +593,7 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is) shi_new.combinedflag= 0xFFFFFF; /* ray trace does all options */ shi_new.light_override= shi->light_override; shi_new.mat_override= shi->mat_override; + shi_new.re = shi->re; VECCOPY(shi_new.camera_co, is->start); @@ -920,7 +927,7 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m /* 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); From d335c2dfcf95e120ebc5e5f84b0c960cb9ca14ae Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 21 Oct 2008 02:04:29 +0000 Subject: [PATCH 35/88] * fixed a memory leak that was happening during preview render --- source/blender/render/intern/source/volumetric.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 6004442e4bc..c8cead3e8c7 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -913,8 +913,13 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m i++; /* display progress every second */ - if(re->test_break()) + if(re->test_break()) { + if(tree) { + RE_ray_tree_free(tree); + tree= NULL; + } return; + } if(time-lasttime>1.0f) { char str[64]; sprintf(str, "Precaching volume: %d%%", (int)(100.0f * (i / res_3f))); @@ -937,11 +942,13 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m } } } - + if(tree) { RE_ray_tree_free(tree); tree= NULL; } + + } /* loop through all objects (and their associated materials) From 97a7b05068254543615ff274d77e66aea356df28 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 21 Oct 2008 06:10:36 +0000 Subject: [PATCH 36/88] fixed a crash in volume shadows --- source/blender/render/intern/source/rayshade.c | 2 ++ source/blender/render/intern/source/volumetric.c | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index d06bbcf3300..7e9a5c9abb3 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -467,6 +467,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo //shi.do_preview= 0; // memset above, so dont need this shi.light_override= origshi->light_override; shi.mat_override= origshi->mat_override; + shi.re = origshi->re; memset(&shr, 0, sizeof(ShadeResult)); @@ -1300,6 +1301,7 @@ void ray_trace_shadow_tra(Isect *is, int depth, int traflag) shi.depth= 1; /* only used to indicate tracing */ shi.mask= 1; + shi.re = &R; /*shi.osatex= 0; shi.thread= shi.sample= 0; diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index c8cead3e8c7..82149f38176 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -297,8 +297,8 @@ static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, fl } } -#if 0 -/* no interpolation, not used */ + +/* no interpolation */ static void vol_get_precached_scattering_nearest(ShadeInput *shi, float *scatter_col, float *co) { const int res = shi->mat->vol_precache_resolution; @@ -319,7 +319,7 @@ static void vol_get_precached_scattering_nearest(ShadeInput *shi, float *scatter 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) @@ -529,7 +529,10 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float if ((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) && (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED)) { - vol_get_precached_scattering(shi, scatter_col, step_mid); + if (G.rt==0) + vol_get_precached_scattering(shi, scatter_col, step_mid); + else + vol_get_precached_scattering_nearest(shi, scatter_col, step_mid); } else vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); From b12d9bfa9caf6d99ca2e19b9cb456d037c17f049 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 21 Oct 2008 08:21:36 +0000 Subject: [PATCH 37/88] * reimplemented some things, hopefully may fix some problems zanqdo was having --- .../render/extern/include/RE_shader_ext.h | 1 - source/blender/render/intern/source/rayshade.c | 2 -- source/blender/render/intern/source/shadeinput.c | 1 - source/blender/render/intern/source/volumetric.c | 16 ++++++++-------- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 5a320da522f..112a1e9929d 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -100,7 +100,6 @@ 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/rayshade.c b/source/blender/render/intern/source/rayshade.c index 7e9a5c9abb3..d06bbcf3300 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -467,7 +467,6 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo //shi.do_preview= 0; // memset above, so dont need this shi.light_override= origshi->light_override; shi.mat_override= origshi->mat_override; - shi.re = origshi->re; memset(&shr, 0, sizeof(ShadeResult)); @@ -1301,7 +1300,6 @@ void ray_trace_shadow_tra(Isect *is, int depth, int traflag) shi.depth= 1; /* only used to indicate tracing */ shi.mask= 1; - shi.re = &R; /*shi.osatex= 0; shi.thread= shi.sample= 0; diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 6989fe66b67..aa11e3d75dd 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -1270,7 +1270,6 @@ 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 82149f38176..ebaf70f1cfe 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -95,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(shi->re->raytree); + float maxsize = RE_ray_tree_max_size(R.raytree); int intersected=0; /* TODO: use object's bounding box to calculate max size */ @@ -114,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(shi->re->raytree, isect, vol_backface_intersect_check); + intersected = RE_ray_tree_intersect_check(R.raytree, isect, vol_backface_intersect_check); else - intersected = RE_ray_tree_intersect(shi->re->raytree, isect); + intersected = RE_ray_tree_intersect(R.raytree, isect); if(intersected) { @@ -455,7 +455,7 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi float col[3] = {0.f, 0.f, 0.f}; int i=0; - for(go=shi->re->lights.first; go; go= go->next) + for(go=R.lights.first; go; go= go->next) { float lacol[3] = {0.f, 0.f, 0.f}; @@ -596,7 +596,6 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is) shi_new.combinedflag= 0xFFFFFF; /* ray trace does all options */ shi_new.light_override= shi->light_override; shi_new.mat_override= shi->mat_override; - shi_new.re = shi->re; VECCOPY(shi_new.camera_co, is->start); @@ -616,7 +615,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(shi->re->raytree); + float maxsize = RE_ray_tree_max_size(R.raytree); VECCOPY(isect.start, co); isect.end[0] = isect.start[0] + shi->view[0] * maxsize; @@ -632,7 +631,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(shi->re->raytree, &isect)) { + if(RE_ray_tree_intersect(R.raytree, &isect)) { shade_intersection(shi, col, &isect); } else { shadeSkyView(col, co, shi->view, NULL); @@ -865,6 +864,8 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m float i = 1.0f; double time, lasttime= PIL_check_seconds_timer(); const int res = ma->vol_precache_resolution; + + R = *re; /* create a raytree with just the faces of the instanced ObjectRen, * used for checking if the cached point is inside or outside. */ @@ -882,7 +883,6 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m 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); From 094fda8cd9c1e6f5f452bf6c47ad53bebb8dd4e6 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 22 Oct 2008 00:09:12 +0000 Subject: [PATCH 38/88] * Fixed a crash with using light cache on a plane (which doesn't really make sense, but shouldn't crash at least) --- source/blender/render/intern/source/volumetric.c | 7 +++++-- source/blender/src/drawnode.c | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index ebaf70f1cfe..cd35bc027d1 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -245,7 +245,7 @@ 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); + CLAMP(z, 0, res-1); return shi->obi->volume_precache[rgb*res*res*res + x*res*res + y*res + z]; } @@ -864,12 +864,13 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m float i = 1.0f; double time, lasttime= PIL_check_seconds_timer(); const int res = ma->vol_precache_resolution; + RayTree *tree; R = *re; /* 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); + tree = create_raytree_obi(obi, bbmin, bbmax); if (!tree) return; /* Need a shadeinput to calculate scattering */ @@ -893,6 +894,8 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m res_3f = (float)res_3; VecSubf(voxel, bbmax, bbmin); + if ((voxel[0] < FLT_EPSILON) || (voxel[1] < FLT_EPSILON) || (voxel[2] < FLT_EPSILON)) + return; VecMulf(voxel, 1.0f/res); obi->volume_precache = MEM_callocN(sizeof(float)*res_3*3, "volume light cache"); diff --git a/source/blender/src/drawnode.c b/source/blender/src/drawnode.c index 618eca15ac6..7decec3f0e3 100644 --- a/source/blender/src/drawnode.c +++ b/source/blender/src/drawnode.c @@ -1550,7 +1550,7 @@ static int node_composit_buts_vecblur(uiBlock *block, bNodeTree *ntree, bNode *n &nbd->maxspeed, 0, 1024, 0, 0, "If not zero, maximum speed in pixels"); uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "BlurFac:", butr->xmin, dy+19, dx, 19, - &nbd->fac, 0.0f, 2.0f, 10, 2, "Scaling factor for motion vectors, actually 'shutter speed' in frames"); + &nbd->fac, 0.0f, 10.0f, 10, 2, "Scaling factor for motion vectors, actually 'shutter speed' in frames"); uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Curved", butr->xmin, dy, dx, 19, &nbd->curved, 0.0f, 2.0f, 10, 2, "Interpolate between frames in a bezier curve, rather than linearly"); From 6f656f6482adfa93b010b364cac41a449b8fdc91 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 22 Oct 2008 00:26:19 +0000 Subject: [PATCH 39/88] fix for a compile error with msvc --- source/blender/render/intern/source/volumetric.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index cd35bc027d1..95cd9e5588b 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -56,6 +56,10 @@ #include "shading.h" #include "texture.h" +#if defined( _MSC_VER ) && !defined( __cplusplus ) +# define inline __inline +#endif // defined( _MSC_VER ) && !defined( __cplusplus ) + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ /* only to be used here in this file, it's for speed */ From 652e4b5225cc88d7bc74dfe092d60a8363ef3189 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 22 Oct 2008 01:31:46 +0000 Subject: [PATCH 40/88] Point Density: Replaced 'Sharp' falloff with 'Soft'. This falloff type has a variable softness, and can get some quite smooth results. It can be useful to get smooth transitions in density when you're using particles on a large scale: http://mke3.net/blender/devel/rendering/volumetrics/pd_falloff_soft.jpg Also removed 'angular velocity' turbulence source - it wasn't doing anything useful atm --- source/blender/blenkernel/intern/texture.c | 1 + source/blender/blenloader/intern/readfile.c | 2 ++ source/blender/makesdna/DNA_texture_types.h | 8 ++++---- .../render/intern/source/pointdensity.c | 19 ++++++++++--------- source/blender/src/buttons_shading.c | 12 +++++++++--- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 33b824623fa..6f58e054f69 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -875,6 +875,7 @@ PointDensity *BKE_add_pointdensity(void) pd= MEM_callocN(sizeof(PointDensity), "pointdensity"); pd->radius = 0.3f; pd->falloff_type = TEX_PD_FALLOFF_STD; + pd->falloff_softness = 2.0; pd->source = TEX_PD_PSYS; pd->point_tree = NULL; pd->point_data = NULL; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 4af54832221..8f005e99053 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7908,6 +7908,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) tex->pd->noise_fac = 1.0f; tex->pd->noise_influence = TEX_PD_NOISE_STATIC; } + if (tex->pd->falloff_softness < 1.0f) + tex->pd->falloff_softness = 2.0f; } } diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 95f61e73c79..c51311bb621 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -131,9 +131,10 @@ typedef struct PointDensity { short flag; short falloff_type; + float falloff_softness; float radius; short source; - short pdpad[3]; + short pdpad; struct Object *object; /* for 'Object' or 'Particle system' type - source object */ short psys_cache_space; /* cache points in worldspace, object space, ... ? */ @@ -425,7 +426,7 @@ typedef struct TexMapping { /* falloff_type */ #define TEX_PD_FALLOFF_STD 0 #define TEX_PD_FALLOFF_SMOOTH 1 -#define TEX_PD_FALLOFF_SHARP 2 +#define TEX_PD_FALLOFF_SOFT 2 #define TEX_PD_FALLOFF_CONSTANT 3 #define TEX_PD_FALLOFF_ROOT 4 @@ -441,8 +442,7 @@ typedef struct TexMapping { /* noise_influence */ #define TEX_PD_NOISE_STATIC 0 #define TEX_PD_NOISE_VEL 1 -#define TEX_PD_NOISE_ANGVEL 2 -#define TEX_PD_NOISE_TIME 3 +#define TEX_PD_NOISE_TIME 2 #endif diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index f7c6767fcd8..5f2c6153384 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -107,10 +107,6 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa pd->point_data[i*3 + 0] = state.vel[0]; pd->point_data[i*3 + 1] = state.vel[1]; pd->point_data[i*3 + 2] = state.vel[2]; - } else if (pd->noise_influence == TEX_PD_NOISE_ANGVEL) { - pd->point_data[i*3 + 0] = state.ave[0]; - pd->point_data[i*3 + 1] = state.ave[1]; - pd->point_data[i*3 + 2] = state.ave[2]; } } } @@ -252,6 +248,7 @@ typedef struct PointDensityRangeData float squared_radius; float *point_data; float *vec; + float softness; short falloff_type; } PointDensityRangeData; @@ -265,8 +262,8 @@ void accum_density(void *userdata, int index, float squared_dist) density = dist; else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH) density = 3.0f*dist*dist - 2.0f*dist*dist*dist; - else if (pdr->falloff_type == TEX_PD_FALLOFF_SHARP) - density = dist*dist; + else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT) + density = pow(dist, pdr->softness); else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT) density = pdr->squared_radius; else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT) @@ -302,6 +299,7 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) pdr.point_data = pd->point_data; pdr.falloff_type = pd->falloff_type; pdr.vec = vec; + pdr.softness = pd->falloff_softness; noise_fac = pd->noise_fac * 0.5f; /* better default */ if (pd->flag & TEX_PD_TURBULENCE) { @@ -329,13 +327,16 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) texres->tin = density; - //texres->tr = vec[0]; - //texres->tg = vec[1]; - //texres->tb = vec[2]; + + + BRICONT; return TEX_INT; /* + texres->tr = vec[0]; + texres->tg = vec[1]; + texres->tb = vec[2]; BRICONTRGB; texres->ta = 1.0; diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 72a396d63be..7e4298b4b6b 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -738,7 +738,7 @@ static void texture_panel_pointdensity(Tex *tex) short yco=PANEL_YMAX; block= uiNewBlock(&curarea->uiblocks, "texture_panel_pointdensity", UI_EMBOSS, UI_HELV, curarea->win); - if(uiNewPanel(curarea, block, "Point Density", "Texture", PANELX, PANELY, PANELW, PANELH)==0) return; + if(uiNewPanel(curarea, block, "Point Density", "Texture", PANELX, PANELY, PANELW, PANELH+25)==0) return; uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE); if(tex->pd==NULL) { @@ -758,8 +758,14 @@ static void texture_panel_pointdensity(Tex *tex) uiDefBut(block, LABEL, B_NOP, "Falloff:", X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - uiDefButS(block, MENU, B_REDR, "Standard %x0|Smooth %x1|Sharp %x2|Constant %x3|Root %x4", + uiBlockBeginAlign(block); + uiDefButS(block, MENU, B_REDR, "Standard %x0|Smooth %x1|Soft %x2|Constant %x3|Root %x4", X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->falloff_type, 0.0, 0.0, 0, 0, "Falloff type"); + if (pd->falloff_type == TEX_PD_FALLOFF_SOFT) { + uiDefButF(block, NUM, B_REDR, "Softness: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->falloff_softness), 1.0, 1024.0, 10, 2, "The intensity of the falloff"); + } + uiBlockEndAlign(block); yco -= YSPACE; @@ -782,7 +788,7 @@ static void texture_panel_pointdensity(Tex *tex) yco -= YSPACE; if (pd->source == TEX_PD_PSYS) { - uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1|Angular Velocity %x2", + uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); } } From febcbdcfcd5e7f7a480f7980410eec853ef04a5e Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 22 Oct 2008 02:59:33 +0000 Subject: [PATCH 41/88] Tweaked rendering inside a volume to always return alpha 1.0. This fixes an issue which darkened the render from inside a volume with sky or premul on. Still need to find a good way to get an alpha value back into the shader (for compositing etc) without getting the render distorted by premul. --- source/blender/render/intern/source/volumetric.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 95cd9e5588b..4ff6f5aea41 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -664,7 +664,8 @@ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) shr->combined[1] = col[1]; shr->combined[2] = col[2]; - if (col[3] > 1.0f) col[3] = 1.0f; + //if (col[3] > 1.0f) + col[3] = 1.0f; shr->combined[3] = col[3]; shr->alpha = col[3]; @@ -858,7 +859,7 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m float co[3], voxel[3], scatter_col[3]; ShadeInput shi; - float view[3] = {0.0,0.0,1.0}; + float view[3] = {0.0,0.0,-1.0}; float density; float stepsize; From 876368d859593c8ad152f94ea06214bacf516b0d Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 22 Oct 2008 05:24:41 +0000 Subject: [PATCH 42/88] * fix for point density - particle systems weren't being deformed by lattices --- source/blender/render/intern/source/pointdensity.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 5f2c6153384..28d8c2388c4 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -65,9 +65,8 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0); dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); - dm->release(dm); - if ( !psys_check_enabled(ob, psys) ){ + if ( !psys_check_enabled(ob, psys)) { psys_render_restore(ob, psys); return; } @@ -76,8 +75,10 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa Mat4Invert(ob->imat, ob->obmat); total_particles = psys->totpart+psys->totchild; + psys->lattice=psys_get_lattice(ob,psys); pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); + if (pd->noise_influence != TEX_PD_NOISE_STATIC) pd->point_data = MEM_mallocN(sizeof(float)*3*total_particles, "point_data"); @@ -112,6 +113,12 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa } BLI_bvhtree_balance(pd->point_tree); + dm->release(dm); + + if(psys->lattice){ + end_latt_deform(); + psys->lattice=0; + } psys_render_restore(ob, psys); } From c62c61a413f90f0af387027f9f94782904c40f17 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 22 Oct 2008 06:10:16 +0000 Subject: [PATCH 43/88] * Fixed a bug in copying (making single user) a point density texture --- source/blender/blenkernel/intern/texture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 6f58e054f69..0dbc0228820 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -895,7 +895,7 @@ PointDensity *BKE_copy_pointdensity(PointDensity *pd) pdn->point_tree = NULL; pdn->point_data = NULL; - return pd; + return pdn; } void BKE_free_pointdensitydata(PointDensity *pd) From 8a6c82684f0e8463bf0a82862929c43b93f18c0b Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 22 Oct 2008 09:26:18 +0000 Subject: [PATCH 44/88] * Did some small tweaks to how density is used with light cache - it makes some very good improvements clearing up artifacts: http://mke3.net/blender/devel/rendering/volumetrics/vol_lc_fixed.jpg --- source/blender/render/intern/source/volumetric.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 4ff6f5aea41..7005f1a6952 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -468,9 +468,6 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi lar= go->lampren; if (lar) { vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density); - - VecMulf(lacol, density); - VecAddf(col, col, lacol); } } @@ -539,7 +536,8 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float vol_get_precached_scattering_nearest(shi, scatter_col, step_mid); } else vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); - + + VecMulf(scatter_col, density); VecAddf(d_radiance, emit_col, scatter_col); /* Lv += Tr * (Lve() + Ld) */ From 3a347c1cafd864f9cce3ba30df8ec45f70a6cbfd Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 23 Oct 2008 01:14:30 +0000 Subject: [PATCH 45/88] Just adding some temporary testing code to help try and find a bug. --- .../blender/render/intern/source/volumetric.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 7005f1a6952..ff1c1ca7b67 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -386,10 +386,14 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE); float shadfac[4]; + if (G.rt==5) printf("s_o_l pre checks col %f %f %f \n", lacol[0], lacol[1], lacol[2]); + if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; if ((lar->lay & shi->lay)==0) return; if (lar->energy == 0.0) return; + if (G.rt==5) printf("s_o_l post checks col %f %f %f \n", lacol[0], lacol[1], lacol[2]); + visifac= lamp_get_visibility(lar, co, lv, &lampdist); if(visifac==0.0f) return; @@ -397,6 +401,8 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * lacol[1] = lar->g; lacol[2] = lar->b; + if (G.rt==5) printf("s_o_l post lacol col %f %f %f \n", lacol[0], lacol[1], lacol[2]); + if(lar->mode & LA_TEXTURE) { shi->osatex= 0; do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE); @@ -404,6 +410,8 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * VecMulf(lacol, visifac*lar->energy); + if (G.rt==5) printf("s_o_l post energy col %f %f %f \n", lacol[0], lacol[1], lacol[2]); + if (ELEM(lar->type, LA_SUN, LA_HEMI)) VECCOPY(lv, lar->vec); VecMulf(lv, -1.0f); @@ -414,6 +422,8 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * if (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED) { Isect is; + if (G.rt==5) printf("s_o_l inside atten col %f %f %f \n", lacol[0], lacol[1], lacol[2]); + /* find minimum of volume bounds, or lamp coord */ if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS, 0)) { float dist = VecLenf(co, hitco); @@ -446,6 +456,8 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * } } + if (G.rt==5) printf("s_o_l post atten col %f %f %f \n", lacol[0], lacol[1], lacol[2]); + vol_get_scattering_fac(shi, &scatter_fac, co, density); VecMulf(lacol, scatter_fac); } @@ -459,16 +471,21 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi float col[3] = {0.f, 0.f, 0.f}; int i=0; + if (G.rt==5) printf("lights count: %d \n", BLI_countlist(&R.lights)); + for(go=R.lights.first; go; go= go->next) { float lacol[3] = {0.f, 0.f, 0.f}; i++; + if (G.rt==5) printf("pre light %d \n", i); lar= go->lampren; if (lar) { + if (G.rt==5) printf("pre vol_shade_one_lamp %d col %f %f %f \n", i, lacol[0], lacol[1], lacol[2]); vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density); VecAddf(col, col, lacol); + if (G.rt==5) printf("post vol_shade_one_lamp %d col %f %f %f \n", i, lacol[0], lacol[1], lacol[2]); } } From ee1a143947ebfc8fe26cf9083fd41c520db3e86b Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 23 Oct 2008 01:40:49 +0000 Subject: [PATCH 46/88] more testing code --- source/blender/render/intern/source/volumetric.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index ff1c1ca7b67..f718dbba703 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -956,9 +956,11 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m } /* don't bother if the point is not inside the volume mesh */ - if (!point_inside_obi(tree, obi, co)) + if (!point_inside_obi(tree, obi, co)) { + if (G.rt==5) printf("not inside mesh \n"); continue; - + } + if (G.rt==5) printf("inside mesh \n"); density = vol_get_density(&shi, co); vol_get_scattering(&shi, scatter_col, co, stepsize, density); From 5fabc7781be98305acda9d8d69042dcba3ac3eef Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 23 Oct 2008 01:52:04 +0000 Subject: [PATCH 47/88] and more debugging --- source/blender/render/intern/source/convertblender.c | 5 ++++- source/blender/render/intern/source/volumetric.c | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 74b03d1082f..d7491d9e3fb 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3094,6 +3094,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) do_autosmooth= 1; if ((ma->material_type == MA_VOLUME) && (ma->vol_shadeflag & MA_VOL_PRECACHESHADING)) { + printf("before add_vol_precache \n"); add_vol_precache(re, obr, ma); } } @@ -4927,8 +4928,10 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) make_sss_tree(re); if(!re->test_break()) - if(re->r.mode & R_RAYTRACE) + if(re->r.mode & R_RAYTRACE) { + printf("before volume_precache \n"); volume_precache(re); + } } if(re->test_break()) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index f718dbba703..dbd241498a9 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -888,11 +888,14 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m R = *re; + if (G.rt==5) printf("before create raytree \n"); /* create a raytree with just the faces of the instanced ObjectRen, * used for checking if the cached point is inside or outside. */ tree = create_raytree_obi(obi, bbmin, bbmax); if (!tree) return; + if (G.rt==5) printf("after create raytree \n"); + /* Need a shadeinput to calculate scattering */ memset(&shi, 0, sizeof(ShadeInput)); shi.depth= 1; @@ -918,6 +921,8 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m return; VecMulf(voxel, 1.0f/res); + if (G.rt==5) printf("before alloc \n"); + 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 @@ -986,6 +991,8 @@ void volume_precache(Render *re) ObjectInstanceRen *obi; VolPrecache *vp; + if (G.rt==5) printf("precache obs: %d \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) From ffe81354f8c7aebaed6168ecb942c86c2da56ce4 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 23 Oct 2008 02:03:54 +0000 Subject: [PATCH 48/88] removed debug stuff --- .../render/intern/source/convertblender.c | 5 +--- .../blender/render/intern/source/volumetric.c | 30 ++----------------- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index d7491d9e3fb..74b03d1082f 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3094,7 +3094,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) do_autosmooth= 1; if ((ma->material_type == MA_VOLUME) && (ma->vol_shadeflag & MA_VOL_PRECACHESHADING)) { - printf("before add_vol_precache \n"); add_vol_precache(re, obr, ma); } } @@ -4928,10 +4927,8 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) make_sss_tree(re); if(!re->test_break()) - if(re->r.mode & R_RAYTRACE) { - printf("before volume_precache \n"); + if(re->r.mode & R_RAYTRACE) volume_precache(re); - } } if(re->test_break()) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index dbd241498a9..7005f1a6952 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -386,14 +386,10 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE); float shadfac[4]; - if (G.rt==5) printf("s_o_l pre checks col %f %f %f \n", lacol[0], lacol[1], lacol[2]); - if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; if ((lar->lay & shi->lay)==0) return; if (lar->energy == 0.0) return; - if (G.rt==5) printf("s_o_l post checks col %f %f %f \n", lacol[0], lacol[1], lacol[2]); - visifac= lamp_get_visibility(lar, co, lv, &lampdist); if(visifac==0.0f) return; @@ -401,8 +397,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * lacol[1] = lar->g; lacol[2] = lar->b; - if (G.rt==5) printf("s_o_l post lacol col %f %f %f \n", lacol[0], lacol[1], lacol[2]); - if(lar->mode & LA_TEXTURE) { shi->osatex= 0; do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE); @@ -410,8 +404,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * VecMulf(lacol, visifac*lar->energy); - if (G.rt==5) printf("s_o_l post energy col %f %f %f \n", lacol[0], lacol[1], lacol[2]); - if (ELEM(lar->type, LA_SUN, LA_HEMI)) VECCOPY(lv, lar->vec); VecMulf(lv, -1.0f); @@ -422,8 +414,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * if (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED) { Isect is; - if (G.rt==5) printf("s_o_l inside atten col %f %f %f \n", lacol[0], lacol[1], lacol[2]); - /* find minimum of volume bounds, or lamp coord */ if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS, 0)) { float dist = VecLenf(co, hitco); @@ -456,8 +446,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * } } - if (G.rt==5) printf("s_o_l post atten col %f %f %f \n", lacol[0], lacol[1], lacol[2]); - vol_get_scattering_fac(shi, &scatter_fac, co, density); VecMulf(lacol, scatter_fac); } @@ -471,21 +459,16 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi float col[3] = {0.f, 0.f, 0.f}; int i=0; - if (G.rt==5) printf("lights count: %d \n", BLI_countlist(&R.lights)); - for(go=R.lights.first; go; go= go->next) { float lacol[3] = {0.f, 0.f, 0.f}; i++; - if (G.rt==5) printf("pre light %d \n", i); lar= go->lampren; if (lar) { - if (G.rt==5) printf("pre vol_shade_one_lamp %d col %f %f %f \n", i, lacol[0], lacol[1], lacol[2]); vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density); VecAddf(col, col, lacol); - if (G.rt==5) printf("post vol_shade_one_lamp %d col %f %f %f \n", i, lacol[0], lacol[1], lacol[2]); } } @@ -888,14 +871,11 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m R = *re; - if (G.rt==5) printf("before create raytree \n"); /* create a raytree with just the faces of the instanced ObjectRen, * used for checking if the cached point is inside or outside. */ tree = create_raytree_obi(obi, bbmin, bbmax); if (!tree) return; - if (G.rt==5) printf("after create raytree \n"); - /* Need a shadeinput to calculate scattering */ memset(&shi, 0, sizeof(ShadeInput)); shi.depth= 1; @@ -921,8 +901,6 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m return; VecMulf(voxel, 1.0f/res); - if (G.rt==5) printf("before alloc \n"); - 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 @@ -961,11 +939,9 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m } /* don't bother if the point is not inside the volume mesh */ - if (!point_inside_obi(tree, obi, co)) { - if (G.rt==5) printf("not inside mesh \n"); + if (!point_inside_obi(tree, obi, co)) continue; - } - if (G.rt==5) printf("inside mesh \n"); + density = vol_get_density(&shi, co); vol_get_scattering(&shi, scatter_col, co, stepsize, density); @@ -991,8 +967,6 @@ void volume_precache(Render *re) ObjectInstanceRen *obi; VolPrecache *vp; - if (G.rt==5) printf("precache obs: %d \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) From ba829e5c36b0e1282f5799720142d464c57c7d54 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 23 Oct 2008 02:15:36 +0000 Subject: [PATCH 49/88] Debugging tests paid off, fixed a ridiculously silly bug that was preventing light cache from working on some people's systems (but went just fine on both my windows pc and mac). I have no idea how the original code even worked at all, it really shouldn't have. But fixed now anyway! Thanks a bunch to Zanqdo for patience in helping me pinpoint this. --- source/blender/render/intern/source/volumetric.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 7005f1a6952..aad8f44441e 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -844,6 +844,8 @@ RayTree *create_raytree_obi(ObjectInstanceRen *obi, float *bbmin, float *bbmax) } RE_ray_tree_done(tree); + + return tree; } /* Precache a volume into a 3D voxel grid. From deea0fa2e70a094cd289ac0083dcbf624453df51 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 23 Oct 2008 03:50:56 +0000 Subject: [PATCH 50/88] * More improvements for light cache Previously when using light cache, there could be artifacts caused when voxel points that were sampled outside the volume object's geometry got interpolated into the rest of the volume. This commit adds a (similar to a dilate) filter pass after creating the light cache, that fills these empty areas with the average of their surrounding voxels. http://mke3.net/blender/devel/rendering/volumetrics/vol_lightcache_filter.jpg --- .../blender/render/intern/source/volumetric.c | 92 ++++++++++++++++--- 1 file changed, 77 insertions(+), 15 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index aad8f44441e..02ebbd83c31 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -75,6 +75,7 @@ static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) return (INPR(is->vec, vlr->n) < 0.0f); } +#if 0 static int vol_frontface_intersect_check(Isect *is, int ob, RayFace *face) { VlakRen *vlr = (VlakRen *)face; @@ -88,6 +89,7 @@ static int vol_always_intersect_check(Isect *is, int ob, RayFace *face) { return 1; } +#endif #define VOL_IS_BACKFACE 1 #define VOL_IS_SAMEMATERIAL 2 @@ -257,12 +259,6 @@ inline float lerp(float t, float v1, float v2) { return (1.f - t) * v1 + t * v2; } -inline float do_lerp(float t, float a, float b) { - if (a > 0.f && b > 0.f) return lerp(t, a, b); - else if (a < 0.f) return b; - else if (b < 0.f) return a; -} - /* trilinear interpolation */ static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co) { @@ -384,7 +380,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * float p; float scatter_fac; float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE); - float shadfac[4]; if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; if ((lar->lay & shi->lay)==0) return; @@ -454,7 +449,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * 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}; int i=0; @@ -530,10 +524,10 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float if ((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) && (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED)) { - if (G.rt==0) - vol_get_precached_scattering(shi, scatter_col, step_mid); - else + if (G.rt==100) vol_get_precached_scattering_nearest(shi, scatter_col, step_mid); + else + vol_get_precached_scattering(shi, scatter_col, step_mid); } else vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); @@ -782,7 +776,6 @@ int intersect_outside_volume(RayTree *tree, Isect *isect, float *offset, int lim 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; @@ -848,6 +841,70 @@ RayTree *create_raytree_obi(ObjectInstanceRen *obi, float *bbmin, float *bbmax) return tree; } +static float get_avg_surrounds(float *cache, int res, int res_2, int res_3, int rgb, int xx, int yy, int zz) +{ + int x, y, z, x_, y_, z_; + int added=0; + float tot=0.0f; + int i; + + for (x=-1; x <= 1; x++) { + x_ = xx+x; + if (x_ >= 0 && x_ <= res-1) { + + for (y=-1; y <= 1; y++) { + y_ = yy+y; + if (y_ >= 0 && y_ <= res-1) { + + for (z=-1; z <= 1; z++) { + z_ = zz+z; + if (z_ >= 0 && z_ <= res-1) { + + i = rgb*res_3 + x_*res_2 + y_*res + z_; + if (cache[i] > 0.0f) { + tot += cache[i]; + added++; + } + + } + } + } + } + } + } + + tot /= added; + + return ((added>0)?tot:0.0f); +} + +/* function to filter the edges of the light cache, where there was no volume originally. + * For each voxel which was originally external to the mesh, it finds the average values of + * the surrounding internal voxels and sets the original external voxel to that average amount. + * Works almost a bit like a 'dilate' filter */ +static void lightcache_filter(float *cache, int res) +{ + int x, y, z, rgb; + int res_2, res_3; + int i; + + res_2 = res*res; + res_3 = res*res*res; + + for (x=0; x < res; x++) { + for (y=0; y < res; y++) { + for (z=0; z < res; z++) { + for (rgb=0; rgb < 3; rgb++) { + i = rgb*res_3 + x*res_2 + y*res + z; + + /* trigger for outside mesh */ + if (cache[i] < 0.5f) cache[i] = get_avg_surrounds(cache, res, res_2, res_3, rgb, x, y, z); + } + } + } + } +} + /* 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. @@ -941,9 +998,12 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m } /* don't bother if the point is not inside the volume mesh */ - if (!point_inside_obi(tree, obi, co)) + if (!point_inside_obi(tree, obi, co)) { + obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; continue; - + } density = vol_get_density(&shi, co); vol_get_scattering(&shi, scatter_col, co, stepsize, density); @@ -959,6 +1019,7 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m tree= NULL; } + lightcache_filter(obi->volume_precache, res); } @@ -990,4 +1051,5 @@ void free_volume_precache(Render *re) } BLI_freelistN(&re->vol_precache_obs); -} \ No newline at end of file +} + From 5fb8debada3db41d2ff40ee9a30e10ddcf35d35e Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 30 Oct 2008 09:26:30 +0000 Subject: [PATCH 51/88] * Added a new, slightly experimental force field type: 'Spin'. It works similarly to Vortex, but it's a more controllable - it doesn't send the particles off accelerating into space, but keeps them spinning around the Z axis of the force field object. This is safe in the branch, but Jahka if you have any feedback, I'd be curious to hear :) --- source/blender/blenkernel/intern/effect.c | 13 +++++++++++++ source/blender/makesdna/DNA_object_force.h | 1 + source/blender/src/buttons_object.c | 4 ++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 122c6c71a6c..8b38fadafb1 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -420,6 +420,19 @@ void do_physical_effector(Object *ob, float *opco, short type, float force_val, VecMulf(mag_vec,force_val*distance*falloff); VecAddf(field,field,mag_vec); + break; + case PFIELD_SPIN: + Projf(temp, velocity, eff_vel); + + Crossf(mag_vec,eff_vel,vec_to_part); + + Normalize(mag_vec); + + VecMulf(mag_vec,force_val*distance*falloff); + VecAddf(mag_vec, mag_vec, temp); + + VecCopyf(velocity, mag_vec); + break; case PFIELD_MAGNET: if(planar) diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index 21c5242a703..2b8a86ac67b 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -210,6 +210,7 @@ typedef struct SoftBody { #define PFIELD_HARMONIC 7 #define PFIELD_CHARGE 8 #define PFIELD_LENNARDJ 9 +#define PFIELD_SPIN 10 /* pd->flag: various settings */ diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index a8ce9da8780..763038adaae 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -3409,8 +3409,8 @@ static void object_panel_fields(Object *ob) sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Curve Guide%%x%d|Magnetic%%x%d|Harmonic%%x%d|Texture%%x%d|Charge%%x%d|Lennard-Jones%%x%d", PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_GUIDE, PFIELD_MAGNET, PFIELD_HARMONIC, PFIELD_TEXTURE, PFIELD_CHARGE, PFIELD_LENNARDJ); else - sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Magnetic%%x%d|Harmonic%%x%d|Texture%%x%d|Charge%%x%d|Lennard-Jones%%x%d", - PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_MAGNET, PFIELD_HARMONIC, PFIELD_TEXTURE, PFIELD_CHARGE, PFIELD_LENNARDJ); + sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Spin%%x%d|Magnetic%%x%d|Harmonic%%x%d|Texture%%x%d|Charge%%x%d|Lennard-Jones%%x%d", + PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_SPIN, PFIELD_MAGNET, PFIELD_HARMONIC, PFIELD_TEXTURE, PFIELD_CHARGE, PFIELD_LENNARDJ); if(pd->forcefield==PFIELD_FORCE) tipstr= "Object center attracts or repels particles (On shared object layers)"; else if(pd->forcefield==PFIELD_WIND) tipstr= "Constant force applied in direction of Object Z axis (On shared object layers)"; From 15579884b1255cba9de7662f72cd21323ad2c701 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 31 Oct 2008 05:29:54 +0000 Subject: [PATCH 52/88] * Added a new turbulence type: Time. It's not entirely well tested, but so far working ok. It's smoother looking than 'velocity' but may need more in depth investigation. --- .../render/intern/source/pointdensity.c | 89 +++++++++++-------- source/blender/render/intern/source/texture.c | 13 ++- source/blender/src/buttons_shading.c | 2 +- 3 files changed, 57 insertions(+), 47 deletions(-) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 28d8c2388c4..483cc96122b 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -35,6 +35,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_global.h" +#include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_particle.h" @@ -56,12 +57,12 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa float partco[3]; float obview[4][4]; - /* init crap */ + /* init everything */ if (!psys || !ob || !pd) return; Mat4MulMat4(obview, re->viewinv, ob->obmat); - /* Just to create a valid rendering context */ + /* Just to create a valid rendering context for particles */ psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0); dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); @@ -79,8 +80,10 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); - if (pd->noise_influence != TEX_PD_NOISE_STATIC) - pd->point_data = MEM_mallocN(sizeof(float)*3*total_particles, "point_data"); + if (pd->noise_influence == TEX_PD_NOISE_VEL) + pd->point_data = MEM_mallocN(sizeof(float)*3*total_particles, "velocity point data"); + else if (pd->noise_influence == TEX_PD_NOISE_TIME) + pd->point_data = MEM_mallocN(sizeof(float)*total_particles, "time point data"); if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; @@ -108,6 +111,8 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa pd->point_data[i*3 + 0] = state.vel[0]; pd->point_data[i*3 + 1] = state.vel[1]; pd->point_data[i*3 + 2] = state.vel[2]; + } else if (pd->noise_influence == TEX_PD_NOISE_TIME) { + pd->point_data[i] = state.time; } } } @@ -256,7 +261,9 @@ typedef struct PointDensityRangeData float *point_data; float *vec; float softness; - short falloff_type; + short falloff_type; + short noise_influence; + float *time; } PointDensityRangeData; void accum_density(void *userdata, int index, float squared_dist) @@ -277,10 +284,14 @@ void accum_density(void *userdata, int index, float squared_dist) density = sqrt(dist); if (pdr->point_data) { - pdr->vec[0] += pdr->point_data[index*3 + 0];// * density; - pdr->vec[1] += pdr->point_data[index*3 + 1];// * density; - pdr->vec[2] += pdr->point_data[index*3 + 2];// * density; - } + if (pdr->noise_influence == TEX_PD_NOISE_VEL) { + pdr->vec[0] += pdr->point_data[index*3 + 0];// * density; + pdr->vec[1] += pdr->point_data[index*3 + 1];// * density; + pdr->vec[2] += pdr->point_data[index*3 + 2];// * density; + } else if (pdr->noise_influence == TEX_PD_NOISE_TIME) { + *pdr->time += pdr->point_data[index]; // * density; + } + } *pdr->density += density; } @@ -288,12 +299,13 @@ void accum_density(void *userdata, int index, float squared_dist) #define MAX_POINTS_NEAREST 25 int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) { - int rv = TEX_INT; + int retval = TEX_INT; PointDensity *pd = tex->pd; PointDensityRangeData pdr; - float density=0.0f; + float density=0.0f, time=0.0f; float vec[3] = {0.0, 0.0, 0.0}; float tv[3]; + float co[3]; float turb, noise_fac; if ((!pd) || (!pd->point_tree)) { @@ -306,54 +318,53 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) pdr.point_data = pd->point_data; pdr.falloff_type = pd->falloff_type; pdr.vec = vec; + pdr.time = &time; pdr.softness = pd->falloff_softness; + pdr.noise_influence = pd->noise_influence; noise_fac = pd->noise_fac * 0.5f; /* better default */ - if (pd->flag & TEX_PD_TURBULENCE) { - VECCOPY(tv, texvec); - - /* find the average speed vectors, for perturbing final density lookup with */ - BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density, &pdr); - - density = 0.0f; - Normalize(vec); + VECCOPY(co, texvec); - turb = BLI_turbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth); + if (pd->flag & TEX_PD_TURBULENCE) { + retval |= TEX_RGB; + if (ELEM(pd->noise_influence, TEX_PD_NOISE_VEL, TEX_PD_NOISE_TIME)) { + /* find the average speed vectors or particle time, + * for perturbing final density lookup with */ + BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); + density = 0.0f; + + if (pd->noise_influence == TEX_PD_NOISE_TIME) + vec[0] = vec[1] = vec[2] = time; + + Normalize(vec); + } + + turb = BLI_turbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth); turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */ - tv[0] = texvec[0] + noise_fac * turb; - tv[1] = texvec[1] + noise_fac * turb; - tv[2] = texvec[2] + noise_fac * turb; - - /* do density lookup with altered coordinates */ - BLI_bvhtree_range_query(pd->point_tree, tv, pd->radius, accum_density, &pdr); + /* now we have an offset coordinate to use for the density lookup */ + co[0] = texvec[0] + noise_fac * turb; + co[1] = texvec[1] + noise_fac * turb; + co[2] = texvec[2] + noise_fac * turb; } - else - BLI_bvhtree_range_query(pd->point_tree, texvec, pd->radius, accum_density, &pdr); + + BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); texres->tin = density; - - - BRICONT; - return TEX_INT; - - /* texres->tr = vec[0]; texres->tg = vec[1]; texres->tb = vec[2]; + texres->ta = density; BRICONTRGB; - texres->ta = 1.0; + return retval; + /* if (texres->nor!=NULL) { texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f; } */ - - //BRICONT; - - //return rv; } diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index dfeb775aca6..972ab4b55a9 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1565,17 +1565,15 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa /* stencil maps on the texture control slider, not texture intensity value */ colfac= mtex->colfac*stencilTin; - tcol[0]=texres.tr; tcol[1]=texres.tg; tcol[2]=texres.tb; - if((rgbnor & TEX_RGB)==0) { tcol[0]= mtex->r; tcol[1]= mtex->g; tcol[2]= mtex->b; + } else { + tcol[0]=texres.tr; + tcol[1]=texres.tg; + tcol[2]=texres.tb; } - else if(mtex->mapto & MAP_ALPHA) { - texres.tin= stencilTin; - } - else texres.tin= texres.ta; if((mapto_flag & MAP_COL) && (mtex->mapto & MAP_COL)) { texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype); @@ -1591,7 +1589,8 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa /* stencil maps on the texture control slider, not texture intensity value */ float varfac= mtex->varfac*stencilTin; - if(rgbnor & TEX_RGB) { + /* convert RGB to intensity if intensity info isn't provided */ + if((rgbnor & TEX_RGB) && !(rgbnor & TEX_INT)) { if(texres.talpha) texres.tin= texres.ta; else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb); } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 04fc9d5314f..dbe3db871b4 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -788,7 +788,7 @@ static void texture_panel_pointdensity(Tex *tex) yco -= YSPACE; if (pd->source == TEX_PD_PSYS) { - uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1", + uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1|Time %x2", X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); } } From 5cdbbe3a925383472c852c0db958d1af11c6413b Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sat, 1 Nov 2008 12:45:19 +0000 Subject: [PATCH 53/88] * Tweaked the spin force field a bit. It worked great for its purpose before, but wasn't playing nice with the other force fields (was overwriting the velocity rather than acting as a force). This version is slightly different, but will work a lot better with other force fields too. --- source/blender/blenkernel/intern/effect.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 8b38fadafb1..4c8394f0eeb 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -422,18 +422,25 @@ void do_physical_effector(Object *ob, float *opco, short type, float force_val, break; case PFIELD_SPIN: - Projf(temp, velocity, eff_vel); + { + float inward[3]; + Projf(temp, velocity, eff_vel); Crossf(mag_vec,eff_vel,vec_to_part); + Crossf(inward, mag_vec, eff_vel); Normalize(mag_vec); + VecSubf(mag_vec, mag_vec, inward); + VecMulf(mag_vec,force_val*distance*falloff); VecAddf(mag_vec, mag_vec, temp); - - VecCopyf(velocity, mag_vec); - + + /* compensate for existing velocity */ + VecSubf(mag_vec, mag_vec, velocity); + VecAddf(field,field,mag_vec); break; + } case PFIELD_MAGNET: if(planar) VecCopyf(temp,eff_vel); From 389588bb4f9f273d5cc1f679e351604859dafc0b Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sun, 2 Nov 2008 23:25:21 +0000 Subject: [PATCH 54/88] Reverted to the previous, more hackish version of the spin field. There has to be a better way of doing this though... jahka? :) --- source/blender/blenkernel/intern/effect.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 4c8394f0eeb..f3d9ea7005a 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -422,25 +422,20 @@ void do_physical_effector(Object *ob, float *opco, short type, float force_val, break; case PFIELD_SPIN: - { - float inward[3]; - Projf(temp, velocity, eff_vel); + Crossf(mag_vec,eff_vel,vec_to_part); - Crossf(inward, mag_vec, eff_vel); Normalize(mag_vec); - VecSubf(mag_vec, mag_vec, inward); - VecMulf(mag_vec,force_val*distance*falloff); VecAddf(mag_vec, mag_vec, temp); - - /* compensate for existing velocity */ - VecSubf(mag_vec, mag_vec, velocity); - VecAddf(field,field,mag_vec); + + VecCopyf(velocity, mag_vec); + //VecSubf(mag_vec, mag_vec, velocity); + //VecAddf(field, field, mag_vec); + break; - } case PFIELD_MAGNET: if(planar) VecCopyf(temp,eff_vel); From f5f0c8fb37eaac8be9efc44b2802fb87fcf85727 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 4 Nov 2008 05:17:02 +0000 Subject: [PATCH 55/88] * Fixed a strange problem with the way textures are interpreted - was causing weird things with point density turbulence on * Reverted the spin field once more.. --- source/blender/blenkernel/intern/effect.c | 15 +++++++++++---- .../blender/render/intern/source/pointdensity.c | 12 +++++++----- source/blender/render/intern/source/texture.c | 8 +++++--- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index f3d9ea7005a..f91a99accef 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -422,20 +422,27 @@ void do_physical_effector(Object *ob, float *opco, short type, float force_val, break; case PFIELD_SPIN: + { + float inward[3]; + Projf(temp, velocity, eff_vel); - Crossf(mag_vec,eff_vel,vec_to_part); + Crossf(inward, mag_vec, eff_vel); Normalize(mag_vec); + Normalize(inward); + VecSubf(mag_vec, mag_vec, inward); VecMulf(mag_vec,force_val*distance*falloff); + VecAddf(mag_vec, mag_vec, temp); - VecCopyf(velocity, mag_vec); - //VecSubf(mag_vec, mag_vec, velocity); - //VecAddf(field, field, mag_vec); + //VecCopyf(velocity, mag_vec); + VecSubf(mag_vec, mag_vec, velocity); + VecAddf(field, field, mag_vec); break; + } case PFIELD_MAGNET: if(planar) VecCopyf(temp,eff_vel); diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 483cc96122b..c80ee767142 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -304,9 +304,9 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) PointDensityRangeData pdr; float density=0.0f, time=0.0f; float vec[3] = {0.0, 0.0, 0.0}; - float tv[3]; float co[3]; float turb, noise_fac; + int num; if ((!pd) || (!pd->point_tree)) { texres->tin = 0.0f; @@ -331,11 +331,13 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) if (ELEM(pd->noise_influence, TEX_PD_NOISE_VEL, TEX_PD_NOISE_TIME)) { /* find the average speed vectors or particle time, * for perturbing final density lookup with */ - BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); + num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); density = 0.0f; - if (pd->noise_influence == TEX_PD_NOISE_TIME) - vec[0] = vec[1] = vec[2] = time; + if (pd->noise_influence == TEX_PD_NOISE_TIME) { + vec[0] = vec[1] = vec[2] = time/num; + //if ((G.rt==1) && (time > 0.f)) printf("time: %f time/num: %f \n", time, time/num); + } Normalize(vec); } @@ -357,7 +359,7 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) texres->tr = vec[0]; texres->tg = vec[1]; texres->tb = vec[2]; - texres->ta = density; + //texres->ta = density; BRICONTRGB; return retval; diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 972ab4b55a9..4fdccc9d892 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1590,9 +1590,11 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa float varfac= mtex->varfac*stencilTin; /* convert RGB to intensity if intensity info isn't provided */ - if((rgbnor & TEX_RGB) && !(rgbnor & TEX_INT)) { - if(texres.talpha) texres.tin= texres.ta; - else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb); + if (rgbnor & TEX_INT) { + if (rgbnor & TEX_RGB) { + if(texres.talpha) texres.tin= texres.ta; + else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb); + } } if((mapto_flag & MAP_EMIT) && (mtex->mapto & MAP_EMIT)) { From a972107b03a3b8b00e1548d99e790612dc9f0ccc Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sun, 9 Nov 2008 01:16:12 +0000 Subject: [PATCH 56/88] Point Density texture: colouring This introduces a few new ways of modifying the intensity and colour output generated by the Point Density texture. Previously, the texture only output intensity information, but now you can map it to colours along a gradient ramp, based on information coming out of a particle system. This lets you do things like colour a particle system based on the individual particles' age - the main reason I need it is to fade particles out over time. The colorband influences both the colour and intensity (using the colorband's alpha value), which makes it easy to map a single point density texture to both intensity values in the Map To panel (such as density or emit) and colour values (such as absorb col or emit col). This is how the below examples are set up, an example .blend file is available here: http://mke3.net/blender/devel/rendering/volumetrics/pd_test4.blend The different modes: * Constant No modifications to intensity or colour (pure white) * Particle Age Maps the color ramp along the particles' lifetimes: http://mke3.net/blender/devel/rendering/volumetrics/pd_mod_partage.mov * Particle Speed Maps the color ramp to the particles' absolute speed per frame (in Blender units). There's an additional scale parameter that you can use to bring this speed into a 0.0 - 1.0 range, if your particles are travelling too faster or slower than 0-1. http://mke3.net/blender/devel/rendering/volumetrics/pd_mod_speed.mov * Velocity -> RGB Outputs the particle XYZ velocity vector as RGB colours. This may be useful for comp work, or maybe in the future things like displacement. Again, there's a scale parameter to control it. http://mke3.net/blender/devel/rendering/volumetrics/pd_mod_velrgb.mov --- source/blender/blenkernel/intern/texture.c | 6 +- source/blender/blenloader/intern/readfile.c | 5 + source/blender/blenloader/intern/writefile.c | 5 +- source/blender/makesdna/DNA_texture_types.h | 21 +- .../render/intern/source/pointdensity.c | 209 ++++++--- source/blender/src/buttons_shading.c | 427 ++++++++++-------- 6 files changed, 424 insertions(+), 249 deletions(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 0dbc0228820..76ef6bdb4e8 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -883,7 +883,9 @@ PointDensity *BKE_add_pointdensity(void) pd->noise_depth = 1; pd->noise_fac = 1.0f; pd->noise_influence = TEX_PD_NOISE_STATIC; - + pd->coba = add_colorband(1); + pd->speed_scale = 1.0f; + pd->totpoints = 0; return pd; } @@ -894,6 +896,7 @@ PointDensity *BKE_copy_pointdensity(PointDensity *pd) pdn= MEM_dupallocN(pd); pdn->point_tree = NULL; pdn->point_data = NULL; + if(pdn->coba) pdn->coba= MEM_dupallocN(pdn->coba); return pdn; } @@ -908,6 +911,7 @@ void BKE_free_pointdensitydata(PointDensity *pd) MEM_freeN(pd->point_data); pd->point_data = NULL; } + if(pd->coba) MEM_freeN(pd->coba); } void BKE_free_pointdensity(PointDensity *pd) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 83a66143ffc..372e9856b98 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2506,6 +2506,7 @@ static void direct_link_texture(FileData *fd, Tex *tex) tex->pd= newdataadr(fd, tex->pd); if(tex->pd) { tex->pd->point_tree = NULL; + tex->pd->coba= newdataadr(fd, tex->pd->coba); } tex->preview = direct_link_preview_image(fd, tex->preview); @@ -7902,6 +7903,10 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } if (tex->pd->falloff_softness < 1.0f) tex->pd->falloff_softness = 2.0f; + if (tex->pd->coba == NULL) { + tex->pd->coba = add_colorband(1); + tex->pd->speed_scale = 1.0f; + } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 7249090dfa7..5c1032045d7 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1335,7 +1335,10 @@ static void write_textures(WriteData *wd, ListBase *idbase) if(tex->plugin) writestruct(wd, DATA, "PluginTex", 1, tex->plugin); if(tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba); if(tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env); - if(tex->pd) writestruct(wd, DATA, "PointDensity", 1, tex->pd); + if(tex->pd) { + writestruct(wd, DATA, "PointDensity", 1, tex->pd); + if(tex->pd->coba) writestruct(wd, DATA, "ColorBand", 1, tex->pd->coba); + } write_previews(wd, tex->preview); } diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index c51311bb621..b057efb4a55 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -134,7 +134,10 @@ typedef struct PointDensity { float falloff_softness; float radius; short source; - short pdpad; + short color_source; + int totpoints; + + int pdpad; struct Object *object; /* for 'Object' or 'Particle system' type - source object */ short psys_cache_space; /* cache points in worldspace, object space, ... ? */ @@ -151,7 +154,9 @@ typedef struct PointDensity { short noise_depth; short noise_influence; float noise_fac; - float pdpad4; + + float speed_scale; + struct ColorBand *coba; /* for time -> color */ } PointDensity; @@ -442,7 +447,17 @@ typedef struct TexMapping { /* noise_influence */ #define TEX_PD_NOISE_STATIC 0 #define TEX_PD_NOISE_VEL 1 -#define TEX_PD_NOISE_TIME 2 +#define TEX_PD_NOISE_AGE 2 +#define TEX_PD_NOISE_TIME 3 + +/* color_source */ +#define TEX_PD_COLOR_CONSTANT 0 +#define TEX_PD_COLOR_PARTAGE 1 +#define TEX_PD_COLOR_PARTSPEED 2 +#define TEX_PD_COLOR_PARTVEL 3 + +#define POINT_DATA_VEL 1 +#define POINT_DATA_LIFE 2 #endif diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index c80ee767142..db3e57e0b79 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -39,6 +39,7 @@ #include "BKE_main.h" #include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_texture.h" #include "DNA_texture_types.h" #include "DNA_particle_types.h" @@ -47,16 +48,59 @@ #include "renderdatabase.h" #include "texture.h" +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + +static int point_data_used(PointDensity *pd) +{ + int pd_bitflag = 0; + + if ((pd->noise_influence == TEX_PD_NOISE_VEL) || (pd->color_source == TEX_PD_COLOR_PARTVEL) || (pd->color_source == TEX_PD_COLOR_PARTSPEED)) + pd_bitflag |= POINT_DATA_VEL; + if ((pd->noise_influence == TEX_PD_NOISE_AGE) || (pd->color_source == TEX_PD_COLOR_PARTAGE)) + pd_bitflag |= POINT_DATA_LIFE; + + return pd_bitflag; +} + + +/* additional data stored alongside the point density BVH, + * accessible by point index number to retrieve other information + * such as particle velocity or lifetime */ +static void make_point_data(PointDensity *pd, int total_particles, int point_data_used) +{ + int data_size = 0; + + if (point_data_used & POINT_DATA_VEL) { + /* store 3 channels of velocity data */ + data_size += 3; + } + if (point_data_used & POINT_DATA_LIFE) { + /* store 1 channel of lifetime data */ + data_size += 1; + } + + if (data_size) + pd->point_data = MEM_mallocN(sizeof(float)*data_size*total_particles, "particle point data"); +} + static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys) { DerivedMesh* dm; ParticleKey state; + ParticleData *pa=NULL; float cfra=bsystem_time(ob,(float)G.scene->r.cfra,0.0); int i, childexists; - int total_particles; + int total_particles, offset=0; + int data_used = point_data_used(pd); float partco[3]; float obview[4][4]; + /* init everything */ if (!psys || !ob || !pd) return; @@ -79,16 +123,14 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa psys->lattice=psys_get_lattice(ob,psys); pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); - - if (pd->noise_influence == TEX_PD_NOISE_VEL) - pd->point_data = MEM_mallocN(sizeof(float)*3*total_particles, "velocity point data"); - else if (pd->noise_influence == TEX_PD_NOISE_TIME) - pd->point_data = MEM_mallocN(sizeof(float)*total_particles, "time point data"); + make_point_data(pd, total_particles, data_used); + pd->totpoints = total_particles; + if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3; if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; - for (i = 0; i < total_particles; i++) { + for (i=0, pa=psys->particles; i < total_particles; i++, pa++) { state.time = cfra; if(psys_get_particle_state(ob, psys, i, &state, 0)) { @@ -107,12 +149,14 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa BLI_bvhtree_insert(pd->point_tree, i, partco, 1); - if (pd->noise_influence == TEX_PD_NOISE_VEL) { + if (data_used & POINT_DATA_VEL) { pd->point_data[i*3 + 0] = state.vel[0]; pd->point_data[i*3 + 1] = state.vel[1]; pd->point_data[i*3 + 2] = state.vel[2]; - } else if (pd->noise_influence == TEX_PD_NOISE_TIME) { - pd->point_data[i] = state.time; + } + if (data_used & POINT_DATA_LIFE) { + float pa_time = (cfra - pa->time)/pa->lifetime; + pd->point_data[offset + i] = pa_time; } } } @@ -140,6 +184,7 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, ObjectRen *o Mat4Invert(obr->ob->imat, obr->ob->obmat); pd->point_tree = BLI_bvhtree_new(obr->totvert, 0.0, 4, 6); + pd->totpoints = obr->totvert; for(i=0; itotvert; i++) { float ver_co[3]; @@ -216,6 +261,7 @@ static void free_pointdensity(Render *re, Tex *tex) MEM_freeN(pd->point_data); pd->point_data = NULL; } + pd->totpoints = 0; } @@ -263,7 +309,9 @@ typedef struct PointDensityRangeData float softness; short falloff_type; short noise_influence; - float *time; + float *age; + int point_data_used; + int offset; } PointDensityRangeData; void accum_density(void *userdata, int index, float squared_dist) @@ -283,83 +331,130 @@ void accum_density(void *userdata, int index, float squared_dist) else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT) density = sqrt(dist); - if (pdr->point_data) { - if (pdr->noise_influence == TEX_PD_NOISE_VEL) { - pdr->vec[0] += pdr->point_data[index*3 + 0];// * density; - pdr->vec[1] += pdr->point_data[index*3 + 1];// * density; - pdr->vec[2] += pdr->point_data[index*3 + 2];// * density; - } else if (pdr->noise_influence == TEX_PD_NOISE_TIME) { - *pdr->time += pdr->point_data[index]; // * density; - } - } + if (pdr->point_data_used & POINT_DATA_VEL) { + pdr->vec[0] += pdr->point_data[index*3 + 0]; //* density; + pdr->vec[1] += pdr->point_data[index*3 + 1]; //* density; + pdr->vec[2] += pdr->point_data[index*3 + 2]; //* density; + } + if (pdr->point_data_used & POINT_DATA_LIFE) { + *pdr->age += pdr->point_data[pdr->offset + index]; // * density; + } *pdr->density += density; } -#define MAX_POINTS_NEAREST 25 + +static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr, float *density, float *vec, float *age) +{ + pdr->squared_radius = pd->radius*pd->radius; + pdr->density = density; + pdr->point_data = pd->point_data; + pdr->falloff_type = pd->falloff_type; + pdr->vec = vec; + pdr->age = age; + pdr->softness = pd->falloff_softness; + pdr->noise_influence = pd->noise_influence; + pdr->point_data_used = point_data_used(pd); + pdr->offset = (pdr->point_data_used & POINT_DATA_VEL)?pd->totpoints*3:0; +} + + int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) { - int retval = TEX_INT; + int retval = TEX_INT+TEX_RGB; PointDensity *pd = tex->pd; PointDensityRangeData pdr; - float density=0.0f, time=0.0f; - float vec[3] = {0.0, 0.0, 0.0}; - float co[3]; + float density=0.0f, age=0.0f, time=0.0f; + float vec[3] = {0.0f, 0.0f, 0.0f}, co[3]; + float col[4]; float turb, noise_fac; - int num; + int num=0; if ((!pd) || (!pd->point_tree)) { texres->tin = 0.0f; return 0; } - pdr.squared_radius = pd->radius*pd->radius; - pdr.density = &density; - pdr.point_data = pd->point_data; - pdr.falloff_type = pd->falloff_type; - pdr.vec = vec; - pdr.time = &time; - pdr.softness = pd->falloff_softness; - pdr.noise_influence = pd->noise_influence; + init_pointdensityrangedata(pd, &pdr, &density, vec, &age); noise_fac = pd->noise_fac * 0.5f; /* better default */ VECCOPY(co, texvec); - if (pd->flag & TEX_PD_TURBULENCE) { - retval |= TEX_RGB; - - if (ELEM(pd->noise_influence, TEX_PD_NOISE_VEL, TEX_PD_NOISE_TIME)) { - /* find the average speed vectors or particle time, - * for perturbing final density lookup with */ - num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); - density = 0.0f; - - if (pd->noise_influence == TEX_PD_NOISE_TIME) { - vec[0] = vec[1] = vec[2] = time/num; - //if ((G.rt==1) && (time > 0.f)) printf("time: %f time/num: %f \n", time, time/num); - } - - Normalize(vec); + if (point_data_used(pd)) { + /* does a BVH lookup to find accumulated density and additional point data * + * stores particle velocity vector in 'vec', and particle lifetime in 'time' */ + num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); + if (num > 0) { + age /= num; + VecMulf(vec, 1.0f/num); } - - turb = BLI_turbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth); + } + + if (pd->flag & TEX_PD_TURBULENCE) { + + if (pd->noise_influence == TEX_PD_NOISE_AGE) { + turb = BLI_turbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth); + } + else if (pd->noise_influence == TEX_PD_NOISE_TIME) { + time = R.cfra / (float)R.r.efra; + turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth); + } + else { + turb = BLI_turbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth); + } + turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */ /* now we have an offset coordinate to use for the density lookup */ co[0] = texvec[0] + noise_fac * turb; co[1] = texvec[1] + noise_fac * turb; co[2] = texvec[2] + noise_fac * turb; + + /* reset and do a new BVH query with the perturbed coordinates */ + density = vec[0] = vec[1] = vec[2] = 0.0f; + num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); + if (num > 0) { + age /= num; + VecMulf(vec, 1.0f/num); + } + } - BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); - texres->tin = density; BRICONT; - texres->tr = vec[0]; - texres->tg = vec[1]; - texres->tb = vec[2]; - //texres->ta = density; + switch (pd->color_source) { + case TEX_PD_COLOR_PARTAGE: + if (pd->coba) { + if (do_colorband(pd->coba, age, col)) { + texres->talpha= 1; + QUATCOPY(&texres->tr, col); + texres->tin *= texres->ta; + } + } + break; + case TEX_PD_COLOR_PARTSPEED: + { + float speed = VecLength(vec) * pd->speed_scale; + + if (pd->coba) { + if (do_colorband(pd->coba, speed, col)) { + texres->talpha= 1; + QUATCOPY(&texres->tr, col); + texres->tin *= texres->ta; + } + } + break; + } + case TEX_PD_COLOR_PARTVEL: + VecMulf(vec, pd->speed_scale); + VECCOPY(&texres->tr, vec); + texres->ta = 1.0f; + break; + default: + texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; + break; + } BRICONTRGB; return retval; diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index dbe3db871b4..b9ea4ebe9d6 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -427,6 +427,115 @@ void do_texbuts(unsigned short event) } } +static void colorband_pos_cb(void *coba_v, void *unused_v) +{ + ColorBand *coba= coba_v; + int a; + + if(coba->tot<2) return; + + for(a=0; atot; a++) coba->data[a].cur= a; + qsort(coba->data, coba->tot, sizeof(CBData), vergcband); + for(a=0; atot; a++) { + if(coba->data[a].cur==coba->cur) { + if(coba->cur!=a) addqueue(curarea->win, REDRAW, 0); /* button cur */ + coba->cur= a; + break; + } + } +} + +static void colorband_add_cb(void *coba_v, void *unused_v) +{ + ColorBand *coba= coba_v; + + if(coba->tot < MAXCOLORBAND-1) coba->tot++; + coba->cur= coba->tot-1; + + colorband_pos_cb(coba, NULL); + BIF_undo_push("Add colorband"); + +} + +static void colorband_del_cb(void *coba_v, void *unused_v) +{ + ColorBand *coba= coba_v; + int a; + + if(coba->tot<2) return; + + for(a=coba->cur; atot; a++) { + coba->data[a]= coba->data[a+1]; + } + if(coba->cur) coba->cur--; + coba->tot--; + + BIF_undo_push("Delete colorband"); + BIF_preview_changed(ID_TE); +} + + +/* offset aligns from bottom, standard width 300, height 115 */ +static void draw_colorband_buts(uiBlock *block, ColorBand *coba, int xoffs, int yoffs, int redraw) +{ + CBData *cbd; + uiBut *bt; + + if(coba==NULL) return; + + bt= uiDefBut(block, BUT, redraw, "Add", 80+xoffs,95+yoffs,37,20, 0, 0, 0, 0, 0, "Adds a new color position to the colorband"); + uiButSetFunc(bt, colorband_add_cb, coba, NULL); + uiDefButS(block, NUM, redraw, "Cur:", 117+xoffs,95+yoffs,81,20, &coba->cur, 0.0, (float)(coba->tot-1), 0, 0, "Displays the active color from the colorband"); + bt= uiDefBut(block, BUT, redraw, "Del", 199+xoffs,95+yoffs,37,20, 0, 0, 0, 0, 0, "Deletes the active position"); + uiButSetFunc(bt, colorband_del_cb, coba, NULL); + uiDefButS(block, ROW, redraw, "E", 236+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 1.0, 0, 0, "Sets interpolation type 'Ease' (quadratic) "); + uiDefButS(block, ROW, redraw, "C", 252+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 3.0, 0, 0, "Sets interpolation type Cardinal"); + uiDefButS(block, ROW, redraw, "L", 268+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 0.0, 0, 0, "Sets interpolation type Linear"); + uiDefButS(block, ROW, redraw, "S", 284+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 2.0, 0, 0, "Sets interpolation type B-Spline"); + + uiDefBut(block, BUT_COLORBAND, redraw, "", xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, ""); + + cbd= coba->data + coba->cur; + + uiBlockBeginAlign(block); + bt= uiDefButF(block, NUM, redraw, "Pos", xoffs,40+yoffs,110,20, &cbd->pos, 0.0, 1.0, 10, 0, "Sets the position of the active color"); + uiButSetFunc(bt, colorband_pos_cb, coba, NULL); + uiDefButF(block, COL, redraw, "", xoffs,20+yoffs,110,20, &(cbd->r), 0, 0, 0, B_BANDCOL, ""); + uiDefButF(block, NUMSLI, redraw, "A ", xoffs,yoffs,110,20, &cbd->a, 0.0, 1.0, 10, 0, "Sets the alpha value for this position"); + + uiBlockBeginAlign(block); + uiDefButF(block, NUMSLI, redraw, "R ", 115+xoffs,40+yoffs,185,20, &cbd->r, 0.0, 1.0, B_BANDCOL, 0, "Sets the red value for the active color"); + uiDefButF(block, NUMSLI, redraw, "G ", 115+xoffs,20+yoffs,185,20, &cbd->g, 0.0, 1.0, B_BANDCOL, 0, "Sets the green value for the active color"); + uiDefButF(block, NUMSLI, redraw, "B ", 115+xoffs,yoffs,185,20, &cbd->b, 0.0, 1.0, B_BANDCOL, 0, "Sets the blue value for the active color"); + uiBlockEndAlign(block); +} + +void draw_colorband_buts_small(uiBlock *block, ColorBand *coba, rctf *butr, int event) +{ + CBData *cbd; + uiBut *bt; + float unit= (butr->xmax-butr->xmin)/14.0f; + float xs= butr->xmin; + + cbd= coba->data + coba->cur; + + uiBlockBeginAlign(block); + uiDefButF(block, COL, event, "", xs,butr->ymin+20.0f,2.0f*unit,20, &(cbd->r), 0, 0, 0, B_BANDCOL, ""); + uiDefButF(block, NUM, event, "A:", xs+2.0f*unit,butr->ymin+20.0f,4.0f*unit,20, &(cbd->a), 0.0f, 1.0f, 10, 2, ""); + bt= uiDefBut(block, BUT, event, "Add", xs+6.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Adds a new color position to the colorband"); + uiButSetFunc(bt, colorband_add_cb, coba, NULL); + bt= uiDefBut(block, BUT, event, "Del", xs+8.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Deletes the active position"); + uiButSetFunc(bt, colorband_del_cb, coba, NULL); + uiDefButS(block, ROW, event, "E", xs+10.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 1.0, 0, 0, "Sets interpolation type 'Ease' (quadratic) "); + uiDefButS(block, ROW, event, "C", xs+11.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 3.0, 0, 0, "Sets interpolation type Cardinal"); + uiDefButS(block, ROW, event, "L", xs+12.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 0.0, 0, 0, "Sets interpolation type Linear"); + uiDefButS(block, ROW, event, "S", xs+13.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 2.0, 0, 0, "Sets interpolation type B-Spline"); + + uiDefBut(block, BUT_COLORBAND, event, "", xs,butr->ymin,butr->xmax-butr->xmin,20.0f, coba, 0, 0, 0, 0, ""); + uiBlockEndAlign(block); + +} + static void texture_panel_plugin(Tex *tex) { uiBlock *block; @@ -731,6 +840,87 @@ static void texture_panel_voronoi(Tex *tex) uiDefButF(block, NUMSLI, B_TEXPRV, "W4: ", 10, 10, 150, 19, &tex->vn_w4, -2.0, 2.0, 10, 0, "Sets feature weight 4"); } +static void texture_panel_pointdensity_modify(Tex *tex) +{ + uiBlock *block; + PointDensity *pd; + short yco=PANEL_YMAX, ymid; + + block= uiNewBlock(&curarea->uiblocks, "texture_panel_pointdensity_modify", UI_EMBOSS, UI_HELV, curarea->win); + if(uiNewPanel(curarea, block, "Modifiers", "Texture", PANELX, PANELY, PANELW, PANELH+20)==0) return; + uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE); + + if(tex->pd==NULL) { + tex->pd= BKE_add_pointdensity(); + } + if(!tex->pd) return; + + if (pd->source == TEX_PD_PSYS) { + uiDefBut(block, LABEL, B_NOP, "Color & Intensity By:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + + uiBlockBeginAlign(block); + uiDefButS(block, MENU, B_TEXREDR_PRV, "Constant %x0|Particle Age %x1|Particle Speed %x2|Velocity -> RGB %x3|", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->color_source, 0.0, 0.0, 0, 0, "Particle Life: Lifetime mapped as 0.0 - 1.0 intensity, Velocity: XYZ velocity mapped as RGB colours"); + if (ELEM(pd->color_source, TEX_PD_COLOR_PARTSPEED, TEX_PD_COLOR_PARTVEL)) { + uiDefButF(block, NUM, B_REDR, "Scale: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->speed_scale), 0.001, 100.0, 10, 2, "Multipler to bring particle speed within an acceptable range"); + } + uiBlockEndAlign(block); + + yco-= 2*BUTH; + + if (ELEM(pd->color_source, TEX_PD_COLOR_PARTAGE, TEX_PD_COLOR_PARTSPEED)) { + rctf rect = {X2CLM1, X2CLM1+BUTW1, yco, yco}; + if (tex->pd->coba == NULL) tex->pd->coba = add_colorband(1); + draw_colorband_buts_small(block, tex->pd->coba, &rect, B_TEXREDR_PRV); + } else { + /* spacer */ + uiDefBut(block, LABEL, B_NOP, "", + X2CLM2, yco, BUTW2, BUTH*2, 0, 0, 0, 0, 0, ""); + } + + if (!ELEM(pd->color_source, TEX_PD_COLOR_PARTSPEED, TEX_PD_COLOR_PARTVEL)) yco -= BUTH; + } + + ymid = yco -= YSPACE; + + uiDefButBitS(block, TOG, TEX_PD_TURBULENCE, B_REDR, "Turbulence", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->flag), 0, 0, 0, 0, "Add directed turbulence to the density estimation"); + + yco -= YSPACE; + + uiBlockBeginAlign(block); + if (pd->flag & TEX_PD_TURBULENCE) { + + uiDefButF(block, NUM, B_REDR, "Size: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_size), 0.001, 100.0, 10, 2, "Turbulence size"); + uiDefButS(block, NUM, B_REDR, "Depth: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_depth), 0.0, 100.0, 10, 2, "Turbulence depth"); + uiDefButF(block, NUM, B_REDR, "Strength: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_fac), 0.001, 100.0, 10, 2, ""); + + uiBlockEndAlign(block); + + yco = ymid - BUTH - YSPACE; + + uiDefBut(block, LABEL, B_NOP, "Noise Influence:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + + if (pd->source == TEX_PD_PSYS) { + uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1|Particle Age %x2|Time %x3", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); + } else if (pd->source == TEX_PD_OBJECT) { + uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Time %x3", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); + } + } else { + uiDefBut(block, LABEL, B_NOP, "", + X2CLM2, yco-=2*BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + } + +} + static void texture_panel_pointdensity(Tex *tex) { uiBlock *block; @@ -738,102 +928,73 @@ static void texture_panel_pointdensity(Tex *tex) short yco=PANEL_YMAX; block= uiNewBlock(&curarea->uiblocks, "texture_panel_pointdensity", UI_EMBOSS, UI_HELV, curarea->win); - if(uiNewPanel(curarea, block, "Point Density", "Texture", PANELX, PANELY, PANELW, PANELH+25)==0) return; + if(uiNewPanel(curarea, block, "Point Density", "Texture", PANELX, PANELY, PANELW, PANELH)==0) return; uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE); if(tex->pd==NULL) { tex->pd= BKE_add_pointdensity(); tex->pd->object= OBACT; } - if(tex->pd) { - pd= tex->pd; + if(!tex->pd) return; + pd= tex->pd; - uiDefBut(block, LABEL, B_NOP, "Density estimation:", - X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, B_NOP, "Density estimation:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - uiDefButF(block, NUM, B_REDR, "Radius: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->radius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); - - yco -= YSPACE; - - uiDefBut(block, LABEL, B_NOP, "Falloff:", - X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiDefButF(block, NUM, B_REDR, "Radius: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->radius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); + + yco -= YSPACE; + + uiDefBut(block, LABEL, B_NOP, "Falloff:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButS(block, MENU, B_REDR, "Standard %x0|Smooth %x1|Soft %x2|Constant %x3|Root %x4", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->falloff_type, 0.0, 0.0, 0, 0, "Falloff type"); + if (pd->falloff_type == TEX_PD_FALLOFF_SOFT) { + uiDefButF(block, NUM, B_REDR, "Softness: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->falloff_softness), 1.0, 1024.0, 10, 2, "The intensity of the falloff"); + } + uiBlockEndAlign(block); + + yco = PANEL_YMAX; + + uiDefBut(block, LABEL, B_NOP, "Point data source:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + + uiDefButS(block, MENU, B_TEXREDR_PRV, "Particle System %x0|Object Vertices %x1", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->source, 0.0, 0.0, 0, 0, "Source"); + + yco -= YSPACE; + + if (pd->source == TEX_PD_PSYS) { uiBlockBeginAlign(block); - uiDefButS(block, MENU, B_REDR, "Standard %x0|Smooth %x1|Soft %x2|Constant %x3|Root %x4", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->falloff_type, 0.0, 0.0, 0, 0, "Falloff type"); - if (pd->falloff_type == TEX_PD_FALLOFF_SOFT) { - uiDefButF(block, NUM, B_REDR, "Softness: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->falloff_softness), 1.0, 1024.0, 10, 2, "The intensity of the falloff"); + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object that has the particle system"); + + if (pd->object && pd->object->particlesystem.first) { + uiDefButS(block, NUM, B_REDR, "PSys:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->psysindex), 1, 10, 10, 3, "Particle system number in the object"); } uiBlockEndAlign(block); yco -= YSPACE; - - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, TEX_PD_TURBULENCE, B_REDR, "Turbulence", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->flag), 0, 0, 0, 0, "Add directed turbulence to the density estimation"); - - if (pd->flag & TEX_PD_TURBULENCE) { - - uiDefButF(block, NUM, B_REDR, "Size: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_size), 0.001, 100.0, 10, 2, "Turbulence size"); - uiDefButS(block, NUM, B_REDR, "Depth: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_depth), 0.0, 100.0, 10, 2, "Turbulence depth"); - uiDefButF(block, NUM, B_REDR, "Strength: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_fac), 0.001, 100.0, 10, 2, ""); - - uiBlockEndAlign(block); - - yco -= YSPACE; - - if (pd->source == TEX_PD_PSYS) { - uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1|Time %x2", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); - } - } - uiBlockEndAlign(block); - - yco = PANEL_YMAX; - - uiDefBut(block, LABEL, B_NOP, "Point data source:", + uiDefBut(block, LABEL, B_NOP, "Cache particles in:", X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - - uiDefButS(block, MENU, B_TEXREDR_PRV, "Particle System %x0|Object Vertices %x1", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->source, 0.0, 0.0, 0, 0, "Source"); + uiDefButS(block, MENU, B_TEXREDR_PRV, "Emit Object Location %x0|Emit Object Space %x1|Global Space %x2", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->psys_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache particles in"); + } + else if (pd->source == TEX_PD_OBJECT) { + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object to render as points"); yco -= YSPACE; - if (pd->source == TEX_PD_PSYS) { - uiBlockBeginAlign(block); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object that has the particle system"); - - if (pd->object && pd->object->particlesystem.first) { - uiDefButS(block, NUM, B_REDR, "PSys:", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->psysindex), 1, 10, 10, 3, "Particle system number in the object"); - } - uiBlockEndAlign(block); - - yco -= YSPACE; - - uiDefBut(block, LABEL, B_NOP, "Cache particles in:", - X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - uiDefButS(block, MENU, B_TEXREDR_PRV, "Emit Object Location %x0|Emit Object Space %x1|Global Space %x2", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->psys_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache particles in"); - - } - else if (pd->source == TEX_PD_OBJECT) { - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object to render as points"); - - yco -= YSPACE; - - uiDefBut(block, LABEL, B_NOP, "Cache vertices in:", - X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - uiDefButS(block, MENU, B_TEXREDR_PRV, "Object Location %x0|Object Space %x1|Global Space %x2", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->ob_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache vertices in"); - } + uiDefBut(block, LABEL, B_NOP, "Cache vertices in:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiDefButS(block, MENU, B_TEXREDR_PRV, "Object Location %x0|Object Space %x1|Global Space %x2", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->ob_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache vertices in"); } } @@ -1514,115 +1675,6 @@ static void texture_panel_envmap(Tex *tex) } } -static void colorband_pos_cb(void *coba_v, void *unused_v) -{ - ColorBand *coba= coba_v; - int a; - - if(coba->tot<2) return; - - for(a=0; atot; a++) coba->data[a].cur= a; - qsort(coba->data, coba->tot, sizeof(CBData), vergcband); - for(a=0; atot; a++) { - if(coba->data[a].cur==coba->cur) { - if(coba->cur!=a) addqueue(curarea->win, REDRAW, 0); /* button cur */ - coba->cur= a; - break; - } - } -} - -static void colorband_add_cb(void *coba_v, void *unused_v) -{ - ColorBand *coba= coba_v; - - if(coba->tot < MAXCOLORBAND-1) coba->tot++; - coba->cur= coba->tot-1; - - colorband_pos_cb(coba, NULL); - BIF_undo_push("Add colorband"); - -} - -static void colorband_del_cb(void *coba_v, void *unused_v) -{ - ColorBand *coba= coba_v; - int a; - - if(coba->tot<2) return; - - for(a=coba->cur; atot; a++) { - coba->data[a]= coba->data[a+1]; - } - if(coba->cur) coba->cur--; - coba->tot--; - - BIF_undo_push("Delete colorband"); - BIF_preview_changed(ID_TE); -} - - -/* offset aligns from bottom, standard width 300, height 115 */ -static void draw_colorband_buts(uiBlock *block, ColorBand *coba, int xoffs, int yoffs, int redraw) -{ - CBData *cbd; - uiBut *bt; - - if(coba==NULL) return; - - bt= uiDefBut(block, BUT, redraw, "Add", 80+xoffs,95+yoffs,37,20, 0, 0, 0, 0, 0, "Adds a new color position to the colorband"); - uiButSetFunc(bt, colorband_add_cb, coba, NULL); - uiDefButS(block, NUM, redraw, "Cur:", 117+xoffs,95+yoffs,81,20, &coba->cur, 0.0, (float)(coba->tot-1), 0, 0, "Displays the active color from the colorband"); - bt= uiDefBut(block, BUT, redraw, "Del", 199+xoffs,95+yoffs,37,20, 0, 0, 0, 0, 0, "Deletes the active position"); - uiButSetFunc(bt, colorband_del_cb, coba, NULL); - uiDefButS(block, ROW, redraw, "E", 236+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 1.0, 0, 0, "Sets interpolation type 'Ease' (quadratic) "); - uiDefButS(block, ROW, redraw, "C", 252+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 3.0, 0, 0, "Sets interpolation type Cardinal"); - uiDefButS(block, ROW, redraw, "L", 268+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 0.0, 0, 0, "Sets interpolation type Linear"); - uiDefButS(block, ROW, redraw, "S", 284+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 2.0, 0, 0, "Sets interpolation type B-Spline"); - - uiDefBut(block, BUT_COLORBAND, redraw, "", xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, ""); - - cbd= coba->data + coba->cur; - - uiBlockBeginAlign(block); - bt= uiDefButF(block, NUM, redraw, "Pos", xoffs,40+yoffs,110,20, &cbd->pos, 0.0, 1.0, 10, 0, "Sets the position of the active color"); - uiButSetFunc(bt, colorband_pos_cb, coba, NULL); - uiDefButF(block, COL, redraw, "", xoffs,20+yoffs,110,20, &(cbd->r), 0, 0, 0, B_BANDCOL, ""); - uiDefButF(block, NUMSLI, redraw, "A ", xoffs,yoffs,110,20, &cbd->a, 0.0, 1.0, 10, 0, "Sets the alpha value for this position"); - - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, redraw, "R ", 115+xoffs,40+yoffs,185,20, &cbd->r, 0.0, 1.0, B_BANDCOL, 0, "Sets the red value for the active color"); - uiDefButF(block, NUMSLI, redraw, "G ", 115+xoffs,20+yoffs,185,20, &cbd->g, 0.0, 1.0, B_BANDCOL, 0, "Sets the green value for the active color"); - uiDefButF(block, NUMSLI, redraw, "B ", 115+xoffs,yoffs,185,20, &cbd->b, 0.0, 1.0, B_BANDCOL, 0, "Sets the blue value for the active color"); - uiBlockEndAlign(block); -} - -void draw_colorband_buts_small(uiBlock *block, ColorBand *coba, rctf *butr, int event) -{ - CBData *cbd; - uiBut *bt; - float unit= (butr->xmax-butr->xmin)/14.0f; - float xs= butr->xmin; - - cbd= coba->data + coba->cur; - - uiBlockBeginAlign(block); - uiDefButF(block, COL, event, "", xs,butr->ymin+20.0f,2.0f*unit,20, &(cbd->r), 0, 0, 0, B_BANDCOL, ""); - uiDefButF(block, NUM, event, "A:", xs+2.0f*unit,butr->ymin+20.0f,4.0f*unit,20, &(cbd->a), 0.0f, 1.0f, 10, 2, ""); - bt= uiDefBut(block, BUT, event, "Add", xs+6.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Adds a new color position to the colorband"); - uiButSetFunc(bt, colorband_add_cb, coba, NULL); - bt= uiDefBut(block, BUT, event, "Del", xs+8.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Deletes the active position"); - uiButSetFunc(bt, colorband_del_cb, coba, NULL); - uiDefButS(block, ROW, event, "E", xs+10.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 1.0, 0, 0, "Sets interpolation type 'Ease' (quadratic) "); - uiDefButS(block, ROW, event, "C", xs+11.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 3.0, 0, 0, "Sets interpolation type Cardinal"); - uiDefButS(block, ROW, event, "L", xs+12.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 0.0, 0, 0, "Sets interpolation type Linear"); - uiDefButS(block, ROW, event, "S", xs+13.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 2.0, 0, 0, "Sets interpolation type B-Spline"); - - uiDefBut(block, BUT_COLORBAND, event, "", xs,butr->ymin,butr->xmax-butr->xmin,20.0f, coba, 0, 0, 0, 0, ""); - uiBlockEndAlign(block); - -} - static void texture_panel_colors(Tex *tex) { uiBlock *block; @@ -4833,6 +4885,7 @@ void texture_panels() break; case TEX_POINTDENSITY: texture_panel_pointdensity(tex); + texture_panel_pointdensity_modify(tex); break; } } From 3b2f996c25e911fb6497fd45b3b4a5ab5e5609ac Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 10 Nov 2008 00:14:35 +0000 Subject: [PATCH 57/88] Point Density * Fixed a stupid crash caused by last commit that worked fine on the mac (but never should have...) * Fix for using child particles with the new particle age color options --- source/blender/blenkernel/intern/texture.c | 2 + .../render/intern/source/pointdensity.c | 14 +- source/blender/src/buttons_shading.c | 162 +++++++++--------- 3 files changed, 94 insertions(+), 84 deletions(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 76ef6bdb4e8..1bb4ef3eeff 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -873,6 +873,7 @@ PointDensity *BKE_add_pointdensity(void) PointDensity *pd; pd= MEM_callocN(sizeof(PointDensity), "pointdensity"); + pd->flag = 0; pd->radius = 0.3f; pd->falloff_type = TEX_PD_FALLOFF_STD; pd->falloff_softness = 2.0; @@ -886,6 +887,7 @@ PointDensity *BKE_add_pointdensity(void) pd->coba = add_colorband(1); pd->speed_scale = 1.0f; pd->totpoints = 0; + pd->coba = add_colorband(1); return pd; } diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index db3e57e0b79..af2a7edae06 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -71,7 +71,7 @@ static int point_data_used(PointDensity *pd) /* additional data stored alongside the point density BVH, * accessible by point index number to retrieve other information * such as particle velocity or lifetime */ -static void make_point_data(PointDensity *pd, int total_particles, int point_data_used) +static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used) { int data_size = 0; @@ -123,7 +123,7 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa psys->lattice=psys_get_lattice(ob,psys); pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); - make_point_data(pd, total_particles, data_used); + alloc_point_data(pd, total_particles, data_used); pd->totpoints = total_particles; if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3; @@ -155,7 +155,15 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa pd->point_data[i*3 + 2] = state.vel[2]; } if (data_used & POINT_DATA_LIFE) { - float pa_time = (cfra - pa->time)/pa->lifetime; + float pa_time; + + if (i < psys->totpart) { + pa_time = (cfra - pa->time)/pa->lifetime; + } else { + ChildParticle *cpa= (psys->child + i) - psys->totpart; + pa_time = psys_get_child_time(psys, cpa, cfra); + } + pd->point_data[offset + i] = pa_time; } } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index b9ea4ebe9d6..5ed39764af0 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -840,87 +840,6 @@ static void texture_panel_voronoi(Tex *tex) uiDefButF(block, NUMSLI, B_TEXPRV, "W4: ", 10, 10, 150, 19, &tex->vn_w4, -2.0, 2.0, 10, 0, "Sets feature weight 4"); } -static void texture_panel_pointdensity_modify(Tex *tex) -{ - uiBlock *block; - PointDensity *pd; - short yco=PANEL_YMAX, ymid; - - block= uiNewBlock(&curarea->uiblocks, "texture_panel_pointdensity_modify", UI_EMBOSS, UI_HELV, curarea->win); - if(uiNewPanel(curarea, block, "Modifiers", "Texture", PANELX, PANELY, PANELW, PANELH+20)==0) return; - uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE); - - if(tex->pd==NULL) { - tex->pd= BKE_add_pointdensity(); - } - if(!tex->pd) return; - - if (pd->source == TEX_PD_PSYS) { - uiDefBut(block, LABEL, B_NOP, "Color & Intensity By:", - X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - - uiBlockBeginAlign(block); - uiDefButS(block, MENU, B_TEXREDR_PRV, "Constant %x0|Particle Age %x1|Particle Speed %x2|Velocity -> RGB %x3|", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->color_source, 0.0, 0.0, 0, 0, "Particle Life: Lifetime mapped as 0.0 - 1.0 intensity, Velocity: XYZ velocity mapped as RGB colours"); - if (ELEM(pd->color_source, TEX_PD_COLOR_PARTSPEED, TEX_PD_COLOR_PARTVEL)) { - uiDefButF(block, NUM, B_REDR, "Scale: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->speed_scale), 0.001, 100.0, 10, 2, "Multipler to bring particle speed within an acceptable range"); - } - uiBlockEndAlign(block); - - yco-= 2*BUTH; - - if (ELEM(pd->color_source, TEX_PD_COLOR_PARTAGE, TEX_PD_COLOR_PARTSPEED)) { - rctf rect = {X2CLM1, X2CLM1+BUTW1, yco, yco}; - if (tex->pd->coba == NULL) tex->pd->coba = add_colorband(1); - draw_colorband_buts_small(block, tex->pd->coba, &rect, B_TEXREDR_PRV); - } else { - /* spacer */ - uiDefBut(block, LABEL, B_NOP, "", - X2CLM2, yco, BUTW2, BUTH*2, 0, 0, 0, 0, 0, ""); - } - - if (!ELEM(pd->color_source, TEX_PD_COLOR_PARTSPEED, TEX_PD_COLOR_PARTVEL)) yco -= BUTH; - } - - ymid = yco -= YSPACE; - - uiDefButBitS(block, TOG, TEX_PD_TURBULENCE, B_REDR, "Turbulence", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->flag), 0, 0, 0, 0, "Add directed turbulence to the density estimation"); - - yco -= YSPACE; - - uiBlockBeginAlign(block); - if (pd->flag & TEX_PD_TURBULENCE) { - - uiDefButF(block, NUM, B_REDR, "Size: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_size), 0.001, 100.0, 10, 2, "Turbulence size"); - uiDefButS(block, NUM, B_REDR, "Depth: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_depth), 0.0, 100.0, 10, 2, "Turbulence depth"); - uiDefButF(block, NUM, B_REDR, "Strength: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_fac), 0.001, 100.0, 10, 2, ""); - - uiBlockEndAlign(block); - - yco = ymid - BUTH - YSPACE; - - uiDefBut(block, LABEL, B_NOP, "Noise Influence:", - X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - - if (pd->source == TEX_PD_PSYS) { - uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1|Particle Age %x2|Time %x3", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); - } else if (pd->source == TEX_PD_OBJECT) { - uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Time %x3", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); - } - } else { - uiDefBut(block, LABEL, B_NOP, "", - X2CLM2, yco-=2*BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - } - -} - static void texture_panel_pointdensity(Tex *tex) { uiBlock *block; @@ -999,6 +918,87 @@ static void texture_panel_pointdensity(Tex *tex) } +static void texture_panel_pointdensity_modify(Tex *tex) +{ + uiBlock *block; + PointDensity *pd; + short yco=PANEL_YMAX, ymid; + + block= uiNewBlock(&curarea->uiblocks, "texture_panel_pointdensity_modify", UI_EMBOSS, UI_HELV, curarea->win); + if(uiNewPanel(curarea, block, "Modifiers", "Texture", PANELX, PANELY, PANELW, PANELH+20)==0) return; + uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE); + + if(tex->pd==NULL) { + tex->pd= BKE_add_pointdensity(); + } + if(!tex->pd) return; + pd= tex->pd; + + if (pd->source == TEX_PD_PSYS) { + uiDefBut(block, LABEL, B_NOP, "Color & Intensity By:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + + uiBlockBeginAlign(block); + uiDefButS(block, MENU, B_TEXREDR_PRV, "Constant %x0|Particle Age %x1|Particle Speed %x2|Velocity -> RGB %x3|", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->color_source, 0.0, 0.0, 0, 0, "Particle Life: Lifetime mapped as 0.0 - 1.0 intensity, Velocity: XYZ velocity mapped as RGB colours"); + if (ELEM(pd->color_source, TEX_PD_COLOR_PARTSPEED, TEX_PD_COLOR_PARTVEL)) { + uiDefButF(block, NUM, B_REDR, "Scale: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->speed_scale), 0.001, 100.0, 10, 2, "Multipler to bring particle speed within an acceptable range"); + } + uiBlockEndAlign(block); + + yco-= 2*BUTH; + + + if (ELEM(pd->color_source, TEX_PD_COLOR_PARTAGE, TEX_PD_COLOR_PARTSPEED)) { + rctf rect = {X2CLM1, X2CLM1+BUTW1, yco, yco}; + if (pd->coba == NULL) pd->coba = add_colorband(1); + draw_colorband_buts_small(block, pd->coba, &rect, B_TEXREDR_PRV); + } else { + uiDefBut(block, LABEL, B_NOP, "", + X2CLM2, yco, BUTW2, BUTH*2, 0, 0, 0, 0, 0, ""); + } + + if (!ELEM(pd->color_source, TEX_PD_COLOR_PARTSPEED, TEX_PD_COLOR_PARTVEL)) yco -= BUTH; + } + + ymid = yco -= YSPACE; + + uiDefButBitS(block, TOG, TEX_PD_TURBULENCE, B_REDR, "Turbulence", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->flag), 0, 0, 0, 0, "Add directed turbulence to the density estimation"); + + yco -= YSPACE; + + uiBlockBeginAlign(block); + if (pd->flag & TEX_PD_TURBULENCE) { + + uiDefButF(block, NUM, B_REDR, "Size: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_size), 0.001, 100.0, 10, 2, "Turbulence size"); + uiDefButS(block, NUM, B_REDR, "Depth: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_depth), 0.0, 100.0, 10, 2, "Turbulence depth"); + uiDefButF(block, NUM, B_REDR, "Strength: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_fac), 0.001, 100.0, 10, 2, ""); + + uiBlockEndAlign(block); + + yco = ymid - BUTH - YSPACE; + + uiDefBut(block, LABEL, B_NOP, "Noise Influence:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + + if (pd->source == TEX_PD_PSYS) { + uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1|Particle Age %x2|Time %x3", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); + } else if (pd->source == TEX_PD_OBJECT) { + uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Time %x3", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence"); + } + } else { + uiDefBut(block, LABEL, B_NOP, "", + X2CLM2, yco-=2*BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + } + +} static char *layer_menu(RenderResult *rr, short *curlay) { From bf747a30af000c024ecb9e98a295a54dd286d0b3 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 11 Nov 2008 23:24:10 +0000 Subject: [PATCH 58/88] * Added a button to the volume material controls 'Alpha' to generate an alpha channel based on the volume's transmission properties, allowing you to use it in comp etc. I'd rather not have this button at all, and make it just work properly by default, however it causes problems with overlapping volumes when 'premul' is on (stoopid thing..) so for the time being, there's the button. I'll try and fix this up later on when I have more time. --- source/blender/makesdna/DNA_material_types.h | 1 + source/blender/render/intern/source/volumetric.c | 16 ++++++++++++---- source/blender/src/buttons_shading.c | 6 ++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 66f23c7905d..f332537e9a8 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -359,6 +359,7 @@ typedef struct Material { #define MA_VOL_ATTENUATED 2 #define MA_VOL_RECVSHADOW 4 #define MA_VOL_PRECACHESHADING 8 +#define MA_VOL_USEALPHA 16 /* vol_phasefunc_type */ #define MA_VOL_PH_ISOTROPIC 0 diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 02ebbd83c31..52d23de45ff 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -656,8 +656,12 @@ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) shr->combined[1] = col[1]; shr->combined[2] = col[2]; - //if (col[3] > 1.0f) - col[3] = 1.0f; + if (shi->mat->vol_shadeflag & MA_VOL_USEALPHA) { + if (col[3] > 1.0f) + col[3] = 1.0f; + } + else + col[3] = 1.0f; shr->combined[3] = col[3]; shr->alpha = col[3]; @@ -683,8 +687,12 @@ void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr) shr->combined[1] = col[1]; shr->combined[2] = col[2]; - //if (col[3] > 1.0f) - col[3] = 1.0f; + if (shi->mat->vol_shadeflag & MA_VOL_USEALPHA) { + if (col[3] > 1.0f) + col[3] = 1.0f; + } + else + col[3] = 1.0f; shr->combined[3] = col[3]; shr->alpha = col[3]; diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 5ed39764af0..3e5f5305033 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4447,6 +4447,12 @@ static void material_panel_material_volume(Material *ma) uiBlockEndAlign(block); } + yco -= YSPACE; + + uiDefButBitS(block, TOG, MA_VOL_USEALPHA, B_MATPRV, "Alpha", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shadeflag), 0, 0, 0, 0, "Generate an alpha channel (causes problems with Premul)"); + + /*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"); */ From a2da0911a6da23dc420f7a25fc258ae048913b7a Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 13 Nov 2008 10:43:02 +0000 Subject: [PATCH 59/88] * Fixed a float -> int conversion rounding error in volume rendering, which was manifesting in little dark dots --- source/blender/render/intern/source/volumetric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 52d23de45ff..1c0828d868c 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -335,7 +335,7 @@ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, f vol_get_absorption(shi, absorb_col, co); dist = VecLenf(co, endco); - nsteps = (int)ceil(dist / stepsize); + nsteps = (int)((dist / stepsize) + 0.5); /* trigger for recalculating density */ if (density < -0.001f) density = vol_get_density(shi, co); @@ -491,7 +491,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float tr[0] = tr[1] = tr[2] = 1.0f; /* ray marching */ - nsteps = (int)ceil(VecLenf(co, endco) / stepsize); + nsteps = (int)((VecLenf(co, endco) / stepsize) + 0.5); VecSubf(vec, endco, co); VECCOPY(stepvec, vec); From 8d5c14b20d61d990691ccaecefc3b5cbce449ef5 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 14 Nov 2008 06:01:06 +0000 Subject: [PATCH 60/88] Volume rendering: * Use a slightly better (but still not exact) approximation for the view vector when pre-shading the light cache. This still doesn't give exactly the same results as non-light-cache shading, but it's better. Will investigate getting a better view vector when there's more time - or if anyone has a simple formula to derive shi->view from shi->co that would be great to hear about too :) --- source/blender/render/intern/source/volumetric.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 1c0828d868c..83c25ad68c6 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -984,7 +984,7 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m for (z=0; z < res; z++) { co[2] = bbmin[2] + (voxel[2] * z); - + time= PIL_check_seconds_timer(); i++; @@ -1012,6 +1012,9 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; continue; } + + VECCOPY(shi.view, co); + Normalize(shi.view); density = vol_get_density(&shi, co); vol_get_scattering(&shi, scatter_col, co, stepsize, density); From e6a903c06e24ce9afd7b6e3de70e36fa450171d6 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sat, 15 Nov 2008 04:16:46 +0000 Subject: [PATCH 61/88] cleaned some code and split volume precaching into a new file --- .../render/intern/include/volume_precache.h | 30 + .../render/intern/include/volumetric.h | 17 +- .../render/intern/source/convertblender.c | 1 + .../render/intern/source/volume_precache.c | 356 +++++++++++ .../blender/render/intern/source/volumetric.c | 566 ++++-------------- 5 files changed, 509 insertions(+), 461 deletions(-) create mode 100644 source/blender/render/intern/include/volume_precache.h create mode 100644 source/blender/render/intern/source/volume_precache.c diff --git a/source/blender/render/intern/include/volume_precache.h b/source/blender/render/intern/include/volume_precache.h new file mode 100644 index 00000000000..7a719840f48 --- /dev/null +++ b/source/blender/render/intern/include/volume_precache.h @@ -0,0 +1,30 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Matt Ebb. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +void volume_precache(Render *re); +void free_volume_precache(Render *re); \ No newline at end of file diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h index fb87035145f..a69238f54b3 100644 --- a/source/blender/render/intern/include/volumetric.h +++ b/source/blender/render/intern/include/volumetric.h @@ -21,12 +21,23 @@ * * The Original Code is: all of this file. * - * Contributor(s): Farsthary (Raul FHernandez), Matt Ebb. + * Contributor(s): Matt Ebb. * * ***** END GPL LICENSE BLOCK ***** */ +float vol_get_stepsize(struct ShadeInput *shi, int context); +float vol_get_density(struct ShadeInput *shi, float *co); +void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsize, float density); + void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr); void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is); -void volume_precache(Render *re); -void free_volume_precache(Render *re); \ No newline at end of file + +#define STEPSIZE_VIEW 0 +#define STEPSIZE_SHADE 1 + +#define VOL_IS_BACKFACE 1 +#define VOL_IS_SAMEMATERIAL 2 + +#define VOL_BOUNDS_DEPTH 0 +#define VOL_BOUNDS_SS 1 \ No newline at end of file diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 45e934e5273..b9b151ab9fd 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -113,6 +113,7 @@ #include "shading.h" #include "strand.h" #include "texture.h" +#include "volume_precache.h" #include "sss.h" #include "strand.h" #include "zbuf.h" diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c new file mode 100644 index 00000000000..5b43aa8f935 --- /dev/null +++ b/source/blender/render/intern/source/volume_precache.c @@ -0,0 +1,356 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Matt Ebb. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "PIL_time.h" + +#include "RE_shader_ext.h" +#include "RE_raytrace.h" + +#include "DNA_material_types.h" + +#include "render_types.h" +#include "renderdatabase.h" +#include "volumetric.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + +/* 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); + 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; vobr->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); + + return tree; +} + +static float get_avg_surrounds(float *cache, int res, int res_2, int res_3, int rgb, int xx, int yy, int zz) +{ + int x, y, z, x_, y_, z_; + int added=0; + float tot=0.0f; + int i; + + for (x=-1; x <= 1; x++) { + x_ = xx+x; + if (x_ >= 0 && x_ <= res-1) { + + for (y=-1; y <= 1; y++) { + y_ = yy+y; + if (y_ >= 0 && y_ <= res-1) { + + for (z=-1; z <= 1; z++) { + z_ = zz+z; + if (z_ >= 0 && z_ <= res-1) { + + i = rgb*res_3 + x_*res_2 + y_*res + z_; + if (cache[i] > 0.0f) { + tot += cache[i]; + added++; + } + + } + } + } + } + } + } + + tot /= added; + + return ((added>0)?tot:0.0f); +} + +/* function to filter the edges of the light cache, where there was no volume originally. + * For each voxel which was originally external to the mesh, it finds the average values of + * the surrounding internal voxels and sets the original external voxel to that average amount. + * Works almost a bit like a 'dilate' filter */ +static void lightcache_filter(float *cache, int res) +{ + int x, y, z, rgb; + int res_2, res_3; + int i; + + res_2 = res*res; + res_3 = res*res*res; + + for (x=0; x < res; x++) { + for (y=0; y < res; y++) { + for (z=0; z < res; z++) { + for (rgb=0; rgb < 3; rgb++) { + i = rgb*res_3 + x*res_2 + y*res + z; + + /* trigger for outside mesh */ + if (cache[i] < 0.5f) cache[i] = get_avg_surrounds(cache, res, res_2, res_3, rgb, x, y, z); + } + } + } + } +} + +/* 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, res_3f; + int res_2, res_3; + + float i = 1.0f; + double time, lasttime= PIL_check_seconds_timer(); + const int res = ma->vol_precache_resolution; + RayTree *tree; + + R = *re; + + /* create a raytree with just the faces of the instanced ObjectRen, + * 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 */ + memset(&shi, 0, sizeof(ShadeInput)); + shi.depth= 1; + shi.mask= 1; + shi.mat = ma; + shi.vlr = NULL; + memcpy(&shi.r, &shi.mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h + shi.har= shi.mat->har; + shi.obi= obi; + shi.obr= obi->obr; + shi.lay = re->scene->lay; + VECCOPY(shi.view, view); + + stepsize = vol_get_stepsize(&shi, STEPSIZE_VIEW); + + resf = (float)res; + res_2 = res*res; + res_3 = res*res*res; + res_3f = (float)res_3; + + VecSubf(voxel, bbmax, bbmin); + if ((voxel[0] < FLT_EPSILON) || (voxel[1] < FLT_EPSILON) || (voxel[2] < FLT_EPSILON)) + return; + VecMulf(voxel, 1.0f/res); + + 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); + + for (y=0; y < res; y++) { + co[1] = bbmin[1] + (voxel[1] * y); + + for (z=0; z < res; z++) { + co[2] = bbmin[2] + (voxel[2] * z); + + time= PIL_check_seconds_timer(); + i++; + + /* display progress every second */ + if(re->test_break()) { + if(tree) { + RE_ray_tree_free(tree); + tree= NULL; + } + return; + } + if(time-lasttime>1.0f) { + char str[64]; + 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; + } + + /* don't bother if the point is not inside the volume mesh */ + if (!point_inside_obi(tree, obi, co)) { + obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; + 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; + } + + lightcache_filter(obi->volume_precache, res); + +} + +/* 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; + + 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]); + } + } + + re->i.infostr= NULL; + re->stats_draw(&re->i); +} + +void free_volume_precache(Render *re) +{ + ObjectInstanceRen *obi; + + for(obi= re->instancetable.first; obi; obi= obi->next) { + if (obi->volume_precache) + MEM_freeN(obi->volume_precache); + } + + BLI_freelistN(&re->vol_precache_obs); +} diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 83c25ad68c6..86705232b1e 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -27,8 +27,8 @@ */ #include -#include #include +#include #include #include "MEM_guardedalloc.h" @@ -36,9 +36,6 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_rand.h" -#include "BLI_kdtree.h" - -#include "PIL_time.h" #include "RE_shader_ext.h" #include "RE_raytrace.h" @@ -48,13 +45,12 @@ #include "DNA_lamp_types.h" #include "BKE_global.h" -#include "BKE_main.h" #include "render_types.h" -#include "renderdatabase.h" #include "pixelshading.h" #include "shading.h" #include "texture.h" +#include "volumetric.h" #if defined( _MSC_VER ) && !defined( __cplusplus ) # define inline __inline @@ -75,29 +71,6 @@ static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) return (INPR(is->vec, vlr->n) < 0.0f); } -#if 0 -static int vol_frontface_intersect_check(Isect *is, int ob, RayFace *face) -{ - VlakRen *vlr = (VlakRen *)face; - - /* only consider faces away, so overlapping layers - * of foward facing geometry don't cause the ray to stop */ - return (INPR(is->vec, vlr->n) > 0.0f); -} - -static int vol_always_intersect_check(Isect *is, int ob, RayFace *face) -{ - return 1; -} -#endif - -#define VOL_IS_BACKFACE 1 -#define VOL_IS_SAMEMATERIAL 2 - - -#define VOL_BOUNDS_DEPTH 0 -#define VOL_BOUNDS_SS 1 - /* 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) { @@ -139,8 +112,6 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, } } -#define STEPSIZE_VIEW 0 -#define STEPSIZE_SHADE 1 float vol_get_stepsize(struct ShadeInput *shi, int context) { if (shi->mat->vol_stepsize_type == MA_VOL_STEP_RANDOMIZED) { @@ -152,8 +123,7 @@ float vol_get_stepsize(struct ShadeInput *shi, int context) else if (context == STEPSIZE_SHADE) return shi->mat->vol_shade_stepsize * rnd; } - else { - // MA_VOL_STEP_CONSTANT + else { // MA_VOL_STEP_CONSTANT if (context == STEPSIZE_VIEW) return shi->mat->vol_stepsize; @@ -164,6 +134,81 @@ float vol_get_stepsize(struct ShadeInput *shi, int context) return shi->mat->vol_stepsize; } +/* SHADING */ + +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(z, 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; + } +} + +/* no interpolation */ +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]; +} + float vol_get_density(struct ShadeInput *shi, float *co) { float density = shi->mat->alpha; @@ -245,82 +290,6 @@ 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(z, 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; - } -} - - -/* no interpolation */ -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]; -} - - /* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau. * Used in the relationship Transmittance = e^(-attenuation) */ @@ -353,7 +322,7 @@ void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, f VecSubf(step_vec, endco, co); VecMulf(step_vec, 1.0f / nsteps); - VECCOPY(step_sta, co); + VecCopyf(step_sta, co); VecAddf(step_end, step_sta, step_vec); for (s = 0; s < nsteps; s++) { @@ -469,17 +438,33 @@ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsi VECCOPY(scatter, col); } + +/* +The main volumetric integrator, using an emission/absorption/scattering model. + +Incoming radiance = + +outgoing radiance from behind surface * beam transmittance/attenuation ++ added radiance from all points along the ray due to participating media + --> radiance for each segment = + (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation + +-- To find transmittance: + compute optical thickness with tau (perhaps involving monte carlo integration) + transmittance = exp(-tau) + +-- To find radiance from segments along the way: + find radiance for one step: + - loop over lights and weight by phase function +*/ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco) { - float tr[3] = {1.0f, 1.0f, 1.0f}; /* total transmittance */ + float tr[3] = {1.0f, 1.0f, 1.0f}; float radiance[3] = {0.f, 0.f, 0.f}, d_radiance[3] = {0.f, 0.f, 0.f}; float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW); - int nsteps; - float vec[3], stepvec[3] = {0.0, 0.0, 0.0}; + int nsteps, s; float tau[3], emit_col[3], scatter_col[3] = {0.0, 0.0, 0.0}; - int s; - float step_sta[3], step_end[3], step_mid[3]; - float alpha; + float stepvec[3], step_sta[3], step_end[3], step_mid[3]; float density = vol_get_density(shi, co); /* multiply col_behind with beam transmittance over entire distance */ @@ -493,11 +478,9 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float /* ray marching */ nsteps = (int)((VecLenf(co, endco) / stepsize) + 0.5); - VecSubf(vec, endco, co); - VECCOPY(stepvec, vec); + VecSubf(stepvec, endco, co); VecMulf(stepvec, 1.0f / nsteps); - - VECCOPY(step_sta, co); + VecCopyf(step_sta, co); VecAddf(step_end, step_sta, stepvec); /* get radiance from all points along the ray due to participating media */ @@ -505,8 +488,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float if (s > 0) density = vol_get_density(shi, step_sta); - /* there's only any use in shading here - * if there's actually some density to shade! */ + /* there's only any use in shading here if there's actually some density to shade! */ if (density > 0.01f) { /* transmittance component (alpha) */ @@ -524,10 +506,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float if ((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) && (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED)) { - if (G.rt==100) - vol_get_precached_scattering_nearest(shi, scatter_col, step_mid); - else - vol_get_precached_scattering(shi, scatter_col, step_mid); + vol_get_precached_scattering(shi, scatter_col, step_mid); } else vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); @@ -541,36 +520,12 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float VecAddf(radiance, radiance, d_radiance); } - VECCOPY(step_sta, step_end); + VecCopyf(step_sta, step_end); VecAddf(step_end, step_end, stepvec); } - col[0] = radiance[0]; - col[1] = radiance[1]; - col[2] = radiance[2]; - - alpha = 1.0f -(tr[0] + tr[1] + tr[2]) * 0.333f; - col[3] = alpha; - - /* - Incoming radiance = - outgoing radiance from behind surface * beam transmittance/attenuation - - + added radiance from all points along the ray due to participating media - --> radiance for each segment = - radiance added by scattering - + radiance added by emission - * beam transmittance/attenuation - - - -- To find transmittance: - compute optical thickness with tau (perhaps involving monte carlo integration) - return exp(-tau) - - -- To find radiance from segments along the way: - find radiance for one step: - - loop over lights and weight by phase function - */ + VecCopyf(col, radiance); + col[3] = 1.0f -(tr[0] + tr[1] + tr[2]) * 0.333f; } static void shade_intersection(ShadeInput *shi, float *col, Isect *is) @@ -759,308 +714,3 @@ void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct } } - -/* 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); - 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; vobr->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); - - return tree; -} - -static float get_avg_surrounds(float *cache, int res, int res_2, int res_3, int rgb, int xx, int yy, int zz) -{ - int x, y, z, x_, y_, z_; - int added=0; - float tot=0.0f; - int i; - - for (x=-1; x <= 1; x++) { - x_ = xx+x; - if (x_ >= 0 && x_ <= res-1) { - - for (y=-1; y <= 1; y++) { - y_ = yy+y; - if (y_ >= 0 && y_ <= res-1) { - - for (z=-1; z <= 1; z++) { - z_ = zz+z; - if (z_ >= 0 && z_ <= res-1) { - - i = rgb*res_3 + x_*res_2 + y_*res + z_; - if (cache[i] > 0.0f) { - tot += cache[i]; - added++; - } - - } - } - } - } - } - } - - tot /= added; - - return ((added>0)?tot:0.0f); -} - -/* function to filter the edges of the light cache, where there was no volume originally. - * For each voxel which was originally external to the mesh, it finds the average values of - * the surrounding internal voxels and sets the original external voxel to that average amount. - * Works almost a bit like a 'dilate' filter */ -static void lightcache_filter(float *cache, int res) -{ - int x, y, z, rgb; - int res_2, res_3; - int i; - - res_2 = res*res; - res_3 = res*res*res; - - for (x=0; x < res; x++) { - for (y=0; y < res; y++) { - for (z=0; z < res; z++) { - for (rgb=0; rgb < 3; rgb++) { - i = rgb*res_3 + x*res_2 + y*res + z; - - /* trigger for outside mesh */ - if (cache[i] < 0.5f) cache[i] = get_avg_surrounds(cache, res, res_2, res_3, rgb, x, y, z); - } - } - } - } -} - -/* 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, res_3f; - int res_2, res_3; - - float i = 1.0f; - double time, lasttime= PIL_check_seconds_timer(); - const int res = ma->vol_precache_resolution; - RayTree *tree; - - R = *re; - - /* create a raytree with just the faces of the instanced ObjectRen, - * 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 */ - memset(&shi, 0, sizeof(ShadeInput)); - shi.depth= 1; - shi.mask= 1; - shi.mat = ma; - shi.vlr = NULL; - memcpy(&shi.r, &shi.mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h - shi.har= shi.mat->har; - shi.obi= obi; - shi.obr= obi->obr; - shi.lay = re->scene->lay; - VECCOPY(shi.view, view); - - stepsize = vol_get_stepsize(&shi, STEPSIZE_VIEW); - - resf = (float)res; - res_2 = res*res; - res_3 = res*res*res; - res_3f = (float)res_3; - - VecSubf(voxel, bbmax, bbmin); - if ((voxel[0] < FLT_EPSILON) || (voxel[1] < FLT_EPSILON) || (voxel[2] < FLT_EPSILON)) - return; - VecMulf(voxel, 1.0f/res); - - 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); - - for (y=0; y < res; y++) { - co[1] = bbmin[1] + (voxel[1] * y); - - for (z=0; z < res; z++) { - co[2] = bbmin[2] + (voxel[2] * z); - - time= PIL_check_seconds_timer(); - i++; - - /* display progress every second */ - if(re->test_break()) { - if(tree) { - RE_ray_tree_free(tree); - tree= NULL; - } - return; - } - if(time-lasttime>1.0f) { - char str[64]; - 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; - } - - /* don't bother if the point is not inside the volume mesh */ - if (!point_inside_obi(tree, obi, co)) { - obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; - obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = -1.0f; - obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; - continue; - } - - VECCOPY(shi.view, co); - Normalize(shi.view); - 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; - } - - lightcache_filter(obi->volume_precache, res); - -} - -/* 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; - - 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]); - } - } - - re->i.infostr= NULL; - re->stats_draw(&re->i); -} - -void free_volume_precache(Render *re) -{ - ObjectInstanceRen *obi; - - for(obi= re->instancetable.first; obi; obi= obi->next) { - if (obi->volume_precache) - MEM_freeN(obi->volume_precache); - } - - BLI_freelistN(&re->vol_precache_obs); -} - From e5b51109e955e3dd6ec4857f833c3aa51f0fa3f4 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 18 Nov 2008 01:53:52 +0000 Subject: [PATCH 62/88] * Exclude volume materials from AO --- source/blender/render/intern/source/occlusion.c | 2 +- source/blender/render/intern/source/rayshade.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index d2d2cf3fb77..04404d71f30 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -663,7 +663,7 @@ static OcclusionTree *occ_tree_build(Render *re) if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++; - if(vlr->mat->mode & MA_TRACEBLE) { + if((vlr->mat->mode & MA_TRACEBLE) && (vlr->mat->material_type == MA_SOLID)) { tree->face[b].obi= c; tree->face[b].facenr= a; tree->occlusion[b]= 1.0f; diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index d06bbcf3300..bba7cb924eb 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -96,6 +96,17 @@ static int vlr_check_intersect(Isect *is, int ob, RayFace *face) return (is->lay & obi->lay); } +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_SOLID) + return 1; + else + return 0; +} + static float *vlr_get_transform(void *userdata, int i) { ObjectInstanceRen *obi= RAY_OBJECT_GET((Render*)userdata, i); @@ -1621,7 +1632,7 @@ static void ray_ao_qmc(ShadeInput *shi, float *shadfac) prev = fac; - if(RE_ray_tree_intersect(R.raytree, &isec)) { + if(RE_ray_tree_intersect_check(R.raytree, &isec, vlr_check_intersect_solid)) { if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac); else fac+= 1.0f; } @@ -1746,7 +1757,7 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac) isec.end[2] = shi->co[2] - maxdist*vec[2]; /* do the trace */ - if(RE_ray_tree_intersect(R.raytree, &isec)) { + if(RE_ray_tree_intersect_check(R.raytree, &isec, vlr_check_intersect_solid)) { if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac); else sh+= 1.0f; } From 14a0718a8a4ed3ee95f6374e20dbe9e74cf3b5c6 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 19 Nov 2008 05:30:52 +0000 Subject: [PATCH 63/88] * fix - constant colour output in point density wasn't working --- .../blender/render/intern/source/pointdensity.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index af2a7edae06..db675c81840 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -418,14 +418,14 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) co[1] = texvec[1] + noise_fac * turb; co[2] = texvec[2] + noise_fac * turb; - /* reset and do a new BVH query with the perturbed coordinates */ + /* reset and prepare for a new BVH query with the perturbed coordinates */ density = vec[0] = vec[1] = vec[2] = 0.0f; - num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); - if (num > 0) { - age /= num; - VecMulf(vec, 1.0f/num); - } - + } + + num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); + if (num > 0) { + age /= num; + VecMulf(vec, 1.0f/num); } texres->tin = density; @@ -459,6 +459,7 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) VECCOPY(&texres->tr, vec); texres->ta = 1.0f; break; + case TEX_PD_COLOR_CONSTANT: default: texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; break; From 6df8cf842a926e9354ee74f1892530b69897da5f Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 19 Nov 2008 23:27:47 +0000 Subject: [PATCH 64/88] * Allow for light linking/overrides in volume materials --- source/blender/render/intern/source/volumetric.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 359f6202fe4..45d54d40fa1 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -417,12 +417,14 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * /* single scattering only for now */ void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsize, float density) { + ListBase *lights; GroupObject *go; LampRen *lar; float col[3] = {0.f, 0.f, 0.f}; int i=0; - for(go=R.lights.first; go; go= go->next) + lights= get_lights(shi); + for(go=lights->first; go; go= go->next) { float lacol[3] = {0.f, 0.f, 0.f}; From bdf6711b70e1800dbf390c8a9264368c0fe01760 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 28 Nov 2008 07:12:32 +0000 Subject: [PATCH 65/88] * Some extra sanity checks for point density --- source/blender/render/intern/source/pointdensity.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index db675c81840..2034ed2d466 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -230,6 +230,8 @@ static void cache_pointdensity(Render *re, Tex *tex) int i; if (!ob) return; + if (BLI_countlist(&ob->particlesystem) == 0) return; + for(psys=ob->particlesystem.first, i=0; i< pd->psysindex-1; i++) psys= psys->next; @@ -260,6 +262,8 @@ static void free_pointdensity(Render *re, Tex *tex) { PointDensity *pd = tex->pd; + if (!pd) return; + if (pd->point_tree) { BLI_bvhtree_free(pd->point_tree); pd->point_tree = NULL; From 1b9eabeef6ac895a4818c4ad74c0899226cabc84 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 5 Dec 2008 04:06:41 +0000 Subject: [PATCH 66/88] * Added other noise basis types to point density turbulence * Fixed a bug in 'ignoring volumes in AAO' --- source/blender/makesdna/DNA_texture_types.h | 2 + .../blender/render/intern/source/occlusion.c | 2 +- .../render/intern/source/pointdensity.c | 7 +- .../render/intern/source/volume_precache.c | 129 ++++++++++++++++++ source/blender/src/buttons_shading.c | 5 + 5 files changed, 141 insertions(+), 4 deletions(-) diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index fd497cef178..b4fcb5efe40 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -153,6 +153,8 @@ typedef struct PointDensity { float noise_size; short noise_depth; short noise_influence; + short noise_basis; + short pdpad3[3]; float noise_fac; float speed_scale; diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index 04404d71f30..f1ea4665120 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -630,7 +630,7 @@ static OcclusionTree *occ_tree_build(Render *re) if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++; - if(vlr->mat->mode & MA_TRACEBLE) + if((vlr->mat->mode & MA_TRACEBLE) && (vlr->mat->material_type == MA_SOLID)) totface++; } } diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 2034ed2d466..392af8411c5 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -405,14 +405,15 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) if (pd->flag & TEX_PD_TURBULENCE) { if (pd->noise_influence == TEX_PD_NOISE_AGE) { - turb = BLI_turbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth); + turb = BLI_gTurbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth, 0, pd->noise_basis); } else if (pd->noise_influence == TEX_PD_NOISE_TIME) { time = R.cfra / (float)R.r.efra; - turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth); + turb = BLI_gTurbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth, 0, pd->noise_basis); + //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth); } else { - turb = BLI_turbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth); + turb = BLI_gTurbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth, 0, pd->noise_basis); } turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */ diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 5b43aa8f935..c56d17f7cc3 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -325,6 +325,135 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m } +#if 0 +void vol_precache_objectinstance_threads(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, res_3f; + int res_2, res_3; + + int edgeparts=2; + int totparts; + + float i = 1.0f; + double time, lasttime= PIL_check_seconds_timer(); + const int res = ma->vol_precache_resolution; + RayTree *tree; + + R = *re; + + /* create a raytree with just the faces of the instanced ObjectRen, + * 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 */ + memset(&shi, 0, sizeof(ShadeInput)); + shi.depth= 1; + shi.mask= 1; + shi.mat = ma; + shi.vlr = NULL; + memcpy(&shi.r, &shi.mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h + shi.har= shi.mat->har; + shi.obi= obi; + shi.obr= obi->obr; + shi.lay = re->scene->lay; + VECCOPY(shi.view, view); + + stepsize = vol_get_stepsize(&shi, STEPSIZE_VIEW); + + resf = (float)res; + res_2 = res*res; + res_3 = res*res*res; + res_3f = (float)res_3; + + 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] = parceil(res/(float)xparts); + part[1] = ceil(rex/(float)yparts); + part[2] = ceil(rex/(float)zparts); + + + + //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); + + for (y=0; y < res; y++) { + co[1] = bbmin[1] + (voxel[1] * y); + + for (z=0; z < res; z++) { + co[2] = bbmin[2] + (voxel[2] * z); + + time= PIL_check_seconds_timer(); + i++; + + // display progress every second + if(re->test_break()) { + if(tree) { + RE_ray_tree_free(tree); + tree= NULL; + } + return; + } + if(time-lasttime>1.0f) { + char str[64]; + 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; + } + + // don't bother if the point is not inside the volume mesh + + if (!point_inside_obi(tree, obi, co)) { + obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; + 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; + } + + lightcache_filter(obi->volume_precache, res); + +} +#endif + /* loop through all objects (and their associated materials) * marked for pre-caching in convertblender.c, and pre-cache them */ void volume_precache(Render *re) diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 55475e74450..c88c341fe53 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -994,6 +994,11 @@ static void texture_panel_pointdensity_modify(Tex *tex) yco = ymid - BUTH - YSPACE; + uiDefBut(block, LABEL, B_NOP, "Noise Basis:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiDefButS(block, MENU, B_REDR, noisebasis_menu(), + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->noise_basis), 0.0, 0.0, 0, 0, "Noise formula used for tubulence"); + uiDefBut(block, LABEL, B_NOP, "Noise Influence:", X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); From 9e1da805e19b3efd822803fa53e4bbc23223f58f Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 9 Dec 2008 04:27:34 +0000 Subject: [PATCH 67/88] * Added back the GR: field for volume materials, limiting lighting to a certain group --- source/blender/src/buttons_shading.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index c88c341fe53..a8aa00370d9 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4529,6 +4529,10 @@ static void material_panel_material_volume(Material *ma) X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); } + yco -= YSPACE; + uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_MATPRV, "GR:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &ma->group, "Limit Lighting to Lamps in this Group"); + } static void material_panel_nodes(Material *ma) From aef61a7000c279a96f1bb0e1fedf7da2574292fd Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 9 Dec 2008 07:19:55 +0000 Subject: [PATCH 68/88] wip commit to work on at home, nothing to see --- .../render/intern/source/volume_precache.c | 187 +++++++++++++++--- 1 file changed, 164 insertions(+), 23 deletions(-) diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index c56d17f7cc3..246f9bc6d69 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -326,13 +326,104 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m } #if 0 +typedef struct VolPrecachePart { + struct VolPrecachePart *next, *prev; + int num; + int minx, maxx; + int miny, maxy; + int minz, maxz; + int res; + float bbmin[3], voxel[3]; + struct RayTree *tree; + struct ShadeInput *shi; + struct ObjectInstanceRen *obi; + int done; +} VolPrecachePart; + +static void *vol_precache_part_test(void *data) +{ + VolPrecachePart *vpt = (VolPrecachePart *)data; + + printf("part number: %d \n", vpt->num); + + return 0; +} + +/* 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! :) + */ +static void *vol_precache_part(void *data) +{ + VolPrecachePart *vpt = (VolPrecachePart *)data; + ObjectInstanceRen *obi = vpt->obi; + RayTree *tree = vpt->tree; + ShadeInput *shi = vpt->shi; + float scatter_col[3] = {0.f, 0.f, 0.f}; + float co[3]; + int x, y, z; + const int res=vpt->res, res_2=vpt->res*vpt->res, res_3=vpt->res*vpt->res*vpt->res; + const float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW); + + res = vpt->res; + res_2 = res*res; + res_3 = res*res*res; + + for (x= vpt->minx; x < vpt->maxx; x++) { + co[0] = vpt->bbmin[0] + (vpt->voxel[0] * x); + + for (y= vpt->miny; y < vpt->maxy; y++) { + co[1] = vpt->bbmin[1] + (vpt->voxel[1] * y); + + for (z=vpt->minz; z < vpt->maxz; z++) { + co[2] = vpt->bbmin[2] + (vpt->voxel[2] * z); + + // don't bother if the point is not inside the volume mesh + if (!point_inside_obi(tree, obi, co)) { + obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; + 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]; + } + } + } + + return 0; +} + +void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi) +{ + float view[3] = {0.0,0.0,-1.0}; + + memset(&shi, 0, sizeof(ShadeInput)); + shi->depth= 1; + shi->mask= 1; + shi->mat = ma; + shi->vlr = NULL; + memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h + shi->har= shi->mat->har; + shi->obi= obi; + shi->obr= obi->obr; + shi->lay = re->scene->lay; + VECCOPY(shi->view, view); +} + void vol_precache_objectinstance_threads(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; @@ -341,6 +432,14 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat int edgeparts=2; int totparts; + ListBase threads; + int cont= 1; + int xparts, yparts, zparts; + float part[3]; + int totthread = re->r.threads; + ListBase precache_parts; + VolPrecachePart *nextpa; + int j; float i = 1.0f; double time, lasttime= PIL_check_seconds_timer(); @@ -355,38 +454,80 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat if (!tree) return; /* Need a shadeinput to calculate scattering */ - memset(&shi, 0, sizeof(ShadeInput)); - shi.depth= 1; - shi.mask= 1; - shi.mat = ma; - shi.vlr = NULL; - memcpy(&shi.r, &shi.mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h - shi.har= shi.mat->har; - shi.obi= obi; - shi.obr= obi->obr; - shi.lay = re->scene->lay; - VECCOPY(shi.view, view); - - stepsize = vol_get_stepsize(&shi, STEPSIZE_VIEW); + precache_setup_shadeinput(re, obi, ma, &shi); - resf = (float)res; - res_2 = res*res; - res_3 = res*res*res; - res_3f = (float)res_3; - 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); - part[0] = parceil(res/(float)xparts); - part[1] = ceil(rex/(float)yparts); - part[2] = ceil(rex/(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); + + 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; + } - //obi->volume_precache = MEM_callocN(sizeof(float)*res_3*3, "volume light cache"); + BLI_init_threads(&threads, vol_precache_part, totthread); + + nextpa = precache_get_new_part(precache_threads); + + while(cont) { + + if(BLI_available_threads(&threads) && !(re->test_break())) { + + precache_get_new_part( + // get new job (data pointer) + for(j=0; j < totparts; j++) { + if (!precache_threads[j].done) { + // tag job 'processed + precache_threads[j].done = 1; + } + } + + BLI_insert_thread(&threads, precache_get_new_part(precache_threads)); + } + else PIL_sleep_ms(50); + + // find if a job is ready, this the do_something_func() should write in job somewhere + cont= 0; + for(go over all jobs) + if(job is ready) { + if(job was not removed) { + BLI_remove_thread(&lb, job); + } + } + else cont= 1; + } + // conditions to exit loop + if(if escape loop event) { + if(BLI_available_threadslots(&lb)==maxthreads) + break; + } + } + + BLI_end_threads(&threads); + + // /* Iterate over the 3d voxel grid, and fill the voxels with scattering information * From 92f5c719aedf79db7e45d3b887146a559321981e Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sat, 13 Dec 2008 05:41:34 +0000 Subject: [PATCH 69/88] * Volume Rendering: Voxel data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- source/blender/blenkernel/BKE_texture.h | 6 ++ source/blender/blenkernel/intern/texture.c | 49 ++++++++++ source/blender/blenloader/intern/readfile.c | 18 ++++ source/blender/blenloader/intern/writefile.c | 1 + source/blender/include/butspace.h | 2 + source/blender/makesdna/DNA_material_types.h | 2 + source/blender/makesdna/DNA_texture_types.h | 24 ++++- .../render/intern/include/render_types.h | 14 +++ .../render/intern/include/volume_precache.h | 3 +- .../render/intern/source/convertblender.c | 61 ++++++++++-- source/blender/render/intern/source/texture.c | 5 + .../render/intern/source/volume_precache.c | 98 +++++++++++-------- .../blender/render/intern/source/volumetric.c | 16 ++- source/blender/src/butspace.c | 2 +- source/blender/src/buttons_shading.c | 80 ++++++++++++++- 15 files changed, 324 insertions(+), 57 deletions(-) diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index e16ac2d369b..985094a7e62 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -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 diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index c972d70d927..c9cae91da6f 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -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) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1fd766be256..8347920319a 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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; + } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 93bf8111c98..fd87080d0ee 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -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) { diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index fd3f6e926b9..a3cd9d1875b 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -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 diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index f332537e9a8..5172f6a970c 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -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]; diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index b4fcb5efe40..e90df908c2b 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -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 diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 6f4537d84fb..65bb12e059d 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -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; diff --git a/source/blender/render/intern/include/volume_precache.h b/source/blender/render/intern/include/volume_precache.h index 7a719840f48..78409e4c646 100644 --- a/source/blender/render/intern/include/volume_precache.h +++ b/source/blender/render/intern/include/volume_precache.h @@ -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 diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 09f2d1275f4..d87ee65c42c 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -104,6 +104,7 @@ #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); + } + } + } + } - vp = MEM_mallocN(sizeof(VolPrecache), "volume precache object"); + { + MatInside *m; + for (m=re->render_volumes_inside.first; m; m=m->next) { + printf("matinside: ma: %s \n", m->ma->id.name+2); + } - vp->ma = ma; - vp->obr = obr; + } +} + +static void add_volume(Render *re, ObjectRen *obr, Material *ma) +{ + struct VolumeOb *vo; - BLI_addtail(&re->vol_precache_obs, vp); + vo = MEM_mallocN(sizeof(VolumeOb), "volume object"); + + 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()) diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index d7d4d124b18..d7b41d7cc2c 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -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) { diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 246f9bc6d69..89f997f4b99 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -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; + + obi->volume_precache = MEM_callocN(sizeof(float)*res_3*3, "volume light cache"); /* Need a shadeinput to calculate scattering */ precache_setup_shadeinput(re, obi, ma, &shi); + precache_init_parts(&precache_parts, tree, shi, obi, bbmin, bbmax, res); - 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); - - 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; +} diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 45d54d40fa1..fba847da2ad 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -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); diff --git a/source/blender/src/butspace.c b/source/blender/src/butspace.c index 2ca709184c5..6d8f806d8f9 100644 --- a/source/blender/src/butspace.c +++ b/source/blender/src/butspace.c @@ -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) diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index a8aa00370d9..6e69414fbe0 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -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; } } } From c2f037da073856ab44096df6d7e5dfbebb5f5efa Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sat, 13 Dec 2008 05:43:10 +0000 Subject: [PATCH 70/88] and the new voxel data files.. --- .../blender/render/intern/include/voxeldata.h | 45 ++ .../blender/render/intern/source/voxeldata.c | 444 ++++++++++++++++++ 2 files changed, 489 insertions(+) create mode 100644 source/blender/render/intern/include/voxeldata.h create mode 100644 source/blender/render/intern/source/voxeldata.c diff --git a/source/blender/render/intern/include/voxeldata.h b/source/blender/render/intern/include/voxeldata.h new file mode 100644 index 00000000000..504d5523db6 --- /dev/null +++ b/source/blender/render/intern/include/voxeldata.h @@ -0,0 +1,45 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef VOXELDATA_H +#define VOXELDATA_H + +/** + * Load voxel data for all point density textures in the scene + */ + +struct Render; +struct TexResult; + +int _I(int x,int y,int z,int n); +void make_voxeldata(struct Render *re); +void free_voxeldata(struct Render *re); +int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres); + + +#endif /* VOXELDATA_H */ diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c new file mode 100644 index 00000000000..b2521e59b41 --- /dev/null +++ b/source/blender/render/intern/source/voxeldata.c @@ -0,0 +1,444 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "DNA_texture_types.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "texture.h" + +/*---------------------------Utils----------------------------------------*/ +int _I(int x,int y,int z,int n) +{ + return (z*(n)+y)*(n)+x; +} + +float Linear(float xx,float yy,float zz,float *x0,int n) +{ + float sx1,sx0,sy1,sy0,sz1,sz0,v0,v1; + int i0,i1,j0,j1,k0,k1; + + if (xx<0.5) xx=0.5f; if (xx>n+0.5) xx=n+0.5f; i0=(int)xx; i1=i0+1; + if (yy<0.5) yy=0.5f; if (yy>n+0.5) yy=n+0.5f; j0=(int)yy; j1=j0+1; + if (zz<0.5) zz=0.5f; if (zz>n+0.5) zz=n+0.5f; k0=(int)zz; k1=k0+1; + + sx1 = xx-i0; sx0 = 1-sx1; + sy1 = yy-j0; sy0 = 1-sy1; + sz1 = zz-k0; sz0 = 1-sz1; + v0 = sx0*(sy0*x0[_I(i0,j0,k0,n)]+sy1*x0[_I(i0,j1,k0,n)])+sx1*(sy0*x0[_I(i1,j0,k0,n)]+sy1*x0[_I(i1,j1,k0,n)]); + v1 = sx0*(sy0*x0[_I(i0,j0,k1,n)]+sy1*x0[_I(i0,j1,k1,n)])+sx1*(sy0*x0[_I(i1,j0,k1,n)]+sy1*x0[_I(i1,j1,k1,n)]); + return sz0*v0 + sz1*v1; + +} + +int C[64][64] = { + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 9,-9,-9, 9, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-6, 6, 6,-6, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-6, 6, 6,-6, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 4,-4,-4, 4, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0}, + {-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 9,-9, 0, 0,-9, 9, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-6, 6, 0, 0, 6,-6, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9, 0, 0,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0}, + { 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0}, + {-27,27,27,-27,27,-27,-27,27,-18,-9,18, 9,18, 9,-18,-9,-18,18,-9, 9,18,-18, 9,-9,-18,18,18,-18,-9, 9, 9,-9,-12,-6,-6,-3,12, 6, 6, 3,-12,-6,12, 6,-6,-3, 6, 3,-12,12,-6, 6,-6, 6,-3, 3,-8,-4,-4,-2,-4,-2,-2,-1}, + {18,-18,-18,18,-18,18,18,-18, 9, 9,-9,-9,-9,-9, 9, 9,12,-12, 6,-6,-12,12,-6, 6,12,-12,-12,12, 6,-6,-6, 6, 6, 6, 3, 3,-6,-6,-3,-3, 6, 6,-6,-6, 3, 3,-3,-3, 8,-8, 4,-4, 4,-4, 2,-2, 4, 4, 2, 2, 2, 2, 1, 1}, + {-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0}, + {18,-18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6, 9,-9, 9,-9,-9, 9,-9, 9,12,-12,-12,12, 6,-6,-6, 6, 6, 3, 6, 3,-6,-3,-6,-3, 8, 4,-8,-4, 4, 2,-4,-2, 6,-6, 6,-6, 3,-3, 3,-3, 4, 2, 4, 2, 2, 1, 2, 1}, + {-12,12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-6, 6,-6, 6, 6,-6, 6,-6,-8, 8, 8,-8,-4, 4, 4,-4,-3,-3,-3,-3, 3, 3, 3, 3,-4,-4, 4, 4,-2,-2, 2, 2,-4, 4,-4, 4,-2, 2,-2, 2,-2,-2,-2,-2,-1,-1,-1,-1}, + { 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-6, 6, 0, 0, 6,-6, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 4,-4, 0, 0,-4, 4, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4, 0, 0,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}, + {-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0}, + {18,-18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6,12,-12, 6,-6,-12,12,-6, 6, 9,-9,-9, 9, 9,-9,-9, 9, 8, 4, 4, 2,-8,-4,-4,-2, 6, 3,-6,-3, 6, 3,-6,-3, 6,-6, 3,-3, 6,-6, 3,-3, 4, 2, 2, 1, 4, 2, 2, 1}, + {-12,12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-8, 8,-4, 4, 8,-8, 4,-4,-6, 6, 6,-6,-6, 6, 6,-6,-4,-4,-2,-2, 4, 4, 2, 2,-3,-3, 3, 3,-3,-3, 3, 3,-4, 4,-2, 2,-4, 4,-2, 2,-2,-2,-1,-1,-2,-2,-1,-1}, + { 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0}, + {-12,12,12,-12,12,-12,-12,12,-8,-4, 8, 4, 8, 4,-8,-4,-6, 6,-6, 6, 6,-6, 6,-6,-6, 6, 6,-6,-6, 6, 6,-6,-4,-2,-4,-2, 4, 2, 4, 2,-4,-2, 4, 2,-4,-2, 4, 2,-3, 3,-3, 3,-3, 3,-3, 3,-2,-1,-2,-1,-2,-1,-2,-1}, + { 8,-8,-8, 8,-8, 8, 8,-8, 4, 4,-4,-4,-4,-4, 4, 4, 4,-4, 4,-4,-4, 4,-4, 4, 4,-4,-4, 4, 4,-4,-4, 4, 2, 2, 2, 2,-2,-2,-2,-2, 2, 2,-2,-2, 2, 2,-2,-2, 2,-2, 2,-2, 2,-2, 2,-2, 1, 1, 1, 1, 1, 1, 1, 1}}; + +int ijk2n(int i, int j, int k) { + return(i+4*j+16*k); +} + +void tricubic_get_coeff_stacked(float a[64], float x[64]) { + int i,j; + for (i=0;i<64;i++) { + a[i]=(float)(0.0); + for (j=0;j<64;j++) { + a[i]+=C[i][j]*x[j]; + } + } +} + +void point2xyz(int p, int *x, int *y, int *z) { + switch (p) { + case 0: *x=0; *y=0; *z=0; break; + case 1: *x=1; *y=0; *z=0; break; + case 2: *x=0; *y=1; *z=0; break; + case 3: *x=1; *y=1; *z=0; break; + case 4: *x=0; *y=0; *z=1; break; + case 5: *x=1; *y=0; *z=1; break; + case 6: *x=0; *y=1; *z=1; break; + case 7: *x=1; *y=1; *z=1; break; + default:*x=0; *y=0; *z=0; + } +} + + +void tricubic_get_coeff(float a[64], float f[8], float dfdx[8], float dfdy[8], float dfdz[8], float d2fdxdy[8], float d2fdxdz[8], float d2fdydz[8], float d3fdxdydz[8]) { + int i; + float x[64]; + for (i=0;i<8;i++) { + x[0+i]=f[i]; + x[8+i]=dfdx[i]; + x[16+i]=dfdy[i]; + x[24+i]=dfdz[i]; + x[32+i]=d2fdxdy[i]; + x[40+i]=d2fdxdz[i]; + x[48+i]=d2fdydz[i]; + x[56+i]=d3fdxdydz[i]; + } + tricubic_get_coeff_stacked(a,x); +} + +float tricubic_eval(float a[64], float x, float y, float z) { + int i,j,k; + float ret=(float)(0.0); + + for (i=0;i<4;i++) { + for (j=0;j<4;j++) { + for (k=0;k<4;k++) { + ret+=a[ijk2n(i,j,k)]*pow(x,i)*pow(y,j)*pow(z,k); + } + } + } + return(ret); +} + + +float tricubic(float xx,float yy,float zz,float *heap,int n) +{ + + int xi,yi,zi; + + if (xx<0.5) xx=0.5f; if (xx>n+0.5) xx=n+0.5f; xi=(int)xx; + if (yy<0.5) yy=0.5f; if (yy>n+0.5) yy=n+0.5f; yi=(int)yy; + if (zz<0.5) zz=0.5f; if (zz>n+0.5) zz=n+0.5f; zi=(int)zz; + + float a[64]; + + float fval[8]={heap[_I(xi,yi,zi,n)],heap[_I(xi+1,yi,zi,n)],heap[_I(xi,yi+1,zi,n)],heap[_I(xi+1,yi+1,zi,n)],heap[_I(xi,yi,zi+1,n)],heap[_I(xi+1,yi,zi+1,n)],heap[_I(xi,yi+1,zi+1,n)],heap[_I(xi+1,yi+1,zi+1,n)]}; + + float dfdxval[8]={0.5f*(heap[_I(xi+1,yi,zi,n)]-heap[_I(xi-1,yi,zi,n)]),0.5f*(heap[_I(xi+2,yi,zi,n)]-heap[_I(xi,yi,zi,n)]), + 0.5f*(heap[_I(xi+1,yi+1,zi,n)]-heap[_I(xi-1,yi+1,zi,n)]),0.5f*(heap[_I(xi+2,yi+1,zi,n)]-heap[_I(xi,yi+1,zi,n)]), + 0.5f*(heap[_I(xi+1,yi,zi+1,n)]-heap[_I(xi-1,yi,zi+1,n)]),0.5f*(heap[_I(xi+2,yi,zi+1,n)]-heap[_I(xi,yi,zi+1,n)]), + 0.5f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi-1,yi+1,zi+1,n)]), + 0.5f*(heap[_I(xi+2,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi+1,n)])}; + + float dfdyval[8]={0.5f*(heap[_I(xi,yi+1,zi,n)]-heap[_I(xi,yi-1,zi,n)]),0.5f*(heap[_I(xi+1,yi+1,zi,n)]-heap[_I(xi+1,yi-1,zi,n)]), + 0.5f*(heap[_I(xi,yi+2,zi,n)]-heap[_I(xi,yi,zi,n)]),0.5f*(heap[_I(xi+1,yi+2,zi,n)]-heap[_I(xi+1,yi,zi,n)]), + 0.5f*(heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi,yi-1,zi+1,n)]),0.5f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi+1,yi-1,zi+1,n)]), + 0.5f*(heap[_I(xi,yi+2,zi+1,n)]-heap[_I(xi,yi,zi+1,n)]), + 0.5f*(heap[_I(xi+1,yi+2,zi+1,n)]-heap[_I(xi+1,yi,zi+1,n)])}; + + float dfdzval[8]={0.5f*(heap[_I(xi,yi,zi+1,n)]-heap[_I(xi,yi,zi-1,n)]),0.5f*(heap[_I(xi+1,yi,zi+1,n)]-heap[_I(xi+1,yi,zi-1,n)]), + 0.5f*(heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi-1,n)]),0.5f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi+1,yi+1,zi-1,n)]), + 0.5f*(heap[_I(xi,yi,zi+2,n)]-heap[_I(xi,yi,zi,n)]),0.5f*(heap[_I(xi+1,yi,zi+2,n)]-heap[_I(xi+1,yi,zi,n)]), + 0.5f*(heap[_I(xi,yi+1,zi+2,n)]-heap[_I(xi,yi+1,zi,n)]), + 0.5f*(heap[_I(xi+1,yi+1,zi+2,n)]-heap[_I(xi+1,yi+1,zi,n)])}; + + float d2fdxdyval[8]={0.25*(heap[_I(xi+1,yi+1,zi,n)]-heap[_I(xi-1,yi+1,zi,n)]-heap[_I(xi+1,yi-1,zi,n)]+heap[_I(xi-1,yi-1,zi,n)]), + 0.25*(heap[_I(xi+2,yi+1,zi,n)]-heap[_I(xi,yi+1,zi,n)]-heap[_I(xi+2,yi-1,zi,n)]+heap[_I(xi,yi-1,zi,n)]), + 0.25*(heap[_I(xi+1,yi+2,zi,n)]-heap[_I(xi-1,yi+2,zi,n)]-heap[_I(xi+1,yi,zi,n)]+heap[_I(xi-1,yi,zi,n)]), + 0.25*(heap[_I(xi+2,yi+2,zi,n)]-heap[_I(xi,yi+2,zi,n)]-heap[_I(xi+2,yi,zi,n)]+heap[_I(xi,yi,zi,n)]), + 0.25*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi-1,yi+1,zi+1,n)]-heap[_I(xi+1,yi-1,zi+1,n)]+heap[_I(xi-1,yi-1,zi+1,n)]), + 0.25*(heap[_I(xi+2,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi+2,yi-1,zi+1,n)]+heap[_I(xi,yi-1,zi+1,n)]), + 0.25*(heap[_I(xi+1,yi+2,zi+1,n)]-heap[_I(xi-1,yi+2,zi+1,n)]-heap[_I(xi+1,yi,zi+1,n)]+heap[_I(xi-1,yi,zi+1,n)]), + 0.25*(heap[_I(xi+2,yi+2,zi+1,n)]-heap[_I(xi,yi+2,zi+1,n)]-heap[_I(xi+2,yi,zi+1,n)]+heap[_I(xi,yi,zi+1,n)])}; + + float d2fdxdzval[8]={0.25f*(heap[_I(xi+1,yi,zi+1,n)]-heap[_I(xi-1,yi,zi+1,n)]-heap[_I(xi+1,yi,zi-1,n)]+heap[_I(xi-1,yi,zi-1,n)]), + 0.25f*(heap[_I(xi+2,yi,zi+1,n)]-heap[_I(xi,yi,zi+1,n)]-heap[_I(xi+2,yi,zi-1,n)]+heap[_I(xi,yi,zi-1,n)]), + 0.25f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi-1,yi+1,zi+1,n)]-heap[_I(xi+1,yi+1,zi-1,n)]+heap[_I(xi-1,yi+1,zi-1,n)]), + 0.25f*(heap[_I(xi+2,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi+2,yi+1,zi-1,n)]+heap[_I(xi,yi+1,zi-1,n)]), + 0.25f*(heap[_I(xi+1,yi,zi+2,n)]-heap[_I(xi-1,yi,zi+2,n)]-heap[_I(xi+1,yi,zi,n)]+heap[_I(xi-1,yi,zi,n)]), + 0.25f*(heap[_I(xi+2,yi,zi+2,n)]-heap[_I(xi,yi,zi+2,n)]-heap[_I(xi+2,yi,zi,n)]+heap[_I(xi,yi,zi,n)]), + 0.25f*(heap[_I(xi+1,yi+1,zi+2,n)]-heap[_I(xi-1,yi+1,zi+2,n)]-heap[_I(xi+1,yi+1,zi,n)]+heap[_I(xi-1,yi+1,zi,n)]), + 0.25f*(heap[_I(xi+2,yi+1,zi+2,n)]-heap[_I(xi,yi+1,zi+2,n)]-heap[_I(xi+2,yi+1,zi,n)]+heap[_I(xi,yi+1,zi,n)])}; + + + float d2fdydzval[8]={0.25f*(heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi,yi-1,zi+1,n)]-heap[_I(xi,yi+1,zi-1,n)]+heap[_I(xi,yi-1,zi-1,n)]), + 0.25f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi+1,yi-1,zi+1,n)]-heap[_I(xi+1,yi+1,zi-1,n)]+heap[_I(xi+1,yi-1,zi-1,n)]), + 0.25f*(heap[_I(xi,yi+2,zi+1,n)]-heap[_I(xi,yi,zi+1,n)]-heap[_I(xi,yi+2,zi-1,n)]+heap[_I(xi,yi,zi-1,n)]), + 0.25f*(heap[_I(xi+1,yi+2,zi+1,n)]-heap[_I(xi+1,yi,zi+1,n)]-heap[_I(xi+1,yi+2,zi-1,n)]+heap[_I(xi+1,yi,zi-1,n)]), + 0.25f*(heap[_I(xi,yi+1,zi+2,n)]-heap[_I(xi,yi-1,zi+2,n)]-heap[_I(xi,yi+1,zi,n)]+heap[_I(xi,yi-1,zi,n)]), + 0.25f*(heap[_I(xi+1,yi+1,zi+2,n)]-heap[_I(xi+1,yi-1,zi+2,n)]-heap[_I(xi+1,yi+1,zi,n)]+heap[_I(xi+1,yi-1,zi,n)]), + 0.25f*(heap[_I(xi,yi+2,zi+2,n)]-heap[_I(xi,yi,zi+2,n)]-heap[_I(xi,yi+2,zi,n)]+heap[_I(xi,yi,zi,n)]), + 0.25f*(heap[_I(xi+1,yi+2,zi+2,n)]-heap[_I(xi+1,yi,zi+2,n)]-heap[_I(xi+1,yi+2,zi,n)]+heap[_I(xi+1,yi,zi,n)])}; + + + float d3fdxdydzval[8]={0.125f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi-1,yi+1,zi+1,n)]-heap[_I(xi+1,yi-1,zi+1,n)]+heap[_I(xi-1,yi-1,zi+1,n)]-heap[_I(xi+1,yi+1,zi-1,n)]+heap[_I(xi-1,yi+1,zi-1,n)]+heap[_I(xi+1,yi-1,zi-1,n)]-heap[_I(xi-1,yi-1,zi-1,n)]), + 0.125f*(heap[_I(xi+2,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi+2,yi-1,zi+1,n)]+heap[_I(xi,yi-1,zi+1,n)]-heap[_I(xi+2,yi+1,zi-1,n)]+heap[_I(xi,yi+1,zi-1,n)]+heap[_I(xi+2,yi-1,zi-1,n)]-heap[_I(xi,yi-1,zi-1,n)]), + 0.125f*(heap[_I(xi+1,yi+2,zi+1,n)]-heap[_I(xi-1,yi+2,zi+1,n)]-heap[_I(xi+1,yi,zi+1,n)]+heap[_I(xi-1,yi,zi+1,n)]-heap[_I(xi+1,yi+2,zi-1,n)]+heap[_I(xi-1,yi+2,zi-1,n)]+heap[_I(xi+1,yi,zi-1,n)]-heap[_I(xi-1,yi,zi-1,n)]), + 0.125f*(heap[_I(xi+2,yi+2,zi+1,n)]-heap[_I(xi,yi+2,zi+1,n)]-heap[_I(xi+2,yi,zi+1,n)]+heap[_I(xi,yi,zi+1,n)]-heap[_I(xi+2,yi+2,zi-1,n)]+heap[_I(xi,yi+2,zi-1,n)]+heap[_I(xi+2,yi,zi-1,n)]-heap[_I(xi,yi,zi-1,n)]), + 0.125f*(heap[_I(xi+1,yi+1,zi+2,n)]-heap[_I(xi-1,yi+1,zi+2,n)]-heap[_I(xi+1,yi-1,zi+2,n)]+heap[_I(xi-1,yi-1,zi+2,n)]-heap[_I(xi+1,yi+1,zi,n)]+heap[_I(xi-1,yi+1,zi,n)]+heap[_I(xi+1,yi-1,zi,n)]-heap[_I(xi-1,yi-1,zi,n)]), + 0.125f*(heap[_I(xi+2,yi+1,zi+2,n)]-heap[_I(xi,yi+1,zi+2,n)]-heap[_I(xi+2,yi-1,zi+2,n)]+heap[_I(xi,yi-1,zi+2,n)]-heap[_I(xi+2,yi+1,zi,n)]+heap[_I(xi,yi+1,zi,n)]+heap[_I(xi+2,yi-1,zi,n)]-heap[_I(xi,yi-1,zi,n)]), + 0.125f*(heap[_I(xi+1,yi+2,zi+2,n)]-heap[_I(xi-1,yi+2,zi+2,n)]-heap[_I(xi+1,yi,zi+2,n)]+heap[_I(xi-1,yi,zi+2,n)]-heap[_I(xi+1,yi+2,zi,n)]+heap[_I(xi-1,yi+2,zi,n)]+heap[_I(xi+1,yi,zi,n)]-heap[_I(xi-1,yi,zi,n)]), + 0.125f*(heap[_I(xi+2,yi+2,zi+2,n)]-heap[_I(xi,yi+2,zi+2,n)]-heap[_I(xi+2,yi,zi+2,n)]+heap[_I(xi,yi,zi+2,n)]-heap[_I(xi+2,yi+2,zi,n)]+heap[_I(xi,yi+2,zi,n)]+heap[_I(xi+2,yi,zi,n)]-heap[_I(xi,yi,zi,n)])}; + + tricubic_get_coeff(a,fval,dfdxval,dfdyval,dfdzval,d2fdxdyval,d2fdxdzval,d2fdydzval,d3fdxdydzval); + + float dx=xx-xi; + float dy=yy-yi; + float dz=zz-zi; + + return tricubic_eval(a,dx,dy,dz); + +} + + + + + +/*--------------------------------------------------------------------*/ + +void load_frame (FILE *fp,float *F, int size,int frame) +{ + + fseek(fp,frame*size*sizeof(float),0); + fread(F,sizeof(float),size,fp); +} + + + + +void cache_voxeldata(struct Render *re,Tex *tex) +{ + VoxelData *vd = tex->vd; + FILE *fp; + int size; + + if (!vd) return; + + vd->resolY=vd->resolX; //for now only support cubic datasets (rectangular datasets could be added latter) + vd->resolZ=vd->resolX; + size = (vd->resolX)*(vd->resolY)*(vd->resolZ); + + vd->dataset=MEM_mallocN(sizeof(float)*size, "voxel dataset"); + + if (!BLI_exists(vd->source_path)) return; + fp = fopen(vd->source_path,"rb"); + if (!fp) return; + + load_frame(fp, vd->dataset, size, re->r.cfra); //here improve the dataset loading function for more dataset types + + fclose(fp); + +} + +void make_voxeldata(struct Render *re) +{ + Tex *tex; + + if(re->scene->r.scemode & R_PREVIEWBUTS) + return; + + re->i.infostr= "Loading voxel datasets"; + re->stats_draw(&re->i); + + for (tex= G.main->tex.first; tex; tex= tex->id.next) { + if(tex->id.us && tex->type==TEX_VOXELDATA) { + cache_voxeldata(re, tex); + } + } + + re->i.infostr= NULL; + re->stats_draw(&re->i); + +} + +static void free_voxeldata_one(Render *re, Tex *tex) +{ + VoxelData *vd = tex->vd; + + if (vd->dataset) { + MEM_freeN(vd->dataset); + vd->dataset = NULL; + } +} + + +void free_voxeldata(Render *re) +{ + Tex *tex; + + if(re->scene->r.scemode & R_PREVIEWBUTS) + return; + + for (tex= G.main->tex.first; tex; tex= tex->id.next) { + if(tex->id.us && tex->type==TEX_VOXELDATA) { + free_voxeldata_one(re, tex); + } + } +} + +int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres) +{ + int retval = TEX_INT; + VoxelData *vd = tex->vd; + float vec[3] = {0.0, 0.0, 0.0}; + float co[3]; + float dx, dy, dz; + int xi, yi, zi; + float xf, yf, zf; + int i=0, fail=0; + int resolX, resolY, resolZ; + + if ((!vd) || (vd->dataset==NULL)) { + texres->tin = 0.0f; + return 0; + } + + //here do the calculation of the interpolation types + + resolX=vd->resolX; + resolY=vd->resolY; + resolZ=vd->resolZ; + + VECCOPY(co, texvec); + + dx=1.0f/(resolX); + dy=1.0f/(resolY); + dz=1.0f/(resolZ); + + xi=co[0]/dx; + yi=co[1]/dy; + zi=co[2]/dz; + + xf=co[0]/dx; + yf=co[1]/dy; + zf=co[2]/dz; + + if (xi>1 && xi1 && yi1 && ziinterp_type) + { + + case TEX_VD_NEARESTNEIGHBOR: + { + texres->tin = vd->dataset[_I(xi,yi,zi,resolX)]; + BRICONT; + break; + } + case TEX_VD_LINEAR: + { + texres->tin = Linear(xf,yf,zf,vd->dataset,resolX); + } + case TEX_VD_TRICUBIC: + { + texres->tin = tricubic(xf,yf,zf,vd->dataset,resolX); + } + + } + + + + } else fail++; + } else fail++; + } else fail++; + + if (fail) texres->tin=0.0f; + + texres->tin *= vd->int_multiplier; + + texres->tr = texres->tin; + texres->tg = texres->tin; + texres->tb = texres->tin; + texres->ta = texres->tin; + BRICONTRGB; + + return retval; +} + + From 5f55aa43d055883af35b7c91474e78e79c6fe352 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sun, 14 Dec 2008 02:22:29 +0000 Subject: [PATCH 71/88] * Compile fixes for voxeldata.c (thanks jms) * Fixed a typo in the patch that made trilinear interpolation really slow * Replaced the patch's trilinear interpolation code with the existing trilinear code from pbrt / light cache (first stage of unifying this voxel interpolation code) --- .../blender/render/intern/source/volumetric.c | 2 +- .../blender/render/intern/source/voxeldata.c | 80 +++++++++++++++---- 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index fba847da2ad..3206989d1d7 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -150,7 +150,7 @@ static float D(ShadeInput *shi, int rgb, int x, int y, int z) return shi->obi->volume_precache[rgb*res*res*res + x*res*res + y*res + z]; } -inline float lerp(float t, float v1, float v2) { +static inline float lerp(float t, float v1, float v2) { return (1.f - t) * v1 + t * v2; } diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index b2521e59b41..bffe30b7d80 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -44,7 +44,7 @@ #include "texture.h" /*---------------------------Utils----------------------------------------*/ -int _I(int x,int y,int z,int n) +static inline int _I(int x,int y,int z,int n) { return (z*(n)+y)*(n)+x; } @@ -67,6 +67,51 @@ float Linear(float xx,float yy,float zz,float *x0,int n) } + +static float D(float *data, const int res, int x, int y, int z) +{ + CLAMP(x, 0, res-1); + CLAMP(y, 0, res-1); + CLAMP(z, 0, res-1); + return data[ _I(x, y, z, res) ]; +} + +static inline float lerp(float t, float v1, float v2) { + return (1.f - t) * v1 + t * v2; +} + +/* trilinear interpolation */ +static float trilinear(float *data, const int res, float *co) +{ + float voxx, voxy, voxz; + int vx, vy, vz; + float dx, dy, dz; + float d00, d10, d01, d11, d0, d1, d_final; + float dim[3]; + + if (!data) return; + + voxx = co[0] * res - 0.5f; + voxy = co[1] * res - 0.5f; + voxz = co[2] * res - 0.5f; + + vx = (int)voxx; vy = (int)voxy; vz = (int)voxz; + + dx = voxx - vx; dy = voxy - vy; dz = voxz - vz; + + d00 = lerp(dx, D(data, res, vx, vy, vz), D(data, res, vx+1, vy, vz)); + d10 = lerp(dx, D(data, res, vx, vy+1, vz), D(data, res, vx+1, vy+1, vz)); + d01 = lerp(dx, D(data, res, vx, vy, vz+1), D(data, res, vx+1, vy, vz+1)); + d11 = lerp(dx, D(data, res, vx, vy+1, vz+1), D(data, res, vx+1, vy+1, vz+1)); + d0 = lerp(dy, d00, d10); + d1 = lerp(dy, d01, d11); + d_final = lerp(dz, d0, d1); + + return d_final; + +} + + int C[64][64] = { { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -196,14 +241,16 @@ float tricubic_eval(float a[64], float x, float y, float z) { float tricubic(float xx,float yy,float zz,float *heap,int n) { - int xi,yi,zi; + int xi,yi,zi; + float dx,dy,dz; + float a[64]; + if (xx<0.5) xx=0.5f; if (xx>n+0.5) xx=n+0.5f; xi=(int)xx; if (yy<0.5) yy=0.5f; if (yy>n+0.5) yy=n+0.5f; yi=(int)yy; if (zz<0.5) zz=0.5f; if (zz>n+0.5) zz=n+0.5f; zi=(int)zz; - float a[64]; - + { float fval[8]={heap[_I(xi,yi,zi,n)],heap[_I(xi+1,yi,zi,n)],heap[_I(xi,yi+1,zi,n)],heap[_I(xi+1,yi+1,zi,n)],heap[_I(xi,yi,zi+1,n)],heap[_I(xi+1,yi,zi+1,n)],heap[_I(xi,yi+1,zi+1,n)],heap[_I(xi+1,yi+1,zi+1,n)]}; float dfdxval[8]={0.5f*(heap[_I(xi+1,yi,zi,n)]-heap[_I(xi-1,yi,zi,n)]),0.5f*(heap[_I(xi+2,yi,zi,n)]-heap[_I(xi,yi,zi,n)]), @@ -261,12 +308,14 @@ float tricubic(float xx,float yy,float zz,float *heap,int n) 0.125f*(heap[_I(xi+2,yi+1,zi+2,n)]-heap[_I(xi,yi+1,zi+2,n)]-heap[_I(xi+2,yi-1,zi+2,n)]+heap[_I(xi,yi-1,zi+2,n)]-heap[_I(xi+2,yi+1,zi,n)]+heap[_I(xi,yi+1,zi,n)]+heap[_I(xi+2,yi-1,zi,n)]-heap[_I(xi,yi-1,zi,n)]), 0.125f*(heap[_I(xi+1,yi+2,zi+2,n)]-heap[_I(xi-1,yi+2,zi+2,n)]-heap[_I(xi+1,yi,zi+2,n)]+heap[_I(xi-1,yi,zi+2,n)]-heap[_I(xi+1,yi+2,zi,n)]+heap[_I(xi-1,yi+2,zi,n)]+heap[_I(xi+1,yi,zi,n)]-heap[_I(xi-1,yi,zi,n)]), 0.125f*(heap[_I(xi+2,yi+2,zi+2,n)]-heap[_I(xi,yi+2,zi+2,n)]-heap[_I(xi+2,yi,zi+2,n)]+heap[_I(xi,yi,zi+2,n)]-heap[_I(xi+2,yi+2,zi,n)]+heap[_I(xi,yi+2,zi,n)]+heap[_I(xi+2,yi,zi,n)]-heap[_I(xi,yi,zi,n)])}; + tricubic_get_coeff(a,fval,dfdxval,dfdyval,dfdzval,d2fdxdyval,d2fdxdzval,d2fdydzval,d3fdxdydzval); - - float dx=xx-xi; - float dy=yy-yi; - float dz=zz-zi; + } + + dx = xx-xi; + dy = yy-yi; + dz = zz-zi; return tricubic_eval(a,dx,dy,dz); @@ -390,7 +439,7 @@ int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres) xi=co[0]/dx; yi=co[1]/dy; zi=co[2]/dz; - + xf=co[0]/dx; yf=co[1]/dy; zf=co[2]/dz; @@ -401,29 +450,24 @@ int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres) { if (zi>1 && ziinterp_type) { - case TEX_VD_NEARESTNEIGHBOR: { texres->tin = vd->dataset[_I(xi,yi,zi,resolX)]; - BRICONT; break; } case TEX_VD_LINEAR: { - texres->tin = Linear(xf,yf,zf,vd->dataset,resolX); + texres->tin = trilinear(vd->dataset, resolX, co); + break; } case TEX_VD_TRICUBIC: { texres->tin = tricubic(xf,yf,zf,vd->dataset,resolX); + break; } - } - - - } else fail++; } else fail++; } else fail++; @@ -432,6 +476,8 @@ int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres) texres->tin *= vd->int_multiplier; + BRICONT; + texres->tr = texres->tin; texres->tg = texres->tin; texres->tb = texres->tin; From 7124d321d88240f14161c365ec1238ade2ec224d Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 15 Dec 2008 05:49:56 +0000 Subject: [PATCH 72/88] * msvc compile fix --- source/blender/render/intern/source/voxeldata.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index bffe30b7d80..2f0bbd44a7c 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -43,6 +43,10 @@ #include "renderdatabase.h" #include "texture.h" +#if defined( _MSC_VER ) && !defined( __cplusplus ) +# define inline __inline +#endif // defined( _MSC_VER ) && !defined( __cplusplus ) + /*---------------------------Utils----------------------------------------*/ static inline int _I(int x,int y,int z,int n) { From be1d06a2c544a4ea27139475a72edb75afa37879 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 22 Dec 2008 20:28:02 +0000 Subject: [PATCH 73/88] Volume rendering: * Multithreaded volume light cache While the render process itself is multithreaded, the light cache pre-process previously wasn't (painfully noticed this the other week rendering on some borrowed octocore nodes!). This commit adds threading, similar to the tiled render - it divides the light cache's voxel grid into 3d parts and renders them with the available threads. This makes the most significant difference on shots where the light cache pre- process is the bottleneck, so shots with either several lights, or a high res light cache, or both. On this file (3 lights, light cache res 120), on my Core 2 Duo it now renders in 27 seconds compared to 49 previously. http://mke3.net/blender/devel/rendering/volumetrics/threaded_cache.jpg --- .../render/intern/include/render_types.h | 26 +- .../render/intern/source/volume_precache.c | 325 ++++++++---------- 2 files changed, 168 insertions(+), 183 deletions(-) diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 65bb12e059d..8dbdde77726 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -202,9 +202,9 @@ struct Render struct Object *excludeob; - ListBase vol_precache_obs; ListBase render_volumes_inside; ListBase volumes; + ListBase volume_precache_parts; /* arena for allocating data for use during render, for * example dynamic TFaces to go in the VlakRen structure. @@ -404,13 +404,6 @@ typedef struct StrandRen { /* ------------------------------------------------------------------------- */ -typedef struct VolPrecache -{ - struct VolPrecache *next, *prev; - struct Material *ma; - struct ObjectRen *obr; -} VolPrecache; - typedef struct VolumeOb { struct VolumeOb *next, *prev; @@ -423,6 +416,23 @@ typedef struct MatInside { struct Material *ma; } MatInside; +typedef struct VolPrecachePart +{ + struct VolPrecachePart *next, *prev; + struct RayTree *tree; + struct ShadeInput *shi; + struct ObjectInstanceRen *obi; + int num; + int minx, maxx; + int miny, maxy; + int minz, maxz; + int res; + float bbmin[3]; + float voxel[3]; + int working, done; +} VolPrecachePart; + + /* ------------------------------------------------------------------------- */ struct LampRen; diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 89f997f4b99..18687962d79 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -35,6 +35,7 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" +#include "BLI_threads.h" #include "PIL_time.h" @@ -47,6 +48,9 @@ #include "renderdatabase.h" #include "volumetric.h" + +#include "BKE_global.h" + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ /* only to be used here in this file, it's for speed */ @@ -207,11 +211,7 @@ static void lightcache_filter(float *cache, int res) } } -/* 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; @@ -325,29 +325,20 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m } -#if 0 -typedef struct VolPrecachePart { - struct VolPrecachePart *next, *prev; - int num; - int minx, maxx; - int miny, maxy; - int minz, maxz; - int res; - float bbmin[3], voxel[3]; - struct RayTree *tree; - struct ShadeInput *shi; - struct ObjectInstanceRen *obi; - int done; -} VolPrecachePart; - +#if 0 // debug stuff static void *vol_precache_part_test(void *data) { - VolPrecachePart *vpt = (VolPrecachePart *)data; + VolPrecachePart *pa = data; - printf("part number: %d \n", vpt->num); + printf("part number: %d \n", pa->num); + printf("done: %d \n", pa->done); + printf("x min: %d x max: %d \n", pa->minx, pa->maxx); + printf("y min: %d y max: %d \n", pa->miny, pa->maxy); + printf("z min: %d z max: %d \n", pa->minz, pa->maxz); - return 0; + return NULL; } +#endif /* Iterate over the 3d voxel grid, and fill the voxels with scattering information * @@ -357,28 +348,24 @@ static void *vol_precache_part_test(void *data) */ static void *vol_precache_part(void *data) { - VolPrecachePart *vpt = (VolPrecachePart *)data; - ObjectInstanceRen *obi = vpt->obi; - RayTree *tree = vpt->tree; - ShadeInput *shi = vpt->shi; - float scatter_col[3] = {0.f, 0.f, 0.f}; + VolPrecachePart *pa = (VolPrecachePart *)data; + ObjectInstanceRen *obi = pa->obi; + RayTree *tree = pa->tree; + ShadeInput *shi = pa->shi; + float density, scatter_col[3] = {0.f, 0.f, 0.f}; float co[3]; int x, y, z; - const int res=vpt->res, res_2=vpt->res*vpt->res, res_3=vpt->res*vpt->res*vpt->res; + const int res=pa->res, res_2=pa->res*pa->res, res_3=pa->res*pa->res*pa->res; const float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW); - - res = vpt->res; - res_2 = res*res; - res_3 = res*res*res; - - for (x= vpt->minx; x < vpt->maxx; x++) { - co[0] = vpt->bbmin[0] + (vpt->voxel[0] * x); + + for (x= pa->minx; x < pa->maxx; x++) { + co[0] = pa->bbmin[0] + (pa->voxel[0] * x); - for (y= vpt->miny; y < vpt->maxy; y++) { - co[1] = vpt->bbmin[1] + (vpt->voxel[1] * y); + for (y= pa->miny; y < pa->maxy; y++) { + co[1] = pa->bbmin[1] + (pa->voxel[1] * y); - for (z=vpt->minz; z < vpt->maxz; z++) { - co[2] = vpt->bbmin[2] + (vpt->voxel[2] * z); + for (z=pa->minz; z < pa->maxz; z++) { + co[2] = pa->bbmin[2] + (pa->voxel[2] * z); // don't bother if the point is not inside the volume mesh if (!point_inside_obi(tree, obi, co)) { @@ -397,14 +384,17 @@ static void *vol_precache_part(void *data) } } + pa->done = 1; + return 0; } + static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi) { float view[3] = {0.0,0.0,-1.0}; - memset(&shi, 0, sizeof(ShadeInput)); + memset(shi, 0, sizeof(ShadeInput)); shi->depth= 1; shi->mask= 1; shi->mat = ma; @@ -417,61 +407,102 @@ static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Materi VECCOPY(shi->view, view); } -static void precache_init_parts(ListBase *precache_parts, RayTree *tree, ShadeInput *shi, ObjectInstanceRen *obi, float *bbmin, float *bbmax, int res) +static void precache_init_parts(Render *re, RayTree *tree, ShadeInput *shi, ObjectInstanceRen *obi, float *bbmin, float *bbmax, int res, int totthread, int *parts) { - int i; + int i=0, x, y, z; float voxel[3]; - + int sizex, sizey, sizez; + int minx, maxx; + int miny, maxy; + int minz, maxz; + + BLI_freelistN(&re->volume_precache_parts); + + /* currently we just subdivide the box, number of threads per side */ + parts[0] = parts[1] = parts[2] = totthread; + 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; + for (x=0; x < parts[0]; x++) { + sizex = ceil(res / (float)parts[0]); + minx = x * sizex; + maxx = minx + sizex; + maxx = (maxx>res)?res:maxx; - 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); + for (y=0; y < parts[1]; y++) { + sizey = ceil(res / (float)parts[1]); + miny = y * sizey; + maxy = miny + sizey; + maxy = (maxy>res)?res:maxy; + + for (z=0; z < parts[2]; z++) { + VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part"); + + sizez = ceil(res / (float)parts[2]); + minz = z * sizez; + maxz = minz + sizez; + maxz = (maxz>res)?res:maxz; + + pa->done = 0; + pa->working = 0; + + pa->num = i; + pa->tree = tree; + pa->shi = shi; + pa->obi = obi; + VECCOPY(pa->bbmin, bbmin); + VECCOPY(pa->voxel, voxel); + pa->res = res; + + pa->minx = minx; pa->maxx = maxx; + pa->miny = miny; pa->maxy = maxy; + pa->minz = minz; pa->maxz = maxz; + + + BLI_addtail(&re->volume_precache_parts, pa); + + i++; + } + } } - } +static VolPrecachePart *precache_get_new_part(Render *re) +{ + VolPrecachePart *pa, *nextpa=NULL; + + for (pa = re->volume_precache_parts.first; pa; pa=pa->next) + { + if (pa->done==0 && pa->working==0) { + nextpa = pa; + break; + } + } + + return nextpa; +} + +/* 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_threads(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 density; - float stepsize; - - float resf, res_3f; - int res_2, res_3; - - int edgeparts=2; - ListBase threads, precache_parts; - int cont= 1; - int xparts, yparts, zparts; - float part[3]; - int totthread = re->r.threads; - int totparts = edgeparts*edgeparts*edgeparts; - VolPrecachePart *nextpa; - int j; - - float i = 1.0f; - double time, lasttime= PIL_check_seconds_timer(); - const int res = ma->vol_precache_resolution; + VolPrecachePart *nextpa, *pa; RayTree *tree; + ShadeInput shi; + ListBase threads; + const int res = ma->vol_precache_resolution; + int parts[3], totparts; + + int caching=1, counter=0; + int totthread = re->r.threads; + + double time, lasttime= PIL_check_seconds_timer(); R = *re; @@ -480,119 +511,62 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat tree = create_raytree_obi(obi, bbmin, bbmax); if (!tree) return; - obi->volume_precache = MEM_callocN(sizeof(float)*res_3*3, "volume light cache"); + obi->volume_precache = MEM_callocN(sizeof(float)*res*res*res*3, "volume light cache"); /* Need a shadeinput to calculate scattering */ precache_setup_shadeinput(re, obi, ma, &shi); - precache_init_parts(&precache_parts, tree, shi, obi, bbmin, bbmax, res); - + + precache_init_parts(re, tree, &shi, obi, bbmin, bbmax, res, totthread, parts); + totparts = parts[0] * parts[1] * parts[2]; + BLI_init_threads(&threads, vol_precache_part, totthread); - nextpa = precache_get_new_part(precache_threads); - - while(cont) { + while(caching) { if(BLI_available_threads(&threads) && !(re->test_break())) { - - precache_get_new_part( - // get new job (data pointer) - for(j=0; j < totparts; j++) { - if (!precache_threads[j].done) { - // tag job 'processed - precache_threads[j].done = 1; - } + nextpa = precache_get_new_part(re); + if (nextpa) { + nextpa->working = 1; + BLI_insert_thread(&threads, nextpa); } - - BLI_insert_thread(&threads, precache_get_new_part(precache_threads)); } else PIL_sleep_ms(50); - // find if a job is ready, this the do_something_func() should write in job somewhere - cont= 0; - for(go over all jobs) - if(job is ready) { - if(job was not removed) { - BLI_remove_thread(&lb, job); - } - } - else cont= 1; + caching=0; + counter=0; + for(pa= re->volume_precache_parts.first; pa; pa= pa->next) { + + if(pa->done) { + counter++; + BLI_remove_thread(&threads, pa); + } else + caching = 1; } - // conditions to exit loop - if(if escape loop event) { - if(BLI_available_threadslots(&lb)==maxthreads) - break; - } - } - - BLI_end_threads(&threads); - - // - - /* 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); - for (y=0; y < res; y++) { - co[1] = bbmin[1] + (voxel[1] * y); - - for (z=0; z < res; z++) { - co[2] = bbmin[2] + (voxel[2] * z); - - time= PIL_check_seconds_timer(); - i++; - - // display progress every second - if(re->test_break()) { - if(tree) { - RE_ray_tree_free(tree); - tree= NULL; - } - return; - } - if(time-lasttime>1.0f) { - char str[64]; - 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; - } - - // don't bother if the point is not inside the volume mesh - - if (!point_inside_obi(tree, obi, co)) { - obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; - obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = -1.0f; - obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; - 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 (re->test_break() && BLI_available_threads(&threads)==totthread) + caching=0; + + time= PIL_check_seconds_timer(); + if(time-lasttime>1.0f) { + char str[64]; + sprintf(str, "Precaching volume: %d%%", (int)(100.0f * ((float)counter / (float)totparts))); + re->i.infostr= str; + re->stats_draw(&re->i); + re->i.infostr= NULL; + lasttime= time; } } - */ - + + BLI_end_threads(&threads); + BLI_freelistN(&re->volume_precache_parts); + if(tree) { RE_ray_tree_free(tree); tree= NULL; } lightcache_filter(obi->volume_precache, res); - } -#endif /* loop through all objects (and their associated materials) * marked for pre-caching in convertblender.c, and pre-cache them */ @@ -605,7 +579,8 @@ void volume_precache(Render *re) 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]); + if (G.rt==10) vol_precache_objectinstance(re, obi, vo->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]); + else vol_precache_objectinstance_threads(re, obi, vo->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]); } } } @@ -624,7 +599,7 @@ void free_volume_precache(Render *re) MEM_freeN(obi->volume_precache); } - BLI_freelistN(&re->vol_precache_obs); + BLI_freelistN(&re->volumes); } int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co) From 834fda50d99210a5a69360bbed84f76934792171 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 31 Dec 2008 05:08:04 +0000 Subject: [PATCH 74/88] Volume rendering * Fixed an old problem where if both the camera and a solid surface were inside a volume, the volume wouldn't attenuate in front of the surface (was visible in the blender conference art festival clouds animation: http://mke3.net/blender/devel/rendering/volumetrics/vol_shade_cam_inside.mov * Initial support for refracting solids inside volumes. I might be able to make this work better, but not sure at the moment. It's a bit dodgy, limited by the code that does the recursive ray shading - it's really not set up for this kind of thing and could use a refactor very much. --- .../render/intern/include/volumetric.h | 10 ++- .../blender/render/intern/source/rayshade.c | 20 ++++-- .../blender/render/intern/source/shadeinput.c | 23 +++---- .../blender/render/intern/source/volumetric.c | 61 ++++++++++++++++--- 4 files changed, 87 insertions(+), 27 deletions(-) diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h index a69238f54b3..40d79e8d173 100644 --- a/source/blender/render/intern/include/volumetric.h +++ b/source/blender/render/intern/include/volumetric.h @@ -30,8 +30,9 @@ float vol_get_stepsize(struct ShadeInput *shi, int context); float vol_get_density(struct ShadeInput *shi, float *co); void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsize, float density); -void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr); -void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is); +void shade_volume_outside(ShadeInput *shi, ShadeResult *shr); +void shade_volume_inside(ShadeInput *shi, ShadeResult *shr); +void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is); #define STEPSIZE_VIEW 0 #define STEPSIZE_SHADE 1 @@ -40,4 +41,7 @@ void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct #define VOL_IS_SAMEMATERIAL 2 #define VOL_BOUNDS_DEPTH 0 -#define VOL_BOUNDS_SS 1 \ No newline at end of file +#define VOL_BOUNDS_SS 1 + +#define VOL_SHADE_OUTSIDE 0 +#define VOL_SHADE_INSIDE 1 \ No newline at end of file diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 8bbdb243c8a..d09bd5c707a 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -276,9 +276,9 @@ void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) if (shi->mat->material_type == MA_VOLUME) { if(ELEM(is->mode, RE_RAY_SHADOW, RE_RAY_SHADOW_TRA)) { - volume_trace_shadow(shi, shr, is); + shade_volume_shadow(shi, shr, is); } else { - shade_volume_loop(shi, shr); + shade_volume_outside(shi, shr); } } else if(is->mode==RE_RAY_SHADOW_TRA) @@ -295,7 +295,18 @@ void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ } else { - shade_material_loop(shi, shr); + int tempdepth; + /* XXX dodgy business here, set ray depth to -1 + * to ignore raytrace in shade_material_loop() + * this could really use a refactor --Matt */ + if (shi->volume_depth == 0) { + tempdepth = shi->depth; + shi->depth = -1; + shade_material_loop(shi, shr); + shi->depth = tempdepth; + } else { + shade_material_loop(shi, shr); + } } /* raytrace likes to separate the spec color */ VECSUB(shr->diff, shr->combined, shr->spec); @@ -467,7 +478,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo shi.mask= origshi->mask; shi.osatex= origshi->osatex; - shi.depth= 1; /* only used to indicate tracing */ + shi.depth = origshi->depth + 1; /* only used to indicate tracing */ shi.thread= origshi->thread; //shi.sample= 0; // memset above, so dont need this shi.xs= origshi->xs; @@ -482,6 +493,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo memset(&shr, 0, sizeof(ShadeResult)); shade_ray(&isec, &shi, &shr); + if (traflag & RAY_TRA) d= shade_by_transmission(&isec, &shi, &shr); diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index aa11e3d75dd..5bf2f58ae4e 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -121,7 +121,7 @@ void shade_material_loop(ShadeInput *shi, ShadeResult *shr) } /* depth >= 1 when ray-shading */ - if(shi->depth==0) { + if(shi->depth >= 0 && (shi->depth < MAX2(shi->mat->ray_depth_tra, shi->mat->ray_depth))) { if(R.r.mode & R_RAYTRACE) { if(shi->ray_mirror!=0.0f || ((shi->mat->mode & MA_RAYTRANSP) && shr->alpha!=1.0f)) { /* ray trace works on combined, but gives pass info */ @@ -132,16 +132,13 @@ void shade_material_loop(ShadeInput *shi, ShadeResult *shr) if(shi->mat->mode & MA_RAYTRANSP) if((shi->layflag & SCE_LAY_SKY) && (R.r.alphamode==R_ADDSKY)) shr->alpha= 1.0f; - } + } + + if(R.r.mode & R_RAYTRACE) { + shade_volume_inside(shi, shr); + } } -/* delivers a fully filled in ShadeResult, for all passes */ -void shade_volume_loop(ShadeInput *shi, ShadeResult *shr) -{ - if(R.r.mode & R_RAYTRACE) volume_trace(shi, shr); -} - - /* do a shade, finish up some passes, apply mist */ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) { @@ -157,8 +154,12 @@ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); shi->har= shi->mat->har; - if (shi->mat->material_type == MA_SOLID) shade_material_loop(shi, shr); - else if (shi->mat->material_type == MA_VOLUME) shade_volume_loop(shi, shr); + if (shi->mat->material_type == MA_SOLID) { + shade_material_loop(shi, shr); + } else if (shi->mat->material_type == MA_VOLUME) { + if(R.r.mode & R_RAYTRACE) + shade_volume_outside(shi, shr); + } } /* copy additional passes */ diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 3206989d1d7..10a3f83758c 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -548,7 +548,7 @@ static void shade_intersection(ShadeInput *shi, float *col, Isect *is) shi_new.mask= shi->mask; shi_new.osatex= shi->osatex; shi_new.thread= shi->thread; - shi_new.depth= 1; + shi_new.depth = shi->depth + 1; shi_new.volume_depth= shi->volume_depth + 1; shi_new.xs= shi->xs; shi_new.ys= shi->ys; @@ -601,18 +601,31 @@ 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) +static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume) { float hitco[3], col[4] = {0.f,0.f,0.f,0.f}; + int trace_behind = 1; Isect is; - memset(shr, 0, sizeof(ShadeResult)); + /* check for shading an internal face a volume object directly */ + if (inside_volume == VOL_SHADE_INSIDE) { + trace_behind = 0; + } + if (inside_volume == VOL_SHADE_OUTSIDE) { + if (shi->flippednor) + inside_volume = VOL_SHADE_INSIDE; + } - /* if 1st hit normal is facing away from the camera, - * then we're inside the volume already. */ - if (shi->flippednor) { - /* trace behind the 1st hit point */ - vol_trace_behind(shi, shi->vlr, shi->co, col); + if (inside_volume == VOL_SHADE_INSIDE) { + + if (trace_behind) { + /* trace behind the volume object */ + vol_trace_behind(shi, shi->vlr, shi->co, col); + } else { + /* we're tracing through the volume between the camera + * and a solid surface, so use that pre-shaded radiance */ + QUATCOPY(col, shr->combined); + } /* shade volume from 'camera' to 1st hit point */ volumeintegrate(shi, col, shi->camera_co, shi->co); @@ -673,7 +686,7 @@ 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) +void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is) { float hitco[3]; float tr[3] = {1.0,1.0,1.0}; @@ -724,3 +737,33 @@ void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct } } + +/* delivers a fully filled in ShadeResult, for all passes */ +void shade_volume_outside(ShadeInput *shi, ShadeResult *shr) +{ + memset(shr, 0, sizeof(ShadeResult)); + + volume_trace(shi, shr, VOL_SHADE_OUTSIDE); +} + + +void shade_volume_inside(ShadeInput *shi, ShadeResult *shr) +{ + MatInside *m; + Material *mat_backup; + + if (BLI_countlist(&R.render_volumes_inside) == 0) return; + + mat_backup = shi->mat; + +// for (m=R.render_volumes_inside.first; m; m=m->next) { +// printf("matinside: ma: %s \n", m->ma->id.name+2); +// } + + m = R.render_volumes_inside.first; + shi->mat = m->ma; + + volume_trace(shi, shr, VOL_SHADE_INSIDE); + + shi->mat = mat_backup; +} \ No newline at end of file From 0572f1a5f61c96c44e81af5a49d9f1f01e9c9b69 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 8 Jan 2009 22:49:03 +0000 Subject: [PATCH 75/88] * fixed an incredibly silly typo-bug in light cache --- source/blender/render/intern/source/volume_precache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 18687962d79..75759b651ed 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -204,7 +204,7 @@ static void lightcache_filter(float *cache, int res) i = rgb*res_3 + x*res_2 + y*res + z; /* trigger for outside mesh */ - if (cache[i] < 0.5f) cache[i] = get_avg_surrounds(cache, res, res_2, res_3, rgb, x, y, z); + if (cache[i] < -0.5f) cache[i] = get_avg_surrounds(cache, res, res_2, res_3, rgb, x, y, z); } } } From 6cfbb0017a525262f55767bf3b560ba3ae2e8d42 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 13 Jan 2009 02:39:46 +0000 Subject: [PATCH 76/88] * Little feature, blend texture can have extrapolation modes (like repeat). This should probably go in trunk, but I'll stay away for now with all the 2.5 work on. --- source/blender/blenkernel/BKE_blender.h | 2 +- source/blender/blenloader/intern/readfile.c | 11 ++++++++++- source/blender/render/intern/source/texture.c | 17 +++++++++++++++++ source/blender/src/buttons_shading.c | 6 ++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index f392d57521c..db6d4762b17 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -41,7 +41,7 @@ struct ListBase; struct MemFile; #define BLENDER_VERSION 248 -#define BLENDER_SUBVERSION 1 +#define BLENDER_SUBVERSION 3 #define BLENDER_MINVERSION 245 #define BLENDER_MINSUBVERSION 15 diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 8347920319a..35e4c8b915c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7975,7 +7975,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) tex->vd->int_multiplier = 1.0; } } - } /* set the curve radius interpolation to 2.47 default - easy */ @@ -8074,6 +8073,16 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } + if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 3)) { + Tex *tex; + + /* blend texture extrapolation */ + for(tex=main->tex.first; tex; tex= tex->id.next) { + if (tex->type == TEX_BLEND) + tex->extend = TEX_EXTEND; + } + } + /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */ diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index d7b41d7cc2c..e5e8a285f28 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -197,6 +197,23 @@ static int blend(Tex *tex, float *texvec, TexResult *texres) y= texvec[1]; } + if (tex->extend == TEX_REPEAT) { + if (x < -1.0 || x > 1.0) { + const float x2 = (x + 1.0)* 0.5; /* to 0.0, 1.0 */ + x = (x2 - floor(x2) - 0.5) * 2.0; /* to -1.0, 1.0 */ + } + if (y < -1.0 || y > 1.0) { + const float y2 = (y + 1.0)* 0.5; /* to 0.0, 1.0 */ + y = (y2 - floor(y2) - 0.5) * 2.0; /* to -1.0, 1.0 */ + } + } else if (tex->extend == TEX_CLIP) { + if (x < -1.0 || x > 1.0 || y < -1.0 || y > 1.0) { + texres->tin = 0.f; + BRICONT; + return TEX_INT; + } + } + if(tex->stype==TEX_LIN) { /* lin */ texres->tin= (1.0+x)/2.0; } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 6e69414fbe0..4f6a25058c3 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -644,7 +644,13 @@ static void texture_panel_blend(Tex *tex) uiDefButS(block, ROW, B_TEXPRV, "Sphere", 85, 160, 75, 19, &tex->stype, 2.0, (float)TEX_SPHERE, 0, 0, "Use progression with the shape of a sphere"); uiDefButS(block, ROW, B_TEXPRV, "Halo", 160, 160, 75, 19, &tex->stype, 2.0, (float)TEX_HALO, 0, 0, "Use a quadratic progression with the shape of a sphere"); uiDefButS(block, ROW, B_TEXPRV, "Radial", 235, 160, 75, 19, &tex->stype, 2.0, (float)TEX_RAD, 0, 0, "Use a polar progression"); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); + uiDefButS(block, ROW, B_TEXREDR_PRV, "Extend", 10,120,63,19, &tex->extend, 4.0, 1.0, 0, 0, "Extends the color of the edge pixels"); + uiDefButS(block, ROW, B_TEXREDR_PRV, "Clip", 73,120,48,19, &tex->extend, 4.0, 2.0, 0, 0, "Sets alpha 0.0 outside Image edges"); + uiDefButS(block, ROW, B_TEXREDR_PRV, "Repeat", 121,120,63,19, &tex->extend, 4.0, 3.0, 0, 0, "Causes Image to repeat horizontally and vertically"); + uiBlockEndAlign(block); } /* newnoise: noisebasis menu string */ From 1ed26fffb88ffcf70aa62c65964cc98348712b9d Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 26 Jan 2009 02:42:17 +0000 Subject: [PATCH 77/88] Volume rendering: multiple scattering This is mostly a contribution from Raul 'farsthary' Hernandez - an approximation for multiple scattering within volumes. Thanks, Raul! Where single scattering considers the path from the light to a point in the volume, and to the eye, multiple scattering approximates the interactions of light as it bounces around randomly within the volume, before eventually reaching the eye. It works as a diffusion process that effectively blurs the lighting information that's already stored within the light cache. A cloudy sky setup, with single scattering, and multiple scattering: http://mke3.net/blender/devel/rendering/volumetrics/vol_sky_ss_ms.jpg http://mke3.net/blender/devel/rendering/volumetrics/sky_ms.blend To enable it, there is a menu in the volume panel (which needs a bit of cleanup, for later), that lets you choose between self-shading methods: * None: No attenuation of the light source by the volume - light passes straight through at full strength * Single Scattering: (same as previously, with 'self-shading' enabled) * Multiple Scattering: Uses multiple scattering only for shading information * Single + Multiple: Adds the multiple scattering lighting on top of the existing single scattered light - this can be useful to tweak the strength of the effect, while still retaining details in the lighting. An example of how the different scattering methods affect the visual result: http://mke3.net/blender/devel/rendering/volumetrics/ss_ms_comparison.jpg http://mke3.net/blender/devel/rendering/volumetrics/ss_ms_comparison.blend The multiple scattering methods introduce 3 new controls when enabled: * Blur: A factor blending between fully diffuse/blurred lighting, and sharper * Spread: The range that the diffuse blurred lighting spreads over - similar to a blur width. The higher the spread, the slower the processing time. * Intensity: A multiplier for the multiple scattering light brightness Here's the effect of multiple scattering on a tight beam (similar to a laser). The effect of the 'spread' value is pretty clear here: http://mke3.net/blender/devel/rendering/volumetrics/ms_spread_laser.jpg Unlike the rest of the system so far, this part of the volume rendering engine isn't physically based, and currently it's not unusual to get non-physical results (i.e. much more light being scattered out then goes in via lamps or emit). To counter this, you can use the intensity slider to tweak the brightness - on the todo, perhaps there is a more automatic method we can work on for this later on. I'd also like to check on speeding this up further with threading too. --- source/blender/blenloader/intern/readfile.c | 14 +- source/blender/makesdna/DNA_material_types.h | 14 +- .../render/intern/include/volume_precache.h | 4 +- .../render/intern/source/volume_precache.c | 229 ++++++++++-------- .../blender/render/intern/source/volumetric.c | 10 +- source/blender/src/buttons_shading.c | 62 ++++- 6 files changed, 212 insertions(+), 121 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 35e4c8b915c..7993d2eec89 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8072,17 +8072,27 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } } - + if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 3)) { Tex *tex; + Material *ma; /* blend texture extrapolation */ for(tex=main->tex.first; tex; tex= tex->id.next) { if (tex->type == TEX_BLEND) tex->extend = TEX_EXTEND; } + + for(ma=main->mat.first; ma; ma= ma->id.next) { + if (ma->vol_shadeflag & 2) { // old MA_VOL_ATTENUATED + ma->vol_shade_type = MA_VOL_SHADE_SINGLE; + ma->vol_ms_diff = 0.5f; + ma->vol_ms_steps = 5; + ma->vol_ms_intensity = 1.0; + } + } } - + /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */ diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 5172f6a970c..dafa816cb96 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -70,13 +70,18 @@ typedef struct Material { short vol_precache_resolution; float vol_stepsize, vol_shade_stepsize; float vol_depth_cutoff; - float vpad; + short vol_shade_type; + short vpad; float vol_density_scale; float vol_absorption, vol_scattering; float vol_absorption_col[3]; short vol_shadeflag; short vol_phasefunc_type; float vol_phasefunc_g; + float vpad2; + + float vol_ms_diff, vol_ms_intensity; + int vol_ms_steps; float fresnel_mir, fresnel_mir_i; float fresnel_tra, fresnel_tra_i; @@ -358,11 +363,16 @@ typedef struct Material { /* vol_shadeflag */ #define MA_VOL_SHADED 1 -#define MA_VOL_ATTENUATED 2 #define MA_VOL_RECVSHADOW 4 #define MA_VOL_PRECACHESHADING 8 #define MA_VOL_USEALPHA 16 +/* 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 + /* vol_phasefunc_type */ #define MA_VOL_PH_ISOTROPIC 0 #define MA_VOL_PH_MIEHAZY 1 diff --git a/source/blender/render/intern/include/volume_precache.h b/source/blender/render/intern/include/volume_precache.h index 78409e4c646..9d87a219c82 100644 --- a/source/blender/render/intern/include/volume_precache.h +++ b/source/blender/render/intern/include/volume_precache.h @@ -28,4 +28,6 @@ void volume_precache(Render *re); void free_volume_precache(Render *re); -int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co); \ No newline at end of file +int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co); + +#define VOL_MS_TIMESTEP 0.1f \ No newline at end of file diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 75759b651ed..4cdffc5ad35 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -47,6 +47,7 @@ #include "render_types.h" #include "renderdatabase.h" #include "volumetric.h" +#include "volume_precache.h" #include "BKE_global.h" @@ -211,120 +212,141 @@ static void lightcache_filter(float *cache, int res) } } +static inline int I(int x,int y,int z,int n) //has a pad of 1 voxel surrounding the core for boundary simulation +{ + return (x*(n+2)+y)*(n+2)+z; +} -void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *ma, float *bbmin, float *bbmax) +static void ms_diffuse(int b, float* x0, float* x, float diff, int n) { - int x, y, z; + int i, j, k, l; + const float dt = VOL_MS_TIMESTEP; + const float a = dt*diff*n*n*n; + + for (l=0; l<20; l++) + { + for (k=1; k<=n; k++) + { + for (j=1; j<=n; j++) + { + for (i=1; i<=n; i++) + { + x[I(i,j,k,n)] = (x0[I(i,j,k,n)] + a*( + x[I(i-1,j,k,n)]+x[I(i+1,j,k,n)]+ + x[I(i,j-1,k,n)]+x[I(i,j+1,k,n)]+ + x[I(i,j,k-1,n)]+x[I(i,j,k+1,n)]))/(1+6*a); + } + } + } + } +} - 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, res_3f; - int res_2, res_3; - - float i = 1.0f; +void multiple_scattering_diffusion(Render *re, float *cache, int res, Material *ma) +{ + const float diff = ma->vol_ms_diff * 0.001f; /* compensate for scaling for a nicer UI range */ + const float fac = ma->vol_ms_intensity; + const float simframes = ma->vol_ms_steps; + const int shade_type = ma->vol_shade_type; + const float dt = VOL_MS_TIMESTEP; + + int i, j, k, m; + int n = res; + const int size = (n+2)*(n+2)*(n+2); double time, lasttime= PIL_check_seconds_timer(); - const int res = ma->vol_precache_resolution; - RayTree *tree; + float total; + float c=1.0f; + int index; + float origf; /* factor for blending in original light cache */ - R = *re; + + float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sg=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); - /* create a raytree with just the faces of the instanced ObjectRen, - * used for checking if the cached point is inside or outside. */ - tree = create_raytree_obi(obi, bbmin, bbmax); - if (!tree) return; + total = (float)(n*n*n*simframes); + + /* Scattering as diffusion pass */ + for (m=0; m 0.0f) + sr[I(i,j,k,n)] += cache[index]; + if (cache[1*n*n*n + index] > 0.0f) + sg[I(i,j,k,n)] += cache[1*n*n*n + index]; + if (cache[2*n*n*n + index] > 0.0f) + sb[I(i,j,k,n)] += cache[2*n*n*n + index]; - /* Need a shadeinput to calculate scattering */ - memset(&shi, 0, sizeof(ShadeInput)); - shi.depth= 1; - shi.mask= 1; - shi.mat = ma; - shi.vlr = NULL; - memcpy(&shi.r, &shi.mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h - shi.har= shi.mat->har; - shi.obi= obi; - shi.obr= obi->obr; - shi.lay = re->scene->lay; - VECCOPY(shi.view, view); - - stepsize = vol_get_stepsize(&shi, STEPSIZE_VIEW); - resf = (float)res; - res_2 = res*res; - res_3 = res*res*res; - res_3f = (float)res_3; - - VecSubf(voxel, bbmax, bbmin); - if ((voxel[0] < FLT_EPSILON) || (voxel[1] < FLT_EPSILON) || (voxel[2] < FLT_EPSILON)) - return; - VecMulf(voxel, 1.0f/res); - - 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); - - for (y=0; y < res; y++) { - co[1] = bbmin[1] + (voxel[1] * y); - - for (z=0; z < res; z++) { - co[2] = bbmin[2] + (voxel[2] * z); - - time= PIL_check_seconds_timer(); - i++; - - /* display progress every second */ - if(re->test_break()) { - if(tree) { - RE_ray_tree_free(tree); - tree= NULL; + /* Displays progress every second */ + if(time-lasttime>1.0f) { + char str[64]; + sprintf(str, "Simulating multiple scattering: %d%%", (int) + (100.0f * (c / total))); + re->i.infostr= str; + re->stats_draw(&re->i); + re->i.infostr= NULL; + lasttime= time; } - return; } - if(time-lasttime>1.0f) { - char str[64]; - 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; - } - - /* don't bother if the point is not inside the volume mesh */ - if (!point_inside_obi(tree, obi, co)) { - obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; - obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = -1.0f; - obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; - 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]; + } + } + SWAP(float *, sr, sr0); + SWAP(float *, sg, sg0); + SWAP(float *, sb, sb0); + + /* main diffusion simulation */ + ms_diffuse(0, sr0, sr, diff, n); + ms_diffuse(0, sg0, sg, diff, n); + ms_diffuse(0, sb0, sb, diff, n); + + if (re->test_break()) break; + } + + /* copy to light cache */ + + if (shade_type == MA_VOL_SHADE_SINGLEPLUSMULTIPLE) + origf = 1.0f; + else + origf = 0.0f; + + for (k=1;k<=n;k++) + { + for (j=1;j<=n;j++) + { + for (i=1;i<=n;i++) + { + index=(i-1)*n*n + (j-1)*n + k-1; + cache[index] = origf * cache[index] + fac * sr[I(i,j,k,n)]; + cache[1*n*n*n + index] = origf * cache[1*n*n*n + index] + fac * sg[I(i,j,k,n)]; + cache[2*n*n*n + index] = origf * cache[2*n*n*n + index] + fac * sb[I(i,j,k,n)]; } } } - if(tree) { - RE_ray_tree_free(tree); - tree= NULL; - } - - lightcache_filter(obi->volume_precache, res); - + MEM_freeN(sr0); + MEM_freeN(sr); + MEM_freeN(sg0); + MEM_freeN(sg); + MEM_freeN(sb0); + MEM_freeN(sb); } + + #if 0 // debug stuff static void *vol_precache_part_test(void *data) { @@ -566,6 +588,11 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat } lightcache_filter(obi->volume_precache, res); + + if (ELEM(ma->vol_shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE)) + { + multiple_scattering_diffusion(re, obi->volume_precache, res, ma); + } } /* loop through all objects (and their associated materials) @@ -575,12 +602,14 @@ void volume_precache(Render *re) ObjectInstanceRen *obi; VolumeOb *vo; + /* ignore light cache and multiple scattering for preview render .. for now? */ + if (re->r.scemode & R_PREVIEWBUTS) return; + 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) { - if (G.rt==10) vol_precache_objectinstance(re, obi, vo->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]); - else vol_precache_objectinstance_threads(re, obi, vo->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]); + vol_precache_objectinstance_threads(re, obi, vo->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]); } } } diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 10a3f83758c..c8361844e11 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -379,7 +379,7 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * p = vol_get_phasefunc(shi, shi->mat->vol_phasefunc_type, shi->mat->vol_phasefunc_g, shi->view, lv); VecMulf(lacol, p); - if (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED) { + if (shi->mat->vol_shade_type != MA_VOL_SHADE_NONE) { Isect is; /* find minimum of volume bounds, or lamp coord */ @@ -511,8 +511,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->mat->vol_shadeflag & MA_VOL_ATTENUATED)) { + + if (R.r.scemode & R_PREVIEWBUTS) { + vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); + } else if (((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) && + (shi->mat->vol_shade_type == MA_VOL_SHADE_SINGLE)) || + (ELEM(shi->mat->vol_shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE))) { vol_get_precached_scattering(shi, scatter_col, step_mid); } else vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 4f6a25058c3..658b79f99fb 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -4534,23 +4534,59 @@ static void material_panel_material_volume(Material *ma) yco -= YSPACE; + uiDefBut(block, LABEL, B_NOP, "Self Shading:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + 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"); - uiBlockEndAlign(block); + uiDefButS(block, MENU, B_TEXREDR_PRV, "Self Shading %t|None %x0|Single Scattering %x1|Multiple Scattering %x2|Single + Multiple %x3", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &ma->vol_shade_type, 0.0, 0.0, 0, 0, "Use absorbtion to attenuate light - Single scattering: direct lighting, Multiple scattering: internal light bouncing & diffusion"); + + if (ELEM3(ma->vol_shade_type, MA_VOL_SHADE_SINGLE, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE)) + { + uiDefButF(block, NUM, B_MATPRV, "Step Size: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shade_stepsize), 0.001, 100.0, 10, 2, "Step"); - yco -= YSPACE; - - 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); + + yco -= YSPACE; + + if (ma->vol_shade_type == MA_VOL_SHADE_SINGLE) + { + 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, speeds up shading at slightly less accuracy"); + 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)"); + + } + else if (ELEM(ma->vol_shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE)) + { + uiDefBut(block, LABEL, B_NOP, "Light Cache:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + 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); + + yco -= YSPACE; + + if (ELEM(ma->vol_shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE)) { + uiDefBut(block, LABEL, B_NOP, "Multiple Scattering:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_MATPRV, "Blur: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_ms_diff), 0.01, 1.0, 10, 2, "Diffusion factor, the strength of the blurring effect"); + uiDefButI(block, NUM, B_MATPRV, "Spread: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_ms_steps), 1, 512.0, 10, 2, "Simulation steps, the effective distance over which the light is diffused"); + uiDefButF(block, NUM, B_MATPRV, "Intensity: ", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_ms_intensity), 0.00001, 1024.0, 10, 2, "Multiplier for multiple scattered light energy"); + uiBlockEndAlign(block); + } } + uiBlockEndAlign(block); yco -= YSPACE; From 8fa180a9b19649067edce3b973be4a27ea5b8daa Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 26 Feb 2009 00:13:40 +0000 Subject: [PATCH 78/88] * Fix for a small bug where multiple scattering wasn't being enabled properly. * Also a MSVC compile fix --- .../render/intern/include/volume_precache.h | 1 + .../blender/render/intern/source/volume_precache.c | 14 +++++++++++--- source/blender/render/intern/source/volumetric.c | 4 +--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/source/blender/render/intern/include/volume_precache.h b/source/blender/render/intern/include/volume_precache.h index 9d87a219c82..d8a94c2d560 100644 --- a/source/blender/render/intern/include/volume_precache.h +++ b/source/blender/render/intern/include/volume_precache.h @@ -29,5 +29,6 @@ void volume_precache(Render *re); void free_volume_precache(Render *re); int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co); +int using_lightcache(Material *ma); #define VOL_MS_TIMESTEP 0.1f \ No newline at end of file diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 4cdffc5ad35..ba5fae0f284 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -49,6 +49,9 @@ #include "volumetric.h" #include "volume_precache.h" +#if defined( _MSC_VER ) && !defined( __cplusplus ) +# define inline __inline +#endif // defined( _MSC_VER ) && !defined( __cplusplus ) #include "BKE_global.h" @@ -247,8 +250,7 @@ void multiple_scattering_diffusion(Render *re, float *cache, int res, Material * const float fac = ma->vol_ms_intensity; const float simframes = ma->vol_ms_steps; const int shade_type = ma->vol_shade_type; - const float dt = VOL_MS_TIMESTEP; - + int i, j, k, m; int n = res; const int size = (n+2)*(n+2)*(n+2); @@ -595,6 +597,12 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat } } +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))); +} + /* loop through all objects (and their associated materials) * marked for pre-caching in convertblender.c, and pre-cache them */ void volume_precache(Render *re) @@ -606,7 +614,7 @@ void volume_precache(Render *re) if (re->r.scemode & R_PREVIEWBUTS) return; for(vo= re->volumes.first; vo; vo= vo->next) { - if (vo->ma->vol_shadeflag & MA_VOL_PRECACHESHADING) { + if (using_lightcache(vo->ma)) { for(obi= re->instancetable.first; obi; obi= obi->next) { if (obi->obr == vo->obr) { vol_precache_objectinstance_threads(re, obi, vo->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]); diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index c8361844e11..01c4ac8fa74 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -514,9 +514,7 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float if (R.r.scemode & R_PREVIEWBUTS) { vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); - } else if (((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) && - (shi->mat->vol_shade_type == MA_VOL_SHADE_SINGLE)) || - (ELEM(shi->mat->vol_shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE))) { + } else if (using_lightcache(shi->mat)) { vol_get_precached_scattering(shi, scatter_col, step_mid); } else vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); From ce637a00469bf5caf620d4ed27a54e658469ee54 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 11 Mar 2009 05:32:11 +0000 Subject: [PATCH 79/88] * Patch by Raul F Hernandez This adds a header to the voxel data texture's data file format, to auto-fill the resolution settings upon loading a file. I don't have a data file of the right format to test with, so I'll trust it works and wait for confirmation! It also adds a 'still frame' setting, to pause the voxel data sequence on a specified frame, throughout the course of the rendered animation. --- source/blender/makesdna/DNA_texture_types.h | 1 + .../blender/render/intern/include/voxeldata.h | 8 +- .../blender/render/intern/source/voxeldata.c | 115 +++++++++--------- source/blender/src/buttons_shading.c | 28 ++++- 4 files changed, 91 insertions(+), 61 deletions(-) diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index e90df908c2b..420850ce396 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -169,6 +169,7 @@ typedef struct VoxelData { float int_multiplier; float vxpad; + int still, still_frame; char source_path[240]; float *dataset; diff --git a/source/blender/render/intern/include/voxeldata.h b/source/blender/render/intern/include/voxeldata.h index 504d5523db6..190a5a5a1c4 100644 --- a/source/blender/render/intern/include/voxeldata.h +++ b/source/blender/render/intern/include/voxeldata.h @@ -36,7 +36,13 @@ struct Render; struct TexResult; -int _I(int x,int y,int z,int n); +typedef struct VoxelDataHeader +{ +int resolX, resolY, resolZ; +int frames; +} VoxelDataHeader; + +inline int _I(int x, int y, int z, int *n); void make_voxeldata(struct Render *re); void free_voxeldata(struct Render *re); int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres); diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 2f0bbd44a7c..86cc54c0d44 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -42,25 +42,26 @@ #include "render_types.h" #include "renderdatabase.h" #include "texture.h" +#include "voxeldata.h" #if defined( _MSC_VER ) && !defined( __cplusplus ) # define inline __inline #endif // defined( _MSC_VER ) && !defined( __cplusplus ) /*---------------------------Utils----------------------------------------*/ -static inline int _I(int x,int y,int z,int n) +inline int _I(int x, int y, int z, int *n) { - return (z*(n)+y)*(n)+x; + return (z*(n[1])+y)*(n[2])+x; } -float Linear(float xx,float yy,float zz,float *x0,int n) +float Linear(float xx, float yy, float zz, float *x0, int *n) { float sx1,sx0,sy1,sy0,sz1,sz0,v0,v1; int i0,i1,j0,j1,k0,k1; - if (xx<0.5) xx=0.5f; if (xx>n+0.5) xx=n+0.5f; i0=(int)xx; i1=i0+1; - if (yy<0.5) yy=0.5f; if (yy>n+0.5) yy=n+0.5f; j0=(int)yy; j1=j0+1; - if (zz<0.5) zz=0.5f; if (zz>n+0.5) zz=n+0.5f; k0=(int)zz; k1=k0+1; + if (xx<0.5) xx=0.5f; if (xx>n[0]+0.5) xx=n[0]+0.5f; i0=(int)xx; i1=i0+1; + if (yy<0.5) yy=0.5f; if (yy>n[1]+0.5) yy=n[1]+0.5f; j0=(int)yy; j1=j0+1; + if (zz<0.5) zz=0.5f; if (zz>n[2]+0.5) zz=n[2]+0.5f; k0=(int)zz; k1=k0+1; sx1 = xx-i0; sx0 = 1-sx1; sy1 = yy-j0; sy0 = 1-sy1; @@ -68,15 +69,14 @@ float Linear(float xx,float yy,float zz,float *x0,int n) v0 = sx0*(sy0*x0[_I(i0,j0,k0,n)]+sy1*x0[_I(i0,j1,k0,n)])+sx1*(sy0*x0[_I(i1,j0,k0,n)]+sy1*x0[_I(i1,j1,k0,n)]); v1 = sx0*(sy0*x0[_I(i0,j0,k1,n)]+sy1*x0[_I(i0,j1,k1,n)])+sx1*(sy0*x0[_I(i1,j0,k1,n)]+sy1*x0[_I(i1,j1,k1,n)]); return sz0*v0 + sz1*v1; - } -static float D(float *data, const int res, int x, int y, int z) +static float D(float *data, int *res, int x, int y, int z) { - CLAMP(x, 0, res-1); - CLAMP(y, 0, res-1); - CLAMP(z, 0, res-1); + CLAMP(x, 0, res[0]-1); + CLAMP(y, 0, res[1]-1); + CLAMP(z, 0, res[2]-1); return data[ _I(x, y, z, res) ]; } @@ -85,19 +85,18 @@ static inline float lerp(float t, float v1, float v2) { } /* trilinear interpolation */ -static float trilinear(float *data, const int res, float *co) +static float trilinear(float *data, int *res, float *co) { float voxx, voxy, voxz; int vx, vy, vz; float dx, dy, dz; float d00, d10, d01, d11, d0, d1, d_final; - float dim[3]; - - if (!data) return; + + if (!data) return 0.f; - voxx = co[0] * res - 0.5f; - voxy = co[1] * res - 0.5f; - voxz = co[2] * res - 0.5f; + voxx = co[0] * res[0] - 0.5f; + voxy = co[1] * res[1] - 0.5f; + voxz = co[2] * res[2] - 0.5f; vx = (int)voxx; vy = (int)voxy; vz = (int)voxz; @@ -112,7 +111,6 @@ static float trilinear(float *data, const int res, float *co) d_final = lerp(dz, d0, d1); return d_final; - } @@ -242,17 +240,16 @@ float tricubic_eval(float a[64], float x, float y, float z) { } -float tricubic(float xx,float yy,float zz,float *heap,int n) +float tricubic(float xx, float yy, float zz, float *heap, int *n) { int xi,yi,zi; float dx,dy,dz; float a[64]; - - if (xx<0.5) xx=0.5f; if (xx>n+0.5) xx=n+0.5f; xi=(int)xx; - if (yy<0.5) yy=0.5f; if (yy>n+0.5) yy=n+0.5f; yi=(int)yy; - if (zz<0.5) zz=0.5f; if (zz>n+0.5) zz=n+0.5f; zi=(int)zz; + if (xx<0.5) xx=0.5f; if (xx>n[0]+0.5) xx=n[0]+0.5f; xi=(int)xx; + if (yy<0.5) yy=0.5f; if (yy>n[1]+0.5) yy=n[1]+0.5f; yi=(int)yy; + if (zz<0.5) zz=0.5f; if (zz>n[2]+0.5) zz=n[2]+0.5f; zi=(int)zz; { float fval[8]={heap[_I(xi,yi,zi,n)],heap[_I(xi+1,yi,zi,n)],heap[_I(xi,yi+1,zi,n)],heap[_I(xi+1,yi+1,zi,n)],heap[_I(xi,yi,zi+1,n)],heap[_I(xi+1,yi,zi+1,n)],heap[_I(xi,yi+1,zi+1,n)],heap[_I(xi+1,yi+1,zi+1,n)]}; @@ -325,21 +322,30 @@ float tricubic(float xx,float yy,float zz,float *heap,int n) } - - - - -/*--------------------------------------------------------------------*/ - -void load_frame (FILE *fp,float *F, int size,int frame) -{ - - fseek(fp,frame*size*sizeof(float),0); +void load_frame (FILE *fp, float *F, int size, int frame, int offset) +{ + fseek(fp,frame*size*sizeof(float)+offset,0); fread(F,sizeof(float),size,fp); } +void write_voxeldata_header(struct VoxelDataHeader *h, FILE *fp) +{ + fwrite(h,sizeof(struct VoxelDataHeader),1,fp); +} +void read_voxeldata_header(FILE *fp, struct VoxelData *vd) +{ + VoxelDataHeader *h=(VoxelDataHeader *)MEM_mallocN(sizeof(VoxelDataHeader), "voxel data header"); + + rewind(fp); + fread(h,sizeof(VoxelDataHeader),1,fp); + + vd->resolX=h->resolX; + vd->resolY=h->resolY; + vd->resolZ=h->resolZ; + MEM_freeN(h); +} void cache_voxeldata(struct Render *re,Tex *tex) { @@ -349,20 +355,19 @@ void cache_voxeldata(struct Render *re,Tex *tex) if (!vd) return; - vd->resolY=vd->resolX; //for now only support cubic datasets (rectangular datasets could be added latter) - vd->resolZ=vd->resolX; - size = (vd->resolX)*(vd->resolY)*(vd->resolZ); - - vd->dataset=MEM_mallocN(sizeof(float)*size, "voxel dataset"); + read_voxeldata_header(fp, vd); + size = (vd->resolX)*(vd->resolY)*(vd->resolZ); + vd->dataset = MEM_mallocN(sizeof(float)*size, "voxel dataset"); if (!BLI_exists(vd->source_path)) return; fp = fopen(vd->source_path,"rb"); if (!fp) return; - load_frame(fp, vd->dataset, size, re->r.cfra); //here improve the dataset loading function for more dataset types + //here improve the dataset loading function for more dataset types + if (vd->still) load_frame(fp, vd->dataset, size, vd->still_frame, sizeof(VoxelDataHeader)); + else load_frame(fp, vd->dataset, size, re->r.cfra, sizeof(VoxelDataHeader)); fclose(fp); - } void make_voxeldata(struct Render *re) @@ -421,24 +426,22 @@ int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres) int xi, yi, zi; float xf, yf, zf; int i=0, fail=0; - int resolX, resolY, resolZ; + int resol[3]; if ((!vd) || (vd->dataset==NULL)) { texres->tin = 0.0f; return 0; } - //here do the calculation of the interpolation types - - resolX=vd->resolX; - resolY=vd->resolY; - resolZ=vd->resolZ; + resol[0] = vd->resolX; + resol[1] = vd->resolY; + resol[2] = vd->resolZ; VECCOPY(co, texvec); - dx=1.0f/(resolX); - dy=1.0f/(resolY); - dz=1.0f/(resolZ); + dx=1.0f/(resol[0]); + dy=1.0f/(resol[1]); + dz=1.0f/(resol[2]); xi=co[0]/dx; yi=co[1]/dy; @@ -448,27 +451,27 @@ int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres) yf=co[1]/dy; zf=co[2]/dz; - if (xi>1 && xi1 && xi1 && yi1 && yi1 && zi1 && ziinterp_type) { case TEX_VD_NEARESTNEIGHBOR: { - texres->tin = vd->dataset[_I(xi,yi,zi,resolX)]; + texres->tin = vd->dataset[_I(xi,yi,zi,resol)]; break; } case TEX_VD_LINEAR: { - texres->tin = trilinear(vd->dataset, resolX, co); + texres->tin = trilinear(vd->dataset, resol, co); break; } case TEX_VD_TRICUBIC: { - texres->tin = tricubic(xf,yf,zf,vd->dataset,resolX); + texres->tin = tricubic(xf, yf, zf, vd->dataset, resol); break; } } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 658b79f99fb..875184d6cc1 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -1060,7 +1060,7 @@ static void texture_panel_voxeldata(Tex *tex) 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; + if(uiNewPanel(curarea, block, "Voxel Data", "Texture", PANELX, PANELY, PANELW, PANELH+YSPACE)==0) return; uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE); if(tex->vd==NULL) { @@ -1085,13 +1085,33 @@ static void texture_panel_voxeldata(Tex *tex) 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"); + + yco = PANEL_YMAX - 2*BUTH - 2*YSPACE; + + uiDefBut(block, LABEL, B_NOP, "Resolution:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButI(block, NUM, B_REDR, "X: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->resolX), 1, 10000, 0, 0, "Resolution of the voxel data"); + uiDefButI(block, NUM, B_REDR, "Y: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->resolY), 1, 10000, 0, 0, "Resolution of the voxel data"); + uiDefButI(block, NUM, B_REDR, "Z: ", + X2CLM2, yco-= BUTH, BUTW2, BUTH, &(vd->resolZ), 1, 10000, 0, 0, "Resolution of the voxel data"); + uiBlockEndAlign(block); + + yco -= YSPACE; + + uiBlockBeginAlign(block); + uiDefButI(block,TOG, B_REDR, "Still", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->still), 0,1, 0, 0, "Use a still frame from the data sequence for the entire rendered animation"); + if (vd->still) uiDefButI(block, NUM, B_REDR, "Frame: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->still_frame), 1, 10000, 0, 0, "The frame to pause on for the entire rendered animation"); + uiBlockEndAlign(block); + } } From 2b05a837295e32c2dd91a59984870803a3f0a52d Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 17 Mar 2009 05:33:05 +0000 Subject: [PATCH 80/88] Fixed a problem in how volumes were interpreting textures, and removed associated workarounds in point density texture. --- .../render/intern/source/pointdensity.c | 35 ++++++++++++------- source/blender/render/intern/source/texture.c | 2 +- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 392af8411c5..2c8b6aaf0a5 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -373,7 +373,7 @@ static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData * int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) { - int retval = TEX_INT+TEX_RGB; + int retval = TEX_INT; PointDensity *pd = tex->pd; PointDensityRangeData pdr; float density=0.0f, age=0.0f, time=0.0f; @@ -382,11 +382,11 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) float turb, noise_fac; int num=0; - if ((!pd) || (!pd->point_tree)) { - texres->tin = 0.0f; - return 0; - } + texres->tin = 0.0f; + if ((!pd) || (!pd->point_tree)) + return 0; + init_pointdensityrangedata(pd, &pdr, &density, vec, &age); noise_fac = pd->noise_fac * 0.5f; /* better default */ @@ -400,6 +400,9 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) age /= num; VecMulf(vec, 1.0f/num); } + + /* reset */ + density = vec[0] = vec[1] = vec[2] = 0.0f; } if (pd->flag & TEX_PD_TURBULENCE) { @@ -422,11 +425,9 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) co[0] = texvec[0] + noise_fac * turb; co[1] = texvec[1] + noise_fac * turb; co[2] = texvec[2] + noise_fac * turb; - - /* reset and prepare for a new BVH query with the perturbed coordinates */ - density = vec[0] = vec[1] = vec[2] = 0.0f; } + /* BVH query with the potentially perturbed coordinates */ num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); if (num > 0) { age /= num; @@ -436,13 +437,19 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) texres->tin = density; BRICONT; + if (pd->color_source == TEX_PD_COLOR_CONSTANT) + return retval; + + retval |= TEX_RGB; + switch (pd->color_source) { case TEX_PD_COLOR_PARTAGE: if (pd->coba) { if (do_colorband(pd->coba, age, col)) { texres->talpha= 1; - QUATCOPY(&texres->tr, col); - texres->tin *= texres->ta; + VECCOPY(&texres->tr, col); + texres->tin *= col[3]; + texres->ta = texres->tin; } } break; @@ -453,16 +460,18 @@ int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) if (pd->coba) { if (do_colorband(pd->coba, speed, col)) { texres->talpha= 1; - QUATCOPY(&texres->tr, col); - texres->tin *= texres->ta; + VECCOPY(&texres->tr, col); + texres->tin *= col[3]; + texres->ta = texres->tin; } } break; } case TEX_PD_COLOR_PARTVEL: + texres->talpha= 1; VecMulf(vec, pd->speed_scale); VECCOPY(&texres->tr, vec); - texres->ta = 1.0f; + texres->ta = texres->tin; break; case TEX_PD_COLOR_CONSTANT: default: diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index e5e8a285f28..d1115e1d399 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1653,7 +1653,7 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa float varfac= mtex->varfac*stencilTin; /* convert RGB to intensity if intensity info isn't provided */ - if (rgbnor & TEX_INT) { + if (!(rgbnor & TEX_INT)) { if (rgbnor & TEX_RGB) { if(texres.talpha) texres.tin= texres.ta; else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb); From 41b2a2a530804db35c3a0fed2d881acf6f332c3d Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 18 Mar 2009 03:52:17 +0000 Subject: [PATCH 81/88] * Volume rendering / multiple scattering - normalisation This changes the effect of the multiple scattering approximation to be more physically plausible (and easier to use) by making it conserve energy. Previously, the multiple scattering could show wildly different results based on the spread settings, often outputting much more light than was put in (via lamps), which is physically incorrect and made it difficult to use by requiring a lot of tweaking of the intensity value. This fixes it to some extent with a simple normalization, where it scales the light energy after multiple scattering to be the same as what was previously there in the light cache via single scattering. This means that using the default intensity of 1.0 should give good results by default, although you can still use it to tweak the effect. Note: This will render differently if you've already set up a .blend using multiple scattering with the old code, so you'll need to tweak older files. Setting the intensity back to the default 1.0 should be good though. * Smaller thing - fixed the camera view vector stuff up a bit in light cache, it now gives much more similar results to non-light cache when using anisotropic scattering. --- .../render/intern/source/volume_precache.c | 80 ++++++++++++++++--- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index ba5fae0f284..b3cffb45a27 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -220,6 +220,53 @@ static inline int I(int x,int y,int z,int n) //has a pad of 1 voxel surrounding return (x*(n+2)+y)*(n+2)+z; } + +/* get the total amount of light energy in the light cache. used to normalise after multiple scattering */ +static float total_ss_energy(float *cache, const int res) +{ + int x, y, z, rgb; + int res_2, res_3; + int i; + float energy=0.f; + + res_2 = res*res; + res_3 = res*res*res; + + for (x=0; x < res; x++) { + for (y=0; y < res; y++) { + for (z=0; z < res; z++) { + for (rgb=0; rgb < 3; rgb++) { + i = rgb*res_3 + x*res_2 + y*res + z; + + if (cache[i] > 0.f) energy += cache[i]; + } + } + } + } + + return energy; +} + +static float total_ms_energy(float *sr, float *sg, float *sb, const int res) +{ + int x, y, z, i; + float energy=0.f; + + for (z=1;z<=res;z++) { + for (y=1;y<=res;y++) { + for (x=1;x<=res;x++) { + + i = I(x,y,z,res); + if (sr[i] > 0.f) energy += sr[i]; + if (sg[i] > 0.f) energy += sg[i]; + if (sb[i] > 0.f) energy += sb[i]; + } + } + } + + return energy; +} + static void ms_diffuse(int b, float* x0, float* x, float diff, int n) { int i, j, k, l; @@ -247,9 +294,9 @@ static void ms_diffuse(int b, float* x0, float* x, float diff, int n) void multiple_scattering_diffusion(Render *re, float *cache, int res, Material *ma) { const float diff = ma->vol_ms_diff * 0.001f; /* compensate for scaling for a nicer UI range */ - const float fac = ma->vol_ms_intensity; const float simframes = ma->vol_ms_steps; const int shade_type = ma->vol_shade_type; + float fac = ma->vol_ms_intensity; int i, j, k, m; int n = res; @@ -259,8 +306,8 @@ void multiple_scattering_diffusion(Render *re, float *cache, int res, Material * float c=1.0f; int index; float origf; /* factor for blending in original light cache */ - - + float energy_ss, energy_ms; + float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); @@ -270,6 +317,8 @@ void multiple_scattering_diffusion(Render *re, float *cache, int res, Material * total = (float)(n*n*n*simframes); + energy_ss = total_ss_energy(cache, res); + /* Scattering as diffusion pass */ for (m=0; mtest_break()) break; } - /* copy to light cache */ - - if (shade_type == MA_VOL_SHADE_SINGLEPLUSMULTIPLE) - origf = 1.0f; - else + /* normalisation factor to conserve energy */ + energy_ms = total_ms_energy(sr, sg, sb, res); + fac *= (energy_ss / energy_ms); + + /* blend multiple scattering back in the light cache */ + if (shade_type == MA_VOL_SHADE_SINGLEPLUSMULTIPLE) { + /* conserve energy - half single, half multiple */ + origf = 0.5f; + fac *= 0.5f; + } else { origf = 0.0f; + } for (k=1;k<=n;k++) { @@ -390,7 +445,7 @@ static void *vol_precache_part(void *data) for (z=pa->minz; z < pa->maxz; z++) { co[2] = pa->bbmin[2] + (pa->voxel[2] * z); - + // don't bother if the point is not inside the volume mesh if (!point_inside_obi(tree, obi, co)) { obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; @@ -398,6 +453,9 @@ static void *vol_precache_part(void *data) obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; continue; } + + VecCopyf(shi->view, co); + Normalize(shi->view); density = vol_get_density(shi, co); vol_get_scattering(shi, scatter_col, co, stepsize, density); @@ -416,8 +474,6 @@ static void *vol_precache_part(void *data) static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi) { - float view[3] = {0.0,0.0,-1.0}; - memset(shi, 0, sizeof(ShadeInput)); shi->depth= 1; shi->mask= 1; @@ -428,7 +484,6 @@ static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Materi shi->obi= obi; shi->obr= obi->obr; shi->lay = re->scene->lay; - VECCOPY(shi->view, view); } static void precache_init_parts(Render *re, RayTree *tree, ShadeInput *shi, ObjectInstanceRen *obi, float *bbmin, float *bbmax, int res, int totthread, int *parts) @@ -654,3 +709,4 @@ int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co) return inside; } + From fc7a561de1b384280fdae7d3e50dde1736576733 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Tue, 21 Apr 2009 09:31:07 +0000 Subject: [PATCH 82/88] 4th: another file corrupted --- source/blender/imbuf/intern/IMB_jp2.h | 56 --------------------------- 1 file changed, 56 deletions(-) diff --git a/source/blender/imbuf/intern/IMB_jp2.h b/source/blender/imbuf/intern/IMB_jp2.h index 1d89ab8e375..fcdd4589fca 100644 --- a/source/blender/imbuf/intern/IMB_jp2.h +++ b/source/blender/imbuf/intern/IMB_jp2.h @@ -1,62 +1,7 @@ -<<<<<<< .working -/* - * IMB_jp2.h - * -<<<<<<< .working - * $Id: IMB_jp2.h 19805 2009-04-20 00:19:16Z genscher $ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -/** - * \file IMB_jp2.h - * \ingroup imbuf - * \brief Function declarations for jp2.c - */ - -#ifndef IMB_JP2_H -#define IMB_JP2_H - -#ifdef WITH_OPENJPEG -struct ImBuf; - -int imb_is_a_jp2(void *buf); -struct ImBuf *imb_jp2_decode(unsigned char *mem, int size, int flags); -short imb_savejp2(struct ImBuf *ibuf, char *name, int flags); -#endif /* WITH_OPENJPEG */ - -#endif - -======= /* * IMB_jp2.h * * $Id: IMB_bmp.h 14444 2008-04-16 22:40:48Z hos $ -======= - * $Id$ ->>>>>>> .merge-right.r19825 * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -102,4 +47,3 @@ short imb_savejp2(struct ImBuf *ibuf, char *name, int flags); #endif ->>>>>>> .merge-right.r19804 From e1122a1b67173ee180cfda9fe8dda2f4c37481bf Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Tue, 21 Apr 2009 10:19:14 +0000 Subject: [PATCH 83/88] 5th: another compile fix --- source/gameengine/Ketsji/KX_PythonInit.cpp | 43 ++++++++++++---------- source/gameengine/Ketsji/KX_PythonInit.h | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 2227072d2e7..873e49be6bb 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -216,13 +216,13 @@ static PyObject* gPyGetSpectrum(PyObject*) for (int index = 0; index < 512; index++) { - PyList_SetItem(resultlist, index, PyFloat_FromDouble(spectrum[index])); + PyList_SET_ITEM(resultlist, index, PyFloat_FromDouble(spectrum[index])); } } else { for (int index = 0; index < 512; index++) { - PyList_SetItem(resultlist, index, PyFloat_FromDouble(0.0)); + PyList_SET_ITEM(resultlist, index, PyFloat_FromDouble(0.0)); } } @@ -553,7 +553,7 @@ static PyObject* gPySetEyeSeparation(PyObject*, PyObject* args) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setEyeSeparation(float), Rasterizer not available"); return NULL; } @@ -565,7 +565,7 @@ static PyObject* gPySetEyeSeparation(PyObject*, PyObject* args) static PyObject* gPyGetEyeSeparation(PyObject*) { if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getEyeSeparation(), Rasterizer not available"); return NULL; } @@ -579,7 +579,7 @@ static PyObject* gPySetFocalLength(PyObject*, PyObject* args) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setFocalLength(float), Rasterizer not available"); return NULL; } @@ -591,7 +591,7 @@ static PyObject* gPySetFocalLength(PyObject*, PyObject* args) static PyObject* gPyGetFocalLength(PyObject*, PyObject*, PyObject*) { if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getFocalLength(), Rasterizer not available"); return NULL; } @@ -624,7 +624,7 @@ static PyObject* gPySetMistColor(PyObject*, PyObject* value) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistColor(color), Rasterizer not available"); return NULL; } gp_Rasterizer->SetFogColor(vec[0], vec[1], vec[2]); @@ -642,7 +642,7 @@ static PyObject* gPySetMistStart(PyObject*, PyObject* args) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistStart(float), Rasterizer not available"); return NULL; } @@ -661,7 +661,7 @@ static PyObject* gPySetMistEnd(PyObject*, PyObject* args) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistEnd(float), Rasterizer not available"); return NULL; } @@ -679,7 +679,7 @@ static PyObject* gPySetAmbientColor(PyObject*, PyObject* value) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setAmbientColor(color), Rasterizer not available"); return NULL; } gp_Rasterizer->SetAmbientColor(vec[0], vec[1], vec[2]); @@ -711,7 +711,7 @@ static PyObject* gPyEnableMotionBlur(PyObject*, PyObject* args) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.enableMotionBlur(float), Rasterizer not available"); return NULL; } @@ -723,7 +723,7 @@ static PyObject* gPyEnableMotionBlur(PyObject*, PyObject* args) static PyObject* gPyDisableMotionBlur(PyObject*, PyObject* args) { if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.disableMotionBlur(), Rasterizer not available"); return NULL; } @@ -763,7 +763,7 @@ static PyObject* gPySetGLSLMaterialSetting(PyObject*, flag = getGLSLSettingFlag(setting); if (flag==-1) { - PyErr_SetString(PyExc_ValueError, "glsl setting is not known"); + PyErr_SetString(PyExc_ValueError, "Rasterizer.setGLSLMaterialSetting(string): glsl setting is not known"); return NULL; } @@ -804,7 +804,7 @@ static PyObject* gPyGetGLSLMaterialSetting(PyObject*, flag = getGLSLSettingFlag(setting); if (flag==-1) { - PyErr_SetString(PyExc_ValueError, "glsl setting is not known"); + PyErr_SetString(PyExc_ValueError, "Rasterizer.getGLSLMaterialSetting(string): glsl setting is not known"); return NULL; } @@ -832,7 +832,7 @@ static PyObject* gPySetMaterialType(PyObject*, else if(type == KX_TEXFACE_MATERIAL) flag = 0; else { - PyErr_SetString(PyExc_ValueError, "material type is not known"); + PyErr_SetString(PyExc_ValueError, "Rasterizer.setMaterialType(int): material type is not known"); return NULL; } @@ -863,7 +863,7 @@ static PyObject* gPyDrawLine(PyObject*, PyObject* args) PyObject* ob_color; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.drawLine(obFrom, obTo, color): Rasterizer not available"); return NULL; } @@ -1270,7 +1270,7 @@ PyObject *KXpy_reload(PyObject *self, PyObject *args) { return newmodule; if (found==0) /* if its found but could not import then it has its own error */ - PyErr_SetString(PyExc_ImportError, "failed to reload from blenders internal text"); + PyErr_SetString(PyExc_ImportError, "reload(module): failed to reload from blenders internal text"); return newmodule; } @@ -1357,14 +1357,17 @@ void setSandbox(TPythonSecurityLevel level) /** * Python is not initialised. */ -PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie) +PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie, int argc, char** argv) { STR_String pname = progname; Py_SetProgramName(pname.Ptr()); Py_NoSiteFlag=1; Py_FrozenFlag=1; Py_Initialize(); - + + if(argv) /* browser plugins dont currently set this */ + PySys_SetArgv(argc, argv); + //importBlenderModules() setSandbox(level); @@ -1517,7 +1520,7 @@ static PyObject* gPyEventToString(PyObject*, PyObject* value) PyErr_Clear(); // incase there was an error clearing Py_DECREF(mod); - if (!ret) PyErr_SetString(PyExc_ValueError, "expected a valid int keyboard event"); + if (!ret) PyErr_SetString(PyExc_ValueError, "GameKeys.EventToString(int): expected a valid int keyboard event"); else Py_INCREF(ret); return ret; diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index 97d23fe391c..11360197b95 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -43,7 +43,7 @@ extern bool gUseVisibilityTemp; PyObject* initGameLogic(class KX_KetsjiEngine *engine, class KX_Scene* ketsjiscene); PyObject* initGameKeys(); PyObject* initRasterizer(class RAS_IRasterizer* rasty,class RAS_ICanvas* canvas); -PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, struct Main *maggie); +PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, struct Main *maggie, int argc, char** argv); PyObject* initMathutils(); PyObject* initBGL(); PyObject* initVideoTexture(void); From ffbd75e57116ba05a1261f14be0d1206acce7e3d Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sat, 16 May 2009 13:17:21 +0000 Subject: [PATCH 84/88] * Fix for simple bug in voxel data texture --- source/blender/render/intern/source/voxeldata.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 86cc54c0d44..f0816cfddff 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -355,14 +355,14 @@ void cache_voxeldata(struct Render *re,Tex *tex) if (!vd) return; - read_voxeldata_header(fp, vd); - size = (vd->resolX)*(vd->resolY)*(vd->resolZ); - vd->dataset = MEM_mallocN(sizeof(float)*size, "voxel dataset"); - if (!BLI_exists(vd->source_path)) return; fp = fopen(vd->source_path,"rb"); if (!fp) return; + read_voxeldata_header(fp, vd); + size = (vd->resolX)*(vd->resolY)*(vd->resolZ); + vd->dataset = MEM_mallocN(sizeof(float)*size, "voxel dataset"); + //here improve the dataset loading function for more dataset types if (vd->still) load_frame(fp, vd->dataset, size, vd->still_frame, sizeof(VoxelDataHeader)); else load_frame(fp, vd->dataset, size, re->r.cfra, sizeof(VoxelDataHeader)); From 44cebb39b88a6f411dbe0eb05109869ae82bbc9f Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 10 Jun 2009 07:45:12 +0000 Subject: [PATCH 85/88] * raised some limits in point density --- source/blender/src/buttons_shading.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 2e6dc7da9e1..f74afde5e81 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -909,7 +909,7 @@ static void texture_panel_pointdensity(Tex *tex) X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); uiDefButF(block, NUM, B_REDR, "Radius: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->radius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within"); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->radius), 0.001, 10000.0, 10, 2, "Radius to look for nearby particles within"); yco -= YSPACE; @@ -1021,11 +1021,11 @@ static void texture_panel_pointdensity_modify(Tex *tex) if (pd->flag & TEX_PD_TURBULENCE) { uiDefButF(block, NUM, B_REDR, "Size: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_size), 0.001, 100.0, 10, 2, "Turbulence size"); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_size), 0.001, 10000.0, 10, 2, "Turbulence size"); uiDefButS(block, NUM, B_REDR, "Depth: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_depth), 0.0, 100.0, 10, 2, "Turbulence depth"); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_depth), 0.0, 1024.0, 10, 2, "Turbulence depth"); uiDefButF(block, NUM, B_REDR, "Strength: ", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_fac), 0.001, 100.0, 10, 2, ""); + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_fac), 0.001, 10000.0, 10, 2, ""); uiBlockEndAlign(block); From 3b2ec949778649f19b83c5ada413f3a50bb0e0e8 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sat, 20 Jun 2009 06:41:50 +0000 Subject: [PATCH 86/88] Voxel data & volume light cache * Added support for additional file types in the voxel data texture. I added support for 8 bit raw files, but most notably for image sequences. Image sequences generate the voxel grid by stacking layers of image slices on top of each other to generate the voxels in the Z axis - the number of slices in the sequence is the resolution of the voxel grid's Z axis. i.e. http://mke3.net/blender/devel/rendering/volumetrics/skull_layers.jpg The image sequence option is particularly useful for loading medical data into Blender. 3d medical data such as MRIs or CT scans are often stored as DICOM format image sequences. It's not in Blender's scope to support the DICOM format, but there are plenty of utilities such as ImageMagick, Photoshop or OsiriX that can easily convert DICOM files to formats that Blender supports, such as PNG or JPEG. Here are some example renderings using these file formats to load medical data: http://vimeo.com/5242961 http://vimeo.com/5242989 http://vimeo.com/5243228 Currently the 8 bit raw and image sequence formats only support the 'still' rendering feature. * Changed the default texture placement to be centred around 0.5,0.5,0.5, rather than within the 0.0,1.0 cube. This is more consistent with image textures, and it also means you can easily add a voxel data texture to a default cube without having to mess around with mapping. * Added some more extrapolation modes such as Repeat and Extend rather than just clipping http://mke3.net/blender/devel/rendering/volumetrics/bradybunch.jpg * Changed the voxel data storage to use MEM_Mapalloc (memory mapped disk cache) rather than storing in ram, to help cut down memory usage. * Refactored and cleaned up the code a lot. Now the access and interpolation code is separated into a separate voxel library inside blenlib. This is now properly shared between voxel data texture and light cache (previously there was some duplicated code). * Made volume light cache support non-cubic voxel grids. Now the resolution specified in the material properties is used for the longest edge of the volume object's bounding box, and the shorter edges are proportional (similar to how resolution is calculated for fluid sim domains). This is *much* more memory efficient for squashed volume regions like clouds layer bounding boxes, allowing you to raise the resolution considerably while still keeping memory usage acceptable. --- source/blender/blenlib/BLI_voxel.h | 40 ++ source/blender/blenlib/intern/voxel.c | 311 +++++++++++ source/blender/makesdna/DNA_texture_types.h | 22 +- .../render/intern/include/render_types.h | 13 +- .../blender/render/intern/include/voxeldata.h | 10 +- .../blender/render/intern/source/shadeinput.c | 1 + .../render/intern/source/volume_precache.c | 260 +++++----- .../blender/render/intern/source/volumetric.c | 73 +-- .../blender/render/intern/source/voxeldata.c | 484 ++++++------------ source/blender/src/buttons_shading.c | 198 ++++--- 10 files changed, 816 insertions(+), 596 deletions(-) create mode 100644 source/blender/blenlib/BLI_voxel.h create mode 100644 source/blender/blenlib/intern/voxel.c diff --git a/source/blender/blenlib/BLI_voxel.h b/source/blender/blenlib/BLI_voxel.h new file mode 100644 index 00000000000..091d8e3682d --- /dev/null +++ b/source/blender/blenlib/BLI_voxel.h @@ -0,0 +1,40 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary). + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BLI_VOXEL_H +#define BLI_VOXEL_H + +/* find the index number of a voxel, given x/y/z integer coords and resolution vector */ +#define V_I(x, y, z, res) ( (z)*(res)[1]*(res)[0] + (y)*(res)[0] + (x) ) + +/* all input coordinates must be in bounding box 0.0 - 1.0 */ +float voxel_sample_nearest(float *data, int *res, float *co); +float voxel_sample_trilinear(float *data, int *res, float *co); +float voxel_sample_tricubic(float *data, int *res, float *co); + +#endif /* BLI_VOXEL_H */ \ No newline at end of file diff --git a/source/blender/blenlib/intern/voxel.c b/source/blender/blenlib/intern/voxel.c new file mode 100644 index 00000000000..8a1ca6e59ff --- /dev/null +++ b/source/blender/blenlib/intern/voxel.c @@ -0,0 +1,311 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary). + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include + +#include "BLI_voxel.h" + +#include "BKE_utildefines.h" + + +#if defined( _MSC_VER ) && !defined( __cplusplus ) +# define inline __inline +#endif // defined( _MSC_VER ) && !defined( __cplusplus ) + +static inline float D(float *data, int *res, int x, int y, int z) +{ + CLAMP(x, 0, res[0]-1); + CLAMP(y, 0, res[1]-1); + CLAMP(z, 0, res[2]-1); + return data[ V_I(x, y, z, res) ]; +} + +/* *** nearest neighbour *** */ +/* input coordinates must be in bounding box 0.0 - 1.0 */ +float voxel_sample_nearest(float *data, int *res, float *co) +{ + int xi, yi, zi; + + xi = co[0] * res[0]; + yi = co[1] * res[1]; + zi = co[2] * res[2]; + + return D(data, res, xi, yi, zi); +} + + +/* *** trilinear *** */ +/* input coordinates must be in bounding box 0.0 - 1.0 */ + +static inline float lerp(float t, float v1, float v2) { + return (1.f - t) * v1 + t * v2; +} + +/* trilinear interpolation - taken partly from pbrt's implementation: http://www.pbrt.org */ +float voxel_sample_trilinear(float *data, int *res, float *co) +{ + float voxx, voxy, voxz; + int vx, vy, vz; + float dx, dy, dz; + float d00, d10, d01, d11, d0, d1, d_final; + + if (!data) return 0.f; + + voxx = co[0] * res[0] - 0.5f; + voxy = co[1] * res[1] - 0.5f; + voxz = co[2] * res[2] - 0.5f; + + vx = (int)voxx; vy = (int)voxy; vz = (int)voxz; + + dx = voxx - vx; dy = voxy - vy; dz = voxz - vz; + + d00 = lerp(dx, D(data, res, vx, vy, vz), D(data, res, vx+1, vy, vz)); + d10 = lerp(dx, D(data, res, vx, vy+1, vz), D(data, res, vx+1, vy+1, vz)); + d01 = lerp(dx, D(data, res, vx, vy, vz+1), D(data, res, vx+1, vy, vz+1)); + d11 = lerp(dx, D(data, res, vx, vy+1, vz+1), D(data, res, vx+1, vy+1, vz+1)); + d0 = lerp(dy, d00, d10); + d1 = lerp(dy, d01, d11); + d_final = lerp(dz, d0, d1); + + return d_final; +} + +/* *** tricubic *** */ + +int C[64][64] = { +{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 9,-9,-9, 9, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{-6, 6, 6,-6, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{-6, 6, 6,-6, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 4,-4,-4, 4, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0}, +{-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 9,-9, 0, 0,-9, 9, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{-6, 6, 0, 0, 6,-6, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9, 0, 0,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0}, +{ 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0}, +{-27,27,27,-27,27,-27,-27,27,-18,-9,18, 9,18, 9,-18,-9,-18,18,-9, 9,18,-18, 9,-9,-18,18,18,-18,-9, 9, 9,-9,-12,-6,-6,-3,12, 6, 6, 3,-12,-6,12, 6,-6,-3, 6, 3,-12,12,-6, 6,-6, 6,-3, 3,-8,-4,-4,-2,-4,-2,-2,-1}, +{18,-18,-18,18,-18,18,18,-18, 9, 9,-9,-9,-9,-9, 9, 9,12,-12, 6,-6,-12,12,-6, 6,12,-12,-12,12, 6,-6,-6, 6, 6, 6, 3, 3,-6,-6,-3,-3, 6, 6,-6,-6, 3, 3,-3,-3, 8,-8, 4,-4, 4,-4, 2,-2, 4, 4, 2, 2, 2, 2, 1, 1}, +{-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0}, +{18,-18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6, 9,-9, 9,-9,-9, 9,-9, 9,12,-12,-12,12, 6,-6,-6, 6, 6, 3, 6, 3,-6,-3,-6,-3, 8, 4,-8,-4, 4, 2,-4,-2, 6,-6, 6,-6, 3,-3, 3,-3, 4, 2, 4, 2, 2, 1, 2, 1}, +{-12,12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-6, 6,-6, 6, 6,-6, 6,-6,-8, 8, 8,-8,-4, 4, 4,-4,-3,-3,-3,-3, 3, 3, 3, 3,-4,-4, 4, 4,-2,-2, 2, 2,-4, 4,-4, 4,-2, 2,-2, 2,-2,-2,-2,-2,-1,-1,-1,-1}, +{ 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{-6, 6, 0, 0, 6,-6, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 4,-4, 0, 0,-4, 4, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4, 0, 0,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}, +{-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0}, +{18,-18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6,12,-12, 6,-6,-12,12,-6, 6, 9,-9,-9, 9, 9,-9,-9, 9, 8, 4, 4, 2,-8,-4,-4,-2, 6, 3,-6,-3, 6, 3,-6,-3, 6,-6, 3,-3, 6,-6, 3,-3, 4, 2, 2, 1, 4, 2, 2, 1}, +{-12,12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-8, 8,-4, 4, 8,-8, 4,-4,-6, 6, 6,-6,-6, 6, 6,-6,-4,-4,-2,-2, 4, 4, 2, 2,-3,-3, 3, 3,-3,-3, 3, 3,-4, 4,-2, 2,-4, 4,-2, 2,-2,-2,-1,-1,-2,-2,-1,-1}, +{ 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0}, +{-12,12,12,-12,12,-12,-12,12,-8,-4, 8, 4, 8, 4,-8,-4,-6, 6,-6, 6, 6,-6, 6,-6,-6, 6, 6,-6,-6, 6, 6,-6,-4,-2,-4,-2, 4, 2, 4, 2,-4,-2, 4, 2,-4,-2, 4, 2,-3, 3,-3, 3,-3, 3,-3, 3,-2,-1,-2,-1,-2,-1,-2,-1}, +{ 8,-8,-8, 8,-8, 8, 8,-8, 4, 4,-4,-4,-4,-4, 4, 4, 4,-4, 4,-4,-4, 4,-4, 4, 4,-4,-4, 4, 4,-4,-4, 4, 2, 2, 2, 2,-2,-2,-2,-2, 2, 2,-2,-2, 2, 2,-2,-2, 2,-2, 2,-2, 2,-2, 2,-2, 1, 1, 1, 1, 1, 1, 1, 1}}; + +static int ijk2n(int i, int j, int k) { + return(i+4*j+16*k); +} + +static void tricubic_get_coeff_stacked(float a[64], float x[64]) { + int i,j; + for (i=0;i<64;i++) { + a[i]=(float)(0.0); + for (j=0;j<64;j++) { + a[i]+=C[i][j]*x[j]; + } + } +} + +static void point2xyz(int p, int *x, int *y, int *z) { + switch (p) { + case 0: *x=0; *y=0; *z=0; break; + case 1: *x=1; *y=0; *z=0; break; + case 2: *x=0; *y=1; *z=0; break; + case 3: *x=1; *y=1; *z=0; break; + case 4: *x=0; *y=0; *z=1; break; + case 5: *x=1; *y=0; *z=1; break; + case 6: *x=0; *y=1; *z=1; break; + case 7: *x=1; *y=1; *z=1; break; + default:*x=0; *y=0; *z=0; + } +} + + +static void tricubic_get_coeff(float a[64], float f[8], float dfdx[8], float dfdy[8], float dfdz[8], float d2fdxdy[8], float d2fdxdz[8], float d2fdydz[8], float d3fdxdydz[8]) { + int i; + float x[64]; + for (i=0;i<8;i++) { + x[0+i]=f[i]; + x[8+i]=dfdx[i]; + x[16+i]=dfdy[i]; + x[24+i]=dfdz[i]; + x[32+i]=d2fdxdy[i]; + x[40+i]=d2fdxdz[i]; + x[48+i]=d2fdydz[i]; + x[56+i]=d3fdxdydz[i]; + } + tricubic_get_coeff_stacked(a,x); +} + +static float tricubic_eval(float a[64], float x, float y, float z) { + int i,j,k; + float ret=(float)(0.0); + + for (i=0;i<4;i++) { + for (j=0;j<4;j++) { + for (k=0;k<4;k++) { + ret+=a[ijk2n(i,j,k)]*pow(x,i)*pow(y,j)*pow(z,k); + } + } + } + return(ret); +} + +/* tricubic interpolation + * from 'libtricubic': http://www.lekien.com/~francois/software/tricubic/ + * input coordinates must be in bounding box 0.0 - 1.0 */ +float voxel_sample_tricubic(float *data, int *res, float *co) +{ + float xx, yy, zz; + int xi,yi,zi; + int *n = res; + float dx,dy,dz; + float a[64]; + + xx = co[0] * res[0] - 0.5f; + yy = co[1] * res[1] - 0.5f; + zz = co[2] * res[2] - 0.5f; + + xi = (int)xx; yi = (int)yy; zi = (int)zz; + + { + float fval[8]={data[V_I(xi,yi,zi,n)],data[V_I(xi+1,yi,zi,n)],data[V_I(xi,yi+1,zi,n)],data[V_I(xi+1,yi+1,zi,n)],data[V_I(xi,yi,zi+1,n)],data[V_I(xi+1,yi,zi+1,n)],data[V_I(xi,yi+1,zi+1,n)],data[V_I(xi+1,yi+1,zi+1,n)]}; + + float dfdxval[8]={0.5f*(data[V_I(xi+1,yi,zi,n)]-data[V_I(xi-1,yi,zi,n)]),0.5f*(data[V_I(xi+2,yi,zi,n)]-data[V_I(xi,yi,zi,n)]), + 0.5f*(data[V_I(xi+1,yi+1,zi,n)]-data[V_I(xi-1,yi+1,zi,n)]),0.5f*(data[V_I(xi+2,yi+1,zi,n)]-data[V_I(xi,yi+1,zi,n)]), + 0.5f*(data[V_I(xi+1,yi,zi+1,n)]-data[V_I(xi-1,yi,zi+1,n)]),0.5f*(data[V_I(xi+2,yi,zi+1,n)]-data[V_I(xi,yi,zi+1,n)]), + 0.5f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi-1,yi+1,zi+1,n)]), + 0.5f*(data[V_I(xi+2,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi+1,n)])}; + + float dfdyval[8]={0.5f*(data[V_I(xi,yi+1,zi,n)]-data[V_I(xi,yi-1,zi,n)]),0.5f*(data[V_I(xi+1,yi+1,zi,n)]-data[V_I(xi+1,yi-1,zi,n)]), + 0.5f*(data[V_I(xi,yi+2,zi,n)]-data[V_I(xi,yi,zi,n)]),0.5f*(data[V_I(xi+1,yi+2,zi,n)]-data[V_I(xi+1,yi,zi,n)]), + 0.5f*(data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi,yi-1,zi+1,n)]),0.5f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi+1,yi-1,zi+1,n)]), + 0.5f*(data[V_I(xi,yi+2,zi+1,n)]-data[V_I(xi,yi,zi+1,n)]), + 0.5f*(data[V_I(xi+1,yi+2,zi+1,n)]-data[V_I(xi+1,yi,zi+1,n)])}; + + float dfdzval[8]={0.5f*(data[V_I(xi,yi,zi+1,n)]-data[V_I(xi,yi,zi-1,n)]),0.5f*(data[V_I(xi+1,yi,zi+1,n)]-data[V_I(xi+1,yi,zi-1,n)]), + 0.5f*(data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi-1,n)]),0.5f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi+1,yi+1,zi-1,n)]), + 0.5f*(data[V_I(xi,yi,zi+2,n)]-data[V_I(xi,yi,zi,n)]),0.5f*(data[V_I(xi+1,yi,zi+2,n)]-data[V_I(xi+1,yi,zi,n)]), + 0.5f*(data[V_I(xi,yi+1,zi+2,n)]-data[V_I(xi,yi+1,zi,n)]), + 0.5f*(data[V_I(xi+1,yi+1,zi+2,n)]-data[V_I(xi+1,yi+1,zi,n)])}; + + float d2fdxdyval[8]={0.25*(data[V_I(xi+1,yi+1,zi,n)]-data[V_I(xi-1,yi+1,zi,n)]-data[V_I(xi+1,yi-1,zi,n)]+data[V_I(xi-1,yi-1,zi,n)]), + 0.25*(data[V_I(xi+2,yi+1,zi,n)]-data[V_I(xi,yi+1,zi,n)]-data[V_I(xi+2,yi-1,zi,n)]+data[V_I(xi,yi-1,zi,n)]), + 0.25*(data[V_I(xi+1,yi+2,zi,n)]-data[V_I(xi-1,yi+2,zi,n)]-data[V_I(xi+1,yi,zi,n)]+data[V_I(xi-1,yi,zi,n)]), + 0.25*(data[V_I(xi+2,yi+2,zi,n)]-data[V_I(xi,yi+2,zi,n)]-data[V_I(xi+2,yi,zi,n)]+data[V_I(xi,yi,zi,n)]), + 0.25*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi-1,yi+1,zi+1,n)]-data[V_I(xi+1,yi-1,zi+1,n)]+data[V_I(xi-1,yi-1,zi+1,n)]), + 0.25*(data[V_I(xi+2,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi+2,yi-1,zi+1,n)]+data[V_I(xi,yi-1,zi+1,n)]), + 0.25*(data[V_I(xi+1,yi+2,zi+1,n)]-data[V_I(xi-1,yi+2,zi+1,n)]-data[V_I(xi+1,yi,zi+1,n)]+data[V_I(xi-1,yi,zi+1,n)]), + 0.25*(data[V_I(xi+2,yi+2,zi+1,n)]-data[V_I(xi,yi+2,zi+1,n)]-data[V_I(xi+2,yi,zi+1,n)]+data[V_I(xi,yi,zi+1,n)])}; + + float d2fdxdzval[8]={0.25f*(data[V_I(xi+1,yi,zi+1,n)]-data[V_I(xi-1,yi,zi+1,n)]-data[V_I(xi+1,yi,zi-1,n)]+data[V_I(xi-1,yi,zi-1,n)]), + 0.25f*(data[V_I(xi+2,yi,zi+1,n)]-data[V_I(xi,yi,zi+1,n)]-data[V_I(xi+2,yi,zi-1,n)]+data[V_I(xi,yi,zi-1,n)]), + 0.25f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi-1,yi+1,zi+1,n)]-data[V_I(xi+1,yi+1,zi-1,n)]+data[V_I(xi-1,yi+1,zi-1,n)]), + 0.25f*(data[V_I(xi+2,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi+2,yi+1,zi-1,n)]+data[V_I(xi,yi+1,zi-1,n)]), + 0.25f*(data[V_I(xi+1,yi,zi+2,n)]-data[V_I(xi-1,yi,zi+2,n)]-data[V_I(xi+1,yi,zi,n)]+data[V_I(xi-1,yi,zi,n)]), + 0.25f*(data[V_I(xi+2,yi,zi+2,n)]-data[V_I(xi,yi,zi+2,n)]-data[V_I(xi+2,yi,zi,n)]+data[V_I(xi,yi,zi,n)]), + 0.25f*(data[V_I(xi+1,yi+1,zi+2,n)]-data[V_I(xi-1,yi+1,zi+2,n)]-data[V_I(xi+1,yi+1,zi,n)]+data[V_I(xi-1,yi+1,zi,n)]), + 0.25f*(data[V_I(xi+2,yi+1,zi+2,n)]-data[V_I(xi,yi+1,zi+2,n)]-data[V_I(xi+2,yi+1,zi,n)]+data[V_I(xi,yi+1,zi,n)])}; + + + float d2fdydzval[8]={0.25f*(data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi,yi-1,zi+1,n)]-data[V_I(xi,yi+1,zi-1,n)]+data[V_I(xi,yi-1,zi-1,n)]), + 0.25f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi+1,yi-1,zi+1,n)]-data[V_I(xi+1,yi+1,zi-1,n)]+data[V_I(xi+1,yi-1,zi-1,n)]), + 0.25f*(data[V_I(xi,yi+2,zi+1,n)]-data[V_I(xi,yi,zi+1,n)]-data[V_I(xi,yi+2,zi-1,n)]+data[V_I(xi,yi,zi-1,n)]), + 0.25f*(data[V_I(xi+1,yi+2,zi+1,n)]-data[V_I(xi+1,yi,zi+1,n)]-data[V_I(xi+1,yi+2,zi-1,n)]+data[V_I(xi+1,yi,zi-1,n)]), + 0.25f*(data[V_I(xi,yi+1,zi+2,n)]-data[V_I(xi,yi-1,zi+2,n)]-data[V_I(xi,yi+1,zi,n)]+data[V_I(xi,yi-1,zi,n)]), + 0.25f*(data[V_I(xi+1,yi+1,zi+2,n)]-data[V_I(xi+1,yi-1,zi+2,n)]-data[V_I(xi+1,yi+1,zi,n)]+data[V_I(xi+1,yi-1,zi,n)]), + 0.25f*(data[V_I(xi,yi+2,zi+2,n)]-data[V_I(xi,yi,zi+2,n)]-data[V_I(xi,yi+2,zi,n)]+data[V_I(xi,yi,zi,n)]), + 0.25f*(data[V_I(xi+1,yi+2,zi+2,n)]-data[V_I(xi+1,yi,zi+2,n)]-data[V_I(xi+1,yi+2,zi,n)]+data[V_I(xi+1,yi,zi,n)])}; + + + float d3fdxdydzval[8]={0.125f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi-1,yi+1,zi+1,n)]-data[V_I(xi+1,yi-1,zi+1,n)]+data[V_I(xi-1,yi-1,zi+1,n)]-data[V_I(xi+1,yi+1,zi-1,n)]+data[V_I(xi-1,yi+1,zi-1,n)]+data[V_I(xi+1,yi-1,zi-1,n)]-data[V_I(xi-1,yi-1,zi-1,n)]), + 0.125f*(data[V_I(xi+2,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi+2,yi-1,zi+1,n)]+data[V_I(xi,yi-1,zi+1,n)]-data[V_I(xi+2,yi+1,zi-1,n)]+data[V_I(xi,yi+1,zi-1,n)]+data[V_I(xi+2,yi-1,zi-1,n)]-data[V_I(xi,yi-1,zi-1,n)]), + 0.125f*(data[V_I(xi+1,yi+2,zi+1,n)]-data[V_I(xi-1,yi+2,zi+1,n)]-data[V_I(xi+1,yi,zi+1,n)]+data[V_I(xi-1,yi,zi+1,n)]-data[V_I(xi+1,yi+2,zi-1,n)]+data[V_I(xi-1,yi+2,zi-1,n)]+data[V_I(xi+1,yi,zi-1,n)]-data[V_I(xi-1,yi,zi-1,n)]), + 0.125f*(data[V_I(xi+2,yi+2,zi+1,n)]-data[V_I(xi,yi+2,zi+1,n)]-data[V_I(xi+2,yi,zi+1,n)]+data[V_I(xi,yi,zi+1,n)]-data[V_I(xi+2,yi+2,zi-1,n)]+data[V_I(xi,yi+2,zi-1,n)]+data[V_I(xi+2,yi,zi-1,n)]-data[V_I(xi,yi,zi-1,n)]), + 0.125f*(data[V_I(xi+1,yi+1,zi+2,n)]-data[V_I(xi-1,yi+1,zi+2,n)]-data[V_I(xi+1,yi-1,zi+2,n)]+data[V_I(xi-1,yi-1,zi+2,n)]-data[V_I(xi+1,yi+1,zi,n)]+data[V_I(xi-1,yi+1,zi,n)]+data[V_I(xi+1,yi-1,zi,n)]-data[V_I(xi-1,yi-1,zi,n)]), + 0.125f*(data[V_I(xi+2,yi+1,zi+2,n)]-data[V_I(xi,yi+1,zi+2,n)]-data[V_I(xi+2,yi-1,zi+2,n)]+data[V_I(xi,yi-1,zi+2,n)]-data[V_I(xi+2,yi+1,zi,n)]+data[V_I(xi,yi+1,zi,n)]+data[V_I(xi+2,yi-1,zi,n)]-data[V_I(xi,yi-1,zi,n)]), + 0.125f*(data[V_I(xi+1,yi+2,zi+2,n)]-data[V_I(xi-1,yi+2,zi+2,n)]-data[V_I(xi+1,yi,zi+2,n)]+data[V_I(xi-1,yi,zi+2,n)]-data[V_I(xi+1,yi+2,zi,n)]+data[V_I(xi-1,yi+2,zi,n)]+data[V_I(xi+1,yi,zi,n)]-data[V_I(xi-1,yi,zi,n)]), + 0.125f*(data[V_I(xi+2,yi+2,zi+2,n)]-data[V_I(xi,yi+2,zi+2,n)]-data[V_I(xi+2,yi,zi+2,n)]+data[V_I(xi,yi,zi+2,n)]-data[V_I(xi+2,yi+2,zi,n)]+data[V_I(xi,yi+2,zi,n)]+data[V_I(xi+2,yi,zi,n)]-data[V_I(xi,yi,zi,n)])}; + + + tricubic_get_coeff(a,fval,dfdxval,dfdyval,dfdzval,d2fdxdyval,d2fdxdzval,d2fdydzval,d3fdxdydzval); + } + + dx = xx-xi; + dy = yy-yi; + dz = zz-zi; + + return tricubic_eval(a,dx,dy,dz); + +} + diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 420850ce396..5cbad6cf424 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -165,9 +165,10 @@ typedef struct PointDensity { typedef struct VoxelData { int resolX, resolY, resolZ; int interp_type; - + short file_format; + short flag; + float int_multiplier; - float vxpad; int still, still_frame; char source_path[240]; @@ -480,13 +481,20 @@ 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 - +/******************** Voxel Data *****************************/ +/* flag */ + + +/* interpolation */ #define TEX_VD_NEARESTNEIGHBOR 0 -#define TEX_VD_LINEAR 1 +#define TEX_VD_LINEAR 1 #define TEX_VD_TRICUBIC 2 +/* file format */ +#define TEX_VD_BLENDERVOXEL 0 +#define TEX_VD_RAW_8BIT 1 +#define TEX_VD_RAW_16BIT 2 +#define TEX_VD_IMAGE_SEQUENCE 3 + #endif diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 8dbdde77726..9703ab10821 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -290,8 +290,8 @@ typedef struct ObjectInstanceRen { float dupliorco[3], dupliuv[2]; float (*duplitexmat)[4]; - float *volume_precache; - + struct VolumePrecache *volume_precache; + float *vectors; int totvector; } ObjectInstanceRen; @@ -426,12 +426,19 @@ typedef struct VolPrecachePart int minx, maxx; int miny, maxy; int minz, maxz; - int res; + int res[3]; float bbmin[3]; float voxel[3]; int working, done; } VolPrecachePart; +typedef struct VolumePrecache +{ + int res[3]; + float *data_r; + float *data_g; + float *data_b; +} VolumePrecache; /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/include/voxeldata.h b/source/blender/render/intern/include/voxeldata.h index 36c7789da80..b291bdc096d 100644 --- a/source/blender/render/intern/include/voxeldata.h +++ b/source/blender/render/intern/include/voxeldata.h @@ -29,23 +29,17 @@ #ifndef VOXELDATA_H #define VOXELDATA_H -/** - * Load voxel data for all point density textures in the scene - */ - struct Render; struct TexResult; typedef struct VoxelDataHeader { -int resolX, resolY, resolZ; -int frames; + int resolX, resolY, resolZ; + int frames; } VoxelDataHeader; -__inline int _I(int x, int y, int z, int *n); void make_voxeldata(struct Render *re); void free_voxeldata(struct Render *re); int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres); - #endif /* VOXELDATA_H */ diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 294175460bf..59ab5661c19 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -51,6 +51,7 @@ #include "shading.h" #include "strand.h" #include "texture.h" +#include "volumetric.h" #include "zbuf.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index b3cffb45a27..98a1a2ec2c8 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -36,6 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_threads.h" +#include "BLI_voxel.h" #include "PIL_time.h" @@ -61,6 +62,7 @@ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* *** utility code to set up an individual raytree for objectinstance, for checking inside/outside *** */ /* 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 */ @@ -151,28 +153,28 @@ RayTree *create_raytree_obi(ObjectInstanceRen *obi, float *bbmin, float *bbmax) return tree; } -static float get_avg_surrounds(float *cache, int res, int res_2, int res_3, int rgb, int xx, int yy, int zz) +/* *** light cache filtering *** */ + +static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz) { int x, y, z, x_, y_, z_; int added=0; float tot=0.0f; - int i; - for (x=-1; x <= 1; x++) { - x_ = xx+x; - if (x_ >= 0 && x_ <= res-1) { + for (z=-1; z <= 1; z++) { + z_ = zz+z; + if (z_ >= 0 && z_ <= res[2]-1) { for (y=-1; y <= 1; y++) { y_ = yy+y; - if (y_ >= 0 && y_ <= res-1) { + if (y_ >= 0 && y_ <= res[1]-1) { - for (z=-1; z <= 1; z++) { - z_ = zz+z; - if (z_ >= 0 && z_ <= res-1) { + for (x=-1; x <= 1; x++) { + x_ = xx+x; + if (x_ >= 0 && x_ <= res[0]-1) { - i = rgb*res_3 + x_*res_2 + y_*res + z_; - if (cache[i] > 0.0f) { - tot += cache[i]; + if (cache[ V_I(x_, y_, z_, res) ] > 0.0f) { + tot += cache[ V_I(x_, y_, z_, res) ]; added++; } @@ -192,54 +194,46 @@ static float get_avg_surrounds(float *cache, int res, int res_2, int res_3, int * For each voxel which was originally external to the mesh, it finds the average values of * the surrounding internal voxels and sets the original external voxel to that average amount. * Works almost a bit like a 'dilate' filter */ -static void lightcache_filter(float *cache, int res) +static void lightcache_filter(VolumePrecache *vp) { - int x, y, z, rgb; - int res_2, res_3; - int i; - - res_2 = res*res; - res_3 = res*res*res; + int x, y, z; - for (x=0; x < res; x++) { - for (y=0; y < res; y++) { - for (z=0; z < res; z++) { - for (rgb=0; rgb < 3; rgb++) { - i = rgb*res_3 + x*res_2 + y*res + z; - - /* trigger for outside mesh */ - if (cache[i] < -0.5f) cache[i] = get_avg_surrounds(cache, res, res_2, res_3, rgb, x, y, z); - } + for (z=0; z < vp->res[2]; z++) { + for (y=0; y < vp->res[1]; y++) { + for (x=0; x < vp->res[0]; x++) { + /* trigger for outside mesh */ + if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.5f) + vp->data_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z); + if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.5f) + vp->data_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z); + if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.5f) + vp->data_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z); } } } } -static inline int I(int x,int y,int z,int n) //has a pad of 1 voxel surrounding the core for boundary simulation +static inline int ms_I(int x, int y, int z, int *n) //has a pad of 1 voxel surrounding the core for boundary simulation { - return (x*(n+2)+y)*(n+2)+z; + return z*(n[1]+2)*(n[0]+2) + y*(n[0]+2) + x; } +/* *** multiple scattering approximation *** */ + /* get the total amount of light energy in the light cache. used to normalise after multiple scattering */ -static float total_ss_energy(float *cache, const int res) +static float total_ss_energy(VolumePrecache *vp) { - int x, y, z, rgb; - int res_2, res_3; - int i; + int x, y, z; + int *res = vp->res; float energy=0.f; - res_2 = res*res; - res_3 = res*res*res; - - for (x=0; x < res; x++) { - for (y=0; y < res; y++) { - for (z=0; z < res; z++) { - for (rgb=0; rgb < 3; rgb++) { - i = rgb*res_3 + x*res_2 + y*res + z; - - if (cache[i] > 0.f) energy += cache[i]; - } + for (z=0; z < res[2]; z++) { + for (y=0; y < res[1]; y++) { + for (x=0; x < res[0]; x++) { + if (vp->data_r[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_r[ V_I(x, y, z, res) ]; + if (vp->data_g[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_g[ V_I(x, y, z, res) ]; + if (vp->data_b[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_b[ V_I(x, y, z, res) ]; } } } @@ -247,16 +241,16 @@ static float total_ss_energy(float *cache, const int res) return energy; } -static float total_ms_energy(float *sr, float *sg, float *sb, const int res) +static float total_ms_energy(float *sr, float *sg, float *sb, int *res) { int x, y, z, i; float energy=0.f; - for (z=1;z<=res;z++) { - for (y=1;y<=res;y++) { - for (x=1;x<=res;x++) { + for (z=1;z<=res[2];z++) { + for (y=1;y<=res[1];y++) { + for (x=1;x<=res[0];x++) { - i = I(x,y,z,res); + i = ms_I(x,y,z,res); if (sr[i] > 0.f) energy += sr[i]; if (sg[i] > 0.f) energy += sg[i]; if (sb[i] > 0.f) energy += sb[i]; @@ -267,44 +261,44 @@ static float total_ms_energy(float *sr, float *sg, float *sb, const int res) return energy; } -static void ms_diffuse(int b, float* x0, float* x, float diff, int n) +static void ms_diffuse(int b, float* x0, float* x, float diff, int *n) { int i, j, k, l; const float dt = VOL_MS_TIMESTEP; - const float a = dt*diff*n*n*n; + const float a = dt*diff*n[0]*n[1]*n[2]; for (l=0; l<20; l++) { - for (k=1; k<=n; k++) + for (k=1; k<=n[2]; k++) { - for (j=1; j<=n; j++) + for (j=1; j<=n[1]; j++) { - for (i=1; i<=n; i++) + for (i=1; i<=n[0]; i++) { - x[I(i,j,k,n)] = (x0[I(i,j,k,n)] + a*( - x[I(i-1,j,k,n)]+x[I(i+1,j,k,n)]+ - x[I(i,j-1,k,n)]+x[I(i,j+1,k,n)]+ - x[I(i,j,k-1,n)]+x[I(i,j,k+1,n)]))/(1+6*a); + x[ms_I(i,j,k,n)] = (x0[ms_I(i,j,k,n)] + a*( + x[ms_I(i-1,j,k,n)]+x[ms_I(i+1,j,k,n)]+ + x[ms_I(i,j-1,k,n)]+x[ms_I(i,j+1,k,n)]+ + x[ms_I(i,j,k-1,n)]+x[ms_I(i,j,k+1,n)]))/(1+6*a); } } } } } -void multiple_scattering_diffusion(Render *re, float *cache, int res, Material *ma) +void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma) { const float diff = ma->vol_ms_diff * 0.001f; /* compensate for scaling for a nicer UI range */ const float simframes = ma->vol_ms_steps; const int shade_type = ma->vol_shade_type; float fac = ma->vol_ms_intensity; - int i, j, k, m; - int n = res; - const int size = (n+2)*(n+2)*(n+2); + int x, y, z, m; + int *n = vp->res; + const int size = (n[0]+2)*(n[1]+2)*(n[2]+2); double time, lasttime= PIL_check_seconds_timer(); float total; float c=1.0f; - int index; + int i; float origf; /* factor for blending in original light cache */ float energy_ss, energy_ms; @@ -315,33 +309,31 @@ void multiple_scattering_diffusion(Render *re, float *cache, int res, Material * float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); - total = (float)(n*n*n*simframes); + total = (float)(n[0]*n[1]*n[2]*simframes); - energy_ss = total_ss_energy(cache, res); + energy_ss = total_ss_energy(vp); /* Scattering as diffusion pass */ for (m=0; mdata_r[i] > 0.f) + sr[ms_I(x,y,z,n)] += vp->data_r[i]; + if (vp->data_g[i] > 0.f) + sg[ms_I(x,y,z,n)] += vp->data_g[i]; + if (vp->data_b[i] > 0.f) + sb[ms_I(x,y,z,n)] += vp->data_b[i]; - index=(i-1)*n*n + (j-1)*n + k-1; - - if (cache[index] > 0.0f) - sr[I(i,j,k,n)] += cache[index]; - if (cache[1*n*n*n + index] > 0.0f) - sg[I(i,j,k,n)] += cache[1*n*n*n + index]; - if (cache[2*n*n*n + index] > 0.0f) - sb[I(i,j,k,n)] += cache[2*n*n*n + index]; - - /* Displays progress every second */ if(time-lasttime>1.0f) { char str[64]; @@ -368,7 +360,7 @@ void multiple_scattering_diffusion(Render *re, float *cache, int res, Material * } /* normalisation factor to conserve energy */ - energy_ms = total_ms_energy(sr, sg, sb, res); + energy_ms = total_ms_energy(sr, sg, sb, n); fac *= (energy_ss / energy_ms); /* blend multiple scattering back in the light cache */ @@ -380,16 +372,16 @@ void multiple_scattering_diffusion(Render *re, float *cache, int res, Material * origf = 0.0f; } - for (k=1;k<=n;k++) + for (z=1;z<=n[2];z++) { - for (j=1;j<=n;j++) + for (y=1;y<=n[1];y++) { - for (i=1;i<=n;i++) + for (x=1;x<=n[0];x++) { - index=(i-1)*n*n + (j-1)*n + k-1; - cache[index] = origf * cache[index] + fac * sr[I(i,j,k,n)]; - cache[1*n*n*n + index] = origf * cache[1*n*n*n + index] + fac * sg[I(i,j,k,n)]; - cache[2*n*n*n + index] = origf * cache[2*n*n*n + index] + fac * sb[I(i,j,k,n)]; + int index=(x-1)*n[1]*n[2] + (y-1)*n[2] + z-1; + vp->data_r[index] = origf * vp->data_r[index] + fac * sr[ms_I(x,y,z,n)]; + vp->data_g[index] = origf * vp->data_g[index] + fac * sg[ms_I(x,y,z,n)]; + vp->data_b[index] = origf * vp->data_b[index] + fac * sb[ms_I(x,y,z,n)]; } } } @@ -434,23 +426,23 @@ static void *vol_precache_part(void *data) float density, scatter_col[3] = {0.f, 0.f, 0.f}; float co[3]; int x, y, z; - const int res=pa->res, res_2=pa->res*pa->res, res_3=pa->res*pa->res*pa->res; + const int res[3]= {pa->res[0], pa->res[1], pa->res[2]}; const float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW); - for (x= pa->minx; x < pa->maxx; x++) { - co[0] = pa->bbmin[0] + (pa->voxel[0] * x); + for (z= pa->minz; z < pa->maxz; z++) { + co[2] = pa->bbmin[2] + (pa->voxel[2] * z); for (y= pa->miny; y < pa->maxy; y++) { co[1] = pa->bbmin[1] + (pa->voxel[1] * y); - for (z=pa->minz; z < pa->maxz; z++) { - co[2] = pa->bbmin[2] + (pa->voxel[2] * z); + for (x=pa->minx; x < pa->maxx; x++) { + co[0] = pa->bbmin[0] + (pa->voxel[0] * x); // don't bother if the point is not inside the volume mesh if (!point_inside_obi(tree, obi, co)) { - obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; - obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = -1.0f; - obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache->data_r[ V_I(x, y, z, res) ] = -1.0f; + obi->volume_precache->data_g[ V_I(x, y, z, res) ] = -1.0f; + obi->volume_precache->data_b[ V_I(x, y, z, res) ] = -1.0f; continue; } @@ -459,9 +451,9 @@ static void *vol_precache_part(void *data) 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]; + obi->volume_precache->data_r[ V_I(x, y, z, res) ] = scatter_col[0]; + obi->volume_precache->data_g[ V_I(x, y, z, res) ] = scatter_col[1]; + obi->volume_precache->data_b[ V_I(x, y, z, res) ] = scatter_col[2]; } } } @@ -486,44 +478,52 @@ static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Materi shi->lay = re->scene->lay; } -static void precache_init_parts(Render *re, RayTree *tree, ShadeInput *shi, ObjectInstanceRen *obi, float *bbmin, float *bbmax, int res, int totthread, int *parts) +static void precache_init_parts(Render *re, RayTree *tree, ShadeInput *shi, ObjectInstanceRen *obi, int totthread, int *parts) { + VolumePrecache *vp = obi->volume_precache; int i=0, x, y, z; float voxel[3]; int sizex, sizey, sizez; + float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1]; + int *res; int minx, maxx; int miny, maxy; int minz, maxz; + if (!vp) return; + BLI_freelistN(&re->volume_precache_parts); /* currently we just subdivide the box, number of threads per side */ parts[0] = parts[1] = parts[2] = totthread; + res = vp->res; VecSubf(voxel, bbmax, bbmin); if ((voxel[0] < FLT_EPSILON) || (voxel[1] < FLT_EPSILON) || (voxel[2] < FLT_EPSILON)) return; - VecMulf(voxel, 1.0f/res); + voxel[0] /= res[0]; + voxel[1] /= res[1]; + voxel[2] /= res[2]; for (x=0; x < parts[0]; x++) { - sizex = ceil(res / (float)parts[0]); + sizex = ceil(res[0] / (float)parts[0]); minx = x * sizex; maxx = minx + sizex; - maxx = (maxx>res)?res:maxx; + maxx = (maxx>res[0])?res[0]:maxx; for (y=0; y < parts[1]; y++) { - sizey = ceil(res / (float)parts[1]); + sizey = ceil(res[1] / (float)parts[1]); miny = y * sizey; maxy = miny + sizey; - maxy = (maxy>res)?res:maxy; + maxy = (maxy>res[1])?res[1]:maxy; for (z=0; z < parts[2]; z++) { VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part"); - sizez = ceil(res / (float)parts[2]); + sizez = ceil(res[2] / (float)parts[2]); minz = z * sizez; maxz = minz + sizez; - maxz = (maxz>res)?res:maxz; + maxz = (maxz>res[2])?res[2]:maxz; pa->done = 0; pa->working = 0; @@ -534,7 +534,7 @@ static void precache_init_parts(Render *re, RayTree *tree, ShadeInput *shi, Obje pa->obi = obi; VECCOPY(pa->bbmin, bbmin); VECCOPY(pa->voxel, voxel); - pa->res = res; + VECCOPY(pa->res, res); pa->minx = minx; pa->maxx = maxx; pa->miny = miny; pa->maxy = maxy; @@ -564,19 +564,37 @@ static VolPrecachePart *precache_get_new_part(Render *re) return nextpa; } +static void precache_resolution(VolumePrecache *vp, float *bbmin, float *bbmax, int res) +{ + float dim[3], div; + + VecSubf(dim, bbmax, bbmin); + + div = MAX3(dim[0], dim[1], dim[2]); + dim[0] /= div; + dim[1] /= div; + dim[2] /= div; + + vp->res[0] = dim[0] * (float)res; + vp->res[1] = dim[1] * (float)res; + vp->res[2] = dim[2] * (float)res; +} + /* 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_threads(Render *re, ObjectInstanceRen *obi, Material *ma, float *bbmin, float *bbmax) +void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma) { + VolumePrecache *vp; VolPrecachePart *nextpa, *pa; RayTree *tree; ShadeInput shi; ListBase threads; - const int res = ma->vol_precache_resolution; + float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1]; int parts[3], totparts; + int res[3]; int caching=1, counter=0; int totthread = re->r.threads; @@ -589,13 +607,19 @@ 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; - - obi->volume_precache = MEM_callocN(sizeof(float)*res*res*res*3, "volume light cache"); + + vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache"); + precache_resolution(vp, bbmin, bbmax, ma->vol_precache_resolution); + + vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel"); + vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel"); + vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel"); + obi->volume_precache = vp; /* Need a shadeinput to calculate scattering */ precache_setup_shadeinput(re, obi, ma, &shi); - precache_init_parts(re, tree, &shi, obi, bbmin, bbmax, res, totthread, parts); + precache_init_parts(re, tree, &shi, obi, totthread, parts); totparts = parts[0] * parts[1] * parts[2]; BLI_init_threads(&threads, vol_precache_part, totthread); @@ -644,11 +668,11 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat tree= NULL; } - lightcache_filter(obi->volume_precache, res); + lightcache_filter(obi->volume_precache); if (ELEM(ma->vol_shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE)) { - multiple_scattering_diffusion(re, obi->volume_precache, res, ma); + multiple_scattering_diffusion(re, vp, ma); } } @@ -672,7 +696,7 @@ void volume_precache(Render *re) if (using_lightcache(vo->ma)) { for(obi= re->instancetable.first; obi; obi= obi->next) { if (obi->obr == vo->obr) { - vol_precache_objectinstance_threads(re, obi, vo->ma, obi->obr->boundbox[0], obi->obr->boundbox[1]); + vol_precache_objectinstance_threads(re, obi, vo->ma); } } } @@ -687,8 +711,12 @@ 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 != NULL) { MEM_freeN(obi->volume_precache); + MEM_freeN(obi->volume_precache->data_r); + MEM_freeN(obi->volume_precache->data_g); + MEM_freeN(obi->volume_precache->data_b); + } } BLI_freelistN(&re->volumes); diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 01c4ac8fa74..65f2916af59 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -36,6 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_rand.h" +#include "BLI_voxel.h" #include "RE_shader_ext.h" #include "RE_raytrace.h" @@ -139,79 +140,27 @@ 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) -{ - const int res = shi->mat->vol_precache_resolution; - CLAMP(x, 0, res-1); - CLAMP(y, 0, res-1); - CLAMP(z, 0, res-1); - return shi->obi->volume_precache[rgb*res*res*res + x*res*res + y*res + z]; -} - -static 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; + VolumePrecache *vp = shi->obi->volume_precache; float bbmin[3], bbmax[3], dim[3]; - int rgb; + float sample_co[3]; - if (!shi->obi->volume_precache) return; + if (!vp) return; + /* convert input coords to 0.0, 1.0 */ 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; - } -} -/* no interpolation */ -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]; + sample_co[0] = ((co[0] - bbmin[0]) / dim[0]); + sample_co[1] = ((co[1] - bbmin[1]) / dim[1]); + sample_co[2] = ((co[2] - bbmin[2]) / dim[2]); - 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]; + scatter_col[0] = voxel_sample_trilinear(vp->data_r, vp->res, sample_co); + scatter_col[1] = voxel_sample_trilinear(vp->data_g, vp->res, sample_co); + scatter_col[2] = voxel_sample_trilinear(vp->data_b, vp->res, sample_co); } float vol_get_density(struct ShadeInput *shi, float *co) diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index f0816cfddff..241b11e04b9 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -34,8 +34,13 @@ #include "BLI_arithb.h" #include "BLI_blenlib.h" +#include "BLI_voxel.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" #include "BKE_global.h" +#include "BKE_image.h" #include "BKE_main.h" #include "DNA_texture_types.h" @@ -44,290 +49,81 @@ #include "texture.h" #include "voxeldata.h" -#if defined( _MSC_VER ) && !defined( __cplusplus ) -# define inline __inline -#endif // defined( _MSC_VER ) && !defined( __cplusplus ) - -/*---------------------------Utils----------------------------------------*/ -inline int _I(int x, int y, int z, int *n) -{ - return (z*(n[1])+y)*(n[2])+x; -} - -float Linear(float xx, float yy, float zz, float *x0, int *n) -{ - float sx1,sx0,sy1,sy0,sz1,sz0,v0,v1; - int i0,i1,j0,j1,k0,k1; - - if (xx<0.5) xx=0.5f; if (xx>n[0]+0.5) xx=n[0]+0.5f; i0=(int)xx; i1=i0+1; - if (yy<0.5) yy=0.5f; if (yy>n[1]+0.5) yy=n[1]+0.5f; j0=(int)yy; j1=j0+1; - if (zz<0.5) zz=0.5f; if (zz>n[2]+0.5) zz=n[2]+0.5f; k0=(int)zz; k1=k0+1; - - sx1 = xx-i0; sx0 = 1-sx1; - sy1 = yy-j0; sy0 = 1-sy1; - sz1 = zz-k0; sz0 = 1-sz1; - v0 = sx0*(sy0*x0[_I(i0,j0,k0,n)]+sy1*x0[_I(i0,j1,k0,n)])+sx1*(sy0*x0[_I(i1,j0,k0,n)]+sy1*x0[_I(i1,j1,k0,n)]); - v1 = sx0*(sy0*x0[_I(i0,j0,k1,n)]+sy1*x0[_I(i0,j1,k1,n)])+sx1*(sy0*x0[_I(i1,j0,k1,n)]+sy1*x0[_I(i1,j1,k1,n)]); - return sz0*v0 + sz1*v1; -} - - -static float D(float *data, int *res, int x, int y, int z) -{ - CLAMP(x, 0, res[0]-1); - CLAMP(y, 0, res[1]-1); - CLAMP(z, 0, res[2]-1); - return data[ _I(x, y, z, res) ]; -} - -static inline float lerp(float t, float v1, float v2) { - return (1.f - t) * v1 + t * v2; -} - -/* trilinear interpolation */ -static float trilinear(float *data, int *res, float *co) -{ - float voxx, voxy, voxz; - int vx, vy, vz; - float dx, dy, dz; - float d00, d10, d01, d11, d0, d1, d_final; - - if (!data) return 0.f; - - voxx = co[0] * res[0] - 0.5f; - voxy = co[1] * res[1] - 0.5f; - voxz = co[2] * res[2] - 0.5f; - - vx = (int)voxx; vy = (int)voxy; vz = (int)voxz; - - dx = voxx - vx; dy = voxy - vy; dz = voxz - vz; - - d00 = lerp(dx, D(data, res, vx, vy, vz), D(data, res, vx+1, vy, vz)); - d10 = lerp(dx, D(data, res, vx, vy+1, vz), D(data, res, vx+1, vy+1, vz)); - d01 = lerp(dx, D(data, res, vx, vy, vz+1), D(data, res, vx+1, vy, vz+1)); - d11 = lerp(dx, D(data, res, vx, vy+1, vz+1), D(data, res, vx+1, vy+1, vz+1)); - d0 = lerp(dy, d00, d10); - d1 = lerp(dy, d01, d11); - d_final = lerp(dz, d0, d1); - - return d_final; -} - - -int C[64][64] = { - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 9,-9,-9, 9, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {-6, 6, 6,-6, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {-6, 6, 6,-6, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 4,-4,-4, 4, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0}, - {-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 9,-9, 0, 0,-9, 9, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {-6, 6, 0, 0, 6,-6, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9, 0, 0,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0}, - { 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0}, - {-27,27,27,-27,27,-27,-27,27,-18,-9,18, 9,18, 9,-18,-9,-18,18,-9, 9,18,-18, 9,-9,-18,18,18,-18,-9, 9, 9,-9,-12,-6,-6,-3,12, 6, 6, 3,-12,-6,12, 6,-6,-3, 6, 3,-12,12,-6, 6,-6, 6,-3, 3,-8,-4,-4,-2,-4,-2,-2,-1}, - {18,-18,-18,18,-18,18,18,-18, 9, 9,-9,-9,-9,-9, 9, 9,12,-12, 6,-6,-12,12,-6, 6,12,-12,-12,12, 6,-6,-6, 6, 6, 6, 3, 3,-6,-6,-3,-3, 6, 6,-6,-6, 3, 3,-3,-3, 8,-8, 4,-4, 4,-4, 2,-2, 4, 4, 2, 2, 2, 2, 1, 1}, - {-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0}, - {18,-18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6, 9,-9, 9,-9,-9, 9,-9, 9,12,-12,-12,12, 6,-6,-6, 6, 6, 3, 6, 3,-6,-3,-6,-3, 8, 4,-8,-4, 4, 2,-4,-2, 6,-6, 6,-6, 3,-3, 3,-3, 4, 2, 4, 2, 2, 1, 2, 1}, - {-12,12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-6, 6,-6, 6, 6,-6, 6,-6,-8, 8, 8,-8,-4, 4, 4,-4,-3,-3,-3,-3, 3, 3, 3, 3,-4,-4, 4, 4,-2,-2, 2, 2,-4, 4,-4, 4,-2, 2,-2, 2,-2,-2,-2,-2,-1,-1,-1,-1}, - { 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {-6, 6, 0, 0, 6,-6, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 4,-4, 0, 0,-4, 4, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4, 0, 0,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}, - {-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0}, - {18,-18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6,12,-12, 6,-6,-12,12,-6, 6, 9,-9,-9, 9, 9,-9,-9, 9, 8, 4, 4, 2,-8,-4,-4,-2, 6, 3,-6,-3, 6, 3,-6,-3, 6,-6, 3,-3, 6,-6, 3,-3, 4, 2, 2, 1, 4, 2, 2, 1}, - {-12,12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-8, 8,-4, 4, 8,-8, 4,-4,-6, 6, 6,-6,-6, 6, 6,-6,-4,-4,-2,-2, 4, 4, 2, 2,-3,-3, 3, 3,-3,-3, 3, 3,-4, 4,-2, 2,-4, 4,-2, 2,-2,-2,-1,-1,-2,-2,-1,-1}, - { 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0}, - {-12,12,12,-12,12,-12,-12,12,-8,-4, 8, 4, 8, 4,-8,-4,-6, 6,-6, 6, 6,-6, 6,-6,-6, 6, 6,-6,-6, 6, 6,-6,-4,-2,-4,-2, 4, 2, 4, 2,-4,-2, 4, 2,-4,-2, 4, 2,-3, 3,-3, 3,-3, 3,-3, 3,-2,-1,-2,-1,-2,-1,-2,-1}, - { 8,-8,-8, 8,-8, 8, 8,-8, 4, 4,-4,-4,-4,-4, 4, 4, 4,-4, 4,-4,-4, 4,-4, 4, 4,-4,-4, 4, 4,-4,-4, 4, 2, 2, 2, 2,-2,-2,-2,-2, 2, 2,-2,-2, 2, 2,-2,-2, 2,-2, 2,-2, 2,-2, 2,-2, 1, 1, 1, 1, 1, 1, 1, 1}}; - -int ijk2n(int i, int j, int k) { - return(i+4*j+16*k); -} - -void tricubic_get_coeff_stacked(float a[64], float x[64]) { - int i,j; - for (i=0;i<64;i++) { - a[i]=(float)(0.0); - for (j=0;j<64;j++) { - a[i]+=C[i][j]*x[j]; - } - } -} - -void point2xyz(int p, int *x, int *y, int *z) { - switch (p) { - case 0: *x=0; *y=0; *z=0; break; - case 1: *x=1; *y=0; *z=0; break; - case 2: *x=0; *y=1; *z=0; break; - case 3: *x=1; *y=1; *z=0; break; - case 4: *x=0; *y=0; *z=1; break; - case 5: *x=1; *y=0; *z=1; break; - case 6: *x=0; *y=1; *z=1; break; - case 7: *x=1; *y=1; *z=1; break; - default:*x=0; *y=0; *z=0; - } -} - - -void tricubic_get_coeff(float a[64], float f[8], float dfdx[8], float dfdy[8], float dfdz[8], float d2fdxdy[8], float d2fdxdz[8], float d2fdydz[8], float d3fdxdydz[8]) { - int i; - float x[64]; - for (i=0;i<8;i++) { - x[0+i]=f[i]; - x[8+i]=dfdx[i]; - x[16+i]=dfdy[i]; - x[24+i]=dfdz[i]; - x[32+i]=d2fdxdy[i]; - x[40+i]=d2fdxdz[i]; - x[48+i]=d2fdydz[i]; - x[56+i]=d3fdxdydz[i]; - } - tricubic_get_coeff_stacked(a,x); -} - -float tricubic_eval(float a[64], float x, float y, float z) { - int i,j,k; - float ret=(float)(0.0); - - for (i=0;i<4;i++) { - for (j=0;j<4;j++) { - for (k=0;k<4;k++) { - ret+=a[ijk2n(i,j,k)]*pow(x,i)*pow(y,j)*pow(z,k); - } - } - } - return(ret); -} - - -float tricubic(float xx, float yy, float zz, float *heap, int *n) -{ - - int xi,yi,zi; - float dx,dy,dz; - float a[64]; - - if (xx<0.5) xx=0.5f; if (xx>n[0]+0.5) xx=n[0]+0.5f; xi=(int)xx; - if (yy<0.5) yy=0.5f; if (yy>n[1]+0.5) yy=n[1]+0.5f; yi=(int)yy; - if (zz<0.5) zz=0.5f; if (zz>n[2]+0.5) zz=n[2]+0.5f; zi=(int)zz; - - { - float fval[8]={heap[_I(xi,yi,zi,n)],heap[_I(xi+1,yi,zi,n)],heap[_I(xi,yi+1,zi,n)],heap[_I(xi+1,yi+1,zi,n)],heap[_I(xi,yi,zi+1,n)],heap[_I(xi+1,yi,zi+1,n)],heap[_I(xi,yi+1,zi+1,n)],heap[_I(xi+1,yi+1,zi+1,n)]}; - - float dfdxval[8]={0.5f*(heap[_I(xi+1,yi,zi,n)]-heap[_I(xi-1,yi,zi,n)]),0.5f*(heap[_I(xi+2,yi,zi,n)]-heap[_I(xi,yi,zi,n)]), - 0.5f*(heap[_I(xi+1,yi+1,zi,n)]-heap[_I(xi-1,yi+1,zi,n)]),0.5f*(heap[_I(xi+2,yi+1,zi,n)]-heap[_I(xi,yi+1,zi,n)]), - 0.5f*(heap[_I(xi+1,yi,zi+1,n)]-heap[_I(xi-1,yi,zi+1,n)]),0.5f*(heap[_I(xi+2,yi,zi+1,n)]-heap[_I(xi,yi,zi+1,n)]), - 0.5f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi-1,yi+1,zi+1,n)]), - 0.5f*(heap[_I(xi+2,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi+1,n)])}; - - float dfdyval[8]={0.5f*(heap[_I(xi,yi+1,zi,n)]-heap[_I(xi,yi-1,zi,n)]),0.5f*(heap[_I(xi+1,yi+1,zi,n)]-heap[_I(xi+1,yi-1,zi,n)]), - 0.5f*(heap[_I(xi,yi+2,zi,n)]-heap[_I(xi,yi,zi,n)]),0.5f*(heap[_I(xi+1,yi+2,zi,n)]-heap[_I(xi+1,yi,zi,n)]), - 0.5f*(heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi,yi-1,zi+1,n)]),0.5f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi+1,yi-1,zi+1,n)]), - 0.5f*(heap[_I(xi,yi+2,zi+1,n)]-heap[_I(xi,yi,zi+1,n)]), - 0.5f*(heap[_I(xi+1,yi+2,zi+1,n)]-heap[_I(xi+1,yi,zi+1,n)])}; - - float dfdzval[8]={0.5f*(heap[_I(xi,yi,zi+1,n)]-heap[_I(xi,yi,zi-1,n)]),0.5f*(heap[_I(xi+1,yi,zi+1,n)]-heap[_I(xi+1,yi,zi-1,n)]), - 0.5f*(heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi-1,n)]),0.5f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi+1,yi+1,zi-1,n)]), - 0.5f*(heap[_I(xi,yi,zi+2,n)]-heap[_I(xi,yi,zi,n)]),0.5f*(heap[_I(xi+1,yi,zi+2,n)]-heap[_I(xi+1,yi,zi,n)]), - 0.5f*(heap[_I(xi,yi+1,zi+2,n)]-heap[_I(xi,yi+1,zi,n)]), - 0.5f*(heap[_I(xi+1,yi+1,zi+2,n)]-heap[_I(xi+1,yi+1,zi,n)])}; - - float d2fdxdyval[8]={0.25*(heap[_I(xi+1,yi+1,zi,n)]-heap[_I(xi-1,yi+1,zi,n)]-heap[_I(xi+1,yi-1,zi,n)]+heap[_I(xi-1,yi-1,zi,n)]), - 0.25*(heap[_I(xi+2,yi+1,zi,n)]-heap[_I(xi,yi+1,zi,n)]-heap[_I(xi+2,yi-1,zi,n)]+heap[_I(xi,yi-1,zi,n)]), - 0.25*(heap[_I(xi+1,yi+2,zi,n)]-heap[_I(xi-1,yi+2,zi,n)]-heap[_I(xi+1,yi,zi,n)]+heap[_I(xi-1,yi,zi,n)]), - 0.25*(heap[_I(xi+2,yi+2,zi,n)]-heap[_I(xi,yi+2,zi,n)]-heap[_I(xi+2,yi,zi,n)]+heap[_I(xi,yi,zi,n)]), - 0.25*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi-1,yi+1,zi+1,n)]-heap[_I(xi+1,yi-1,zi+1,n)]+heap[_I(xi-1,yi-1,zi+1,n)]), - 0.25*(heap[_I(xi+2,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi+2,yi-1,zi+1,n)]+heap[_I(xi,yi-1,zi+1,n)]), - 0.25*(heap[_I(xi+1,yi+2,zi+1,n)]-heap[_I(xi-1,yi+2,zi+1,n)]-heap[_I(xi+1,yi,zi+1,n)]+heap[_I(xi-1,yi,zi+1,n)]), - 0.25*(heap[_I(xi+2,yi+2,zi+1,n)]-heap[_I(xi,yi+2,zi+1,n)]-heap[_I(xi+2,yi,zi+1,n)]+heap[_I(xi,yi,zi+1,n)])}; - - float d2fdxdzval[8]={0.25f*(heap[_I(xi+1,yi,zi+1,n)]-heap[_I(xi-1,yi,zi+1,n)]-heap[_I(xi+1,yi,zi-1,n)]+heap[_I(xi-1,yi,zi-1,n)]), - 0.25f*(heap[_I(xi+2,yi,zi+1,n)]-heap[_I(xi,yi,zi+1,n)]-heap[_I(xi+2,yi,zi-1,n)]+heap[_I(xi,yi,zi-1,n)]), - 0.25f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi-1,yi+1,zi+1,n)]-heap[_I(xi+1,yi+1,zi-1,n)]+heap[_I(xi-1,yi+1,zi-1,n)]), - 0.25f*(heap[_I(xi+2,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi+2,yi+1,zi-1,n)]+heap[_I(xi,yi+1,zi-1,n)]), - 0.25f*(heap[_I(xi+1,yi,zi+2,n)]-heap[_I(xi-1,yi,zi+2,n)]-heap[_I(xi+1,yi,zi,n)]+heap[_I(xi-1,yi,zi,n)]), - 0.25f*(heap[_I(xi+2,yi,zi+2,n)]-heap[_I(xi,yi,zi+2,n)]-heap[_I(xi+2,yi,zi,n)]+heap[_I(xi,yi,zi,n)]), - 0.25f*(heap[_I(xi+1,yi+1,zi+2,n)]-heap[_I(xi-1,yi+1,zi+2,n)]-heap[_I(xi+1,yi+1,zi,n)]+heap[_I(xi-1,yi+1,zi,n)]), - 0.25f*(heap[_I(xi+2,yi+1,zi+2,n)]-heap[_I(xi,yi+1,zi+2,n)]-heap[_I(xi+2,yi+1,zi,n)]+heap[_I(xi,yi+1,zi,n)])}; - - - float d2fdydzval[8]={0.25f*(heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi,yi-1,zi+1,n)]-heap[_I(xi,yi+1,zi-1,n)]+heap[_I(xi,yi-1,zi-1,n)]), - 0.25f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi+1,yi-1,zi+1,n)]-heap[_I(xi+1,yi+1,zi-1,n)]+heap[_I(xi+1,yi-1,zi-1,n)]), - 0.25f*(heap[_I(xi,yi+2,zi+1,n)]-heap[_I(xi,yi,zi+1,n)]-heap[_I(xi,yi+2,zi-1,n)]+heap[_I(xi,yi,zi-1,n)]), - 0.25f*(heap[_I(xi+1,yi+2,zi+1,n)]-heap[_I(xi+1,yi,zi+1,n)]-heap[_I(xi+1,yi+2,zi-1,n)]+heap[_I(xi+1,yi,zi-1,n)]), - 0.25f*(heap[_I(xi,yi+1,zi+2,n)]-heap[_I(xi,yi-1,zi+2,n)]-heap[_I(xi,yi+1,zi,n)]+heap[_I(xi,yi-1,zi,n)]), - 0.25f*(heap[_I(xi+1,yi+1,zi+2,n)]-heap[_I(xi+1,yi-1,zi+2,n)]-heap[_I(xi+1,yi+1,zi,n)]+heap[_I(xi+1,yi-1,zi,n)]), - 0.25f*(heap[_I(xi,yi+2,zi+2,n)]-heap[_I(xi,yi,zi+2,n)]-heap[_I(xi,yi+2,zi,n)]+heap[_I(xi,yi,zi,n)]), - 0.25f*(heap[_I(xi+1,yi+2,zi+2,n)]-heap[_I(xi+1,yi,zi+2,n)]-heap[_I(xi+1,yi+2,zi,n)]+heap[_I(xi+1,yi,zi,n)])}; - - - float d3fdxdydzval[8]={0.125f*(heap[_I(xi+1,yi+1,zi+1,n)]-heap[_I(xi-1,yi+1,zi+1,n)]-heap[_I(xi+1,yi-1,zi+1,n)]+heap[_I(xi-1,yi-1,zi+1,n)]-heap[_I(xi+1,yi+1,zi-1,n)]+heap[_I(xi-1,yi+1,zi-1,n)]+heap[_I(xi+1,yi-1,zi-1,n)]-heap[_I(xi-1,yi-1,zi-1,n)]), - 0.125f*(heap[_I(xi+2,yi+1,zi+1,n)]-heap[_I(xi,yi+1,zi+1,n)]-heap[_I(xi+2,yi-1,zi+1,n)]+heap[_I(xi,yi-1,zi+1,n)]-heap[_I(xi+2,yi+1,zi-1,n)]+heap[_I(xi,yi+1,zi-1,n)]+heap[_I(xi+2,yi-1,zi-1,n)]-heap[_I(xi,yi-1,zi-1,n)]), - 0.125f*(heap[_I(xi+1,yi+2,zi+1,n)]-heap[_I(xi-1,yi+2,zi+1,n)]-heap[_I(xi+1,yi,zi+1,n)]+heap[_I(xi-1,yi,zi+1,n)]-heap[_I(xi+1,yi+2,zi-1,n)]+heap[_I(xi-1,yi+2,zi-1,n)]+heap[_I(xi+1,yi,zi-1,n)]-heap[_I(xi-1,yi,zi-1,n)]), - 0.125f*(heap[_I(xi+2,yi+2,zi+1,n)]-heap[_I(xi,yi+2,zi+1,n)]-heap[_I(xi+2,yi,zi+1,n)]+heap[_I(xi,yi,zi+1,n)]-heap[_I(xi+2,yi+2,zi-1,n)]+heap[_I(xi,yi+2,zi-1,n)]+heap[_I(xi+2,yi,zi-1,n)]-heap[_I(xi,yi,zi-1,n)]), - 0.125f*(heap[_I(xi+1,yi+1,zi+2,n)]-heap[_I(xi-1,yi+1,zi+2,n)]-heap[_I(xi+1,yi-1,zi+2,n)]+heap[_I(xi-1,yi-1,zi+2,n)]-heap[_I(xi+1,yi+1,zi,n)]+heap[_I(xi-1,yi+1,zi,n)]+heap[_I(xi+1,yi-1,zi,n)]-heap[_I(xi-1,yi-1,zi,n)]), - 0.125f*(heap[_I(xi+2,yi+1,zi+2,n)]-heap[_I(xi,yi+1,zi+2,n)]-heap[_I(xi+2,yi-1,zi+2,n)]+heap[_I(xi,yi-1,zi+2,n)]-heap[_I(xi+2,yi+1,zi,n)]+heap[_I(xi,yi+1,zi,n)]+heap[_I(xi+2,yi-1,zi,n)]-heap[_I(xi,yi-1,zi,n)]), - 0.125f*(heap[_I(xi+1,yi+2,zi+2,n)]-heap[_I(xi-1,yi+2,zi+2,n)]-heap[_I(xi+1,yi,zi+2,n)]+heap[_I(xi-1,yi,zi+2,n)]-heap[_I(xi+1,yi+2,zi,n)]+heap[_I(xi-1,yi+2,zi,n)]+heap[_I(xi+1,yi,zi,n)]-heap[_I(xi-1,yi,zi,n)]), - 0.125f*(heap[_I(xi+2,yi+2,zi+2,n)]-heap[_I(xi,yi+2,zi+2,n)]-heap[_I(xi+2,yi,zi+2,n)]+heap[_I(xi,yi,zi+2,n)]-heap[_I(xi+2,yi+2,zi,n)]+heap[_I(xi,yi+2,zi,n)]+heap[_I(xi+2,yi,zi,n)]-heap[_I(xi,yi,zi,n)])}; - - - tricubic_get_coeff(a,fval,dfdxval,dfdyval,dfdzval,d2fdxdyval,d2fdxdzval,d2fdydzval,d3fdxdydzval); - } - - dx = xx-xi; - dy = yy-yi; - dz = zz-zi; - - return tricubic_eval(a,dx,dy,dz); - -} - -void load_frame (FILE *fp, float *F, int size, int frame, int offset) +void load_frame_blendervoxel(FILE *fp, float *F, int size, int frame, int offset) { fseek(fp,frame*size*sizeof(float)+offset,0); fread(F,sizeof(float),size,fp); } +void load_frame_raw8(FILE *fp, float *F, int size, int frame) +{ + char *tmp; + int i; + + tmp = (char *)MEM_mallocN(sizeof(char)*size, "temporary voxel file reading storage"); + + fseek(fp,(frame-1)*size*sizeof(char),0); + fread(tmp, sizeof(char), size, fp); + + for (i=0; iima; + ImageUser *iuser = &tex->iuser; + int x=0, y=0, z=0; + float r, g, b; + float *rf; + + if (!ima || !iuser) return; + + ima->source = IMA_SRC_SEQUENCE; + iuser->framenr = 1 + iuser->offset; + + /* find the first valid ibuf and use it to initialise the resolution of the data set */ + /* need to do this in advance so we know how much memory to allocate */ + ibuf= BKE_image_get_ibuf(ima, iuser); + while (!ibuf && (iuser->framenr < iuser->frames)) { + iuser->framenr++; + ibuf= BKE_image_get_ibuf(ima, iuser); + } + if (!ibuf) return; + if (!ibuf->rect_float) IMB_float_from_rect(ibuf); + + vd->still = 1; + vd->resolX = ibuf->x; + vd->resolY = ibuf->y; + vd->resolZ = iuser->frames; + vd->dataset = MEM_mapallocN(sizeof(float)*(vd->resolX)*(vd->resolY)*(vd->resolZ), "voxel dataset"); + + for (z=0; z < iuser->frames; z++) + { + /* get a new ibuf for each frame */ + if (z > 0) { + iuser->framenr++; + ibuf= BKE_image_get_ibuf(ima, iuser); + if (!ibuf) break; + if (!ibuf->rect_float) IMB_float_from_rect(ibuf); + } + rf = ibuf->rect_float; + + for (y=0; y < ibuf->y; y++) + { + for (x=0; x < ibuf->x; x++) + { + /* currently converted to monchrome */ + vd->dataset[ V_I(x, y, z, &vd->resolX) ] = (rf[0] + rf[1] + rf[2])*0.333f; + rf +=4; + } + } + } +} + void write_voxeldata_header(struct VoxelDataHeader *h, FILE *fp) { fwrite(h,sizeof(struct VoxelDataHeader),1,fp); @@ -352,20 +148,37 @@ void cache_voxeldata(struct Render *re,Tex *tex) VoxelData *vd = tex->vd; FILE *fp; int size; + int curframe; if (!vd) return; + /* image sequence gets special treatment */ + if (vd->file_format == TEX_VD_IMAGE_SEQUENCE) { + load_frame_image_sequence(re, vd, tex); + return; + } + if (!BLI_exists(vd->source_path)) return; fp = fopen(vd->source_path,"rb"); if (!fp) return; + + if (vd->file_format == TEX_VD_BLENDERVOXEL) + read_voxeldata_header(fp, vd); - read_voxeldata_header(fp, vd); size = (vd->resolX)*(vd->resolY)*(vd->resolZ); - vd->dataset = MEM_mallocN(sizeof(float)*size, "voxel dataset"); + vd->dataset = MEM_mapallocN(sizeof(float)*size, "voxel dataset"); + + if (vd->still) curframe = vd->still_frame; + else curframe = re->r.cfra; - //here improve the dataset loading function for more dataset types - if (vd->still) load_frame(fp, vd->dataset, size, vd->still_frame, sizeof(VoxelDataHeader)); - else load_frame(fp, vd->dataset, size, re->r.cfra, sizeof(VoxelDataHeader)); + switch(vd->file_format) { + case TEX_VD_BLENDERVOXEL: + load_frame_blendervoxel(fp, vd->dataset, size, curframe-1, sizeof(VoxelDataHeader)); + break; + case TEX_VD_RAW_8BIT: + load_frame_raw8(fp, vd->dataset, size, curframe); + break; + } fclose(fp); } @@ -380,6 +193,7 @@ void make_voxeldata(struct Render *re) re->i.infostr= "Loading voxel datasets"; re->stats_draw(&re->i); + /* XXX: should be doing only textures used in this render */ for (tex= G.main->tex.first; tex; tex= tex->id.next) { if(tex->id.us && tex->type==TEX_VOXELDATA) { cache_voxeldata(re, tex); @@ -420,69 +234,59 @@ int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres) { int retval = TEX_INT; VoxelData *vd = tex->vd; - float vec[3] = {0.0, 0.0, 0.0}; - float co[3]; - float dx, dy, dz; - int xi, yi, zi; - float xf, yf, zf; - int i=0, fail=0; - int resol[3]; - + float co[3], offset[3] = {0.5, 0.5, 0.5}; + if ((!vd) || (vd->dataset==NULL)) { texres->tin = 0.0f; return 0; } - resol[0] = vd->resolX; - resol[1] = vd->resolY; - resol[2] = vd->resolZ; - - VECCOPY(co, texvec); - - dx=1.0f/(resol[0]); - dy=1.0f/(resol[1]); - dz=1.0f/(resol[2]); - - xi=co[0]/dx; - yi=co[1]/dy; - zi=co[2]/dz; - - xf=co[0]/dx; - yf=co[1]/dy; - zf=co[2]/dz; - - if (xi>1 && xi1 && yi1 && ziinterp_type) - { - case TEX_VD_NEARESTNEIGHBOR: - { - texres->tin = vd->dataset[_I(xi,yi,zi,resol)]; - break; - } - case TEX_VD_LINEAR: - { - texres->tin = trilinear(vd->dataset, resol, co); - break; - } - case TEX_VD_TRICUBIC: - { - texres->tin = tricubic(xf, yf, zf, vd->dataset, resol); - break; - } - } - } else fail++; - } else fail++; - } else fail++; - - if (fail) texres->tin=0.0f; + /* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */ + /* in implementation this works backwards, bringing sample locations from -1.0, 1.0 + * to the range 0.0, 1.0, before looking up in the voxel structure. */ + VecCopyf(co, texvec); + VecMulf(co, 0.5f); + VecAddf(co, co, offset); - texres->tin *= vd->int_multiplier; + /* co is now in the range 0.0, 1.0 */ + switch (tex->extend) { + case TEX_CLIP: + { + if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) { + texres->tin = 0.f; + return retval; + } + break; + } + case TEX_REPEAT: + { + co[0] = co[0] - floor(co[0]); + co[1] = co[1] - floor(co[1]); + co[2] = co[2] - floor(co[2]); + break; + } + case TEX_EXTEND: + { + CLAMP(co[0], 0.f, 1.f); + CLAMP(co[1], 0.f, 1.f); + CLAMP(co[2], 0.f, 1.f); + break; + } + } + switch (vd->interp_type) { + case TEX_VD_NEARESTNEIGHBOR: + texres->tin = voxel_sample_nearest(vd->dataset, &vd->resolX, co); + break; + case TEX_VD_LINEAR: + texres->tin = voxel_sample_trilinear(vd->dataset, &vd->resolX, co); + break; + case TEX_VD_TRICUBIC: + texres->tin = voxel_sample_tricubic(vd->dataset, &vd->resolX, co); + break; + } + + texres->tin *= vd->int_multiplier; BRICONT; texres->tr = texres->tin; diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index f74afde5e81..54fc639059d 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -1053,67 +1053,7 @@ 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+YSPACE)==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"); - - 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"); - - yco = PANEL_YMAX - 2*BUTH - 2*YSPACE; - - uiDefBut(block, LABEL, B_NOP, "Resolution:", - X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); - uiBlockBeginAlign(block); - uiDefButI(block, NUM, B_REDR, "X: ", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->resolX), 1, 10000, 0, 0, "Resolution of the voxel data"); - uiDefButI(block, NUM, B_REDR, "Y: ", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->resolY), 1, 10000, 0, 0, "Resolution of the voxel data"); - uiDefButI(block, NUM, B_REDR, "Z: ", - X2CLM2, yco-= BUTH, BUTW2, BUTH, &(vd->resolZ), 1, 10000, 0, 0, "Resolution of the voxel data"); - uiBlockEndAlign(block); - - yco -= YSPACE; - - uiBlockBeginAlign(block); - uiDefButI(block,TOG, B_REDR, "Still", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->still), 0,1, 0, 0, "Use a still frame from the data sequence for the entire rendered animation"); - if (vd->still) uiDefButI(block, NUM, B_REDR, "Frame: ", - X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->still_frame), 1, 10000, 0, 0, "The frame to pause on for the entire rendered animation"); - uiBlockEndAlign(block); - - } -} static char *layer_menu(RenderResult *rr, short *curlay) { @@ -1791,6 +1731,144 @@ static void texture_panel_envmap(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+BUTH+2*YSPACE)==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, ""); + + if (vd->file_format != TEX_VD_IMAGE_SEQUENCE) { + 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"); + } + else { + char *strp; + char str[128]; + ImageUser *iuser = &(tex->iuser); + uiBut *but; + + /* Browse */ + IMAnames_to_pupstring(&strp, NULL, NULL, &(G.main->image), NULL, &iuser->menunr); + + uiBlockBeginAlign(block); + but= uiDefButS(block, MENU, B_REDR, strp, + X2CLM1, yco-=BUTH, ICONBUTW, BUTH, &iuser->menunr, 0, 0, 0, 0, "Selects an existing Image or Movie"); + uiButSetFunc(but, image_browse_cb, &(tex->ima), iuser); + + MEM_freeN(strp); + + if (tex->ima) { + uiSetButLock(tex->ima->id.lib!=NULL, ERROR_LIBDATA_MESSAGE); + but= uiDefIconBut(block, BUT, B_REDR, ICON_FILESEL, + X2CLM1+ICONBUTW, yco, X2CLM1+ICONBUTW, BUTH, 0, 0, 0, 0, 0, "Open Fileselect to load new Image"); + uiButSetFunc(but, image_load_fs_cb, &(tex->ima), iuser); + + but= uiDefBut(block, TEX, B_IDNAME, "IM:", + X2CLM1+2*ICONBUTW, yco, PANEL_XMAX-4*ICONBUTW-BUTW4, BUTH, tex->ima->id.name+2, 0.0, 21.0, 0, 0, "Current Image Datablock name."); + uiButSetFunc(but, test_idbutton_cb, tex->ima->id.name, NULL); + + but= uiDefBut(block, BUT, B_REDR, "Reload", + PANEL_XMAX-2*ICONBUTW-BUTW4, yco, BUTW4, BUTH, NULL, 0, 0, 0, 0, "Reloads Image or Movie"); + uiButSetFunc(but, image_reload_cb, &(tex->ima), iuser); + + but= uiDefIconBut(block, BUT, B_REDR, ICON_X, + PANEL_XMAX-2*ICONBUTW, yco, ICONBUTW, BUTH, 0, 0, 0, 0, 0, "Unlink Image block"); + uiButSetFunc(but, image_unlink_cb, &(tex->ima), NULL); + + sprintf(str, "%d", tex->ima->id.us); + uiDefBut(block, BUT, B_NOP, str, + PANEL_XMAX-ICONBUTW, yco, ICONBUTW, BUTH, 0, 0, 0, 0, 0, "Only displays number of users of Image block"); + uiBlockEndAlign(block); + + yco -= (BUTH); + + uiBlockBeginAlign(block); + uiDefButI(block, NUM, B_NOP, "Slices:", + X2CLM1, yco, BUTW2, BUTH, &iuser->frames, 1.0, MAXFRAMEF, 0, 0, "Number of images in the sequence"); + uiDefButI(block, NUM, B_NOP, "Offset:", + X2CLM2, yco, BUTW2, BUTH, &iuser->offset, -MAXFRAMEF, MAXFRAMEF, 0, 0, "Offsets the file number to consider as the start of the sequence"); + uiBlockEndAlign(block); + + } else { + but= uiDefBut(block, BUT, B_REDR, "Load", + X2CLM1+ICONBUTW, yco, BUTW2-ICONBUTW, BUTH, NULL, 0, 0, 0, 0, "Load new Image"); + uiButSetFunc(but, image_load_fs_cb, &(tex->ima), iuser); + } + } + + 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"); + + yco -= YSPACE; + + uiDefBut(block, LABEL, B_NOP, "Extend:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiDefButS(block, MENU, B_REDR, "Repeat %x3|Clip %x2|Extend %x1", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &(tex->extend), 0.0, 0.0, 0, 0, "Extrapolation type"); + + 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"); + + yco = PANEL_YMAX - 2*BUTH - YSPACE; + if (vd->file_format == TEX_VD_IMAGE_SEQUENCE) yco -= BUTH; + + uiDefBut(block, LABEL, B_NOP, "File Format:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiDefButS(block, MENU, B_REDR, "Blender Voxel %x0|Raw (8 bit) %x1|Image Sequence %x3", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &vd->file_format, 0.0, 0.0, 0, 0, "File format of the voxel data file"); + + if (ELEM(vd->file_format, TEX_VD_RAW_8BIT, TEX_VD_RAW_16BIT)) { + uiDefBut(block, LABEL, B_NOP, "Resolution:", + X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButI(block, NUM, B_REDR, "X: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->resolX), 1, 10000, 0, 0, "Resolution of the voxel data"); + uiDefButI(block, NUM, B_REDR, "Y: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->resolY), 1, 10000, 0, 0, "Resolution of the voxel data"); + uiDefButI(block, NUM, B_REDR, "Z: ", + X2CLM2, yco-= BUTH, BUTW2, BUTH, &(vd->resolZ), 1, 10000, 0, 0, "Resolution of the voxel data"); + uiBlockEndAlign(block); + + yco -= YSPACE; + } + + if (vd->file_format == TEX_VD_BLENDERVOXEL) { + yco -= (BUTH+YSPACE); + uiBlockBeginAlign(block); + uiDefButI(block,TOG, B_REDR, "Still", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->still), 0,1, 0, 0, "Use a still frame from the data sequence for the entire rendered animation"); + if (vd->still) + uiDefButI(block, NUM, B_REDR, "Frame: ", + X2CLM2, yco-=BUTH, BUTW2, BUTH, &(vd->still_frame), 1, 10000, 0, 0, "The frame to pause on for the entire rendered animation"); + uiBlockEndAlign(block); + } + + + } +} + static void texture_panel_colors(Tex *tex) { uiBlock *block; From d5e9eb7d76792ef019021d64a7229a82b10fdb62 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sun, 21 Jun 2009 22:17:06 +0000 Subject: [PATCH 87/88] * fix for small bug in volume texture stack --- source/blender/render/intern/source/texture.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index d1115e1d399..5df814358d5 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1289,7 +1289,7 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, texres->tg= col[1]; texres->tb= col[2]; texres->ta= col[3]; - retval |= 1; + retval |= TEX_RGB; } } return retval; @@ -1636,8 +1636,11 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa tcol[0]=texres.tr; tcol[1]=texres.tg; tcol[2]=texres.tb; + if(texres.talpha) + texres.tin= texres.ta; } + /* used for emit */ if((mapto_flag & MAP_COL) && (mtex->mapto & MAP_COL)) { texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype); } From 7da0d1a71efee9b360eb344e7bfaa9b5f0f4ece5 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 3 Jul 2009 11:03:09 +0000 Subject: [PATCH 88/88] * Fixed a crazy memory leak in voxel data image sequence data source --- source/blender/render/intern/source/voxeldata.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 241b11e04b9..8a1a8e0bbeb 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -121,6 +121,8 @@ void load_frame_image_sequence(Render *re, VoxelData *vd, Tex *tex) rf +=4; } } + + BKE_image_free_anim_ibufs(ima, iuser->framenr); } }