[Bf-blender-cvs] [116bab7] master: Fix T47639: OpenGL render with smoke and fire incorrect when using transparency.

Kévin Dietrich noreply at git.blender.org
Sun Aug 28 16:51:29 CEST 2016


Commit: 116bab702e009ce8043b976b4a9c4afa4c7ff5b0
Author: Kévin Dietrich
Date:   Sun Aug 28 16:50:49 2016 +0200
Branches: master
https://developer.blender.org/rB116bab702e009ce8043b976b4a9c4afa4c7ff5b0

Fix T47639: OpenGL render with smoke and fire incorrect when using
transparency.

The issue is that we are rendering to a 0..1 clamped sRGB buffer with
unpremultiplied alpha, where the correct thing to do would be to render
to an unclamped linear premultiplied alpha buffer. Then we would just
make fire purely emissive without affecting the alpha channel at all,
but that doesn't work here.

So for now, draw fire and smoke separately using different shaders and
blend modes, like it used to before the smoke programs were rewritten
(see rB0372b642).

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

M	source/blender/editors/space_view3d/drawvolume.c
M	source/blender/gpu/CMakeLists.txt
M	source/blender/gpu/intern/gpu_shader.c
A	source/blender/gpu/shaders/gpu_shader_fire_frag.glsl
M	source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl

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

diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 8dbc278..06677ef 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -288,6 +288,108 @@ static int create_view_aligned_slices(VolumeSlicer *slicer,
 	return num_points;
 }
 
+static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec,
+                        bool use_fire, const float min[3],
+                        const float ob_sizei[3], const float invsize[3])
+{
+	int invsize_location = GPU_shader_get_uniform(shader, "invsize");
+	int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei");
+	int min_location = GPU_shader_get_uniform(shader, "min_location");
+
+	int soot_location;
+	int stepsize_location;
+	int densityscale_location;
+	int spec_location, flame_location;
+	int shadow_location, actcol_location;
+
+	if (use_fire) {
+		spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
+		flame_location = GPU_shader_get_uniform(shader, "flame_texture");
+	}
+	else {
+		shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
+		actcol_location = GPU_shader_get_uniform(shader, "active_color");
+		soot_location = GPU_shader_get_uniform(shader, "soot_texture");
+		stepsize_location = GPU_shader_get_uniform(shader, "step_size");
+		densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
+	}
+
+	GPU_shader_bind(shader);
+
+	if (use_fire) {
+		GPU_texture_bind(sds->tex_flame, 2);
+		GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
+
+		GPU_texture_bind(tex_spec, 3);
+		GPU_shader_uniform_texture(shader, spec_location, tex_spec);
+	}
+	else {
+		float density_scale = 10.0f;
+
+		GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
+		GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
+
+		GPU_texture_bind(sds->tex, 0);
+		GPU_shader_uniform_texture(shader, soot_location, sds->tex);
+
+		GPU_texture_bind(sds->tex_shadow, 1);
+		GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow);
+
+		float active_color[3] = { 0.9, 0.9, 0.9 };
+		if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
+			mul_v3_v3(active_color, sds->active_color);
+		GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
+	}
+
+	GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
+	GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei);
+	GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
+}
+
+static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool use_fire)
+{
+	GPU_shader_unbind();
+
+	GPU_texture_unbind(sds->tex);
+
+	if (use_fire) {
+		GPU_texture_unbind(sds->tex_flame);
+		GPU_texture_unbind(tex_spec);
+		GPU_texture_free(tex_spec);
+	}
+	else {
+		GPU_texture_unbind(sds->tex_shadow);
+	}
+}
+
+static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer,
+                        const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire)
+{
+	GPUTexture *tex_spec = (do_fire) ? create_flame_spectrum_texture() : NULL;
+
+	GLuint vertex_buffer;
+	glGenBuffers(1, &vertex_buffer);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW);
+
+	bind_shader(sds, shader, tex_spec, do_fire, slicer->min, ob_sizei, invsize);
+
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glVertexPointer(3, GL_FLOAT, 0, NULL);
+
+	glDrawArrays(GL_TRIANGLES, 0, num_points);
+
+	glDisableClientState(GL_VERTEX_ARRAY);
+
+	unbind_shader(sds, tex_spec, do_fire);
+
+	/* cleanup */
+
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+	glDeleteBuffers(1, &vertex_buffer);
+}
+
 void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
                        const float min[3], const float max[3],
                         const float viewnormal[3])
@@ -299,14 +401,23 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
 
 	const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame;
 
-	GPUShader *shader = GPU_shader_get_builtin_shader(
-	                        (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE);
+	GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE);
 
 	if (!shader) {
 		fprintf(stderr, "Unable to create GLSL smoke shader.\n");
 		return;
 	}
 
