Merge branch 'master' into blender2.8
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 15 Feb 2018 11:33:44 +0000 (12:33 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 15 Feb 2018 11:33:44 +0000 (12:33 +0100)
16 files changed:
release/scripts/startup/bl_ui/properties_particle.py
release/scripts/startup/bl_ui/properties_texture.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/blenkernel/intern/smoke.c
source/blender/blenkernel/intern/texture.c
source/blender/blenkernel/particle_private.h
source/blender/blenlib/intern/math_vector.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_particle_types.h
source/blender/makesdna/DNA_texture_types.h
source/blender/makesrna/intern/rna_particle.c

index 4932f3467c570b423234e0392d52a3f41c9b7627..017c1b40386f526af0562327ab58fcf9a6c8733e 100644 (file)
@@ -1197,6 +1197,12 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
         col.label(text="Effects:")
 
         sub = col.column(align=True)
+        if part.child_type == 'SIMPLE':
+            sub.prop(part, "twist")
+            sub.prop(part, "use_twist_curve")
+            if part.use_twist_curve:
+                sub.template_curve_mapping(part, "twist_curve")
+
         sub.prop(part, "use_clump_curve")
         if part.use_clump_curve:
             sub.template_curve_mapping(part, "clump_curve")
@@ -1384,6 +1390,10 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel):
         row.prop_search(psys, "vertex_group_roughness_end", ob, "vertex_groups", text="Roughness End")
         row.prop(psys, "invert_vertex_group_roughness_end", text="", toggle=True, icon='ARROW_LEFTRIGHT')
 
+        row = col.row(align=True)
+        row.prop_search(psys, "vertex_group_twist", ob, "vertex_groups", text="Twist")
+        row.prop(psys, "invert_vertex_group_twist", text="", toggle=True, icon='ARROW_LEFTRIGHT')
+
         # Commented out vertex groups don't work and are still waiting for better implementation
         # row = layout.row()
         # row.prop_search(psys, "vertex_group_velocity", ob, "vertex_groups", text="Velocity")
index 01c36347b56d4f46696f729a396c7d5a6d63c218..38a7fff8ed339157029c6d3961aa387ef6c4f78d 100644 (file)
@@ -1173,6 +1173,7 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel):
             col = split.column()
             factor_but(col, "use_map_length", "length_factor", "Length")
             factor_but(col, "use_map_clump", "clump_factor", "Clump")
+            factor_but(col, "use_map_twist", "twist_factor", "Twist")
 
             col = split.column()
             factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude")
index 9492f7e32fa6482e365deb79e3b1e20e3323fd98..2db4126057abc00dcce6ec336523922751f16543 100644 (file)
@@ -115,6 +115,7 @@ typedef struct ParticleTexture {
        float damp, gravity, field;           /* used in physics */
        float length, clump, kink_freq, kink_amp, effector;  /* used in path caching */
        float rough1, rough2, roughe;         /* used in path caching */
+       float twist;  /* used in path caching */
 } ParticleTexture;
 
 typedef struct ParticleSeam {
@@ -162,9 +163,11 @@ typedef struct ParticleThreadContext {
        float *vg_length, *vg_clump, *vg_kink;
        float *vg_rough1, *vg_rough2, *vg_roughe;
        float *vg_effector;
+       float *vg_twist;
 
        struct CurveMapping *clumpcurve;
        struct CurveMapping *roughcurve;
+       struct CurveMapping *twistcurve;
 } ParticleThreadContext;
 
 typedef struct ParticleTask {
@@ -353,6 +356,7 @@ int psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct Pa
 /* child paths */
 void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
 void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
+void BKE_particlesettings_twist_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, const float parent_orco[3]);
index ef2ed9e2b6583bd2de3cbc136eb10eb4bbea5e8f..ff70e71edd43804089becd995133c291780d3855 100644 (file)
@@ -413,6 +413,8 @@ void BKE_particlesettings_free(ParticleSettings *part)
                curvemapping_free(part->clumpcurve);
        if (part->roughcurve)
                curvemapping_free(part->roughcurve);
+       if (part->twistcurve)
+               curvemapping_free(part->twistcurve);
        
        free_partdeflect(part->pd);
        free_partdeflect(part->pd2);
@@ -2144,6 +2146,7 @@ static bool psys_thread_context_init_path(
        ctx->vg_rough1 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH1);
        ctx->vg_rough2 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH2);
        ctx->vg_roughe = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGHE);
+       ctx->vg_twist = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_TWIST);
        if (psys->part->flag & PART_CHILD_EFFECT)
                ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR);
 
