Cycles: support for different 3D transform per volume grid

This is not yet fully supported by automatic volume bounds but works fine in
most cases that will have mostly matching bounds.

Ref T73201
This commit is contained in:
Brecht Van Lommel 2020-03-17 16:48:00 +01:00
parent fd53b72871
commit 006025ead0
Notes: blender-bot 2023-02-14 06:00:49 +01:00
Referenced by issue #73201, New volume object type
11 changed files with 92 additions and 34 deletions

View File

@ -15,6 +15,7 @@
*/
#include "render/colorspace.h"
#include "render/image.h"
#include "render/mesh.h"
#include "render/object.h"
@ -68,6 +69,15 @@ class BlenderSmokeLoader : public ImageLoader {
metadata.height = resolution.y * amplify;
metadata.depth = resolution.z * amplify;
/* Create a matrix to transform from object space to mesh texture space.
* This does not work with deformations but that can probably only be done
* well with a volume grid mapping of coordinates. */
BL::Mesh b_mesh(b_ob.data());
float3 loc, size;
mesh_texture_space(b_mesh, loc, size);
metadata.transform_3d = transform_translate(-loc) * transform_scale(size);
metadata.use_transform_3d = true;
return true;
}

View File

@ -51,10 +51,14 @@ ccl_device float volume_attribute_float(KernelGlobals *kg,
const ShaderData *sd,
const AttributeDescriptor desc)
{
float3 P = volume_normalized_position(kg, sd, sd->P);
/* 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);
InterpolationType interp = (sd->flag & SD_VOLUME_CUBIC) ? INTERPOLATION_CUBIC :
INTERPOLATION_NONE;
float4 r = kernel_tex_image_interp_3d(kg, desc.offset, P.x, P.y, P.z, interp);
float4 r = kernel_tex_image_interp_3d(kg, desc.offset, P, interp);
return average(float4_to_float3(r));
}
@ -62,10 +66,11 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg,
const ShaderData *sd,
const AttributeDescriptor desc)
{
float3 P = volume_normalized_position(kg, sd, sd->P);
float3 P = sd->P;
object_inverse_position_transform(kg, sd, &P);
InterpolationType interp = (sd->flag & SD_VOLUME_CUBIC) ? INTERPOLATION_CUBIC :
INTERPOLATION_NONE;
float4 r = kernel_tex_image_interp_3d(kg, desc.offset, P.x, P.y, P.z, interp);
float4 r = kernel_tex_image_interp_3d(kg, desc.offset, P, interp);
if (r.w > 1e-6f && r.w != 1.0f) {
/* For RGBA colors, unpremultiply after interpolation. */

View File

@ -498,28 +498,34 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl
}
}
ccl_device float4 kernel_tex_image_interp_3d(
KernelGlobals *kg, int id, float x, float y, float z, InterpolationType interp)
ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg,
int id,
float3 P,
InterpolationType interp)
{
const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
if (info.use_transform_3d) {
P = transform_point(&info.transform_3d, P);
}
switch (info.data_type) {
case IMAGE_DATA_TYPE_HALF:
return TextureInterpolator<half>::interp_3d(info, x, y, z, interp);
return TextureInterpolator<half>::interp_3d(info, P.x, P.y, P.z, interp);
case IMAGE_DATA_TYPE_BYTE:
return TextureInterpolator<uchar>::interp_3d(info, x, y, z, interp);
return TextureInterpolator<uchar>::interp_3d(info, P.x, P.y, P.z, interp);
case IMAGE_DATA_TYPE_USHORT:
return TextureInterpolator<uint16_t>::interp_3d(info, x, y, z, interp);
return TextureInterpolator<uint16_t>::interp_3d(info, P.x, P.y, P.z, interp);
case IMAGE_DATA_TYPE_FLOAT:
return TextureInterpolator<float>::interp_3d(info, x, y, z, interp);
return TextureInterpolator<float>::interp_3d(info, P.x, P.y, P.z, interp);
case IMAGE_DATA_TYPE_HALF4:
return TextureInterpolator<half4>::interp_3d(info, x, y, z, interp);
return TextureInterpolator<half4>::interp_3d(info, P.x, P.y, P.z, interp);
case IMAGE_DATA_TYPE_BYTE4:
return TextureInterpolator<uchar4>::interp_3d(info, x, y, z, interp);
return TextureInterpolator<uchar4>::interp_3d(info, P.x, P.y, P.z, interp);
case IMAGE_DATA_TYPE_USHORT4:
return TextureInterpolator<ushort4>::interp_3d(info, x, y, z, interp);
return TextureInterpolator<ushort4>::interp_3d(info, P.x, P.y, P.z, interp);
case IMAGE_DATA_TYPE_FLOAT4:
return TextureInterpolator<float4>::interp_3d(info, x, y, z, interp);
return TextureInterpolator<float4>::interp_3d(info, P.x, P.y, P.z, interp);
default:
assert(0);
return make_float4(

View File

@ -149,10 +149,21 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl
}
}
ccl_device float4 kernel_tex_image_interp_3d(
KernelGlobals *kg, int id, float x, float y, float z, InterpolationType interp)
ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg,
int id,
float3 P,
InterpolationType interp)
{
const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
if (info.use_transform_3d) {
P = transform_point(&info.transform_3d, P);
}
const float x = P.x;
const float y = P.y;
const float z = P.z;
CUtexObject tex = (CUtexObject)info.data;
uint interpolation = (interp == INTERPOLATION_NONE) ? info.interpolation : interp;

View File

@ -202,11 +202,19 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl
}
}
ccl_device float4
kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x, float y, float z, int interp)
ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float3 P, int interp)
{
const ccl_global TextureInfo *info = kernel_tex_info(kg, id);
if (info->use_transform_3d) {
Transform tfm = info->transform_3d;
P = transform_point(&tfm, P);
}
const float x = P.x;
const float y = P.y;
const float z = P.z;
if (info->extension == EXTENSION_CLIP) {
if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -1222,8 +1222,8 @@ bool OSLRenderServices::texture3d(ustring filename,
ShaderData *sd = (ShaderData *)(sg->renderstate);
KernelGlobals *kernel_globals = sd->osl_globals;
int slot = handle->svm_slot;
float4 rgba = kernel_tex_image_interp_3d(
kernel_globals, slot, P.x, P.y, P.z, INTERPOLATION_NONE);
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);
result[0] = rgba[0];
if (nchannels > 1)

View File

@ -39,7 +39,7 @@ ccl_device void svm_node_tex_voxel(
co = transform_point(&tfm, co);
}
float4 r = kernel_tex_image_interp_3d(kg, id, co.x, co.y, co.z, INTERPOLATION_NONE);
float4 r = kernel_tex_image_interp_3d(kg, id, co, INTERPOLATION_NONE);
#else
float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
#endif

View File

@ -183,6 +183,7 @@ ImageMetaData::ImageMetaData()
type(IMAGE_DATA_NUM_TYPES),
colorspace(u_colorspace_raw),
colorspace_file_format(""),
use_transform_3d(false),
compress_as_srgb(false)
{
}
@ -190,8 +191,9 @@ ImageMetaData::ImageMetaData()
bool ImageMetaData::operator==(const ImageMetaData &other) const
{
return channels == other.channels && width == other.width && height == other.height &&
depth == other.depth && type == other.type && colorspace == other.colorspace &&
compress_as_srgb == other.compress_as_srgb;
depth == other.depth && use_transform_3d == other.use_transform_3d &&
(!use_transform_3d || transform_3d == other.transform_3d) && type == other.type &&
colorspace == other.colorspace && compress_as_srgb == other.compress_as_srgb;
}
bool ImageMetaData::is_float() const
@ -626,6 +628,8 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
img->mem = new device_texture(
device, img->mem_name.c_str(), slot, type, img->params.interpolation, img->params.extension);
img->mem->info.use_transform_3d = img->metadata.use_transform_3d;
img->mem->info.transform_3d = img->metadata.transform_3d;
/* Create new texture. */
if (type == IMAGE_DATA_TYPE_FLOAT4) {

View File

@ -24,6 +24,7 @@
#include "util/util_string.h"
#include "util/util_thread.h"
#include "util/util_transform.h"
#include "util/util_unique_ptr.h"
#include "util/util_vector.h"
@ -81,6 +82,10 @@ class ImageMetaData {
ustring colorspace;
const char *colorspace_file_format;
/* Optional transform for 3D images. */
bool use_transform_3d;
Transform transform_3d;
/* Automatically set. */
bool compress_as_srgb;

View File

@ -373,13 +373,15 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress)
VolumeParams volume_params;
volume_params.resolution = make_int3(0, 0, 0);
Transform transform = transform_identity();
foreach (Attribute &attr, mesh->attributes.attributes) {
if (attr.element != ATTR_ELEMENT_VOXEL) {
continue;
}
ImageHandle &handle = attr.data_voxel();
device_memory *image_memory = handle.image_memory();
device_texture *image_memory = handle.image_memory();
int3 resolution = make_int3(
image_memory->data_width, image_memory->data_height, image_memory->data_depth);
@ -387,14 +389,20 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress)
volume_params.resolution = resolution;
}
else if (volume_params.resolution != resolution) {
VLOG(1) << "Can't create volume mesh, all voxel grid resolutions must be equal\n";
return;
/* TODO: support this as it's common for OpenVDB. */
VLOG(1) << "Can't create accurate volume mesh, all voxel grid resolutions must be equal\n";
continue;
}
VoxelAttributeGrid voxel_grid;
voxel_grid.data = static_cast<float *>(image_memory->host_pointer);
voxel_grid.channels = image_memory->data_elements;
voxel_grids.push_back(voxel_grid);
/* TODO: support multiple transforms. */
if (image_memory->info.use_transform_3d) {
transform = image_memory->info.transform_3d;
}
}
if (voxel_grids.empty()) {
@ -427,17 +435,14 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress)
}
/* Compute start point and cell size from transform. */
Attribute *attr = mesh->attributes.find(ATTR_STD_GENERATED_TRANSFORM);
const int3 resolution = volume_params.resolution;
float3 start_point = make_float3(0.0f, 0.0f, 0.0f);
float3 cell_size = make_float3(1.0f / resolution.x, 1.0f / resolution.y, 1.0f / resolution.z);
if (attr) {
const Transform *tfm = attr->data_transform();
const Transform itfm = transform_inverse(*tfm);
start_point = transform_point(&itfm, start_point);
cell_size = transform_direction(&itfm, cell_size);
}
/* TODO: support arbitrary transforms, not just scale + translate. */
const Transform itfm = transform_inverse(transform);
start_point = transform_point(&itfm, start_point);
cell_size = transform_direction(&itfm, cell_size);
volume_params.start_point = start_point;
volume_params.cell_size = cell_size;

View File

@ -17,6 +17,8 @@
#ifndef __UTIL_TEXTURE_H__
#define __UTIL_TEXTURE_H__
#include "util_transform.h"
CCL_NAMESPACE_BEGIN
/* Texture limits on devices. */
@ -99,7 +101,9 @@ typedef struct TextureInfo {
uint interpolation, extension;
/* Dimensions. */
uint width, height, depth;
uint pad[3];
/* Transform for 3D textures. */
uint use_transform_3d;
Transform transform_3d;
} TextureInfo;
CCL_NAMESPACE_END