[Bf-blender-cvs] [737140f] hair_system: Implemented hair frame calculation using parallel transport along curve segments.

Lukas Tönne noreply at git.blender.org
Tue Jul 29 12:41:14 CEST 2014


Commit: 737140f4802f13227d04c79cf82859fea755f4c6
Author: Lukas Tönne
Date:   Tue Jul 29 12:37:56 2014 +0200
Branches: hair_system
https://developer.blender.org/rB737140f4802f13227d04c79cf82859fea755f4c6

Implemented hair frame calculation using parallel transport along
curve segments.

This can be done on-the-fly but rotating the root hair frame
incrementally according to each hair segment angle. Note: a similar
approach can be found in the Blender curve code for calculating twist
vectors.

A novel feature of the hair frame calculation is the use of smoothed
hair curves. This prevents artifacts in case of sharp segment angles by
removing small-scale noise from the curve.

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

M	source/blender/editors/space_view3d/drawhair.c
M	source/blender/hair/HAIR_capi.cpp
M	source/blender/hair/HAIR_capi.h
M	source/blender/hair/intern/HAIR_curve.h
M	source/blender/hair/intern/HAIR_math.h
M	source/blender/hair/intern/HAIR_smoothing.h
M	source/blender/hair/intern/HAIR_types.h

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

diff --git a/source/blender/editors/space_view3d/drawhair.c b/source/blender/editors/space_view3d/drawhair.c
index b8d0153..a96ede3 100644
--- a/source/blender/editors/space_view3d/drawhair.c
+++ b/source/blender/editors/space_view3d/drawhair.c
@@ -69,6 +69,60 @@ static void draw_hair_curve(HairSystem *hsys, HairCurve *hair)
 	}
 	glEnd();
 	
+	/* frames */
+	{
+		struct HAIR_FrameIterator *iter;
+		float co[3], nor[3], tan[3], cotan[3];
+		int k = 0;
+		const float scale = 0.1f;
+		
+		glBegin(GL_LINES);
+		iter = HAIR_frame_iter_new(hair, 1.0f / hair->totpoints, hsys->smooth, nor, tan, cotan);
+		copy_v3_v3(co, hair->points[0].co);
+		mul_v3_fl(nor, scale);
+		mul_v3_fl(tan, scale);
+		mul_v3_fl(cotan, scale);
+		add_v3_v3(nor, co);
+		add_v3_v3(tan, co);
+		add_v3_v3(cotan, co);
+		++k;
+		
+		glColor3f(1.0f, 0.0f, 0.0f);
+		glVertex3fv(co);
+		glVertex3fv(nor);
+		glColor3f(0.0f, 1.0f, 0.0f);
+		glVertex3fv(co);
+		glVertex3fv(tan);
+		glColor3f(0.0f, 0.0f, 1.0f);
+		glVertex3fv(co);
+		glVertex3fv(cotan);
+		
+		while (HAIR_frame_iter_valid(hair, iter)) {
+			HAIR_frame_iter_next(hair, iter, nor, tan, cotan);
+			copy_v3_v3(co, hair->points[k].co);
+			mul_v3_fl(nor, scale);
+			mul_v3_fl(tan, scale);
+			mul_v3_fl(cotan, scale);
+			add_v3_v3(nor, co);
+			add_v3_v3(tan, co);
+			add_v3_v3(cotan, co);
+			++k;
+			
+			glColor3f(1.0f, 0.0f, 0.0f);
+			glVertex3fv(co);
+			glVertex3fv(nor);
+			glColor3f(0.0f, 1.0f, 0.0f);
+			glVertex3fv(co);
+			glVertex3fv(tan);
+			glColor3f(0.0f, 0.0f, 1.0f);
+			glVertex3fv(co);
+			glVertex3fv(cotan);
+		}
+		HAIR_frame_iter_free(iter);
+		glEnd();
+	}
+	
+#if 0
 	/* smoothed curve */
 	if (hair->totpoints >= 2) {
 		struct HAIR_SmoothingIteratorFloat3 *iter;
@@ -102,6 +156,7 @@ static void draw_hair_curve(HairSystem *hsys, HairCurve *hair)
 		glEnd();
 		glPointSize(1.0f);
 	}
