Volumes: add render settings for volume datablock

* Space: volume density and step size in object or world space
* Step Size: override automatic step size
* Clipping: values below this are ignored for tighter volume bounds

The last two are Cycles only currently.

Ref T73201
This commit is contained in:
Brecht Van Lommel
2020-03-16 14:42:56 +01:00
parent 1162ba206d
commit 7537cad576
13 changed files with 126 additions and 20 deletions

View File

@@ -207,7 +207,7 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float
continue; continue;
} }
mesh->volume_isovalue = b_domain.clipping(); mesh->volume_clipping = b_domain.clipping();
Attribute *attr = mesh->attributes.add(std); Attribute *attr = mesh->attributes.add(std);
@@ -292,7 +292,11 @@ static void sync_volume_object(BL::BlendData &b_data, BL::Object &b_ob, Scene *s
BL::Volume b_volume(b_ob.data()); BL::Volume b_volume(b_ob.data());
b_volume.grids.load(b_data.ptr.data); b_volume.grids.load(b_data.ptr.data);
mesh->volume_isovalue = 1e-3f; /* TODO: make user setting. */ BL::VolumeRender b_render(b_volume.render());
mesh->volume_clipping = b_render.clipping();
mesh->volume_step_size = b_render.step_size();
mesh->volume_object_space = (b_render.space() == BL::VolumeRender::space_OBJECT);
/* Find grid with matching name. */ /* Find grid with matching name. */
BL::Volume::grids_iterator b_grid_iter; BL::Volume::grids_iterator b_grid_iter;

View File

@@ -322,6 +322,15 @@ ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
/* Volume step size */ /* Volume step size */
ccl_device_inline float object_volume_density(KernelGlobals *kg, int object)
{
if (object == OBJECT_NONE) {
return 1.0f;
}
return kernel_tex_fetch(__objects, object).surface_area;
}
ccl_device_inline float object_volume_step_size(KernelGlobals *kg, int object) ccl_device_inline float object_volume_step_size(KernelGlobals *kg, int object)
{ {
if (object == OBJECT_NONE) { if (object == OBJECT_NONE) {

View File

@@ -48,7 +48,8 @@ ccl_device_inline bool volume_shader_extinction_sample(KernelGlobals *kg,
shader_eval_volume(kg, sd, state, state->volume_stack, PATH_RAY_SHADOW); shader_eval_volume(kg, sd, state, state->volume_stack, PATH_RAY_SHADOW);
if (sd->flag & SD_EXTINCTION) { if (sd->flag & SD_EXTINCTION) {
*extinction = sd->closure_transparent_extinction; const float density = object_volume_density(kg, sd->object);
*extinction = sd->closure_transparent_extinction * density;
return true; return true;
} }
else { else {
@@ -84,6 +85,11 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals *kg,
} }
} }
const float density = object_volume_density(kg, sd->object);
coeff->sigma_s *= density;
coeff->sigma_t *= density;
coeff->emission *= density;
return true; return true;
} }

View File

@@ -145,7 +145,9 @@ Mesh::Mesh() : Geometry(node_type, Geometry::MESH), subd_attributes(this, ATTR_P
num_subd_verts = 0; num_subd_verts = 0;
volume_isovalue = 0.001f; volume_clipping = 0.001f;
volume_step_size = 0.0f;
volume_object_space = false;
num_ngons = 0; num_ngons = 0;

View File

@@ -133,7 +133,9 @@ class Mesh : public Geometry {
array<int> triangle_patch; /* must be < 0 for non subd triangles */ array<int> triangle_patch; /* must be < 0 for non subd triangles */
array<float2> vert_patch_uv; array<float2> vert_patch_uv;
float volume_isovalue; float volume_clipping;
float volume_step_size;
bool volume_object_space;
array<SubdFace> subd_faces; array<SubdFace> subd_faces;
array<int> subd_face_corners; array<int> subd_face_corners;

View File

@@ -450,7 +450,7 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress)
/* Build bounding mesh around non-empty volume cells. */ /* Build bounding mesh around non-empty volume cells. */
VolumeMeshBuilder builder(&volume_params); VolumeMeshBuilder builder(&volume_params);
const float isovalue = mesh->volume_isovalue; const float clipping = mesh->volume_clipping;
for (int z = 0; z < resolution.z; ++z) { for (int z = 0; z < resolution.z; ++z) {
for (int y = 0; y < resolution.y; ++y) { for (int y = 0; y < resolution.y; ++y) {
@@ -462,7 +462,7 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress)
const int channels = voxel_grid.channels; const int channels = voxel_grid.channels;
for (int c = 0; c < channels; c++) { for (int c = 0; c < channels; c++) {
if (voxel_grid.data[voxel_index * channels + c] >= isovalue) { if (voxel_grid.data[voxel_index * channels + c] >= clipping) {
builder.add_node_with_padding(x, y, z); builder.add_node_with_padding(x, y, z);
break; break;
} }

View File

@@ -270,14 +270,20 @@ uint Object::visibility_for_tracing() const
float Object::compute_volume_step_size() const float Object::compute_volume_step_size() const
{ {
if (!geometry->has_volume) { if (geometry->type != Geometry::MESH) {
return FLT_MAX;
}
Mesh *mesh = static_cast<Mesh *>(geometry);
if (!mesh->has_volume) {
return FLT_MAX; return FLT_MAX;
} }
/* Compute step rate from shaders. */ /* Compute step rate from shaders. */
float step_rate = FLT_MAX; float step_rate = FLT_MAX;
foreach (Shader *shader, geometry->used_shaders) { foreach (Shader *shader, mesh->used_shaders) {
if (shader->has_volume) { if (shader->has_volume) {
if ((shader->heterogeneous_volume && shader->has_volume_spatial_varying) || if ((shader->heterogeneous_volume && shader->has_volume_spatial_varying) ||
(shader->has_volume_attribute_dependency)) { (shader->has_volume_attribute_dependency)) {
@@ -293,7 +299,7 @@ float Object::compute_volume_step_size() const
/* Compute step size from voxel grids. */ /* Compute step size from voxel grids. */
float step_size = FLT_MAX; float step_size = FLT_MAX;
foreach (Attribute &attr, geometry->attributes.attributes) { foreach (Attribute &attr, mesh->attributes.attributes) {
if (attr.element == ATTR_ELEMENT_VOXEL) { if (attr.element == ATTR_ELEMENT_VOXEL) {
ImageHandle &handle = attr.data_voxel(); ImageHandle &handle = attr.data_voxel();
const ImageMetaData &metadata = handle.metadata(); const ImageMetaData &metadata = handle.metadata();
@@ -301,15 +307,26 @@ float Object::compute_volume_step_size() const
continue; continue;
} }
/* User specified step size. */
float voxel_step_size = mesh->volume_step_size;
if (voxel_step_size == 0.0f) {
/* Auto detect step size. */
float3 size = make_float3(
1.0f / metadata.width, 1.0f / metadata.height, 1.0f / metadata.depth);
/* Step size is transformed from voxel to world space. */ /* Step size is transformed from voxel to world space. */
Transform voxel_tfm = tfm; Transform voxel_tfm = tfm;
if (metadata.use_transform_3d) { if (metadata.use_transform_3d) {
voxel_tfm = tfm * transform_inverse(metadata.transform_3d); voxel_tfm = tfm * transform_inverse(metadata.transform_3d);
} }
voxel_step_size = min3(fabs(transform_direction(&voxel_tfm, size)));
float3 size = make_float3( }
1.0f / metadata.width, 1.0f / metadata.height, 1.0f / metadata.depth); else if (mesh->volume_object_space) {
float voxel_step_size = min3(fabs(transform_direction(&voxel_tfm, size))); /* User specified step size in object space. */
float3 size = make_float3(voxel_step_size, voxel_step_size, voxel_step_size);
voxel_step_size = min3(fabs(transform_direction(&tfm, size)));
}
if (voxel_step_size > 0.0f) { if (voxel_step_size > 0.0f) {
step_size = fminf(voxel_step_size, step_size); step_size = fminf(voxel_step_size, step_size);
@@ -352,12 +369,23 @@ static float object_surface_area(UpdateObjectTransformState *state,
return 0.0f; return 0.0f;
} }
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->has_volume) {
/* Volume density automatically adjust to object scale. */
if (mesh->volume_object_space) {
const float3 unit = normalize(make_float3(1.0f, 1.0f, 1.0f));
return 1.0f / len(transform_direction(&tfm, unit));
}
else {
return 1.0f;
}
}
/* Compute surface area. for uniform scale we can do avoid the many /* Compute surface area. for uniform scale we can do avoid the many
* transform calls and share computation for instances. * transform calls and share computation for instances.
* *
* TODO(brecht): Correct for displacement, and move to a better place. * TODO(brecht): Correct for displacement, and move to a better place.
*/ */
Mesh *mesh = static_cast<Mesh *>(geom);
float surface_area = 0.0f; float surface_area = 0.0f;
float uniform_scale; float uniform_scale;
if (transform_uniform_scale(tfm, uniform_scale)) { if (transform_uniform_scale(tfm, uniform_scale)) {

View File

@@ -108,6 +108,29 @@ class DATA_PT_volume_grids(DataButtonsPanel, Panel):
layout.template_list("VOLUME_UL_grids", "grids", volume, "grids", volume.grids, "active_index", rows=3) layout.template_list("VOLUME_UL_grids", "grids", volume, "grids", volume.grids, "active_index", rows=3)
class DATA_PT_volume_render(DataButtonsPanel, Panel):
bl_label = "Render"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = context.scene
volume = context.volume
render = volume.render
col = layout.column(align=True)
col.prop(render, "space")
if scene.render.engine == 'CYCLES':
col.prop(render, "step_size")
col = layout.column(align=True)
col.prop(render, "clipping")
class DATA_PT_volume_viewport_display(DataButtonsPanel, Panel): class DATA_PT_volume_viewport_display(DataButtonsPanel, Panel):
bl_label = "Viewport Display" bl_label = "Viewport Display"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@@ -140,6 +163,7 @@ classes = (
DATA_PT_volume_grids, DATA_PT_volume_grids,
DATA_PT_volume_file, DATA_PT_volume_file,
DATA_PT_volume_viewport_display, DATA_PT_volume_viewport_display,
DATA_PT_volume_render,
DATA_PT_custom_props_volume, DATA_PT_custom_props_volume,
VOLUME_UL_grids, VOLUME_UL_grids,
) )

View File

@@ -65,6 +65,10 @@ void BKE_volume_grid_wireframe(const struct Volume *volume,
BKE_volume_wireframe_cb cb, BKE_volume_wireframe_cb cb,
void *cb_userdata); void *cb_userdata);
/* Render */
float BKE_volume_density_scale(const struct Volume *volume, const float matrix[4][4]);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -356,3 +356,18 @@ void BKE_volume_grid_wireframe(const Volume *volume,
cb(cb_userdata, NULL, NULL, 0, 0); cb(cb_userdata, NULL, NULL, 0, 0);
#endif #endif
} }
/* Render */
float BKE_volume_density_scale(const Volume *volume, const float matrix[4][4])
{
if (volume->render.space == VOLUME_SPACE_OBJECT) {
float unit[3] = {1.0f, 1.0f, 1.0f};
normalize_v3(unit);
mul_mat3_m4_v3(matrix, unit);
return 1.0f / len_v3(unit);
}
else {
return 1.0f;
}
}

View File

@@ -451,6 +451,10 @@ static bool eevee_volume_object_grids_init(Object *ob, ListBase *gpu_grids, DRWS
DRW_shgroup_uniform_vec3_copy(grp, "volumeOrcoLoc", (float[3]){0.5f, 0.5f, 0.5f}); DRW_shgroup_uniform_vec3_copy(grp, "volumeOrcoLoc", (float[3]){0.5f, 0.5f, 0.5f});
DRW_shgroup_uniform_vec3_copy(grp, "volumeOrcoSize", (float[3]){0.5f, 0.5f, 0.5f}); DRW_shgroup_uniform_vec3_copy(grp, "volumeOrcoSize", (float[3]){0.5f, 0.5f, 0.5f});
/* Set density scale. */
const float density_scale = BKE_volume_density_scale(volume, ob->obmat);
DRW_shgroup_uniform_float_copy(grp, "volumeDensityScale", density_scale);
/* Bind volume grid textures. */ /* Bind volume grid textures. */
LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) { LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) {
VolumeGrid *volume_grid = BKE_volume_grid_find(volume, gpu_grid->name); VolumeGrid *volume_grid = BKE_volume_grid_find(volume, gpu_grid->name);

View File

@@ -8,6 +8,7 @@
uniform vec3 volumeOrcoLoc; uniform vec3 volumeOrcoLoc;
uniform vec3 volumeOrcoSize; uniform vec3 volumeOrcoSize;
uniform mat4 volumeObjectToTexture; uniform mat4 volumeObjectToTexture;
uniform float volumeDensityScale = 1.0;
#endif #endif
flat in int slice; flat in int slice;
@@ -52,6 +53,12 @@ void main()
Closure cl = nodetree_exec(); Closure cl = nodetree_exec();
#endif #endif
#ifdef MESH_SHADER
cl.scatter *= volumeDensityScale;
cl.absorption *= volumeDensityScale;
cl.emission *= volumeDensityScale;
#endif
volumeScattering = vec4(cl.scatter, 1.0); volumeScattering = vec4(cl.scatter, 1.0);
volumeExtinction = vec4(cl.absorption + cl.scatter, 1.0); volumeExtinction = vec4(cl.absorption + cl.scatter, 1.0);
volumeEmissive = vec4(cl.emission, 1.0); volumeEmissive = vec4(cl.emission, 1.0);

View File

@@ -229,7 +229,8 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata,
step_length = len_v3(slice_ct); step_length = len_v3(slice_ct);
/* Compute density scale. */ /* Compute density scale. */
const float density_scale = volume->display.density; const float density_scale = volume->display.density *
BKE_volume_density_scale(volume, ob->obmat);
/* Set uniforms. */ /* Set uniforms. */
DRWShadingGroup *grp = DRW_shgroup_create(sh, vedata->psl->volume_ps); DRWShadingGroup *grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);