[Bf-blender-cvs] [b2db8c07b9a] hair_guides: More detailed API for partially updating hair export caches.

Lukas Tönne noreply at git.blender.org
Fri May 18 17:29:26 CEST 2018


Commit: b2db8c07b9a9c2aa910dd21fec211228f6a69361
Author: Lukas Tönne
Date:   Fri May 18 16:27:37 2018 +0100
Branches: hair_guides
https://developer.blender.org/rBb2db8c07b9a9c2aa910dd21fec211228f6a69361

More detailed API for partially updating hair export caches.

This will allow proper caching of draw data as well as optimization
of GPU buffer uploads when only guide curve deform changes.

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

M	source/blender/blenkernel/BKE_hair.h
M	source/blender/blenkernel/intern/hair.c
M	source/blender/makesdna/DNA_particle_types.h

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

diff --git a/source/blender/blenkernel/BKE_hair.h b/source/blender/blenkernel/BKE_hair.h
index 34eb9d2df3a..d1ad0f10504 100644
--- a/source/blender/blenkernel/BKE_hair.h
+++ b/source/blender/blenkernel/BKE_hair.h
@@ -135,10 +135,62 @@ typedef struct HairExportCache
 	const struct HairFollicle *follicles;
 } HairExportCache;
 
+/* Identifiers for data stored in hair export caches.
+ * Note some flags include dependent parts, which automatically
+ * invalidates those parts when their dependencies are invalidated.
+ * 
+ * In particular: guide vertex locations can be changed without having to update fiber base data,
+ * which allows animation of guide curves without rebuilding fiber data apart from final locations.
+ */
+typedef enum eHairExportCacheUpdateFlags
+{
+	/* Follicle placement on the scalp mesh */
+	HAIR_EXPORT_FIBER_ROOT_POSITIONS      = (1 << 0),
+	/* Fiber vertex counts */
+	HAIR_EXPORT_FIBER_VERTEX_COUNTS     = (1 << 1),
+	/* Follicle parent indices and weights */
+	HAIR_EXPORT_FOLLICLE_BINDING        = (1 << 2) | HAIR_EXPORT_FIBER_ROOT_POSITIONS | HAIR_EXPORT_FIBER_VERTEX_COUNTS,
+	/* Guide vertex positions (deform only) */
+	HAIR_EXPORT_GUIDE_VERTICES          = (1 << 3),
+	/* Guide curve number and vertex counts (topology changes) */
+	HAIR_EXPORT_GUIDE_CURVES            = (1 << 4) | HAIR_EXPORT_GUIDE_VERTICES | HAIR_EXPORT_FOLLICLE_BINDING,
+	
+	HAIR_EXPORT_ALL                     =
+	    HAIR_EXPORT_FIBER_ROOT_POSITIONS |
+	    HAIR_EXPORT_FIBER_VERTEX_COUNTS |
+	    HAIR_EXPORT_FOLLICLE_BINDING |
+	    HAIR_EXPORT_GUIDE_VERTICES |
+	    HAIR_EXPORT_GUIDE_CURVES
+} eHairExportCacheUpdateFlags;
+
+/* Create a new export cache.
+ * This can be used to construct full fiber data for rendering.
+ */
 struct HairExportCache* BKE_hair_export_cache_new(const struct HairSystem *hsys, int subdiv, struct DerivedMesh *scalp);
+
+/* Create a new export cache.
+ * This can be used to construct full fiber data for rendering.
+ * XXX Mesh-based version for Cycles export, until DerivedMesh->Mesh conversion is done.
+ */
 struct HairExportCache* BKE_hair_export_cache_new_mesh(const struct HairSystem *hsys, int subdiv, struct Mesh *scalp);
+
+/* Update an existing export cache when data is invalidated.
+ */
+int BKE_hair_export_cache_update(const struct HairSystem *hsys, int subdiv, struct DerivedMesh *scalp,
+                                 struct HairExportCache *cache, int data);
+
+/* Free the given export cache */
 void BKE_hair_export_cache_free(struct HairExportCache *cache);
 
+/* Returns flags for missing data parts */
+int BKE_hair_export_cache_get_required_updates(const struct HairExportCache *cache);
+
+/* Invalidate all data in a hair export cache */
+void BKE_hair_export_cache_clear(struct HairExportCache *cache);
+
+/* Invalidate part of the data in a hair export cache */
+void BKE_hair_export_cache_invalidate(struct HairExportCache *cache, int invalidate);
+
 /* === Draw Cache === */
 
 enum {
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index 2b0d95f83ad..999c305e426 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -546,102 +546,164 @@ static void hair_guide_calc_vectors(const HairGuideVertex* verts, int numverts,
 	        r_tangents[numverts-1], r_normals[numverts-1]);
 }
 