+#endif
 }
 
 /* called from drawobject.c, return true if nothing was drawn */
diff --git a/source/blender/hair/HAIR_capi.cpp b/source/blender/hair/HAIR_capi.cpp
index 5dd8cc2..3c88835 100644
--- a/source/blender/hair/HAIR_capi.cpp
+++ b/source/blender/hair/HAIR_capi.cpp
@@ -179,3 +179,54 @@ void HAIR_smoothing_iter_end(HairCurve *curve, struct HAIR_SmoothingIteratorFloa
 	float3 val = iter->next(co);
 	copy_v3_v3(cval, val.data());
 }
+
+
+struct HAIR_FrameIterator *HAIR_frame_iter_new(HairCurve *curve, float rest_length, float amount, float cnor[3], float ctan[3], float ccotan[3])
+{
+	FrameIterator *iter;
+	float3 co0, co1;
+	
+	if (curve->totpoints >= 2) {
+		co0 = curve->points[0].co;
+		co1 = curve->points[1].co;
+	}
+	else if (curve->totpoints >= 1) {
+		co0 = co1 = curve->points[0].co;
+	}
+	else {
+		static const float3 v(0.0f, 0.0f, 0.0f);
+		co0 = co1 = v;
+	}
+	
+	iter = new FrameIterator(rest_length, amount, curve->totpoints, co0, co1);
+	copy_v3_v3(cnor, iter->frame().normal.data());
+	copy_v3_v3(ctan, iter->frame().tangent.data());
+	copy_v3_v3(ccotan, iter->frame().cotangent.data());
+	
+	return (struct HAIR_FrameIterator *)iter;
+}
+
+void HAIR_frame_iter_free(struct HAIR_FrameIterator *citer)
+{
+	FrameIterator *iter = (FrameIterator *)citer;
+	
+	delete iter;
+}
+
+bool HAIR_frame_iter_valid(HairCurve *curve, struct HAIR_FrameIterator *citer)
+{
+	FrameIterator *iter = (FrameIterator *)citer;
+	
+	return iter->valid();
+}
+
+void HAIR_frame_iter_next(HairCurve *curve, struct HAIR_FrameIterator *citer, float cnor[3], float ctan[3], float ccotan[3])
+{
+	FrameIterator *iter = (FrameIterator *)citer;
+	
+	float *co = curve->points[iter->cur()].co;
+	iter->next(co);
+	copy_v3_v3(cnor, iter->frame().normal.data());
+	copy_v3_v3(ctan, iter->frame().tangent.data());
+	copy_v3_v3(ccotan, iter->frame().cotangent.data());
+}
diff --git a/source/blender/hair/HAIR_capi.h b/source/blender/hair/HAIR_capi.h
index 7de4374..59062f3 100644
--- a/source/blender/hair/HAIR_capi.h
+++ b/source/blender/hair/HAIR_capi.h
@@ -35,6 +35,7 @@ struct HairSystem;
 
 struct HAIR_Solver;
 struct HAIR_SmoothingIteratorFloat3;
+struct HAIR_FrameIterator;
 
 struct HAIR_Solver *HAIR_solver_new(const struct HairParams *params);
 void HAIR_solver_free(struct HAIR_Solver *solver);
