Commit: 48b4ecd86bdfb17b6a28a4beaf8c010c3a7efb8a Author: Alexander Gavrilov Date: Sun Sep 12 19:35:48 2021 +0300 Branches: temp-angavrilov https://developer.blender.org/rB48b4ecd86bdfb17b6a28a4beaf8c010c3a7efb8a
Force Fields: implement new true power and custom falloff options. The 'power' falloff option in Blender force fields does not actually generate a true power falloff function, as pointed out in D2389. However, that patch adds a special 'gravity' falloff option to Force fields, without addressing the shortcoming in the common options. The reason for not using the true curve in the options, as far as one can tell, is that the power curve goes up to infinity as the distance is reduced to 0, while the falloff options are designed so that the maximum value of the curve is 1. However, in reality forces with a power falloff don't actually go to infinity, because real objects have a nonzero size, and the force reaches its maximum at the surface of the object. This can be used to integrate an option to use a true power falloff with the design of falloff settings, if it requires a nonzero 'minimum' distance to be set, and uses a curve that reaches 1 at that distance. Since this is adding a new feature to the minimum distance value, it is also a good opportunity to add a feature to the maximum distance. Specifically, the new options can be used to apply arbitrary brush-style falloff curves between min and max, including a fully custom curve option. When used together with power falloff, the two curves are multiplied together. While the true power option allows creating more physically correct forces, the custom curves aid artistic effects. Differential Revision: https://developer.blender.org/D8075 =================================================================== M release/scripts/startup/bl_ui/properties_physics_common.py M release/scripts/startup/bl_ui/properties_physics_field.py M source/blender/blenkernel/BKE_effect.h M source/blender/blenkernel/BKE_particle.h M source/blender/blenkernel/intern/effect.c M source/blender/blenkernel/intern/object.cc M source/blender/blenkernel/intern/particle.c M source/blender/makesdna/DNA_object_force_types.h M source/blender/makesrna/intern/rna_object_force.c =================================================================== diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index 4146a8ca51a..f2e30e523a4 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -337,6 +337,10 @@ def basic_force_field_falloff_ui(self, field): sub.prop(field, "distance_min", text="") row.prop_decorator(field, "distance_min") + col = layout.column() + col.active = field.use_min_distance and field.distance_min > 0 + col.prop(field, "use_true_power") + col = layout.column(align=False, heading="Max Distance") col.use_property_decorate = False row = col.row(align=True) @@ -347,6 +351,13 @@ def basic_force_field_falloff_ui(self, field): sub.prop(field, "distance_max", text="") row.prop_decorator(field, "distance_max") + col = layout.column() + col.active = field.use_max_distance and field.distance_max > field.distance_min + col.prop(field, "falloff_curve_type", text="Curve") + + if field.falloff_curve_type == 'CUSTOM': + col.template_curve_mapping(field, "falloff_curve", type='NONE', brush=True) + classes = ( PHYSICS_PT_add, diff --git a/release/scripts/startup/bl_ui/properties_physics_field.py b/release/scripts/startup/bl_ui/properties_physics_field.py index 36d5dc7f68d..635897247c9 100644 --- a/release/scripts/startup/bl_ui/properties_physics_field.py +++ b/release/scripts/startup/bl_ui/properties_physics_field.py @@ -238,20 +238,36 @@ class PHYSICS_PT_field_falloff_angular(PhysicButtonsPanel, Panel): col = flow.column() col.prop(field, "radial_falloff", text="Power") - col = flow.column() - col.prop(field, "use_radial_min", text="Use Min Angle") - - sub = col.column() + col = layout.column(align=False, heading="Min Angle") + col.use_property_decorate = False + row = col.row(align=True) + sub = row.row(align=True) + sub.prop(field, "use_radial_min", text="") + sub = sub.row(align=True) sub.active = field.use_radial_min - sub.prop(field, "radial_min", text="Min Angle") - - col = flow.column() - col.prop(field, "use_radial_max", text="Use Max Angle") + sub.prop(field, "radial_min", text="") + row.prop_decorator(field, "radial_min") - sub = col.column() + col = layout.column() + col.active = field.use_radial_min and field.radial_min > 0 + col.prop(field, "use_radial_true_power") + + col = layout.column(align=False, heading="Max Angle") + col.use_property_decorate = False + row = col.row(align=True) + sub = row.row(align=True) + sub.prop(field, "use_radial_max", text="") + sub = sub.row(align=True) sub.active = field.use_radial_max - sub.prop(field, "radial_max", text="Max Angle") + sub.prop(field, "radial_max", text="") + row.prop_decorator(field, "radial_max") + + col = layout.column() + col.active = field.use_radial_max and field.radial_max > field.radial_min + col.prop(field, "radial_falloff_curve_type", text="Curve") + if field.radial_falloff_curve_type == 'CUSTOM': + col.template_curve_mapping(field, "radial_falloff_curve", type='NONE', brush=True) class PHYSICS_PT_field_falloff_radial(PhysicButtonsPanel, Panel): bl_label = "Radial" @@ -277,19 +293,36 @@ class PHYSICS_PT_field_falloff_radial(PhysicButtonsPanel, Panel): col = flow.column() col.prop(field, "radial_falloff", text="Power") - col = flow.column() - col.prop(field, "use_radial_min", text="Use Minimum") - - sub = col.column() + col = layout.column(align=False, heading="Min Distance") + col.use_property_decorate = False + row = col.row(align=True) + sub = row.row(align=True) + sub.prop(field, "use_radial_min", text="") + sub = sub.row(align=True) sub.active = field.use_radial_min - sub.prop(field, "radial_min", text="Min Distance") - - col = flow.column() - col.prop(field, "use_radial_max", text="Use Maximum") + sub.prop(field, "radial_min", text="") + row.prop_decorator(field, "radial_min") - sub = col.column() + col = layout.column() + col.active = field.use_radial_min and field.radial_min > 0 + col.prop(field, "use_radial_true_power") + + col = layout.column(align=False, heading="Max Distance") + col.use_property_decorate = False + row = col.row(align=True) + sub = row.row(align=True) + sub.prop(field, "use_radial_max", text="") + sub = sub.row(align=True) sub.active = field.use_radial_max - sub.prop(field, "radial_max", text="Max Distance") + sub.prop(field, "radial_max", text="") + row.prop_decorator(field, "radial_max") + + col = layout.column() + col.active = field.use_radial_max and field.radial_max > field.radial_min + col.prop(field, "radial_falloff_curve_type", text="Curve") + + if field.radial_falloff_curve_type == 'CUSTOM': + col.template_curve_mapping(field, "radial_falloff_curve", type='NONE', brush=True) def collision_warning(layout): diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 3226455a183..63604d53f19 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -6,12 +6,15 @@ * \ingroup bke */ +#include "DNA_color_types.h" + #include "BLI_utildefines.h" #ifdef __cplusplus extern "C" { #endif +enum eCurveMappingPreset; struct Collection; struct Depsgraph; struct ListBase; @@ -97,6 +100,10 @@ struct PartDeflect *BKE_partdeflect_new(int type); struct PartDeflect *BKE_partdeflect_copy(const struct PartDeflect *pd_src); void BKE_partdeflect_free(struct PartDeflect *pd); +void BKE_partdeflect_falloff_curve_preset(struct PartDeflect *pd, eCurveMappingPreset preset); +void BKE_partdeflect_radial_falloff_curve_preset(struct PartDeflect *pd, + eCurveMappingPreset preset); + /** * Create list of effector relations in the collection or entire scene. * This is used by the depsgraph to build relations, as well as faster diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 618e69b5436..dfd51060343 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -693,6 +693,8 @@ extern void (*BKE_particle_batch_cache_free_cb)(struct ParticleSystem *psys); /* .blend file I/O */ +void BKE_particle_partdeflect_blend_write(struct BlendWriter *writer, + const struct PartDeflect *pd); void BKE_particle_partdeflect_blend_read_data(struct BlendDataReader *reader, struct PartDeflect *pd); void BKE_particle_partdeflect_blend_read_lib(struct BlendLibReader *reader, diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index c2ae4efbde8..c7696064d16 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -37,6 +37,7 @@ #include "BKE_bvhutils.h" #include "BKE_collection.h" #include "BKE_collision.h" +#include "BKE_colortools.h" #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_effect.h" @@ -116,6 +117,12 @@ PartDeflect *BKE_partdeflect_copy(const struct PartDeflect *pd_src) if (pd_dst->rng != NULL) { pd_dst->rng = BLI_rng_copy(pd_dst->rng); } + if (pd_dst->falloff_curve != NULL) { + pd_dst->falloff_curve = BKE_curvemapping_copy(pd_dst->falloff_curve); + } + if (pd_dst->falloff_curve_r != NULL) { + pd_dst->falloff_curve_r = BKE_curvemapping_copy(pd_dst->falloff_curve_r); + } return pd_dst; } @@ -127,9 +134,43 @@ void BKE_partdeflect_free(PartDeflect *pd) if (pd->rng) { BLI_rng_free(pd->rng); } + if (pd->falloff_curve) { + BKE_curvemapping_free(pd->falloff_curve); + } + if (pd->falloff_curve_r) { + BKE_curvemapping_free(pd->falloff_curve_r); + } MEM_freeN(pd); } +static void init_falloff_curve(CurveMapping **p_curve, eCurveMappingPreset preset) +{ + CurveMapping *cumap = NULL; + CurveMap *cuma = NULL; + + if (!*p_curve) { + *p_curve = BKE_curvemapping_add(1, 0, 0, 1, 1); + } + + cumap = *p_curve; + cumap->flag &= ~CUMA_EXTEND_EXTRAPOLATE; + cumap->preset = preset; + + cuma = cumap->cm; + BKE_curvemap_reset(cuma, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_NEGATIVE); + BKE_curvemapping_changed(cumap, false); +} + +void BKE_partdeflect_falloff_curve_preset(PartDeflect *pd, eCurveMappingPreset preset) +{ + init_falloff_curve(&pd->falloff_curve, preset); +} + +void BKE_partdeflect_radial_falloff_curve_preset(PartDeflect *pd, eCurveMappingPreset preset) +{ + init_falloff_curve(&pd->falloff_curve_r, preset); +} + /******************** EFFECTOR RELATIONS ***********************/ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *eff) @@ -143,6 +184,13 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra); } + if (eff->pd->falloff_curve) { + BKE_curvemapping_init(eff->pd->falloff_curve); + } + if (eff->pd->falloff_curve_r) { + BKE_curvemapping_init(eff->pd->falloff_curve_r); + } + if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVES_LEGACY) { Curve *cu = eff->ob->data; if (cu->flag & CU_PATH) { @@ -547,26 +595,101 @@ static float wind_func(struct RNG *rng, float strength) return ret; } -/* maxdist: zero effect from this distance outwards (if usemax) */ -/* mindist: full effect up to this distance (if usemin) */ -/* power: falloff with formula 1/r^power */ -static float falloff_func( - float fac, int usemin, float mindist, int usemax, float maxdist, float power) +/* Arbitrary falloff curve. */ +static float falloff_curve_strength( + float fac, float mindist, float maxdist, eFie @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs