[Bf-blender-cvs] [9210f39] alembic: Child strand deformation based on parent motion states when reading from caches.

Lukas Tönne noreply at git.blender.org
Sat Apr 11 12:46:37 CEST 2015


Commit: 9210f39112cd6ff60b18448787e4762dc922b351
Author: Lukas Tönne
Date:   Sat Apr 11 12:40:33 2015 +0200
Branches: alembic
https://developer.blender.org/rB9210f39112cd6ff60b18448787e4762dc922b351

Child strand deformation based on parent motion states when reading from
caches.

This allows child strands to follow the motion of parent strands as
calculated by the hair simulation. Unlike the particle system path
caching, this method does not regenerate all the children every frame.
Instead, it relies on an initial child setup that defines the base
shape, then applies the parent motion as a weighted linear deformation.

The result is in fact the same as with regular particle clumping, kink,
roughness etc.. Particles also take care to not change the child shape
when the parent moves, but this is not formalized anywhere (which makes
changing particle code quite difficult). So ignoring the particle code
is both permissible and efficient.

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

M	source/blender/blenkernel/BKE_strands.h
M	source/blender/blenkernel/intern/strands.c
M	source/blender/makesdna/DNA_strands_types.h
M	source/blender/pointcache/alembic/abc_particles.cpp
M	source/blender/pointcache/alembic/abc_particles.h

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

diff --git a/source/blender/blenkernel/BKE_strands.h b/source/blender/blenkernel/BKE_strands.h
index 3a80950..4d9c365 100644
--- a/source/blender/blenkernel/BKE_strands.h
+++ b/source/blender/blenkernel/BKE_strands.h
@@ -39,6 +39,8 @@ void BKE_strands_get_minmax(struct Strands *strands, float min[3], float max[3],
 struct StrandsChildren *BKE_strands_children_new(int strands, int verts);
 void BKE_strands_children_free(struct StrandsChildren *strands);
 
+void BKE_strands_children_deform_from_parents(struct StrandsChildren *strands, struct Strands *parents);
+
 void BKE_strands_children_ensure_normals(struct StrandsChildren *strands);
 
 void BKE_strands_children_get_minmax(struct StrandsChildren *strands, float min[3], float max[3]);
diff --git a/source/blender/blenkernel/intern/strands.c b/source/blender/blenkernel/intern/strands.c
index af6891e..82a2b04 100644
--- a/source/blender/blenkernel/intern/strands.c
+++ b/source/blender/blenkernel/intern/strands.c
@@ -181,6 +181,79 @@ void BKE_strands_children_free(StrandsChildren *strands)
 	}
 }
 
