[Bf-blender-cvs] [062e52b] strand_gpu: Alternative implementation for strand fiber interpolation without a geometry shader.

Lukas Tönne noreply at git.blender.org
Mon Jul 11 21:08:23 CEST 2016


Commit: 062e52b8ee508babdde804b39aaaced236299760
Author: Lukas Tönne
Date:   Mon Jul 11 20:19:06 2016 +0200
Branches: strand_gpu
https://developer.blender.org/rB062e52b8ee508babdde804b39aaaced236299760

Alternative implementation for strand fiber interpolation without a geometry shader.

Geometry shaders easily become performance bottlenecks, for in-depth explanation see e.g.

http://gamedev.stackexchange.com/a/48434
http://rastergrid.com/blog/2010/09/history-of-hardware-tessellation/

The geometry shader was used so far for generating the fiber geometry (line strips)
from just the root vertices. Without a geometry shader every vertex has to be put into
a buffer and uploaded to the GPU (we could use a tesselation shader to cut down on size,
but that remains to be decided later if OpenGL 4.x is available).

To limit the size of this vertex buffer, the vertices contain only minimal necessary
information: an index for the fiber curve, and an interpolation curve parammeter in [0.0, 1.0].
The locations of vertices are interpolated in the vertex shader using texture lookups.
A range of textures encode all the necessary per-fiber attributes, in particular the
interpolation indices and weights wrt. control curves. These control curves are stored in
yet another texture (as is the case with the geometry shader too).

Initial performance seems to improve drastically without the geometry shader.

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

M	release/scripts/startup/bl_ui/properties_data_modifier.py
M	source/blender/editors/space_view3d/drawstrands.c
M	source/blender/gpu/GPU_buffers.h
M	source/blender/gpu/GPU_strands.h
M	source/blender/gpu/intern/gpu_buffers.c
M	source/blender/gpu/intern/gpu_strands.c
M	source/blender/gpu/shaders/gpu_shader_strand_frag.glsl
M	source/blender/gpu/shaders/gpu_shader_strand_geom.glsl
M	source/blender/gpu/shaders/gpu_shader_strand_vert.glsl
M	source/blender/makesdna/DNA_modifier_types.h
M	source/blender/makesrna/intern/rna_modifier.c

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

diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 4328546..0319e6c 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -892,6 +892,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
         col.prop(md, "show_strands", text="Control Strands")
         col.prop(md, "show_fibers", text="Fibers")
         col.prop(md, "subdivisions")
+        col.prop(md, "use_geometry_shader")
         
         col.separator()
 