@@ -48,6 +49,11 @@ bool HAIR_smoothing_iter_valid(struct HairCurve *curve, struct HAIR_SmoothingIte
 void HAIR_smoothing_iter_next(struct HairCurve *curve, struct HAIR_SmoothingIteratorFloat3 *iter, float val[3]);
 void HAIR_smoothing_iter_end(struct HairCurve *curve, struct HAIR_SmoothingIteratorFloat3 *citer, float cval[3]);
 
+struct HAIR_FrameIterator *HAIR_frame_iter_new(struct HairCurve *curve, float rest_length, float amount, float nor[3], float tan[3], float cotan[3]);
+void HAIR_frame_iter_free(struct HAIR_FrameIterator *iter);
+bool HAIR_frame_iter_valid(struct HairCurve *curve, struct HAIR_FrameIterator *iter);
+void HAIR_frame_iter_next(struct HairCurve *curve, struct HAIR_FrameIterator *iter, float nor[3], float tan[3], float cotan[3]);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/hair/intern/HAIR_curve.h b/source/blender/hair/intern/HAIR_curve.h
index 93f402a..b2c1617 100644
--- a/source/blender/hair/intern/HAIR_curve.h
+++ b/source/blender/hair/intern/HAIR_curve.h
@@ -61,6 +61,33 @@ struct Curve {
 	HAIR_CXX_CLASS_ALLOC(Curve)
 };
 
+struct Frame {
+	Frame() :
+	    normal(float3(1.0f, 0.0f, 0.0f)),
+	    tangent(float3(0.0f, 1.0f, 0.0f)),
+	    cotangent(float3(0.0f, 0.0f, 1.0f))
+	{}
+	Frame(const float3 &normal, const float3 &tangent, const float3 &cotangent) :
+	    normal(normal),
+	    tangent(tangent),
+	    cotangent(cotangent)
+	{}
+	Frame(const Transform &t) :
+	    normal(float3(t.x.x, t.y.x, t.z.x)),
+	    tangent(float3(t.x.y, t.y.y, t.z.y)),
+	    cotangent(float3(t.x.z, t.y.z, t.z.z))
+	{}
+	
+	float3 normal;
+	float3 tangent;
+	float3 cotangent;
+	
+	__forceinline Transform to_transform() const
+	{
+		return Transform(normal.to_direction(), tangent.to_direction(), cotangent.to_direction(), float4(0.0f, 0.0f, 0.0f, 1.0f));
+	}
+};
+
 HAIR_NAMESPACE_END
 
 #endif
diff --git a/source/blender/hair/intern/HAIR_math.h b/source/blender/hair/intern/HAIR_math.h
index d9167c6..2166bf0 100644
--- a/source/blender/hair/intern/HAIR_math.h
+++ b/source/blender/hair/intern/HAIR_math.h
@@ -140,6 +140,11 @@ __forceinline float dot_v4_v4(const float4 &a, const float4 &b)
 	return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
 }
 
+__forceinline float3 cross_v3_v3(const float3 &a, const float3 &b)
+{
+	return float3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
+}
+
 __forceinline float len_v3(const float3 &v)
 {
 	return sqrtf(dot_v3_v3(v, v));
@@ -152,6 +157,51 @@ __forceinline float normalize_v3_v3(float3 &r, const float3 &v)
 	return len;
 }
 
+/* quaternion functions */
+
+__forceinline float3 mul_qt_v3(const float4 &q, const float3 &v)
+{
+	float t0, t1, t2;
+	float3 r;
+	
+	t0  = -q.x * v.x - q.y * v.y - q.z * v.z;
+	t1  =  q.w * v.x + q.y * v.z - q.z * v.y;
+	t2  =  q.w * v.y + q.z * v.x - q.x * v.z;
+	r.z =  q.w * v.z + q.x * v.y - q.y * v.x;
+	r.x =  t1;
+	r.y =  t2;
+	
+	t1  = t0 * -q.x + r.x * q.w - r.y * q.z + r.z * q.y;
+	t2  = t0 * -q.y + r.y * q.w - r.z * q.x + r.x * q.z;
+	r.z = t0 * -q.z + r.z * q.w - r.x * q.y + r.y * q.x;
+	r.x = t1;
+	r.y = t2;
+	
+	return r;
+}
+
+__forceinline float4 mul_qt_v4(const float4 &q, const float4 &v)
+{
+	float t0, t1, t2;
+	float4 r;
+	
+	t0  = -q.x * v.x - q.y * v.y - q.z * v.z;
+	t1  =  q.w * v.x + q.y * v.z - q.z * v.y;
+	t2  =  q.w * v.y + q.z * v.x - q.x * v.z;
+	r.z =  q.w * v.z + q.x * v.y - q.y * v.x;
+	r.x =  t1;
+	r.y =  t2;
+	
+	t1  = t0 * -q.x + r.x * q.w - r.y * q.z + r.z * q.y;
+	t2  = t0 * -q.y + r.y * q.w - r.z * q.x + r.x * q.z;
+	r.z = t0 * -q.z + r.z * q.w - r.x * q.y + r.y * q.x;
+	r.x = t1;
+	r.y = t2;
+	r.w = 1.0f;
+	
+	return r;
+}
+
 /* matrix arithmetic */
 
 __forceinline Transform operator + (const Transform &a, const Transform &b)
