From 646dc7fe4d7e65b77765c0c2019f1a76038aec6b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 11 Jan 2025 04:42:13 +0100 Subject: [PATCH] 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 --- intern/cycles/kernel/geom/primitive.h | 7 +- intern/cycles/kernel/geom/volume.h | 10 +- .../cycles/kernel/integrator/shade_volume.h | 14 + .../cycles/kernel/integrator/volume_shader.h | 4 +- intern/cycles/kernel/osl/services.cpp | 6 +- intern/cycles/kernel/osl/services_gpu.h | 6 +- intern/cycles/kernel/svm/attribute.h | 2 +- intern/cycles/kernel/svm/closure.h | 6 +- intern/cycles/kernel/util/texture_3d.h | 285 +++++++++++++----- .../render/openvdb/cycles_renders/fire.png | 4 +- .../openvdb/cycles_renders/smoke_color.png | 4 +- .../openvdb/cycles_renders/smoke_fire.png | 4 +- 12 files changed, 256 insertions(+), 96 deletions(-) diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h index 1141bcbe54b..0ee6483800d 100644 --- a/intern/cycles/kernel/geom/primitive.h +++ b/intern/cycles/kernel/geom/primitive.h @@ -84,11 +84,12 @@ ccl_device_forceinline bool primitive_is_volume_attribute(const ccl_private Shad template ccl_device_inline T primitive_volume_attribute(KernelGlobals kg, - const ccl_private ShaderData *sd, - const AttributeDescriptor desc) + ccl_private ShaderData *sd, + const AttributeDescriptor desc, + const bool stochastic) { if (primitive_is_volume_attribute(sd)) { - return volume_attribute_value(volume_attribute_float4(kg, sd, desc)); + return volume_attribute_value(volume_attribute_float4(kg, sd, desc, stochastic)); } return make_zero(); } diff --git a/intern/cycles/kernel/geom/volume.h b/intern/cycles/kernel/geom/volume.h index 4949c411ab1..1b3a3f1f625 100644 --- a/intern/cycles/kernel/geom/volume.h +++ b/intern/cycles/kernel/geom/volume.h @@ -18,6 +18,8 @@ #include "kernel/geom/attribute.h" #include "kernel/geom/object.h" +#include "kernel/sample/lcg.h" + #include "kernel/util/texture_3d.h" CCL_NAMESPACE_BEGIN @@ -77,8 +79,9 @@ ccl_device float volume_attribute_alpha(const float4 value) } ccl_device float4 volume_attribute_float4(KernelGlobals kg, - const ccl_private ShaderData *sd, - const AttributeDescriptor desc) + 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); @@ -91,7 +94,8 @@ ccl_device float4 volume_attribute_float4(KernelGlobals kg, 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); + return kernel_tex_image_interp_3d( + kg, desc.offset, P, interp, (stochastic) ? lcg_step_float(&sd->lcg_state) : -1.0f); } return zero_float4(); } diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index 0b02c806fb9..c840324c1eb 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -21,6 +21,8 @@ #include "kernel/geom/shader_data.h" +#include "kernel/sample/lcg.h" + CCL_NAMESPACE_BEGIN #ifdef __VOLUME__ @@ -220,6 +222,12 @@ ccl_device void volume_shadow_heterogeneous(KernelGlobals kg, RNGState rng_state; shadow_path_state_rng_load(state, &rng_state); + /* For stochastic texture sampling. */ + sd->lcg_state = lcg_state_init(INTEGRATOR_STATE(state, shadow_path, rng_pixel), + INTEGRATOR_STATE(state, shadow_path, rng_offset), + INTEGRATOR_STATE(state, shadow_path, sample), + 0xd9111870); + Spectrum tp = *throughput; /* Prepare for stepping. */ @@ -988,6 +996,12 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, RNGState rng_state; path_state_rng_load(state, &rng_state); + /* For stochastic texture sampling. */ + sd.lcg_state = lcg_state_init(INTEGRATOR_STATE(state, path, rng_pixel), + INTEGRATOR_STATE(state, path, rng_offset), + INTEGRATOR_STATE(state, path, sample), + 0x15b4f88d); + /* Sample light ahead of volume stepping, for equiangular sampling. */ /* TODO: distant lights are ignored now, but could instead use even distribution. */ LightSample ls ccl_optional_struct_init; diff --git a/intern/cycles/kernel/integrator/volume_shader.h b/intern/cycles/kernel/integrator/volume_shader.h index b5fdc90877c..6c7a44fb498 100644 --- a/intern/cycles/kernel/integrator/volume_shader.h +++ b/intern/cycles/kernel/integrator/volume_shader.h @@ -409,14 +409,14 @@ ccl_device_inline void volume_shader_motion_blur(KernelGlobals kg, */ /* Find velocity. */ - float3 velocity = primitive_volume_attribute(kg, sd, v_desc); + float3 velocity = primitive_volume_attribute(kg, sd, v_desc, true); object_dir_transform(kg, sd, &velocity); /* Find advected P. */ sd->P = P - (time - time_offset) * velocity_scale * velocity; /* Find advected velocity. */ - velocity = primitive_volume_attribute(kg, sd, v_desc); + velocity = primitive_volume_attribute(kg, sd, v_desc, true); object_dir_transform(kg, sd, &velocity); /* Find advected P. */ diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp index 595fd817b7b..3b649be9f1c 100644 --- a/intern/cycles/kernel/osl/services.cpp +++ b/intern/cycles/kernel/osl/services.cpp @@ -657,7 +657,7 @@ inline bool get_object_attribute_impl(const ThreadKernelGlobalsCPU *kg, T dy = make_zero(); #ifdef __VOLUME__ if (primitive_is_volume_attribute(sd)) { - v = primitive_volume_attribute(kg, sd, desc); + v = primitive_volume_attribute(kg, sd, desc, false); } else #endif @@ -1345,9 +1345,11 @@ bool OSLRenderServices::texture3d(OSLUStringHash filename, switch (texture_type) { case OSLTextureHandle::SVM: { /* Packed texture. */ + ShaderData *sd = globals->sd; const int slot = handle->svm_slots[0].y; const float3 P_float3 = make_float3(P.x, P.y, P.z); - float4 rgba = kernel_tex_image_interp_3d(kernel_globals, slot, P_float3, INTERPOLATION_NONE); + float4 rgba = kernel_tex_image_interp_3d( + kernel_globals, slot, P_float3, INTERPOLATION_NONE, lcg_step_float(&sd->lcg_state)); result[0] = rgba[0]; if (nchannels > 1) { diff --git a/intern/cycles/kernel/osl/services_gpu.h b/intern/cycles/kernel/osl/services_gpu.h index 532531e6414..41c9d57caea 100644 --- a/intern/cycles/kernel/osl/services_gpu.h +++ b/intern/cycles/kernel/osl/services_gpu.h @@ -764,7 +764,7 @@ ccl_device_inline bool get_object_attribute_impl(KernelGlobals kg, T dy = make_zero(); #ifdef __VOLUME__ if (primitive_is_volume_attribute(sd)) { - v = primitive_volume_attribute(kg, sd, desc); + v = primitive_volume_attribute(kg, sd, desc, false); } else #endif @@ -1147,7 +1147,9 @@ ccl_device_extern bool rs_texture3d(ccl_private ShaderGlobals *sg, switch (type) { case OSL_TEXTURE_HANDLE_TYPE_SVM: { - const float4 rgba = kernel_tex_image_interp_3d(nullptr, slot, *P, INTERPOLATION_NONE); + ccl_private ShaderData *const sd = static_cast(sg->renderstate); + const float4 rgba = kernel_tex_image_interp_3d( + nullptr, slot, *P, INTERPOLATION_NONE, lcg_step_float(&sd->lcg_state)); if (nchannels > 0) { result[0] = rgba.x; } diff --git a/intern/cycles/kernel/svm/attribute.h b/intern/cycles/kernel/svm/attribute.h index 0d6611dabbc..01192d98ea8 100644 --- a/intern/cycles/kernel/svm/attribute.h +++ b/intern/cycles/kernel/svm/attribute.h @@ -65,7 +65,7 @@ ccl_device_noinline void svm_node_attr(KernelGlobals kg, /* Volumes * NOTE: moving this into its own node type might help improve performance. */ if (primitive_is_volume_attribute(sd)) { - const float4 value = volume_attribute_float4(kg, sd, desc); + const float4 value = volume_attribute_float4(kg, sd, desc, false); if (type == NODE_ATTR_OUTPUT_FLOAT) { const float f = volume_attribute_value(value); diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index adf6cb40ab4..4e1e472135e 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -1272,7 +1272,7 @@ ccl_device_noinline int svm_node_principled_volume(KernelGlobals kg, /* Density and color attribute lookup if available. */ const AttributeDescriptor attr_density = find_attribute(kg, sd, attr_node.x); if (attr_density.offset != ATTR_STD_NOT_FOUND) { - primitive_density = primitive_volume_attribute(kg, sd, attr_density); + primitive_density = primitive_volume_attribute(kg, sd, attr_density, true); density = fmaxf(density * primitive_density, 0.0f); } } @@ -1283,7 +1283,7 @@ ccl_device_noinline int svm_node_principled_volume(KernelGlobals kg, const AttributeDescriptor attr_color = find_attribute(kg, sd, attr_node.y); if (attr_color.offset != ATTR_STD_NOT_FOUND) { - color *= rgb_to_spectrum(primitive_volume_attribute(kg, sd, attr_color)); + color *= rgb_to_spectrum(primitive_volume_attribute(kg, sd, attr_color, true)); } /* Add closure for volume scattering. */ @@ -1338,7 +1338,7 @@ ccl_device_noinline int svm_node_principled_volume(KernelGlobals kg, /* Add flame temperature from attribute if available. */ const AttributeDescriptor attr_temperature = find_attribute(kg, sd, attr_node.z); if (attr_temperature.offset != ATTR_STD_NOT_FOUND) { - const float temperature = primitive_volume_attribute(kg, sd, attr_temperature); + const float temperature = primitive_volume_attribute(kg, sd, attr_temperature, true); T *= fmaxf(temperature, 0.0f); } diff --git a/intern/cycles/kernel/util/texture_3d.h b/intern/cycles/kernel/util/texture_3d.h index 9c6e932016a..4e4067e3bb8 100644 --- a/intern/cycles/kernel/util/texture_3d.h +++ b/intern/cycles/kernel/util/texture_3d.h @@ -5,6 +5,7 @@ #pragma once #include "kernel/globals.h" +#include "util/texture.h" #if !defined(__KERNEL_METAL__) && !defined(__KERNEL_ONEAPI__) # ifdef WITH_NANOVDB @@ -20,65 +21,203 @@ CCL_NAMESPACE_BEGIN namespace { #endif -ccl_device_inline float interp_frac(const float x, ccl_private int *ix) +#ifdef WITH_NANOVDB +/* Stochastically turn a tricubic filter into a trilinear filter. */ +ccl_device_inline float3 interp_tricubic_to_trilinear_stochastic(const float3 P, float randu) { - int i = float_to_int(x) - ((x < 0.0f) ? 1 : 0); - *ix = i; - return x - (float)i; + /* Some optimizations possible: + * - Could use select() for SIMD if we split the random number into 10 + * bits each and use that for each dimensions. + * - For GPU would be better not to compute P0 and P1 for all dimensions + * in advance? + * - 1/g0 and 1/(1 - g0) are computed twice. + */ + + const float3 p = floor(P); + const float3 t = P - p; + + /* Cubic weights. */ + const float3 w0 = (1.0f / 6.0f) * (t * (t * (-t + 3.0f) - 3.0f) + 1.0f); + const float3 w1 = (1.0f / 6.0f) * (t * t * (3.0f * t - 6.0f) + 4.0f); + // float3 w2 = (1.0f / 6.0f) * (t * (t * (-3.0f * t + 3.0f) + 3.0f) + 1.0f); + const float3 w3 = (1.0f / 6.0f) * (t * t * t); + + const float3 g0 = w0 + w1; + const float3 P0 = p + (w1 / g0) - 1.0f; + const float3 P1 = p + (w3 / (make_float3(1.0f) - g0)) + 1.0f; + + float3 Pnew = P0; + + if (randu < g0.x) { + randu /= g0.x; + } + else { + Pnew.x = P1.x; + randu = (randu - g0.x) / (1 - g0.x); + } + + if (randu < g0.y) { + randu /= g0.y; + } + else { + Pnew.y = P1.y; + randu = (randu - g0.y) / (1 - g0.y); + } + + if (randu < g0.z) { + } + else { + Pnew.z = P1.z; + } + + return Pnew; } -#ifdef WITH_NANOVDB +/* From "Stochastic Texture Filtering": https://arxiv.org/abs/2305.05810 + * + * Could be used in specific situations where we are certain a single + * tap is enough. Maybe better to try optimizing bilinear lookups in + * NanoVDB (detect when fully inside a single leaf) than deal with this. */ + +# if 0 +ccl_device int3 interp_tricubic_stochastic(const float3 P, float randu) +{ + const float ix = floorf(P.x); + const float iy = floorf(P.y); + const float iz = floorf(P.z); + const float deltas[3] = {P.x - ix, P.y - iy, P.z - iz}; + int idx[3] = {(int)ix - 1, (int)iy - 1, (int)iz - 1}; + + for (int i = 0; i < 3; i++) { + const float t = deltas[i]; + const float t2 = t * t; + + /* Weighted reservoir sampling, first tap always accepted */ + const float w0 = (1.0f / 6.0f) * (-t * t2 + 3 * t2 - 3 * t + 1); + float sumWt = w0; + int index = 0; + + /* TODO: reduce number of divisions? */ + + /* Sample the other 3 filter taps. */ + { + const float w1 = (1.0f / 6.0f) * (3 * t * t2 - 6 * t2 + 4); + sumWt += w1; + const float p = w1 / sumWt; + if (randu < p) { + index = 1; + randu /= p; + } + else { + randu = (randu - p) / (1 - p); + } + } + + { + const float w2 = (1.0f / 6.0f) * (-3 * t * t2 + 3 * t2 + 3 * t + 1); + sumWt += w2; + const float p = w2 / sumWt; + if (randu < p) { + index = 2; + randu /= p; + } + else { + randu = (randu - p) / (1 - p); + } + } + + { + const float w3 = (1.0f / 6.0f) * t * t2; + sumWt += w3; + const float p = w3 / sumWt; + if (randu < p) { + index = 3; + randu /= p; + } + else { + randu = (randu - p) / (1 - p); + } + } + + idx[i] += index; + } + + return make_int3(idx[0], idx[1], idx[2]); +} + +ccl_device int3 interp_trilinear_stochastic(const float3 P, float randu) +{ + const float ix = floorf(P.x); + const float iy = floorf(P.y); + const float iz = floorf(P.z); + int idx[3] = {(int)ix, (int)iy, (int)iz}; + + const float tx = P.x - ix; + const float ty = P.y - iy; + const float tz = P.z - iz; + + if (randu < tx) { + idx[0]++; + randu /= tx; + } + else { + randu = (randu - tx) / (1 - tx); + } + + if (randu < ty) { + idx[1]++; + randu /= ty; + } + else { + randu = (randu - ty) / (1 - ty); + } + + if (randu < tz) { + idx[2]++; + } + + return make_int3(idx[0], idx[1], idx[2]); +} +# endif + template ccl_device OutT kernel_tex_image_interp_trilinear_nanovdb(ccl_private Acc &acc, const float3 P) { - int ix, iy, iz; - const float tx = interp_frac(P.x - 0.5f, &ix); - const float ty = interp_frac(P.y - 0.5f, &iy); - const float tz = interp_frac(P.z - 0.5f, &iz); + const float3 floor_P = floor(P); + const float3 t = P - floor_P; + const int3 index = make_int3(floor_P); + + const int ix = index.x; + const int iy = index.y; + const int iz = index.z; return mix(mix(mix(OutT(acc.getValue(make_int3(ix, iy, iz))), OutT(acc.getValue(make_int3(ix, iy, iz + 1))), - tz), + t.z), mix(OutT(acc.getValue(make_int3(ix, iy + 1, iz + 1))), OutT(acc.getValue(make_int3(ix, iy + 1, iz))), - 1.0f - tz), - ty), + 1.0f - t.z), + t.y), mix(mix(OutT(acc.getValue(make_int3(ix + 1, iy + 1, iz))), OutT(acc.getValue(make_int3(ix + 1, iy + 1, iz + 1))), - tz), + t.z), mix(OutT(acc.getValue(make_int3(ix + 1, iy, iz + 1))), OutT(acc.getValue(make_int3(ix + 1, iy, iz))), - 1.0f - tz), - 1.0f - ty), - tx); + 1.0f - t.z), + 1.0f - t.y), + t.x); } template ccl_device OutT kernel_tex_image_interp_tricubic_nanovdb(ccl_private Acc &acc, const float3 P) { - int ix, iy, iz; - int nix, niy, niz; - int pix, piy, piz; - int nnix, nniy, nniz; + const float3 floor_P = floor(P); + const float3 t = P - floor_P; + const int3 index = make_int3(floor_P); - /* A -0.5 offset is used to center the cubic samples around the sample point. */ - const float tx = interp_frac(P.x - 0.5f, &ix); - const float ty = interp_frac(P.y - 0.5f, &iy); - const float tz = interp_frac(P.z - 0.5f, &iz); - - pix = ix - 1; - piy = iy - 1; - piz = iz - 1; - nix = ix + 1; - niy = iy + 1; - niz = iz + 1; - nnix = ix + 2; - nniy = iy + 2; - nniz = iz + 2; - - const int xc[4] = {pix, ix, nix, nnix}; - const int yc[4] = {piy, iy, niy, nniy}; - const int zc[4] = {piz, iz, niz, nniz}; + const int xc[4] = {index.x - 1, index.x, index.x + 1, index.x + 2}; + const int yc[4] = {index.y - 1, index.y, index.y + 1, index.y + 2}; + const int zc[4] = {index.z - 1, index.z, index.z + 1, index.z + 2}; float u[4], v[4], w[4]; /* Some helper macros to keep code size reasonable. @@ -100,9 +239,9 @@ ccl_device OutT kernel_tex_image_interp_tricubic_nanovdb(ccl_private Acc &acc, c # define ROW_TERM(row) \ (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row))) - SET_CUBIC_SPLINE_WEIGHTS(u, tx); - SET_CUBIC_SPLINE_WEIGHTS(v, ty); - SET_CUBIC_SPLINE_WEIGHTS(w, tz); + SET_CUBIC_SPLINE_WEIGHTS(u, t.x); + SET_CUBIC_SPLINE_WEIGHTS(v, t.y); + SET_CUBIC_SPLINE_WEIGHTS(w, t.z); /* Actual interpolation. */ return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3); @@ -113,56 +252,54 @@ ccl_device OutT kernel_tex_image_interp_tricubic_nanovdb(ccl_private Acc &acc, c # undef SET_CUBIC_SPLINE_WEIGHTS } +template # if defined(__KERNEL_METAL__) -template -__attribute__((noinline)) OutT kernel_tex_image_interp_nanovdb(const ccl_global TextureInfo &info, - const float3 P, - const InterpolationType interp) +__attribute__((noinline)) # else -template -ccl_device_noinline OutT kernel_tex_image_interp_nanovdb(const ccl_global TextureInfo &info, - const float3 P, - const InterpolationType interp) +ccl_device_noinline # endif +OutT kernel_tex_image_interp_nanovdb(const ccl_global TextureInfo &info, + float3 P, + const InterpolationType interp) { - using namespace nanovdb; + ccl_global nanovdb::NanoGrid *const grid = (ccl_global nanovdb::NanoGrid *)info.data; - ccl_global NanoGrid *const grid = (ccl_global NanoGrid *)info.data; - - switch (interp) { - case INTERPOLATION_CLOSEST: { - ReadAccessor acc(grid->tree().root()); - return OutT(acc.getValue(make_int3(floor(P)))); - } - case INTERPOLATION_LINEAR: { - CachedReadAccessor acc(grid->tree().root()); - return kernel_tex_image_interp_trilinear_nanovdb(acc, P); - } - default: { - CachedReadAccessor acc(grid->tree().root()); - return kernel_tex_image_interp_tricubic_nanovdb(acc, P); - } + if (interp == INTERPOLATION_CLOSEST) { + nanovdb::ReadAccessor acc(grid->tree().root()); + return OutT(acc.getValue(make_int3(floor(P)))); } + + nanovdb::CachedReadAccessor acc(grid->tree().root()); + if (interp == INTERPOLATION_LINEAR) { + return kernel_tex_image_interp_trilinear_nanovdb(acc, P); + } + + return kernel_tex_image_interp_tricubic_nanovdb(acc, P); } #endif /* WITH_NANOVDB */ -ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg, - const int id, - float3 P, - InterpolationType interp) +ccl_device float4 kernel_tex_image_interp_3d( + KernelGlobals kg, const int id, float3 P, InterpolationType interp, const float randu) { +#ifdef WITH_NANOVDB const ccl_global TextureInfo &info = kernel_data_fetch(texture_info, id); if (info.use_transform_3d) { P = transform_point(&info.transform_3d, P); } - const InterpolationType interpolation = (interp == INTERPOLATION_NONE) ? - (InterpolationType)info.interpolation : - interp; - const ImageDataType data_type = (ImageDataType)info.data_type; + InterpolationType interpolation = (interp == INTERPOLATION_NONE) ? + (InterpolationType)info.interpolation : + interp; -#ifdef WITH_NANOVDB + /* A -0.5 offset is used to center the cubic samples around the sample point. */ + P = P - make_float3(0.5f); + if (interpolation == INTERPOLATION_CUBIC && randu >= 0.0f) { + P = interp_tricubic_to_trilinear_stochastic(P, randu); + interpolation = INTERPOLATION_LINEAR; + } + + const ImageDataType data_type = (ImageDataType)info.data_type; if (data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT) { const float f = kernel_tex_image_interp_nanovdb(info, P, interpolation); return make_float4(f, f, f, 1.0f); diff --git a/tests/files/render/openvdb/cycles_renders/fire.png b/tests/files/render/openvdb/cycles_renders/fire.png index 4942229b837..6e9c9f0081e 100644 --- a/tests/files/render/openvdb/cycles_renders/fire.png +++ b/tests/files/render/openvdb/cycles_renders/fire.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:09bd8c4b2d1eb0d030196780084508b99e46bca7c4f649b4e0cf9d026ae54730 -size 38986 +oid sha256:66ef9339c46ddc5d3bf0aa61c7437610a02a95974b73abc7e10ce1f567eda734 +size 39043 diff --git a/tests/files/render/openvdb/cycles_renders/smoke_color.png b/tests/files/render/openvdb/cycles_renders/smoke_color.png index 42c6b5d5cb8..6e5d35d3165 100644 --- a/tests/files/render/openvdb/cycles_renders/smoke_color.png +++ b/tests/files/render/openvdb/cycles_renders/smoke_color.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0897e3a60632d0e2d82abaa494262b31eecf945069a489f5de4304785e562e82 -size 28034 +oid sha256:7dff2bee0a44eb316e1eb9ccf90de929237d88f5b9e1e09d8b4be49224266e92 +size 325 diff --git a/tests/files/render/openvdb/cycles_renders/smoke_fire.png b/tests/files/render/openvdb/cycles_renders/smoke_fire.png index 079cbcdb26c..705ca530336 100644 --- a/tests/files/render/openvdb/cycles_renders/smoke_fire.png +++ b/tests/files/render/openvdb/cycles_renders/smoke_fire.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80781598a001106cd8aff375829a4dd4003a9aae1ee3f0c2314d707d56ced6f6 -size 38727 +oid sha256:2e81e1670742c07ceee4736b9828b7284f735a4b26e8dcd441a7ef511560e1c4 +size 325