[Bf-blender-cvs] [3abaace4604] temp-angavrilov: Force Fields: implement new true power and custom falloff options.

Alexander Gavrilov noreply at git.blender.org
Fri Sep 2 16:12:26 CEST 2022


Commit: 3abaace46043d49b82845afaf8fe1f23b6c30ef9
Author: Alexander Gavrilov
Date:   Sun Sep 12 19:35:48 2021 +0300
Branches: temp-angavrilov
https://developer.blender.org/rB3abaace46043d49b82845afaf8fe1f23b6c30ef9

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 60f384a3839..757e3015cf1 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 113f9ac3b4c..58d6a4ebeb5 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 5f8b2fafdd3..bc6bc27a8bd 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -689,6 +689,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 7722c2fa004..49ada35078f 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) {
@@ -546,26 +594,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. @@



More information about the Bf-blender-cvs mailing list