diff --git a/source/blender/editors/space_view3d/drawstrands.c b/source/blender/editors/space_view3d/drawstrands.c
index 6b0f227..d76b4a6 100644
--- a/source/blender/editors/space_view3d/drawstrands.c
+++ b/source/blender/editors/space_view3d/drawstrands.c
@@ -104,6 +104,8 @@ void draw_strands(Scene *scene, View3D *UNUSED(v3d), RegionView3D *rv3d,
 	Strands *strands = smd->strands;
 	bool show_controls = smd->flag & MOD_STRANDS_SHOW_STRANDS;
 	bool show_strands = smd->flag & MOD_STRANDS_SHOW_FIBERS;
+	bool use_geomshader = smd->flag & MOD_STRANDS_USE_GEOMSHADER;
+	
 	if (strands == NULL)
 		return;
 	
@@ -111,13 +113,15 @@ void draw_strands(Scene *scene, View3D *UNUSED(v3d), RegionView3D *rv3d,
 	params.strands = smd->strands;
 	params.root_dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
 	params.subdiv = smd->subdiv;
+	params.use_geomshader = use_geomshader;
 	
 	if (smd->gpu_buffer == NULL)
 		smd->gpu_buffer = GPU_strands_buffer_create(&params);
 	GPUDrawStrands *buffer = smd->gpu_buffer;
 	GPUStrandsShader *shader = GPU_strand_shader_get(strands,
 	                                                 get_shader_model(smd->shader_model),
-	                                                 get_effects(smd->effects));
+	                                                 get_effects(smd->effects),
+	                                                 use_geomshader);
 	
 	if (show_controls) {
 		GPU_strands_setup_edges(buffer, &params);
@@ -132,15 +136,30 @@ void draw_strands(Scene *scene, View3D *UNUSED(v3d), RegionView3D *rv3d,
 		bind_strands_shader(shader, rv3d, ob, smd);
 		
 		GPU_strands_setup_fibers(buffer, &params);
-		if (buffer->fiber_points) {
+		if (use_geomshader) {
+			if (buffer->fibers) {
+				struct GPUAttrib *attrib;
+				int num_attrib;
+				GPU_strand_shader_get_fiber_attributes(shader, &attrib, &num_attrib);
+				
+				int elemsize = GPU_attrib_element_size(attrib, num_attrib);
+				GPU_interleaved_attrib_setup(buffer->fibers, attrib, num_attrib, elemsize, false);
+				
+				glDrawArrays(GL_POINTS, 0, buffer->totfibers * elemsize);
+				
+				GPU_interleaved_attrib_unbind();
+			}
+		}
+		else {
 			struct GPUAttrib *attrib;
 			int num_attrib;
-			GPU_strand_shader_get_attributes(shader, &attrib, &num_attrib);
+			GPU_strand_shader_get_fiber_attributes(shader, &attrib, &num_attrib);
 			
 			int elemsize = GPU_attrib_element_size(attrib, num_attrib);
 			GPU_interleaved_attrib_setup(buffer->fiber_points, attrib, num_attrib, elemsize, false);
 			
-			glDrawArrays(GL_POINTS, 0, buffer->totfibers * elemsize);
+			GPU_buffer_draw_elements(buffer->fiber_edges, GL_LINES, 0,
+			                         buffer->fiber_totedges * 2);
 			
 			GPU_interleaved_attrib_unbind();
 		}
@@ -467,6 +486,7 @@ void draw_strands_edit(Scene *scene, View3D *UNUSED(v3d), RegionView3D *rv3d,
 	BMEditStrands *edit = smd->edit;
 	bool show_controls = smd->flag & MOD_STRANDS_SHOW_STRANDS;
 	bool show_strands = smd->flag & MOD_STRANDS_SHOW_FIBERS;
+	bool use_geomshader = smd->flag & MOD_STRANDS_USE_GEOMSHADER;
 	
 	if (smd->strands == NULL || edit == NULL)
 		return;
@@ -476,13 +496,15 @@ void draw_strands_edit(Scene *scene, View3D *UNUSED(v3d), RegionView3D *rv3d,
 	params.edit = edit;
 	params.root_dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
 	params.subdiv = smd->subdiv;
+	params.use_geomshader = use_geomshader;
 	
 	if (smd->gpu_buffer == NULL)
 		smd->gpu_buffer = GPU_strands_buffer_create(&params);
 	GPUDrawStrands *buffer = smd->gpu_buffer;
 	GPUStrandsShader *shader = GPU_strand_shader_get(smd->strands,
 	                                                 get_shader_model(smd->shader_model),
-	                                                 get_effects(smd->effects));
+	                                                 get_effects(smd->effects),
+	                                                 use_geomshader);
 	
 	if (show_controls) {
 		GPU_strands_setup_edges(buffer, &params);
@@ -496,15 +518,30 @@ void draw_strands_edit(Scene *scene, View3D *UNUSED(v3d), RegionView3D *rv3d,
 		bind_strands_shader(shader, rv3d, ob, smd);
 		
 		GPU_strands_setup_fibers(buffer, &params);
-		if (buffer->fiber_points) {
+		if (use_geomshader) {
+			if (buffer->fibers) {
+				struct GPUAttrib *attrib;
+				int num_attrib;
+				GPU_strand_shader_get_fiber_attributes(shader, &attrib, &num_attrib);
+				
+				int elemsize = GPU_attrib_element_size(attrib, num_attrib);
+				GPU_interleaved_attrib_setup(buffer->fibers, attrib, num_attrib, elemsize, false);
+				
+				glDrawArrays(GL_POINTS, 0, buffer->totfibers * elemsize);
+				
+				GPU_interleaved_attrib_unbind();
+			}
+		}
+		else {
 			struct GPUAttrib *attrib;
 			int num_attrib;
-			GPU_strand_shader_get_attributes(shader, &attrib, &num_attrib);
+			GPU_strand_shader_get_fiber_attributes(shader, &attrib, &num_attrib);
 			
 			int elemsize = GPU_attrib_element_size(attrib, num_attrib);
 			GPU_interleaved_attrib_setup(buffer->fiber_points, attrib, num_attrib, elemsize, false);
 			
-			glDrawArrays(GL_POINTS, 0, buffer->totfibers * elemsize);
+			GPU_buffer_draw_elements(buffer->fiber_edges, GL_LINES, 0,
+			                         buffer->fiber_totedges * 2);
 			
 			GPU_interleaved_attrib_unbind();
 		}
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index ae12fdc..c30020a 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -154,17 +154,33 @@ typedef struct GPUDrawStrands {
 	GPUBuffer *strand_edges;
 	GPUBuffer *control_points;
 	GPUBuffer *control_curves;
+	GPUBuffer *fibers;
 	GPUBuffer *fiber_points;
+	GPUBuffer *fiber_edges;
+	GPUBuffer *fiber_position;
+	GPUBuffer *fiber_normal;
+	GPUBuffer *fiber_tangent;
+	GPUBuffer *fiber_control_index;
+	GPUBuffer *fiber_control_weight;
+	GPUBuffer *fiber_root_distance;
 
 	/* GL texture id for control point texture buffer */
 	GPUBufferTexture control_points_tex;
 	GPUBufferTexture control_curves_tex;
+	GPUBufferTexture fiber_position_tex;
+	GPUBufferTexture fiber_normal_tex;
+	GPUBufferTexture fiber_tangent_tex;
+	GPUBufferTexture fiber_control_index_tex;
+	GPUBufferTexture fiber_control_weight_tex;
+	GPUBufferTexture fiber_root_distance_tex;
 
 	unsigned int strand_totverts;
 	unsigned int strand_totedges;
 	unsigned int control_totverts;
 	unsigned int control_totcurves;
 	unsigned int totfibers;
+	unsigned int fiber_totverts;
+	unsigned int fiber_totedges;
 } GPUDrawStrands;
 
 
@@ -300,6 +316,7 @@ typedef struct GPUDrawStrandsParams {
 	struct BMEditStrands *edit;
 	struct DerivedMesh *root_dm;
 	int subdiv;
+	bool use_geomshader;
 } GPUDrawStrandsParams;
 
 struct GPUDrawStrands *GPU_strands_buffer_create(struct GPUDrawStrandsParams *params);
diff --git a/source/blender/gpu/GPU_strands.h b/source/blender/gpu/GPU_strands.h
index e74165f..f72ab7f 100644
--- a/source/blender/gpu/GPU_strands.h
+++ b/source/blender/gpu/GPU_strands.h
@@ -55,7 +55,8 @@ typedef enum GPUStrands_Effects {
 
 GPUStrandsShader *GPU_strand_shader_get(struct Strands *strands,
                                         GPUStrands_ShaderModel shader_model,
-                                        int effects);
+                                        int effects,
+                                        bool use_geometry_shader);
 
 void GPU_strand_shader_free(struct GPUStrandsShader *gpu_shader);
 
@@ -69,8 +70,8 @@ void GPU_strand_shader_bind_uniforms(
 void GPU_strand_shader_unbind(GPUStrandsShader *gpu_shader);
 bool GPU_strand_shader_bound(GPUStrandsShader *gpu_shader);
 
-void GPU_strand_shader_get_attributes(struct GPUStrandsShader *gpu_shader,
-                                      struct GPUAttrib **r_attrib, int *r_num);
+void GPU_strand_shader_get_fiber_attributes(struct GPUStrandsShader *gpu_shader,
+                                            struct GPUAttrib **r_attrib, int *r_num);
 
 #ifdef __cplusplus
 }
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 0308ca8..b0c221b 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -2122,7 +2122,7 @@ void GPU_end_draw_pbvh_BB(void)
 /* *************** */
 /* Strands Buffers */
 
-typedef struct FiberVertex {
+typedef struct GPUFiber {
 	/* object space location and orientation of the follicle */
 	float co[3];
 	float normal[3];
@@ -2132,28 +2132,56 @@ typedef struct FiberVertex {
 	float control_weight[4];
 	/* parametric distance from the primary control strand */
 	float root_distance[2];
-} FiberVertex;
+} GPUFiber;
+
+typedef struct GPUFiberVertex {
+	/* index of the fiber curve (for texture lookup) */
+	unsigned int fiber_index;
+	/* curve parameter for interpolation */
+	float curve_param;
+} GPUFiberVertex;
 
 typedef enum GPUStrandBufferType {
 	GPU_STRAND_BUFFER_STRAND_VERTEX = 0,
 	GPU_STRAND_BUFFER_STRAND_EDGE,
 	GPU_STRAND_BUFFER_CONTROL_VERTEX,
 	GPU_STRAND_BUFFER_CONTROL_CURVE,
+	/* fiber buffers */
 	GPU_STRAND_BUFFER_FIBER_VERTEX,
+	GPU_STRAND_BUFFER_FIBER_EDGE,
+	/* fiber curve attributes (buffer textures) */
+	GPU_STRAND_BUFFER_FIBER_POSITION,
+	GPU_STRAND_BUFFER_FIBER_NORMAL,
+	GPU_STRAND_BUFFER_FIBER_TANGENT,
+	GPU_STRAND_BUFFER_FIBER_CONTROL_INDEX,
+	GPU_STRAND_BUFFER_FIBER_CONTROL_WEIGHT,
+	GPU_STRAND_BUFFER_FIBER_ROOT_DISTANCE,
+	/* fiber vertex buffer (geometry shader only) */
+	GPU_STRAND_BUFFER_FIBER,
 } GPUStrandBufferType;
 
-const GPUBufferTypeSettings gpu_strand_buffer_type_settings[] = {
-    /* STRAND_VERTEX */
-    {GL_ARRAY_BUFFER, 3},
-    /* STRAND_EDGE */
-    {GL_ELEMENT_ARRAY_BUFFER, 2},
-    /* CONTROL_VERTEX */
-    {GL_ARR

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list