+	GPUShader *fire_shader = NULL;
+	if (use_fire) {
+		fire_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE_FIRE);
+
+		if (!fire_shader) {
+			fprintf(stderr, "Unable to create GLSL fire shader.\n");
+			return;
+		}
+	}
+
 	const float ob_sizei[3] = {
 	    1.0f / fabsf(ob->size[0]),
 	    1.0f / fabsf(ob->size[1]),
@@ -320,50 +431,6 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
 	TIMEIT_START(draw);
 #endif
 
-	/* setup smoke shader */
-
-	int soot_location = GPU_shader_get_uniform(shader, "soot_texture");
-	int spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
-	int shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
-	int flame_location = GPU_shader_get_uniform(shader, "flame_texture");
-	int actcol_location = GPU_shader_get_uniform(shader, "active_color");
-	int stepsize_location = GPU_shader_get_uniform(shader, "step_size");
-	int densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
-	int invsize_location = GPU_shader_get_uniform(shader, "invsize");
-	int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei");
-	int min_location = GPU_shader_get_uniform(shader, "min_location");
-
-	GPU_shader_bind(shader);
-
-	GPU_texture_bind(sds->tex, 0);
-	GPU_shader_uniform_texture(shader, soot_location, sds->tex);
-
-	GPU_texture_bind(sds->tex_shadow, 1);
-	GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow);
-
-	GPUTexture *tex_spec = NULL;
-
-	if (use_fire) {
-		GPU_texture_bind(sds->tex_flame, 2);
-		GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
-
-		tex_spec = create_flame_spectrum_texture();
-		GPU_texture_bind(tex_spec, 3);
-		GPU_shader_uniform_texture(shader, spec_location, tex_spec);
-	}
-
-	float active_color[3] = { 0.9, 0.9, 0.9 };
-	float density_scale = 10.0f;
-	if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
-		mul_v3_v3(active_color, sds->active_color);
-
-	GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
-	GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
-	GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
-	GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
-	GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei);
-	GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
-
 	/* setup slicing information */
 
 	const int max_slices = 256;
@@ -387,43 +454,23 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
 	glEnable(GL_DEPTH_TEST);
 	glDepthMask(GL_FALSE);
 	glEnable(GL_BLEND);
-	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
-	GLuint vertex_buffer;
-	glGenBuffers(1, &vertex_buffer);
-	glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer.verts[0][0], GL_STATIC_DRAW);
 
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glVertexPointer(3, GL_FLOAT, 0, NULL);
-
-	glDrawArrays(GL_TRIANGLES, 0, num_points);
+	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+	draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false);
 
-	glDisableClientState(GL_VERTEX_ARRAY);
+	/* Draw fire separately (T47639). */
+	if (use_fire) {
+		glBlendFunc(GL_ONE, GL_ONE);
+		draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true);
+	}
 
 #ifdef DEBUG_DRAW_TIME
 	printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
 	TIMEIT_END(draw);
 #endif
 
-	/* cleanup */
-
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-	glDeleteBuffers(1, &vertex_buffer);
-
-	GPU_texture_unbind(sds->tex);
-	GPU_texture_unbind(sds->tex_shadow);
-
-	if (use_fire) {
-		GPU_texture_unbind(sds->tex_flame);
-		GPU_texture_unbind(tex_spec);
-		GPU_texture_free(tex_spec);
-	}
-
 	MEM_freeN(slicer.verts);
 
-	GPU_shader_unbind();
-
 	glDepthMask(gl_depth_write);
 
 	if (!gl_blend) {
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index cfa0831..8885209 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -78,6 +78,7 @@ set(SRC
 	shaders/gpu_shader_vsm_store_frag.glsl
 	shaders/gpu_shader_vsm_store_vert.glsl
 	shaders/gpu_shader_fx_depth_resolve.glsl
+	shaders/gpu_shader_fire_frag.glsl
 	shaders/gpu_shader_smoke_frag.glsl
 	shaders/gpu_shader_smoke_vert.glsl
 
@@ -99,6 +100,7 @@ set(SRC
 )
 
 data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fire_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_smoke_vert.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index df1213b..5cfb323 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -45,6 +45,7 @@
 #define MAX_EXT_DEFINE_LENGTH 1024
 
 /* Non-generated shaders */
+extern char datatoc_gpu_shader_fire_frag_glsl[];
 extern char datatoc_gpu_shader_smoke_vert_glsl[];
 extern char datatoc_gpu_shader_smoke_frag_glsl[];
 extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
@@ -618,8 +619,8 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
 		case GPU_SHADER_SMOKE_FIRE:
 			if (!GG.shaders.smoke_fire)
 				GG.shaders.smoke_fire = GPU_shader_create(
-				        datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
-				        NULL, NULL, "#define USE_FIRE;\n", 0, 0, 0);
+				        datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_fire_frag_glsl,
+				        NULL, NULL, NULL, 0, 0, 0);
 			retval = GG.shaders.smoke_fire;
 			break;
 	}
diff --git a/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl
new file mode 100644


@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list