diff --git a/source/blender/hair/intern/HAIR_smoothing.h b/source/blender/hair/intern/HAIR_smoothing.h
index 119ff0a..5b05a1b 100644
--- a/source/blender/hair/intern/HAIR_smoothing.h
+++ b/source/blender/hair/intern/HAIR_smoothing.h
@@ -27,8 +27,10 @@
 #ifndef __HAIR_SMOOTHING_H__
 #define __HAIR_SMOOTHING_H__
 
+#include "HAIR_curve.h"
 #include "HAIR_math.h"
 #include "HAIR_memalloc.h"
+#include "HAIR_types.h"
 
 HAIR_NAMESPACE_BEGIN
 
@@ -58,6 +60,7 @@ struct NullDefaultCtor {
 template <typename T, typename NullT = NullDefaultCtor<T> >
 struct SmoothingIterator {
 	SmoothingIterator(float rest_length, float amount) :
+	    num(1),
 	    beta(min_ff(1.0f, amount > 0.0f ? 1.0f - expf(- rest_length / amount) : 1.0f)),
 	    f1(2.0f*(1.0f-beta)),
 	    f2((1.0f-beta)*(1.0f-beta)),
@@ -104,6 +107,70 @@ struct SmoothingIterator {
 	HAIR_CXX_CLASS_ALLOC(SmoothingIterator)
 };
 
+struct FrameIterator {
+	FrameIterator(float rest_length, float amount, int totpoints, const float3 &co0, const float3 &co1) :
+	    m_loc_iter(rest_length, amount),\
+	    m_totpoints(totpoints),
+	    m_frame(Transform::Identity)
+	{
+		float3 smooth_co1 = m_loc_iter.begin(co0, co1);
+		
+		normalize_v3_v3(m_prev_dir, smooth_co1 - co0);
+		m_prev_co = smooth_co1;
+	}
+	
+	int cur() const { return m_loc_iter.num; }
+	
+	bool valid() const
+	{
+		/* note: totpoints is still allowed, so the iterator yields a frame
+		 * for the last point (without reading from loc_iter though).
+		 */
+		return m_loc_iter.num <= m_totpoints;
+	}
+	
+	void next(const float3 &co)
+	{
+		float3 dir;
+		static const float epsilon = 1.0e-6;
+		
+		float3 smooth_co = m_loc_iter.next(co);
+		
+		normalize_v3_v3(dir, smooth_co - m_prev_co);
+		
+		float3 C = cross_v3_v3(m_prev_dir, dir);
+		float D = dot_v3_v3(m_prev_dir, dir);
+		/* test if angle too small for usable result
+		 * XXX define epsilon better
+		 */
+		if (fabsf(D) < 1.0f - epsilon) {
+			/* construct rotation from one segment to the next */
+			float cos_phi_2 = sqrtf((1.0f + D) * 0.5f); /* cos(phi/2) -> quaternion w element */
+			float3 axis = C / (2.0f * cos_phi_2); /* axis * sin(phi/2) -> quaternion (x,y,z) elements */
+			float4 rot(axis.x, axis.y, axis.z, cos_phi_2);
+			
+			/* apply the local rotation to the frame axes */
+			m_frame.normal = mul_qt_v3(rot, m_frame.normal);
+			m_frame.tangent = mul_qt_v3(

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list