@@ -2162,6 +2165,13 @@ static bool psys_thread_context_init_path(
        else {
                ctx->roughcurve = NULL;
        }
+       if ((part->child_flag & PART_CHILD_USE_TWIST_CURVE) && part->twistcurve) {
+               ctx->twistcurve = curvemapping_copy(part->twistcurve);
+               curvemapping_changed_all(ctx->twistcurve);
+       }
+       else {
+               ctx->twistcurve = NULL;
+       }
 
        return true;
 }
@@ -2306,7 +2316,19 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
 
                /* get the original coordinates (orco) for texture usage */
                cpa_from = part->from;
-               cpa_num = pa->num;
+
+               /*
+                * NOTE: Should in theory be the same as:
+                cpa_num = psys_particle_dm_face_lookup(
+                       ctx->sim.psmd->dm_final,
+                       ctx->sim.psmd->dm_deformed,
+                       pa->num, pa->fuv,
+                       NULL);
+               */
+               cpa_num = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND))
+                       ? pa->num
+                       : pa->num_dmcache;
+
                /* XXX hack to avoid messed up particle num and subsequent crash (#40733) */
                if (cpa_num > ctx->sim.psmd->dm_final->getNumTessFaces(ctx->sim.psmd->dm_final))
                        cpa_num = 0;
@@ -3349,6 +3371,18 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part)
        part->roughcurve = cumap;
 }
 
+void BKE_particlesettings_twist_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->twistcurve = cumap;
+}
+
 /**
  * Only copy internal data of ParticleSettings ID from source to already allocated/initialized destination.
  * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
@@ -3371,6 +3405,9 @@ void BKE_particlesettings_copy_data(
        if (part_src->roughcurve) {
                part_dst->roughcurve = curvemapping_copy(part_src->roughcurve);
        }
+       if (part_src->twistcurve) {
+               part_dst->twistcurve = curvemapping_copy(part_src->twistcurve);
+       }
 
        part_dst->boids = boid_copy_settings(part_src->boids);
 
@@ -3490,6 +3527,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
        ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp =
        ptex->gravity = ptex->field = ptex->time = ptex->clump = ptex->kink_freq = ptex->kink_amp =
        ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
+       ptex->twist = 1.0f;
 
        ptex->length = 1.0f - part->randlength * psys_frand(psys, child_index + 26);
        ptex->length *= part->clength_thres < psys_frand(psys, child_index + 27) ? part->clength : 1.0f;
@@ -3542,6 +3580,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
                        SET_PARTICLE_TEXTURE(PAMAP_KINK_AMP, ptex->kink_amp, mtex->kinkampfac);
                        SET_PARTICLE_TEXTURE(PAMAP_KINK_FREQ, ptex->kink_freq, mtex->kinkfac);
                        SET_PARTICLE_TEXTURE(PAMAP_DENS, ptex->exist, mtex->padensfac);
+                       SET_PARTICLE_TEXTURE(PAMAP_TWIST, ptex->twist, mtex->twistfac);
                }
        }
 
@@ -3567,6 +3606,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
        ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp =
        ptex->gravity = ptex->field = ptex->length = ptex->clump = ptex->kink_freq = ptex->kink_amp =
        ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
+       ptex->twist = 1.0f;
 
        ptex->time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart;
 
@@ -3641,6 +3681,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
                        SET_PARTICLE_TEXTURE(PAMAP_GRAVITY, ptex->gravity, mtex->gravityfac);
                        SET_PARTICLE_TEXTURE(PAMAP_DAMP, ptex->damp, mtex->dampfac);
                        SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac);
+                       SET_PARTICLE_TEXTURE(PAMAP_TWIST, ptex->twist, mtex->twistfac);
                }
        }
 
@@ -3732,6 +3773,8 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
                ptex->roughe *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe);
        if (ctx->vg_effector)
                ptex->effector *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
+       if (ctx->vg_twist)
+               ptex->twist *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
 }
 /* get's hair (or keyed) particles state at the "path time" specified in state->time */
 void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, const bool vel)
@@ -3937,7 +3980,18 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
                                copy_particle_key(&tstate, state, 1);
 
                        /* apply different deformations to the child path */
