The attribute handling code in the kernel is currently highly duplicated since it needs to handle five different data types and we couldn't use templates back then. We can now, so might as well make use of it and get rid of ~1000 lines. There are also some small fixes for the GPU OSL code: - Wrong derivative for .w component when converting float2/float3->float4 - Different conversion for float2->float (CPU averages, GPU used to take .x) - Removed useless code for converting to float2, not used by OSL Pull Request: https://projects.blender.org/blender/blender/pulls/134694
101 lines
3.1 KiB
C++
101 lines
3.1 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/image.h"
|
|
|
|
#include "kernel/geom/attribute.h"
|
|
#include "kernel/geom/object.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,
|
|
const ccl_private ShaderData *sd,
|
|
const AttributeDescriptor desc)
|
|
{
|
|
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);
|
|
}
|
|
return zero_float4();
|
|
}
|
|
|
|
#endif
|
|
|
|
CCL_NAMESPACE_END
|