Viewport smoke: add support to render the volume using a color ramp.
authorKévin Dietrich <kevin.dietrich@mailoo.org>
Sun, 30 Oct 2016 11:29:05 +0000 (12:29 +0100)
committerKévin Dietrich <kevin.dietrich@mailoo.org>
Sun, 30 Oct 2016 11:29:05 +0000 (12:29 +0100)
This is yet another debug option that allows to render an arbitrary
simulation field by using a color ramp to inspect its voxel values.
Note that when using this, fire rendering is turned off.

Reviewers: plasmasolutions, gottfried

Differential Revision: https://developer.blender.org/D1733

12 files changed:
release/scripts/startup/bl_ui/properties_physics_smoke.py
source/blender/blenkernel/intern/smoke.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/drawvolume.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/gpu/GPU_shader.h
source/blender/gpu/intern/gpu_shader.c
source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
source/blender/makesdna/DNA_smoke_types.h
source/blender/makesrna/intern/rna_smoke.c

index df03f23a4b5f10ca8893c36c12f9e94b1527aa7f..0374d0321419a35005ca96929eb2c1a77704d48f 100644 (file)
@@ -397,6 +397,14 @@ class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel):
         col.prop(domain, "vector_draw_type")
         col.prop(domain, "vector_scale")
 
+        layout.separator()
+        layout.label(text="Color Mapping:")
+        layout.prop(domain, "use_color_ramp")
+        col = layout.column();
+        col.enabled = domain.use_color_ramp
+        col.prop(domain, "coba_field")
+        col.template_color_ramp(domain, "color_ramp", expand=True)
+
 
 if __name__ == "__main__":  # only for live edit.
     bpy.utils.register_module(__name__)
index 05540f515880c81bb3b6ca9010cf944222d90c07..e8970d416e94f641bf0254c690e04ae921ace225 100644 (file)
@@ -360,6 +360,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
                BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
                smd->domain->point_cache[0] = NULL;
 
+               if (smd->domain->coba) {
+                       MEM_freeN(smd->domain->coba);
+               }
+
                MEM_freeN(smd->domain);
                smd->domain = NULL;
        }
@@ -544,6 +548,9 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
                        smd->domain->slice_depth = 0.5f;
                        smd->domain->slice_axis = 0;
                        smd->domain->vector_scale = 1.0f;
+
+                       smd->domain->coba = NULL;
+                       smd->domain->coba_field = FLUID_FIELD_DENSITY;
                }
                else if (smd->type & MOD_SMOKE_TYPE_FLOW)
                {
@@ -646,6 +653,10 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
                tsmd->domain->draw_velocity = smd->domain->draw_velocity;
                tsmd->domain->vector_draw_type = smd->domain->vector_draw_type;
                tsmd->domain->vector_scale = smd->domain->vector_scale;
+
+               if (smd->domain->coba) {
+                       tsmd->domain->coba = MEM_dupallocN(smd->domain->coba);
+               }
        }
        else if (tsmd->flow) {
                tsmd->flow->psys = smd->flow->psys;
index 41b275751d15d82f5f3a8cb214f91bb411cdf8a6..98c8a260993ec1c19a7b8ca300e1e390cb6f672d 100644 (file)
@@ -5091,6 +5091,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
                                smd->domain->tex = NULL;
                                smd->domain->tex_shadow = NULL;
                                smd->domain->tex_wt = NULL;
+                               smd->domain->coba = newdataadr(fd, smd->domain->coba);
                                
                                smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights);
                                if (!smd->domain->effector_weights)
index 6678189872ce05684c28b70108750954d890d951..d104fc85eb7a4e40555d04347bdef4100ee7983a 100644 (file)
@@ -1728,6 +1728,10 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
                                        smd->domain->point_cache[1]->step = 1;
 
                                        write_pointcaches(wd, &(smd->domain->ptcaches[1]));
+
+                                       if (smd->domain->coba) {
+                                               writestruct(wd, DATA, ColorBand, 1, smd->domain->coba);
+                                       }
                                }
 
                                writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
index ea40d4eb5e11137d1351806e26241ed4eeaa0f53..dd282c427f678c30853ae5bf6bb280621f084f4a 100644 (file)
@@ -7915,10 +7915,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
                        if (!render_override && sds->draw_velocity) {
                                draw_smoke_velocity(sds, viewnormal);
                        }
-
-#ifdef SMOKE_DEBUG_HEAT
-                       draw_smoke_heat(smd->domain, ob);
-#endif
                }
        }
 