-                       do_child_modifiers(NULL, sim, &ptex, par->co, par->vel, par->rot, par_orco, cpa, orco, hairmat, state, t);
+                       ParticleChildModifierContext modifier_ctx = {NULL};
+                       modifier_ctx.thread_ctx = NULL;
+                       modifier_ctx.sim = sim;
+                       modifier_ctx.ptex = &ptex;
+                       modifier_ctx.cpa = cpa;
+                       modifier_ctx.orco = orco;
+                       modifier_ctx.par_co = par->co;
+                       modifier_ctx.par_vel = par->vel;
+                       modifier_ctx.par_rot = par->rot;
+                       modifier_ctx.par_orco = par_orco;
+                       modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL;
+                       do_child_modifiers(&modifier_ctx, hairmat, state, t);
 
                        /* try to estimate correct velocity */
                        if (vel) {
@@ -4040,7 +4094,19 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
                        CLAMP(t, 0.0f, 1.0f);
 
                        unit_m4(mat);
-                       do_child_modifiers(NULL, sim, NULL, key1->co, key1->vel, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
+                       ParticleChildModifierContext modifier_ctx = {NULL};
+                       modifier_ctx.thread_ctx = NULL;
+                       modifier_ctx.sim = sim;
+                       modifier_ctx.ptex = NULL;
+                       modifier_ctx.cpa = cpa;
+                       modifier_ctx.orco = cpa->fuv;
+                       modifier_ctx.par_co = key1->co;
+                       modifier_ctx.par_vel = key1->vel;
+                       modifier_ctx.par_rot = key1->rot;
+                       modifier_ctx.par_orco = par_orco;
+                       modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL;
+
+                       do_child_modifiers(&modifier_ctx, mat, state, t);
 
                        if (psys->lattice_deform_data)
                                calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength);
index bc4c32f58053b9ec67a404e018d76cf721889e29..8cdd668b7e7e8602815206ce9ec62b266733edaf 100644 (file)
@@ -235,6 +235,15 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co
        kink_base[part->kink_axis] = 1.0f;
        mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base);
 
+       /* Fill in invariant part of modifier context. */
+       ParticleChildModifierContext modifier_ctx = {NULL};
+       modifier_ctx.thread_ctx = ctx;
+       modifier_ctx.sim = &ctx->sim;
+       modifier_ctx.ptex = ptex;
+       modifier_ctx.cpa = cpa;
+       modifier_ctx.orco = orco;
+       modifier_ctx.parent_keys = parent_keys;
+
        for (k = 0, key = keys; k < end_index; k++, key++) {
                float par_time;
                float *par_co, *par_vel, *par_rot;
@@ -274,8 +283,14 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co
                        do_kink_spiral_deform((ParticleKey *)key, dir, kink, spiral_time, kink_freq, kink_shape, kink_amp, spiral_start);
                }
 
-               /* apply different deformations to the child path */
-               do_child_modifiers(ctx, &ctx->sim, ptex, par_co, par_vel, par_rot, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, par_time);
+               /* Fill in variant part of modifier context. */
+               modifier_ctx.par_co = par_co;
+               modifier_ctx.par_vel = par_vel;
+               modifier_ctx.par_rot = par_rot;
+               modifier_ctx.par_orco = parent_orco;
+
+               /* Apply different deformations to the child path/ */
+               do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, par_time);
        }
 
        totlen = 0.0f;
@@ -331,19 +346,33 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
                keys->segments = totkeys - 1;
        }
        else {
-               ParticlePathIterator iter;
+               /* Fill in invariant part of modifier context. */
+               ParticleChildModifierContext modifier_ctx = {NULL};
+               modifier_ctx.thread_ctx = ctx;
+               modifier_ctx.sim = &ctx->sim;
+               modifier_ctx.ptex = ptex;
+               modifier_ctx.cpa = cpa;
+               modifier_ctx.orco = orco;
+               modifier_ctx.parent_keys = parent_keys;
 
                totkeys = ctx->segments + 1;
                max_length = ptex->length;
 
+               printf("%f\n", ptex->twist);
                for (k = 0, key = keys; k < totkeys; k++, key++) {
-                       ParticleKey *par;
-
+                       ParticlePathIterator iter;
                        psys_path_iter_get(&iter, keys, totkeys, parent_keys, k);
-                       par = (ParticleKey *)iter.parent_key;
 
-                       /* apply different deformations to the child path */
-                       do_child_modifiers(ctx, &ctx->sim, ptex, par->co, par->vel, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time);
+                       ParticleKey *par = (ParticleKey *)iter.parent_key;
+
+                       /* Fill in variant part of modifier context. */
+                       modifier_ctx.par_co = par->co;
+                       modifier_ctx.par_vel = par->vel;
+                       modifier_ctx.par_rot = iter.parent_rotation;
+                       modifier_ctx.par_orco = parent_orco;
+
+                       /* Apply different deformations to the child path. */
+                       do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, iter.time);
                }
        }
 
