diff options
Diffstat (limited to 'source/blender/render/intern/source/pointdensity.c')
-rw-r--r-- | source/blender/render/intern/source/pointdensity.c | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c new file mode 100644 index 00000000000..5f8cf5504fa --- /dev/null +++ b/source/blender/render/intern/source/pointdensity.c @@ -0,0 +1,484 @@ +/* + * ***** 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 <math.h> +#include <stdlib.h> +#include <stdio.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_kdopbvh.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_global.h" +#include "BKE_lattice.h" +#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" + +#include "render_types.h" +#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 alloc_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(re->scene, ob, (float)re->scene->r.cfra, 0.0); + int i, childexists; + 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; + + Mat4MulMat4(obview, re->viewinv, ob->obmat); + + /* 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(re->scene, ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + + if ( !psys_check_enabled(ob, psys)) { + psys_render_restore(ob, psys); + return; + } + + /* in case ob->imat isn't up-to-date */ + Mat4Invert(ob->imat, ob->obmat); + + total_particles = psys->totpart+psys->totchild; + psys->lattice=psys_get_lattice(re->scene,ob,psys); + + pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); + alloc_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, pa=psys->particles; i < total_particles; i++, pa++) { + + state.time = cfra; + if(psys_get_particle_state(re->scene, ob, psys, i, &state, 0)) { + + VECCOPY(partco, state.co); + + if (pd->psys_cache_space == TEX_PD_OBJECTSPACE) + Mat4MulVecfl(ob->imat, partco); + else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { + float obloc[3]; + VECCOPY(obloc, ob->loc); + VecSubf(partco, partco, obloc); + } else { + /* TEX_PD_WORLDSPACE */ + } + + BLI_bvhtree_insert(pd->point_tree, i, partco, 1); + + 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]; + } + if (data_used & POINT_DATA_LIFE) { + float pa_time; + + if (i < psys->totpart) { + pa_time = (cfra - pa->time)/pa->lifetime; + } else { + ChildParticle *cpa= (psys->child + i) - psys->totpart; + float pa_birthtime, pa_dietime; + + pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); + } + + pd->point_data[offset + i] = pa_time; + } + } + } + + BLI_bvhtree_balance(pd->point_tree); + dm->release(dm); + + if(psys->lattice){ + end_latt_deform(psys->lattice); + psys->lattice=0; + } + + psys_render_restore(ob, psys); +} + + +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_bvhtree_new(obr->totvert, 0.0, 4, 6); + pd->totpoints = obr->totvert; + + for(i=0; i<obr->totvert; i++) { + float ver_co[3]; + 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(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 */ + } + + BLI_bvhtree_insert(pd->point_tree, i, ver_co, 1); + } + + BLI_bvhtree_balance(pd->point_tree); + +} +static void cache_pointdensity(Render *re, Tex *tex) +{ + PointDensity *pd = tex->pd; + + if (pd->point_tree) { + BLI_bvhtree_free(pd->point_tree); + pd->point_tree = NULL; + } + + if (pd->source == TEX_PD_PSYS) { + Object *ob = pd->object; + + if (!ob) return; + if (!pd->psys) return; + + pointdensity_cache_psys(re, pd, ob, pd->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) +{ + PointDensity *pd = tex->pd; + + if (!pd) return; + + if (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; + } + pd->totpoints = 0; +} + + + +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->sdh, &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); + } + } + + re->i.infostr= NULL; + re->stats_draw(re->sdh, &re->i); +} + +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); + } + } +} + +typedef struct PointDensityRangeData +{ + float *density; + float squared_radius; + float *point_data; + float *vec; + float softness; + short falloff_type; + short noise_influence; + float *age; + int point_data_used; + int offset; +} PointDensityRangeData; + +void accum_density(void *userdata, int index, float squared_dist) +{ + PointDensityRangeData *pdr = (PointDensityRangeData *)userdata; + const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f; + float density = 0.0f; + + if (pdr->falloff_type == TEX_PD_FALLOFF_STD) + 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_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) + density = sqrt(dist); + + 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; +} + + +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; + PointDensity *pd = tex->pd; + PointDensityRangeData pdr; + 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=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 */ + + VECCOPY(co, texvec); + + 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); + } + + /* reset */ + density = vec[0] = vec[1] = vec[2] = 0.0f; + } + + if (pd->flag & TEX_PD_TURBULENCE) { + + if (pd->noise_influence == TEX_PD_NOISE_AGE) { + 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_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_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 */ + + /* 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; + } + + /* 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; + VecMulf(vec, 1.0f/num); + } + + 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; + VECCOPY(&texres->tr, col); + texres->tin *= col[3]; + texres->ta = texres->tin; + } + } + 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; + 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 = texres->tin; + break; + case TEX_PD_COLOR_CONSTANT: + default: + texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; + break; + } + BRICONTRGB; + + return retval; + + /* + if (texres->nor!=NULL) { + texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f; + } + */ +} |