Files
test2/intern/cycles/kernel/geom/volume.h
Brecht Van Lommel 646dc7fe4d Cycles: Use stochastic sampling to speed up tricubic volume filter
Stochastically turn a tricubic filter into a trilinear one. This
reduces the number of taps from 64 to 8. It combines ideas from
the "Stochastic Texture Filtering" paper and our previous GPU
sampling of 3D textures.

This is currently only used in a few places where we know stochastic
interpolation is valid or close enough in practice.
* Principled volume density, color and temperature
* Motion blur velocity

On an Macbook Pro M3 with the openvdb_smoke.blend regression test
and cubic sampling, this gives a ~2x speedup for CPU and ~4x speedup
for GPU. However it also increases noise, usually only a little. Equal
time renders for this scene show a clear reduction in noise for both
CPU and GPU.

Note we can probably get a bigger speedup with acceptable noise trade-off
using full stochastic sampling, but will investigate that separately.

Pull Request: https://projects.blender.org/blender/blender/pulls/132908
2025-07-09 21:04:38 +02:00

106 lines
3.3 KiB
C++

/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
/* Volume Primitive
*
* Volumes are just regions inside meshes with the mesh surface as boundaries.
* There isn't as much data to access as for surfaces, there is only a position
* to do lookups in 3D voxel or procedural textures.
*
* 3D voxel textures can be assigned as attributes per mesh, which means the
* same shader can be used for volume objects with different densities, etc. */
#pragma once
#include "kernel/globals.h"
#include "kernel/geom/attribute.h"
#include "kernel/geom/object.h"
#include "kernel/sample/lcg.h"
#include "kernel/util/texture_3d.h"
CCL_NAMESPACE_BEGIN
#ifdef __VOLUME__
/* Return position normalized to 0..1 in mesh bounds */
ccl_device_inline float3 volume_normalized_position(KernelGlobals kg,
const ccl_private ShaderData *sd,
float3 P)
{
/* todo: optimize this so it's just a single matrix multiplication when
* possible (not motion blur), or perhaps even just translation + scale */
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM);
object_inverse_position_transform(kg, sd, &P);
if (desc.offset != ATTR_STD_NOT_FOUND) {
const Transform tfm = primitive_attribute_matrix(kg, desc);
P = transform_point(&tfm, P);
}
return P;
}
template<typename T> ccl_device_inline T volume_attribute_value(const float4 value);
ccl_device_template_spec float volume_attribute_value(const float4 value)
{
return average(make_float3(value));
}
ccl_device_template_spec float2 volume_attribute_value(const float4 /*value*/)
{
kernel_assert(!"Float2 attribute not supported for volumes");
return zero_float2();
}
ccl_device_template_spec float3 volume_attribute_value(const float4 value)
{
if (value.w > 1e-6f && value.w != 1.0f) {
/* For RGBA colors, unpremultiply after interpolation. */
return make_float3(value) / value.w;
}
return make_float3(value);
}
ccl_device_template_spec float4 volume_attribute_value(const float4 value)
{
return value;
}
ccl_device float volume_attribute_alpha(const float4 value)
{
return value.w;
}
ccl_device float4 volume_attribute_float4(KernelGlobals kg,
ccl_private ShaderData *sd,
const AttributeDescriptor desc,
const bool stochastic)
{
if (desc.element & (ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
return kernel_data_fetch(attributes_float4, desc.offset);
}
if (desc.element == ATTR_ELEMENT_VOXEL) {
/* todo: optimize this so we don't have to transform both here and in
* kernel_tex_image_interp_3d when possible. Also could optimize for the
* common case where transform is translation/scale only. */
float3 P = sd->P;
object_inverse_position_transform(kg, sd, &P);
const InterpolationType interp = (sd->flag & SD_VOLUME_CUBIC) ? INTERPOLATION_CUBIC :
INTERPOLATION_NONE;
return kernel_tex_image_interp_3d(
kg, desc.offset, P, interp, (stochastic) ? lcg_step_float(&sd->lcg_state) : -1.0f);
}
return zero_float4();
}
#endif
CCL_NAMESPACE_END