@@ -662,10 +691,100 @@ static void do_rough_curve(const float loc[3], float mat[4][4], float time, floa
        madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
 }
 
-void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim, ParticleTexture *ptex,
-                        const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
-                        ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t)
+static int twist_num_segments(const ParticleChildModifierContext *modifier_ctx)
+{
+       ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
+       return (thread_ctx != NULL) ? thread_ctx->segments
+                                   : modifier_ctx->sim->psys->part->draw_step;
+}
+
+static void twist_get_axis(const ParticleChildModifierContext *modifier_ctx,
+                           const float time, float r_axis[3])
+{
+       const int num_segments = twist_num_segments(modifier_ctx);
+       const int index = clamp_i(time * num_segments, 0, num_segments);
+       if (index > 0) {
+               sub_v3_v3v3(r_axis,
+                           modifier_ctx->parent_keys[index].co,
+                           modifier_ctx->parent_keys[index - 1].co);
+       }
+       else {
+               sub_v3_v3v3(r_axis,
+                           modifier_ctx->parent_keys[index + 1].co,
+                           modifier_ctx->parent_keys[index].co);
+       }
+}
+
+static float curvemapping_integrate_clamped(CurveMapping *curve,
+                                            float start, float end, float step)
+{
+       float integral = 0.0f;
+       float x = start;
+       while (x < end) {
+               float y = curvemapping_evaluateF(curve, 0, x);
+               y = clamp_f(y, 0.0f, 1.0f);
+               /* TODO(sergey): Clamp last step to end. */
+               integral += y * step;
+               x += step;
+       }
+       return integral;
+}
+
+static void do_twist(const ParticleChildModifierContext *modifier_ctx,
+                     ParticleKey *state, const float time)
+{
+       ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
+       ParticleSimulationData *sim = modifier_ctx->sim;
+       ParticleTexture *ptex = modifier_ctx->ptex;
+       ParticleSettings *part = sim->psys->part;
+       /* Early output checks. */
+       if (part->childtype != PART_CHILD_PARTICLES) {
+               /* Interpolated children behave weird with twist. */
+               return;
+       }
+       if (part->twist == 0.0f) {
+               /* No twist along the strand.  */
+               return;
+       }
+       /* Dependent on whether it's threaded update or not, curve comes
+        * from different places.
+        */
+       CurveMapping *twist_curve = NULL;
+       if (part->child_flag & PART_CHILD_USE_TWIST_CURVE) {
+               twist_curve = (thread_ctx != NULL) ? thread_ctx->twistcurve
+                                                  : part->twistcurve;
+       }
+       /* Axis of rotation. */
+       float axis[3];
+       twist_get_axis(modifier_ctx, time, axis);
+       /* Angle of rotation. */
+       float angle = part->twist;
+       if (ptex != NULL) {
+               angle *= (ptex->twist - 0.5f) * 2.0f;
+       }
+       if (twist_curve != NULL) {
+               const int num_segments = twist_num_segments(modifier_ctx);
+               angle *= curvemapping_integrate_clamped(twist_curve,
+                                                       0.0f, time,
+                                                       1.0f / num_segments);
+       }
+       else {
+               angle *= time;
+       }
+       /* Perform rotation around parent curve. */
+       float vec[3];
+       sub_v3_v3v3(vec, state->co, modifier_ctx->par_co);
+       rotate_v3_v3v3fl(state->co, vec, axis, angle * 2.0f * M_PI);
+       add_v3_v3(state->co, modifier_ctx->par_co);
+}
+
+void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
+                        float mat[4][4], ParticleKey *state, float t)
 {
+       ParticleThreadContext *ctx = modifier_ctx->thread_ctx;
+       ParticleSimulationData *sim = modifier_ctx->sim;
+       ParticleTexture *ptex = modifier_ctx->ptex;
+       ChildParticle *cpa = modifier_ctx->cpa;
        ParticleSettings *part = sim->psys->part;
        CurveMapping *clumpcurve = NULL, *roughcurve = NULL;
        int i = cpa - sim->psys->child;
@@ -694,6 +813,8 @@ void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim,
                rough_end *= ptex->roughe;
        }
 