index b0e21601b9c6d1b7c39a131cff7e74e181364dee..27ecbf83db54c42bc1964d0300e37c26d4fa6910 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -41,6 +41,7 @@
 #include "BLI_math.h"
 
 #include "BKE_DerivedMesh.h"
+#include "BKE_texture.h"
 #include "BKE_particle.h"
 
 #include "smoke_API.h"
@@ -62,28 +63,33 @@ struct GPUTexture;
 #  include "PIL_time_utildefines.h"
 #endif
 
-static GPUTexture *create_flame_spectrum_texture(void)
+/* *************************** Transfer functions *************************** */
+
+enum {
+       TFUNC_FLAME_SPECTRUM = 0,
+       TFUNC_COLOR_RAMP     = 1,
+};
+
+#define TFUNC_WIDTH 256
+
+static void create_flame_spectrum_texture(float *data)
 {
-#define SPEC_WIDTH 256
 #define FIRE_THRESH 7
 #define MAX_FIRE_ALPHA 0.06f
 #define FULL_ON_FIRE 100
 
-       GPUTexture *tex;
-       int i, j, k;
-       float *spec_data = MEM_mallocN(SPEC_WIDTH * 4 * sizeof(float), "spec_data");
-       float *spec_pixels = MEM_mallocN(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
+       float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
 
-       blackbody_temperature_to_rgb_table(spec_data, SPEC_WIDTH, 1500, 3000);
+       blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
 
-       for (i = 0; i < 16; i++) {
-               for (j = 0; j < 16; j++) {
-                       for (k = 0; k < SPEC_WIDTH; k++) {
-                               int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4;
+       for (int i = 0; i < 16; i++) {
+               for (int j = 0; j < 16; j++) {
+                       for (int k = 0; k < TFUNC_WIDTH; k++) {
+                               int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4;
                                if (k >= FIRE_THRESH) {
-                                       spec_pixels[index] = (spec_data[k * 4]);
-                                       spec_pixels[index + 1] = (spec_data[k * 4 + 1]);
-                                       spec_pixels[index + 2] = (spec_data[k * 4 + 2]);
+                                       spec_pixels[index] = (data[k * 4]);
+                                       spec_pixels[index + 1] = (data[k * 4 + 1]);
+                                       spec_pixels[index + 2] = (data[k * 4 + 2]);
                                        spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
                                                (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
                                }
@@ -94,19 +100,69 @@ static GPUTexture *create_flame_spectrum_texture(void)
                }
        }
 
-       tex = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);
+       memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
 
-       MEM_freeN(spec_data);
        MEM_freeN(spec_pixels);
 
-#undef SPEC_WIDTH
 #undef FIRE_THRESH
 #undef MAX_FIRE_ALPHA
 #undef FULL_ON_FIRE
+}
+
+static void create_color_ramp(const ColorBand *coba, float *data)
+{
+       for (int i = 0; i < TFUNC_WIDTH; i++) {
+               do_colorband(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
+       }
+}
+
+static GPUTexture *create_transfer_function(int type, const ColorBand *coba)
+{
+       float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
+
+       switch (type) {
+               case TFUNC_FLAME_SPECTRUM:
+                       create_flame_spectrum_texture(data);
+                       break;
+               case TFUNC_COLOR_RAMP:
+                       create_color_ramp(coba, data);
+                       break;
+       }
+
+       GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, data, NULL);
+
+       MEM_freeN(data);
 
        return tex;
 }
 
+static GPUTexture *create_field_texture(SmokeDomainSettings *sds)
+{
+       float *field = NULL;
+
+       switch (sds->coba_field) {
+#ifdef WITH_SMOKE
+               case FLUID_FIELD_DENSITY:    field = smoke_get_density(sds->fluid); break;
+               case FLUID_FIELD_HEAT:       field = smoke_get_heat(sds->fluid); break;
+               case FLUID_FIELD_FUEL:       field = smoke_get_fuel(sds->fluid); break;
+               case FLUID_FIELD_REACT:      field = smoke_get_react(sds->fluid); break;
+               case FLUID_FIELD_FLAME:      field = smoke_get_flame(sds->fluid); break;
+               case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break;
+               case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break;
+               case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break;
+               case FLUID_FIELD_COLOR_R:    field = smoke_get_color_r(sds->fluid); break;
+               case FLUID_FIELD_COLOR_G:    field = smoke_get_color_g(sds->fluid); break;
+               case FLUID_FIELD_COLOR_B:    field = smoke_get_color_b(sds->fluid); break;
+               case FLUID_FIELD_FORCE_X:    field = smoke_get_force_x(sds->fluid); break;
+               case FLUID_FIELD_FORCE_Y:    field = smoke_get_force_y(sds->fluid); break;
+               case FLUID_FIELD_FORCE_Z:    field = smoke_get_force_z(sds->fluid); break;
+#endif
+               default: return NULL;
+       }
+
+       return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field);
+}
+
 typedef struct VolumeSlicer {
        float size[3];
        float min[3];
@@ -347,6 +403,7 @@ static int create_view_aligned_slices(VolumeSlicer *slicer,
 }
 
 static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec,
+                        GPUTexture *tex_tfunc, GPUTexture *tex_coba,
                         bool use_fire, const float min[3],
                         const float ob_sizei[3], const float invsize[3])
 {
@@ -359,6 +416,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture
        int densityscale_location;
        int spec_location, flame_location;
        int shadow_location, actcol_location;
+       int tfunc_location = 0;
+       int coba_location = 0;
 
        if (use_fire) {
                spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
@@ -370,6 +429,11 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture
                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");
+
+               if (sds->use_coba) {
+                       tfunc_location = GPU_shader_get_uniform(shader, "transfer_texture");
+                       coba_location = GPU_shader_get_uniform(shader, "color_band_texture");
+               }
        }
 
        GPU_shader_bind(shader);
@@ -397,6 +461,14 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture
                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);
+
+               if (sds->use_coba) {
+                       GPU_texture_bind(tex_tfunc, 4);
+                       GPU_shader_uniform_texture(shader, tfunc_location, tex_tfunc);
+
+                       GPU_texture_bind(tex_coba, 5);
+                       GPU_shader_uniform_texture(shader, coba_location, tex_coba);
+               }
        }
 
        GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
@@ -404,7 +476,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture
        GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
 }
 
-static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool use_fire)
+static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec,
+                          GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire)
 {
        GPU_shader_unbind();
 
@@ -417,20 +490,30 @@ static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool u
        }
        else {
                GPU_texture_unbind(sds->tex_shadow);
+
+               if (sds->use_coba) {
+                       GPU_texture_unbind(tex_tfunc);
+                       GPU_texture_free(tex_tfunc);
+
+                       GPU_texture_unbind(tex_coba);
+                       GPU_texture_free(tex_coba);
+               }
        }
 }
 
 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;
