diff options
-rw-r--r-- | source/blender/editors/space_view3d/drawvolume.c | 447 | ||||
-rw-r--r-- | source/blender/gpu/CMakeLists.txt | 9 | ||||
-rw-r--r-- | source/blender/gpu/GPU_shader.h | 21 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_shader.c | 122 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl | 32 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_program_smoke_frag.glsl | 27 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl | 48 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl | 12 |
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; +} |