+static int *strands_calc_vertex_start(Strands *strands)
+{
+	int *vertstart = MEM_mallocN(sizeof(int) * strands->totcurves, "strand curves vertex start");
+	StrandIterator it_strand;
+	int start;
+	
+	start = 0;
+	for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+		vertstart[it_strand.index] = start;
+		start += it_strand.curve->numverts;
+	}
+	
+	return vertstart;
+}
+
+void BKE_strands_children_deform_from_parents(StrandsChildren *strands, Strands *parents)
+{
+	int *vertstart;
+	StrandChildIterator it_strand;
+	
+	if (!parents || !parents->state)
+		return;
+	
+	vertstart = strands_calc_vertex_start(parents);
+	
+	if (!vertstart)
+		return;
+	
+	for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+		int i;
+		
+		for (i = 0; i < 4; ++i) {
+			int p = it_strand.curve->parents[i];
+			float w = it_strand.curve->parent_weights[i];
+			if (p >= 0 && w > 0.0f) {
+				StrandsCurve *parent = &parents->curves[p];
+				StrandsVertex *pverts;
+				StrandsMotionState *pstate;
+				int pv0, pv1;
+				StrandChildVertexIterator it_vert;
+				
+				if (parent->numverts <= 0)
+					continue;
+				
+				pverts = &parents->verts[vertstart[p]];
+				pstate = &parents->state[vertstart[p]];
+				pv0 = 0;
+				for (BKE_strand_child_vertex_iter_init(&it_vert, &it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) {
+					float time = it_vert.vertex->time;
+					float dt, x;
+					float poffset0[3], poffset1[3], offset[3];
+					
+					/* advance to the matching parent edge for interpolation */
+					while (pv0 < parent->numverts-1 && pverts[pv0+1].time < time)
+						++pv0;
+					pv1 = (pv0 < parent->numverts-1)? pv0+1 : pv0;
+					
+					sub_v3_v3v3(poffset0, pstate[pv0].co, pverts[pv0].co);
+					sub_v3_v3v3(poffset1, pstate[pv1].co, pverts[pv1].co);
+					
+					dt = pverts[pv1].time - pverts[pv0].time;
+					x = dt > 0.0f ? (time - pverts[pv0].time) / dt : 0.0f;
+					interp_v3_v3v3(offset, poffset0, poffset1, x);
+					
+					madd_v3_v3fl(it_vert.vertex->co, offset, w);
+				}
+			}
+		}
+	}
+	
+	MEM_freeN(vertstart);
+}
+
 static void calc_child_normals(StrandsChildren *strands)
 {
 	StrandChildIterator it_strand;
diff --git a/source/blender/makesdna/DNA_strands_types.h b/source/blender/makesdna/DNA_strands_types.h
index 1b64a83..623db20 100644
--- a/source/blender/makesdna/DNA_strands_types.h
+++ b/source/blender/makesdna/DNA_strands_types.h
@@ -59,6 +59,8 @@ typedef struct Strands {
 
 typedef struct StrandsChildCurve {
 	int numverts;
+	int parents[4];
+	float parent_weights[4];
 } StrandsChildCurve;
 
 typedef struct StrandsChildVertex {
diff --git a/source/blender/pointcache/alembic/abc_particles.cpp b/source/blender/pointcache/alembic/abc_particles.cpp
index 3fa1d40..e4b83da 100644
--- a/source/blender/pointcache/alembic/abc_particles.cpp
+++ b/source/blender/pointcache/alembic/abc_particles.cpp
@@ -136,6 +136,8 @@ struct StrandsChildrenSample {
 	
 	std::vector<V3f> positions;
 	std::vector<float32_t> times;
+	std::vector<int32_t> parents;
+	std::vector<float32_t> parent_weights;
 };
 
 struct StrandsSample {
@@ -169,8 +171,11 @@ void AbcHairChildrenWriter::init_abc(OObject parent)
 	
 	OCurvesSchema &schema = m_curves.getSchema();
 	OCompoundProperty geom_props = schema.getArbGeomParams();
+	OCompoundProperty user_props = schema.getUserProperties();
 	
 	m_param_times = OFloatGeomParam(geom_props, "times", false, kVertexScope, 1, 0);
+	m_prop_parents = OInt32ArrayProperty(user_props, "parents", abc_archive()->frame_sampling());
+	m_prop_parent_weights = OFloatArrayProperty(user_props, "parent_weights", abc_archive()->frame_sampling());
 }
 
 static int hair_children_count_totkeys(ParticleCacheKey **pathcache, int totpart)
@@ -186,24 +191,50 @@ static int hair_children_count_totkeys(ParticleCacheKey **pathcache, int totpart
 	return totkeys;
 }
 
-static void hair_children_create_sample(ParticleCacheKey **pathcache, int totpart, int totkeys, float imat[4][4], StrandsChildrenSample &sample, bool do_numkeys)
+static void hair_children_create_sample(ParticleSystem *psys, ParticleCacheKey **pathcache, int totpart, int totkeys, float imat[4][4], StrandsChildrenSample &sample, bool do_numkeys)
 {
+	const bool between = (psys->part->childtype == PART_CHILD_FACES);
 	float iqt[4];
 	mat4_to_quat(iqt, imat);
 	
 	int p, k;
 	
-	if (do_numkeys)
+	if (do_numkeys) {
 		sample.numverts.reserve(totpart);
+		sample.parents.reserve(4*totpart);
+		sample.parent_weights.reserve(4*totpart);
+	}
 	sample.positions.reserve(totkeys);
 	sample.times.reserve(totkeys);
 	
 	for (p = 0; p < totpart; ++p) {
+		ChildParticle *cpa = &psys->child[p];
 		ParticleCacheKey *keys = pathcache[p];
 		int numkeys = keys->segments + 1;
 		
-		if (do_numkeys)
+		if (do_numkeys) {
 			sample.numverts.push_back(numkeys);
+			if (between) {
+				sample.parents.push_back(cpa->pa[0]);
+				sample.parents.push_back(cpa->pa[1]);
+				sample.parents.push_back(cpa->pa[2]);
+				sample.parents.push_back(cpa->pa[3]);
+				sample.parent_weights.push_back(cpa->w[0]);
+				sample.parent_weights.push_back(cpa->w[1]);
+				sample.parent_weights.push_back(cpa->w[2]);
+				sample.parent_weights.push_back(cpa->w[3]);
+			}
+			else {
+				sample.parents.push_back(cpa->parent);
+				sample.parents.push_back(-1);
+				sample.parents.push_back(-1);
+				sample.parents.push_back(-1);
+				sample.parent_weights.push_back(1.0f);
+				sample.parent_weights.push_back(0.0f);
+				sample.parent_weights.push_back(0.0f);
+				sample.parent_weights.push_back(0.0f);
+			}
+		}
 		
 		for (k = 0; k < numkeys; ++k) {
 			ParticleCacheKey *key = &keys[k];
@@ -240,11 +271,13 @@ void AbcHairChildrenWriter::write_sample()
 	OCurvesSchema::Sample sample;
 	if (schema.getNumSamples() == 0) {
 		/* write curve sizes only first time, assuming they are constant! */
-		hair_children_create_sample(m_psys->childcache, m_psys->totchild, totkeys, imat, child_sample, true);
+		hair_children_create_sample(m_psys, m_psys->childcache, m_psys->totchild, totkeys, imat, child_sample, true);
 		sample = OCurvesSchema::Sample(child_sample.positions, child_sample.numverts);
+		m_prop_parents.set(Int32ArraySample(child_sample.parents));
+		m_prop_parent_weights.set(FloatArraySample(child_sample.parent_weights));
 	}
 	else {
-		hair_children_create_sample(m_psys->childcache, m_psys->totchild, totkeys, imat, child_sample, false);
+		hair_children_create_sample(m_psys, m_psys->childcache, m_psys->totchild, totkeys, imat, child_sample, false);
 		sample = OCurvesSchema::Sample(child_sample.positions);
 	}
 	schema.set(sample);
@@ -399,8 +432,11 @@ void AbcStrandsChildrenWriter::init_abc(OObject parent)
 	
 	OCurvesSchema &schema = m_curves.getSchema();
 	OCompoundProperty geom_props = schema.getArbGeomParams();
+	OCompoundProperty user_props = schema.getUserProperties();
 	
 	m_param_times = OFloatGeomParam(geom_props, "times", false, kVertexScope, 1, abc_archive()->frame_sampling());
+	m_prop_parents = OInt32ArrayProperty(user_props, "parents", abc_archive()->frame_sampling());
+	m_prop_parent_weights = OFloatArrayProperty(user_props, "parent_weights", abc_archive()->frame_sampling());
 }
 
 static void strands_children_create_sample(StrandsChildren *strands, StrandsChildrenSample &sample, bool do_numverts)
@@ -411,8 +447,11 @@ static void strands_children_create_sample(StrandsChildren *strands, StrandsChil
 	if (totverts == 0)
 		return;
 	
-	if (do_numverts)
+	if (do_numverts) {
 		sample.numverts.reserve(totcurves);
+		sample.parents.reserve(4*totcurves);
+		sample.parent_weights.reserve(4*totcurves);
+	}
 	
 	sample.positions.reserve(totverts);
 	sample.times.reserve(totverts);
@@ -421,8 +460,17 @@ static void strands_children_create_sample(StrandsChildren *strands, StrandsChil
 	for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
 		int numverts = it_strand.curve->numverts;
 		
-		if (do_numverts)
+		if (do_numverts) {
 			sample.numverts.push_back(numverts);
+			sample.parents.push_back(it_strand.curve->parents[0]);
+			sample.parents.push_back(it_strand.curve->parents[1]);
+			sample.parents.push_back(it_strand.curve->parents[2]);
+			sample.parents.push_back(it_strand.curve->parents[3]);
+			sample.parent_weights.push_back(it_strand.curve->parent_weights[0]);
+			sample.parent_weights.push_back(it_strand.curve->parent_weights[1]);
+			sample.parent_weights.push_back(it_strand.curve->parent_weights[2]);
+			sample.parent_weights.push_back(it_strand.curve->parent_weights[3]);
+		}
 		
 		StrandChildVertexIterator it_vert;
 		for (BKE_strand_child_vertex_iter_init(&it_vert, &it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) {
@@ -449,6 +497,8 @@ void AbcStrandsChildrenWriter::write_sample()
 		/* write curve sizes only first time, assuming they are constant! */
 		strands_children_create_sample(strands, strands_sample, true);
 		sample = OCurvesSchema::Sample(strands_s

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list