[Bf-blender-cvs] [81a26cc] hair_system: Use the hair root normal for setting up the reference frames.

Lukas Tönne noreply at git.blender.org
Thu Aug 7 15:23:06 CEST 2014


Commit: 81a26ccf91bfed4b3577a960878e53b75e9bc197
Author: Lukas Tönne
Date:   Thu Aug 7 14:23:03 2014 +0200
Branches: hair_system
https://developer.blender.org/rB81a26ccf91bfed4b3577a960878e53b75e9bc197

Use the hair root normal for setting up the reference frames.

Currently the tangent is generated simply by projecting the Z-axis,
eventually we need to have a user-defined tangent space of some kind for
this.

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

M	source/blender/blenkernel/intern/object.c
M	source/blender/editors/physics/hair_ops.c
M	source/blender/hair/intern/HAIR_curve.h
M	source/blender/hair/intern/HAIR_math.cpp
M	source/blender/hair/intern/HAIR_math.h
M	source/blender/hair/intern/HAIR_scene.cpp
M	source/blender/hair/intern/HAIR_smoothing.h
M	source/blender/hair/intern/HAIR_solver.cpp
M	source/blender/hair/intern/HAIR_types.h
M	source/blender/makesdna/DNA_hair_types.h

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

diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 70513cb..96612ff 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -3121,9 +3121,12 @@ void BKE_object_sim_tick(Scene *UNUSED(scene), Object *ob, float ctime, float ti
 		if (md->type == eModifierType_Hair) {
 			HairModifierData *hmd = (HairModifierData*) md;
 			
-#if 0 /* debugging? */
+#if 0
 			HAIR_solver_step(hmd->solver, ctime, timestep);
 #else
+			/* Debug Version
+			 * WARNING: Debugging is not threadsafe atm, crashes with large hair numbers (>1024)!
+			 */
 			float imat[4][4];
 			
 			invert_m4_m4(imat, ob->obmat);
diff --git a/source/blender/editors/physics/hair_ops.c b/source/blender/editors/physics/hair_ops.c
index 6768340..4d07680 100644
--- a/source/blender/editors/physics/hair_ops.c
+++ b/source/blender/editors/physics/hair_ops.c
@@ -45,6 +45,7 @@
 #include "BKE_context.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_hair.h"
+#include "BKE_mesh_sample.h"
 #include "BKE_modifier.h"
 #include "BKE_object.h"
 #include "BKE_particle.h"
@@ -203,6 +204,7 @@ static void hair_copy_from_particles_psys(Object *ob, HairSystem *hsys, Particle
 		HairCurve *hair = hairs + i;
 		HairPoint *points;
 		int totpoints;
+		float loc[3], tan[3];
 		
 		if (pa_cache->steps == 0)
 			continue;
@@ -211,6 +213,9 @@ static void hair_copy_from_particles_psys(Object *ob, HairSystem *hsys, Particle
 		points = BKE_hair_point_append_multi(hsys, hair, totpoints);
 		
 		hair_copy_particle_emitter_location(ob, psys, root, dm, &hair->root);
+		BKE_mesh_sample_eval(dm, &hair->root, loc, hair->rest_nor);
+		tan[0] = 0.0f; tan[1] = 0.0f; tan[2] = 1.0f;
+		madd_v3_v3v3fl(hair->rest_tan, tan, hair->rest_nor, -dot_v3v3(tan, hair->rest_nor));
 		
 		for (k = 0; k < totpoints; ++k) {
 			ParticleCacheKey *pa_key = pa_cache + k;
diff --git a/source/blender/hair/intern/HAIR_curve.h b/source/blender/hair/intern/HAIR_curve.h
index a954de9..ca75700 100644
--- a/source/blender/hair/intern/HAIR_curve.h
+++ b/source/blender/hair/intern/HAIR_curve.h
@@ -67,6 +67,7 @@ struct Point {
 struct CurveRoot {
 	float3 co;
 	float3 nor;
+	float3 tan;
 };
 
 struct Curve {
@@ -77,7 +78,8 @@ struct Curve {
 	int totpoints;
 	float avg_rest_length;
 	
-	CurveRoot root0, root1;
+	CurveRoot root0, root1;     /* root data at start and end of the time interval */
+	float3 rest_root_normal, rest_root_tangent;
 	
 	HAIR_CXX_CLASS_ALLOC(Curve)
 };
diff --git a/source/blender/hair/intern/HAIR_math.cpp b/source/blender/hair/intern/HAIR_math.cpp
index a89036b..3f7fe2d 100644
--- a/source/blender/hair/intern/HAIR_math.cpp
+++ b/source/blender/hair/intern/HAIR_math.cpp
@@ -24,7 +24,10 @@
  * ***** END GPL LICENSE BLOCK *****
  */
 
+#include <stdlib.h>
 #include <cstring>
+#include <limits>
+#include <cfloat>
 
 extern "C" {
 #include "BLI_utildefines.h"
@@ -34,6 +37,63 @@ extern "C" {
 
 HAIR_NAMESPACE_BEGIN
 
+
+/**
+ * Generic function for implementing slerp
+ * (quaternions and spherical vector coords).
+ *
+ * \param t: factor in [0..1]
+ * \param cosom: dot product from normalized vectors/quats.
+ * \param r_w: calculated weights.
+ */
+static float2 interp_dot_slerp(float t, float cosom)
+{
+	const float eps = 1e-4f;
+
+	float2 w;
+
+	BLI_assert(IN_RANGE_INCL(cosom, -1.0001f, 1.0001f));
+
+	/* within [-1..1] range, avoid aligned axis */
+	if (LIKELY(fabsf(cosom) < (1.0f - eps))) {
+		float omega, sinom;
+
+		omega = acosf(cosom);
+		sinom = sinf(omega);
+		w[0] = sinf((1.0f - t) * omega) / sinom;
+		w[1] = sinf(t * omega) / sinom;
+	}
+	else {
+		/* fallback to lerp */
+		w[0] = 1.0f - t;
+		w[1] = t;
+	}
+	
+	return w;
+}
+
+bool interp_v3v3_slerp(float3 &r, const float3 &a, const float3 &b, float t)
+{
+//	BLI_ASSERT_UNIT_V3(a);
+//	BLI_ASSERT_UNIT_V3(b);
+
+	float cosom = dot_v3v3(a, b);
+
+	/* direct opposites */
+	if (UNLIKELY(cosom < (-1.0f + FLT_EPSILON))) {
+		return false;
+	}
+
+	float2 w = interp_dot_slerp(t, cosom);
+
+	r = float3(w.x * a.x + w.y * b.x,
+	           w.x * a.y + w.y * b.y,
+	           w.x * a.z + w.y * b.z);
+
+	return true;
+}
+
+
 static bool transform_matrix4_gj_inverse(float R[][4], float M[][4])
 {
 	/* forward elimination */
diff --git a/source/blender/hair/intern/HAIR_math.h b/source/blender/hair/intern/HAIR_math.h
index ef4474c..b232b3e 100644
--- a/source/blender/hair/intern/HAIR_math.h
+++ b/source/blender/hair/intern/HAIR_math.h
@@ -157,6 +157,11 @@ __forceinline float normalize_v3_v3(float3 &r, const float3 &v)
 	return len;
 }
 
+/**
+ * slerp, treat vectors as spherical coordinates
+ */
+bool interp_v3v3_slerp(float3 &r, const float3 &a, const float3 &b, float t);
+
 /* quaternion functions */
 
 __forceinline float3 mul_qt_v3(const float4 &q, const float3 &v)
diff --git a/source/blender/hair/intern/HAIR_scene.cpp b/source/blender/hair/intern/HAIR_scene.cpp
index d09761b..a00dc6b 100644
--- a/source/blender/hair/intern/HAIR_scene.cpp
+++ b/source/blender/hair/intern/HAIR_scene.cpp
@@ -88,8 +88,12 @@ SolverData *SceneConverter::build_solver_data(Scene *scene, Object *ob, DerivedM
 		*curve = Curve(hair->totpoints, point);
 		
 		mesh_sample_eval(dm, mat, &hair->root, curve->root1.co, curve->root1.nor);
+		normalize_v3_v3(curve->root1.tan, float3(0,0,1) - dot_v3v3(float3(0,0,1), curve->root1.nor) * curve->root1.nor);
 		curve->root0 = curve->root1;
 		
+		curve->rest_root_normal = float3(hair->rest_nor);
+		curve->rest_root_tangent = float3(hair->rest_tan);
+		
 		for (int k = 0; k < hair->totpoints; ++k, ++point) {
 			HairPoint *hair_pt = hair->points + k;
 			
diff --git a/source/blender/hair/intern/HAIR_smoothing.h b/source/blender/hair/intern/HAIR_smoothing.h
index 2443a64..feb4952 100644
--- a/source/blender/hair/intern/HAIR_smoothing.h
+++ b/source/blender/hair/intern/HAIR_smoothing.h
@@ -119,6 +119,7 @@ struct FrameIterator {
 	    m_loc_iter(walker, rest_length, amount),
 	    m_frame(initial_frame)
 	{
+		m_dir = initial_frame.normal;
 	}
 	
 	int index() const { return m_loc_iter.index(); }
@@ -128,33 +129,25 @@ struct FrameIterator {
 	{
 		static const float epsilon = 1.0e-6;
 		
-		if (index() == 0) {
-			float3 prev_co = m_loc_iter.get();
-			m_loc_iter.next();
-			float3 co = m_loc_iter.get();
-			normalize_v3_v3(m_dir, co - prev_co);
-		}
-		else {
-			float3 prev_dir = m_dir;
-			
-			float3 prev_co = m_loc_iter.get();
-			m_loc_iter.next();
-			float3 co = m_loc_iter.get();
-			normalize_v3_v3(m_dir, co - prev_co);
-			
-			float3 C = cross_v3_v3(prev_dir, m_dir);
-			float D = dot_v3v3(prev_dir, m_dir);
-			if (D > epsilon && fabsf(D) < 1.0f - epsilon) {
-				/* half angle sine, cosine */
-				D = sqrtf((1.0f + D) * 0.5f);
-				C = C / D * 0.5f;
-				/* construct rotation from one segment to the next */
-				float4 rot(C.x, C.y, C.z, D);
-				/* apply the local rotation to the frame axes */
-				m_frame.normal = mul_qt_v3(rot, m_frame.normal);
-				m_frame.tangent = mul_qt_v3(rot, m_frame.tangent);
-				m_frame.cotangent = mul_qt_v3(rot, m_frame.cotangent);
-			}
+		float3 prev_dir = m_dir;
+		
+		float3 prev_co = m_loc_iter.get();
+		m_loc_iter.next();
+		float3 co = m_loc_iter.get();
+		normalize_v3_v3(m_dir, co - prev_co);
+		
+		float3 C = cross_v3_v3(prev_dir, m_dir);
+		float D = dot_v3v3(prev_dir, m_dir);
+		if (D > epsilon && fabsf(D) < 1.0f - epsilon) {
+			/* half angle sine, cosine */
+			D = sqrtf((1.0f + D) * 0.5f);
+			C = C / D * 0.5f;
+			/* construct rotation from one segment to the next */
+			float4 rot(C.x, C.y, C.z, D);
+			/* apply the local rotation to the frame axes */
+			m_frame.normal = mul_qt_v3(rot, m_frame.normal);
+			m_frame.tangent = mul_qt_v3(rot, m_frame.tangent);
+			m_frame.cotangent = mul_qt_v3(rot, m_frame.cotangent);
 		}
 	}
 	
diff --git a/source/blender/hair/intern/HAIR_solver.cpp b/source/blender/hair/intern/HAIR_solver.cpp
index 830357e..174ba35 100644
--- a/source/blender/hair/intern/HAIR_solver.cpp
+++ b/source/blender/hair/intern/HAIR_solver.cpp
@@ -126,10 +126,8 @@ void SolverData::precompute_rest_bend(const HairParams &params)
 		else if (curve->totpoints == 1)
 			pt->rest_bend = float3(0.0f, 0.0f, 0.0f);
 		else {
-			/* XXX calculating a rest frame ad-hoc from identity here, should use the surface normal/tangent instead! */
-			float3 normal, tangent;
-			normalize_v3_v3(normal, next_pt->rest_co - pt->rest_co);
-			normalize_v3_v3(tangent, float3(0,1,0) - dot_v3v3(float3(0,1,0), normal) * normal);
+			
+			float3 normal = curve->rest_root_normal, tangent = curve->rest_root_tangent;
 			Frame rest_frame(normal, tangent, cross_v3_v3(normal, tangent));
 			
 			FrameIterator<SolverDataRestLocWalker> iter(SolverDataRestLocWalker(curve), curve->avg_rest_length, params.bend_smoothing, rest_frame);
@@ -287,7 +285,7 @@ void Solver::free_data()
 	}
 }
 
-static void calc_root_animation(float t0, float t1, float t, Curve *curve, float3 &co, float3 &vel)
+static void calc_root_animation(float t0, float t1, float t, Curve *curve, float3 &co, float3 &vel, float3 &normal, float3 &tangent)
 {
 	const CurveRoot &root0 = curve->root0;
 	const CurveRoot &root1 = curve->root1;
@@ -298,10 +296,14 @@ static void calc_root_animation(float t0, float t1, float t, Curve *curve, float
 		
 		co = root0.co * mx + root1.co * x;
 		vel = (root1.co - root0.co) / (t1 - t0);
+		interp_v3v3_slerp(normal, root0.nor, root1.nor, x);
+		interp_v3v3_slerp(tangent, root0.tan, root1.tan, x);
 	}
 	else {
 		co = root0.co;
 		vel = float3(0.0f, 0.0f, 0.0f);
+		normal = root0.nor;
+		tangent = root0.tan;
 	}
 }
 
@@ -383,17 +385,9 @@ static void step(const HairParams &params, const SolverForces &forces, float tim
 		/* note: roots are evaluated at the end of the timestep: time + timestep
 		 * so the hair points align perfectly with them
 		 */
-		calc_root_animation(t0, t1, time + timestep, curve, point->next.co, point->next.vel);
-		
 		float3 normal, tangent;
-		if (numpoints >= 2) {
-			normalize_v3_v3(normal, (point+1)->cur.co - point->cur.co);
-			normalize_v3_v3(tangent, float3(0,1,0) - dot_v3v3(float3(0,1,0), normal) * normal);
-		}
-		else {
-			normal = float3(1,0,0);
-			tangent = float3(0,1,0);
-		}
+		calc_root_animation(t0, t1, time + timestep, 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list