diff options
Diffstat (limited to 'source/blender/render/intern/source/pointdensity.c')
-rw-r--r-- | source/blender/render/intern/source/pointdensity.c | 706 |
1 files changed, 539 insertions, 167 deletions
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index b8d8cc37ae3..59aaad661c9 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -39,9 +39,16 @@ #include "BLI_noise.h" #include "BLI_kdopbvh.h" #include "BLI_utildefines.h" +#include "BLI_task.h" #include "BLT_translation.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "DNA_texture_types.h" + +#include "BKE_deform.h" #include "BKE_DerivedMesh.h" #include "BKE_lattice.h" #include "BKE_main.h" @@ -51,10 +58,6 @@ #include "BKE_texture.h" #include "BKE_colortools.h" -#include "DNA_meshdata_types.h" -#include "DNA_texture_types.h" -#include "DNA_particle_types.h" - #include "render_types.h" #include "texture.h" #include "pointdensity.h" @@ -88,29 +91,78 @@ static int point_data_used(PointDensity *pd) pd_bitflag |= POINT_DATA_LIFE; } } + else if (pd->source == TEX_PD_OBJECT) { + if (ELEM(pd->ob_color_source, TEX_PD_COLOR_VERTCOL, TEX_PD_COLOR_VERTWEIGHT, TEX_PD_COLOR_VERTNOR)) { + pd_bitflag |= POINT_DATA_COLOR; + } + } return pd_bitflag; } +static void point_data_pointers(PointDensity *pd, + float **r_data_velocity, float **r_data_life, float **r_data_color) +{ + const int data_used = point_data_used(pd); + const int totpoint = pd->totpoints; + float *data = pd->point_data; + int offset = 0; + + if (data_used & POINT_DATA_VEL) { + if (r_data_velocity) + *r_data_velocity = data + offset; + offset += 3 * totpoint; + } + else { + if (r_data_velocity) + *r_data_velocity = NULL; + } + + if (data_used & POINT_DATA_LIFE) { + if (r_data_life) + *r_data_life = data + offset; + offset += totpoint; + } + else { + if (r_data_life) + *r_data_life = NULL; + } + + if (data_used & POINT_DATA_COLOR) { + if (r_data_color) + *r_data_color = data + offset; + offset += 3 * totpoint; + } + else { + if (r_data_color) + *r_data_color = NULL; + } +} /* 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) +static void alloc_point_data(PointDensity *pd) { + const int totpoints = pd->totpoints; + int data_used = point_data_used(pd); int data_size = 0; - if (point_data_used & POINT_DATA_VEL) { + if (data_used & POINT_DATA_VEL) { /* store 3 channels of velocity data */ data_size += 3; } - if (point_data_used & POINT_DATA_LIFE) { + if (data_used & POINT_DATA_LIFE) { /* store 1 channel of lifetime data */ data_size += 1; } + if (data_used & POINT_DATA_COLOR) { + /* store 3 channels of RGB data */ + data_size += 3; + } if (data_size) { - pd->point_data = MEM_mallocN(sizeof(float) * data_size * total_particles, + pd->point_data = MEM_callocN(sizeof(float) * data_size * totpoints, "particle point data"); } } @@ -121,7 +173,8 @@ static void pointdensity_cache_psys(Scene *scene, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], - int winx, int winy) + int winx, int winy, + const bool use_render_params) { DerivedMesh *dm; ParticleKey state; @@ -130,8 +183,9 @@ static void pointdensity_cache_psys(Scene *scene, ParticleData *pa = NULL; float cfra = BKE_scene_frame_get(scene); int i /*, childexists*/ /* UNUSED */; - int total_particles, offset = 0; - int data_used = point_data_used(pd); + int total_particles; + int data_used; + float *data_vel, *data_life; float partco[3]; /* init everything */ @@ -139,12 +193,25 @@ static void pointdensity_cache_psys(Scene *scene, return; } + data_used = point_data_used(pd); + /* Just to create a valid rendering context for particles */ - psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0); + if (use_render_params) { + psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0); + } - dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + if (use_render_params) { + dm = mesh_create_derived_render(scene, + ob, + CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + } + else { + dm = mesh_get_derived_final(scene, + ob, + CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + } - if ( !psys_check_enabled(ob, psys)) { + if (!psys_check_enabled(ob, psys)) { psys_render_restore(ob, psys); return; } @@ -161,11 +228,9 @@ static void pointdensity_cache_psys(Scene *scene, psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); 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; - } + alloc_point_data(pd); + point_data_pointers(pd, &data_vel, &data_life, NULL); #if 0 /* UNUSED */ if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) @@ -222,13 +287,13 @@ static void pointdensity_cache_psys(Scene *scene, 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_vel) { + data_vel[i*3 + 0] = state.vel[0]; + data_vel[i*3 + 1] = state.vel[1]; + data_vel[i*3 + 2] = state.vel[2]; } - if (data_used & POINT_DATA_LIFE) { - pd->point_data[offset + i] = state.time; + if (data_life) { + data_life[i] = state.time; } } @@ -240,30 +305,133 @@ static void pointdensity_cache_psys(Scene *scene, psys->lattice_deform_data = NULL; } - psys_render_restore(ob, psys); + if (use_render_params) { + psys_render_restore(ob, psys); + } } -static void pointdensity_cache_object(Scene *scene, PointDensity *pd, Object *ob) +static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob), DerivedMesh *dm, float *data_color) +{ + const MLoop *mloop = dm->getLoopArray(dm); + const int totloop = dm->getNumLoops(dm); + const MLoopCol *mcol; + char layername[MAX_CUSTOMDATA_LAYER_NAME]; + int i; + + BLI_assert(data_color); + + if (!CustomData_has_layer(&dm->loopData, CD_MLOOPCOL)) + return; + CustomData_validate_layer_name(&dm->loopData, CD_MLOOPCOL, pd->vertex_attribute_name, layername); + mcol = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, layername); + if (!mcol) + return; + + /* Stores the number of MLoops using the same vertex, so we can normalize colors. */ + int *mcorners = MEM_callocN(sizeof(int) * pd->totpoints, "point density corner count"); + + for (i = 0; i < totloop; i++) { + int v = mloop[i].v; + rgb_uchar_to_float(&data_color[v*3], &mcol[i].r); + ++mcorners[v]; + } + + /* Normalize colors by averaging over mcorners. + * All the corners share the same vertex, ie. occupy the same point in space. + */ + for (i = 0; i < pd->totpoints; i++) { + if (mcorners[i] > 0) + mul_v3_fl(&data_color[i*3], 1.0f / mcorners[i]); + } + + MEM_freeN(mcorners); +} + +static void pointdensity_cache_vertex_weight(PointDensity *pd, Object *ob, DerivedMesh *dm, float *data_color) { + const int totvert = dm->getNumVerts(dm); + const MDeformVert *mdef, *dv; + int mdef_index; + int i; + + BLI_assert(data_color); + + mdef = CustomData_get_layer(&dm->vertData, CD_MDEFORMVERT); + if (!mdef) + return; + mdef_index = defgroup_name_index(ob, pd->vertex_attribute_name); + if (mdef_index < 0) + mdef_index = ob->actdef - 1; + if (mdef_index < 0) + return; + + for (i = 0, dv = mdef; i < totvert; ++i, ++dv, data_color += 3) { + MDeformWeight *dw; + int j; + + for (j = 0, dw = dv->dw; j < dv->totweight; ++j, ++dw) { + if (dw->def_nr == mdef_index) { + copy_v3_fl(data_color, dw->weight); + break; + } + } + } +} + +static void pointdensity_cache_vertex_normal(PointDensity *pd, Object *UNUSED(ob), DerivedMesh *dm, float *data_color) +{ + MVert *mvert = dm->getVertArray(dm), *mv; + int i; + + BLI_assert(data_color); + + for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++, data_color += 3) { + normal_short_to_float_v3(data_color, mv->no); + } +} + +static void pointdensity_cache_object(Scene *scene, + PointDensity *pd, + Object *ob, + const bool use_render_params) +{ + float *data_color; int i; DerivedMesh *dm; - MVert *mvert = NULL; + CustomDataMask mask = CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL; + MVert *mvert = NULL, *mv; - dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); - mvert = dm->getVertArray(dm); /* local object space */ + switch (pd->ob_color_source) { + case TEX_PD_COLOR_VERTCOL: + mask |= CD_MASK_MLOOPCOL; + break; + case TEX_PD_COLOR_VERTWEIGHT: + mask |= CD_MASK_MDEFORMVERT; + break; + } + if (use_render_params) { + dm = mesh_create_derived_render(scene, ob, mask); + } + else { + dm = mesh_get_derived_final(scene, ob, mask); + } + + mvert = dm->getVertArray(dm); /* local object space */ pd->totpoints = dm->getNumVerts(dm); if (pd->totpoints == 0) { return; } pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6); + alloc_point_data(pd); + point_data_pointers(pd, NULL, NULL, &data_color); - for (i = 0; i < pd->totpoints; i++, mvert++) { + for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++) { float co[3]; - copy_v3_v3(co, mvert->co); + copy_v3_v3(co, mv->co); switch (pd->ob_cache_space) { case TEX_PD_OBJECTSPACE: @@ -280,6 +448,18 @@ static void pointdensity_cache_object(Scene *scene, PointDensity *pd, Object *ob BLI_bvhtree_insert(pd->point_tree, i, co, 1); } + + switch (pd->ob_color_source) { + case TEX_PD_COLOR_VERTCOL: + pointdensity_cache_vertex_color(pd, ob, dm, data_color); + break; + case TEX_PD_COLOR_VERTWEIGHT: + pointdensity_cache_vertex_weight(pd, ob, dm, data_color); + break; + case TEX_PD_COLOR_VERTNOR: + pointdensity_cache_vertex_normal(pd, ob, dm, data_color); + break; + } BLI_bvhtree_balance(pd->point_tree); dm->release(dm); @@ -290,7 +470,8 @@ static void cache_pointdensity_ex(Scene *scene, PointDensity *pd, float viewmat[4][4], float winmat[4][4], - int winx, int winy) + int winx, int winy, + const bool use_render_params) { if (pd == NULL) { return; @@ -314,18 +495,28 @@ static void cache_pointdensity_ex(Scene *scene, return; } - pointdensity_cache_psys(scene, pd, ob, psys, viewmat, winmat, winx, winy); + pointdensity_cache_psys(scene, + pd, + ob, + psys, + viewmat, winmat, + winx, winy, + use_render_params); } else if (pd->source == TEX_PD_OBJECT) { Object *ob = pd->object; if (ob && ob->type == OB_MESH) - pointdensity_cache_object(scene, pd, ob); + pointdensity_cache_object(scene, pd, ob, use_render_params); } } void cache_pointdensity(Render *re, PointDensity *pd) { - cache_pointdensity_ex(re->scene, pd, re->viewmat, re->winmat, re->winx, re->winy); + cache_pointdensity_ex(re->scene, + pd, + re->viewmat, re->winmat, + re->winx, re->winy, + true); } void free_pointdensity(PointDensity *pd) @@ -384,78 +575,99 @@ void free_pointdensities(Render *re) typedef struct PointDensityRangeData { float *density; float squared_radius; - const float *point_data; + float *point_data_life; + float *point_data_velocity; + float *point_data_color; float *vec; + float *col; float softness; short falloff_type; short noise_influence; float *age; - int point_data_used; - int offset; struct CurveMapping *density_curve; float velscale; } PointDensityRangeData; -static void accum_density(void *userdata, int index, float squared_dist) +static float density_falloff(PointDensityRangeData *pdr, 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->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; - } - - 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 = sqrtf(dist); - else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) { - if (pdr->point_data_used & POINT_DATA_LIFE) - density = dist * MIN2(pdr->point_data[pdr->offset + index], 1.0f); - else - density = dist; - } - else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) { - if (pdr->point_data_used & POINT_DATA_VEL) - density = dist * len_v3(pdr->point_data + index * 3) * pdr->velscale; - else + + switch (pdr->falloff_type) { + case TEX_PD_FALLOFF_STD: density = dist; + break; + case TEX_PD_FALLOFF_SMOOTH: + density = 3.0f * dist * dist - 2.0f * dist * dist * dist; + break; + case TEX_PD_FALLOFF_SOFT: + density = pow(dist, pdr->softness); + break; + case TEX_PD_FALLOFF_CONSTANT: + density = pdr->squared_radius; + break; + case TEX_PD_FALLOFF_ROOT: + density = sqrtf(dist); + break; + case TEX_PD_FALLOFF_PARTICLE_AGE: + if (pdr->point_data_life) + density = dist * MIN2(pdr->point_data_life[index], 1.0f); + else + density = dist; + break; + case TEX_PD_FALLOFF_PARTICLE_VEL: + if (pdr->point_data_velocity) + density = dist * len_v3(&pdr->point_data_velocity[index * 3]) * pdr->velscale; + else + density = dist; + break; } - + if (pdr->density_curve && dist != 0.0f) { curvemapping_initialize(pdr->density_curve); density = curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist; } + + return density; +} + +static void accum_density(void *userdata, int index, const float co[3], float squared_dist) +{ + PointDensityRangeData *pdr = (PointDensityRangeData *)userdata; + float density = 0.0f; + + UNUSED_VARS(co); + + if (pdr->point_data_velocity) { + pdr->vec[0] += pdr->point_data_velocity[index * 3 + 0]; // * density; + pdr->vec[1] += pdr->point_data_velocity[index * 3 + 1]; // * density; + pdr->vec[2] += pdr->point_data_velocity[index * 3 + 2]; // * density; + } + if (pdr->point_data_life) { + *pdr->age += pdr->point_data_life[index]; // * density; + } + if (pdr->point_data_color) { + add_v3_v3(pdr->col, &pdr->point_data_color[index * 3]); // * density; + } + + density = density_falloff(pdr, index, squared_dist); *pdr->density += density; } static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr, - float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale) + float *density, float *vec, float *age, float *col, struct CurveMapping *density_curve, float velscale) { 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->col = col; 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; + point_data_pointers(pd, &pdr->point_data_velocity, &pdr->point_data_life, &pdr->point_data_color); pdr->density_curve = density_curve; pdr->velscale = velscale; } @@ -464,13 +676,14 @@ static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData * static int pointdensity(PointDensity *pd, const float texvec[3], TexResult *texres, + float r_vec[3], float *r_age, - float r_vec[3]) + float r_col[3]) { int retval = TEX_INT; PointDensityRangeData pdr; float density = 0.0f, age = 0.0f, time = 0.0f; - float vec[3] = {0.0f, 0.0f, 0.0f}, co[3]; + float vec[3] = {0.0f, 0.0f, 0.0f}, col[3] = {0.0f, 0.0f, 0.0f}, co[3]; float turb, noise_fac; int num = 0; @@ -479,7 +692,7 @@ static int pointdensity(PointDensity *pd, if ((!pd) || (!pd->point_tree)) return 0; - init_pointdensityrangedata(pd, &pdr, &density, vec, &age, + init_pointdensityrangedata(pd, &pdr, &density, vec, &age, col, (pd->flag & TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), pd->falloff_speed_scale * 0.001f); noise_fac = pd->noise_fac * 0.5f; /* better default */ @@ -493,10 +706,13 @@ static int pointdensity(PointDensity *pd, if (num > 0) { age /= num; mul_v3_fl(vec, 1.0f / num); + mul_v3_fl(col, 1.0f / num); } /* reset */ - density = vec[0] = vec[1] = vec[2] = 0.0f; + density = 0.0f; + zero_v3(vec); + zero_v3(col); } if (pd->flag & TEX_PD_TURBULENCE) { @@ -529,6 +745,7 @@ static int pointdensity(PointDensity *pd, if (num > 0) { age /= num; mul_v3_fl(vec, 1.0f / num); + mul_v3_fl(col, 1.0f / num); } texres->tin = density; @@ -538,51 +755,88 @@ static int pointdensity(PointDensity *pd, if (r_vec != NULL) { copy_v3_v3(r_vec, vec); } + if (r_col != NULL) { + copy_v3_v3(r_col, col); + } return retval; } -static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3]) +static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3], const float col[3]) { - int retval = 0; - float col[4]; - - retval |= TEX_RGB; + int retval = TEX_RGB; - switch (pd->color_source) { - case TEX_PD_COLOR_PARTAGE: - if (pd->coba) { - if (do_colorband(pd->coba, age, col)) { - texres->talpha = true; - copy_v3_v3(&texres->tr, col); - texres->tin *= col[3]; - texres->ta = texres->tin; + if (pd->source == TEX_PD_PSYS) { + float rgba[4]; + + switch (pd->color_source) { + case TEX_PD_COLOR_PARTAGE: + if (pd->coba) { + if (do_colorband(pd->coba, age, rgba)) { + texres->talpha = true; + copy_v3_v3(&texres->tr, rgba); + texres->tin *= rgba[3]; + texres->ta = texres->tin; + } } + break; + case TEX_PD_COLOR_PARTSPEED: + { + float speed = len_v3(vec) * pd->speed_scale; + + if (pd->coba) { + if (do_colorband(pd->coba, speed, rgba)) { + texres->talpha = true; + copy_v3_v3(&texres->tr, rgba); + texres->tin *= rgba[3]; + texres->ta = texres->tin; + } + } + break; } - break; - case TEX_PD_COLOR_PARTSPEED: - { - float speed = len_v3(vec) * pd->speed_scale; - - if (pd->coba) { - if (do_colorband(pd->coba, speed, col)) { - texres->talpha = true; + case TEX_PD_COLOR_PARTVEL: + texres->talpha = true; + mul_v3_v3fl(&texres->tr, vec, pd->speed_scale); + texres->ta = texres->tin; + break; + case TEX_PD_COLOR_CONSTANT: + default: + texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; + retval = TEX_INT; + break; + } + } + else { + float rgba[4]; + + switch (pd->ob_color_source) { + case TEX_PD_COLOR_VERTCOL: + texres->talpha = true; + copy_v3_v3(&texres->tr, col); + texres->ta = texres->tin; + break; + case TEX_PD_COLOR_VERTWEIGHT: + texres->talpha = true; + if (pd->coba && do_colorband(pd->coba, col[0], rgba)) { + copy_v3_v3(&texres->tr, rgba); + texres->tin *= rgba[3]; + } + else { copy_v3_v3(&texres->tr, col); - texres->tin *= col[3]; - texres->ta = texres->tin; } - } - break; + texres->ta = texres->tin; + break; + case TEX_PD_COLOR_VERTNOR: + texres->talpha = true; + copy_v3_v3(&texres->tr, col); + texres->ta = texres->tin; + break; + case TEX_PD_COLOR_CONSTANT: + default: + texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; + retval = TEX_INT; + break; } - case TEX_PD_COLOR_PARTVEL: - texres->talpha = true; - mul_v3_v3fl(&texres->tr, vec, pd->speed_scale); - texres->ta = texres->tin; - break; - case TEX_PD_COLOR_CONSTANT: - default: - texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; - break; } return retval; @@ -593,13 +847,12 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres) PointDensity *pd = tex->pd; float age = 0.0f; float vec[3] = {0.0f, 0.0f, 0.0f}; - int retval = pointdensity(pd, texvec, texres, &age, vec); - - BRICONT; + float col[3] = {0.0f, 0.0f, 0.0f}; + int retval = pointdensity(pd, texvec, texres, vec, &age, col); - retval |= pointdensity_color(pd, texres, age, vec); + retval |= pointdensity_color(pd, texres, age, vec, col); BRICONTRGB; - + return retval; #if 0 @@ -614,100 +867,219 @@ static void sample_dummy_point_density(int resolution, float *values) memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution); } -static void particle_system_minmax(Object *object, +static void particle_system_minmax(Scene *scene, + Object *object, ParticleSystem *psys, float radius, + const bool use_render_params, float min[3], float max[3]) { + const float size[3] = {radius, radius, radius}; + const float cfra = BKE_scene_frame_get(scene); ParticleSettings *part = psys->part; - float imat[4][4]; - float size[3] = {radius, radius, radius}; - PARTICLE_P; + ParticleSimulationData sim = {NULL}; + ParticleData *pa = NULL; + int i; + int total_particles; + float mat[4][4], imat[4][4]; + INIT_MINMAX(min, max); if (part->type == PART_HAIR) { /* TOOD(sergey): Not supported currently. */ return; } + + unit_m4(mat); + if (use_render_params) { + psys_render_set(object, psys, mat, mat, 1, 1, 0); + } + + sim.scene = scene; + sim.ob = object; + sim.psys = psys; + sim.psmd = psys_get_modifier(object, psys); + invert_m4_m4(imat, object->obmat); - LOOP_PARTICLES { + total_particles = psys->totpart + psys->totchild; + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) { float co_object[3], co_min[3], co_max[3]; - mul_v3_m4v3(co_object, imat, pa->state.co); + ParticleKey state; + state.time = cfra; + if (!psys_get_particle_state(&sim, i, &state, 0)) { + continue; + } + mul_v3_m4v3(co_object, imat, state.co); sub_v3_v3v3(co_min, co_object, size); add_v3_v3v3(co_max, co_object, size); minmax_v3v3_v3(min, max, co_min); minmax_v3v3_v3(min, max, co_max); } + + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; + } + + if (use_render_params) { + psys_render_restore(object, psys); + } } -void RE_sample_point_density(Scene *scene, PointDensity *pd, - int resolution, float *values) +void RE_point_density_cache( + Scene *scene, + PointDensity *pd, + const bool use_render_params) { - const size_t resolution2 = resolution * resolution; - Object *object = pd->object; - size_t x, y, z; - float min[3], max[3], dim[3], mat[4][4]; + float mat[4][4]; + /* Same matricies/resolution as dupli_render_particle_set(). */ + unit_m4(mat); + BLI_mutex_lock(&sample_mutex); + cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params); + BLI_mutex_unlock(&sample_mutex); +} +void RE_point_density_minmax( + struct Scene *scene, + struct PointDensity *pd, + const bool use_render_params, + float r_min[3], float r_max[3]) +{ + Object *object = pd->object; if (object == NULL) { - sample_dummy_point_density(resolution, values); + zero_v3(r_min); + zero_v3(r_max); return; } - if (pd->source == TEX_PD_PSYS) { ParticleSystem *psys; if (pd->psys == 0) { - sample_dummy_point_density(resolution, values); + zero_v3(r_min); + zero_v3(r_max); return; } psys = BLI_findlink(&object->particlesystem, pd->psys - 1); if (psys == NULL) { - sample_dummy_point_density(resolution, values); + zero_v3(r_min); + zero_v3(r_max); return; } - particle_system_minmax(object, psys, pd->radius, min, max); + particle_system_minmax(scene, + object, + psys, + pd->radius, + use_render_params, + r_min, r_max); } else { float radius[3] = {pd->radius, pd->radius, pd->radius}; float *loc, *size; - BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL); - sub_v3_v3v3(min, loc, size); - add_v3_v3v3(max, loc, size); - /* Adjust texture space to include density points on the boundaries. */ - sub_v3_v3(min, radius); - add_v3_v3(max, radius); + + if (BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL)) { + sub_v3_v3v3(r_min, loc, size); + add_v3_v3v3(r_max, loc, size); + /* Adjust texture space to include density points on the boundaries. */ + sub_v3_v3(r_min, radius); + add_v3_v3(r_max, radius); + } + else { + zero_v3(r_min); + zero_v3(r_max); + } } +} +typedef struct SampleCallbackData { + PointDensity *pd; + int resolution; + float *min, *dim; + float *values; +} SampleCallbackData; + +static void point_density_sample_func(void *data_v, const int iter) +{ + SampleCallbackData *data = (SampleCallbackData *)data_v; + + const int resolution = data->resolution; + const int resolution2 = resolution * resolution; + const float *min = data->min, *dim = data->dim; + PointDensity *pd = data->pd; + float *values = data->values; + + size_t z = (size_t)iter; + for (size_t y = 0; y < resolution; ++y) { + for (size_t x = 0; x < resolution; ++x) { + size_t index = z * resolution2 + y * resolution + x; + float texvec[3]; + float age, vec[3], col[3]; + TexResult texres; + + copy_v3_v3(texvec, min); + texvec[0] += dim[0] * (float)x / (float)resolution; + texvec[1] += dim[1] * (float)y / (float)resolution; + texvec[2] += dim[2] * (float)z / (float)resolution; + + pointdensity(pd, texvec, &texres, vec, &age, col); + pointdensity_color(pd, &texres, age, vec, col); + + copy_v3_v3(&values[index*4 + 0], &texres.tr); + values[index*4 + 3] = texres.tin; + } + } +} + +/* NOTE 1: Requires RE_point_density_cache() to be called first. + * NOTE 2: Frees point density structure after sampling. + */ +void RE_point_density_sample( + Scene *scene, + PointDensity *pd, + const int resolution, + const bool use_render_params, + float *values) +{ + Object *object = pd->object; + float min[3], max[3], dim[3]; + + /* TODO(sergey): Implement some sort of assert() that point density + * was cached already. + */ + + if (object == NULL) { + sample_dummy_point_density(resolution, values); + return; + } + + BLI_mutex_lock(&sample_mutex); + RE_point_density_minmax(scene, + pd, + use_render_params, + min, + max); + BLI_mutex_unlock(&sample_mutex); sub_v3_v3v3(dim, max, min); if (dim[0] <= 0.0f || dim[1] <= 0.0f || dim[2] <= 0.0f) { sample_dummy_point_density(resolution, values); return; } - /* Same matricies/resolution as dupli_render_particle_set(). */ - unit_m4(mat); + SampleCallbackData data; + data.pd = pd; + data.resolution = resolution; + data.min = min; + data.dim = dim; + data.values = values; + BLI_task_parallel_range(0, + resolution, + &data, + point_density_sample_func, + resolution > 32); - BLI_mutex_lock(&sample_mutex); - cache_pointdensity_ex(scene, pd, mat, mat, 1, 1); - for (z = 0; z < resolution; ++z) { - for (y = 0; y < resolution; ++y) { - for (x = 0; x < resolution; ++x) { - size_t index = z * resolution2 + y * resolution + x; - float texvec[3]; - float age, vec[3]; - TexResult texres; - - copy_v3_v3(texvec, min); - texvec[0] += dim[0] * (float)x / (float)resolution; - texvec[1] += dim[1] * (float)y / (float)resolution; - texvec[2] += dim[2] * (float)z / (float)resolution; - - pointdensity(pd, texvec, &texres, &age, vec); - pointdensity_color(pd, &texres, age, vec); - - copy_v3_v3(&values[index*4 + 0], &texres.tr); - values[index*4 + 3] = texres.tin; - } - } - } free_pointdensity(pd); - BLI_mutex_unlock(&sample_mutex); +} + +void RE_point_density_free(struct PointDensity *pd) +{ + free_pointdensity(pd); } |