+       GPUTexture *tex_spec = (do_fire) ? create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL) : NULL;
+       GPUTexture *tex_tfunc = (sds->use_coba) ? create_transfer_function(TFUNC_COLOR_RAMP, sds->coba) : NULL;
+       GPUTexture *tex_coba = (sds->use_coba) ? create_field_texture(sds) : 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);
+       bind_shader(sds, shader, tex_spec, tex_tfunc, tex_coba, do_fire, slicer->min, ob_sizei, invsize);
 
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, 0, NULL);
@@ -439,7 +522,7 @@ static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const Volum
 
        glDisableClientState(GL_VERTEX_ARRAY);
 
-       unbind_shader(sds, tex_spec, do_fire);
+       unbind_shader(sds, tex_spec, tex_tfunc, tex_coba, do_fire);
 
        /* cleanup */
 
@@ -459,7 +542,16 @@ 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(GPU_SHADER_SMOKE);
+       GPUBuiltinShader builtin_shader;
+
+       if (sds->use_coba) {
+               builtin_shader = GPU_SHADER_SMOKE_COBA;
+       }
+       else {
+               builtin_shader = GPU_SHADER_SMOKE;
+       }
+
+       GPUShader *shader = GPU_shader_get_builtin_shader(builtin_shader);
 
        if (!shader) {
                fprintf(stderr, "Unable to create GLSL smoke shader.\n");
@@ -549,7 +641,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
        draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false);
 
        /* Draw fire separately (T47639). */
-       if (use_fire) {
+       if (use_fire && !sds->use_coba) {
                glBlendFunc(GL_ONE, GL_ONE);
                draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true);
        }
@@ -759,50 +851,3 @@ void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3])
        UNUSED_VARS(domain, viewnormal);
 #endif
 }