+       do_twist(modifier_ctx, state, t);
+
        if (part->flag & PART_CHILD_EFFECT)
                /* state is safe to cast, since only co and vel are used */
                guided = do_guides(sim->eval_ctx, sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
@@ -702,25 +823,43 @@ void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim,
                float orco_offset[3];
                float clump;
 
-               sub_v3_v3v3(orco_offset, orco, par_orco);
-               clump = do_clump(state, par_co, t, orco_offset, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f,
-                                part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, clumpcurve);
+               sub_v3_v3v3(orco_offset, modifier_ctx->orco, modifier_ctx->par_orco);
+               clump = do_clump(state,
+                                modifier_ctx->par_co,
+                                t,
+                                orco_offset,
+                                part->clumpfac,
+                                part->clumppow,
+                                ptex ? ptex->clump : 1.0f,
+                                part->child_flag & PART_CHILD_USE_CLUMP_NOISE,
+                                part->clump_noise_size,
+                                clumpcurve);
 
                if (kink_freq != 0.f) {
                        kink_amp *= (1.f - kink_amp_clump * clump);
 
-                       do_kink(state, par_co, par_vel, par_rot, t, kink_freq, part->kink_shape,
-                               kink_amp, part->kink_flat, part->kink, part->kink_axis,
-                               sim->ob->obmat, smooth_start);
+                       do_kink(state,
+                               modifier_ctx->par_co,
+                               modifier_ctx->par_vel,
+                               modifier_ctx->par_rot,
+                               t,
+                               kink_freq,
+                               part->kink_shape,
+                               kink_amp,
+                               part->kink_flat,
+                               part->kink,
+                               part->kink_axis,
+                               sim->ob->obmat,
+                               smooth_start);
                }
        }
 
        if (roughcurve) {
-               do_rough_curve(orco, mat, t, rough1, part->rough1_size, roughcurve, state);
+               do_rough_curve(modifier_ctx->orco, mat, t, rough1, part->rough1_size, roughcurve, state);
        }
        else {
                if (rough1 > 0.f)
-                       do_rough(orco, mat, t, rough1, part->rough1_size, 0.0, state);
+                       do_rough(modifier_ctx->orco, mat, t, rough1, part->rough1_size, 0.0, state);
 
                if (rough2 > 0.f) {
                        float vec[3];
index 0fcc918a069fd027ccfa33bd7f67b39e2e6c9edb..8171f3e7812cb349c4c60d61118be530c03ebac2 100644 (file)
@@ -499,6 +499,8 @@ void psys_thread_context_free(ParticleThreadContext *ctx)
                MEM_freeN(ctx->vg_rough2);
        if (ctx->vg_roughe)
                MEM_freeN(ctx->vg_roughe);
+       if (ctx->vg_twist)
+               MEM_freeN(ctx->vg_twist);
 
        if (ctx->sim.psys->lattice_deform_data) {
                end_latt_deform(ctx->sim.psys->lattice_deform_data);
@@ -521,6 +523,9 @@ void psys_thread_context_free(ParticleThreadContext *ctx)
        if (ctx->roughcurve != NULL) {
                curvemapping_free(ctx->roughcurve);
        }
+       if (ctx->twistcurve != NULL) {
+               curvemapping_free(ctx->twistcurve);
+       }
 }
 
 static void initialize_particle_texture(ParticleSimulationData *sim, ParticleData *pa, int p)
index 9f9818127bcfde4b76a6622004ba221573a88946..4ab7b76aaabba2fd8c032af37e2a4bad6a1c6709 100644 (file)
@@ -1287,6 +1287,8 @@ static void emit_from_particles(
                        curvemapping_changed_all(psys->part->clumpcurve);
                if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
                        curvemapping_changed_all(psys->part->roughcurve);
+               if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve)
+                       curvemapping_changed_all(psys->part->twistcurve);
 
                /* initialize particle cache */
                if (psys->part->type == PART_HAIR) {
index fcedd8806158177b985d633ea270f8af19a77241..71b90641e025740a6a175b90dceb6df5a9d95997 100644 (file)
@@ -412,6 +412,7 @@ void BKE_texture_mtex_default(MTex *mtex)
        mtex->kinkfac = 1.0f;
        mtex->kinkampfac = 1.0f;
        mtex->roughfac = 1.0f;
+       mtex->twistfac = 1.0f;
        mtex->padensfac = 1.0f;
        mtex->lifefac = 1.0f;
        mtex->sizefac = 1.0f;
index b4878807df71256efca6f4183dbd2a93b16a2b50..2189527118b2f2f29a9b71bb27e2a1bda1f1cfa4 100644 (file)
 #ifndef __PARTICLE_PRIVATE_H__
 #define __PARTICLE_PRIVATE_H__
 
+typedef struct ParticleChildModifierContext {
+       ParticleThreadContext *thread_ctx;
+       ParticleSimulationData *sim;
+       ParticleTexture *ptex;
+       ChildParticle *cpa;
+       const float *par_co;    /* float3 */
+       const float *par_vel;   /* float3 */
+       const float *par_rot;   /* float4 */
+       const float *par_orco;  /* float3 */
+       const float *orco;      /* float3 */
+       ParticleCacheKey *parent_keys;
+} ParticleChildModifierContext;
+
 void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], const float par_rot[4], 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, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
                bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve);
-void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim,
-                        ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
-                        ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
+void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
+                        float mat[4][4], ParticleKey *state, float t);
 
 #endif /* __PARTICLE_PRIVATE_H__ */
