diff options
author | Matt Ebb <matt@mke3.net> | 2009-09-30 02:01:32 +0400 |
---|---|---|
committer | Matt Ebb <matt@mke3.net> | 2009-09-30 02:01:32 +0400 |
commit | 71b3088596feb008e503be6430a30555aaffa586 (patch) | |
tree | 0c2e7fe3cb4cc46939cebd80f1027efd7eb3108e | |
parent | 98ee2a781dd20bb58f72ee5700a11b2dd5124d74 (diff) |
Rework of volume shading
After code review and experimentation, this commit makes some changes to the way that volumes are shaded. Previously, there were problems with the 'scattering' component, in that it wasn't physically correct - it didn't conserve energy and was just acting as a brightness multiplier. This has been changed to be more correct, so that as the light is scattered out of the volume, there is less remaining to penetrate through.
Since this behaviour is very similar to absorption but more useful, absorption has been removed and has been replaced by a 'transmission colour' - controlling the colour of light penetrating through the volume after it has been scattered/absorbed. As well as this, there's now 'reflection', a non-physically correct RGB multiplier for out-scattered light. This is handy for tweaking the overall colour of the volume, without having to worry about wavelength dependent absorption, and its effects on transmitted light. Now at least, even though there is the ability to tweak things non-physically, volume shading is physically based by default, and has a better combination of correctness and ease of use.
There's more detailed information and example images here:
http://wiki.blender.org/index.php/User:Broken/VolumeRendering
Also did some tweaks/optimisation:
* Removed shading step size (was a bit annoying, if it comes back, it will be in a different form)
* Removed phase function options, now just one asymmetry slider controls the range between back-scattering, isotropic scattering, and forward scattering. (note, more extreme values gives artifacts with light cache, will fix...)
* Disabled the extra 'bounce lights' from the preview render for volumes, speeds updates significantly
* Enabled voxeldata texture in preview render
* Fixed volume shadows (they were too dark, fixed by avoiding using the shadfac/AddAlphaLight stuff)
More revisions to come later...
18 files changed, 395 insertions, 283 deletions
diff --git a/release/scripts/ui/buttons_material.py b/release/scripts/ui/buttons_material.py index 448cb36e130..ee7193da301 100644 --- a/release/scripts/ui/buttons_material.py +++ b/release/scripts/ui/buttons_material.py @@ -609,6 +609,23 @@ class VolumeButtonsPanel(bpy.types.Panel): mat = context.material engine = context.scene.render_data.engine return mat and (mat.type == 'VOLUME') and (engine in self.COMPAT_ENGINES) + +class MATERIAL_PT_volume_density(VolumeButtonsPanel): + __label__ = "Density" + __default_closed__ = False + COMPAT_ENGINES = set(['BLENDER_RENDER']) + + def draw(self, context): + layout = self.layout + + mat = context.material + vol = context.material.volume + + split = layout.split() + row = split.row() + row.itemR(vol, "density") + row.itemR(vol, "density_scale") + class MATERIAL_PT_volume_shading(VolumeButtonsPanel): __label__ = "Shading" @@ -620,22 +637,23 @@ class MATERIAL_PT_volume_shading(VolumeButtonsPanel): vol = context.material.volume - row = layout.row() - row.itemR(vol, "density") - row.itemR(vol, "scattering") - split = layout.split() col = split.column() - col.itemR(vol, "absorption") - col.itemR(vol, "absorption_color", text="") - + col.itemR(vol, "scattering") + col.itemR(vol, "asymmetry") + col.itemR(vol, "transmission_color") + col = split.column() - col.itemR(vol, "emission") - col.itemR(vol, "emission_color", text="") + sub = col.column(align=True) + sub.itemR(vol, "emission") + sub.itemR(vol, "emission_color", text="") + sub = col.column(align=True) + sub.itemR(vol, "reflection") + sub.itemR(vol, "reflection_color", text="") -class MATERIAL_PT_volume_scattering(VolumeButtonsPanel): - __label__ = "Scattering" +class MATERIAL_PT_volume_lighting(VolumeButtonsPanel): + __label__ = "Lighting" __default_closed__ = False COMPAT_ENGINES = set(['BLENDER_RENDER']) @@ -648,24 +666,26 @@ class MATERIAL_PT_volume_scattering(VolumeButtonsPanel): col = split.column() col.itemR(vol, "scattering_mode", text="") + + col = split.column() + if vol.scattering_mode == 'SINGLE_SCATTERING': col.itemR(vol, "light_cache") sub = col.column() sub.active = vol.light_cache sub.itemR(vol, "cache_resolution") elif vol.scattering_mode in ('MULTIPLE_SCATTERING', 'SINGLE_PLUS_MULTIPLE_SCATTERING'): + sub = col.column() + sub.enabled = True + sub.active = False + sub.itemR(vol, "light_cache") col.itemR(vol, "cache_resolution") sub = col.column(align=True) sub.itemR(vol, "ms_diffusion") sub.itemR(vol, "ms_spread") sub.itemR(vol, "ms_intensity") - - col = split.column() - # col.itemL(text="Anisotropic Scattering:") - col.itemR(vol, "phase_function", text="") - if vol.phase_function in ('SCHLICK', 'HENYEY-GREENSTEIN'): - col.itemR(vol, "asymmetry") + class MATERIAL_PT_volume_transp(VolumeButtonsPanel): __label__= "Transparency" @@ -693,16 +713,15 @@ class MATERIAL_PT_volume_integration(VolumeButtonsPanel): col = split.column() col.itemL(text="Step Calculation:") col.itemR(vol, "step_calculation", text="") - sub = col.column(align=True) - sub.itemR(vol, "step_size") - sub.itemR(vol, "shading_step_size") + col = col.column(align=True) + col.itemR(vol, "step_size") col = split.column() col.itemL() col.itemR(vol, "depth_cutoff") - col.itemR(vol, "density_scale") +bpy.types.register(MATERIAL_PT_volume_density) bpy.types.register(MATERIAL_PT_volume_shading) -bpy.types.register(MATERIAL_PT_volume_scattering) +bpy.types.register(MATERIAL_PT_volume_lighting) bpy.types.register(MATERIAL_PT_volume_transp) bpy.types.register(MATERIAL_PT_volume_integration) diff --git a/release/scripts/ui/buttons_texture.py b/release/scripts/ui/buttons_texture.py index c95fa266aaa..9765aa93ca4 100644 --- a/release/scripts/ui/buttons_texture.py +++ b/release/scripts/ui/buttons_texture.py @@ -246,13 +246,14 @@ class TEXTURE_PT_influence(TextureSlotPanel): col = split.column() factor_but(col, tex.map_density, "map_density", "density_factor", "Density") factor_but(col, tex.map_emission, "map_emission", "emission_factor", "Emission") - factor_but(col, tex.map_absorption, "map_absorption", "absorption_factor", "Absorption") factor_but(col, tex.map_scattering, "map_scattering", "scattering_factor", "Scattering") + factor_but(col, tex.map_reflection, "map_reflection", "reflection_factor", "Reflection") col = split.column() col.itemL(text=" ") factor_but(col, tex.map_alpha, "map_coloremission", "coloremission_factor", "Emission Color") - factor_but(col, tex.map_colorabsorption, "map_colorabsorption", "colorabsorption_factor", "Absorption Color") + factor_but(col, tex.map_colortransmission, "map_colortransmission", "colortransmission_factor", "Transmission Color") + factor_but(col, tex.map_colorreflection, "map_colorreflection", "colorreflection_factor", "Reflection Color") elif la: row = layout.row() @@ -642,6 +643,7 @@ class TEXTURE_PT_voxeldata(TextureButtonsPanel): row.itemR(vd, "still_frame_number") layout.itemR(vd, "interpolation") + layout.itemR(vd, "extension") layout.itemR(vd, "intensity") class TEXTURE_PT_pointdensity(TextureButtonsPanel): diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 1667bd97102..cbd306f6d87 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -172,15 +172,15 @@ void init_material(Material *ma) ma->vol.density = 1.0f; ma->vol.emission = 0.0f; - ma->vol.absorption = 1.0f; ma->vol.scattering = 1.0f; + ma->vol.reflection = 1.0f; + ma->vol.transmission_col[0] = ma->vol.transmission_col[1] = ma->vol.transmission_col[2] = 1.0f; + ma->vol.reflection_col[0] = ma->vol.reflection_col[1] = ma->vol.reflection_col[2] = 1.0f; ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f; - ma->vol.absorption_col[0] = ma->vol.absorption_col[1] = ma->vol.absorption_col[2] = 0.0f; ma->vol.density_scale = 1.0f; ma->vol.depth_cutoff = 0.01f; ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED; ma->vol.stepsize = 0.2f; - ma->vol.shade_stepsize = 0.2f; ma->vol.shade_type = MA_VOL_SHADE_SINGLE; ma->vol.shadeflag |= MA_VOL_PRECACHESHADING; ma->vol.precache_resolution = 50; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index d7616ec8a9a..287396a85c8 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -984,6 +984,7 @@ struct VoxelData *BKE_add_voxeldata(void) vd->interp_type= TEX_VD_LINEAR; vd->file_format= TEX_VD_SMOKE; vd->int_multiplier = 1.0; + vd->extend = TEX_CLIP; vd->object = NULL; return vd; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 114ec9095b1..94478b0d235 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9573,15 +9573,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main) if (ma->vol.stepsize < 0.0001f) { ma->vol.density = 1.0f; ma->vol.emission = 0.0f; - ma->vol.absorption = 1.0f; ma->vol.scattering = 1.0f; ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f; - ma->vol.absorption_col[0] = ma->vol.absorption_col[1] = ma->vol.absorption_col[2] = 0.0f; ma->vol.density_scale = 1.0f; ma->vol.depth_cutoff = 0.01f; ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED; ma->vol.stepsize = 0.2f; - ma->vol.shade_stepsize = 0.2f; ma->vol.shade_type = MA_VOL_SHADE_SINGLE; ma->vol.shadeflag |= MA_VOL_PRECACHESHADING; ma->vol.precache_resolution = 50; @@ -9703,6 +9700,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) { Scene *sce; Object *ob; + Material *ma; + Tex *tex; for(sce = main->scene.first; sce; sce = sce->id.next) if(sce->unit.scale_length == 0.0f) @@ -9716,7 +9715,21 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* rotation modes were added, but old objects would now default to being 'quaternion based' */ ob->rotmode= ROT_MODE_EUL; } + + for (ma = main->mat.first; ma; ma=ma->id.next) { + if (ma->vol.reflection == 0.f) { + ma->vol.reflection = 1.f; + ma->vol.transmission_col[0] = ma->vol.transmission_col[1] = ma->vol.transmission_col[2] = 1.0f; + ma->vol.reflection_col[0] = ma->vol.reflection_col[1] = ma->vol.reflection_col[2] = 1.0f; + } + } + for (tex = main->tex.first; tex; tex=tex->id.next) { + if (tex->vd) { + if (tex->vd->extend == 0) tex->vd->extend = TEX_CLIP; + } + } + for(sce= main->scene.first; sce; sce= sce->id.next) { if(sce->audio.main == 0.0) diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 81f6badc24b..7dc04a47c51 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -334,6 +334,19 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre } } } + + /* turn off bounce lights for volume, + * doesn't make much visual difference and slows it down too */ + if(mat->material_type == MA_TYPE_VOLUME) { + for(base= sce->base.first; base; base= base->next) { + if(base->object->type == OB_LAMP) { + /* if doesn't match 'Lamp.002' --> main key light */ + if( strcmp(base->object->id.name+2, "Lamp.002") != 0 ) { + base->object->restrictflag |= OB_RESTRICT_RENDER; + } + } + } + } if(sp->pr_method==PR_ICON_RENDER) { @@ -363,6 +376,8 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre if(matar && actcol < base->object->totcol) (*matar)[actcol]= mat; + } else if (base->object->type == OB_LAMP) { + base->object->restrictflag &= ~OB_RESTRICT_RENDER; } } } diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 55e3c9107e4..b3a7e74e91d 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -50,26 +50,23 @@ struct Ipo; typedef struct VolumeSettings { float density; float emission; - float absorption; float scattering; + float reflection; float emission_col[3]; - float absorption_col[3]; + float transmission_col[3]; + float reflection_col[3]; + float density_scale; float depth_cutoff; - - short phasefunc_type; - short vpad[3]; - float phasefunc_g; - - float stepsize; - float shade_stepsize; + float asymmetry; short stepsize_type; short shadeflag; short shade_type; short precache_resolution; - + + float stepsize; float ms_diff; float ms_intensity; int ms_steps; @@ -160,9 +157,8 @@ typedef struct Material { float sss_front, sss_back; short sss_flag, sss_preset; - /* yafray: absorption color, dispersion parameters and material preset menu */ - float YF_ar, YF_ag, YF_ab, YF_dscale, YF_dpwr; - int YF_dsmp, YF_preset, YF_djit; + int mapto_textured; /* render-time cache to optimise texture lookups */ + int pad4; ListBase gpumaterial; /* runtime */ } Material; @@ -320,12 +316,14 @@ typedef struct Material { #define MAP_LAYER 16384 /* volume mapto - reuse definitions for now - a bit naughty! */ -#define MAP_DENSITY 128 -#define MAP_EMISSION 64 -#define MAP_EMISSION_COL 1 -#define MAP_ABSORPTION 512 -#define MAP_ABSORPTION_COL 8 -#define MAP_SCATTERING 16 +#define MAP_DENSITY 128 +#define MAP_EMISSION 64 +#define MAP_EMISSION_COL 1 +#define MAP_SCATTERING 16 +#define MAP_TRANSMISSION_COL 8 +#define MAP_REFLECTION_COL 4 +#define MAP_REFLECTION 32 + /* mapto for halo */ //#define MAP_HA_COL 1 @@ -386,13 +384,5 @@ typedef struct Material { #define MA_VOL_SHADE_MULTIPLE 2 #define MA_VOL_SHADE_SINGLEPLUSMULTIPLE 3 -/* vol_phasefunc_type */ -#define MA_VOL_PH_ISOTROPIC 0 -#define MA_VOL_PH_MIEHAZY 1 -#define MA_VOL_PH_MIEMURKY 2 -#define MA_VOL_PH_RAYLEIGH 3 -#define MA_VOL_PH_HG 4 -#define MA_VOL_PH_SCHLICK 5 - #endif diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index c13c0522004..c8f35b4306f 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -167,7 +167,8 @@ typedef struct VoxelData { int interp_type; short file_format; short flag; - int pad; + short extend; + short pad; struct Object *object; /* for rendering smoke sims */ float int_multiplier; diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 9f7b97dfa05..593fc2e5935 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -537,14 +537,19 @@ static void rna_def_material_mtex(BlenderRNA *brna) /* volume material */ prop= RNA_def_property(srna, "map_coloremission", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_EMISSION_COL); - RNA_def_property_ui_text(prop, "Emission Color", "Causes the texture to affect the colour of emission"); + RNA_def_property_ui_text(prop, "Emission Color", "Causes the texture to affect the color of emission"); RNA_def_property_update(prop, 0, "rna_Material_update"); - prop= RNA_def_property(srna, "map_colorabsorption", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_ABSORPTION_COL); - RNA_def_property_ui_text(prop, "Absorption Color", "Causes the texture to affect the result colour after absorption"); + prop= RNA_def_property(srna, "map_colorreflection", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_REFLECTION_COL); + RNA_def_property_ui_text(prop, "Reflection Color", "Causes the texture to affect the color of scattered light"); RNA_def_property_update(prop, 0, "rna_Material_update"); + prop= RNA_def_property(srna, "map_colortransmission", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_TRANSMISSION_COL); + RNA_def_property_ui_text(prop, "Transmission Color", "Causes the texture to affect the result color after other light has been scattered/absorbed"); + RNA_def_property_update(prop, NC_TEXTURE, NULL); + prop= RNA_def_property(srna, "map_density", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_DENSITY); RNA_def_property_ui_text(prop, "Density", "Causes the texture to affect the volume's density"); @@ -555,28 +560,34 @@ static void rna_def_material_mtex(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Emission", "Causes the texture to affect the volume's emission"); RNA_def_property_update(prop, 0, "rna_Material_update"); - prop= RNA_def_property(srna, "map_absorption", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_ABSORPTION); - RNA_def_property_ui_text(prop, "Absorption", "Causes the texture to affect the volume's absorption"); - RNA_def_property_update(prop, 0, "rna_Material_update"); - prop= RNA_def_property(srna, "map_scattering", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_SCATTERING); RNA_def_property_ui_text(prop, "Scattering", "Causes the texture to affect the volume's scattering"); RNA_def_property_update(prop, 0, "rna_Material_update"); + prop= RNA_def_property(srna, "map_reflection", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_REFLECTION); + RNA_def_property_ui_text(prop, "Reflection", "Causes the texture to affect the reflected light's brightness"); + RNA_def_property_update(prop, NC_TEXTURE, NULL); + prop= RNA_def_property(srna, "coloremission_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "colfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); RNA_def_property_ui_text(prop, "Emission Color Factor", "Amount texture affects emission color."); RNA_def_property_update(prop, 0, "rna_Material_update"); - prop= RNA_def_property(srna, "colorabsorption_factor", PROP_FLOAT, PROP_NONE); + prop= RNA_def_property(srna, "colorreflection_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "colfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); - RNA_def_property_ui_text(prop, "Absorpion Color Factor", "Amount texture affects diffuse color."); + RNA_def_property_ui_text(prop, "Reflection Color Factor", "Amount texture affects color of out-scattered light"); RNA_def_property_update(prop, 0, "rna_Material_update"); + prop= RNA_def_property(srna, "colortransmission_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "colfac"); + RNA_def_property_ui_range(prop, 0, 1, 10, 3); + RNA_def_property_ui_text(prop, "Transmission Color Factor", "Amount texture affects result color after light has been scattered/absorbed."); + RNA_def_property_update(prop, NC_TEXTURE, NULL); + prop= RNA_def_property(srna, "density_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "varfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); @@ -589,16 +600,16 @@ static void rna_def_material_mtex(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Emission Factor", "Amount texture affects emission."); RNA_def_property_update(prop, 0, "rna_Material_update"); - prop= RNA_def_property(srna, "absorption_factor", PROP_FLOAT, PROP_NONE); + prop= RNA_def_property(srna, "scattering_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "varfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); - RNA_def_property_ui_text(prop, "Absorption Factor", "Amount texture affects absorption."); + RNA_def_property_ui_text(prop, "Scattering Factor", "Amount texture affects scattering."); RNA_def_property_update(prop, 0, "rna_Material_update"); - - prop= RNA_def_property(srna, "scattering_factor", PROP_FLOAT, PROP_NONE); + + prop= RNA_def_property(srna, "reflection_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "varfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); - RNA_def_property_ui_text(prop, "Scattering Factor", "Amount texture affects scattering."); + RNA_def_property_ui_text(prop, "Reflection Factor", "Amount texture affects brightness of out-scattered light."); RNA_def_property_update(prop, 0, "rna_Material_update"); /* end volume material */ @@ -955,15 +966,6 @@ static void rna_def_material_volume(BlenderRNA *brna) //{MA_VOL_STEP_ADAPTIVE, "ADAPTIVE", 0, "Adaptive", ""}, {0, NULL, 0, NULL, NULL}}; - static EnumPropertyItem prop_phasefunction_items[] = { - {MA_VOL_PH_ISOTROPIC, "ISOTROPIC", 0, "Isotropic", ""}, - {MA_VOL_PH_MIEHAZY, "MIE_HAZY", 0, "Mie Hazy", ""}, - {MA_VOL_PH_MIEMURKY, "MIE_MURKY", 0, "Mie Murky", ""}, - {MA_VOL_PH_RAYLEIGH, "RAYLEIGH", 0, "Rayleigh", ""}, - {MA_VOL_PH_HG, "HENYEY-GREENSTEIN", 0, "Henyey-Greenstein", ""}, - {MA_VOL_PH_SCHLICK, "SCHLICK", 0, "Schlick", ""}, - {0, NULL, 0, NULL, NULL}}; - srna= RNA_def_struct(brna, "MaterialVolume", NULL); RNA_def_struct_sdna(srna, "VolumeSettings"); RNA_def_struct_nested(brna, srna, "Material"); @@ -982,13 +984,6 @@ static void rna_def_material_volume(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Step Size", "Distance between subsequent volume depth samples."); RNA_def_property_update(prop, 0, "rna_Material_update"); - prop= RNA_def_property(srna, "shading_step_size", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "shade_stepsize"); - RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 3); - RNA_def_property_ui_text(prop, "Shading Step Size", "Distance between subsequent volume shading samples."); - RNA_def_property_update(prop, 0, "rna_Material_update"); - prop= RNA_def_property(srna, "scattering_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "shade_type"); RNA_def_property_enum_items(prop, prop_scattering_items); @@ -1043,31 +1038,30 @@ static void rna_def_material_volume(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Density Scale", "Multiplier for the material's density"); RNA_def_property_update(prop, 0, "rna_Material_update"); - prop= RNA_def_property(srna, "absorption", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "absorption"); + prop= RNA_def_property(srna, "scattering", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "scattering"); RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); - RNA_def_property_ui_text(prop, "Absorption", "Amount of light that gets absorbed by the volume - higher values mean light travels less distance"); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1 ,3); + RNA_def_property_ui_text(prop, "Scattering", "Amount of light that gets scattered out by the volume - the more out-scattering, the shallower the light will penetrate "); RNA_def_property_update(prop, 0, "rna_Material_update"); - prop= RNA_def_property(srna, "absorption_color", PROP_FLOAT, PROP_COLOR); - RNA_def_property_float_sdna(prop, NULL, "absorption_col"); + prop= RNA_def_property(srna, "transmission_color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_float_sdna(prop, NULL, "transmission_col"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Absorption Color", ""); + RNA_def_property_ui_text(prop, "Transmission Color", "Result color of the volume, after other light has been scattered/absorbed"); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); - prop= RNA_def_property(srna, "scattering", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "scattering"); - RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1 ,3); - RNA_def_property_ui_text(prop, "Scattering", "Amount of light that gets scattered by the volume - values > 1.0 are non-physical"); - RNA_def_property_update(prop, 0, "rna_Material_update"); + prop= RNA_def_property(srna, "reflection_color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_float_sdna(prop, NULL, "reflection_col"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Reflection Color", "Colour of light scattered out of the volume (does not affect transmission)"); + RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING_DRAW, NULL); - prop= RNA_def_property(srna, "emission", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "emission"); + prop= RNA_def_property(srna, "reflection", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "reflection"); RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); - RNA_def_property_ui_text(prop, "Emission", "Amount of light that gets emitted by the volume"); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1 ,3); + RNA_def_property_ui_text(prop, "Reflection", "Multiplier to make out-scattered light brighter or darker (non-physically correct)"); RNA_def_property_update(prop, 0, "rna_Material_update"); prop= RNA_def_property(srna, "emission_color", PROP_FLOAT, PROP_COLOR); @@ -1076,16 +1070,17 @@ static void rna_def_material_volume(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Emission Color", ""); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); - prop= RNA_def_property(srna, "phase_function", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "phasefunc_type"); - RNA_def_property_enum_items(prop, prop_phasefunction_items); - RNA_def_property_ui_text(prop, "Phase Function", "Isotropic/Anisotropic scattering"); + prop= RNA_def_property(srna, "emission", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "emission"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); + RNA_def_property_ui_text(prop, "Emission", "Amount of light that gets emitted by the volume"); RNA_def_property_update(prop, 0, "rna_Material_update"); - + prop= RNA_def_property(srna, "asymmetry", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "phasefunc_g"); + RNA_def_property_float_sdna(prop, NULL, "asymmetry"); RNA_def_property_range(prop, -1.0f, 1.0f); - RNA_def_property_ui_text(prop, "Asymmetry", "Continuum between forward scattering and back scattering"); + RNA_def_property_ui_text(prop, "Asymmetry", "Back scattering (-1.0) to Forward scattering (1.0) and the range in between."); RNA_def_property_update(prop, 0, "rna_Material_update"); } diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index d63f5823b2e..7bc8570ce13 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -955,11 +955,11 @@ static void rna_def_texture_image(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem prop_image_extension[] = { - {1, "EXTEND", 0, "Extend", "Extends by repeating edge pixels of the image"}, - {2, "CLIP", 0, "Clip", "Clips to image size and sets exterior pixels as transparent"}, - {4, "CLIP_CUBE", 0, "Clip Cube", "Clips to cubic-shaped area around the image and sets exterior pixels as transparent"}, - {3, "REPEAT", 0, "Repeat", "Causes the image to repeat horizontally and vertically"}, - {5, "CHECKER", 0, "Checker", "Causes the image to repeat in checker board pattern"}, + {TEX_EXTEND, "EXTEND", 0, "Extend", "Extends by repeating edge pixels of the image"}, + {TEX_CLIP, "CLIP", 0, "Clip", "Clips to image size and sets exterior pixels as transparent"}, + {TEX_CLIPCUBE, "CLIP_CUBE", 0, "Clip Cube", "Clips to cubic-shaped area around the image and sets exterior pixels as transparent"}, + {TEX_REPEAT, "REPEAT", 0, "Repeat", "Causes the image to repeat horizontally and vertically"}, + {TEX_CHECKER, "CHECKER", 0, "Checker", "Causes the image to repeat in checker board pattern"}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "ImageTexture", "Texture"); @@ -1016,7 +1016,7 @@ static void rna_def_texture_image(BlenderRNA *brna) prop= RNA_def_property(srna, "extension", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "extend"); RNA_def_property_enum_items(prop, prop_image_extension); - RNA_def_property_ui_text(prop, "Extension", "Sets how the image is stretched in the texture"); + RNA_def_property_ui_text(prop, "Extension", "Sets how the image is extrapolated past its original bounds"); RNA_def_property_update(prop, 0, "rna_Texture_update"); prop= RNA_def_property(srna, "repeat_x", PROP_INT, PROP_NONE); @@ -1562,6 +1562,12 @@ static void rna_def_texture_voxeldata(BlenderRNA *brna) {TEX_VD_IMAGE_SEQUENCE, "IMAGE_SEQUENCE", 0, "Image Sequence", "Generate voxels from a sequence of image slices"}, {TEX_VD_SMOKE, "SMOKE", 0, "Smoke", "Render voxels from a Blender smoke simulation"}, {0, NULL, 0, NULL, NULL}}; + + static EnumPropertyItem voxeldata_extension[] = { + {TEX_EXTEND, "EXTEND", 0, "Extend", "Extends by repeating edge pixels of the image"}, + {TEX_CLIP, "CLIP", 0, "Clip", "Clips to image size and sets exterior pixels as transparent"}, + {TEX_REPEAT, "REPEAT", 0, "Repeat", "Causes the image to repeat horizontally and vertically"}, + {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "VoxelData", NULL); RNA_def_struct_sdna(srna, "VoxelData"); @@ -1573,6 +1579,12 @@ static void rna_def_texture_voxeldata(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Interpolation", "Method to interpolate/smooth values between voxel cells"); RNA_def_property_update(prop, 0, "rna_Texture_update"); + prop= RNA_def_property(srna, "extension", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "extend"); + RNA_def_property_enum_items(prop, voxeldata_extension); + RNA_def_property_ui_text(prop, "Extension", "Sets how the texture is extrapolated past its original bounds"); + RNA_def_property_update(prop, 0, "rna_Texture_update"); + prop= RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "int_multiplier"); RNA_def_property_range(prop, 0.01, FLT_MAX); diff --git a/source/blender/render/intern/include/volume_precache.h b/source/blender/render/intern/include/volume_precache.h index 9d87a219c82..368d60ee7f0 100644 --- a/source/blender/render/intern/include/volume_precache.h +++ b/source/blender/render/intern/include/volume_precache.h @@ -30,4 +30,4 @@ void volume_precache(Render *re); void free_volume_precache(Render *re); int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co); -#define VOL_MS_TIMESTEP 0.1f
\ No newline at end of file +#define VOL_MS_TIMESTEP 0.1f diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h index 026b4840ea3..97e7e022fa0 100644 --- a/source/blender/render/intern/include/volumetric.h +++ b/source/blender/render/intern/include/volumetric.h @@ -26,9 +26,8 @@ * ***** END GPL LICENSE BLOCK ***** */ -float vol_get_stepsize(struct ShadeInput *shi, int context); float vol_get_density(struct ShadeInput *shi, float *co); -void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co, float stepsize, float density); +void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co_); void shade_volume_outside(ShadeInput *shi, ShadeResult *shr); void shade_volume_inside(ShadeInput *shi, ShadeResult *shr); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 48a7c003c9f..b3784f26048 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -889,6 +889,28 @@ static void free_mesh_orco_hash(Render *re) } } +static void check_material_mapto(Material *ma) +{ + int a; + ma->mapto_textured = 0; + + /* cache which inputs are actually textured. + * this can avoid a bit of time spent iterating through all the texture slots, map inputs and map tos + * every time a property which may or may not be textured is accessed */ + + for(a=0; a<MAX_MTEX; a++) { + if(ma->mtex[a] && ma->mtex[a]->tex) { + /* currently used only in volume render, so we'll check for those flags */ + if(ma->mtex[a]->mapto & MAP_DENSITY) ma->mapto_textured |= MAP_DENSITY; + if(ma->mtex[a]->mapto & MAP_EMISSION) ma->mapto_textured |= MAP_EMISSION; + if(ma->mtex[a]->mapto & MAP_EMISSION_COL) ma->mapto_textured |= MAP_EMISSION_COL; + if(ma->mtex[a]->mapto & MAP_SCATTERING) ma->mapto_textured |= MAP_SCATTERING; + if(ma->mtex[a]->mapto & MAP_TRANSMISSION_COL) ma->mapto_textured |= MAP_TRANSMISSION_COL; + if(ma->mtex[a]->mapto & MAP_REFLECTION) ma->mapto_textured |= MAP_REFLECTION; + if(ma->mtex[a]->mapto & MAP_REFLECTION_COL) ma->mapto_textured |= MAP_REFLECTION_COL; + } + } +} static void flag_render_node_material(Render *re, bNodeTree *ntree) { bNode *node; @@ -930,6 +952,8 @@ static Material *give_render_material(Render *re, Object *ob, int nr) if(ma->nodetree && ma->use_nodes) flag_render_node_material(re, ma->nodetree); + check_material_mapto(ma); + return ma; } diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index c1d0c943ca9..cce99d64b39 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -1343,7 +1343,8 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int /* mix colors based on shadfac (rgb + amount of light factor) */ addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter); } else if (shi.mat->material_type == MA_TYPE_VOLUME) { - addAlphaLight(is->col, shr.combined, shr.alpha, 1.0f); + QUATCOPY(is->col, shr.combined); + is->col[3] = 1.f; } if(depth>0 && is->col[3]>0.0f) { diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 4830dab7d37..02b7f6aad86 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -2385,7 +2385,7 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa } - if((mapto_flag & (MAP_EMISSION_COL+MAP_ABSORPTION_COL)) && (mtex->mapto & (MAP_EMISSION_COL+MAP_ABSORPTION_COL))) { + if((mapto_flag & (MAP_EMISSION_COL+MAP_TRANSMISSION_COL+MAP_REFLECTION_COL)) && (mtex->mapto & (MAP_EMISSION_COL+MAP_TRANSMISSION_COL+MAP_REFLECTION_COL))) { float tcol[3], colfac; /* stencil maps on the texture control slider, not texture intensity value */ @@ -2413,8 +2413,11 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype); } - /* MAP_COLMIR is abused for absorption colour at the moment */ - if((mapto_flag & MAP_ABSORPTION_COL) && (mtex->mapto & MAP_ABSORPTION_COL)) { + if((mapto_flag & MAP_REFLECTION_COL) && (mtex->mapto & MAP_REFLECTION_COL)) { + texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype); + } + + if((mapto_flag & MAP_TRANSMISSION_COL) && (mtex->mapto & MAP_TRANSMISSION_COL)) { texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype); } } @@ -2443,14 +2446,14 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa *val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip); CLAMP(*val, 0.0, 1.0); } - if((mapto_flag & MAP_ABSORPTION) && (mtex->mapto & MAP_ABSORPTION)) { - int flip= mtex->maptoneg & MAP_ABSORPTION; + if((mapto_flag & MAP_SCATTERING) && (mtex->mapto & MAP_SCATTERING)) { + int flip= mtex->maptoneg & MAP_SCATTERING; *val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip); CLAMP(*val, 0.0, 1.0); } - if((mapto_flag & MAP_SCATTERING) && (mtex->mapto & MAP_SCATTERING)) { - int flip= mtex->maptoneg & MAP_SCATTERING; + if((mapto_flag & MAP_REFLECTION) && (mtex->mapto & MAP_REFLECTION)) { + int flip= mtex->maptoneg & MAP_REFLECTION; *val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip); CLAMP(*val, 0.0, 1.0); diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 15d8643fea4..7ecaf83ae27 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -185,9 +185,9 @@ static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz) } } - tot /= added; + if (added > 0) tot /= added; - return ((added>0)?tot:0.0f); + return tot; } /* function to filter the edges of the light cache, where there was no volume originally. @@ -202,17 +202,54 @@ static void lightcache_filter(VolumePrecache *vp) for (y=0; y < vp->res[1]; y++) { for (x=0; x < vp->res[0]; x++) { /* trigger for outside mesh */ - if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.5f) + if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.f) vp->data_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z); - if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.5f) + if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.f) vp->data_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z); - if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.5f) + if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.f) vp->data_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z); } } } } +static void lightcache_filter2(VolumePrecache *vp) +{ + int x, y, z; + float *new_r, *new_g, *new_b; + int field_size = vp->res[0]*vp->res[1]*vp->res[2]*sizeof(float); + + new_r = MEM_mallocN(field_size, "temp buffer for light cache filter r channel"); + new_g = MEM_mallocN(field_size, "temp buffer for light cache filter g channel"); + new_b = MEM_mallocN(field_size, "temp buffer for light cache filter b channel"); + + memcpy(new_r, vp->data_r, field_size); + memcpy(new_g, vp->data_g, field_size); + memcpy(new_b, vp->data_b, field_size); + + for (z=0; z < vp->res[2]; z++) { + for (y=0; y < vp->res[1]; y++) { + for (x=0; x < vp->res[0]; x++) { + /* trigger for outside mesh */ + if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.f) + new_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z); + if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.f) + new_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z); + if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.f) + new_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z); + } + } + } + + SWAP(float *, vp->data_r, new_r); + SWAP(float *, vp->data_g, new_g); + SWAP(float *, vp->data_b, new_b); + + if (new_r) { MEM_freeN(new_r); new_r=NULL; } + if (new_g) { MEM_freeN(new_g); new_g=NULL; } + if (new_b) { MEM_freeN(new_b); new_b=NULL; } +} + static inline int ms_I(int x, int y, int z, int *n) //has a pad of 1 voxel surrounding the core for boundary simulation { return z*(n[1]+2)*(n[0]+2) + y*(n[0]+2) + x; @@ -423,11 +460,10 @@ static void *vol_precache_part(void *data) ObjectInstanceRen *obi = pa->obi; RayTree *tree = pa->tree; ShadeInput *shi = pa->shi; - float density, scatter_col[3] = {0.f, 0.f, 0.f}; + float scatter_col[3] = {0.f, 0.f, 0.f}; float co[3]; int x, y, z; const int res[3]= {pa->res[0], pa->res[1], pa->res[2]}; - const float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW); for (z= pa->minz; z < pa->maxz; z++) { co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f)); @@ -448,8 +484,7 @@ static void *vol_precache_part(void *data) VecCopyf(shi->view, co); Normalize(shi->view); - density = vol_get_density(shi, co); - vol_get_scattering(shi, scatter_col, co, stepsize, density); + vol_get_scattering(shi, scatter_col, co); obi->volume_precache->data_r[ V_I(x, y, z, res) ] = scatter_col[0]; obi->volume_precache->data_g[ V_I(x, y, z, res) ] = scatter_col[1]; diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index b2692c25b99..381a32de027 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -170,29 +170,6 @@ static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *co } } -/* input shader data */ - -float vol_get_stepsize(struct ShadeInput *shi, int context) -{ - if (shi->mat->vol.stepsize_type == MA_VOL_STEP_RANDOMIZED) { - /* range between 0.75 and 1.25 */ - const float rnd = 0.5f * BLI_thread_frand(shi->thread) + 0.75f; - - if (context == STEPSIZE_VIEW) - return shi->mat->vol.stepsize * rnd; - else if (context == STEPSIZE_SHADE) - return shi->mat->vol.shade_stepsize * rnd; - } - else { // MA_VOL_STEP_CONSTANT - - if (context == STEPSIZE_VIEW) - return shi->mat->vol.stepsize; - else if (context == STEPSIZE_SHADE) - return shi->mat->vol.shade_stepsize; - } - - return shi->mat->vol.stepsize; -} /* trilinear interpolation */ static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co) @@ -212,9 +189,9 @@ static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, fl sample_co[1] = ((co[1] - bbmin[1]) / dim[1]); sample_co[2] = ((co[2] - bbmin[2]) / dim[2]); - scatter_col[0] = voxel_sample_trilinear(vp->data_r, vp->res, sample_co); - scatter_col[1] = voxel_sample_trilinear(vp->data_g, vp->res, sample_co); - scatter_col[2] = voxel_sample_trilinear(vp->data_b, vp->res, sample_co); + scatter_col[0] = voxel_sample_triquadratic(vp->data_r, vp->res, sample_co); + scatter_col[1] = voxel_sample_triquadratic(vp->data_g, vp->res, sample_co); + scatter_col[2] = voxel_sample_triquadratic(vp->data_b, vp->res, sample_co); } /* Meta object density, brute force for now @@ -270,7 +247,8 @@ float vol_get_density(struct ShadeInput *shi, float *co) float density = shi->mat->vol.density; float density_scale = shi->mat->vol.density_scale; - do_volume_tex(shi, co, MAP_DENSITY, NULL, &density); + if (shi->mat->mapto_textured & MAP_DENSITY) + do_volume_tex(shi, co, MAP_DENSITY, NULL, &density); // if meta-object, modulate by metadensity without increasing it if (shi->obi->obr->ob->type == OB_MBALL) { @@ -281,79 +259,110 @@ float vol_get_density(struct ShadeInput *shi, float *co) return density * density_scale; } -/* scattering multiplier, values above 1.0 are non-physical, - * but can be useful to tweak lighting */ -float vol_get_scattering_fac(ShadeInput *shi, float *co) + +/* Color of light that gets scattered out by the volume */ +/* Uses same physically based scattering parameter as in transmission calculations, + * along with artificial reflection scale/reflection color tint */ +void vol_get_reflection_color(ShadeInput *shi, float *ref_col, float *co) { float scatter = shi->mat->vol.scattering; - float col[3] = {0.0, 0.0, 0.0}; + float reflection= shi->mat->vol.reflection; + VECCOPY(ref_col, shi->mat->vol.reflection_col); + + if (shi->mat->mapto_textured & (MAP_SCATTERING+MAP_REFLECTION_COL)) + do_volume_tex(shi, co, MAP_SCATTERING+MAP_REFLECTION_COL, ref_col, &scatter); - do_volume_tex(shi, co, MAP_SCATTERING, col, &scatter); + /* only one single float parameter at a time... :s */ + if (shi->mat->mapto_textured & (MAP_REFLECTION)) + do_volume_tex(shi, co, MAP_REFLECTION, NULL, &reflection); - return scatter; + ref_col[0] = reflection * ref_col[0] * scatter; + ref_col[1] = reflection * ref_col[1] * scatter; + ref_col[2] = reflection * ref_col[2] * scatter; } /* compute emission component, amount of radiance to add per segment * can be textured with 'emit' */ -void vol_get_emission(ShadeInput *shi, float *emission_col, float *co, float density) +void vol_get_emission(ShadeInput *shi, float *emission_col, float *co) { float emission = shi->mat->vol.emission; VECCOPY(emission_col, shi->mat->vol.emission_col); - do_volume_tex(shi, co, MAP_EMISSION+MAP_EMISSION_COL, emission_col, &emission); + if (shi->mat->mapto_textured & (MAP_EMISSION+MAP_EMISSION_COL)) + do_volume_tex(shi, co, MAP_EMISSION+MAP_EMISSION_COL, emission_col, &emission); - emission_col[0] = emission_col[0] * emission * density; - emission_col[1] = emission_col[1] * emission * density; - emission_col[2] = emission_col[2] * emission * density; + emission_col[0] = emission_col[0] * emission; + emission_col[1] = emission_col[1] * emission; + emission_col[2] = emission_col[2] * emission; } -void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co) + +/* A combination of scattering and absorption -> known as sigma T. + * This can possibly use a specific scattering colour, + * and absorption multiplier factor too, but these parameters are left out for simplicity. + * It's easy enough to get a good wide range of results with just these two parameters. */ +void vol_get_sigma_t(ShadeInput *shi, float *sigma_t, float *co) { - float absorption = shi->mat->vol.absorption; - VECCOPY(absorb_col, shi->mat->vol.absorption_col); + /* technically absorption, but named transmission color + * since it describes the effect of the coloring *after* absorption */ + float transmission_col[3] = {shi->mat->vol.transmission_col[0], shi->mat->vol.transmission_col[1], shi->mat->vol.transmission_col[2]}; + float scattering = shi->mat->vol.scattering; - do_volume_tex(shi, co, MAP_ABSORPTION+MAP_ABSORPTION_COL, absorb_col, &absorption); + if (shi->mat->mapto_textured & (MAP_SCATTERING+MAP_TRANSMISSION_COL)) + do_volume_tex(shi, co, MAP_SCATTERING+MAP_TRANSMISSION_COL, transmission_col, &scattering); - absorb_col[0] = (1.0f - absorb_col[0]) * absorption; - absorb_col[1] = (1.0f - absorb_col[1]) * absorption; - absorb_col[2] = (1.0f - absorb_col[2]) * absorption; + sigma_t[0] = (1.0f - transmission_col[0]) + scattering; + sigma_t[1] = (1.0f - transmission_col[1]) + scattering; + sigma_t[2] = (1.0f - transmission_col[2]) + scattering; } /* phase function - determines in which directions the light * is scattered in the volume relative to incoming direction * and view direction */ -float vol_get_phasefunc(ShadeInput *shi, short phasefunc_type, float g, float *w, float *wp) +float vol_get_phasefunc(ShadeInput *shi, float g, float *w, float *wp) { - const float costheta = Inpf(w, wp); - const float scale = M_PI; - - /* - * Scale constant is required, since Blender's shading system doesn't normalise for - * energy conservation - eg. scaling by 1/pi for a lambert shader. - * This makes volumes darker than other solid objects, for the same lighting intensity. - * To correct this, scale up the phase function values + const float normalize = 0.25f; // = 1.f/4.f = M_PI/(4.f*M_PI) + + /* normalization constant is 1/4 rather than 1/4pi, since + * Blender's shading system doesn't normalise for + * energy conservation - eg. multiplying by pdf ( 1/pi for a lambert brdf ). + * This means that lambert surfaces in Blender are pi times brighter than they 'should be' + * and therefore, with correct energy conservation, volumes will darker than other solid objects, + * for the same lighting intensity. + * To correct this, scale up the phase function values by pi * until Blender's shading system supports this better. --matt */ + if (g == 0.f) { /* isotropic */ + return normalize * 1.f; + } else { /* schlick */ + const float k = 1.55f * g - .55f * g * g * g; + const float kcostheta = k * Inpf(w, wp); + return normalize * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta)); + } + + /* + * not used, but here for reference: switch (phasefunc_type) { case MA_VOL_PH_MIEHAZY: - return scale * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)) / (4.f*M_PI); + return normalize * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)); case MA_VOL_PH_MIEMURKY: - return scale * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)) / (4.f*M_PI); + return normalize * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)); case MA_VOL_PH_RAYLEIGH: - return scale * 3.f/(16.f*M_PI) * (1 + costheta * costheta); + return normalize * 3.f/4.f * (1 + costheta * costheta); case MA_VOL_PH_HG: - return scale * (1.f / (4.f * M_PI) * (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f)); + return normalize * (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f)); case MA_VOL_PH_SCHLICK: { const float k = 1.55f * g - .55f * g * g * g; const float kcostheta = k * costheta; - return scale * (1.f / (4.f * M_PI) * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta))); + return normalize * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta)); } case MA_VOL_PH_ISOTROPIC: default: - return scale * (1.f / (4.f * M_PI)); + return normalize * 1.f; } + */ } /* Compute transmittance = e^(-attenuation) */ @@ -361,15 +370,15 @@ void vol_get_transmittance_seg(ShadeInput *shi, float *tr, float stepsize, float { /* input density = density at co */ float tau[3] = {0.f, 0.f, 0.f}; - float absorb[3]; - const float scatter_dens = vol_get_scattering_fac(shi, co) * density * stepsize; - - vol_get_absorption(shi, absorb, co); + const float stepd = density * stepsize; + float sigma_t[3]; + + vol_get_sigma_t(shi, sigma_t, co); /* homogenous volume within the sampled distance */ - tau[0] += scatter_dens * absorb[0]; - tau[1] += scatter_dens * absorb[1]; - tau[2] += scatter_dens * absorb[2]; + tau[0] += stepd * sigma_t[0]; + tau[1] += stepd * sigma_t[1]; + tau[2] += stepd * sigma_t[2]; tr[0] *= exp(-tau[0]); tr[1] *= exp(-tau[1]); @@ -381,31 +390,29 @@ static void vol_get_transmittance(ShadeInput *shi, float *tr, float *co, float * { float p[3] = {co[0], co[1], co[2]}; float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]}; - //const float ambtau = -logf(shi->mat->vol.depth_cutoff); // never zero float tau[3] = {0.f, 0.f, 0.f}; float t0 = 0.f; float t1 = Normalize(step_vec); float pt0 = t0; - t0 += shi->mat->vol.shade_stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread)); + t0 += shi->mat->vol.stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread)); p[0] += t0 * step_vec[0]; p[1] += t0 * step_vec[1]; p[2] += t0 * step_vec[2]; - VecMulf(step_vec, shi->mat->vol.shade_stepsize); + VecMulf(step_vec, shi->mat->vol.stepsize); - for (; t0 < t1; pt0 = t0, t0 += shi->mat->vol.shade_stepsize) { - float absorb[3]; + for (; t0 < t1; pt0 = t0, t0 += shi->mat->vol.stepsize) { const float d = vol_get_density(shi, p); const float stepd = (t0 - pt0) * d; - const float scatter_dens = vol_get_scattering_fac(shi, p) * stepd; - vol_get_absorption(shi, absorb, p); + float sigma_t[3]; + + vol_get_sigma_t(shi, sigma_t, co); - tau[0] += scatter_dens * absorb[0]; - tau[1] += scatter_dens * absorb[1]; - tau[2] += scatter_dens * absorb[2]; + tau[0] += stepd * sigma_t[0]; + tau[1] += stepd * sigma_t[1]; + tau[2] += stepd * sigma_t[2]; - //if (luminance(tau) >= ambtau) break; VecAddf(p, p, step_vec); } @@ -420,8 +427,7 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * float visifac, lv[3], lampdist; float tr[3]={1.0,1.0,1.0}; float hitco[3], *atten_co; - float p; - float scatter_fac; + float p, ref_col[3]; if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; if ((lar->lay & shi->lay)==0) return; @@ -475,15 +481,20 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * } } - p = vol_get_phasefunc(shi, shi->mat->vol.phasefunc_type, shi->mat->vol.phasefunc_g, shi->view, lv); - VecMulf(lacol, p); + if (luminance(lacol) < 0.001f) return; + + p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, shi->view, lv); + + /* physically based scattering with non-physically based RGB gain */ + vol_get_reflection_color(shi, ref_col, co); - scatter_fac = vol_get_scattering_fac(shi, co); - VecMulf(lacol, scatter_fac); + lacol[0] *= p * ref_col[0]; + lacol[1] *= p * ref_col[1]; + lacol[2] *= p * ref_col[2]; } /* single scattering only for now */ -void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co, float stepsize, float density) +void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co) { ListBase *lights; GroupObject *go; @@ -515,71 +526,69 @@ outgoing radiance from behind surface * beam transmittance/attenuation --> radiance for each segment = (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation */ + +/* For ease of use, I've also introduced a 'reflection' and 'reflection color' parameter, which isn't + * physically correct. This works as an RGB tint/gain on out-scattered light, but doesn't affect the light + * that is transmitted through the volume. While having wavelength dependent absorption/scattering is more correct, + * it also makes it harder to control the overall look of the volume since colouring the outscattered light results + * in the inverse colour being transmitted through the rest of the volume. + */ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco) { - float tr[3] = {1.0f, 1.0f, 1.0f}; - float radiance[3] = {0.f, 0.f, 0.f}, d_radiance[3] = {0.f, 0.f, 0.f}; - float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW); - int nsteps, s; - float emit_col[3], scatter_col[3] = {0.0, 0.0, 0.0}; - float stepvec[3], step_sta[3], step_end[3], step_mid[3]; - float density; - const float depth_cutoff = shi->mat->vol.depth_cutoff; - - /* ray marching */ - nsteps = (int)((VecLenf(co, endco) / stepsize) + 0.5); - - VecSubf(stepvec, endco, co); - VecMulf(stepvec, 1.0f / nsteps); - VecCopyf(step_sta, co); - VecAddf(step_end, step_sta, stepvec); - - /* get radiance from all points along the ray due to participating media */ - for (s = 0; s < nsteps; s++) { - - density = vol_get_density(shi, step_sta); + float radiance[3] = {0.f, 0.f, 0.f}; + float tr[3] = {1.f, 1.f, 1.f}; + float p[3] = {co[0], co[1], co[2]}; + float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]}; + const float stepsize = shi->mat->vol.stepsize; + + float t0 = 0.f; + float pt0 = t0; + float t1 = Normalize(step_vec); /* returns vector length */ + + t0 += stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread)); + p[0] += t0 * step_vec[0]; + p[1] += t0 * step_vec[1]; + p[2] += t0 * step_vec[2]; + VecMulf(step_vec, stepsize); + + for (; t0 < t1; pt0 = t0, t0 += stepsize) { + const float density = vol_get_density(shi, p); - /* there's only any use in shading here if there's actually some density to shade! */ if (density > 0.01f) { - + float scatter_col[3], emit_col[3]; + const float stepd = (t0 - pt0) * density; + /* transmittance component (alpha) */ vol_get_transmittance_seg(shi, tr, stepsize, co, density); - - step_mid[0] = step_sta[0] + (stepvec[0] * 0.5); - step_mid[1] = step_sta[1] + (stepvec[1] * 0.5); - step_mid[2] = step_sta[2] + (stepvec[2] * 0.5); - - /* incoming light via emission or scattering (additive) */ - vol_get_emission(shi, emit_col, step_mid, density); - if (shi->obi->volume_precache) - vol_get_precached_scattering(shi, scatter_col, step_mid); - else - vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); + if (luminance(tr) < shi->mat->vol.depth_cutoff) break; - VecMulf(scatter_col, density); - VecAddf(d_radiance, emit_col, scatter_col); + vol_get_emission(shi, emit_col, p); - /* Lv += Tr * (Lve() + Ld) */ - VecMulVecf(d_radiance, tr, d_radiance); - VecMulf(d_radiance, stepsize); + if (shi->obi->volume_precache) { + float p2[3]; + + p2[0] = p[0] + (step_vec[0] * 0.5); + p2[1] = p[1] + (step_vec[1] * 0.5); + p2[2] = p[2] + (step_vec[2] * 0.5); + + vol_get_precached_scattering(shi, scatter_col, p2); + } else + vol_get_scattering(shi, scatter_col, p); - VecAddf(radiance, radiance, d_radiance); + radiance[0] += stepd * tr[0] * (emit_col[0] + scatter_col[0]); + radiance[1] += stepd * tr[1] * (emit_col[1] + scatter_col[1]); + radiance[2] += stepd * tr[2] * (emit_col[2] + scatter_col[2]); } - - VecCopyf(step_sta, step_end); - VecAddf(step_end, step_end, stepvec); - - /* luminance rec. 709 */ - if ((0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]) < depth_cutoff) break; + VecAddf(p, p, step_vec); } - /* multiply original color (behind volume) with beam transmittance over entire distance */ - VecMulVecf(col, tr, col); + /* multiply original color (from behind volume) with transmittance over entire distance */ + VecMulVecf(col, tr, col); VecAddf(col, col, radiance); /* alpha <-- transmission luminance */ - col[3] = 1.0f -(0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]); + col[3] = 1.0f - luminance(tr); } /* the main entry point for volume shading */ @@ -606,7 +615,7 @@ static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int in /* don't render the backfaces of ztransp volume materials. * volume shading renders the internal volume from between the - * near view intersection of the solid volume to the + * ' view intersection of the solid volume to the * intersection on the other side, as part of the shading of * the front face. @@ -709,8 +718,7 @@ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct vol_get_transmittance(shi, tr, startco, endco); VecCopyf(shr->combined, tr); - shr->combined[3] = 1.0f -(0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]); - shr->alpha = shr->combined[3]; + shr->combined[3] = 1.0f - luminance(tr); } diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 9318d37620c..479f33c9ff2 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -226,9 +226,6 @@ void make_voxeldata(struct Render *re) { Tex *tex; - if(re->scene->r.scemode & R_PREVIEWBUTS) - return; - re->i.infostr= "Loading voxel datasets"; re->stats_draw(re->sdh, &re->i); @@ -259,9 +256,6 @@ void free_voxeldata(Render *re) { Tex *tex; - if(re->scene->r.scemode & R_PREVIEWBUTS) - return; - for (tex= G.main->tex.first; tex; tex= tex->id.next) { if(tex->id.us && tex->type==TEX_VOXELDATA) { free_voxeldata_one(re, tex); |