Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c447
-rw-r--r--source/blender/gpu/CMakeLists.txt9
-rw-r--r--source/blender/gpu/GPU_shader.h21
-rw-r--r--source/blender/gpu/intern/gpu_shader.c122
-rw-r--r--source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl32
-rw-r--r--source/blender/gpu/shaders/gpu_program_smoke_frag.glsl27
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl48
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl12
8 files changed, 340 insertions, 378 deletions
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 72d84b4be04..591cf94b86f 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -46,6 +46,7 @@
#include "BIF_gl.h"
+#include "GPU_debug.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -60,35 +61,6 @@ struct GPUTexture;
# include "PIL_time_utildefines.h"
#endif
-static int intersect_edges(float (*points)[3], float a, float b, float c, float d, const float edges[12][2][3])
-{
- int i;
- float t;
- int numpoints = 0;
-
- for (i = 0; i < 12; i++) {
- t = -(a * edges[i][0][0] + b * edges[i][0][1] + c * edges[i][0][2] + d) /
- (a * edges[i][1][0] + b * edges[i][1][1] + c * edges[i][1][2]);
- if ((t > 0) && (t < 1)) {
- points[numpoints][0] = edges[i][0][0] + edges[i][1][0] * t;
- points[numpoints][1] = edges[i][0][1] + edges[i][1][1] * t;
- points[numpoints][2] = edges[i][0][2] + edges[i][1][2] * t;
- numpoints++;
- }
- }
- return numpoints;
-}
-
-static bool convex(const float p0[3], const float up[3], const float a[3], const float b[3])
-{
- /* Vec3 va = a-p0, vb = b-p0; */
- float va[3], vb[3], tmp[3];
- sub_v3_v3v3(va, a, p0);
- sub_v3_v3v3(vb, b, p0);
- cross_v3_v3v3(tmp, va, vb);
- return dot_v3v3(up, tmp) >= 0;
-}
-
static GPUTexture *create_flame_spectrum_texture(void)
{
#define SPEC_WIDTH 256
@@ -134,218 +106,308 @@ static GPUTexture *create_flame_spectrum_texture(void)
return tex;
}
-void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
- const float min[3], const float max[3],
- const float viewnormal[3])
+typedef struct VolumeSlicer {
+ float size[3];
+ float min[3];
+ float max[3];
+ float (*verts)[3];
+} VolumeSlicer;
+
+/* *************************** View Aligned Slicing ************************** */
+
+/* Code adapted from:
+ * "GPU-based Volume Rendering, Real-time Volume Graphics", AK Peters/CRC Press
+ */
+static int create_view_aligned_slices(VolumeSlicer *slicer,
+ const int num_slices,
+ const float view_dir[3])
{
- GPUTexture *tex_spec = NULL;
- GPUProgram *smoke_program;
- const int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED
- : GPU_PROGRAM_SMOKE;
+ const int indices[] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5 };
+
+ const float vertices[8][3] = {
+ { slicer->min[0], slicer->min[1], slicer->min[2] },
+ { slicer->max[0], slicer->min[1], slicer->min[2] },
+ { slicer->max[0], slicer->max[1], slicer->min[2] },
+ { slicer->min[0], slicer->max[1], slicer->min[2] },
+ { slicer->min[0], slicer->min[1], slicer->max[2] },
+ { slicer->max[0], slicer->min[1], slicer->max[2] },
+ { slicer->max[0], slicer->max[1], slicer->max[2] },
+ { slicer->min[0], slicer->max[1], slicer->max[2] }
+ };
- const float ob_sizei[3] = {
- 1.0f / fabsf(ob->size[0]),
- 1.0f / fabsf(ob->size[1]),
- 1.0f / fabsf(ob->size[2])
+ const int edges[12][2] = {
+ { 0, 1 }, { 1, 2 }, { 2, 3 },
+ { 3, 0 }, { 0, 4 }, { 1, 5 },
+ { 2, 6 }, { 3, 7 }, { 4, 5 },
+ { 5, 6 }, { 6, 7 }, { 7, 4 }
};
- int i, j, n, good_index;
- float d /*, d0 */ /* UNUSED */, dd, ds;
- float (*points)[3] = NULL;
- int numpoints = 0;
- int gl_depth = 0, gl_blend = 0;
+ const int edge_list[8][12] = {
+ { 0, 1, 5, 6, 4, 8, 11, 9, 3, 7, 2, 10 },
+ { 0, 4, 3, 11, 1, 2, 6, 7, 5, 9, 8, 10 },
+ { 1, 5, 0, 8, 2, 3, 7, 4, 6, 10, 9, 11 },
+ { 7, 11, 10, 8, 2, 6, 1, 9, 3, 0, 4, 5 },
+ { 8, 5, 9, 1, 11, 10, 7, 6, 4, 3, 0, 2 },
+ { 9, 6, 10, 2, 8, 11, 4, 7, 5, 0, 1, 3 },
+ { 9, 8, 5, 4, 6, 1, 2, 0, 10, 7, 11, 3 },
+ { 10, 9, 6, 5, 7, 2, 3, 1, 11, 4, 8, 0 }
+ };
- const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) != 0;
+ /* find vertex that is the furthest from the view plane */
+ int max_index = 0;
+ float max_dist, min_dist;
+ min_dist = max_dist = dot_v3v3(view_dir, vertices[0]);
- /* draw slices of smoke is adapted from c++ code authored
- * by: Johannes Schmid and Ingemar Rask, 2006, johnny@grob.org */
- const float verts[8][3] = {
- { max[0], max[1], max[2] },
- { min[0], max[1], max[2] },
- { min[0], min[1], max[2] },
- { max[0], min[1], max[2] },
- { max[0], max[1], min[2] },
- { min[0], max[1], min[2] },
- { min[0], min[1], min[2] },
- { max[0], min[1], min[2] }
- };
+ for (int i = 1; i < 8; i++) {
+ float dist = dot_v3v3(view_dir, vertices[i]);
- 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] };
+ if (dist > max_dist) {
+ max_dist = dist;
+ max_index = i;
+ }
- /* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */
- const float edges[12][2][3] = {
- {{verts[4][0], verts[4][1], verts[4][2]}, {0.0f, 0.0f, size[2]}},
- {{verts[5][0], verts[5][1], verts[5][2]}, {0.0f, 0.0f, size[2]}},
- {{verts[6][0], verts[6][1], verts[6][2]}, {0.0f, 0.0f, size[2]}},
- {{verts[7][0], verts[7][1], verts[7][2]}, {0.0f, 0.0f, size[2]}},
-
- {{verts[3][0], verts[3][1], verts[3][2]}, {0.0f, size[1], 0.0f}},
- {{verts[2][0], verts[2][1], verts[2][2]}, {0.0f, size[1], 0.0f}},
- {{verts[6][0], verts[6][1], verts[6][2]}, {0.0f, size[1], 0.0f}},
- {{verts[7][0], verts[7][1], verts[7][2]}, {0.0f, size[1], 0.0f}},
-
- {{verts[1][0], verts[1][1], verts[1][2]}, {size[0], 0.0f, 0.0f}},
- {{verts[2][0], verts[2][1], verts[2][2]}, {size[0], 0.0f, 0.0f}},
- {{verts[6][0], verts[6][1], verts[6][2]}, {size[0], 0.0f, 0.0f}},
- {{verts[5][0], verts[5][1], verts[5][2]}, {size[0], 0.0f, 0.0f}}
- };
+ if (dist < min_dist) {
+ min_dist = dist;
+ }
+ }
- if (!sds->tex) {
- printf("Could not allocate 3D texture for 3D View smoke drawing.\n");
- return;
+ max_dist -= FLT_EPSILON;
+ min_dist += FLT_EPSILON;
+
+ /* start and direction vectors */
+ float vec_start[12][3], vec_dir[12][3];
+ /* lambda intersection values */
+ float lambda[12], lambda_inc[12];
+ float denom = 0.0f;
+
+ float plane_dist = min_dist;
+ float plane_dist_inc = (max_dist - min_dist) / (float)num_slices;
+
+ /* for all egdes */
+ for (int i = 0; i < 12; i++) {
+ copy_v3_v3(vec_start[i], vertices[edges[edge_list[max_index][i]][0]]);
+ copy_v3_v3(vec_dir[i], vertices[edges[edge_list[max_index][i]][1]]);
+ sub_v3_v3(vec_dir[i], vec_start[i]);
+
+ denom = dot_v3v3(vec_dir[i], view_dir);
+
+ if (1.0f + denom != 1.0f) {
+ lambda_inc[i] = plane_dist_inc / denom;
+ lambda[i] = (plane_dist - dot_v3v3(vec_start[i], view_dir)) / denom;
+ }
+ else {
+ lambda[i] = -1.0f;
+ lambda_inc[i] = 0.0f;
+ }
}
-#ifdef DEBUG_DRAW_TIME
- TIMEIT_START(draw);
-#endif
+ float intersections[6][3];
+ float dL[12];
+ int num_points = 0;
+ /* find intersections for each slice, process them in back to front order */
+ for (int i = 0; i < num_slices; i++) {
+ for (int e = 0; e < 12; e++) {
+ dL[e] = lambda[e] + i * lambda_inc[e];
+ }
- // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]);
- // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]);
+ if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[0], vec_start[0], vec_dir[0], dL[0]);
+ }
+ else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[0], vec_start[1], vec_dir[1], dL[1]);
+ }
+ else if ((dL[3] >= 0.0f) && (dL[3] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[0], vec_start[3], vec_dir[3], dL[3]);
+ }
+ else continue;
- glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
- glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
+ if ((dL[2] >= 0.0f) && (dL[2] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[1], vec_start[2], vec_dir[2], dL[2]);
+ }
+ else if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[1], vec_start[0], vec_dir[0], dL[0]);
+ }
+ else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[1], vec_start[1], vec_dir[1], dL[1]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[1], vec_start[3], vec_dir[3], dL[3]);
+ }
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
+ if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[2], vec_start[4], vec_dir[4], dL[4]);
+ }
+ else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[2], vec_start[5], vec_dir[5], dL[5]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[2], vec_start[7], vec_dir[7], dL[7]);
+ }
+
+ if ((dL[6] >= 0.0f) && (dL[6] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[3], vec_start[6], vec_dir[6], dL[6]);
+ }
+ else if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[3], vec_start[4], vec_dir[4], dL[4]);
+ }
+ else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[3], vec_start[5], vec_dir[5], dL[5]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[3], vec_start[7], vec_dir[7], dL[7]);
+ }
+
+ if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[4], vec_start[8], vec_dir[8], dL[8]);
+ }
+ else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[4], vec_start[9], vec_dir[9], dL[9]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[4], vec_start[11], vec_dir[11], dL[11]);
+ }
- /* find cube vertex that is closest to the viewer */
- for (i = 0; i < 8; i++) {
- float x = verts[i][0] - viewnormal[0] * size[0] * 0.5f;
- float y = verts[i][1] - viewnormal[1] * size[1] * 0.5f;
- float z = verts[i][2] - viewnormal[2] * size[2] * 0.5f;
-
- if ((x >= min[0]) && (x <= max[0]) &&
- (y >= min[1]) && (y <= max[1]) &&
- (z >= min[2]) && (z <= max[2]))
- {
- break;
+ if ((dL[10] >= 0.0f) && (dL[10] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[5], vec_start[10], vec_dir[10], dL[10]);
+ }
+ else if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[5], vec_start[8], vec_dir[8], dL[8]);
+ }
+ else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[5], vec_start[9], vec_dir[9], dL[9]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[5], vec_start[11], vec_dir[11], dL[11]);
+ }
+
+ for (int e = 0; e < 12; e++) {
+ copy_v3_v3(slicer->verts[num_points++], intersections[indices[e]]);
}
}
- if (i >= 8) {
- /* fallback, avoid using buffer over-run */
- i = 0;
+ return num_points;
+}
+
+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;
}
- // printf("i: %d\n", i);
- // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);
+ const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) != 0;
- smoke_program = GPU_shader_get_builtin_program(progtype);
- if (smoke_program) {
- GPU_program_bind(smoke_program);
+ GPUShader *shader = GPU_shader_get_builtin_shader(
+ (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE);
- /* cell spacing */
- GPU_program_parameter_4f(smoke_program, 0, sds->dx, sds->dx, sds->dx, 1.0);
- /* custom parameter for smoke style (higher = thicker) */
- if (sds->active_fields & SM_ACTIVE_COLORS)
- GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0);
- else
- GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
+ if (!shader) {
+ fprintf(stderr, "Unable to create GLSL smoke shader.\n");
+ return;
}
- else
- printf("Your gfx card does not support 3D View smoke drawing.\n");
+
+ 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 cellspace_location = GPU_shader_get_uniform(shader, "cell_spacing");
+ 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);
- if (sds->tex_shadow)
- GPU_texture_bind(sds->tex_shadow, 1);
- else
- printf("No volume shadow\n");
+ 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 (sds->tex_flame) {
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);
}
- /* our slices are defined by the plane equation a*x + b*y +c*z + d = 0
- * (a,b,c), the plane normal, are given by viewdir
- * d is the parameter along the view direction. the first d is given by
- * inserting previously found vertex into the plane equation */
-
- /* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
- ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]);
- dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f;
- n = 0;
- good_index = i;
+ float active_color[4] = { 1.0, 1.0, 1.0, 10.0 };
+ if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
+ copy_v3_v3(active_color, sds->active_color);
- // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds);
+ GPU_shader_uniform_vector(shader, actcol_location, 4, 1, active_color);
+ GPU_shader_uniform_vector(shader, cellspace_location, 1, 1, &sds->dx);
+ 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);
- points = MEM_callocN(sizeof(*points) * 12, "smoke_points_preview");
+ /* setup slicing information */
- while (1) {
- float p0[3], tmp_point[3];
+ const int max_slices = 256;
+ const int max_points = max_slices * 12;
- if (dd * (float)n > ds)
- break;
+ 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");
- madd_v3_v3v3fl(tmp_point, verts[good_index], viewnormal, -dd * ((ds / dd) - (float)n));
- d = dot_v3v3(tmp_point, viewnormal);
+ const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal);
- // printf("my d: %f\n", d);
+ /* setup buffer and draw */
- /* intersect_edges returns the intersection points of all cube edges with
- * the given plane that lie within the cube */
- numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges);
+ int gl_depth = 0, gl_blend = 0;
+ glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
+ glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
- // printf("points: %d\n", numpoints);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- if (numpoints > 2) {
- copy_v3_v3(p0, points[0]);
+ 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);
- /* sort points to get a convex polygon */
- for (i = 1; i < numpoints - 1; i++) {
- for (j = i + 1; j < numpoints; j++) {
- if (!convex(p0, viewnormal, points[j], points[i])) {
- swap_v3_v3(points[i], points[j]);
- }
- }
- }
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, NULL);
- /* render fire slice */
- if (use_fire) {
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
-
- GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0);
- glBegin(GL_POLYGON);
- for (i = 0; i < numpoints; i++) {
- glTexCoord3d((points[i][0] - min[0]) * invsize[0],
- (points[i][1] - min[1]) * invsize[1],
- (points[i][2] - min[2]) * invsize[2]);
- glVertex3f(points[i][0] * ob_sizei[0],
- points[i][1] * ob_sizei[1],
- points[i][2] * ob_sizei[2]);
- }
- glEnd();
- }
+ glDrawArrays(GL_TRIANGLES, 0, num_points);
- /* render smoke slice */
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0);
- glBegin(GL_POLYGON);
- for (i = 0; i < numpoints; i++) {
- glTexCoord3d((points[i][0] - min[0]) * invsize[0],
- (points[i][1] - min[1]) * invsize[1],
- (points[i][2] - min[2]) * invsize[2]);
- glVertex3f(points[i][0] * ob_sizei[0],
- points[i][1] * ob_sizei[1],
- points[i][2] * ob_sizei[2]);
- }
- glEnd();
- }
- n++;
- }
+ glDisableClientState(GL_VERTEX_ARRAY);
#ifdef DEBUG_DRAW_TIME
printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
TIMEIT_END(draw);
#endif
- GPU_texture_unbind(sds->tex);
+ /* cleanup */
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glDeleteBuffers(1, &vertex_buffer);
- if (sds->tex_shadow)
- GPU_texture_unbind(sds->tex_shadow);
+ GPU_texture_unbind(sds->tex);
+ GPU_texture_unbind(sds->tex_shadow);
if (sds->tex_flame) {
GPU_texture_unbind(sds->tex_flame);
@@ -353,10 +415,9 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
GPU_texture_free(tex_spec);
}
- if (smoke_program)
- GPU_program_unbind(smoke_program);
+ MEM_freeN(slicer.verts);
- MEM_freeN(points);
+ GPU_shader_unbind();
if (!gl_blend) {
glDisable(GL_BLEND);
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 6d3a5d37d66..3b228c18f5e 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -60,9 +60,6 @@ set(SRC
intern/gpu_shader.c
intern/gpu_texture.c
- shaders/gpu_program_smoke_frag.glsl
- shaders/gpu_program_smoke_color_frag.glsl
-
shaders/gpu_shader_fx_lib.glsl
shaders/gpu_shader_fx_ssao_frag.glsl
shaders/gpu_shader_fx_dof_frag.glsl
@@ -80,6 +77,8 @@ 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_smoke_frag.glsl
+ shaders/gpu_shader_smoke_vert.glsl
GPU_basic_shader.h
GPU_buffers.h
@@ -99,8 +98,8 @@ set(SRC
)
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
-data_to_c_simple(shaders/gpu_program_smoke_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_program_smoke_color_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)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC)
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 6464fb7454a..468cc2f0f6e 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -37,21 +37,8 @@ extern "C" {
#endif
typedef struct GPUShader GPUShader;
-typedef struct GPUProgram GPUProgram;
struct GPUTexture;
-/* Builtin/Non-generated shaders */
-typedef enum GPUProgramType {
- GPU_PROGRAM_TYPE_FRAGMENT = 0
-} GPUProgramType;
-
-/* TODO: remove ARB program support (recode smoke shader in GLSL) */
-GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code);
-void GPU_program_free(GPUProgram *program);
-void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w);
-void GPU_program_bind(GPUProgram *);
-void GPU_program_unbind(GPUProgram *);
-
/* GPU Shader
* - only for fragment shaders now
* - must call texture bind before setting a texture as uniform! */
@@ -97,15 +84,11 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name);
typedef enum GPUBuiltinShader {
GPU_SHADER_VSM_STORE = 0,
GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
+ GPU_SHADER_SMOKE = 2,
+ GPU_SHADER_SMOKE_FIRE = 3,
} GPUBuiltinShader;
-typedef enum GPUBuiltinProgram {
- GPU_PROGRAM_SMOKE = 0,
- GPU_PROGRAM_SMOKE_COLORED = 1,
-} GPUBuiltinProgram;
-
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
-GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program);
GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp);
void GPU_shader_free_builtin_shaders(void);
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index be1cc1c004f..5bef3df928c 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -46,8 +46,8 @@
#define MAX_EXT_DEFINE_LENGTH 1024
/* Non-generated shaders */
-extern char datatoc_gpu_program_smoke_frag_glsl[];
-extern char datatoc_gpu_program_smoke_color_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[];
extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
@@ -66,8 +66,8 @@ static struct GPUShadersGlobal {
struct {
GPUShader *vsm_store;
GPUShader *sep_gaussian_blur;
- GPUProgram *smoke;
- GPUProgram *smoke_colored;
+ GPUShader *smoke;
+ GPUShader *smoke_fire;
/* cache for shader fx. Those can exist in combinations so store them here */
GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
} shaders;
@@ -86,11 +86,6 @@ struct GPUShader {
int uniforms; /* required uniforms */
};
-struct GPUProgram {
- GPUProgramType type;
- GLuint prog;
-};
-
static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
{
int i;
@@ -230,70 +225,6 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], bool us
return;
}
-void GPU_program_bind(GPUProgram *program)
-{
- glEnable(program->type);
- glBindProgramARB(program->type, program->prog);
-}
-
-void GPU_program_unbind(GPUProgram *program)
-{
- glDisable(program->type);
- glBindProgramARB(program->type, 0);
-}
-
-
-GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code)
-{
- /* TODO(merwin): remove ARB program support (recode smoke shader in GLSL) */
-
- GPUProgram *program;
- GLint error_pos, is_native;
-
- if (!(GLEW_ARB_fragment_program && type == GPU_PROGRAM_TYPE_FRAGMENT))
- return NULL;
-
- program = MEM_callocN(sizeof(GPUProgram), "GPUProgram");
-
- switch (type) {
- case GPU_PROGRAM_TYPE_FRAGMENT:
- program->type = GL_FRAGMENT_PROGRAM_ARB;
- break;
- }
-
- /* create the object and set its code string */
- glGenProgramsARB(1, &program->prog);
- glBindProgramARB(program->type, program->prog);
-
- glProgramStringARB(program->type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), code);
-
- glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
- glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &is_native);
- if ((error_pos == -1) && (is_native == 1)) {
- return program;
- }
- else {
- /* glGetError is set before that, clear it */
- while (glGetError() != GL_NO_ERROR)
- ;
- shader_print_errors("compile", (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB), &code, 1);
- MEM_freeN(program);
- }
-
- return NULL;
-}
-
-void GPU_program_free(GPUProgram *program)
-{
- glDeleteProgramsARB(1, &program->prog);
- MEM_freeN(program);
-}
-
-void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w)
-{
- glProgramLocalParameter4fARB(program->type, location, x, y, z, w);
-}
-
GPUShader *GPU_shader_create(const char *vertexcode,
const char *fragcode,
const char *geocode,
@@ -646,37 +577,24 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.sep_gaussian_blur;
break;
- }
-
- if (retval == NULL)
- printf("Unable to create a GPUShader for builtin shader: %u\n", shader);
-
- return retval;
-}
-
-GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program)
-{
- GPUProgram *retval = NULL;
-
- switch (program) {
- case GPU_PROGRAM_SMOKE:
- if (!GG.shaders.smoke) {
- GG.shaders.smoke = GPU_program_shader_create(
- GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_frag_glsl);
- }
+ case GPU_SHADER_SMOKE:
+ if (!GG.shaders.smoke)
+ GG.shaders.smoke = GPU_shader_create(
+ datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
+ NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.smoke;
break;
- case GPU_PROGRAM_SMOKE_COLORED:
- if (!GG.shaders.smoke_colored) {
- GG.shaders.smoke_colored = GPU_program_shader_create(
- GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_color_frag_glsl);
- }
- retval = GG.shaders.smoke_colored;
+ 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);
+ retval = GG.shaders.smoke_fire;
break;
}
if (retval == NULL)
- printf("Unable to create a GPUProgram for builtin program: %u\n", program);
+ printf("Unable to create a GPUShader for builtin shader: %u\n", shader);
return retval;
}
@@ -773,13 +691,13 @@ void GPU_shader_free_builtin_shaders(void)
}
if (GG.shaders.smoke) {
- GPU_program_free(GG.shaders.smoke);
+ GPU_shader_free(GG.shaders.smoke);
GG.shaders.smoke = NULL;
}
- if (GG.shaders.smoke_colored) {
- GPU_program_free(GG.shaders.smoke_colored);
- GG.shaders.smoke_colored = NULL;
+ if (GG.shaders.smoke_fire) {
+ GPU_shader_free(GG.shaders.smoke_fire);
+ GG.shaders.smoke_fire = NULL;
}
for (i = 0; i < 2 * MAX_FX_SHADERS; i++) {
diff --git a/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl
deleted file mode 100644
index a94c823f408..00000000000
--- a/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-!!ARBfp1.0
-PARAM dx = program.local[0];
-PARAM darkness = program.local[1];
-PARAM render = program.local[2];
-PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};
-TEMP temp, shadow, flame, spec, value;
-TEX temp, fragment.texcoord[0], texture[0], 3D;
-TEX shadow, fragment.texcoord[0], texture[1], 3D;
-TEX flame, fragment.texcoord[0], texture[2], 3D;
-TEX spec, flame.r, texture[3], 1D;
-# unpremultiply volume texture
-RCP value.r, temp.a;
-MUL temp.r, temp.r, value.r;
-MUL temp.g, temp.g, value.r;
-MUL temp.b, temp.b, value.r;
-# calculate shading factor from density
-MUL value.r, temp.a, darkness.a;
-MUL value.r, value.r, dx.r;
-MUL value.r, value.r, f.r;
-EX2 value.r, -value.r;
-# alpha
-SUB temp.a, 1.0, value.r;
-# shade colors
-MUL temp.r, temp.r, shadow.r;
-MUL temp.g, temp.g, shadow.r;
-MUL temp.b, temp.b, shadow.r;
-MUL temp.r, temp.r, value.r;
-MUL temp.g, temp.g, value.r;
-MUL temp.b, temp.b, value.r;
-# for now this just replace smoke shading if rendering fire
-CMP result.color, render.r, temp, spec;
-END
diff --git a/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl
deleted file mode 100644
index 04b171d24bd..00000000000
--- a/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl
+++ /dev/null
@@ -1,27 +0,0 @@
-!!ARBfp1.0
-PARAM dx = program.local[0];
-PARAM darkness = program.local[1];
-PARAM render = program.local[2];
-PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};
-TEMP temp, shadow, flame, spec, value;
-TEX temp, fragment.texcoord[0], texture[0], 3D;
-TEX shadow, fragment.texcoord[0], texture[1], 3D;
-TEX flame, fragment.texcoord[0], texture[2], 3D;
-TEX spec, flame.r, texture[3], 1D;
-# calculate shading factor from density
-MUL value.r, temp.a, darkness.a;
-MUL value.r, value.r, dx.r;
-MUL value.r, value.r, f.r;
-EX2 temp, -value.r;
-# alpha
-SUB temp.a, 1.0, temp.r;
-# shade colors
-MUL temp.r, temp.r, shadow.r;
-MUL temp.g, temp.g, shadow.r;
-MUL temp.b, temp.b, shadow.r;
-MUL temp.r, temp.r, darkness.r;
-MUL temp.g, temp.g, darkness.g;
-MUL temp.b, temp.b, darkness.b;
-# for now this just replace smoke shading if rendering fire
-CMP result.color, render.r, temp, spec;
-END
diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
new file mode 100644
index 00000000000..c467925725d
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
@@ -0,0 +1,48 @@
+
+varying vec3 coords;
+
+uniform vec4 active_color;
+uniform float cell_spacing;
+
+uniform sampler3D soot_texture;
+uniform sampler3D shadow_texture;
+
+#ifdef USE_FIRE
+uniform sampler3D flame_texture;
+uniform sampler1D spectrum_texture;
+#endif
+
+void main()
+{
+ vec4 soot = texture3D(soot_texture, coords);
+
+ /* unpremultiply volume texture */
+ float value = 1.0f / soot.a;
+ soot.xyz *= vec3(value);
+
+ /* calculate shading factor from soot */
+ value = soot.a * active_color.a;
+ value *= cell_spacing;
+ value *= 1.442695041;
+ soot = vec4(pow(2.0, -value));
+
+ /* alpha */
+ soot.a = 1.0 - soot.r;
+
+ /* shade colors */
+ vec3 shadow = texture3D(shadow_texture, coords).rrr;
+ soot.xyz *= shadow;
+ soot.xyz *= active_color.xyz;
+
+ /* premultiply alpha */
+ vec4 color = vec4(soot.a * soot.rgb, soot.a);
+
+#ifdef USE_FIRE
+ /* blend in fire */
+ float flame = texture3D(flame_texture, coords).r;
+ vec4 spec = texture1D(spectrum_texture, flame);
+ color = vec4(color.rgb + (1 - color.a) * spec.a * spec.rgb, color.a);
+#endif
+
+ gl_FragColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl
new file mode 100644
index 00000000000..daabf9b97a3
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl
@@ -0,0 +1,12 @@
+
+varying vec3 coords;
+
+uniform vec3 min;
+uniform vec3 invsize;
+uniform vec3 ob_sizei;
+
+void main()
+{
+ gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz * ob_sizei, 1.0);
+ coords = (gl_Vertex.xyz - min) * invsize;
+}