index 0556250227860dd5922efa597a089d347a54059e..d6e48fa59e7dd91bf1d4b26c1bb94ecc760cca05 100644 (file)
@@ -890,6 +890,8 @@ void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axi
 
 void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle)
 {
+       BLI_assert(r != p);
+
        float axis_n[3];
 
        normalize_v3_v3(axis_n, axis);
index b75a2de935a77079cc6cce755b07cc5b018f7cf9..c20246bcbfbf1c2e87d54913c1fca792fe34e58e 100644 (file)
@@ -4406,6 +4406,9 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
        part->roughcurve = newdataadr(fd, part->roughcurve);
        if (part->roughcurve)
                direct_link_curvemapping(fd, part->roughcurve);
+       part->twistcurve = newdataadr(fd, part->twistcurve);
+       if (part->twistcurve)
+               direct_link_curvemapping(fd, part->twistcurve);
 
        part->effector_weights = newdataadr(fd, part->effector_weights);
        if (!part->effector_weights)
index 712ce3340024ccaa8b599f987b2a14ffb7313dcc..d566058f4a77497c83dfcd6c69e6c07adca66472 100644 (file)
@@ -1337,6 +1337,9 @@ static void write_particlesettings(WriteData *wd, ParticleSettings *part)
                if (part->roughcurve) {
                        write_curvemapping(wd, part->roughcurve);
                }
+               if (part->twistcurve) {
+                       write_curvemapping(wd, part->twistcurve);
+               }
 
                for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
                        /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
index 240eda4bf8e3a4da899ae09b1762126c1efe0a58..75c217c4f0cb022ff1887e2f8535f09ad1c97cb2 100644 (file)
@@ -5978,6 +5978,8 @@ static void draw_new_particle_system(
                curvemapping_changed_all(psys->part->clumpcurve);
        if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
                curvemapping_changed_all(psys->part->roughcurve);
+       if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve)
+               curvemapping_changed_all(psys->part->twistcurve);
 
 /* 2. */
        sim.eval_ctx = eval_ctx;
index ea7905eb2adc7707425158370ec079b76b5f153e..a7be2e37c4b5f0880de9597287f416e18055b6c4 100644 (file)
@@ -263,6 +263,11 @@ typedef struct ParticleSettings {
 
        short pad5;
        int recalc;
+
+       float twist;
+       float pad6;
+       struct CurveMapping *twistcurve;
+       void *pad7;
 } ParticleSettings;
 
 typedef struct ParticleSystem {
@@ -305,7 +310,8 @@ typedef struct ParticleSystem {
        char bb_uvname[3][64];                                  /* billboard uv name, MAX_CUSTOMDATA_LAYER_NAME */
 
        /* if you change these remember to update array lengths to PSYS_TOT_VG! */
-       short vgroup[12], vg_neg, rt3;                  /* vertex groups, 0==disable, 1==starting index */
+       short vgroup[13], vg_neg, rt3;                  /* vertex groups, 0==disable, 1==starting index */
+       char pad[6];
 
        /* temporary storage during render */
        struct ParticleRenderData *renderdata;
@@ -439,6 +445,7 @@ typedef enum eParticleChildFlag {
        PART_CHILD_USE_CLUMP_NOISE  = (1<<0),
        PART_CHILD_USE_CLUMP_CURVE  = (1<<1),
        PART_CHILD_USE_ROUGH_CURVE  = (1<<2),
+       PART_CHILD_USE_TWIST_CURVE  = (1<<3),
 } eParticleChildFlag;
 
 /* part->draw_col */
@@ -566,7 +573,7 @@ typedef enum eParticleChildFlag {
 #define PART_DUPLIW_CURRENT    1
 
 /* psys->vg */
-#define PSYS_TOT_VG                    12
+#define PSYS_TOT_VG                    13
 
 #define PSYS_VG_DENSITY                0
 #define PSYS_VG_VEL                    1
@@ -580,6 +587,7 @@ typedef enum eParticleChildFlag {
 #define PSYS_VG_TAN                    9
 #define PSYS_VG_ROT                    10
 #define PSYS_VG_EFFECTOR       11
+#define PSYS_VG_TWIST  12
 
 /* ParticleTarget->flag */
 #define PTARGET_CURRENT                1
@@ -611,7 +619,8 @@ typedef enum eParticleTextureInfluence {
        PAMAP_KINK_AMP  = (1<<12),
        PAMAP_ROUGH             = (1<<9),
        PAMAP_LENGTH    = (1<<4),
-       PAMAP_CHILD             = (PAMAP_CLUMP | PAMAP_KINK_FREQ | PAMAP_KINK_AMP | PAMAP_ROUGH | PAMAP_LENGTH),
+       PAMAP_TWIST     = (1<<13),
+       PAMAP_CHILD             = (PAMAP_CLUMP | PAMAP_KINK_FREQ | PAMAP_KINK_AMP | PAMAP_ROUGH | PAMAP_LENGTH | PAMAP_TWIST),
 } eParticleTextureInfluence;
 
 #endif
index 995d7645dc0087df3040852910043cc12d95ca30..0eb54a9b5b38214a9b0bc1cf84bc7fb5c59edf6e 100644 (file)
@@ -86,7 +86,7 @@ typedef struct MTex {
        float timefac, lengthfac, clumpfac, dampfac;
        float kinkfac, kinkampfac, roughfac, padensfac, gravityfac;
        float lifefac, sizefac, ivelfac, fieldfac;
-       int pad2;
+       float twistfac;
 
        /* lamp */
        float shadowfac;
index 1a819c3bcdbbd6ad0146b0dfd72ca5894ad56351..14bf612f46742bf73c369e7ca44721e9f597fe45 100644 (file)
@@ -953,6 +953,19 @@ static void rna_ParticleSettings_use_roughness_curve_update(Main *bmain, Scene *
        rna_Particle_redo_child(bmain, scene, ptr);
 }
 
+static void rna_ParticleSettings_use_twist_curve_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+       ParticleSettings *part = ptr->data;
+
+       if (part->child_flag & PART_CHILD_USE_TWIST_CURVE) {
+               if (!part->twistcurve) {
+                       BKE_particlesettings_twist_curve_init(part);
+               }
+       }
+
+       rna_Particle_redo_child(bmain, scene, ptr);
+}
+
 static void rna_ParticleSystem_name_set(PointerRNA *ptr, const char *value)
 {
        Object *ob = ptr->id.data;
@@ -1309,6 +1322,7 @@ static void rna_ParticleVGroup_name_get_8(PointerRNA *ptr, char *value) { psys_v
 static void rna_ParticleVGroup_name_get_9(PointerRNA *ptr, char *value) { psys_vg_name_get__internal(ptr, value, 9); }
 static void rna_ParticleVGroup_name_get_10(PointerRNA *ptr, char *value) { psys_vg_name_get__internal(ptr, value, 10); }
 static void rna_ParticleVGroup_name_get_11(PointerRNA *ptr, char *value) { psys_vg_name_get__internal(ptr, value, 11); }
+static void rna_ParticleVGroup_name_get_12(PointerRNA *ptr, char *value) { psys_vg_name_get__internal(ptr, value, 12); }
 
 static int rna_ParticleVGroup_name_len_0(PointerRNA *ptr) { return psys_vg_name_len__internal(ptr, 0); }
 static int rna_ParticleVGroup_name_len_1(PointerRNA *ptr) { return psys_vg_name_len__internal(ptr, 1); }
@@ -1322,6 +1336,7 @@ static int rna_ParticleVGroup_name_len_8(PointerRNA *ptr) { return psys_vg_name_
 static int rna_ParticleVGroup_name_len_9(PointerRNA *ptr) { return psys_vg_name_len__internal(ptr, 9); }
 static int rna_ParticleVGroup_name_len_10(PointerRNA *ptr) { return psys_vg_name_len__internal(ptr, 10); }
 static int rna_ParticleVGroup_name_len_11(PointerRNA *ptr) { return psys_vg_name_len__internal(ptr, 11); }
+static int rna_ParticleVGroup_name_len_12(PointerRNA *ptr) { return psys_vg_name_len__internal(ptr, 12); }
 
 static void rna_ParticleVGroup_name_set_0(PointerRNA *ptr, const char *value) { psys_vg_name_set__internal(ptr, value, 0); }
 static void rna_ParticleVGroup_name_set_1(PointerRNA *ptr, const char *value) { psys_vg_name_set__internal(ptr, value, 1); }
@@ -1335,6 +1350,7 @@ static void rna_ParticleVGroup_name_set_8(PointerRNA *ptr, const char *value) {
 static void rna_ParticleVGroup_name_set_9(PointerRNA *ptr, const char *value) { psys_vg_name_set__internal(ptr, value, 9); }
 static void rna_ParticleVGroup_name_set_10(PointerRNA *ptr, const char *value) { psys_vg_name_set__internal(ptr, value, 10); }
 static void rna_ParticleVGroup_name_set_11(PointerRNA *ptr, const char *value) { psys_vg_name_set__internal(ptr, value, 11); }
+static void rna_ParticleVGroup_name_set_12(PointerRNA *ptr, const char *value) { psys_vg_name_set__internal(ptr, value, 12); }
 
 
 #else
@@ -1887,6 +1903,10 @@ static void rna_def_particle_settings_mtex(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Length", "Affect the child hair length");
        RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
 
+       prop = RNA_def_property(srna, "use_map_twist", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "mapto", PAMAP_TWIST);
+       RNA_def_property_ui_text(prop, "Twist", "Affect the child twist");
+       RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
 
        /* influence factors */
        prop = RNA_def_property(srna, "time_factor", PROP_FLOAT, PROP_NONE);
@@ -1968,6 +1988,12 @@ static void rna_def_particle_settings_mtex(BlenderRNA *brna)
        RNA_def_property_ui_range(prop, 0, 1, 10, 3);
        RNA_def_property_ui_text(prop, "Rough Factor", "Amount texture affects child roughness");
        RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+       prop = RNA_def_property(srna, "twist_factor", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "twistfac");
+       RNA_def_property_ui_range(prop, 0, 1, 10, 3);
+       RNA_def_property_ui_text(prop, "Twist Factor", "Amount texture affects child twist");
+       RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
 }
 
 static void rna_def_particle_settings(BlenderRNA *brna)
@@ -3174,6 +3200,25 @@ static void rna_def_particle_settings(BlenderRNA *brna)
        RNA_def_property_struct_type(prop, "FieldSettings");
        RNA_def_property_pointer_funcs(prop, "rna_Particle_field2_get", NULL, NULL, NULL);
        RNA_def_property_ui_text(prop, "Force Field 2", "");
+
+       /* twist */
+       prop = RNA_def_property(srna, "twist", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_range(prop, -100000.0f, 100000.0f);
+       RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.1, 3);
+       RNA_def_property_ui_text(prop, "Twist", "Number of turns around parent allong the strand");
+       RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+       prop = RNA_def_property(srna, "use_twist_curve", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "child_flag", PART_CHILD_USE_TWIST_CURVE);
+       RNA_def_property_ui_text(prop, "Use Twist Curve", "Use a curve to define twist");
+       RNA_def_property_update(prop, 0, "rna_ParticleSettings_use_twist_curve_update");
+
+       prop = RNA_def_property(srna, "twist_curve", PROP_POINTER, PROP_NONE);
+       RNA_def_property_pointer_sdna(prop, NULL, "twistcurve");
+       RNA_def_property_struct_type(prop, "CurveMapping");
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Twist Curve", "Curve defining twist");
+       RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
 }
 
 static void rna_def_particle_target(BlenderRNA *brna)
@@ -3507,6 +3552,18 @@ static void rna_def_particle_system(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Vertex Group Field Negate", "Negate the effect of the field vertex group");
        RNA_def_property_update(prop, 0, "rna_Particle_reset");
 
+       prop = RNA_def_property(srna, "vertex_group_twist", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_funcs(prop, "rna_ParticleVGroup_name_get_12", "rna_ParticleVGroup_name_len_12",
+                                     "rna_ParticleVGroup_name_set_12");
+       RNA_def_property_ui_text(prop, "Vertex Group Twist", "Vertex group to control twist");
+       RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+       prop = RNA_def_property(srna, "invert_vertex_group_twist", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "vg_neg", (1 << PSYS_VG_TWIST));
+       RNA_def_property_ui_text(prop, "Vertex Group Twist Negate",
+                                "Negate the effect of the twist vertex group");
+       RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
        /* pointcache */
        prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
        RNA_def_property_flag(prop, PROP_NEVER_NULL);