diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_particle.py | 6 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_particle.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 26 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle_child.c | 87 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/smoke.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/particle_private.h | 1 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 3 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 3 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 2 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_particle_types.h | 5 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_particle.c | 32 |
12 files changed, 172 insertions, 0 deletions
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index b01d1ebbfa3..e552ff35ffa 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -1198,6 +1198,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") diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 2c72373c2a9..747a6b65bb0 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -162,6 +162,7 @@ typedef struct ParticleThreadContext { struct CurveMapping *clumpcurve; struct CurveMapping *roughcurve; + struct CurveMapping *twistcurve; } ParticleThreadContext; typedef struct ParticleTask { @@ -349,6 +350,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]); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 8aa7b167b85..ea27e23ed2f 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -405,6 +405,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); @@ -2152,6 +2154,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; } @@ -3337,6 +3346,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. @@ -3359,6 +3380,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); @@ -3935,6 +3959,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * 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 */ @@ -4048,6 +4073,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta 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); diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index 70e635e16cf..53bf577d4f4 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -242,6 +242,7 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co 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; @@ -352,6 +353,7 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod 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; @@ -688,6 +690,89 @@ 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]); } +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; + 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 (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) { @@ -723,6 +808,8 @@ void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx, 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->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index dfc732dcb74..bae76354705 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -519,6 +519,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) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 3cf98b284b1..34ff9a155b4 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -1285,6 +1285,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) { diff --git a/source/blender/blenkernel/particle_private.h b/source/blender/blenkernel/particle_private.h index 00a7637e246..2189527118b 100644 --- a/source/blender/blenkernel/particle_private.h +++ b/source/blender/blenkernel/particle_private.h @@ -41,6 +41,7 @@ typedef struct ParticleChildModifierContext { 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, diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2a25de121b3..9aa67e8651f 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4253,6 +4253,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) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ceb1233596a..5941f96041c 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1304,6 +1304,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.) */ diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 828617d1447..c3823627009 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -5044,6 +5044,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv 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.scene = scene; diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index f6bed37dfa2..371b53567a6 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -261,6 +261,10 @@ typedef struct ParticleSettings { short use_modifier_stack; short pad5[3]; + float twist; + float pad6; + struct CurveMapping *twistcurve; + void *pad7; } ParticleSettings; typedef struct ParticleSystem { @@ -435,6 +439,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 */ diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 9e52457d32a..e9bbc981a13 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -944,6 +944,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; @@ -3170,6 +3183,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) |