Curve-based control for child path tapering.

This is an alternative method to the current fixed function with a
clump factor and "shape" parameter. This function is quite limited and
does not give the desired result in many cases (e.g. long, parallel
rasta strands are problematic). So rather than trying to add more
parameters there is now a fully user-defined optional curve for setting
the tapering shape.
This commit is contained in:
Lukas Tönne 2015-01-09 14:24:19 +01:00
parent 4c82367fd8
commit c86d55d5e7
10 changed files with 108 additions and 14 deletions

View File

@ -1167,8 +1167,12 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
col.label(text="Effects:")
sub = col.column(align=True)
sub.prop(part, "clump_factor", slider=True)
sub.prop(part, "clump_shape", slider=True)
sub.prop(part, "use_clump_curve")
if part.use_clump_curve:
sub.template_curve_mapping(part, "clump_curve")
else:
sub.prop(part, "clump_factor", slider=True)
sub.prop(part, "clump_shape", slider=True)
sub = col.column(align=True)
sub.prop(part, "child_length", slider=True)

View File

@ -330,7 +330,7 @@ void psys_find_parents(struct ParticleSimulationData *sim);
void psys_cache_paths(struct ParticleSimulationData *sim, float cfra);
void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra);
void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, int editupdate);
int do_guides(struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
int do_guides(struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors);
float psys_get_timestep(struct ParticleSimulationData *sim);
float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime);
@ -339,6 +339,7 @@ void psys_get_particle_on_path(struct ParticleSimulationData *sim, int pa_num, s
int psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, int always);
/* child paths */
void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
void psys_apply_child_modifiers(struct ParticleThreadContext *ctx, struct ListBase *modifiers,
struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys);

View File