-
-#ifdef SMOKE_DEBUG_HEAT
-void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob)
-{
-       float x, y, z;
-       float x0, y0, z0;
-       int *base_res = domain->base_res;
-       int *res = domain->res;
-       int *res_min = domain->res_min;
-       int *res_max = domain->res_max;
-       float *heat = smoke_get_heat(domain->fluid);
-
-       float min[3];
-       float *cell_size = domain->cell_size;
-       float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f;
-       float vf = domain->scale / 16.f * 2.f; /* velocity factor */
-
-       /* set first position so that it doesn't jump when domain moves */
-       x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size);
-       y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size);
-       z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size);
-       if (x0 < res_min[0]) x0 += step_size;
-       if (y0 < res_min[1]) y0 += step_size;
-       if (z0 < res_min[2]) z0 += step_size;
-       add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
-
-       for (x = floor(x0); x < res_max[0]; x += step_size)
-               for (y = floor(y0); y < res_max[1]; y += step_size)
-                       for (z = floor(z0); z < res_max[2]; z += step_size) {
-                               int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1];
-
-                               float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]};
-
-                               /* draw heat as different sized points */
-                               if (heat[index] >= 0.01f) {
-                                       float col_gb = 1.0f - heat[index];
-                                       CLAMP(col_gb, 0.0f, 1.0f);
-                                       glColor3f(1.0f, col_gb, col_gb);
-                                       glPointSize(24.0f * heat[index]);
-
-                                       glBegin(GL_POINTS);
-                                       glVertex3f(pos[0], pos[1], pos[2]);
-                                       glEnd();
-                               }
-                       }
-}
-#endif
index 0e2cb95dd898684556048e6f2bdc7f808254a2ca..b11f42bcfeff8cd3c3cec7586075d107741822b1 100644 (file)
@@ -296,14 +296,8 @@ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob,
                        const float min[3], const float max[3],
                        const float viewnormal[3]);
 
-//#define SMOKE_DEBUG_HEAT
-
 void draw_smoke_velocity(struct SmokeDomainSettings *domain, float viewnormal[3]);
 
-#ifdef SMOKE_DEBUG_HEAT
-void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob);
-#endif
-
 /* workaround for trivial but noticeable camera bug caused by imprecision
  * between view border calculation in 2D/3D space, workaround for bug [#28037].
  * without this define we get the old behavior which is to try and align them
index 762329ee077e21cafc587800a172ac1cc0f547fe..5b94db6e12073953ce47e4d3f97024b467dd3ec8 100644 (file)
@@ -89,6 +89,7 @@ typedef enum GPUBuiltinShader {
        GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
        GPU_SHADER_SMOKE             = 2,
        GPU_SHADER_SMOKE_FIRE        = 3,
+       GPU_SHADER_SMOKE_COBA        = 4,
 } GPUBuiltinShader;
 
 GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
index 5cfb323bc4bc2e12424b87f4dc4b9a2681752838..14f2764b0095c9ac2d42587c37a59f455e72eec2 100644 (file)
@@ -68,6 +68,7 @@ static struct GPUShadersGlobal {
                GPUShader *sep_gaussian_blur;
                GPUShader *smoke;
                GPUShader *smoke_fire;
+               GPUShader *smoke_coba;
                /* cache for shader fx. Those can exist in combinations so store them here */
                GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
        } shaders;
@@ -623,6 +624,13 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
                                        NULL, NULL, NULL, 0, 0, 0);
                        retval = GG.shaders.smoke_fire;
                        break;
+               case GPU_SHADER_SMOKE_COBA:
+                       if (!GG.shaders.smoke_coba)
+                               GG.shaders.smoke_coba = GPU_shader_create(
+                                       datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
+                                       NULL, NULL, "#define USE_COBA;\n", 0, 0, 0);
+                       retval = GG.shaders.smoke_coba;
+                       break;
        }
 
        if (retval == NULL)
@@ -734,6 +742,11 @@ void GPU_shader_free_builtin_shaders(void)
                GG.shaders.smoke_fire = NULL;
        }
 
