2022-02-11 13:53:21 +01:00
|
|
|
/* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
* Copyright 2018-2022 Blender Foundation. */
|
2018-11-07 12:58:12 +01:00
|
|
|
|
2019-06-15 09:24:38 +10:00
|
|
|
/* This class implements a ray accelerator for Cycles using Intel's Embree library.
|
2018-11-07 12:58:12 +01:00
|
|
|
* It supports triangles, curves, object and deformation blur and instancing.
|
|
|
|
|
*
|
2019-05-01 21:14:11 +10:00
|
|
|
* Since Embree allows object to be either curves or triangles but not both, Cycles object IDs are
|
2019-07-07 15:38:41 +10:00
|
|
|
* mapped to Embree IDs by multiplying by two and adding one for curves.
|
2018-11-07 12:58:12 +01:00
|
|
|
*
|
2019-05-01 21:14:11 +10:00
|
|
|
* This implementation shares RTCDevices between Cycles instances. Eventually each instance should
|
|
|
|
|
* get a separate RTCDevice to correctly keep track of memory usage.
|
2018-11-07 12:58:12 +01:00
|
|
|
*
|
2019-05-01 21:14:11 +10:00
|
|
|
* Vertex and index buffers are duplicated between Cycles device arrays and Embree. These could be
|
2019-06-16 13:37:21 +10:00
|
|
|
* merged, which would require changes to intersection refinement, shader setup, mesh light
|
2019-05-01 21:14:11 +10:00
|
|
|
* sampling and a few other places in Cycles where direct access to vertex data is required.
|
2018-11-07 12:58:12 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_EMBREE
|
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
# include <embree3/rtcore_geometry.h>
|
2018-11-07 12:58:12 +01:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
# include "bvh/embree.h"
|
2018-11-07 12:58:12 +01:00
|
|
|
|
2022-07-25 13:53:48 +02:00
|
|
|
# include "kernel/device/cpu/bvh.h"
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
# include "kernel/device/cpu/compat.h"
|
|
|
|
|
# include "kernel/device/cpu/globals.h"
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
# include "scene/hair.h"
|
|
|
|
|
# include "scene/mesh.h"
|
|
|
|
|
# include "scene/object.h"
|
2021-12-01 17:30:46 +01:00
|
|
|
# include "scene/pointcloud.h"
|
2020-06-05 11:39:11 +02:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
# include "util/foreach.h"
|
|
|
|
|
# include "util/log.h"
|
|
|
|
|
# include "util/progress.h"
|
|
|
|
|
# include "util/stats.h"
|
2018-11-07 12:58:12 +01:00
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
2020-02-18 14:02:40 +01:00
|
|
|
static_assert(Object::MAX_MOTION_STEPS <= RTC_MAX_TIME_STEP_COUNT,
|
|
|
|
|
"Object and Embree max motion steps inconsistent");
|
|
|
|
|
static_assert(Object::MAX_MOTION_STEPS == Geometry::MAX_MOTION_STEPS,
|
|
|
|
|
"Object and Geometry max motion steps inconsistent");
|
|
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
static size_t unaccounted_mem = 0;
|
|
|
|
|
|
|
|
|
|
static bool rtc_memory_monitor_func(void *userPtr, const ssize_t bytes, const bool)
|
|
|
|
|
{
|
|
|
|
|
Stats *stats = (Stats *)userPtr;
|
|
|
|
|
if (stats) {
|
|
|
|
|
if (bytes > 0) {
|
|
|
|
|
stats->mem_alloc(bytes);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
stats->mem_free(-bytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* A stats pointer may not yet be available. Keep track of the memory usage for later. */
|
|
|
|
|
if (bytes >= 0) {
|
|
|
|
|
atomic_add_and_fetch_z(&unaccounted_mem, bytes);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
atomic_sub_and_fetch_z(&unaccounted_mem, -bytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void rtc_error_func(void *, enum RTCError, const char *str)
|
|
|
|
|
{
|
2022-06-16 19:39:13 +02:00
|
|
|
VLOG_WARNING << str;
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
|
2021-11-17 17:22:05 +01:00
|
|
|
static double progress_start_time = 0.0;
|
2018-11-07 12:58:12 +01:00
|
|
|
|
|
|
|
|
static bool rtc_progress_func(void *user_ptr, const double n)
|
|
|
|
|
{
|
|
|
|
|
Progress *progress = (Progress *)user_ptr;
|
|
|
|
|
|
|
|
|
|
if (time_dt() - progress_start_time < 0.25) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string msg = string_printf("Building BVH %.0f%%", n * 100.0);
|
|
|
|
|
progress->set_substatus(msg);
|
|
|
|
|
progress_start_time = time_dt();
|
|
|
|
|
|
|
|
|
|
return !progress->get_cancel();
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-26 17:29:06 +02:00
|
|
|
BVHEmbree::BVHEmbree(const BVHParams ¶ms_,
|
2020-02-02 12:04:19 +01:00
|
|
|
const vector<Geometry *> &geometry_,
|
2020-12-10 14:18:25 +01:00
|
|
|
const vector<Object *> &objects_)
|
2020-02-02 12:04:19 +01:00
|
|
|
: BVH(params_, geometry_, objects_),
|
2018-11-07 12:58:12 +01:00
|
|
|
scene(NULL),
|
2020-12-10 14:18:25 +01:00
|
|
|
rtc_device(NULL),
|
|
|
|
|
build_quality(RTC_BUILD_QUALITY_REFIT)
|
2018-11-07 12:58:12 +01:00
|
|
|
{
|
2021-02-15 17:41:30 +01:00
|
|
|
SIMD_SET_FLUSH_TO_ZERO;
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BVHEmbree::~BVHEmbree()
|
|
|
|
|
{
|
|
|
|
|
if (scene) {
|
|
|
|
|
rtcReleaseScene(scene);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-10 14:18:25 +01:00
|
|
|
void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
|
2018-11-07 12:58:12 +01:00
|
|
|
{
|
2020-12-10 14:18:25 +01:00
|
|
|
rtc_device = rtc_device_;
|
2020-09-01 14:47:34 +02:00
|
|
|
assert(rtc_device);
|
2020-12-10 14:18:25 +01:00
|
|
|
|
|
|
|
|
rtcSetDeviceErrorFunction(rtc_device, rtc_error_func, NULL);
|
2020-09-01 14:47:34 +02:00
|
|
|
rtcSetDeviceMemoryMonitorFunction(rtc_device, rtc_memory_monitor_func, stats);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
progress.set_substatus("Building BVH");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
if (scene) {
|
|
|
|
|
rtcReleaseScene(scene);
|
|
|
|
|
scene = NULL;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
const bool dynamic = params.bvh_type == BVH_TYPE_DYNAMIC;
|
2022-01-25 17:16:13 +01:00
|
|
|
const bool compact = params.use_compact_structure;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-01 14:47:34 +02:00
|
|
|
scene = rtcNewScene(rtc_device);
|
2018-11-07 12:58:12 +01:00
|
|
|
const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
|
2022-01-25 17:16:13 +01:00
|
|
|
(compact ? RTC_SCENE_FLAG_COMPACT : RTC_SCENE_FLAG_NONE) |
|
|
|
|
|
RTC_SCENE_FLAG_ROBUST;
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcSetSceneFlags(scene, scene_flags);
|
|
|
|
|
build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
|
|
|
|
|
(params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH :
|
|
|
|
|
RTC_BUILD_QUALITY_MEDIUM);
|
|
|
|
|
rtcSetSceneBuildQuality(scene, build_quality);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
int i = 0;
|
|
|
|
|
foreach (Object *ob, objects) {
|
|
|
|
|
if (params.top_level) {
|
|
|
|
|
if (!ob->is_traceable()) {
|
|
|
|
|
++i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
if (!ob->get_geometry()->is_instanced()) {
|
2018-11-07 12:58:12 +01:00
|
|
|
add_object(ob, i);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
add_instance(ob, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
add_object(ob, i);
|
|
|
|
|
}
|
|
|
|
|
++i;
|
|
|
|
|
if (progress.get_cancel())
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
if (progress.get_cancel()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
|
|
|
|
|
rtcCommitScene(scene);
|
2019-01-08 18:10:32 +01:00
|
|
|
}
|
|
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
void BVHEmbree::add_object(Object *ob, int i)
|
|
|
|
|
{
|
2020-11-04 11:17:38 +01:00
|
|
|
Geometry *geom = ob->get_geometry();
|
2020-02-02 12:04:19 +01:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
|
2020-02-02 12:04:19 +01:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(geom);
|
|
|
|
|
if (mesh->num_triangles() > 0) {
|
|
|
|
|
add_triangles(ob, mesh, i);
|
|
|
|
|
}
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
else if (geom->geometry_type == Geometry::HAIR) {
|
2020-02-02 12:04:19 +01:00
|
|
|
Hair *hair = static_cast<Hair *>(geom);
|
|
|
|
|
if (hair->num_curves() > 0) {
|
|
|
|
|
add_curves(ob, hair, i);
|
|
|
|
|
}
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
2021-12-01 17:30:46 +01:00
|
|
|
else if (geom->geometry_type == Geometry::POINTCLOUD) {
|
|
|
|
|
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
|
|
|
|
if (pointcloud->num_points() > 0) {
|
|
|
|
|
add_points(ob, pointcloud, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BVHEmbree::add_instance(Object *ob, int i)
|
|
|
|
|
{
|
2020-11-04 11:17:38 +01:00
|
|
|
BVHEmbree *instance_bvh = (BVHEmbree *)(ob->get_geometry()->bvh);
|
2020-12-10 14:18:25 +01:00
|
|
|
assert(instance_bvh != NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
const size_t num_object_motion_steps = ob->use_motion() ? ob->get_motion().size() : 1;
|
2022-02-10 10:37:00 +01:00
|
|
|
const size_t num_motion_steps = min(num_object_motion_steps, (size_t)RTC_MAX_TIME_STEP_COUNT);
|
2020-02-18 14:02:40 +01:00
|
|
|
assert(num_object_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
|
|
|
|
|
|
2020-09-01 14:47:34 +02:00
|
|
|
RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_INSTANCE);
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
|
|
|
|
|
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
if (ob->use_motion()) {
|
2020-11-04 11:17:38 +01:00
|
|
|
array<DecomposedTransform> decomp(ob->get_motion().size());
|
|
|
|
|
transform_motion_decompose(decomp.data(), ob->get_motion().data(), ob->get_motion().size());
|
2018-11-07 12:58:12 +01:00
|
|
|
for (size_t step = 0; step < num_motion_steps; ++step) {
|
2020-02-17 23:44:12 +01:00
|
|
|
RTCQuaternionDecomposition rtc_decomp;
|
|
|
|
|
rtcInitQuaternionDecomposition(&rtc_decomp);
|
|
|
|
|
rtcQuaternionDecompositionSetQuaternion(
|
|
|
|
|
&rtc_decomp, decomp[step].x.w, decomp[step].x.x, decomp[step].x.y, decomp[step].x.z);
|
|
|
|
|
rtcQuaternionDecompositionSetScale(
|
|
|
|
|
&rtc_decomp, decomp[step].y.w, decomp[step].z.w, decomp[step].w.w);
|
|
|
|
|
rtcQuaternionDecompositionSetTranslation(
|
|
|
|
|
&rtc_decomp, decomp[step].y.x, decomp[step].y.y, decomp[step].y.z);
|
|
|
|
|
rtcQuaternionDecompositionSetSkew(
|
|
|
|
|
&rtc_decomp, decomp[step].z.x, decomp[step].z.y, decomp[step].w.x);
|
|
|
|
|
rtcSetGeometryTransformQuaternion(geom_id, step, &rtc_decomp);
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-11-04 11:17:38 +01:00
|
|
|
rtcSetGeometryTransform(
|
|
|
|
|
geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float *)&ob->get_tfm());
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcSetGeometryUserData(geom_id, (void *)instance_bvh->scene);
|
2020-02-18 00:04:21 +01:00
|
|
|
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcCommitGeometry(geom_id);
|
|
|
|
|
rtcAttachGeometryByID(scene, geom_id, i * 2);
|
|
|
|
|
rtcReleaseGeometry(geom_id);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-02 12:04:19 +01:00
|
|
|
void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
|
2018-11-07 12:58:12 +01:00
|
|
|
{
|
2021-02-28 23:23:24 +01:00
|
|
|
size_t prim_offset = mesh->prim_offset;
|
2020-12-10 14:18:25 +01:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
const Attribute *attr_mP = NULL;
|
2020-12-10 14:18:25 +01:00
|
|
|
size_t num_motion_steps = 1;
|
2018-11-07 12:58:12 +01:00
|
|
|
if (mesh->has_motion_blur()) {
|
|
|
|
|
attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
|
|
|
if (attr_mP) {
|
2020-12-10 14:18:25 +01:00
|
|
|
num_motion_steps = mesh->get_motion_steps();
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-12-10 14:18:25 +01:00
|
|
|
assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
|
2022-02-10 10:37:00 +01:00
|
|
|
num_motion_steps = min(num_motion_steps, (size_t)RTC_MAX_TIME_STEP_COUNT);
|
2020-02-18 14:02:40 +01:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
const size_t num_triangles = mesh->num_triangles();
|
2020-12-10 14:18:25 +01:00
|
|
|
|
2020-09-01 14:47:34 +02:00
|
|
|
RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_TRIANGLE);
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcSetGeometryBuildQuality(geom_id, build_quality);
|
|
|
|
|
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
|
|
|
|
|
geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(int) * 3, num_triangles);
|
|
|
|
|
assert(rtc_indices);
|
|
|
|
|
if (!rtc_indices) {
|
2022-06-16 19:39:13 +02:00
|
|
|
VLOG_WARNING << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str()
|
|
|
|
|
<< ".\n";
|
2018-11-07 12:58:12 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (size_t j = 0; j < num_triangles; ++j) {
|
|
|
|
|
Mesh::Triangle t = mesh->get_triangle(j);
|
|
|
|
|
rtc_indices[j * 3] = t.v[0];
|
|
|
|
|
rtc_indices[j * 3 + 1] = t.v[1];
|
|
|
|
|
rtc_indices[j * 3 + 2] = t.v[2];
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-23 18:03:43 +02:00
|
|
|
set_tri_vertex_buffer(geom_id, mesh, false);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
2022-07-25 13:53:48 +02:00
|
|
|
rtcSetGeometryOccludedFilterFunction(geom_id, kernel_embree_filter_occluded_func);
|
|
|
|
|
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_intersection_func);
|
2020-02-18 00:04:21 +01:00
|
|
|
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcCommitGeometry(geom_id);
|
|
|
|
|
rtcAttachGeometryByID(scene, geom_id, i * 2);
|
|
|
|
|
rtcReleaseGeometry(geom_id);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-23 18:03:43 +02:00
|
|
|
void BVHEmbree::set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, const bool update)
|
2018-11-07 12:58:12 +01:00
|
|
|
{
|
|
|
|
|
const Attribute *attr_mP = NULL;
|
|
|
|
|
size_t num_motion_steps = 1;
|
|
|
|
|
int t_mid = 0;
|
|
|
|
|
if (mesh->has_motion_blur()) {
|
|
|
|
|
attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
|
|
|
if (attr_mP) {
|
2020-11-04 11:17:38 +01:00
|
|
|
num_motion_steps = mesh->get_motion_steps();
|
2018-11-07 12:58:12 +01:00
|
|
|
t_mid = (num_motion_steps - 1) / 2;
|
|
|
|
|
if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
|
|
|
|
|
assert(0);
|
|
|
|
|
num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-10 14:18:25 +01:00
|
|
|
const size_t num_verts = mesh->get_verts().size();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
for (int t = 0; t < num_motion_steps; ++t) {
|
|
|
|
|
const float3 *verts;
|
|
|
|
|
if (t == t_mid) {
|
2020-12-10 14:18:25 +01:00
|
|
|
verts = mesh->get_verts().data();
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int t_ = (t > t_mid) ? (t - 1) : t;
|
|
|
|
|
verts = &attr_mP->data_float3()[t_ * num_verts];
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-23 18:03:43 +02:00
|
|
|
float *rtc_verts = (update) ?
|
|
|
|
|
(float *)rtcGetGeometryBufferData(geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
|
|
|
|
|
(float *)rtcSetNewGeometryBuffer(geom_id,
|
|
|
|
|
RTC_BUFFER_TYPE_VERTEX,
|
|
|
|
|
t,
|
|
|
|
|
RTC_FORMAT_FLOAT3,
|
|
|
|
|
sizeof(float) * 3,
|
|
|
|
|
num_verts + 1);
|
|
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
assert(rtc_verts);
|
|
|
|
|
if (rtc_verts) {
|
|
|
|
|
for (size_t j = 0; j < num_verts; ++j) {
|
|
|
|
|
rtc_verts[0] = verts[j].x;
|
|
|
|
|
rtc_verts[1] = verts[j].y;
|
|
|
|
|
rtc_verts[2] = verts[j].z;
|
|
|
|
|
rtc_verts += 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-10-23 18:03:43 +02:00
|
|
|
|
|
|
|
|
if (update) {
|
|
|
|
|
rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
|
|
|
|
|
}
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-23 18:03:43 +02:00
|
|
|
void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, const bool update)
|
2018-11-07 12:58:12 +01:00
|
|
|
{
|
|
|
|
|
const Attribute *attr_mP = NULL;
|
|
|
|
|
size_t num_motion_steps = 1;
|
2020-02-02 12:04:19 +01:00
|
|
|
if (hair->has_motion_blur()) {
|
|
|
|
|
attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
2018-11-07 12:58:12 +01:00
|
|
|
if (attr_mP) {
|
2020-11-04 11:17:38 +01:00
|
|
|
num_motion_steps = hair->get_motion_steps();
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-02 12:04:19 +01:00
|
|
|
const size_t num_curves = hair->num_curves();
|
2018-11-07 12:58:12 +01:00
|
|
|
size_t num_keys = 0;
|
|
|
|
|
for (size_t j = 0; j < num_curves; ++j) {
|
2020-02-02 12:04:19 +01:00
|
|
|
const Hair::Curve c = hair->get_curve(j);
|
2018-11-07 12:58:12 +01:00
|
|
|
num_keys += c.num_keys;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-20 10:28:32 +01:00
|
|
|
/* Catmull-Rom splines need extra CVs at the beginning and end of each curve. */
|
2020-02-24 20:29:01 +01:00
|
|
|
size_t num_keys_embree = num_keys;
|
2020-06-04 15:12:31 +02:00
|
|
|
num_keys_embree += num_curves * 2;
|
2020-02-20 10:28:32 +01:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
/* Copy the CV data to Embree */
|
|
|
|
|
const int t_mid = (num_motion_steps - 1) / 2;
|
2020-11-04 11:17:38 +01:00
|
|
|
const float *curve_radius = &hair->get_curve_radius()[0];
|
2018-11-07 12:58:12 +01:00
|
|
|
for (int t = 0; t < num_motion_steps; ++t) {
|
|
|
|
|
const float3 *verts;
|
|
|
|
|
if (t == t_mid || attr_mP == NULL) {
|
2020-11-04 11:17:38 +01:00
|
|
|
verts = &hair->get_curve_keys()[0];
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int t_ = (t > t_mid) ? (t - 1) : t;
|
|
|
|
|
verts = &attr_mP->data_float3()[t_ * num_keys];
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-23 18:03:43 +02:00
|
|
|
float4 *rtc_verts = (update) ? (float4 *)rtcGetGeometryBufferData(
|
|
|
|
|
geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
|
|
|
|
|
(float4 *)rtcSetNewGeometryBuffer(geom_id,
|
|
|
|
|
RTC_BUFFER_TYPE_VERTEX,
|
|
|
|
|
t,
|
|
|
|
|
RTC_FORMAT_FLOAT4,
|
|
|
|
|
sizeof(float) * 4,
|
|
|
|
|
num_keys_embree);
|
2020-02-20 10:28:32 +01:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
assert(rtc_verts);
|
|
|
|
|
if (rtc_verts) {
|
2020-06-04 15:12:31 +02:00
|
|
|
const size_t num_curves = hair->num_curves();
|
|
|
|
|
for (size_t j = 0; j < num_curves; ++j) {
|
|
|
|
|
Hair::Curve c = hair->get_curve(j);
|
|
|
|
|
int fk = c.first_key;
|
|
|
|
|
int k = 1;
|
|
|
|
|
for (; k < c.num_keys + 1; ++k, ++fk) {
|
|
|
|
|
rtc_verts[k] = float3_to_float4(verts[fk]);
|
|
|
|
|
rtc_verts[k].w = curve_radius[fk];
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
2020-06-04 15:12:31 +02:00
|
|
|
/* Duplicate Embree's Catmull-Rom spline CVs at the start and end of each curve. */
|
|
|
|
|
rtc_verts[0] = rtc_verts[1];
|
|
|
|
|
rtc_verts[k] = rtc_verts[k - 1];
|
|
|
|
|
rtc_verts += c.num_keys + 2;
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-23 18:03:43 +02:00
|
|
|
|
|
|
|
|
if (update) {
|
|
|
|
|
rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
|
|
|
|
|
}
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-01 17:30:46 +01:00
|
|
|
void BVHEmbree::set_point_vertex_buffer(RTCGeometry geom_id,
|
|
|
|
|
const PointCloud *pointcloud,
|
|
|
|
|
const bool update)
|
|
|
|
|
{
|
|
|
|
|
const Attribute *attr_mP = NULL;
|
|
|
|
|
size_t num_motion_steps = 1;
|
|
|
|
|
if (pointcloud->has_motion_blur()) {
|
|
|
|
|
attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
|
|
|
if (attr_mP) {
|
|
|
|
|
num_motion_steps = pointcloud->get_motion_steps();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t num_points = pointcloud->num_points();
|
|
|
|
|
|
|
|
|
|
/* Copy the point data to Embree */
|
|
|
|
|
const int t_mid = (num_motion_steps - 1) / 2;
|
|
|
|
|
const float *radius = pointcloud->get_radius().data();
|
|
|
|
|
for (int t = 0; t < num_motion_steps; ++t) {
|
|
|
|
|
const float3 *verts;
|
|
|
|
|
if (t == t_mid || attr_mP == NULL) {
|
|
|
|
|
verts = pointcloud->get_points().data();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int t_ = (t > t_mid) ? (t - 1) : t;
|
|
|
|
|
verts = &attr_mP->data_float3()[t_ * num_points];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float4 *rtc_verts = (update) ? (float4 *)rtcGetGeometryBufferData(
|
|
|
|
|
geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
|
|
|
|
|
(float4 *)rtcSetNewGeometryBuffer(geom_id,
|
|
|
|
|
RTC_BUFFER_TYPE_VERTEX,
|
|
|
|
|
t,
|
|
|
|
|
RTC_FORMAT_FLOAT4,
|
|
|
|
|
sizeof(float) * 4,
|
|
|
|
|
num_points);
|
|
|
|
|
|
|
|
|
|
assert(rtc_verts);
|
|
|
|
|
if (rtc_verts) {
|
|
|
|
|
for (size_t j = 0; j < num_points; ++j) {
|
|
|
|
|
rtc_verts[j] = float3_to_float4(verts[j]);
|
|
|
|
|
rtc_verts[j].w = radius[j];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (update) {
|
|
|
|
|
rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BVHEmbree::add_points(const Object *ob, const PointCloud *pointcloud, int i)
|
|
|
|
|
{
|
|
|
|
|
size_t prim_offset = pointcloud->prim_offset;
|
|
|
|
|
|
|
|
|
|
const Attribute *attr_mP = NULL;
|
|
|
|
|
size_t num_motion_steps = 1;
|
|
|
|
|
if (pointcloud->has_motion_blur()) {
|
|
|
|
|
attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
|
|
|
if (attr_mP) {
|
|
|
|
|
num_motion_steps = pointcloud->get_motion_steps();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum RTCGeometryType type = RTC_GEOMETRY_TYPE_SPHERE_POINT;
|
|
|
|
|
|
|
|
|
|
RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
|
|
|
|
|
|
|
|
|
|
rtcSetGeometryBuildQuality(geom_id, build_quality);
|
|
|
|
|
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
|
|
|
|
|
|
|
|
|
|
set_point_vertex_buffer(geom_id, pointcloud, false);
|
|
|
|
|
|
|
|
|
|
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
2022-07-25 13:53:48 +02:00
|
|
|
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_func_backface_cull);
|
|
|
|
|
rtcSetGeometryOccludedFilterFunction(geom_id, kernel_embree_filter_occluded_func_backface_cull);
|
2021-12-01 17:30:46 +01:00
|
|
|
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
|
|
|
|
|
|
|
|
|
rtcCommitGeometry(geom_id);
|
|
|
|
|
rtcAttachGeometryByID(scene, geom_id, i * 2);
|
|
|
|
|
rtcReleaseGeometry(geom_id);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-02 12:04:19 +01:00
|
|
|
void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
|
2018-11-07 12:58:12 +01:00
|
|
|
{
|
2021-02-28 23:23:24 +01:00
|
|
|
size_t prim_offset = hair->curve_segment_offset;
|
2020-12-10 14:18:25 +01:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
const Attribute *attr_mP = NULL;
|
2020-12-10 14:18:25 +01:00
|
|
|
size_t num_motion_steps = 1;
|
2020-02-02 12:04:19 +01:00
|
|
|
if (hair->has_motion_blur()) {
|
|
|
|
|
attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
2018-11-07 12:58:12 +01:00
|
|
|
if (attr_mP) {
|
2020-12-10 14:18:25 +01:00
|
|
|
num_motion_steps = hair->get_motion_steps();
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-12-10 14:18:25 +01:00
|
|
|
assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
|
2022-02-10 10:37:00 +01:00
|
|
|
num_motion_steps = min(num_motion_steps, (size_t)RTC_MAX_TIME_STEP_COUNT);
|
2020-02-18 14:02:40 +01:00
|
|
|
|
2020-02-02 12:04:19 +01:00
|
|
|
const size_t num_curves = hair->num_curves();
|
2018-11-07 12:58:12 +01:00
|
|
|
size_t num_segments = 0;
|
|
|
|
|
for (size_t j = 0; j < num_curves; ++j) {
|
2020-02-02 12:04:19 +01:00
|
|
|
Hair::Curve c = hair->get_curve(j);
|
2018-11-07 12:58:12 +01:00
|
|
|
assert(c.num_segments() > 0);
|
|
|
|
|
num_segments += c.num_segments();
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-06-10 19:07:07 +02:00
|
|
|
enum RTCGeometryType type = (hair->curve_shape == CURVE_RIBBON ?
|
|
|
|
|
RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE :
|
|
|
|
|
RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-01 14:47:34 +02:00
|
|
|
RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
|
2020-12-10 14:18:25 +01:00
|
|
|
rtcSetGeometryTessellationRate(geom_id, params.curve_subdivisions + 1);
|
2018-11-07 12:58:12 +01:00
|
|
|
unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
|
2019-03-20 10:48:49 +01:00
|
|
|
geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof(int), num_segments);
|
2018-11-07 12:58:12 +01:00
|
|
|
size_t rtc_index = 0;
|
|
|
|
|
for (size_t j = 0; j < num_curves; ++j) {
|
2020-02-02 12:04:19 +01:00
|
|
|
Hair::Curve c = hair->get_curve(j);
|
2018-11-07 12:58:12 +01:00
|
|
|
for (size_t k = 0; k < c.num_segments(); ++k) {
|
|
|
|
|
rtc_indices[rtc_index] = c.first_key + k;
|
2020-06-04 15:12:31 +02:00
|
|
|
/* Room for extra CVs at Catmull-Rom splines. */
|
|
|
|
|
rtc_indices[rtc_index] += j * 2;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
++rtc_index;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcSetGeometryBuildQuality(geom_id, build_quality);
|
|
|
|
|
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-23 18:03:43 +02:00
|
|
|
set_curve_vertex_buffer(geom_id, hair, false);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
2020-06-10 19:07:07 +02:00
|
|
|
if (hair->curve_shape == CURVE_RIBBON) {
|
2022-07-25 13:53:48 +02:00
|
|
|
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_intersection_func);
|
|
|
|
|
rtcSetGeometryOccludedFilterFunction(geom_id, kernel_embree_filter_occluded_func);
|
2020-06-10 18:34:18 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2022-07-25 13:53:48 +02:00
|
|
|
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_func_backface_cull);
|
|
|
|
|
rtcSetGeometryOccludedFilterFunction(geom_id,
|
|
|
|
|
kernel_embree_filter_occluded_func_backface_cull);
|
2020-06-10 18:34:18 +02:00
|
|
|
}
|
2020-02-18 00:04:21 +01:00
|
|
|
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcCommitGeometry(geom_id);
|
|
|
|
|
rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);
|
|
|
|
|
rtcReleaseGeometry(geom_id);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-10 14:18:25 +01:00
|
|
|
void BVHEmbree::refit(Progress &progress)
|
2018-11-07 12:58:12 +01:00
|
|
|
{
|
2020-12-10 14:18:25 +01:00
|
|
|
progress.set_substatus("Refitting BVH nodes");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
/* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */
|
|
|
|
|
unsigned geom_id = 0;
|
|
|
|
|
foreach (Object *ob, objects) {
|
2020-11-04 11:17:38 +01:00
|
|
|
if (!params.top_level || (ob->is_traceable() && !ob->get_geometry()->is_instanced())) {
|
|
|
|
|
Geometry *geom = ob->get_geometry();
|
2020-02-02 12:04:19 +01:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
|
2020-02-02 12:04:19 +01:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(geom);
|
|
|
|
|
if (mesh->num_triangles() > 0) {
|
2020-10-23 18:03:43 +02:00
|
|
|
RTCGeometry geom = rtcGetGeometry(scene, geom_id);
|
|
|
|
|
set_tri_vertex_buffer(geom, mesh, true);
|
2021-02-28 23:23:24 +01:00
|
|
|
rtcSetGeometryUserData(geom, (void *)mesh->prim_offset);
|
2020-10-23 18:03:43 +02:00
|
|
|
rtcCommitGeometry(geom);
|
2020-02-02 12:04:19 +01:00
|
|
|
}
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
else if (geom->geometry_type == Geometry::HAIR) {
|
2020-02-02 12:04:19 +01:00
|
|
|
Hair *hair = static_cast<Hair *>(geom);
|
|
|
|
|
if (hair->num_curves() > 0) {
|
2020-10-23 18:03:43 +02:00
|
|
|
RTCGeometry geom = rtcGetGeometry(scene, geom_id + 1);
|
|
|
|
|
set_curve_vertex_buffer(geom, hair, true);
|
2021-02-28 23:23:24 +01:00
|
|
|
rtcSetGeometryUserData(geom, (void *)hair->curve_segment_offset);
|
2020-10-23 18:03:43 +02:00
|
|
|
rtcCommitGeometry(geom);
|
2020-02-02 12:04:19 +01:00
|
|
|
}
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
2021-12-01 17:30:46 +01:00
|
|
|
else if (geom->geometry_type == Geometry::POINTCLOUD) {
|
|
|
|
|
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
|
|
|
|
if (pointcloud->num_points() > 0) {
|
|
|
|
|
RTCGeometry geom = rtcGetGeometry(scene, geom_id);
|
|
|
|
|
set_point_vertex_buffer(geom, pointcloud, true);
|
|
|
|
|
rtcCommitGeometry(geom);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-11-07 12:58:12 +01:00
|
|
|
}
|
|
|
|
|
geom_id += 2;
|
|
|
|
|
}
|
2020-12-10 14:18:25 +01:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
rtcCommitScene(scene);
|
|
|
|
|
}
|
2020-12-10 14:18:25 +01:00
|
|
|
|
2018-11-07 12:58:12 +01:00
|
|
|
CCL_NAMESPACE_END
|
|
|
|
|
|
|
|
|
|
#endif /* WITH_EMBREE */
|