Exemplo n.º 1
0
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
                       const float min[3], const float max[3],
                        const float viewnormal[3])
{
	if (!sds->tex || !sds->tex_shadow) {
		fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n");
		return;
	}

	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);

	if (!shader) {
		fprintf(stderr, "Unable to create GLSL smoke shader.\n");
		return;
	}

	const float ob_sizei[3] = {
	    1.0f / fabsf(ob->size[0]),
	    1.0f / fabsf(ob->size[1]),
	    1.0f / fabsf(ob->size[2])
	};

	const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] };
	const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] };

#ifdef DEBUG_DRAW_TIME
	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");

	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;
	const int max_points = max_slices * 12;

	VolumeSlicer slicer;
	copy_v3_v3(slicer.min, min);
	copy_v3_v3(slicer.max, max);
	copy_v3_v3(slicer.size, size);
	slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices");

	const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal);

	/* setup buffer and draw */

	int gl_depth = 0, gl_blend = 0;
	glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
	glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);

	glEnable(GL_DEPTH_TEST);
	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);

	glDisableClientState(GL_VERTEX_ARRAY);

#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();

	if (!gl_blend) {
		glDisable(GL_BLEND);
	}

	if (gl_depth) {
		glEnable(GL_DEPTH_TEST);
	}
}
Exemplo n.º 2
0
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
                       const float min[3], const float max[3],
                        const float viewnormal[3])
{
	if (!sds->tex || !sds->tex_shadow) {
		fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n");
		return;
	}

	const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame;

	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]),
	    1.0f / fabsf(ob->size[2])
	};

	const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] };
	const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] };

#ifdef DEBUG_DRAW_TIME
	TIMEIT_START(draw);
#endif

	/* setup slicing information */

	const int max_slices = 256;
	const int max_points = max_slices * 12;

	VolumeSlicer slicer;
	copy_v3_v3(slicer.min, min);
	copy_v3_v3(slicer.max, max);
	copy_v3_v3(slicer.size, size);
	slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices");

	const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal);

	/* setup buffer and draw */

	int gl_depth = 0, gl_blend = 0, gl_depth_write = 0;
	glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
	glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
	glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&gl_depth_write);

	glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_FALSE);
	glEnable(GL_BLEND);

	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
	draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false);

	/* 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

	MEM_freeN(slicer.verts);

	glDepthMask(gl_depth_write);

	if (!gl_blend) {
		glDisable(GL_BLEND);
	}

	if (gl_depth) {
		glEnable(GL_DEPTH_TEST);
	}
}