+       if (GG.shaders.smoke_coba) {
+               GPU_shader_free(GG.shaders.smoke_coba);
+               GG.shaders.smoke_coba = NULL;
+       }
+
        for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) {
                if (GG.shaders.fx_shaders[i]) {
                        GPU_shader_free(GG.shaders.fx_shaders[i]);
index fd790009e024c9675295065593eeb594f818a601..6ded453225efe726db388385d1b1117aed237227 100644 (file)
@@ -8,10 +8,17 @@ uniform float density_scale;
 uniform sampler3D soot_texture;
 uniform sampler3D shadow_texture;
 
+#ifdef USE_COBA
+uniform sampler1D transfer_texture;
+uniform sampler3D color_band_texture;
+#endif
+
 void main()
 {
        /* compute color and density from volume texture */
        vec4 soot = texture3D(soot_texture, coords);
+
+#ifndef USE_COBA
        vec3 soot_color;
        if (soot.a != 0) {
                soot_color = active_color * soot.rgb / soot.a;
@@ -31,6 +38,11 @@ void main()
 
        /* premultiply alpha */
        vec4 color = vec4(soot_alpha * soot_color, soot_alpha);
+#else
+       float color_band = texture3D(color_band_texture, coords).r;
+       vec4 transfer_function = texture1D(transfer_texture, color_band);
+       vec4 color = transfer_function * density_scale;
+#endif
 
        gl_FragColor = color;
 }
index ba7f73c2f638403b904eb30ffd7bb1349ced0b5b..c95e0a1f54a44c661b0bf1140febb10e26f94475 100644 (file)
@@ -77,6 +77,23 @@ enum {
        VECTOR_DRAW_STREAMLINE = 1,
 };
 
+enum {
+       FLUID_FIELD_DENSITY    = 0,
+       FLUID_FIELD_HEAT       = 1,
+       FLUID_FIELD_FUEL       = 2,
+       FLUID_FIELD_REACT      = 3,
+       FLUID_FIELD_FLAME      = 4,
+       FLUID_FIELD_VELOCITY_X = 5,
+       FLUID_FIELD_VELOCITY_Y = 6,
+       FLUID_FIELD_VELOCITY_Z = 7,
+       FLUID_FIELD_COLOR_R    = 8,
+       FLUID_FIELD_COLOR_G    = 9,
+       FLUID_FIELD_COLOR_B    = 10,
+       FLUID_FIELD_FORCE_X    = 11,
+       FLUID_FIELD_FORCE_Y    = 12,
+       FLUID_FIELD_FORCE_Z    = 13,
+};
+
 /* cache compression */
 #define SM_CACHE_LIGHT         0
 #define SM_CACHE_HEAVY         1
@@ -193,9 +210,13 @@ typedef struct SmokeDomainSettings {
        float slice_per_voxel;
        float slice_depth;
        float display_thickness;
+
+       struct ColorBand *coba;
        float vector_scale;
        char vector_draw_type;
-       char pad2[3];
+       char use_coba;
+       char coba_field;  /* simulation field used for the color mapping */
+       char pad2;
 } SmokeDomainSettings;
 
 
index b4ba306df3f8f63d91f54305421cda18335a7753..6db370fc1526cfcfeb23722625c73ae1062dec1f 100644 (file)
@@ -30,6 +30,7 @@
 #include <limits.h>
 
 #include "RNA_define.h"
+#include "RNA_enum_types.h"
 
 #include "rna_internal.h"
 
@@ -53,6 +54,7 @@
 #include "BKE_context.h"
 #include "BKE_depsgraph.h"
 #include "BKE_particle.h"
+#include "BKE_texture.h"
 
 #include "smoke_API.h"
 
@@ -383,6 +385,17 @@ static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value)
        rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name));
 }
 
+static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, int value)
+{
+       SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+
+       sds->use_coba = value;
+
+       if (value && sds->coba == NULL) {
+               sds->coba = add_colorband(false);
+       }
+}
+
 #else
 
 static void rna_def_smoke_domain_settings(BlenderRNA *brna)
@@ -805,6 +818,41 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
        RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
        RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors");
        RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+       /* --------- Color mapping. --------- */
+
+       prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0);
+       RNA_def_property_boolean_funcs(prop, NULL, "rna_Smoke_use_color_ramp_set");
+       RNA_def_property_ui_text(prop, "Use Color Ramp",
+                                "Render a simulation field while mapping its voxels values to the colors of a ramp");
+       RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+       static EnumPropertyItem coba_field_items[] = {
+           {FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"},
+           {FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"},
+           {FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"},
+               {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"},
+           {FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"},
+           {FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"},
+           {FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"},
+           {FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"},
+           {FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"},
+           {FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"},
+               {0, NULL, 0, NULL, NULL}
+       };
+
+       prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "coba_field");
+       RNA_def_property_enum_items(prop, coba_field_items);
+       RNA_def_property_ui_text(prop, "Field", "Simulation field to color map");
+       RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+       prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL);
+       RNA_def_property_pointer_sdna(prop, NULL, "coba");
+       RNA_def_property_struct_type(prop, "ColorRamp");
+       RNA_def_property_ui_text(prop, "Color Ramp", "");
+       RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
 }
 
 static void rna_def_smoke_flow_settings(BlenderRNA *brna)