[Bf-blender-cvs] [8ee7e626a5a] microfacet_hair: Interpolate between the curvature vector and the minimal twist vector with custom weight

Weizhen Huang noreply at git.blender.org
Mon Jan 9 17:33:11 CET 2023


Commit: 8ee7e626a5a6e4b5471fc1bddb508d77f072e0c2
Author: Weizhen Huang
Date:   Mon Jan 9 17:32:17 2023 +0100
Branches: microfacet_hair
https://developer.blender.org/rB8ee7e626a5a6e4b5471fc1bddb508d77f072e0c2

Interpolate between the curvature vector and the minimal twist vector
with custom weight

===================================================================

M	source/blender/blenkernel/BKE_curves.hh
M	source/blender/blenkernel/intern/curve_catmull_rom.cc
M	source/blender/blenkernel/intern/curves_geometry.cc
M	source/blender/makesrna/intern/rna_curves.c
M	source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc

===================================================================

diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 14aa854a4f2..2aa1e3b5156 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -242,6 +242,13 @@ class CurvesGeometry : public ::CurvesGeometry {
   VArray<int8_t> normal_mode() const;
   MutableSpan<int8_t> normal_mode_for_write();
 
+  /**
+   * Used for normal mode curvature vector, specifying the weight as opposed to the minimal twist
+   * normal.
+   */
+  VArray<float> curvature_vector_weight() const;
+  MutableSpan<float> curvature_vector_weight_for_write();
+
   /**
    * Handle types for Bezier control points. Call #tag_topology_changed after changes.
    */
@@ -707,6 +714,7 @@ void calculate_tangents(Span<float3> positions,
 void calculate_normals(Span<float3> positions,
                        bool is_cyclic,
                        int resolution,
+                       float weight_bending,
                        MutableSpan<float3> normals);
 
 /**
diff --git a/source/blender/blenkernel/intern/curve_catmull_rom.cc b/source/blender/blenkernel/intern/curve_catmull_rom.cc
index a93b90ea598..fa2fe01c0b0 100644
--- a/source/blender/blenkernel/intern/curve_catmull_rom.cc
+++ b/source/blender/blenkernel/intern/curve_catmull_rom.cc
@@ -251,6 +251,7 @@ static float find_root_newton_bisection(float x_begin,
 void calculate_normals(const Span<float3> positions,
                        const bool is_cyclic,
                        const int resolution,
+                       const float weight_bending,
                        MutableSpan<float3> evaluated_normals)
 {
   if (evaluated_normals.size() == 1) {
@@ -258,6 +259,8 @@ void calculate_normals(const Span<float3> positions,
     return;
   }
 
+  const float weight_twist = 1.0f - clamp_f(weight_bending, 0.0f, 1.0f);
+
   /* TODO: check if derivatives == 0.*/
   Vector<float3> first_derivatives_(evaluated_normals.size());
   MutableSpan<float3> first_derivatives = first_derivatives_;
@@ -265,21 +268,35 @@ void calculate_normals(const Span<float3> positions,
 
   Vector<float3> second_derivatives_(evaluated_normals.size());
   MutableSpan<float3> second_derivatives = second_derivatives_;
-  interpolate_to_evaluated(2, positions, is_cyclic, resolution, second_derivatives);
-
-  /* TODO: below are hair-specific values, assuming elliptical cross-section. Maybe make them more
-   * general by specifying user-defined weight? */
-  /* Values taken from Table 9.5 in book Chemical and Physical Behavior of Human Hair by Clarence
-   * R. Robbins, 5th edition. Unit: GPa. */
-  const float youngs_modulus = 3.89f;
-  const float shear_modulus = 0.89f;
-  /* Assuming major axis a = 1. */
-  const float aspect_ratio = 0.5f; /* Minimal realistic value. */
-  const float aspect_ratio_squared = aspect_ratio * aspect_ratio;
-  const float torsion_constant = M_PI * aspect_ratio_squared * aspect_ratio /
-                                 (1.0f + aspect_ratio_squared);
-  const float moment_of_inertia_coefficient = M_PI * aspect_ratio * 0.25f *
-                                              (1.0f - aspect_ratio_squared);
+  if (weight_twist < 1.0f) {
+    interpolate_to_evaluated(2, positions, is_cyclic, resolution, second_derivatives);
+  }
+  else {
+    /* TODO: Actually only the first entry needs to be evaluated. */
+    interpolate_to_evaluated(
+        2,
+        positions,
+        is_cyclic,
+        [resolution](const int segment_i) -> IndexRange {
+          return {segment_i * resolution, 1};
+        },
+        second_derivatives);
+  }
+
+  /* Hair-specific values, taken from Table 9.5 in book Chemical and Physical Behavior of Human
+   * Hair by Clarence R. Robbins, 5th edition. Unit: GPa. */
+  // const float youngs_modulus = 3.89f;
+  // const float shear_modulus = 0.89f;
+  // /* Assuming major axis a = 1. */
+  // const float aspect_ratio = 0.5f; /* Minimal realistic value. */
+  // const float aspect_ratio_squared = aspect_ratio * aspect_ratio;
+  // const float torsion_constant = M_PI * aspect_ratio_squared * aspect_ratio /
+  //                                (1.0f + aspect_ratio_squared);
+  // const float moment_of_inertia_coefficient = M_PI * aspect_ratio * 0.25f *
+  //                                             (1.0f - aspect_ratio_squared);
+
+  // const float weight_bending = 0.5f * youngs_modulus * moment_of_inertia_coefficient;
+  // const float weight_twist = 0.5f * shear_modulus * torsion_constant;
 
   const float dt = 1.0f / resolution;
   /* Compute evaluated_normals. */
@@ -296,15 +313,15 @@ void calculate_normals(const Span<float3> positions,
       continue;
     }
 
-    const float first_derivative_norm = math::length(first_derivatives[i]);
-    /* Arc length depends on the unit, assuming meter. */
-    const float arc_length = first_derivative_norm * dt;
-    const float curvature = math::length(binormal) / pow3f(first_derivative_norm);
-
-    const float weight_twist = 0.5f * shear_modulus * torsion_constant / arc_length;
-    const float weight_bending = 0.5f * arc_length * curvature * curvature * youngs_modulus *
-                                 moment_of_inertia_coefficient;
+    if (weight_twist == 0.0f) {
+      if (angle_normalized_v3v3(curvature_vector, evaluated_normals[i - 1]) < 0) {
+        curvature_vector = -curvature_vector;
+      }
+      evaluated_normals[i] = curvature_vector;
+      continue;
+    }
 
+    const float first_derivative_norm = math::length(first_derivatives[i]);
     const float3 last_tangent = math::normalize(first_derivatives[i - 1]);
     const float3 current_tangent = first_derivatives[i] / first_derivative_norm;
     const float angle = angle_normalized_v3v3(last_tangent, current_tangent);
@@ -315,6 +332,18 @@ void calculate_normals(const Span<float3> positions,
                 last_normal, math::normalize(math::cross(last_tangent, current_tangent)), angle) :
             last_normal;
 
+    if (weight_twist == 1.0f) {
+      evaluated_normals[i] = minimal_twist_normal;
+      continue;
+    }
+
+    /* Arc length depends on the unit, assuming meter. */
+    const float arc_length = first_derivative_norm * dt;
+    const float curvature = math::length(binormal) / pow3f(first_derivative_norm);
+
+    const float coefficient_twist = weight_twist / arc_length;
+    const float coefficient_bending = weight_bending * arc_length * curvature * curvature;
+
     /* Angle between the curvature vector and the minimal twist normal. */
     float theta_t = angle_normalized_v3v3(curvature_vector, minimal_twist_normal);
     if (theta_t > M_PI_2) {
@@ -326,18 +355,18 @@ void calculate_normals(const Span<float3> positions,
      * equation: 2 * wt * (θ - θt)  + wb * sin(2θ) = 0, with θ being the angle between the computed
      * normal and the curvature vector. */
     const float theta_begin = 0.0f;
-    const float theta_end = weight_twist + weight_bending * cosf(2.0f * theta_t) < 0 ?
-                                0.5f * acosf(-weight_twist / weight_bending) :
+    const float theta_end = coefficient_twist + coefficient_bending * cosf(2.0f * theta_t) < 0 ?
+                                0.5f * acosf(-coefficient_twist / coefficient_bending) :
                                 theta_t;
 
     const float theta = find_root_newton_bisection(
         theta_begin,
         theta_end,
-        [weight_bending, weight_twist, theta_t](float t) -> float {
-          return 2.0f * weight_twist * (t - theta_t) + weight_bending * sinf(2.0f * t);
+        [coefficient_bending, coefficient_twist, theta_t](float t) -> float {
+          return 2.0f * coefficient_twist * (t - theta_t) + coefficient_bending * sinf(2.0f * t);
         },
-        [weight_bending, weight_twist](float t) -> float {
-          return 2.0f * (weight_twist + weight_bending * cosf(2.0f * t));
+        [coefficient_bending, coefficient_twist](float t) -> float {
+          return 2.0f * (coefficient_twist + coefficient_bending * cosf(2.0f * t));
         },
         1e-5f);
 
@@ -347,6 +376,8 @@ void calculate_normals(const Span<float3> positions,
                             -current_tangent;
     evaluated_normals[i] = math::rotate_direction_around_axis(curvature_vector, axis, theta);
   }
+
+  /* TODO: correct normals along the cyclic curve. */
 }
 
 }  // namespace blender::bke::curves::catmull_rom
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index 10325c0bed0..1ea8eb4ab18 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -31,6 +31,7 @@ static const std::string ATTR_CURVE_TYPE = "curve_type";
 static const std::string ATTR_CYCLIC = "cyclic";
 static const std::string ATTR_RESOLUTION = "resolution";
 static const std::string ATTR_NORMAL_MODE = "normal_mode";
+static const std::string ATTR_CURVATURE_VECTOR_WEIGHT = "curvature_vector_weight";
 static const std::string ATTR_HANDLE_TYPE_LEFT = "handle_type_left";
 static const std::string ATTR_HANDLE_TYPE_RIGHT = "handle_type_right";
 static const std::string ATTR_HANDLE_POSITION_LEFT = "handle_left";
@@ -349,6 +350,15 @@ MutableSpan<int8_t> CurvesGeometry::normal_mode_for_write()
   return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NORMAL_MODE);
 }
 
+VArray<float> CurvesGeometry::curvature_vector_weight() const
+{
+  return get_varray_attribute<float>(*this, ATTR_DOMAIN_CURVE, ATTR_CURVATURE_VECTOR_WEIGHT, 0.8f);
+}
+MutableSpan<float> CurvesGeometry::curvature_vector_weight_for_write()
+{
+  return get_mutable_attribute<float>(*this, ATTR_DOMAIN_CURVE, ATTR_CURVATURE_VECTOR_WEIGHT);
+}
+
 VArray<float> CurvesGeometry::tilt() const
 {
   return get_varray_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_TILT, 0.0f);
@@ -733,6 +743,7 @@ Span<float3> CurvesGeometry::evaluated_normals() const
     const VArray<bool> cyclic = this->cyclic();
     Span<float3> positions = this->positions();
     VArray<int> resolution = this->resolution();
+    const VArray<float> weight = this->curvature_vector_weight();
     const VArray<int8_t> normal_mode = this->normal_mode();
     const VArray<int8_t> types = this->curve_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list