[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