@ -64,6 +64,7 @@
#include "BKE_boids.h"
#include "BKE_cloth.h"
#include "BKE_colortools.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_group.h"
@ -373,6 +374,10 @@ void BKE_particlesettings_free(ParticleSettings *part)
MTex *mtex;
int a;
BKE_free_animdata(&part->id);
if (part->clumpcurve)
curvemapping_free(part->clumpcurve);
free_partdeflect(part->pd);
free_partdeflect(part->pd2);
@ -1665,7 +1670,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
extern void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat,
short type, short axis, float obmat[4][4], int smooth_start);
extern float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump);
extern float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve);
void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
{
@ -1708,7 +1713,7 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
}
}
int do_guides(ListBase *effectors, ParticleKey *state, int index, float time)
int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time)
{
EffectorCache *eff;
PartDeflect *pd;
@ -1777,10 +1782,14 @@ int do_guides(ListBase *effectors, ParticleKey *state, int index, float time)
mul_v3_fl(vec_to_point, radius);
}
}
if (part->clumpcurve)
curvemapping_changed_all(part->clumpcurve);
par.co[0] = par.co[1] = par.co[2] = 0.0f;
copy_v3_v3(key.co, vec_to_point);
do_kink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0);
do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f);
do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f, part->clumpcurve);
copy_v3_v3(vec_to_point, key.co);
add_v3_v3(vec_to_point, guidevec);
@ -1979,6 +1988,10 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
if (psys->part->flag & PART_CHILD_EFFECT)
ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR);
/* prepare curvemapping tables */
if (part->clumpcurve)
curvemapping_changed_all(part->clumpcurve);
return true;
}
@ -2545,7 +2558,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
if (sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT) == 0) {
for (k = 0, ca = cache[p]; k <= steps; k++, ca++)
/* ca is safe to cast, since only co and vel are used */
do_guides(sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)steps);
do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)steps);
}
/* lattices have to be calculated separately to avoid mixups between effector calculations */
@ -3141,6 +3154,18 @@ ParticleSettings *psys_new_settings(const char *name, Main *main)
return part;
}
void BKE_particlesettings_clump_curve_init(ParticleSettings *part)
{
CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
cumap->cm[0].curve[0].x = 0.0f;
cumap->cm[0].curve[0].y = 1.0f;
cumap->cm[0].curve[1].x = 1.0f;
cumap->cm[0].curve[1].y = 1.0f;
part->clumpcurve = cumap;
}
ParticleSettings *BKE_particlesettings_copy(ParticleSettings *part)
{
ParticleSettings *partn;
@ -3152,6 +3177,9 @@ ParticleSettings *BKE_particlesettings_copy(ParticleSettings *part)
partn->effector_weights = MEM_dupallocN(part->effector_weights);
partn->fluid = MEM_dupallocN(part->fluid);
if (part->clumpcurve)
partn->clumpcurve = curvemapping_copy(part->clumpcurve);
partn->boids = boid_copy_settings(part->boids);
for (a = 0; a < MAX_MTEX; a++) {
@ -3604,7 +3632,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
mul_mat3_m4_v3(hairmat, state->vel);
if (sim->psys->effectors && (part->flag & PART_CHILD_GUIDE) == 0) {
do_guides(sim->psys->effectors, state, p, state->time);
do_guides(sim->psys->part, sim->psys->effectors, state, p, state->time);
/* TODO: proper velocity handling */
}

View File

@ -34,13 +34,14 @@
#include "DNA_material_types.h"
#include "BKE_colortools.h"
#include "BKE_particle.h"
struct Material;
void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat,
short type, short axis, float obmat[4][4], int smooth_start);
float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump);
float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve);
void do_child_modifiers(ParticleSimulationData *sim,
ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa,
const float orco[3], float mat[4][4], ParticleKey *state, float t);
@ -359,11 +360,19 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f
copy_v3_v3(state->co, result);
}
float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump)
float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve)
{
float clump = 0.f;
if (par && clumpfac != 0.0f) {
if (!par)
return 0.0f;
if (clumpcurve) {
clump = pa_clump * (1.0f - CLAMPIS(curvemapping_evaluateF(clumpcurve, 0, time), 0.0f, 1.0f));
interp_v3_v3v3(state->co, state->co, par->co, clump);
}
else if (clumpfac != 0.0f) {
float cpow;
if (clumppow < 0.0f)
@ -439,10 +448,10 @@ void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, Part
if (part->flag & PART_CHILD_EFFECT)
/* state is safe to cast, since only co and vel are used */
guided = do_guides(sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
guided = do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
if (guided == 0) {
float clump = do_clump(state, par, t, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f);
float clump = do_clump(state, par, t, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f, part->clumpcurve);
if (kink_freq != 0.f) {
float kink_amp = part->kink_amp * (1.f - part->kink_amp_clump * clump);

View File

@ -2089,7 +2089,7 @@ static void basic_integrate(ParticleSimulationData *sim, int p, float dfra, floa
tkey.time=pa->state.time;
if (part->type != PART_HAIR) {
if (do_guides(sim->psys->effectors, &tkey, p, time)) {
if (do_guides(sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
copy_v3_v3(pa->state.co,tkey.co);
/* guides don't produce valid velocity */
sub_v3_v3v3(pa->state.vel, tkey.co, pa->prev_state.co);

View File

@ -3816,6 +3816,10 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
direct_link_partdeflect(part->pd);
direct_link_partdeflect(part->pd2);
part->clumpcurve = newdataadr(fd, part->clumpcurve);
if (part->clumpcurve)
direct_link_curvemapping(fd, part->clumpcurve);
part->effector_weights = newdataadr(fd, part->effector_weights);
if (!part->effector_weights)
part->effector_weights = BKE_add_effector_weights(part->eff_group);

View File

@ -1108,6 +1108,9 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase)
writestruct(wd, DATA, "PartDeflect", 1, part->pd2);
writestruct(wd, DATA, "EffectorWeights", 1, part->effector_weights);
if (part->clumpcurve)
write_curvemapping(wd, part->clumpcurve);
dw = part->dupliweights.first;
for (; dw; dw=dw->next) {
/* update indices */

View File

@ -233,6 +233,7 @@ typedef struct ParticleSettings {
int trail_count;
/* keyed particles */
int keyed_loops;
struct CurveMapping *clumpcurve;
/* hair dynamics */
float bending_random;

View File

@ -46,6 +46,8 @@
#include "DNA_material_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_sequence_types.h"
#include "MEM_guardedalloc.h"
@ -345,6 +347,13 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
WM_main_add_notifier(NC_LINESTYLE, linestyle);
break;
}
case ID_PA:
{
ParticleSettings *part = ptr->id.data;
DAG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, part);
}
default:
break;
}

View File

@ -131,6 +131,7 @@ static EnumPropertyItem part_hair_ren_as_items[] = {
#include "BKE_context.h"
#include "BKE_cloth.h"
#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
@ -874,6 +875,29 @@ static int rna_PartSettings_is_fluid_get(PointerRNA *ptr)
return part->type == PART_FLUID;
}
int rna_ParticleSettings_use_clump_curve_get(PointerRNA *ptr)
{
ParticleSettings *part = ptr->data;
return part->clumpcurve != NULL;
}
void rna_ParticleSettings_use_clump_curve_set(PointerRNA *ptr, int value)
{
ParticleSettings *part = ptr->data;
if (!value) {
if (part->clumpcurve) {
curvemapping_free(part->clumpcurve);
part->clumpcurve = NULL;
}
}
else {
if (!part->clumpcurve) {
BKE_particlesettings_clump_curve_init(part);
}
}
}
static void rna_ParticleSystem_name_set(PointerRNA *ptr, const char *value)
{
Object *ob = ptr->id.data;
@ -2797,6 +2821,17 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shape", "Shape of clumping");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
prop = RNA_def_property(srna, "use_clump_curve", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_ParticleSettings_use_clump_curve_get", "rna_ParticleSettings_use_clump_curve_set");
RNA_def_property_ui_text(prop, "Use Clump Curve", "Use a curve to define clump tapering");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
prop = RNA_def_property(srna, "clump_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "clumpcurve");
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Clump Curve", "Curve defining clump tapering");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
/* kink */
prop = RNA_def_property(srna, "kink_amplitude", PROP_FLOAT, PROP_NONE);