+/* Create a new export cache.
+ * This can be used to construct full fiber data for rendering.
+ */
+
 HairExportCache* BKE_hair_export_cache_new(const HairSystem *hsys, int subdiv, DerivedMesh *scalp)
 {
 	HairExportCache *cache = MEM_callocN(sizeof(HairExportCache), "hair export cache");
+	
+	BKE_hair_export_cache_update(hsys, subdiv, scalp, cache, HAIR_EXPORT_ALL);
+	
+	return cache;
+}
 
-	const int totguidecurves = cache->totguidecurves = hsys->guides.totcurves;
-	cache->guide_curves = MEM_mallocN(sizeof(HairGuideCurve) * totguidecurves, "hair export guide curves");
+/* Create a new export cache.
+ * This can be used to construct full fiber data for rendering.
+ * XXX Mesh-based version for Cycles export, until DerivedMesh->Mesh conversion is done.
+ */
 
-	/* Cache subdivided curves for repeated lookup */
-	int totguideverts = 0;
-	for (int i = 0; i < totguidecurves; ++i) {
-		const HairGuideCurve *curve_orig = &hsys->guides.curves[i];
-		HairGuideCurve *curve = &cache->guide_curves[i];
-		
-		memcpy(&curve->mesh_sample, &curve_orig->mesh_sample, sizeof(MeshSample));
-		curve->numverts = hair_get_strand_subdiv_length(curve_orig->numverts, subdiv);
-		curve->vertstart = totguideverts;
+HairExportCache* BKE_hair_export_cache_new_mesh(const HairSystem *hsys, int subdiv, struct Mesh *scalp)
+{
+	DerivedMesh *dm = CDDM_from_mesh(scalp);
+	HairExportCache *cache = BKE_hair_export_cache_new(hsys, subdiv, dm);
+	dm->release(dm);
+	return cache;
+}
+
+/* Update an existing export cache when data is invalidated.
+ */
+
+int BKE_hair_export_cache_update(const HairSystem *hsys, int subdiv, DerivedMesh *scalp,
+                                 HairExportCache *cache, int data)
+{
+	/* Check for missing data */
+	data |= BKE_hair_export_cache_get_required_updates(cache);
+	
+	if (data & HAIR_EXPORT_GUIDE_CURVES)
+	{
+		/* Cache subdivided guide curves */
+		const int totguidecurves = cache->totguidecurves = hsys->guides.totcurves;
+		cache->guide_curves = MEM_reallocN_id(cache->guide_curves, sizeof(HairGuideCurve) * totguidecurves, "hair export guide curves");
 		
-		totguideverts  += curve->numverts;
+		int totguideverts = 0;
+		for (int i = 0; i < totguidecurves; ++i) {
+			const HairGuideCurve *curve_orig = &hsys->guides.curves[i];
+			HairGuideCurve *curve = &cache->guide_curves[i];
+			
+			memcpy(&curve->mesh_sample, &curve_orig->mesh_sample, sizeof(MeshSample));
+			curve->numverts = hair_get_strand_subdiv_length(curve_orig->numverts, subdiv);
+			curve->vertstart = totguideverts;
+			
+			totguideverts  += curve->numverts;
+		}
+		cache->totguideverts = totguideverts;
 	}
 	
-	cache->totguideverts = totguideverts;
-	cache->guide_verts = MEM_mallocN(sizeof(HairGuideVertex) * totguideverts, "hair export guide verts");
-	cache->guide_tangents = MEM_mallocN(sizeof(float[3]) * totguideverts, "hair export guide tangents");
-	cache->guide_normals = MEM_mallocN(sizeof(float[3]) * totguideverts, "hair export guide normals");
-	
-	for (int i = 0; i < totguidecurves; ++i) {
-		const HairGuideCurve *curve_orig = &hsys->guides.curves[i];
-		const HairGuideVertex *verts_orig = &hsys->guides.verts[curve_orig->vertstart];
-		const HairGuideCurve *curve = &cache->guide_curves[i];
-		HairGuideVertex *verts = &cache->guide_verts[curve->vertstart];
-		float (*tangents)[3] = &cache->guide_tangents[curve->vertstart];
-		float (*normals)[3] = &cache->guide_normals[curve->vertstart];
-		
-		hair_guide_subdivide(curve_orig, verts_orig, subdiv, verts);
+	if (data & HAIR_EXPORT_GUIDE_VERTICES)
+	{
+		const int totguidecurves = cache->totguidecurves;
+		const int totguideverts = cache->totguideverts;
+		cache->guide_verts = MEM_reallocN_id(cache->guide_verts, sizeof(HairGuideVertex) * totguideverts, "hair export guide verts");
+		cache->guide_tangents = MEM_reallocN_id(cache->guide_tangents, sizeof(float[3]) * totguideverts, "hair export guide tangents");
+		cache->guide_normals = MEM_reallocN_id(cache->guide_normals, sizeof(float[3]) * totguideverts, "hair export guide normals");
 		
-		{
-			/* Root matrix for defining the initial normal direction */
-			float rootpos[3];
-			float rootmat[3][3];
-			BKE_mesh_sample_eval(scalp, &curve->mesh_sample, rootpos, rootmat[2], rootmat[0]);
-			cross_v3_v3v3(rootmat[1], rootmat[2], rootmat[0]);
+		for (int i = 0; i < totguidecurves; ++i) {
+			const HairGuideCurve *curve_orig = &hsys->guides.curves[i];
+			const HairGuideVertex *verts_orig = &hsys->guides.verts[curve_orig->vertstart];
+			const HairGuideCurve *curve = &cache->guide_curves[i];
+			HairGuideVertex *verts = &cache->guide_verts[curve->vertstart];
+			float (*tangents)[3] = &cache->guide_tangents[curve->vertstart];
+			float (*normals)[3] = &cache->guide_normals[curve->vertstart];
+			
+			hair_guide_subdivide(curve_orig, verts_orig, subdiv, verts);
 			
-			hair_guide_calc_vectors(verts, curve->numverts, rootmat, tangents, normals);
+			{
+				/* Root matrix for defining the initial normal direction */
+				float rootpos[3];
+				float rootmat[3][3];
+				BKE_mesh_sample_eval(scalp, &curve->mesh_sample, rootpos, rootmat[2], rootmat[0]);
+				cross_v3_v3v3(rootmat[1], rootmat[2], rootmat[0]);
+				
+				hair_guide_calc_vectors(verts, curve->numverts, rootmat, tangents, normals);
+			}
 		}
 	}
-	
+
 	if (hsys->pattern)
 	{
-		const int totfibercurves = cache->totfibercurves = hsys->pattern->num_follicles;
-		
-		cache->follicles = hsys->pattern->follicles;
-		
-		cache->fiber_numverts = MEM_mallocN(sizeof(int) * totfibercurves, "fiber numverts");
-		cache->fiber_root_position = MEM_mallocN(sizeof(float[3]) * totfibercurves, "fiber root position");
-		
-		// Calculate the length of the fiber from the weighted average of its guide strands
-		cache->totfiberverts = 0;
-		const HairFollicle *follicle = hsys->pattern->follicles;
-		for (int i = 0; i < totfibercurves; ++i, ++follicle) {
-			float fiblen = 0.0f;
+		if (data & HAIR_EXPORT_FOLLICLE_BINDING)
+		{
+			cache->follicles = hsys->pattern->follicles;
+			cache->totfibercurves = hsys->pattern->num_follicles;
+		}
+
+		if (data & HAIR_EXPORT_FIBER_VERTEX_COUNTS)
+		{
+			/* Calculate the length of each fiber from the weighted average of its guide strands */
+			const int totguidecurves = cache->totguidecurves;
+			const int totfibercurves = cache->totfibercurves;
 			
-			for (int k = 0; k < 4; ++k) {
-				const int si = follicle->parent_index[k];
-				const float sw = follicle->parent_weight[k];
-				if (si == HAIR_STRAND_INDEX_NONE || sw == 0.0f) {
-					break;
+			cache->fiber_numverts = MEM_reallocN_id(cache->fiber_numverts, sizeof(int) * totfibercurves, "fiber numverts");
+			cache->totfiberverts = 0;
+			
+			const HairFollicle *follicle = hsys->pattern->follicles;
+			for (int i = 0; i < totfibercurves; ++i, ++follicle) {
+				float fiblen = 0.0f;
+				
+				for (int k = 0; k < 4; ++k) {
+					const int si = follicle->par

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list