Curve-based control for child path tapering.
authorLukas Tönne <lukas.toenne@gmail.com>
Fri, 9 Jan 2015 13:24:19 +0000 (14:24 +0100)
committerLukas Tönne <lukas.toenne@gmail.com>
Tue, 20 Jan 2015 08:30:09 +0000 (09:30 +0100)
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.

release/scripts/startup/bl_ui/properties_particle.py
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_child.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/makesdna/DNA_particle_types.h
source/blender/makesrna/intern/rna_color.c
source/blender/makesrna/intern/rna_particle.c

index 9ebcb2adf98123950bcdd83aad071ac4b58fd511..c5723ea4c711d66b2c8b2f98210715ef9accedee 100644 (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)
index 54901448563a183bd8148de0dfb18d517d6c0220..cb7660824676963b0ef192df2e8eaaf6c485a18b 100644 (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);
index efcc0ebca219989d3920e2ad00b2af105bedc5b2..1001dde2561581c1b70f166d20e1c867d6abbfe3 100644 (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 */
                                        }
 
index fb261b248dc44fc0bc06d021697dc3d9950d251e..68e11c9368ecfddc41eb325f2984622c2d70bf27 100644 (file)
 
 #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);
index 6e7e341e1cc18a9f24ca3ae9175c05532e7e7d17..8c0840ad65187a8c59ad86d8b973199ca16bbbf5 100644 (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);
index 3b2179e9c47887b0cab84285972ce03fe25704ff..10bdfbd70e7b94cb2fa5106e6745b789eebb13dd 100644 (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);
index adb37aaab718754eaf3e6e03ca8a43c644939375..81f4c16cea14dae517ff7e5255ff9533166945cf 100644 (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 */
index 0b1f85c043a14f9897c9364b1564fa5712580a6a..6d119b039bd86b823806ffac018d6ad82b2a28d2 100644 (file)
@@ -233,6 +233,7 @@ typedef struct ParticleSettings {
        int trail_count;
        /* keyed particles */
        int keyed_loops;
+       struct CurveMapping *clumpcurve;
 
        /* hair dynamics */
        float bending_random;
index 37201eca5f6d10b64015bbd08529c8024dcfd98d..5e114a51ceb0eacb586254d7305dd1283591e1e2 100644 (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;
                }
index 6d411cf76083c27dbc8855c4fab0e3eaa59fd5fa..6540604199d1b3bc1af742525058aac54942d998 100644 (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);