Merge with master
This commit is contained in:
parent
af0350393e
commit
e0039cb302
|
@ -2083,9 +2083,9 @@ compile_OIIO() {
|
|||
cmake_d="$cmake_d -D OPENEXR_VERSION=$OPENEXR_VERSION"
|
||||
|
||||
if [ "$_with_built_openexr" = true ]; then
|
||||
cmake_d="$cmake_d -D ILMBASE_HOME=$INST/openexr"
|
||||
cmake_d="$cmake_d -D OPENEXR_HOME=$INST/openexr"
|
||||
INFO "ILMBASE_HOME=$INST/openexr"
|
||||
cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
|
||||
cmake_d="$cmake_d -D OPENEXR_ROOT=$INST/openexr"
|
||||
INFO "Ilmbase_ROOT=$INST/openexr"
|
||||
fi
|
||||
|
||||
# ptex is only needed when nicholas bishop is ready
|
||||
|
@ -2374,9 +2374,9 @@ compile_OSL() {
|
|||
#~ cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION"
|
||||
|
||||
if [ "$_with_built_openexr" = true ]; then
|
||||
INFO "ILMBASE_HOME=$INST/openexr"
|
||||
cmake_d="$cmake_d -D OPENEXR_ROOT_DIR=$INST/openexr"
|
||||
cmake_d="$cmake_d -D ILMBASE_ROOT_DIR=$INST/openexr"
|
||||
cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
|
||||
cmake_d="$cmake_d -D OPENEXR_ROOT=$INST/openexr"
|
||||
INFO "Ilmbase_ROOT=$INST/openexr"
|
||||
# XXX Temp workaround... sigh, ILMBase really messed the things up by defining their custom names ON by default :(
|
||||
fi
|
||||
|
||||
|
|
|
@ -197,3 +197,38 @@ index 67ec0d15f..6dc3e85a0 100644
|
|||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
|
||||
diff --git a/pxr/base/arch/demangle.cpp b/pxr/base/arch/demangle.cpp
|
||||
index 67ec0d15f..6dc3e85a0 100644
|
||||
--- a/pxr/base/arch/demangle.cpp
|
||||
+++ b/pxr/base/arch/demangle.cpp
|
||||
@@ -36,6 +36,7 @@
|
||||
#if (ARCH_COMPILER_GCC_MAJOR == 3 && ARCH_COMPILER_GCC_MINOR >= 1) || \
|
||||
ARCH_COMPILER_GCC_MAJOR > 3 || defined(ARCH_COMPILER_CLANG)
|
||||
#define _AT_LEAST_GCC_THREE_ONE_OR_CLANG
|
||||
+#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
@@ -138,7 +139,6 @@
|
||||
#endif
|
||||
|
||||
#if defined(_AT_LEAST_GCC_THREE_ONE_OR_CLANG)
|
||||
-#include <cxxabi.h>
|
||||
|
||||
/*
|
||||
* This routine doesn't work when you get to gcc3.4.
|
||||
|
||||
diff --git a/pxr/base/work/singularTask.h b/pxr/base/work/singularTask.h
|
||||
index 67ec0d15f..6dc3e85a0 100644
|
||||
--- a/pxr/base/work/singularTask.h
|
||||
+++ b/pxr/base/work/singularTask.h
|
||||
@@ -120,7 +120,7 @@
|
||||
// case we go again to ensure the task can do whatever it
|
||||
// was awakened to do. Once we successfully take the count
|
||||
// to zero, we stop.
|
||||
- size_t old = count;
|
||||
+ std::size_t old = count;
|
||||
do { _fn(); } while (
|
||||
!count.compare_exchange_strong(old, 0));
|
||||
});
|
||||
|
|
|
@ -40,6 +40,7 @@ set(SRC
|
|||
object_cull.cpp
|
||||
output_driver.cpp
|
||||
particles.cpp
|
||||
pointcloud.cpp
|
||||
curves.cpp
|
||||
logging.cpp
|
||||
python.cpp
|
||||
|
|
|
@ -1020,7 +1020,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
|
|||
def poll(cls, context):
|
||||
ob = context.object
|
||||
if CyclesButtonsPanel.poll(context) and ob:
|
||||
if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}:
|
||||
if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA', 'HAIR', 'POINTCLOUD'}:
|
||||
return True
|
||||
if ob.instance_type == 'COLLECTION' and ob.instance_collection:
|
||||
return True
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "scene/hair.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/volume.h"
|
||||
|
||||
#include "blender/sync.h"
|
||||
|
@ -39,6 +40,10 @@ static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_parti
|
|||
return Geometry::HAIR;
|
||||
}
|
||||
|
||||
if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
|
||||
return Geometry::POINTCLOUD;
|
||||
}
|
||||
|
||||
if (b_ob_info.object_data.is_a(&RNA_Volume) ||
|
||||
(b_ob_info.object_data == b_ob_info.real_object.data() &&
|
||||
object_fluid_gas_domain_find(b_ob_info.real_object))) {
|
||||
|
@ -111,6 +116,9 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
|||
else if (geom_type == Geometry::VOLUME) {
|
||||
geom = scene->create_node<Volume>();
|
||||
}
|
||||
else if (geom_type == Geometry::POINTCLOUD) {
|
||||
geom = scene->create_node<PointCloud>();
|
||||
}
|
||||
else {
|
||||
geom = scene->create_node<Mesh>();
|
||||
}
|
||||
|
@ -170,6 +178,10 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
|||
Volume *volume = static_cast<Volume *>(geom);
|
||||
sync_volume(b_ob_info, volume);
|
||||
}
|
||||
else if (geom_type == Geometry::POINTCLOUD) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
sync_pointcloud(pointcloud, b_ob_info);
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh(b_depsgraph, b_ob_info, mesh);
|
||||
|
@ -231,6 +243,10 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
|||
object_fluid_gas_domain_find(b_ob_info.real_object)) {
|
||||
/* No volume motion blur support yet. */
|
||||
}
|
||||
else if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
sync_pointcloud_motion(pointcloud, b_ob_info, motion_step);
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh_motion(b_depsgraph, b_ob_info, mesh, motion_step);
|
||||
|
|
|
@ -72,7 +72,8 @@ bool BlenderSync::object_is_geometry(BObjectInfo &b_ob_info)
|
|||
|
||||
BL::Object::type_enum type = b_ob_info.iter_object.type();
|
||||
|
||||
if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR) {
|
||||
if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR ||
|
||||
type == BL::Object::type_POINTCLOUD) {
|
||||
/* Will be exported attached to mesh. */
|
||||
return true;
|
||||
}
|
||||
|
@ -206,7 +207,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* only interested in object that we can create meshes from */
|
||||
/* only interested in object that we can create geometry from */
|
||||
if (!object_is_geometry(b_ob_info)) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -396,6 +396,13 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
|
|||
/* set the current view */
|
||||
b_engine.active_view_set(b_rview_name.c_str());
|
||||
|
||||
/* Force update in this case, since the camera transform on each frame changes
|
||||
* in different views. This could be optimized by somehow storing the animated
|
||||
* camera transforms separate from the fixed stereo transform. */
|
||||
if ((scene->need_motion() != Scene::MOTION_NONE) && view_index > 0) {
|
||||
sync->tag_update();
|
||||
}
|
||||
|
||||
/* update scene */
|
||||
BL::Object b_camera_override(b_engine.camera_override());
|
||||
sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
|
||||
|
|
|
@ -95,6 +95,11 @@ void BlenderSync::reset(BL::BlendData &b_data, BL::Scene &b_scene)
|
|||
this->b_scene = b_scene;
|
||||
}
|
||||
|
||||
void BlenderSync::tag_update()
|
||||
{
|
||||
has_updates_ = true;
|
||||
}
|
||||
|
||||
/* Sync */
|
||||
|
||||
void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
|
||||
|
|
|
@ -66,6 +66,8 @@ class BlenderSync {
|
|||
|
||||
void reset(BL::BlendData &b_data, BL::Scene &b_scene);
|
||||
|
||||
void tag_update();
|
||||
|
||||
/* sync */
|
||||
void sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
|
||||
void sync_data(BL::RenderSettings &b_render,
|
||||
|
@ -167,12 +169,16 @@ class BlenderSync {
|
|||
Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
|
||||
bool object_has_particle_hair(BL::Object b_ob);
|
||||
|
||||
/* Point Cloud */
|
||||
void sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info);
|
||||
void sync_pointcloud_motion(PointCloud *pointcloud, BObjectInfo &b_ob_info, int motion_step = 0);
|
||||
|
||||
/* Camera */
|
||||
void sync_camera_motion(
|
||||
BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time);
|
||||
|
||||
/* Geometry */
|
||||
Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah,
|
||||
Geometry *sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
bool object_updated,
|
||||
bool use_particle_hair,
|
||||
|
@ -267,7 +273,6 @@ class BlenderSync {
|
|||
|
||||
Progress &progress;
|
||||
|
||||
protected:
|
||||
/* Indicates that `sync_recalc()` detected changes in the scene.
|
||||
* If this flag is false then the data is considered to be up-to-date and will not be
|
||||
* synchronized at all. */
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "scene/hair.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/scene.h"
|
||||
|
||||
#include "util/algorithm.h"
|
||||
|
@ -113,9 +114,9 @@ void BVHBuild::add_reference_triangles(BoundBox &root,
|
|||
else {
|
||||
/* Motion triangles, trace optimized case: we split triangle
|
||||
* primitives into separate nodes for each of the time steps.
|
||||
* This way we minimize overlap of neighbor curve primitives.
|
||||
* This way we minimize overlap of neighbor triangle primitives.
|
||||
*/
|
||||
const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
|
||||
const int num_bvh_steps = params.num_motion_triangle_steps * 2 + 1;
|
||||
const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
|
||||
const size_t num_verts = mesh->verts.size();
|
||||
const size_t num_steps = mesh->motion_steps;
|
||||
|
@ -269,6 +270,101 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox ¢er, Hair *hair
|
|||
}
|
||||
}
|
||||
|
||||
void BVHBuild::add_reference_points(BoundBox &root,
|
||||
BoundBox ¢er,
|
||||
PointCloud *pointcloud,
|
||||
int i)
|
||||
{
|
||||
const Attribute *point_attr_mP = NULL;
|
||||
if (pointcloud->has_motion_blur()) {
|
||||
point_attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
}
|
||||
|
||||
const float3 *points_data = &pointcloud->points[0];
|
||||
const float *radius_data = &pointcloud->radius[0];
|
||||
const size_t num_points = pointcloud->num_points();
|
||||
const float3 *motion_data = (point_attr_mP) ? point_attr_mP->data_float3() : NULL;
|
||||
const size_t num_steps = pointcloud->get_motion_steps();
|
||||
|
||||
if (point_attr_mP == NULL) {
|
||||
/* Really simple logic for static points. */
|
||||
for (uint j = 0; j < num_points; j++) {
|
||||
const PointCloud::Point point = pointcloud->get_point(j);
|
||||
BoundBox bounds = BoundBox::empty;
|
||||
point.bounds_grow(points_data, radius_data, bounds);
|
||||
if (bounds.valid()) {
|
||||
references.push_back(BVHReference(bounds, j, i, PRIMITIVE_POINT));
|
||||
root.grow(bounds);
|
||||
center.grow(bounds.center2());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (params.num_motion_point_steps == 0 || params.use_spatial_split) {
|
||||
/* Simple case of motion points: single node for the whole
|
||||
* shutter time. Lowest memory usage but less optimal
|
||||
* rendering.
|
||||
*/
|
||||
/* TODO(sergey): Support motion steps for spatially split BVH. */
|
||||
for (uint j = 0; j < num_points; j++) {
|
||||
const PointCloud::Point point = pointcloud->get_point(j);
|
||||
BoundBox bounds = BoundBox::empty;
|
||||
point.bounds_grow(points_data, radius_data, bounds);
|
||||
for (size_t step = 0; step < num_steps - 1; step++) {
|
||||
point.bounds_grow(motion_data + step * num_points, radius_data, bounds);
|
||||
}
|
||||
if (bounds.valid()) {
|
||||
references.push_back(BVHReference(bounds, j, i, PRIMITIVE_MOTION_POINT));
|
||||
root.grow(bounds);
|
||||
center.grow(bounds.center2());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Motion points, trace optimized case: we split point
|
||||
* primitives into separate nodes for each of the time steps.
|
||||
* This way we minimize overlap of neighbor point primitives.
|
||||
*/
|
||||
const int num_bvh_steps = params.num_motion_point_steps * 2 + 1;
|
||||
const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
|
||||
|
||||
for (uint j = 0; j < num_points; j++) {
|
||||
const PointCloud::Point point = pointcloud->get_point(j);
|
||||
const size_t num_steps = pointcloud->get_motion_steps();
|
||||
const float3 *point_steps = point_attr_mP->data_float3();
|
||||
|
||||
/* Calculate bounding box of the previous time step.
|
||||
* Will be reused later to avoid duplicated work on
|
||||
* calculating BVH time step boundbox.
|
||||
*/
|
||||
float4 prev_key = point.motion_key(
|
||||
points_data, radius_data, point_steps, num_points, num_steps, 0.0f, j);
|
||||
BoundBox prev_bounds = BoundBox::empty;
|
||||
point.bounds_grow(prev_key, prev_bounds);
|
||||
/* Create all primitive time steps, */
|
||||
for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
|
||||
const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
|
||||
float4 curr_key = point.motion_key(
|
||||
points_data, radius_data, point_steps, num_points, num_steps, curr_time, j);
|
||||
BoundBox curr_bounds = BoundBox::empty;
|
||||
point.bounds_grow(curr_key, curr_bounds);
|
||||
BoundBox bounds = prev_bounds;
|
||||
bounds.grow(curr_bounds);
|
||||
if (bounds.valid()) {
|
||||
const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
|
||||
references.push_back(
|
||||
BVHReference(bounds, j, i, PRIMITIVE_MOTION_POINT, prev_time, curr_time));
|
||||
root.grow(bounds);
|
||||
center.grow(bounds.center2());
|
||||
}
|
||||
/* Current time boundbox becomes previous one for the
|
||||
* next time step.
|
||||
*/
|
||||
prev_bounds = curr_bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BVHBuild::add_reference_geometry(BoundBox &root,
|
||||
BoundBox ¢er,
|
||||
Geometry *geom,
|
||||
|
@ -282,6 +378,10 @@ void BVHBuild::add_reference_geometry(BoundBox &root,
|
|||
Hair *hair = static_cast<Hair *>(geom);
|
||||
add_reference_curves(root, center, hair, object_index);
|
||||
}
|
||||
else if (geom->geometry_type == Geometry::POINTCLOUD) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
add_reference_points(root, center, pointcloud, object_index);
|
||||
}
|
||||
}
|
||||
|
||||
void BVHBuild::add_reference_object(BoundBox &root, BoundBox ¢er, Object *ob, int i)
|
||||
|
@ -311,6 +411,10 @@ static size_t count_primitives(Geometry *geom)
|
|||
Hair *hair = static_cast<Hair *>(geom);
|
||||
return count_curve_segments(hair);
|
||||
}
|
||||
else if (geom->geometry_type == Geometry::POINTCLOUD) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
return pointcloud->num_points();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -328,8 +432,9 @@ void BVHBuild::add_references(BVHRange &root)
|
|||
if (!ob->get_geometry()->is_instanced()) {
|
||||
num_alloc_references += count_primitives(ob->get_geometry());
|
||||
}
|
||||
else
|
||||
else {
|
||||
num_alloc_references++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
num_alloc_references += count_primitives(ob->get_geometry());
|
||||
|
@ -394,7 +499,7 @@ BVHNode *BVHBuild::run()
|
|||
spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha;
|
||||
spatial_free_index = 0;
|
||||
|
||||
need_prim_time = params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0;
|
||||
need_prim_time = params.use_motion_steps();
|
||||
|
||||
/* init progress updates */
|
||||
double build_start_time;
|
||||
|
@ -535,7 +640,8 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range,
|
|||
const vector<BVHReference> &references) const
|
||||
{
|
||||
size_t size = range.size();
|
||||
size_t max_leaf_size = max(params.max_triangle_leaf_size, params.max_curve_leaf_size);
|
||||
size_t max_leaf_size = max(max(params.max_triangle_leaf_size, params.max_curve_leaf_size),
|
||||
params.max_point_leaf_size);
|
||||
|
||||
if (size > max_leaf_size)
|
||||
return false;
|
||||
|
@ -544,32 +650,44 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range,
|
|||
size_t num_motion_triangles = 0;
|
||||
size_t num_curves = 0;
|
||||
size_t num_motion_curves = 0;
|
||||
size_t num_points = 0;
|
||||
size_t num_motion_points = 0;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
const BVHReference &ref = references[range.start() + i];
|
||||
|
||||
if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
|
||||
if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
|
||||
if (ref.prim_type() & PRIMITIVE_CURVE) {
|
||||
if (ref.prim_type() & PRIMITIVE_MOTION) {
|
||||
num_motion_curves++;
|
||||
}
|
||||
else {
|
||||
num_curves++;
|
||||
}
|
||||
}
|
||||
else if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
|
||||
else if (ref.prim_type() & PRIMITIVE_TRIANGLE) {
|
||||
if (ref.prim_type() & PRIMITIVE_MOTION) {
|
||||
num_motion_triangles++;
|
||||
}
|
||||
else {
|
||||
num_triangles++;
|
||||
}
|
||||
}
|
||||
else if (ref.prim_type() & PRIMITIVE_POINT) {
|
||||
if (ref.prim_type() & PRIMITIVE_MOTION) {
|
||||
num_motion_points++;
|
||||
}
|
||||
else {
|
||||
num_points++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (num_triangles <= params.max_triangle_leaf_size) &&
|
||||
(num_motion_triangles <= params.max_motion_triangle_leaf_size) &&
|
||||
(num_curves <= params.max_curve_leaf_size) &&
|
||||
(num_motion_curves <= params.max_motion_curve_leaf_size);
|
||||
(num_motion_curves <= params.max_motion_curve_leaf_size) &&
|
||||
(num_points <= params.max_point_leaf_size) &&
|
||||
(num_motion_points <= params.max_motion_point_leaf_size);
|
||||
}
|
||||
|
||||
/* multithreaded binning builder */
|
||||
|
@ -855,7 +973,7 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer
|
|||
for (int i = 0; i < range.size(); i++) {
|
||||
const BVHReference &ref = references[range.start() + i];
|
||||
if (ref.prim_index() != -1) {
|
||||
uint32_t type_index = bitscan((uint32_t)(ref.prim_type() & PRIMITIVE_ALL));
|
||||
uint32_t type_index = PRIMITIVE_INDEX(ref.prim_type() & PRIMITIVE_ALL);
|
||||
p_ref[type_index].push_back(ref);
|
||||
p_type[type_index].push_back(ref.prim_type());
|
||||
p_index[type_index].push_back(ref.prim_index());
|
||||
|
|
|
@ -39,6 +39,7 @@ class Geometry;
|
|||
class Hair;
|
||||
class Mesh;
|
||||
class Object;
|
||||
class PointCloud;
|
||||
class Progress;
|
||||
|
||||
/* BVH Builder */
|
||||
|
@ -68,6 +69,7 @@ class BVHBuild {
|
|||
/* Adding references. */
|
||||
void add_reference_triangles(BoundBox &root, BoundBox ¢er, Mesh *mesh, int i);
|
||||
void add_reference_curves(BoundBox &root, BoundBox ¢er, Hair *hair, int i);
|
||||
void add_reference_points(BoundBox &root, BoundBox ¢er, PointCloud *pointcloud, int i);
|
||||
void add_reference_geometry(BoundBox &root, BoundBox ¢er, Geometry *geom, int i);
|
||||
void add_reference_object(BoundBox &root, BoundBox ¢er, Object *ob, int i);
|
||||
void add_references(BVHRange &root);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "scene/hair.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/pointcloud.h"
|
||||
|
||||
#include "bvh/build.h"
|
||||
#include "bvh/node.h"
|
||||
|
@ -386,7 +387,7 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility
|
|||
}
|
||||
else {
|
||||
/* Primitives. */
|
||||
if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
|
||||
if (pack.prim_type[prim] & PRIMITIVE_CURVE) {
|
||||
/* Curves. */
|
||||
const Hair *hair = static_cast<const Hair *>(ob->get_geometry());
|
||||
int prim_offset = (params.top_level) ? hair->prim_offset : 0;
|
||||
|
@ -409,6 +410,30 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (pack.prim_type[prim] & PRIMITIVE_POINT) {
|
||||
/* Points. */
|
||||
const PointCloud *pointcloud = static_cast<const PointCloud *>(ob->get_geometry());
|
||||
int prim_offset = (params.top_level) ? pointcloud->prim_offset : 0;
|
||||
const float3 *points = &pointcloud->points[0];
|
||||
const float *radius = &pointcloud->radius[0];
|
||||
PointCloud::Point point = pointcloud->get_point(pidx - prim_offset);
|
||||
|
||||
point.bounds_grow(points, radius, bbox);
|
||||
|
||||
/* Motion points. */
|
||||
if (pointcloud->get_use_motion_blur()) {
|
||||
Attribute *attr = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
||||
if (attr) {
|
||||
size_t pointcloud_size = pointcloud->points.size();
|
||||
size_t steps = pointcloud->get_motion_steps() - 1;
|
||||
float3 *point_steps = attr->data_float3();
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
point.bounds_grow(point_steps + i * pointcloud_size, radius, bbox);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Triangles. */
|
||||
const Mesh *mesh = static_cast<const Mesh *>(ob->get_geometry());
|
||||
|
@ -505,7 +530,8 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
|
|||
pack.leaf_nodes.resize(leaf_nodes_size);
|
||||
pack.object_node.resize(objects.size());
|
||||
|
||||
if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) {
|
||||
if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0 ||
|
||||
params.num_motion_point_steps > 0) {
|
||||
pack.prim_time.resize(prim_index_size);
|
||||
}
|
||||
|
||||
|
@ -564,13 +590,7 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
|
|||
float2 *bvh_prim_time = bvh->pack.prim_time.size() ? &bvh->pack.prim_time[0] : NULL;
|
||||
|
||||
for (size_t i = 0; i < bvh_prim_index_size; i++) {
|
||||
if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
|
||||
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
|
||||
}
|
||||
else {
|
||||
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
|
||||
}
|
||||
|
||||
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
|
||||
pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
|
||||
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
|
||||
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
# include "scene/hair.h"
|
||||
# include "scene/mesh.h"
|
||||
# include "scene/object.h"
|
||||
# include "scene/pointcloud.h"
|
||||
|
||||
# include "util/foreach.h"
|
||||
# include "util/log.h"
|
||||
|
@ -90,7 +91,7 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
|||
++ctx->num_hits;
|
||||
|
||||
/* Always use baked shadow transparency for curves. */
|
||||
if (current_isect.type & PRIMITIVE_ALL_CURVE) {
|
||||
if (current_isect.type & PRIMITIVE_CURVE) {
|
||||
ctx->throughput *= intersection_curve_shadow_transparency(
|
||||
kg, current_isect.object, current_isect.prim, current_isect.u);
|
||||
|
||||
|
@ -245,7 +246,7 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
|||
}
|
||||
}
|
||||
|
||||
static void rtc_filter_func_thick_curve(const RTCFilterFunctionNArguments *args)
|
||||
static void rtc_filter_func_backface_cull(const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
const RTCRay *ray = (RTCRay *)args->ray;
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
|
@ -258,7 +259,7 @@ static void rtc_filter_func_thick_curve(const RTCFilterFunctionNArguments *args)
|
|||
}
|
||||
}
|
||||
|
||||
static void rtc_filter_occluded_func_thick_curve(const RTCFilterFunctionNArguments *args)
|
||||
static void rtc_filter_occluded_func_backface_cull(const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
const RTCRay *ray = (RTCRay *)args->ray;
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
|
@ -410,6 +411,12 @@ void BVHEmbree::add_object(Object *ob, int i)
|
|||
add_curves(ob, hair, i);
|
||||
}
|
||||
}
|
||||
else if (geom->geometry_type == Geometry::POINTCLOUD) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
if (pointcloud->num_points() > 0) {
|
||||
add_points(ob, pointcloud, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BVHEmbree::add_instance(Object *ob, int i)
|
||||
|
@ -624,6 +631,89 @@ void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, c
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_backface_cull);
|
||||
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_backface_cull);
|
||||
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
||||
|
||||
rtcCommitGeometry(geom_id);
|
||||
rtcAttachGeometryByID(scene, geom_id, i * 2);
|
||||
rtcReleaseGeometry(geom_id);
|
||||
}
|
||||
|
||||
void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
|
||||
{
|
||||
size_t prim_offset = hair->curve_segment_offset;
|
||||
|
@ -678,8 +768,8 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
|
|||
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
|
||||
}
|
||||
else {
|
||||
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_thick_curve);
|
||||
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_thick_curve);
|
||||
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_backface_cull);
|
||||
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_backface_cull);
|
||||
}
|
||||
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
||||
|
||||
|
@ -716,6 +806,14 @@ void BVHEmbree::refit(Progress &progress)
|
|||
rtcCommitGeometry(geom);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
geom_id += 2;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ CCL_NAMESPACE_BEGIN
|
|||
|
||||
class Hair;
|
||||
class Mesh;
|
||||
class PointCloud;
|
||||
|
||||
class BVHEmbree : public BVH {
|
||||
public:
|
||||
|
@ -51,11 +52,15 @@ class BVHEmbree : public BVH {
|
|||
void add_object(Object *ob, int i);
|
||||
void add_instance(Object *ob, int i);
|
||||
void add_curves(const Object *ob, const Hair *hair, int i);
|
||||
void add_points(const Object *ob, const PointCloud *pointcloud, int i);
|
||||
void add_triangles(const Object *ob, const Mesh *mesh, int i);
|
||||
|
||||
private:
|
||||
void set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, const bool update);
|
||||
void set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, const bool update);
|
||||
void set_point_vertex_buffer(RTCGeometry geom_id,
|
||||
const PointCloud *pointcloud,
|
||||
const bool update);
|
||||
|
||||
RTCDevice rtc_device;
|
||||
enum RTCBuildQuality build_quality;
|
||||
|
|
|
@ -83,6 +83,8 @@ class BVHParams {
|
|||
int max_motion_triangle_leaf_size;
|
||||
int max_curve_leaf_size;
|
||||
int max_motion_curve_leaf_size;
|
||||
int max_point_leaf_size;
|
||||
int max_motion_point_leaf_size;
|
||||
|
||||
/* object or mesh level bvh */
|
||||
bool top_level;
|
||||
|
@ -98,13 +100,13 @@ class BVHParams {
|
|||
/* Split time range to this number of steps and create leaf node for each
|
||||
* of this time steps.
|
||||
*
|
||||
* Speeds up rendering of motion curve primitives in the cost of higher
|
||||
* memory usage.
|
||||
* Speeds up rendering of motion primitives in the cost of higher memory usage.
|
||||
*/
|
||||
int num_motion_curve_steps;
|
||||
|
||||
/* Same as above, but for triangle primitives. */
|
||||
int num_motion_triangle_steps;
|
||||
int num_motion_curve_steps;
|
||||
int num_motion_point_steps;
|
||||
|
||||
/* Same as in SceneParams. */
|
||||
int bvh_type;
|
||||
|
@ -132,6 +134,8 @@ class BVHParams {
|
|||
max_motion_triangle_leaf_size = 8;
|
||||
max_curve_leaf_size = 1;
|
||||
max_motion_curve_leaf_size = 4;
|
||||
max_point_leaf_size = 8;
|
||||
max_motion_point_leaf_size = 8;
|
||||
|
||||
top_level = false;
|
||||
bvh_layout = BVH_LAYOUT_BVH2;
|
||||
|
@ -139,6 +143,7 @@ class BVHParams {
|
|||
|
||||
num_motion_curve_steps = 0;
|
||||
num_motion_triangle_steps = 0;
|
||||
num_motion_point_steps = 0;
|
||||
|
||||
bvh_type = 0;
|
||||
|
||||
|
@ -166,6 +171,12 @@ class BVHParams {
|
|||
return (size <= min_leaf_size || level >= MAX_DEPTH);
|
||||
}
|
||||
|
||||
bool use_motion_steps()
|
||||
{
|
||||
return num_motion_curve_steps > 0 || num_motion_triangle_steps > 0 ||
|
||||
num_motion_point_steps > 0;
|
||||
}
|
||||
|
||||
/* Gets best matching BVH.
|
||||
*
|
||||
* If the requested layout is supported by the device, it will be used.
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "scene/hair.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/pointcloud.h"
|
||||
|
||||
#include "util/algorithm.h"
|
||||
|
||||
|
@ -426,6 +427,32 @@ void BVHSpatialSplit::split_curve_primitive(const Hair *hair,
|
|||
}
|
||||
}
|
||||
|
||||
void BVHSpatialSplit::split_point_primitive(const PointCloud *pointcloud,
|
||||
const Transform *tfm,
|
||||
int prim_index,
|
||||
int dim,
|
||||
float pos,
|
||||
BoundBox &left_bounds,
|
||||
BoundBox &right_bounds)
|
||||
{
|
||||
/* No real splitting support for points, assume they are small enough for it
|
||||
* not to matter. */
|
||||
float3 point = pointcloud->get_points()[prim_index];
|
||||
|
||||
if (tfm != NULL) {
|
||||
point = transform_point(tfm, point);
|
||||
}
|
||||
point = get_unaligned_point(point);
|
||||
|
||||
if (point[dim] <= pos) {
|
||||
left_bounds.grow(point);
|
||||
}
|
||||
|
||||
if (point[dim] >= pos) {
|
||||
right_bounds.grow(point);
|
||||
}
|
||||
}
|
||||
|
||||
void BVHSpatialSplit::split_triangle_reference(const BVHReference &ref,
|
||||
const Mesh *mesh,
|
||||
int dim,
|
||||
|
@ -453,6 +480,16 @@ void BVHSpatialSplit::split_curve_reference(const BVHReference &ref,
|
|||
right_bounds);
|
||||
}
|
||||
|
||||
void BVHSpatialSplit::split_point_reference(const BVHReference &ref,
|
||||
const PointCloud *pointcloud,
|
||||
int dim,
|
||||
float pos,
|
||||
BoundBox &left_bounds,
|
||||
BoundBox &right_bounds)
|
||||
{
|
||||
split_point_primitive(pointcloud, NULL, ref.prim_index(), dim, pos, left_bounds, right_bounds);
|
||||
}
|
||||
|
||||
void BVHSpatialSplit::split_object_reference(
|
||||
const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
|
||||
{
|
||||
|
@ -475,6 +512,13 @@ void BVHSpatialSplit::split_object_reference(
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (geom->geometry_type == Geometry::POINTCLOUD) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
for (int point_idx = 0; point_idx < pointcloud->num_points(); ++point_idx) {
|
||||
split_point_primitive(
|
||||
pointcloud, &object->get_tfm(), point_idx, dim, pos, left_bounds, right_bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BVHSpatialSplit::split_reference(const BVHBuild &builder,
|
||||
|
@ -491,14 +535,18 @@ void BVHSpatialSplit::split_reference(const BVHBuild &builder,
|
|||
/* loop over vertices/edges. */
|
||||
const Object *ob = builder.objects[ref.prim_object()];
|
||||
|
||||
if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if (ref.prim_type() & PRIMITIVE_TRIANGLE) {
|
||||
Mesh *mesh = static_cast<Mesh *>(ob->get_geometry());
|
||||
split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds);
|
||||
}
|
||||
else if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
|
||||
else if (ref.prim_type() & PRIMITIVE_CURVE) {
|
||||
Hair *hair = static_cast<Hair *>(ob->get_geometry());
|
||||
split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds);
|
||||
}
|
||||
else if (ref.prim_type() & PRIMITIVE_POINT) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(ob->get_geometry());
|
||||
split_point_reference(ref, pointcloud, dim, pos, left_bounds, right_bounds);
|
||||
}
|
||||
else {
|
||||
split_object_reference(ob, dim, pos, left_bounds, right_bounds);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ CCL_NAMESPACE_BEGIN
|
|||
class BVHBuild;
|
||||
class Hair;
|
||||
class Mesh;
|
||||
class PointCloud;
|
||||
struct Transform;
|
||||
|
||||
/* Object Split */
|
||||
|
@ -123,6 +124,13 @@ class BVHSpatialSplit {
|
|||
float pos,
|
||||
BoundBox &left_bounds,
|
||||
BoundBox &right_bounds);
|
||||
void split_point_primitive(const PointCloud *pointcloud,
|
||||
const Transform *tfm,
|
||||
int prim_index,
|
||||
int dim,
|
||||
float pos,
|
||||
BoundBox &left_bounds,
|
||||
BoundBox &right_bounds);
|
||||
|
||||
/* Lower-level functions which calculates boundaries of left and right nodes
|
||||
* needed for spatial split.
|
||||
|
@ -141,6 +149,12 @@ class BVHSpatialSplit {
|
|||
float pos,
|
||||
BoundBox &left_bounds,
|
||||
BoundBox &right_bounds);
|
||||
void split_point_reference(const BVHReference &ref,
|
||||
const PointCloud *pointcloud,
|
||||
int dim,
|
||||
float pos,
|
||||
BoundBox &left_bounds,
|
||||
BoundBox &right_bounds);
|
||||
void split_object_reference(
|
||||
const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds);
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ bool BVHUnaligned::compute_aligned_space(const BVHReference &ref, Transform *ali
|
|||
const int packed_type = ref.prim_type();
|
||||
const int type = (packed_type & PRIMITIVE_ALL);
|
||||
/* No motion blur curves here, we can't fit them to aligned boxes well. */
|
||||
if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
|
||||
if ((type & PRIMITIVE_CURVE) && !(type & PRIMITIVE_MOTION)) {
|
||||
const int curve_index = ref.prim_index();
|
||||
const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
|
||||
const Hair *hair = static_cast<const Hair *>(object->get_geometry());
|
||||
|
@ -95,7 +95,7 @@ BoundBox BVHUnaligned::compute_aligned_prim_boundbox(const BVHReference &prim,
|
|||
const int packed_type = prim.prim_type();
|
||||
const int type = (packed_type & PRIMITIVE_ALL);
|
||||
/* No motion blur curves here, we can't fit them to aligned boxes well. */
|
||||
if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
|
||||
if ((type & PRIMITIVE_CURVE) && !(type & PRIMITIVE_MOTION)) {
|
||||
const int curve_index = prim.prim_index();
|
||||
const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
|
||||
const Hair *hair = static_cast<const Hair *>(object->get_geometry());
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
# include "scene/mesh.h"
|
||||
# include "scene/object.h"
|
||||
# include "scene/pass.h"
|
||||
# include "scene/pointcloud.h"
|
||||
# include "scene/scene.h"
|
||||
|
||||
# include "util/debug.h"
|
||||
|
@ -242,6 +243,9 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
|
|||
else
|
||||
pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM;
|
||||
}
|
||||
if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
|
||||
pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM;
|
||||
}
|
||||
|
||||
/* Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds
|
||||
* This is necessary since objects may be reported to have motion if the Vector pass is
|
||||
|
@ -372,6 +376,18 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
|
|||
}
|
||||
}
|
||||
|
||||
/* Pointclouds */
|
||||
if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
|
||||
group_descs[PG_HITD_POINTCLOUD] = group_descs[PG_HITD];
|
||||
group_descs[PG_HITD_POINTCLOUD].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
|
||||
group_descs[PG_HITD_POINTCLOUD].hitgroup.moduleIS = optix_module;
|
||||
group_descs[PG_HITD_POINTCLOUD].hitgroup.entryFunctionNameIS = "__intersection__point";
|
||||
group_descs[PG_HITS_POINTCLOUD] = group_descs[PG_HITS];
|
||||
group_descs[PG_HITS_POINTCLOUD].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
|
||||
group_descs[PG_HITS_POINTCLOUD].hitgroup.moduleIS = optix_module;
|
||||
group_descs[PG_HITS_POINTCLOUD].hitgroup.entryFunctionNameIS = "__intersection__point";
|
||||
}
|
||||
|
||||
if (kernel_features & (KERNEL_FEATURE_SUBSURFACE | KERNEL_FEATURE_NODE_RAYTRACE)) {
|
||||
/* Add hit group for local intersections. */
|
||||
group_descs[PG_HITL].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
|
||||
|
@ -419,6 +435,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
|
|||
stack_size[PG_HITD_MOTION].cssIS + stack_size[PG_HITD_MOTION].cssAH);
|
||||
trace_css = std::max(trace_css,
|
||||
stack_size[PG_HITS_MOTION].cssIS + stack_size[PG_HITS_MOTION].cssAH);
|
||||
trace_css = std::max(
|
||||
trace_css, stack_size[PG_HITD_POINTCLOUD].cssIS + stack_size[PG_HITD_POINTCLOUD].cssAH);
|
||||
trace_css = std::max(
|
||||
trace_css, stack_size[PG_HITS_POINTCLOUD].cssIS + stack_size[PG_HITS_POINTCLOUD].cssAH);
|
||||
|
||||
OptixPipelineLinkOptions link_options = {};
|
||||
link_options.maxTraceDepth = 1;
|
||||
|
@ -444,6 +464,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
|
|||
pipeline_groups.push_back(groups[PG_HITD_MOTION]);
|
||||
pipeline_groups.push_back(groups[PG_HITS_MOTION]);
|
||||
}
|
||||
if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
|
||||
pipeline_groups.push_back(groups[PG_HITD_POINTCLOUD]);
|
||||
pipeline_groups.push_back(groups[PG_HITS_POINTCLOUD]);
|
||||
}
|
||||
pipeline_groups.push_back(groups[PG_CALL_SVM_AO]);
|
||||
pipeline_groups.push_back(groups[PG_CALL_SVM_BEVEL]);
|
||||
|
||||
|
@ -483,6 +507,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
|
|||
pipeline_groups.push_back(groups[PG_HITD_MOTION]);
|
||||
pipeline_groups.push_back(groups[PG_HITS_MOTION]);
|
||||
}
|
||||
if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
|
||||
pipeline_groups.push_back(groups[PG_HITD_POINTCLOUD]);
|
||||
pipeline_groups.push_back(groups[PG_HITS_POINTCLOUD]);
|
||||
}
|
||||
|
||||
optix_assert(optixPipelineCreate(context,
|
||||
&pipeline_options,
|
||||
|
@ -1374,6 +1402,86 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
|
|||
build_input.triangleArray.numSbtRecords = 1;
|
||||
build_input.triangleArray.primitiveIndexOffset = mesh->prim_offset;
|
||||
|
||||
if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) {
|
||||
progress.set_error("Failed to build OptiX acceleration structure");
|
||||
}
|
||||
}
|
||||
else if (geom->geometry_type == Geometry::POINTCLOUD) {
|
||||
/* Build BLAS for points primitives. */
|
||||
PointCloud *const pointcloud = static_cast<PointCloud *const>(geom);
|
||||
const size_t num_points = pointcloud->num_points();
|
||||
if (num_points == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t num_motion_steps = 1;
|
||||
Attribute *motion_points = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
if (motion_blur && pointcloud->get_use_motion_blur() && motion_points) {
|
||||
num_motion_steps = pointcloud->get_motion_steps();
|
||||
}
|
||||
|
||||
device_vector<OptixAabb> aabb_data(this, "optix temp aabb data", MEM_READ_ONLY);
|
||||
aabb_data.alloc(num_points * num_motion_steps);
|
||||
|
||||
/* Get AABBs for each motion step. */
|
||||
for (size_t step = 0; step < num_motion_steps; ++step) {
|
||||
/* The center step for motion vertices is not stored in the attribute. */
|
||||
const float3 *points = pointcloud->get_points().data();
|
||||
const float *radius = pointcloud->get_radius().data();
|
||||
size_t center_step = (num_motion_steps - 1) / 2;
|
||||
if (step != center_step) {
|
||||
size_t attr_offset = (step > center_step) ? step - 1 : step;
|
||||
/* Technically this is a float4 array, but sizeof(float3) == sizeof(float4). */
|
||||
points = motion_points->data_float3() + attr_offset * num_points;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_points; ++i) {
|
||||
const PointCloud::Point point = pointcloud->get_point(i);
|
||||
BoundBox bounds = BoundBox::empty;
|
||||
point.bounds_grow(points, radius, bounds);
|
||||
|
||||
const size_t index = step * num_points + i;
|
||||
aabb_data[index].minX = bounds.min.x;
|
||||
aabb_data[index].minY = bounds.min.y;
|
||||
aabb_data[index].minZ = bounds.min.z;
|
||||
aabb_data[index].maxX = bounds.max.x;
|
||||
aabb_data[index].maxY = bounds.max.y;
|
||||
aabb_data[index].maxZ = bounds.max.z;
|
||||
}
|
||||
}
|
||||
|
||||
/* Upload AABB data to GPU. */
|
||||
aabb_data.copy_to_device();
|
||||
|
||||
vector<device_ptr> aabb_ptrs;
|
||||
aabb_ptrs.reserve(num_motion_steps);
|
||||
for (size_t step = 0; step < num_motion_steps; ++step) {
|
||||
aabb_ptrs.push_back(aabb_data.device_pointer + step * num_points * sizeof(OptixAabb));
|
||||
}
|
||||
|
||||
/* Disable visibility test any-hit program, since it is already checked during
|
||||
* intersection. Those trace calls that require anyhit can force it with a ray flag.
|
||||
* For those, force a single any-hit call, so shadow record-all behavior works correctly. */
|
||||
unsigned int build_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT |
|
||||
OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;
|
||||
OptixBuildInput build_input = {};
|
||||
build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
|
||||
# if OPTIX_ABI_VERSION < 23
|
||||
build_input.aabbArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
|
||||
build_input.aabbArray.numPrimitives = num_points;
|
||||
build_input.aabbArray.strideInBytes = sizeof(OptixAabb);
|
||||
build_input.aabbArray.flags = &build_flags;
|
||||
build_input.aabbArray.numSbtRecords = 1;
|
||||
build_input.aabbArray.primitiveIndexOffset = pointcloud->prim_offset;
|
||||
# else
|
||||
build_input.customPrimitiveArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
|
||||
build_input.customPrimitiveArray.numPrimitives = num_points;
|
||||
build_input.customPrimitiveArray.strideInBytes = sizeof(OptixAabb);
|
||||
build_input.customPrimitiveArray.flags = &build_flags;
|
||||
build_input.customPrimitiveArray.numSbtRecords = 1;
|
||||
build_input.customPrimitiveArray.primitiveIndexOffset = pointcloud->prim_offset;
|
||||
# endif
|
||||
|
||||
if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) {
|
||||
progress.set_error("Failed to build OptiX acceleration structure");
|
||||
}
|
||||
|
@ -1461,12 +1569,22 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
|
|||
instance.sbtOffset = PG_HITD_MOTION - PG_HITD;
|
||||
}
|
||||
}
|
||||
else if (ob->get_geometry()->geometry_type == Geometry::POINTCLOUD) {
|
||||
/* Use the hit group that has an intersection program for point clouds. */
|
||||
instance.sbtOffset = PG_HITD_POINTCLOUD - PG_HITD;
|
||||
|
||||
/* Also skip point clouds in local trace calls. */
|
||||
instance.visibilityMask |= 4;
|
||||
}
|
||||
|
||||
# if OPTIX_ABI_VERSION < 55
|
||||
/* Cannot disable any-hit program for thick curves, since it needs to filter out end-caps. */
|
||||
else
|
||||
# endif
|
||||
{
|
||||
/* Can disable __anyhit__kernel_optix_visibility_test by default.
|
||||
/* Can disable __anyhit__kernel_optix_visibility_test by default (except for thick curves,
|
||||
* since it needs to filter out end-caps there).
|
||||
|
||||
* It is enabled where necessary (visibility mask exceeds 8 bits or the other any-hit
|
||||
* programs like __anyhit__kernel_optix_shadow_all_hit) via OPTIX_RAY_FLAG_ENFORCE_ANYHIT.
|
||||
*/
|
||||
|
|
|
@ -44,6 +44,8 @@ enum {
|
|||
PG_HITV, /* __VOLUME__ hit group. */
|
||||
PG_HITD_MOTION,
|
||||
PG_HITS_MOTION,
|
||||
PG_HITD_POINTCLOUD,
|
||||
PG_HITS_POINTCLOUD,
|
||||
PG_CALL_SVM_AO,
|
||||
PG_CALL_SVM_BEVEL,
|
||||
NUM_PROGRAM_GROUPS
|
||||
|
@ -52,9 +54,9 @@ enum {
|
|||
static const int MISS_PROGRAM_GROUP_OFFSET = PG_MISS;
|
||||
static const int NUM_MIS_PROGRAM_GROUPS = 1;
|
||||
static const int HIT_PROGAM_GROUP_OFFSET = PG_HITD;
|
||||
static const int NUM_HIT_PROGRAM_GROUPS = 6;
|
||||
static const int NUM_HIT_PROGRAM_GROUPS = 8;
|
||||
static const int CALLABLE_PROGRAM_GROUPS_BASE = PG_CALL_SVM_AO;
|
||||
static const int NUM_CALLABLE_PROGRAM_GROUPS = 3;
|
||||
static const int NUM_CALLABLE_PROGRAM_GROUPS = 2;
|
||||
|
||||
/* List of OptiX pipelines. */
|
||||
enum { PIP_SHADE_RAYTRACE, PIP_INTERSECT, NUM_PIPELINES };
|
||||
|
|
|
@ -1086,8 +1086,14 @@ void RenderScheduler::update_start_resolution_divider()
|
|||
first_render_time_.denoise_time +
|
||||
first_render_time_.display_update_time;
|
||||
|
||||
/* Allow some percent of tolerance, so that if the render time is close enough to the higher
|
||||
* resolution we prefer to use it instead of going way lower resolution and time way below the
|
||||
* desired one. */
|
||||
const int resolution_divider_for_update = calculate_resolution_divider_for_time(
|
||||
desired_update_interval_in_seconds, actual_time_per_update, start_resolution_divider_);
|
||||
desired_update_interval_in_seconds * 1.4, actual_time_per_update);
|
||||
|
||||
/* TODO(sergey): Need to add hysteresis to avoid resolution divider bouncing around when actual
|
||||
* render time is somewhere on a boundary between two resolutions. */
|
||||
|
||||
/* Never increase resolution to higher than the pixel size (which is possible if the scene is
|
||||
* simple and compute device is fast). */
|
||||
|
@ -1174,14 +1180,12 @@ void RenderScheduler::check_time_limit_reached()
|
|||
* Utility functions.
|
||||
*/
|
||||
|
||||
int RenderScheduler::calculate_resolution_divider_for_time(double desired_time,
|
||||
double actual_time,
|
||||
int previous_resolution_divider)
|
||||
int RenderScheduler::calculate_resolution_divider_for_time(double desired_time, double actual_time)
|
||||
{
|
||||
/* TODO(sergey): There should a non-iterative analytical formula here. */
|
||||
|
||||
int resolution_divider = 1;
|
||||
double pre_division_time = actual_time;
|
||||
|
||||
/* This algorithm iterates through resolution dividers until a divider is found that achieves
|
||||
* the desired render time. A limit of default_start_resolution_divider_ is put in place as the
|
||||
* maximum resolution divider to avoid an unreadable viewport due to a low resolution.
|
||||
|
@ -1189,26 +1193,12 @@ int RenderScheduler::calculate_resolution_divider_for_time(double desired_time,
|
|||
* calculation to better predict the performance impact of changing resolution divisions as
|
||||
* the sample count can also change between resolution divisions. */
|
||||
while (actual_time > desired_time && resolution_divider < default_start_resolution_divider_) {
|
||||
pre_division_time = actual_time;
|
||||
int pre_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
|
||||
resolution_divider = resolution_divider * 2;
|
||||
int post_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
|
||||
actual_time /= 4.0 * pre_resolution_division_samples / post_resolution_division_samples;
|
||||
}
|
||||
|
||||
/* Hysteresis to avoid resolution divider bouncing around when actual render time is somewhere
|
||||
* on a boundary between two resolutions. This system allows some percentage of tolerance so
|
||||
* that the viewport tends towards remaining at higher resolutions rather than dropping to a
|
||||
* lower resolution if performance is close to, but not quite reaching the target frame rate.
|
||||
* This system also tends to not increase the viewport resolution unless the hardware can
|
||||
* exceed the performance target by a certain percentage. This is to help ensure the viewport
|
||||
* remains responsive after increasing the resolution. */
|
||||
if (resolution_divider > previous_resolution_divider && pre_division_time < desired_time * 1.5) {
|
||||
return resolution_divider / 2;
|
||||
}
|
||||
if (resolution_divider < previous_resolution_divider && pre_division_time > desired_time / 1.3) {
|
||||
return resolution_divider * 2;
|
||||
}
|
||||
return resolution_divider;
|
||||
}
|
||||
|
||||
|
|
|
@ -462,9 +462,7 @@ class RenderScheduler {
|
|||
* desired one. This call assumes linear dependency of render time from number of pixels
|
||||
* (quadratic dependency from the resolution divider): resolution divider of 2 brings render time
|
||||
* down by a factor of 4. */
|
||||
int calculate_resolution_divider_for_time(double desired_time,
|
||||
double actual_time,
|
||||
int previous_resolution_divider);
|
||||
int calculate_resolution_divider_for_time(double desired_time, double actual_time);
|
||||
};
|
||||
|
||||
int calculate_resolution_divider_for_resolution(int width, int height, int resolution);
|
||||
|
|
|
@ -49,24 +49,24 @@ CCL_NAMESPACE_BEGIN
|
|||
# include "kernel/bvh/nodes.h"
|
||||
|
||||
# define BVH_FUNCTION_NAME bvh_intersect
|
||||
# define BVH_FUNCTION_FEATURES 0
|
||||
# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
|
||||
# include "kernel/bvh/traversal.h"
|
||||
|
||||
# if defined(__HAIR__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_hair
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/traversal.h"
|
||||
# endif
|
||||
|
||||
# if defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_MOTION
|
||||
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/traversal.h"
|
||||
# endif
|
||||
|
||||
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/traversal.h"
|
||||
# endif
|
||||
|
||||
|
@ -102,26 +102,27 @@ CCL_NAMESPACE_BEGIN
|
|||
|
||||
# if defined(__SHADOW_RECORD_ALL__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
|
||||
# define BVH_FUNCTION_FEATURES 0
|
||||
# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
|
||||
# include "kernel/bvh/shadow_all.h"
|
||||
|
||||
# if defined(__HAIR__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/shadow_all.h"
|
||||
# endif
|
||||
|
||||
# if defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_MOTION
|
||||
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/shadow_all.h"
|
||||
# endif
|
||||
|
||||
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/shadow_all.h"
|
||||
# endif
|
||||
|
||||
# endif /* __SHADOW_RECORD_ALL__ */
|
||||
|
||||
/* Record all intersections - Volume BVH traversal. */
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
* without new features slowing things down.
|
||||
*
|
||||
* BVH_HAIR: hair curve rendering
|
||||
* BVH_POINTCLOUD: point cloud rendering
|
||||
* BVH_MOTION: motion blur rendering
|
||||
*/
|
||||
|
||||
|
@ -173,7 +174,7 @@ ccl_device_inline
|
|||
case PRIMITIVE_MOTION_CURVE_THICK:
|
||||
case PRIMITIVE_CURVE_RIBBON:
|
||||
case PRIMITIVE_MOTION_CURVE_RIBBON: {
|
||||
if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
hit = false;
|
||||
|
@ -199,6 +200,34 @@ ccl_device_inline
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
#if BVH_FEATURE(BVH_POINTCLOUD)
|
||||
case PRIMITIVE_POINT:
|
||||
case PRIMITIVE_MOTION_POINT: {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
hit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int point_object = (object == OBJECT_NONE) ?
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int point_prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
const int point_type = kernel_tex_fetch(__prim_type, prim_addr);
|
||||
hit = point_intersect(kg,
|
||||
&isect,
|
||||
P,
|
||||
dir,
|
||||
t_max_current,
|
||||
point_object,
|
||||
point_prim,
|
||||
ray->time,
|
||||
point_type);
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
|
||||
default: {
|
||||
hit = false;
|
||||
break;
|
||||
|
@ -226,7 +255,7 @@ ccl_device_inline
|
|||
bool record_intersection = true;
|
||||
|
||||
/* Always use baked shadow transparency for curves. */
|
||||
if (isect.type & PRIMITIVE_ALL_CURVE) {
|
||||
if (isect.type & PRIMITIVE_CURVE) {
|
||||
*throughput *= intersection_curve_shadow_transparency(
|
||||
kg, isect.object, isect.prim, isect.u);
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
* without new features slowing things down.
|
||||
*
|
||||
* BVH_HAIR: hair curve rendering
|
||||
* BVH_POINTCLOUD: point cloud rendering
|
||||
* BVH_MOTION: motion blur rendering
|
||||
*/
|
||||
|
||||
|
@ -165,7 +166,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
|||
case PRIMITIVE_CURVE_RIBBON:
|
||||
case PRIMITIVE_MOTION_CURVE_RIBBON: {
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
continue;
|
||||
|
@ -188,6 +189,33 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
|||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_HAIR) */
|
||||
#if BVH_FEATURE(BVH_POINTCLOUD)
|
||||
case PRIMITIVE_POINT:
|
||||
case PRIMITIVE_MOTION_POINT: {
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const int point_object = (object == OBJECT_NONE) ?
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int point_prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
const int point_type = kernel_tex_fetch(__prim_type, prim_addr);
|
||||
const bool hit = point_intersect(
|
||||
kg, isect, P, dir, isect->t, point_object, point_prim, ray->time, point_type);
|
||||
if (hit) {
|
||||
/* shadow ray early termination */
|
||||
if (visibility & PATH_RAY_SHADOW_OPAQUE)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -34,6 +34,7 @@ CCL_NAMESPACE_BEGIN
|
|||
|
||||
#define BVH_MOTION 1
|
||||
#define BVH_HAIR 2
|
||||
#define BVH_POINTCLOUD 4
|
||||
|
||||
#define BVH_NAME_JOIN(x, y) x##_##y
|
||||
#define BVH_NAME_EVAL(x, y) BVH_NAME_JOIN(x, y)
|
||||
|
|
|
@ -118,14 +118,16 @@ ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg,
|
|||
{
|
||||
int shader = 0;
|
||||
|
||||
#ifdef __HAIR__
|
||||
if (type & PRIMITIVE_ALL_TRIANGLE)
|
||||
#endif
|
||||
{
|
||||
if (type & PRIMITIVE_TRIANGLE) {
|
||||
shader = kernel_tex_fetch(__tri_shader, prim);
|
||||
}
|
||||
#ifdef __POINTCLOUD__
|
||||
else if (type & PRIMITIVE_POINT) {
|
||||
shader = kernel_tex_fetch(__points_shader, prim);
|
||||
}
|
||||
#endif
|
||||
#ifdef __HAIR__
|
||||
else {
|
||||
else if (type & PRIMITIVE_CURVE) {
|
||||
shader = kernel_tex_fetch(__curves, prim).shader_id;
|
||||
}
|
||||
#endif
|
||||
|
@ -139,14 +141,16 @@ ccl_device_forceinline int intersection_get_shader_from_isect_prim(KernelGlobals
|
|||
{
|
||||
int shader = 0;
|
||||
|
||||
#ifdef __HAIR__
|
||||
if (isect_type & PRIMITIVE_ALL_TRIANGLE)
|
||||
#endif
|
||||
{
|
||||
if (isect_type & PRIMITIVE_TRIANGLE) {
|
||||
shader = kernel_tex_fetch(__tri_shader, prim);
|
||||
}
|
||||
#ifdef __POINTCLOUD__
|
||||
else if (isect_type & PRIMITIVE_POINT) {
|
||||
shader = kernel_tex_fetch(__points_shader, prim);
|
||||
}
|
||||
#endif
|
||||
#ifdef __HAIR__
|
||||
else {
|
||||
else if (isect_type & PRIMITIVE_CURVE) {
|
||||
shader = kernel_tex_fetch(__curves, prim).shader_id;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -124,7 +124,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
|
|||
/* For curves use the smooth normal, particularly for ribbons the geometric
|
||||
* normal gives too much darkening otherwise. */
|
||||
int label;
|
||||
const float3 Ng = (sd->type & PRIMITIVE_ALL_CURVE) ? sc->N : sd->Ng;
|
||||
const float3 Ng = (sd->type & PRIMITIVE_CURVE) ? sc->N : sd->Ng;
|
||||
|
||||
switch (sc->type) {
|
||||
case CLOSURE_BSDF_DIFFUSE_ID:
|
||||
|
|
|
@ -213,9 +213,7 @@ ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd,
|
|||
|
||||
/* TODO: we convert this value to a cosine later and discard the sign, so
|
||||
* we could probably save some operations. */
|
||||
float h = (sd->type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) ?
|
||||
-sd->v :
|
||||
dot(cross(sd->Ng, X), Z);
|
||||
float h = (sd->type & PRIMITIVE_CURVE_RIBBON) ? -sd->v : dot(cross(sd->Ng, X), Z);
|
||||
|
||||
kernel_assert(fabsf(h) < 1.0f + 1e-4f);
|
||||
kernel_assert(isfinite3_safe(Y));
|
||||
|
|
|
@ -211,7 +211,7 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
|
|||
}
|
||||
|
||||
/* Always use baked shadow transparency for curves. */
|
||||
if (type & PRIMITIVE_ALL_CURVE) {
|
||||
if (type & PRIMITIVE_CURVE) {
|
||||
float throughput = payload.throughput;
|
||||
throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, u);
|
||||
payload.throughput = throughput;
|
||||
|
@ -476,7 +476,7 @@ __intersection__curve_ribbon(constant KernelParamsMetal &launch_params_metal [[b
|
|||
result.continue_search = true;
|
||||
result.distance = ray_tmax;
|
||||
|
||||
if (segment.type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
|
||||
if (segment.type & PRIMITIVE_CURVE_RIBBON) {
|
||||
metalrt_intersection_curve(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
|
||||
# if defined(__METALRT_MOTION__)
|
||||
payload.time,
|
||||
|
@ -507,7 +507,7 @@ __intersection__curve_ribbon_shadow(constant KernelParamsMetal &launch_params_me
|
|||
result.continue_search = true;
|
||||
result.distance = ray_tmax;
|
||||
|
||||
if (segment.type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
|
||||
if (segment.type & PRIMITIVE_CURVE_RIBBON) {
|
||||
metalrt_intersection_curve_shadow(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
|
||||
# if defined(__METALRT_MOTION__)
|
||||
payload.time,
|
||||
|
|
|
@ -97,9 +97,9 @@ extern "C" __global__ void __miss__kernel_optix_miss()
|
|||
|
||||
extern "C" __global__ void __anyhit__kernel_optix_local_hit()
|
||||
{
|
||||
#ifdef __HAIR__
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
if (!optixIsTriangleHit()) {
|
||||
/* Ignore curves. */
|
||||
/* Ignore curves and points. */
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
#endif
|
||||
|
@ -194,7 +194,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
|
|||
type = kernel_tex_fetch(__objects, object).primitive_type;
|
||||
}
|
||||
# ifdef __HAIR__
|
||||
else {
|
||||
else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
|
||||
u = __uint_as_float(optixGetAttribute_0());
|
||||
v = __uint_as_float(optixGetAttribute_1());
|
||||
|
||||
|
@ -210,6 +210,11 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
|
|||
# endif
|
||||
}
|
||||
# endif
|
||||
else {
|
||||
type = kernel_tex_fetch(__objects, object).primitive_type;
|
||||
u = 0.0f;
|
||||
v = 0.0f;
|
||||
}
|
||||
|
||||
# ifndef __TRANSPARENT_SHADOWS__
|
||||
/* No transparent shadows support compiled in, make opaque. */
|
||||
|
@ -229,7 +234,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
|
|||
}
|
||||
|
||||
/* Always use baked shadow transparency for curves. */
|
||||
if (type & PRIMITIVE_ALL_CURVE) {
|
||||
if (type & PRIMITIVE_CURVE) {
|
||||
float throughput = __uint_as_float(optixGetPayload_1());
|
||||
throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, u);
|
||||
optixSetPayload_1(__float_as_uint(throughput));
|
||||
|
@ -291,7 +296,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
|
|||
|
||||
extern "C" __global__ void __anyhit__kernel_optix_volume_test()
|
||||
{
|
||||
#ifdef __HAIR__
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
if (!optixIsTriangleHit()) {
|
||||
/* Ignore curves. */
|
||||
return optixIgnoreIntersection();
|
||||
|
@ -315,7 +320,7 @@ extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
|
|||
{
|
||||
#ifdef __HAIR__
|
||||
# if OPTIX_ABI_VERSION < 55
|
||||
if (!optixIsTriangleHit()) {
|
||||
if (optixGetPrimitiveType() == OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE) {
|
||||
/* Filter out curve endcaps. */
|
||||
const float u = __uint_as_float(optixGetAttribute_0());
|
||||
if (u == 0.0f || u == 1.0f) {
|
||||
|
@ -354,13 +359,19 @@ extern "C" __global__ void __closesthit__kernel_optix_hit()
|
|||
optixSetPayload_3(prim);
|
||||
optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type);
|
||||
}
|
||||
else {
|
||||
else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
|
||||
const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
|
||||
optixSetPayload_1(optixGetAttribute_0()); /* Same as 'optixGetCurveParameter()' */
|
||||
optixSetPayload_2(optixGetAttribute_1());
|
||||
optixSetPayload_3(segment.prim);
|
||||
optixSetPayload_5(segment.type);
|
||||
}
|
||||
else {
|
||||
optixSetPayload_1(0);
|
||||
optixSetPayload_2(0);
|
||||
optixSetPayload_3(prim);
|
||||
optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __HAIR__
|
||||
|
@ -395,6 +406,7 @@ ccl_device_inline void optix_intersection_curve(const int prim, const int type)
|
|||
isect.t *= len;
|
||||
|
||||
if (curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
|
||||
static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
|
||||
optixReportIntersection(isect.t / len,
|
||||
type & PRIMITIVE_ALL,
|
||||
__float_as_int(isect.u), /* Attribute_0 */
|
||||
|
@ -407,8 +419,50 @@ extern "C" __global__ void __intersection__curve_ribbon()
|
|||
const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, optixGetPrimitiveIndex());
|
||||
const int prim = segment.prim;
|
||||
const int type = segment.type;
|
||||
if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
|
||||
if (type & PRIMITIVE_CURVE_RIBBON) {
|
||||
optix_intersection_curve(prim, type);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __POINTCLOUD__
|
||||
extern "C" __global__ void __intersection__point()
|
||||
{
|
||||
const int prim = optixGetPrimitiveIndex();
|
||||
const int object = get_object_id();
|
||||
const int type = kernel_tex_fetch(__objects, object).primitive_type;
|
||||
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
const uint visibility = optixGetPayload_4();
|
||||
if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
|
||||
float3 P = optixGetObjectRayOrigin();
|
||||
float3 dir = optixGetObjectRayDirection();
|
||||
|
||||
/* The direction is not normalized by default, the point intersection routine expects that. */
|
||||
float len;
|
||||
dir = normalize_len(dir, &len);
|
||||
|
||||
# ifdef __OBJECT_MOTION__
|
||||
const float time = optixGetRayTime();
|
||||
# else
|
||||
const float time = 0.0f;
|
||||
# endif
|
||||
|
||||
Intersection isect;
|
||||
isect.t = optixGetRayTmax();
|
||||
/* Transform maximum distance into object space. */
|
||||
if (isect.t != FLT_MAX) {
|
||||
isect.t *= len;
|
||||
}
|
||||
|
||||
if (point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
|
||||
static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
|
||||
optixReportIntersection(isect.t / len, type & PRIMITIVE_ALL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -36,7 +36,7 @@ ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, ccl_private const S
|
|||
|
||||
ccl_device_inline uint attribute_primitive_type(KernelGlobals kg, ccl_private const ShaderData *sd)
|
||||
{
|
||||
if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && subd_triangle_patch(kg, sd) != ~0) {
|
||||
if ((sd->type & PRIMITIVE_TRIANGLE) && subd_triangle_patch(kg, sd) != ~0) {
|
||||
return ATTR_PRIM_SUBD;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -205,14 +205,14 @@ ccl_device float curve_thickness(KernelGlobals kg, ccl_private const ShaderData
|
|||
{
|
||||
float r = 0.0f;
|
||||
|
||||
if (sd->type & PRIMITIVE_ALL_CURVE) {
|
||||
if (sd->type & PRIMITIVE_CURVE) {
|
||||
KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
|
||||
int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
|
||||
int k1 = k0 + 1;
|
||||
|
||||
float4 P_curve[2];
|
||||
|
||||
if (!(sd->type & PRIMITIVE_ALL_MOTION)) {
|
||||
if (!(sd->type & PRIMITIVE_MOTION)) {
|
||||
P_curve[0] = kernel_tex_fetch(__curve_keys, k0);
|
||||
P_curve[1] = kernel_tex_fetch(__curve_keys, k1);
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ ccl_device float3 curve_tangent_normal(KernelGlobals kg, ccl_private const Shade
|
|||
{
|
||||
float3 tgN = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
if (sd->type & PRIMITIVE_ALL_CURVE) {
|
||||
if (sd->type & PRIMITIVE_CURVE) {
|
||||
|
||||
tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu, -sd->I) / len_squared(sd->dPdu)));
|
||||
tgN = normalize(tgN);
|
||||
|
|
|
@ -635,7 +635,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
|
|||
float time,
|
||||
int type)
|
||||
{
|
||||
const bool is_motion = (type & PRIMITIVE_ALL_MOTION);
|
||||
const bool is_motion = (type & PRIMITIVE_MOTION);
|
||||
|
||||
KernelCurve kcurve = kernel_tex_fetch(__curves, prim);
|
||||
|
||||
|
@ -655,7 +655,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
|
|||
motion_curve_keys(kg, object, prim, time, ka, k0, k1, kb, curve);
|
||||
}
|
||||
|
||||
if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
|
||||
if (type & PRIMITIVE_CURVE_RIBBON) {
|
||||
/* todo: adaptive number of subdivisions could help performance here. */
|
||||
const int subdivisions = kernel_data.bvh.curve_subdivisions;
|
||||
if (ribbon_intersect(P, dir, tmax, subdivisions, curve, isect)) {
|
||||
|
@ -704,7 +704,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
|
|||
|
||||
float4 P_curve[4];
|
||||
|
||||
if (!(sd->type & PRIMITIVE_ALL_MOTION)) {
|
||||
if (!(sd->type & PRIMITIVE_MOTION)) {
|
||||
P_curve[0] = kernel_tex_fetch(__curve_keys, ka);
|
||||
P_curve[1] = kernel_tex_fetch(__curve_keys, k0);
|
||||
P_curve[2] = kernel_tex_fetch(__curve_keys, k1);
|
||||
|
@ -719,7 +719,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
|
|||
const float4 dPdu4 = catmull_rom_basis_derivative(P_curve, sd->u);
|
||||
const float3 dPdu = float4_to_float3(dPdu4);
|
||||
|
||||
if (sd->type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
|
||||
if (sd->type & PRIMITIVE_CURVE_RIBBON) {
|
||||
/* Rounded smooth normals for ribbons, to approximate thick curve shape. */
|
||||
const float3 tangent = normalize(dPdu);
|
||||
const float3 bitangent = normalize(cross(tangent, -D));
|
||||
|
@ -727,8 +727,6 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
|
|||
const float cosine = safe_sqrtf(1.0f - sine * sine);
|
||||
|
||||
sd->N = normalize(sine * bitangent - cosine * normalize(cross(tangent, bitangent)));
|
||||
sd->Ng = -D;
|
||||
|
||||
# if 0
|
||||
/* This approximates the position and geometric normal of a thick curve too,
|
||||
* but gives too many issues with wrong self intersections. */
|
||||
|
@ -744,25 +742,27 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
|
|||
/* NOTE: It is possible that P will be the same as P_inside (precision issues, or very small
|
||||
* radius). In this case use the view direction to approximate the normal. */
|
||||
const float3 P_inside = float4_to_float3(catmull_rom_basis_eval(P_curve, sd->u));
|
||||
const float3 Ng = (!isequal_float3(P, P_inside)) ? normalize(P - P_inside) : -sd->I;
|
||||
const float3 N = (!isequal_float3(P, P_inside)) ? normalize(P - P_inside) : -sd->I;
|
||||
|
||||
sd->N = Ng;
|
||||
sd->Ng = Ng;
|
||||
sd->N = N;
|
||||
sd->v = 0.0f;
|
||||
}
|
||||
|
||||
# ifdef __DPDU__
|
||||
/* dPdu/dPdv */
|
||||
sd->dPdu = dPdu;
|
||||
sd->dPdv = cross(dPdu, sd->Ng);
|
||||
# endif
|
||||
|
||||
/* Convert to world space. */
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
const Transform tfm = object_get_transform(kg, sd);
|
||||
P = transform_point(&tfm, P);
|
||||
object_position_transform_auto(kg, sd, &P);
|
||||
object_normal_transform_auto(kg, sd, &sd->N);
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdu);
|
||||
}
|
||||
|
||||
sd->P = P;
|
||||
sd->Ng = (sd->type & PRIMITIVE_CURVE_RIBBON) ? sd->I : sd->N;
|
||||
sd->dPdv = cross(sd->dPdu, sd->Ng);
|
||||
sd->shader = kernel_tex_fetch(__curves, sd->prim).shader_id;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#include "kernel/geom/motion_triangle_intersect.h"
|
||||
#include "kernel/geom/motion_triangle_shader.h"
|
||||
#include "kernel/geom/motion_curve.h"
|
||||
#include "kernel/geom/motion_point.h"
|
||||
#include "kernel/geom/point.h"
|
||||
#include "kernel/geom/point_intersect.h"
|
||||
#include "kernel/geom/curve.h"
|
||||
#include "kernel/geom/curve_intersect.h"
|
||||
#include "kernel/geom/volume.h"
|
||||
|
|
|
@ -37,16 +37,21 @@ ccl_device_inline float primitive_surface_attribute_float(KernelGlobals kg,
|
|||
ccl_private float *dx,
|
||||
ccl_private float *dy)
|
||||
{
|
||||
if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
if (subd_triangle_patch(kg, sd) == ~0)
|
||||
return triangle_attribute_float(kg, sd, desc, dx, dy);
|
||||
else
|
||||
return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else if (sd->type & PRIMITIVE_ALL_CURVE) {
|
||||
else if (sd->type & PRIMITIVE_CURVE) {
|
||||
return curve_attribute_float(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
#ifdef __POINTCLOUD__
|
||||
else if (sd->type & PRIMITIVE_POINT) {
|
||||
return point_attribute_float(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
if (dx)
|
||||
|
@ -63,16 +68,21 @@ ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals kg,
|
|||
ccl_private float2 *dx,
|
||||
ccl_private float2 *dy)
|
||||
{
|
||||
if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
if (subd_triangle_patch(kg, sd) == ~0)
|
||||
return triangle_attribute_float2(kg, sd, desc, dx, dy);
|
||||
else
|
||||
return subd_triangle_attribute_float2(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else if (sd->type & PRIMITIVE_ALL_CURVE) {
|
||||
else if (sd->type & PRIMITIVE_CURVE) {
|
||||
return curve_attribute_float2(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
#ifdef __POINTCLOUD__
|
||||
else if (sd->type & PRIMITIVE_POINT) {
|
||||
return point_attribute_float2(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
if (dx)
|
||||
|
@ -89,16 +99,21 @@ ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals kg,
|
|||
ccl_private float3 *dx,
|
||||
ccl_private float3 *dy)
|
||||
{
|
||||
if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
if (subd_triangle_patch(kg, sd) == ~0)
|
||||
return triangle_attribute_float3(kg, sd, desc, dx, dy);
|
||||
else
|
||||
return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else if (sd->type & PRIMITIVE_ALL_CURVE) {
|
||||
else if (sd->type & PRIMITIVE_CURVE) {
|
||||
return curve_attribute_float3(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
#ifdef __POINTCLOUD__
|
||||
else if (sd->type & PRIMITIVE_POINT) {
|
||||
return point_attribute_float3(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
if (dx)
|
||||
|
@ -115,16 +130,21 @@ ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals k
|
|||
ccl_private float4 *dx,
|
||||
ccl_private float4 *dy)
|
||||
{
|
||||
if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
if (subd_triangle_patch(kg, sd) == ~0)
|
||||
return triangle_attribute_float4(kg, sd, desc, dx, dy);
|
||||
else
|
||||
return subd_triangle_attribute_float4(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else if (sd->type & PRIMITIVE_ALL_CURVE) {
|
||||
else if (sd->type & PRIMITIVE_CURVE) {
|
||||
return curve_attribute_float4(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
#ifdef __POINTCLOUD__
|
||||
else if (sd->type & PRIMITIVE_POINT) {
|
||||
return point_attribute_float4(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
if (dx)
|
||||
|
@ -225,8 +245,8 @@ ccl_device bool primitive_ptex(KernelGlobals kg,
|
|||
|
||||
ccl_device float3 primitive_tangent(KernelGlobals kg, ccl_private ShaderData *sd)
|
||||
{
|
||||
#ifdef __HAIR__
|
||||
if (sd->type & PRIMITIVE_ALL_CURVE)
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
if (sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT))
|
||||
# ifdef __DPDU__
|
||||
return normalize(sd->dPdu);
|
||||
# else
|
||||
|
@ -261,10 +281,21 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
|
|||
/* center position */
|
||||
float3 center;
|
||||
|
||||
#ifdef __HAIR__
|
||||
bool is_curve_primitive = sd->type & PRIMITIVE_ALL_CURVE;
|
||||
if (is_curve_primitive) {
|
||||
center = curve_motion_center_location(kg, sd);
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
bool is_curve_or_point = sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT);
|
||||
if (is_curve_or_point) {
|
||||
center = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
if (sd->type & PRIMITIVE_CURVE) {
|
||||
# if defined(__HAIR__)
|
||||
center = curve_motion_center_location(kg, sd);
|
||||
# endif
|
||||
}
|
||||
else if (sd->type & PRIMITIVE_POINT) {
|
||||
# if defined(__POINTCLOUD__)
|
||||
center = point_motion_center_location(kg, sd);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_position_transform(kg, sd, ¢er);
|
||||
|
@ -272,7 +303,9 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
|
|||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
center = sd->P;
|
||||
}
|
||||
|
||||
float3 motion_pre = center, motion_post = center;
|
||||
|
||||
|
@ -284,8 +317,8 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
|
|||
int numverts, numkeys;
|
||||
object_motion_info(kg, sd->object, NULL, &numverts, &numkeys);
|
||||
|
||||
#ifdef __HAIR__
|
||||
if (is_curve_primitive) {
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
if (is_curve_or_point) {
|
||||
motion_pre = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL));
|
||||
desc.offset += numkeys;
|
||||
motion_post = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL));
|
||||
|
@ -298,7 +331,7 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
|
|||
}
|
||||
else
|
||||
#endif
|
||||
if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
/* Triangle */
|
||||
if (subd_triangle_patch(kg, sd) == ~0) {
|
||||
motion_pre = triangle_attribute_float3(kg, sd, desc, NULL, NULL);
|
||||
|
|
|
@ -69,49 +69,58 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
|
|||
sd->I = -ray->D;
|
||||
|
||||
#ifdef __HAIR__
|
||||
if (sd->type & PRIMITIVE_ALL_CURVE) {
|
||||
if (sd->type & PRIMITIVE_CURVE) {
|
||||
/* curve */
|
||||
curve_shader_setup(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
/* static triangle */
|
||||
float3 Ng = triangle_normal(kg, sd);
|
||||
sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
|
||||
#ifdef __POINTCLOUD__
|
||||
if (sd->type & PRIMITIVE_POINT) {
|
||||
/* point */
|
||||
point_shader_setup(kg, sd, isect, ray);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
/* static triangle */
|
||||
float3 Ng = triangle_normal(kg, sd);
|
||||
sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
|
||||
|
||||
/* vectors */
|
||||
sd->P = triangle_refine(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
|
||||
sd->Ng = Ng;
|
||||
sd->N = Ng;
|
||||
/* vectors */
|
||||
sd->P = triangle_refine(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
|
||||
sd->Ng = Ng;
|
||||
sd->N = Ng;
|
||||
|
||||
/* smooth normal */
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL)
|
||||
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
|
||||
/* smooth normal */
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL)
|
||||
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
|
||||
|
||||
#ifdef __DPDU__
|
||||
/* dPdu/dPdv */
|
||||
triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
|
||||
/* dPdu/dPdv */
|
||||
triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* motion triangle */
|
||||
motion_triangle_shader_setup(
|
||||
kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* motion triangle */
|
||||
motion_triangle_shader_setup(
|
||||
kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim, false);
|
||||
}
|
||||
|
||||
sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
/* instance transform */
|
||||
object_normal_transform_auto(kg, sd, &sd->N);
|
||||
object_normal_transform_auto(kg, sd, &sd->Ng);
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
/* instance transform */
|
||||
object_normal_transform_auto(kg, sd, &sd->N);
|
||||
object_normal_transform_auto(kg, sd, &sd->Ng);
|
||||
#ifdef __DPDU__
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdu);
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdv);
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdu);
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdv);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
|
||||
|
||||
/* backfacing test */
|
||||
bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
|
||||
|
||||
|
@ -194,7 +203,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
|
|||
object_dir_transform_auto(kg, sd, &sd->I);
|
||||
}
|
||||
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
/* smooth normal */
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
||||
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
|
||||
|
|
|
@ -82,7 +82,7 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
|
|||
|
||||
# ifdef __HAIR__
|
||||
if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) &&
|
||||
(sd->type & PRIMITIVE_ALL_TRIANGLE))
|
||||
(sd->type & PRIMITIVE_TRIANGLE))
|
||||
# else
|
||||
if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS))
|
||||
# endif
|
||||
|
|
|
@ -191,7 +191,7 @@ ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
|
|||
float3 Ng = (transmit ? -sd->Ng : sd->Ng);
|
||||
float3 P = ray_offset(sd->P, Ng);
|
||||
|
||||
if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
|
||||
if ((sd->type & PRIMITIVE_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
|
||||
const float offset_cutoff =
|
||||
kernel_tex_fetch(__objects, sd->object).shadow_terminator_geometry_offset;
|
||||
/* Do ray offset (heavy stuff) only for close to be terminated triangles:
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "scene/colorspace.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/scene.h"
|
||||
|
||||
#include "kernel/osl/closures.h"
|
||||
|
@ -113,6 +114,8 @@ ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
|
|||
ustring OSLRenderServices::u_curve_length("geom:curve_length");
|
||||
ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
|
||||
ustring OSLRenderServices::u_curve_random("geom:curve_random");
|
||||
ustring OSLRenderServices::u_is_point("geom:is_point");
|
||||
ustring OSLRenderServices::u_point_radius("geom:point_radius");
|
||||
ustring OSLRenderServices::u_normal_map_normal("geom:normal_map_normal");
|
||||
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
|
||||
ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
|
||||
|
@ -957,13 +960,15 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
|
|||
return set_attribute_int(3, type, derivatives, val);
|
||||
}
|
||||
else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices) &&
|
||||
sd->type & PRIMITIVE_ALL_TRIANGLE) {
|
||||
sd->type & PRIMITIVE_TRIANGLE) {
|
||||
float3 P[3];
|
||||
|
||||
if (sd->type & PRIMITIVE_TRIANGLE)
|
||||
triangle_vertices(kg, sd->prim, P);
|
||||
else
|
||||
if (sd->type & PRIMITIVE_MOTION) {
|
||||
motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P);
|
||||
}
|
||||
else {
|
||||
triangle_vertices(kg, sd->prim, P);
|
||||
}
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_position_transform(kg, sd, &P[0]);
|
||||
|
@ -983,7 +988,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
|
|||
}
|
||||
/* Hair Attributes */
|
||||
else if (name == u_is_curve) {
|
||||
float f = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
|
||||
float f = (sd->type & PRIMITIVE_CURVE) != 0;
|
||||
return set_attribute_float(f, type, derivatives, val);
|
||||
}
|
||||
else if (name == u_curve_thickness) {
|
||||
|
@ -994,8 +999,17 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
|
|||
float3 f = curve_tangent_normal(kg, sd);
|
||||
return set_attribute_float3(f, type, derivatives, val);
|
||||
}
|
||||
/* point attributes */
|
||||
else if (name == u_is_point) {
|
||||
float f = (sd->type & PRIMITIVE_POINT) != 0;
|
||||
return set_attribute_float(f, type, derivatives, val);
|
||||
}
|
||||
else if (name == u_point_radius) {
|
||||
float f = point_radius(kg, sd);
|
||||
return set_attribute_float(f, type, derivatives, val);
|
||||
}
|
||||
else if (name == u_normal_map_normal) {
|
||||
if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
|
||||
return set_attribute_float3(f, type, derivatives, val);
|
||||
}
|
||||
|
|
|
@ -297,6 +297,8 @@ class OSLRenderServices : public OSL::RendererServices {
|
|||
static ustring u_curve_length;
|
||||
static ustring u_curve_tangent_normal;
|
||||
static ustring u_curve_random;
|
||||
static ustring u_is_point;
|
||||
static ustring u_point_radius;
|
||||
static ustring u_normal_map_normal;
|
||||
static ustring u_path_ray_length;
|
||||
static ustring u_path_ray_depth;
|
||||
|
|
|
@ -206,12 +206,12 @@ ccl_device float3 svm_bevel(
|
|||
for (int hit = 0; hit < num_eval_hits; hit++) {
|
||||
/* Quickly retrieve P and Ng without setting up ShaderData. */
|
||||
float3 hit_P;
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
hit_P = triangle_refine_local(
|
||||
kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim);
|
||||
}
|
||||
# ifdef __OBJECT_MOTION__
|
||||
else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
|
||||
else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {
|
||||
float3 verts[3];
|
||||
motion_triangle_vertices(kg, sd->object, isect.hits[hit].prim, sd->time, verts);
|
||||
hit_P = motion_triangle_refine_local(
|
||||
|
@ -236,11 +236,11 @@ ccl_device float3 svm_bevel(
|
|||
float u = isect.hits[hit].u;
|
||||
float v = isect.hits[hit].v;
|
||||
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
N = triangle_smooth_normal(kg, N, prim, u, v);
|
||||
}
|
||||
# ifdef __OBJECT_MOTION__
|
||||
else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
|
||||
else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {
|
||||
N = motion_triangle_smooth_normal(kg, N, sd->object, prim, u, v, sd->time);
|
||||
}
|
||||
# endif /* __OBJECT_MOTION__ */
|
||||
|
|
|
@ -107,7 +107,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
}
|
||||
|
||||
float3 N = stack_valid(data_node.x) ? stack_load_float3(stack, data_node.x) : sd->N;
|
||||
if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
|
||||
if (!(sd->type & PRIMITIVE_CURVE)) {
|
||||
N = ensure_valid_reflection(sd->Ng, sd->I, N);
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ?
|
||||
stack_load_float3(stack, data_cn_ssr.x) :
|
||||
sd->N;
|
||||
if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
|
||||
if (!(sd->type & PRIMITIVE_CURVE)) {
|
||||
clearcoat_normal = ensure_valid_reflection(sd->Ng, sd->I, clearcoat_normal);
|
||||
}
|
||||
float3 subsurface_radius = stack_valid(data_cn_ssr.y) ?
|
||||
|
@ -902,7 +902,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
if (stack_valid(data_node.y)) {
|
||||
bsdf->T = normalize(stack_load_float3(stack, data_node.y));
|
||||
}
|
||||
else if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
|
||||
else if (!(sd->type & PRIMITIVE_CURVE)) {
|
||||
bsdf->T = normalize(sd->dPdv);
|
||||
bsdf->offset = 0.0f;
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ ccl_device_noinline void svm_node_hair_info(KernelGlobals kg,
|
|||
|
||||
switch (type) {
|
||||
case NODE_INFO_CURVE_IS_STRAND: {
|
||||
data = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
|
||||
data = (sd->type & PRIMITIVE_CURVE) != 0;
|
||||
stack_store_float(stack, out_offset, data);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -291,7 +291,7 @@ ccl_device_noinline void svm_node_normal_map(KernelGlobals kg,
|
|||
|
||||
if (space == NODE_NORMAL_MAP_TANGENT) {
|
||||
/* tangent space */
|
||||
if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_ALL_TRIANGLE) == 0) {
|
||||
if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_TRIANGLE) == 0) {
|
||||
/* Fallback to unperturbed normal. */
|
||||
stack_store_float3(stack, normal_offset, sd->N);
|
||||
return;
|
||||
|
|
|
@ -42,8 +42,8 @@ ccl_device_inline float wireframe(KernelGlobals kg,
|
|||
int pixel_size,
|
||||
ccl_private float3 *P)
|
||||
{
|
||||
#ifdef __HAIR__
|
||||
if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_ALL_TRIANGLE)
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_TRIANGLE)
|
||||
#else
|
||||
if (sd->prim != PRIM_NONE)
|
||||
#endif
|
||||
|
@ -54,10 +54,12 @@ ccl_device_inline float wireframe(KernelGlobals kg,
|
|||
/* Triangles */
|
||||
int np = 3;
|
||||
|
||||
if (sd->type & PRIMITIVE_TRIANGLE)
|
||||
triangle_vertices(kg, sd->prim, Co);
|
||||
else
|
||||
if (sd->type & PRIMITIVE_MOTION) {
|
||||
motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, Co);
|
||||
}
|
||||
else {
|
||||
triangle_vertices(kg, sd->prim, Co);
|
||||
}
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_position_transform(kg, sd, &Co[0]);
|
||||
|
|
|
@ -55,6 +55,10 @@ KERNEL_TEX(KernelCurveSegment, __curve_segments)
|
|||
/* patches */
|
||||
KERNEL_TEX(uint, __patches)
|
||||
|
||||
/* pointclouds */
|
||||
KERNEL_TEX(float4, __points)
|
||||
KERNEL_TEX(uint, __points_shader)
|
||||
|
||||
/* attributes */
|
||||
KERNEL_TEX(uint4, __attributes_map)
|
||||
KERNEL_TEX(float, __attributes_float)
|
||||
|
|
|
@ -86,6 +86,7 @@ CCL_NAMESPACE_BEGIN
|
|||
#define __AO__
|
||||
#define __PASSES__
|
||||
#define __HAIR__
|
||||
#define __POINTCLOUD__
|
||||
#define __SVM__
|
||||
#define __EMISSION__
|
||||
#define __HOLDOUT__
|
||||
|
@ -125,6 +126,9 @@ CCL_NAMESPACE_BEGIN
|
|||
# if !(__KERNEL_FEATURES & KERNEL_FEATURE_HAIR)
|
||||
# undef __HAIR__
|
||||
# endif
|
||||
# if !(__KERNEL_FEATURES & KERNEL_FEATURE_POINTCLOUD)
|
||||
# undef __POINTCLOUD__
|
||||
# endif
|
||||
# if !(__KERNEL_FEATURES & KERNEL_FEATURE_VOLUME)
|
||||
# undef __VOLUME__
|
||||
# endif
|
||||
|
@ -533,28 +537,34 @@ typedef struct Intersection {
|
|||
typedef enum PrimitiveType {
|
||||
PRIMITIVE_NONE = 0,
|
||||
PRIMITIVE_TRIANGLE = (1 << 0),
|
||||
PRIMITIVE_MOTION_TRIANGLE = (1 << 1),
|
||||
PRIMITIVE_CURVE_THICK = (1 << 2),
|
||||
PRIMITIVE_MOTION_CURVE_THICK = (1 << 3),
|
||||
PRIMITIVE_CURVE_RIBBON = (1 << 4),
|
||||
PRIMITIVE_MOTION_CURVE_RIBBON = (1 << 5),
|
||||
PRIMITIVE_VOLUME = (1 << 6),
|
||||
PRIMITIVE_LAMP = (1 << 7),
|
||||
PRIMITIVE_CURVE_THICK = (1 << 1),
|
||||
PRIMITIVE_CURVE_RIBBON = (1 << 2),
|
||||
PRIMITIVE_POINT = (1 << 3),
|
||||
PRIMITIVE_VOLUME = (1 << 4),
|
||||
PRIMITIVE_LAMP = (1 << 5),
|
||||
|
||||
PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION_TRIANGLE),
|
||||
PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION_CURVE_THICK |
|
||||
PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON),
|
||||
PRIMITIVE_ALL_VOLUME = (PRIMITIVE_VOLUME),
|
||||
PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE | PRIMITIVE_MOTION_CURVE_THICK |
|
||||
PRIMITIVE_MOTION_CURVE_RIBBON),
|
||||
PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE | PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_VOLUME |
|
||||
PRIMITIVE_LAMP),
|
||||
PRIMITIVE_MOTION = (1 << 6),
|
||||
PRIMITIVE_MOTION_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION),
|
||||
PRIMITIVE_MOTION_CURVE_THICK = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION),
|
||||
PRIMITIVE_MOTION_CURVE_RIBBON = (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION),
|
||||
PRIMITIVE_MOTION_POINT = (PRIMITIVE_POINT | PRIMITIVE_MOTION),
|
||||
|
||||
PRIMITIVE_NUM = 8,
|
||||
PRIMITIVE_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_CURVE_RIBBON),
|
||||
|
||||
PRIMITIVE_ALL = (PRIMITIVE_TRIANGLE | PRIMITIVE_CURVE | PRIMITIVE_POINT | PRIMITIVE_VOLUME |
|
||||
PRIMITIVE_LAMP | PRIMITIVE_MOTION),
|
||||
|
||||
PRIMITIVE_NUM_SHAPES = 6,
|
||||
PRIMITIVE_NUM_BITS = PRIMITIVE_NUM_SHAPES + 1, /* All shapes + motion bit. */
|
||||
PRIMITIVE_NUM = PRIMITIVE_NUM_SHAPES * 2, /* With and without motion. */
|
||||
} PrimitiveType;
|
||||
|
||||
#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM) | (type))
|
||||
#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM)
|
||||
/* Convert type to index in range 0..PRIMITIVE_NUM-1. */
|
||||
#define PRIMITIVE_INDEX(type) (bitscan((uint32_t)(type)) * 2 + (((type)&PRIMITIVE_MOTION) ? 1 : 0))
|
||||
|
||||
/* Pack segment into type value to save space. */
|
||||
#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM_BITS) | (type))
|
||||
#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM_BITS)
|
||||
|
||||
typedef enum CurveShapeType {
|
||||
CURVE_RIBBON = 0,
|
||||
|
@ -605,6 +615,7 @@ typedef enum AttributeStandard {
|
|||
ATTR_STD_CURVE_INTERCEPT,
|
||||
ATTR_STD_CURVE_LENGTH,
|
||||
ATTR_STD_CURVE_RANDOM,
|
||||
ATTR_STD_POINT_RANDOM,
|
||||
ATTR_STD_PTEX_FACE_ID,
|
||||
ATTR_STD_PTEX_UV,
|
||||
ATTR_STD_VOLUME_DENSITY,
|
||||
|
@ -1604,6 +1615,9 @@ enum KernelFeatureFlag : unsigned int {
|
|||
KERNEL_FEATURE_AO_PASS = (1U << 25U),
|
||||
KERNEL_FEATURE_AO_ADDITIVE = (1U << 26U),
|
||||
KERNEL_FEATURE_AO = (KERNEL_FEATURE_AO_PASS | KERNEL_FEATURE_AO_ADDITIVE),
|
||||
|
||||
/* Point clouds. */
|
||||
KERNEL_FEATURE_POINTCLOUD = (1U << 27U),
|
||||
};
|
||||
|
||||
/* Shader node feature mask, to specialize shader evaluation for kernels. */
|
||||
|
|
|
@ -40,6 +40,7 @@ set(SRC
|
|||
mesh_displace.cpp
|
||||
mesh_subdivision.cpp
|
||||
procedural.cpp
|
||||
pointcloud.cpp
|
||||
object.cpp
|
||||
osl.cpp
|
||||
particles.cpp
|
||||
|
@ -81,6 +82,7 @@ set(SRC_HEADERS
|
|||
particles.h
|
||||
pass.h
|
||||
procedural.h
|
||||
pointcloud.h
|
||||
curves.h
|
||||
scene.h
|
||||
shader.h
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "scene/curves.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/scene.h"
|
||||
#include "scene/shader.h"
|
||||
|
||||
|
@ -99,6 +100,9 @@ void CachedData::clear()
|
|||
triangles.clear();
|
||||
uv_loops.clear();
|
||||
vertices.clear();
|
||||
points.clear();
|
||||
radiuses.clear();
|
||||
points_shader.clear();
|
||||
|
||||
for (CachedAttribute &attr : attributes) {
|
||||
attr.data.clear();
|
||||
|
@ -146,6 +150,9 @@ bool CachedData::is_constant() const
|
|||
CHECK_IF_CONSTANT(triangles)
|
||||
CHECK_IF_CONSTANT(uv_loops)
|
||||
CHECK_IF_CONSTANT(vertices)
|
||||
CHECK_IF_CONSTANT(points)
|
||||
CHECK_IF_CONSTANT(radiuses)
|
||||
CHECK_IF_CONSTANT(points_shader)
|
||||
|
||||
for (const CachedAttribute &attr : attributes) {
|
||||
if (!attr.data.is_constant()) {
|
||||
|
@ -185,6 +192,9 @@ void CachedData::invalidate_last_loaded_time(bool attributes_only)
|
|||
triangles.invalidate_last_loaded_time();
|
||||
uv_loops.invalidate_last_loaded_time();
|
||||
vertices.invalidate_last_loaded_time();
|
||||
points.invalidate_last_loaded_time();
|
||||
radiuses.invalidate_last_loaded_time();
|
||||
points_shader.invalidate_last_loaded_time();
|
||||
}
|
||||
|
||||
void CachedData::set_time_sampling(TimeSampling time_sampling)
|
||||
|
@ -206,6 +216,9 @@ void CachedData::set_time_sampling(TimeSampling time_sampling)
|
|||
triangles.set_time_sampling(time_sampling);
|
||||
uv_loops.set_time_sampling(time_sampling);
|
||||
vertices.set_time_sampling(time_sampling);
|
||||
points.set_time_sampling(time_sampling);
|
||||
radiuses.set_time_sampling(time_sampling);
|
||||
points_shader.set_time_sampling(time_sampling);
|
||||
|
||||
for (CachedAttribute &attr : attributes) {
|
||||
attr.data.set_time_sampling(time_sampling);
|
||||
|
@ -233,6 +246,9 @@ size_t CachedData::memory_used() const
|
|||
mem_used += triangles.memory_used();
|
||||
mem_used += uv_loops.memory_used();
|
||||
mem_used += vertices.memory_used();
|
||||
mem_used += points.memory_used();
|
||||
mem_used += radiuses.memory_used();
|
||||
mem_used += points_shader.memory_used();
|
||||
|
||||
for (const CachedAttribute &attr : attributes) {
|
||||
mem_used += attr.data.memory_used();
|
||||
|
@ -901,6 +917,9 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
|
|||
else if (object->schema_type == AlembicObject::CURVES) {
|
||||
read_curves(object, frame_time);
|
||||
}
|
||||
else if (object->schema_type == AlembicObject::POINTS) {
|
||||
read_points(object, frame_time);
|
||||
}
|
||||
else if (object->schema_type == AlembicObject::SUBD) {
|
||||
read_subd(object, frame_time);
|
||||
}
|
||||
|
@ -970,6 +989,9 @@ void AlembicProcedural::load_objects(Progress &progress)
|
|||
if (abc_object->schema_type == AlembicObject::CURVES) {
|
||||
geometry = scene_->create_node<Hair>();
|
||||
}
|
||||
else if (abc_object->schema_type == AlembicObject::POINTS) {
|
||||
geometry = scene_->create_node<PointCloud>();
|
||||
}
|
||||
else if (abc_object->schema_type == AlembicObject::POLY_MESH ||
|
||||
abc_object->schema_type == AlembicObject::SUBD) {
|
||||
geometry = scene_->create_node<Mesh>();
|
||||
|
@ -1202,6 +1224,45 @@ void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t fra
|
|||
hair->tag_update(scene_, rebuild);
|
||||
}
|
||||
|
||||
void AlembicProcedural::read_points(AlembicObject *abc_object, Abc::chrono_t frame_time)
|
||||
{
|
||||
CachedData &cached_data = abc_object->get_cached_data();
|
||||
|
||||
/* update sockets */
|
||||
|
||||
Object *object = abc_object->get_object();
|
||||
cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
|
||||
|
||||
if (object->is_modified()) {
|
||||
object->tag_update(scene_);
|
||||
}
|
||||
|
||||
/* Only update sockets for the original Geometry. */
|
||||
if (abc_object->instance_of) {
|
||||
return;
|
||||
}
|
||||
|
||||
PointCloud *point_cloud = static_cast<PointCloud *>(object->get_geometry());
|
||||
|
||||
/* Make sure shader ids are also updated. */
|
||||
if (point_cloud->used_shaders_is_modified()) {
|
||||
point_cloud->tag_shader_modified();
|
||||
}
|
||||
|
||||
cached_data.points.copy_to_socket(frame_time, point_cloud, point_cloud->get_points_socket());
|
||||
cached_data.radiuses.copy_to_socket(frame_time, point_cloud, point_cloud->get_radius_socket());
|
||||
cached_data.points_shader.copy_to_socket(
|
||||
frame_time, point_cloud, point_cloud->get_shader_socket());
|
||||
|
||||
/* update attributes */
|
||||
|
||||
update_attributes(point_cloud->attributes, cached_data, frame_time);
|
||||
|
||||
const bool rebuild = (point_cloud->points_is_modified() || point_cloud->radius_is_modified() ||
|
||||
point_cloud->shader_is_modified());
|
||||
point_cloud->tag_update(scene_, rebuild);
|
||||
}
|
||||
|
||||
void AlembicProcedural::walk_hierarchy(
|
||||
IObject parent,
|
||||
const ObjectHeader &header,
|
||||
|
@ -1314,7 +1375,23 @@ void AlembicProcedural::walk_hierarchy(
|
|||
// ignore the face set, it will be read along with the data
|
||||
}
|
||||
else if (IPoints::matches(header)) {
|
||||
// unsupported for now
|
||||
IPoints points(parent, header.getName());
|
||||
|
||||
unordered_map<std::string, AlembicObject *>::const_iterator iter;
|
||||
iter = object_map.find(points.getFullName());
|
||||
|
||||
if (iter != object_map.end()) {
|
||||
AlembicObject *abc_object = iter->second;
|
||||
abc_object->iobject = points;
|
||||
abc_object->schema_type = AlembicObject::POINTS;
|
||||
|
||||
if (matrix_samples_data.samples) {
|
||||
abc_object->xform_samples = *matrix_samples_data.samples;
|
||||
abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
|
||||
}
|
||||
}
|
||||
|
||||
next_object = points;
|
||||
}
|
||||
else if (INuPatch::matches(header)) {
|
||||
// unsupported for now
|
||||
|
@ -1391,6 +1468,14 @@ void AlembicProcedural::build_caches(Progress &progress)
|
|||
object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
|
||||
}
|
||||
}
|
||||
else if (object->schema_type == AlembicObject::POINTS) {
|
||||
if (!object->has_data_loaded() || default_radius_is_modified() ||
|
||||
object->radius_scale_is_modified()) {
|
||||
IPoints points(object->iobject, Alembic::Abc::kWrapExisting);
|
||||
IPointsSchema schema = points.getSchema();
|
||||
object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
|
||||
}
|
||||
}
|
||||
else if (object->schema_type == AlembicObject::SUBD) {
|
||||
if (!object->has_data_loaded()) {
|
||||
ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
|
||||
|
|
|
@ -327,6 +327,11 @@ struct CachedData {
|
|||
DataStore<array<int>> curve_first_key;
|
||||
DataStore<array<int>> curve_shader;
|
||||
|
||||
/* point data */
|
||||
DataStore<array<float3>> points;
|
||||
DataStore<array<float>> radiuses;
|
||||
DataStore<array<int>> points_shader;
|
||||
|
||||
struct CachedAttribute {
|
||||
AttributeStandard std;
|
||||
AttributeElement element;
|
||||
|
@ -414,6 +419,7 @@ class AlembicObject : public Node {
|
|||
POLY_MESH,
|
||||
SUBD,
|
||||
CURVES,
|
||||
POINTS,
|
||||
};
|
||||
|
||||
bool need_shader_update = true;
|
||||
|
@ -550,6 +556,10 @@ class AlembicProcedural : public Procedural {
|
|||
* Object Nodes in the Cycles scene if none exist yet. */
|
||||
void read_curves(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
|
||||
|
||||
/* Read the data for an IPoints at the specified frame_time. Creates corresponding Geometry and
|
||||
* Object Nodes in the Cycles scene if none exist yet. */
|
||||
void read_points(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
|
||||
|
||||
/* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and
|
||||
* Object Nodes in the Cycles scene if none exist yet. */
|
||||
void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
|
||||
|
|
|
@ -609,6 +609,55 @@ void read_geometry_data(AlembicProcedural *proc,
|
|||
read_data_loop(proc, cached_data, data, read_curves_data, progress);
|
||||
}
|
||||
|
||||
/* Points Geometries. */
|
||||
|
||||
static void read_points_data(CachedData &cached_data, const PointsSchemaData &data, chrono_t time)
|
||||
{
|
||||
const ISampleSelector iss = ISampleSelector(time);
|
||||
|
||||
const P3fArraySamplePtr position = data.positions.getValue(iss);
|
||||
FloatArraySamplePtr radiuses;
|
||||
|
||||
array<float3> a_positions;
|
||||
array<float> a_radius;
|
||||
array<int> a_shader;
|
||||
a_positions.reserve(position->size());
|
||||
a_radius.reserve(position->size());
|
||||
a_shader.reserve(position->size());
|
||||
|
||||
if (data.radiuses.valid()) {
|
||||
IFloatGeomParam::Sample wsample = data.radiuses.getExpandedValue(iss);
|
||||
radiuses = wsample.getVals();
|
||||
}
|
||||
|
||||
const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
|
||||
float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : data.default_radius;
|
||||
|
||||
int offset = 0;
|
||||
for (size_t i = 0; i < position->size(); i++) {
|
||||
const V3f &f = position->get()[offset + i];
|
||||
a_positions.push_back_slow(make_float3_from_yup(f));
|
||||
|
||||
if (do_radius) {
|
||||
radius = (*radiuses)[offset + i];
|
||||
a_radius.push_back_slow(radius);
|
||||
}
|
||||
|
||||
a_shader.push_back_slow((int)0);
|
||||
}
|
||||
|
||||
cached_data.points.add_data(a_positions, time);
|
||||
cached_data.radiuses.add_data(a_radius, time);
|
||||
cached_data.points_shader.add_data(a_shader, time);
|
||||
}
|
||||
|
||||
void read_geometry_data(AlembicProcedural *proc,
|
||||
CachedData &cached_data,
|
||||
const PointsSchemaData &data,
|
||||
Progress &progress)
|
||||
{
|
||||
read_data_loop(proc, cached_data, data, read_points_data, progress);
|
||||
}
|
||||
/* Attributes conversions. */
|
||||
|
||||
/* Type traits for converting between Alembic and Cycles types.
|
||||
|
|
|
@ -122,6 +122,26 @@ void read_geometry_data(AlembicProcedural *proc,
|
|||
const CurvesSchemaData &data,
|
||||
Progress &progress);
|
||||
|
||||
/* Data of a ICurvesSchema that we need to read. */
|
||||
struct PointsSchemaData {
|
||||
Alembic::AbcGeom::TimeSamplingPtr time_sampling;
|
||||
size_t num_samples;
|
||||
|
||||
float default_radius;
|
||||
float radius_scale;
|
||||
|
||||
Alembic::AbcGeom::IP3fArrayProperty positions;
|
||||
Alembic::AbcGeom::IInt32ArrayProperty num_points;
|
||||
Alembic::AbcGeom::IFloatGeomParam radiuses;
|
||||
// Those are unsupported for now.
|
||||
Alembic::AbcGeom::IV3fArrayProperty velocities;
|
||||
};
|
||||
|
||||
void read_geometry_data(AlembicProcedural *proc,
|
||||
CachedData &cached_data,
|
||||
const PointsSchemaData &data,
|
||||
Progress &progress);
|
||||
|
||||
void read_attributes(AlembicProcedural *proc,
|
||||
CachedData &cache,
|
||||
const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "scene/hair.h"
|
||||
#include "scene/image.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/pointcloud.h"
|
||||
|
||||
#include "util/foreach.h"
|
||||
#include "util/log.h"
|
||||
|
@ -205,6 +206,10 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
|
|||
size -= mesh->get_num_subd_verts();
|
||||
}
|
||||
}
|
||||
else if (geom->geometry_type == Geometry::POINTCLOUD) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
size = pointcloud->num_points();
|
||||
}
|
||||
break;
|
||||
case ATTR_ELEMENT_VERTEX_MOTION:
|
||||
if (geom->geometry_type == Geometry::MESH) {
|
||||
|
@ -215,6 +220,10 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
|
|||
size -= mesh->get_num_subd_verts() * (mesh->get_motion_steps() - 1);
|
||||
}
|
||||
}
|
||||
else if (geom->geometry_type == Geometry::POINTCLOUD) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
size = pointcloud->num_points() * (pointcloud->get_motion_steps() - 1);
|
||||
}
|
||||
break;
|
||||
case ATTR_ELEMENT_FACE:
|
||||
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
|
||||
|
@ -346,6 +355,8 @@ const char *Attribute::standard_name(AttributeStandard std)
|
|||
return "curve_length";
|
||||
case ATTR_STD_CURVE_RANDOM:
|
||||
return "curve_random";
|
||||
case ATTR_STD_POINT_RANDOM:
|
||||
return "point_random";
|
||||
case ATTR_STD_PTEX_FACE_ID:
|
||||
return "ptex_face_id";
|
||||
case ATTR_STD_PTEX_UV:
|
||||
|
@ -555,6 +566,28 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if (geometry->geometry_type == Geometry::POINTCLOUD) {
|
||||
switch (std) {
|
||||
case ATTR_STD_UV:
|
||||
attr = add(name, TypeFloat2, ATTR_ELEMENT_VERTEX);
|
||||
break;
|
||||
case ATTR_STD_GENERATED:
|
||||
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
|
||||
break;
|
||||
case ATTR_STD_MOTION_VERTEX_POSITION:
|
||||
attr = add(name, TypeDesc::TypeFloat4, ATTR_ELEMENT_VERTEX_MOTION);
|
||||
break;
|
||||
case ATTR_STD_POINT_RANDOM:
|
||||
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
|
||||
break;
|
||||
case ATTR_STD_GENERATED_TRANSFORM:
|
||||
attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (geometry->geometry_type == Geometry::VOLUME) {
|
||||
switch (std) {
|
||||
case ATTR_STD_VERTEX_NORMAL:
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "scene/light.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/scene.h"
|
||||
#include "scene/shader.h"
|
||||
#include "scene/shader_nodes.h"
|
||||
|
@ -240,6 +241,7 @@ void Geometry::compute_bvh(
|
|||
params->use_bvh_unaligned_nodes;
|
||||
bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
|
||||
bparams.num_motion_curve_steps = params->num_bvh_time_steps;
|
||||
bparams.num_motion_point_steps = params->num_bvh_time_steps;
|
||||
bparams.bvh_type = params->bvh_type;
|
||||
bparams.curve_subdivisions = params->curve_subdivisions();
|
||||
|
||||
|
@ -723,6 +725,12 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
|||
else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION)
|
||||
offset -= hair->curve_key_offset;
|
||||
}
|
||||
else if (geom->is_pointcloud()) {
|
||||
if (element == ATTR_ELEMENT_VERTEX)
|
||||
offset -= geom->prim_offset;
|
||||
else if (element == ATTR_ELEMENT_VERTEX_MOTION)
|
||||
offset -= geom->prim_offset;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* attribute not found */
|
||||
|
@ -1006,6 +1014,8 @@ void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout)
|
|||
size_t curve_key_size = 0;
|
||||
size_t curve_segment_size = 0;
|
||||
|
||||
size_t point_size = 0;
|
||||
|
||||
size_t patch_size = 0;
|
||||
size_t face_size = 0;
|
||||
size_t corner_size = 0;
|
||||
|
@ -1054,6 +1064,14 @@ void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout)
|
|||
curve_key_size += hair->get_curve_keys().size();
|
||||
curve_segment_size += hair->num_segments();
|
||||
}
|
||||
else if (geom->is_pointcloud()) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
|
||||
prim_offset_changed = (pointcloud->prim_offset != point_size);
|
||||
|
||||
pointcloud->prim_offset = point_size;
|
||||
point_size += pointcloud->num_points();
|
||||
}
|
||||
|
||||
if (prim_offset_changed) {
|
||||
/* Need to rebuild BVH in OptiX, since refit only allows modified mesh data there */
|
||||
|
@ -1079,6 +1097,8 @@ void GeometryManager::device_update_mesh(Device *,
|
|||
size_t curve_size = 0;
|
||||
size_t curve_segment_size = 0;
|
||||
|
||||
size_t point_size = 0;
|
||||
|
||||
size_t patch_size = 0;
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
|
@ -1106,6 +1126,10 @@ void GeometryManager::device_update_mesh(Device *,
|
|||
curve_size += hair->num_curves();
|
||||
curve_segment_size += hair->num_segments();
|
||||
}
|
||||
else if (geom->is_pointcloud()) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
point_size += pointcloud->num_points();
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in all the arrays. */
|
||||
|
@ -1201,6 +1225,26 @@ void GeometryManager::device_update_mesh(Device *,
|
|||
dscene->curve_segments.copy_to_device_if_modified();
|
||||
}
|
||||
|
||||
if (point_size != 0) {
|
||||
progress.set_status("Updating Mesh", "Copying Point clouds to device");
|
||||
|
||||
float4 *points = dscene->points.alloc(point_size);
|
||||
uint *points_shader = dscene->points_shader.alloc(point_size);
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->is_pointcloud()) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
pointcloud->pack(
|
||||
scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]);
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dscene->points.copy_to_device();
|
||||
dscene->points_shader.copy_to_device();
|
||||
}
|
||||
|
||||
if (patch_size != 0 && dscene->patches.need_realloc()) {
|
||||
progress.set_status("Updating Mesh", "Copying Patches to device");
|
||||
|
||||
|
@ -1242,6 +1286,7 @@ void GeometryManager::device_update_bvh(Device *device,
|
|||
scene->params.use_bvh_unaligned_nodes;
|
||||
bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps;
|
||||
bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps;
|
||||
bparams.num_motion_point_steps = scene->params.num_bvh_time_steps;
|
||||
bparams.bvh_type = scene->params.bvh_type;
|
||||
bparams.curve_subdivisions = scene->params.curve_subdivisions();
|
||||
|
||||
|
@ -1323,26 +1368,30 @@ void GeometryManager::device_update_bvh(Device *device,
|
|||
enum {
|
||||
DEVICE_CURVE_DATA_MODIFIED = (1 << 0),
|
||||
DEVICE_MESH_DATA_MODIFIED = (1 << 1),
|
||||
DEVICE_POINT_DATA_MODIFIED = (1 << 2),
|
||||
|
||||
ATTR_FLOAT_MODIFIED = (1 << 2),
|
||||
ATTR_FLOAT2_MODIFIED = (1 << 3),
|
||||
ATTR_FLOAT3_MODIFIED = (1 << 4),
|
||||
ATTR_FLOAT4_MODIFIED = (1 << 5),
|
||||
ATTR_UCHAR4_MODIFIED = (1 << 6),
|
||||
ATTR_FLOAT_MODIFIED = (1 << 3),
|
||||
ATTR_FLOAT2_MODIFIED = (1 << 4),
|
||||
ATTR_FLOAT3_MODIFIED = (1 << 5),
|
||||
ATTR_FLOAT4_MODIFIED = (1 << 6),
|
||||
ATTR_UCHAR4_MODIFIED = (1 << 7),
|
||||
|
||||
CURVE_DATA_NEED_REALLOC = (1 << 7),
|
||||
MESH_DATA_NEED_REALLOC = (1 << 8),
|
||||
CURVE_DATA_NEED_REALLOC = (1 << 8),
|
||||
MESH_DATA_NEED_REALLOC = (1 << 9),
|
||||
POINT_DATA_NEED_REALLOC = (1 << 10),
|
||||
|
||||
ATTR_FLOAT_NEEDS_REALLOC = (1 << 9),
|
||||
ATTR_FLOAT2_NEEDS_REALLOC = (1 << 10),
|
||||
ATTR_FLOAT3_NEEDS_REALLOC = (1 << 11),
|
||||
ATTR_FLOAT4_NEEDS_REALLOC = (1 << 12),
|
||||
ATTR_UCHAR4_NEEDS_REALLOC = (1 << 13),
|
||||
ATTR_FLOAT_NEEDS_REALLOC = (1 << 11),
|
||||
ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12),
|
||||
ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13),
|
||||
ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14),
|
||||
|
||||
ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15),
|
||||
|
||||
ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
|
||||
ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC |
|
||||
ATTR_UCHAR4_NEEDS_REALLOC),
|
||||
DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
};
|
||||
|
||||
|
@ -1529,6 +1578,17 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
|
|||
device_update_flags |= DEVICE_MESH_DATA_MODIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (geom->is_pointcloud()) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
|
||||
if (pointcloud->need_update_rebuild) {
|
||||
device_update_flags |= DEVICE_POINT_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
else if (pointcloud->is_modified()) {
|
||||
device_update_flags |= DEVICE_POINT_DATA_MODIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update_flags & (MESH_ADDED | MESH_REMOVED)) {
|
||||
|
@ -1539,10 +1599,15 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
|
|||
device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
|
||||
if (update_flags & (POINT_ADDED | POINT_REMOVED)) {
|
||||
device_update_flags |= DEVICE_POINT_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
|
||||
/* tag the device arrays for reallocation or modification */
|
||||
DeviceScene *dscene = &scene->dscene;
|
||||
|
||||
if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC)) {
|
||||
if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC |
|
||||
DEVICE_POINT_DATA_NEEDS_REALLOC)) {
|
||||
delete scene->bvh;
|
||||
scene->bvh = nullptr;
|
||||
|
||||
|
@ -1570,6 +1635,11 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
|
|||
dscene->curve_keys.tag_realloc();
|
||||
dscene->curve_segments.tag_realloc();
|
||||
}
|
||||
|
||||
if (device_update_flags & DEVICE_POINT_DATA_NEEDS_REALLOC) {
|
||||
dscene->points.tag_realloc();
|
||||
dscene->points_shader.tag_realloc();
|
||||
}
|
||||
}
|
||||
|
||||
if ((update_flags & VISIBILITY_MODIFIED) != 0) {
|
||||
|
@ -1630,6 +1700,11 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
|
|||
dscene->curve_segments.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & DEVICE_POINT_DATA_MODIFIED) {
|
||||
dscene->points.tag_modified();
|
||||
dscene->points_shader.tag_modified();
|
||||
}
|
||||
|
||||
need_flags_update = false;
|
||||
}
|
||||
|
||||
|
@ -2064,6 +2139,8 @@ void GeometryManager::device_update(Device *device,
|
|||
dscene->curves.clear_modified();
|
||||
dscene->curve_keys.clear_modified();
|
||||
dscene->curve_segments.clear_modified();
|
||||
dscene->points.clear_modified();
|
||||
dscene->points_shader.clear_modified();
|
||||
dscene->patches.clear_modified();
|
||||
dscene->attributes_map.clear_modified();
|
||||
dscene->attributes_float.clear_modified();
|
||||
|
@ -2092,6 +2169,8 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool forc
|
|||
dscene->curves.free_if_need_realloc(force_free);
|
||||
dscene->curve_keys.free_if_need_realloc(force_free);
|
||||
dscene->curve_segments.free_if_need_realloc(force_free);
|
||||
dscene->points.free_if_need_realloc(force_free);
|
||||
dscene->points_shader.free_if_need_realloc(force_free);
|
||||
dscene->patches.free_if_need_realloc(force_free);
|
||||
dscene->attributes_map.free_if_need_realloc(force_free);
|
||||
dscene->attributes_float.free_if_need_realloc(force_free);
|
||||
|
|
|
@ -55,6 +55,7 @@ class Geometry : public Node {
|
|||
MESH,
|
||||
HAIR,
|
||||
VOLUME,
|
||||
POINTCLOUD,
|
||||
};
|
||||
|
||||
Type geometry_type;
|
||||
|
@ -155,6 +156,11 @@ class Geometry : public Node {
|
|||
return geometry_type == HAIR;
|
||||
}
|
||||
|
||||
bool is_pointcloud() const
|
||||
{
|
||||
return geometry_type == POINTCLOUD;
|
||||
}
|
||||
|
||||
bool is_volume() const
|
||||
{
|
||||
return geometry_type == VOLUME;
|
||||
|
@ -181,12 +187,14 @@ class GeometryManager {
|
|||
MESH_REMOVED = (1 << 5),
|
||||
HAIR_ADDED = (1 << 6),
|
||||
HAIR_REMOVED = (1 << 7),
|
||||
POINT_ADDED = (1 << 12),
|
||||
POINT_REMOVED = (1 << 13),
|
||||
|
||||
SHADER_ATTRIBUTE_MODIFIED = (1 << 8),
|
||||
SHADER_DISPLACEMENT_MODIFIED = (1 << 9),
|
||||
|
||||
GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED,
|
||||
GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED,
|
||||
GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED | POINT_ADDED,
|
||||
GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED | POINT_REMOVED,
|
||||
|
||||
TRANSFORM_MODIFIED = (1 << 10),
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "scene/light.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/particles.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/scene.h"
|
||||
#include "scene/stats.h"
|
||||
#include "scene/volume.h"
|
||||
|
@ -69,6 +70,7 @@ struct UpdateObjectTransformState {
|
|||
/* Flags which will be synchronized to Integrator. */
|
||||
bool have_motion;
|
||||
bool have_curves;
|
||||
// bool have_points;
|
||||
|
||||
/* ** Scheduling queue. ** */
|
||||
Scene *scene;
|
||||
|
@ -435,7 +437,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
|
|||
state->have_motion = true;
|
||||
}
|
||||
|
||||
if (geom->geometry_type == Geometry::MESH) {
|
||||
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::POINTCLOUD) {
|
||||
/* TODO: why only mesh? */
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
|
||||
|
@ -491,6 +493,8 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
|
|||
kobject.dupli_generated[2] = ob->dupli_generated[2];
|
||||
kobject.numkeys = (geom->geometry_type == Geometry::HAIR) ?
|
||||
static_cast<Hair *>(geom)->get_curve_keys().size() :
|
||||
(geom->geometry_type == Geometry::POINTCLOUD) ?
|
||||
static_cast<PointCloud *>(geom)->num_points() :
|
||||
0;
|
||||
kobject.dupli_uv[0] = ob->dupli_uv[0];
|
||||
kobject.dupli_uv[1] = ob->dupli_uv[1];
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "scene/object.h"
|
||||
#include "scene/osl.h"
|
||||
#include "scene/particles.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/procedural.h"
|
||||
#include "scene/scene.h"
|
||||
#include "scene/shader.h"
|
||||
|
@ -64,6 +65,8 @@ DeviceScene::DeviceScene(Device *device)
|
|||
curve_keys(device, "__curve_keys", MEM_GLOBAL),
|
||||
curve_segments(device, "__curve_segments", MEM_GLOBAL),
|
||||
patches(device, "__patches", MEM_GLOBAL),
|
||||
points(device, "__points", MEM_GLOBAL),
|
||||
points_shader(device, "__points_shader", MEM_GLOBAL),
|
||||
objects(device, "__objects", MEM_GLOBAL),
|
||||
object_motion_pass(device, "__object_motion_pass", MEM_GLOBAL),
|
||||
object_motion(device, "__object_motion", MEM_GLOBAL),
|
||||
|
@ -523,6 +526,9 @@ void Scene::update_kernel_features()
|
|||
else if (geom->is_hair()) {
|
||||
kernel_features |= KERNEL_FEATURE_HAIR;
|
||||
}
|
||||
else if (geom->is_pointcloud()) {
|
||||
kernel_features |= KERNEL_FEATURE_POINTCLOUD;
|
||||
}
|
||||
}
|
||||
|
||||
if (bake_manager->get_baking()) {
|
||||
|
@ -575,6 +581,7 @@ static void log_kernel_features(const uint features)
|
|||
VLOG(2) << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING)
|
||||
<< "\n";
|
||||
VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n";
|
||||
VLOG(2) << "Use Pointclouds " << string_from_bool(features & KERNEL_FEATURE_POINTCLOUD) << "\n";
|
||||
VLOG(2) << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION)
|
||||
<< "\n";
|
||||
VLOG(2) << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION)
|
||||
|
@ -757,6 +764,15 @@ template<> Volume *Scene::create_node<Volume>()
|
|||
return node;
|
||||
}
|
||||
|
||||
template<> PointCloud *Scene::create_node<PointCloud>()
|
||||
{
|
||||
PointCloud *node = new PointCloud();
|
||||
node->set_owner(this);
|
||||
geometry.push_back(node);
|
||||
geometry_manager->tag_update(this, GeometryManager::POINT_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
template<> Object *Scene::create_node<Object>()
|
||||
{
|
||||
Object *node = new Object();
|
||||
|
@ -844,6 +860,12 @@ template<> void Scene::delete_node_impl(Volume *node)
|
|||
geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(PointCloud *node)
|
||||
{
|
||||
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
||||
geometry_manager->tag_update(this, GeometryManager::POINT_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Geometry *node)
|
||||
{
|
||||
uint flag;
|
||||
|
|
|
@ -54,6 +54,7 @@ class Object;
|
|||
class ObjectManager;
|
||||
class ParticleSystemManager;
|
||||
class ParticleSystem;
|
||||
class PointCloud;
|
||||
class Procedural;
|
||||
class ProceduralManager;
|
||||
class CurveSystemManager;
|
||||
|
@ -94,6 +95,10 @@ class DeviceScene {
|
|||
|
||||
device_vector<uint> patches;
|
||||
|
||||
/* pointcloud */
|
||||
device_vector<float4> points;
|
||||
device_vector<uint> points_shader;
|
||||
|
||||
/* objects */
|
||||
device_vector<KernelObject> objects;
|
||||
device_vector<Transform> object_motion_pass;
|
||||
|
@ -365,6 +370,8 @@ template<> Hair *Scene::create_node<Hair>();
|
|||
|
||||
template<> Volume *Scene::create_node<Volume>();
|
||||
|
||||
template<> PointCloud *Scene::create_node<PointCloud>();
|
||||
|
||||
template<> ParticleSystem *Scene::create_node<ParticleSystem>();
|
||||
|
||||
template<> Shader *Scene::create_node<Shader>();
|
||||
|
@ -379,6 +386,8 @@ template<> void Scene::delete_node_impl(Mesh *node);
|
|||
|
||||
template<> void Scene::delete_node_impl(Volume *node);
|
||||
|
||||
template<> void Scene::delete_node_impl(PointCloud *node);
|
||||
|
||||
template<> void Scene::delete_node_impl(Hair *node);
|
||||
|
||||
template<> void Scene::delete_node_impl(Geometry *node);
|
||||
|
|
|
@ -27,9 +27,21 @@
|
|||
|
||||
#ifdef WITH_LIBMV_GUARDED_ALLOC
|
||||
# include "MEM_guardedalloc.h"
|
||||
# define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW
|
||||
# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
|
||||
# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
|
||||
# if defined __GNUC__
|
||||
# define LIBMV_OBJECT_NEW(type, args...) \
|
||||
new (MEM_mallocN(sizeof(type), __func__)) type(args)
|
||||
# else
|
||||
# define LIBMV_OBJECT_NEW(type, ...) \
|
||||
new (MEM_mallocN(sizeof(type), __FUNCTION__)) type(__VA_ARGS__)
|
||||
# endif
|
||||
# define LIBMV_OBJECT_DELETE(what, type) \
|
||||
{ \
|
||||
if (what) { \
|
||||
((type*)what)->~type(); \
|
||||
MEM_freeN(what); \
|
||||
} \
|
||||
} \
|
||||
(void)0
|
||||
# define LIBMV_STRUCT_NEW(type, count) \
|
||||
(type*)MEM_mallocN(sizeof(type) * count, __func__)
|
||||
# define LIBMV_STRUCT_DELETE(what) MEM_freeN(what)
|
||||
|
|
|
@ -67,7 +67,7 @@ static void OCIO_reportException(Exception &exception)
|
|||
|
||||
OCIO_ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void)
|
||||
{
|
||||
ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr);
|
||||
ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__);
|
||||
|
||||
try {
|
||||
*config = GetCurrentConfig();
|
||||
|
@ -79,7 +79,7 @@ OCIO_ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void)
|
|||
OCIO_reportException(exception);
|
||||
}
|
||||
|
||||
OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr);
|
||||
MEM_delete(config);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ void OCIOImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr *config)
|
|||
|
||||
OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void)
|
||||
{
|
||||
ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr);
|
||||
ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__);
|
||||
|
||||
try {
|
||||
*config = Config::CreateFromEnv();
|
||||
|
@ -108,14 +108,14 @@ OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void)
|
|||
OCIO_reportException(exception);
|
||||
}
|
||||
|
||||
OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr);
|
||||
MEM_delete(config);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename)
|
||||
{
|
||||
ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr);
|
||||
ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__);
|
||||
|
||||
try {
|
||||
*config = Config::CreateFromFile(filename);
|
||||
|
@ -127,14 +127,14 @@ OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename)
|
|||
OCIO_reportException(exception);
|
||||
}
|
||||
|
||||
OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr);
|
||||
MEM_delete(config);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void OCIOImpl::configRelease(OCIO_ConstConfigRcPtr *config)
|
||||
{
|
||||
OBJECT_GUARDED_DELETE((ConstConfigRcPtr *)config, ConstConfigRcPtr);
|
||||
MEM_delete((ConstConfigRcPtr *)config);
|
||||
}
|
||||
|
||||
int OCIOImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config)
|
||||
|
@ -164,7 +164,7 @@ const char *OCIOImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *conf
|
|||
OCIO_ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(OCIO_ConstConfigRcPtr *config,
|
||||
const char *name)
|
||||
{
|
||||
ConstColorSpaceRcPtr *cs = OBJECT_GUARDED_NEW(ConstColorSpaceRcPtr);
|
||||
ConstColorSpaceRcPtr *cs = MEM_new<ConstColorSpaceRcPtr>(__func__);
|
||||
|
||||
try {
|
||||
*cs = (*(ConstConfigRcPtr *)config)->getColorSpace(name);
|
||||
|
@ -176,7 +176,7 @@ OCIO_ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(OCIO_ConstConfigRcPtr *
|
|||
OCIO_reportException(exception);
|
||||
}
|
||||
|
||||
OBJECT_GUARDED_DELETE(cs, ConstColorSpaceRcPtr);
|
||||
MEM_delete(cs);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ const char *OCIOImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, in
|
|||
|
||||
OCIO_ConstLookRcPtr *OCIOImpl::configGetLook(OCIO_ConstConfigRcPtr *config, const char *name)
|
||||
{
|
||||
ConstLookRcPtr *look = OBJECT_GUARDED_NEW(ConstLookRcPtr);
|
||||
ConstLookRcPtr *look = MEM_new<ConstLookRcPtr>(__func__);
|
||||
|
||||
try {
|
||||
*look = (*(ConstConfigRcPtr *)config)->getLook(name);
|
||||
|
@ -392,7 +392,7 @@ OCIO_ConstLookRcPtr *OCIOImpl::configGetLook(OCIO_ConstConfigRcPtr *config, cons
|
|||
OCIO_reportException(exception);
|
||||
}
|
||||
|
||||
OBJECT_GUARDED_DELETE(look, ConstLookRcPtr);
|
||||
MEM_delete(look);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ const char *OCIOImpl::lookGetProcessSpace(OCIO_ConstLookRcPtr *look)
|
|||
|
||||
void OCIOImpl::lookRelease(OCIO_ConstLookRcPtr *look)
|
||||
{
|
||||
OBJECT_GUARDED_DELETE((ConstLookRcPtr *)look, ConstLookRcPtr);
|
||||
MEM_delete((ConstLookRcPtr *)look);
|
||||
}
|
||||
|
||||
int OCIOImpl::colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs_)
|
||||
|
@ -521,14 +521,14 @@ void OCIOImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config_,
|
|||
|
||||
void OCIOImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs)
|
||||
{
|
||||
OBJECT_GUARDED_DELETE((ConstColorSpaceRcPtr *)cs, ConstColorSpaceRcPtr);
|
||||
MEM_delete((ConstColorSpaceRcPtr *)cs);
|
||||
}
|
||||
|
||||
OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config,
|
||||
const char *srcName,
|
||||
const char *dstName)
|
||||
{
|
||||
ConstProcessorRcPtr *processor = OBJECT_GUARDED_NEW(ConstProcessorRcPtr);
|
||||
ConstProcessorRcPtr *processor = MEM_new<ConstProcessorRcPtr>(__func__);
|
||||
|
||||
try {
|
||||
*processor = (*(ConstConfigRcPtr *)config)->getProcessor(srcName, dstName);
|
||||
|
@ -540,20 +540,20 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(OCIO_ConstConfig
|
|||
OCIO_reportException(exception);
|
||||
}
|
||||
|
||||
OBJECT_GUARDED_DELETE(processor, ConstProcessorRcPtr);
|
||||
MEM_delete(processor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OCIOImpl::processorRelease(OCIO_ConstProcessorRcPtr *processor)
|
||||
{
|
||||
OBJECT_GUARDED_DELETE(processor, ConstProcessorRcPtr);
|
||||
MEM_delete(processor);
|
||||
}
|
||||
|
||||
OCIO_ConstCPUProcessorRcPtr *OCIOImpl::processorGetCPUProcessor(
|
||||
OCIO_ConstProcessorRcPtr *processor)
|
||||
{
|
||||
ConstCPUProcessorRcPtr *cpu_processor = OBJECT_GUARDED_NEW(ConstCPUProcessorRcPtr);
|
||||
ConstCPUProcessorRcPtr *cpu_processor = MEM_new<ConstCPUProcessorRcPtr>(__func__);
|
||||
*cpu_processor = (*(ConstProcessorRcPtr *)processor)->getDefaultCPUProcessor();
|
||||
return (OCIO_ConstCPUProcessorRcPtr *)cpu_processor;
|
||||
}
|
||||
|
@ -636,7 +636,7 @@ void OCIOImpl::cpuProcessorApplyRGBA_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_
|
|||
|
||||
void OCIOImpl::cpuProcessorRelease(OCIO_ConstCPUProcessorRcPtr *cpu_processor)
|
||||
{
|
||||
OBJECT_GUARDED_DELETE(cpu_processor, ConstCPUProcessorRcPtr);
|
||||
MEM_delete(cpu_processor);
|
||||
}
|
||||
|
||||
const char *OCIOImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
|
||||
|
@ -725,7 +725,7 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr
|
|||
|
||||
/* Create processor from transform. This is the moment were OCIO validates
|
||||
* the entire transform, no need to check for the validity of inputs above. */
|
||||
ConstProcessorRcPtr *p = OBJECT_GUARDED_NEW(ConstProcessorRcPtr);
|
||||
ConstProcessorRcPtr *p = MEM_new<ConstProcessorRcPtr>(__func__);
|
||||
|
||||
try {
|
||||
*p = config->getProcessor(group);
|
||||
|
@ -737,7 +737,7 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr
|
|||
OCIO_reportException(exception);
|
||||
}
|
||||
|
||||
OBJECT_GUARDED_DELETE(p, ConstProcessorRcPtr);
|
||||
MEM_delete(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -771,7 +771,7 @@ OCIO_PackedImageDesc *OCIOImpl::createOCIO_PackedImageDesc(float *data,
|
|||
|
||||
void OCIOImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
|
||||
{
|
||||
OBJECT_GUARDED_DELETE((PackedImageDesc *)id, PackedImageDesc);
|
||||
MEM_delete((PackedImageDesc *)id);
|
||||
}
|
||||
|
||||
const char *OCIOImpl::getVersionString(void)
|
||||
|
|
|
@ -156,7 +156,7 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
|
|||
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner)
|
||||
{
|
||||
OpenSubdiv_Evaluator *evaluator = OBJECT_GUARDED_NEW(OpenSubdiv_Evaluator);
|
||||
OpenSubdiv_Evaluator *evaluator = MEM_new<OpenSubdiv_Evaluator>(__func__);
|
||||
assignFunctionPointers(evaluator);
|
||||
evaluator->impl = openSubdiv_createEvaluatorInternal(topology_refiner);
|
||||
return evaluator;
|
||||
|
@ -165,5 +165,5 @@ OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
|
|||
void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator)
|
||||
{
|
||||
openSubdiv_deleteEvaluatorInternal(evaluator->impl);
|
||||
OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_Evaluator);
|
||||
MEM_delete(evaluator);
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ void assignFunctionPointers(OpenSubdiv_TopologyRefiner *topology_refiner)
|
|||
|
||||
OpenSubdiv_TopologyRefiner *allocateTopologyRefiner()
|
||||
{
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefiner);
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner = MEM_new<OpenSubdiv_TopologyRefiner>(__func__);
|
||||
assignFunctionPointers(topology_refiner);
|
||||
return topology_refiner;
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter(
|
|||
void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner *topology_refiner)
|
||||
{
|
||||
delete topology_refiner->impl;
|
||||
OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefiner);
|
||||
MEM_delete(topology_refiner);
|
||||
}
|
||||
|
||||
bool openSubdiv_topologyRefinerCompareWithConverter(
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ece39d809ceb27b5a06da7c4b8f25ca77016b151
|
||||
Subproject commit c2eeb9bb4732602c324a011f7f913a33a5e8b1f2
|
|
@ -1 +1 @@
|
|||
Subproject commit 42da56aa73726710107031787af5eea186797984
|
||||
Subproject commit 7936dde9ece881d531b1a2ee6c45ddb56d30038c
|
|
@ -588,7 +588,7 @@ class TOPBAR_MT_edit(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("ed.undo_history", text="Undo History...")
|
||||
layout.menu("TOPBAR_MT_undo_history")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -100,9 +100,17 @@ void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dva
|
|||
*/
|
||||
void driver_change_variable_type(struct DriverVar *dvar, int type);
|
||||
/**
|
||||
* Validate driver name (after being renamed).
|
||||
* Validate driver variable name (after being renamed).
|
||||
*
|
||||
*/
|
||||
void driver_variable_name_validate(struct DriverVar *dvar);
|
||||
/**
|
||||
* Ensure the driver variable's name is unique.
|
||||
*
|
||||
* Assumes the driver variable has already been assigned to the driver, so that
|
||||
* the prev/next pointers can be used to find the other variables.
|
||||
*/
|
||||
void driver_variable_unique_name(struct DriverVar *dvar);
|
||||
/**
|
||||
* Add a new driver variable.
|
||||
*/
|
||||
|
|
|
@ -50,9 +50,6 @@ typedef struct Global {
|
|||
/** Last used location for library link/append. */
|
||||
char lib[1024];
|
||||
|
||||
/** When set: `G_MAIN->filepath` contains valid relative base path. */
|
||||
bool relbase_valid;
|
||||
|
||||
/**
|
||||
* Strings of recently opened files to show in the file menu.
|
||||
* A list of #RecentFile read from #BLENDER_HISTORY_FILE.
|
||||
|
|
|
@ -116,6 +116,7 @@ enum {
|
|||
|
||||
typedef struct Main {
|
||||
struct Main *next, *prev;
|
||||
/** The file-path of this blend file, an empty string indicates an unsaved file. */
|
||||
char filepath[1024]; /* 1024 = FILE_MAX */
|
||||
short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */
|
||||
short minversionfile, minsubversionfile;
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
|
||||
#include "RNA_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include "BLI_string_ref.hh"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -114,6 +118,7 @@ namespace nodes {
|
|||
class NodeMultiFunctionBuilder;
|
||||
class GeoNodeExecParams;
|
||||
class NodeDeclarationBuilder;
|
||||
class GatherLinkSearchOpParams;
|
||||
} // namespace nodes
|
||||
namespace fn {
|
||||
class CPPType;
|
||||
|
@ -129,10 +134,15 @@ using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, voi
|
|||
using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket,
|
||||
void *r_value);
|
||||
|
||||
/* Adds socket link operations that are specific to this node type. */
|
||||
using NodeGatherSocketLinkOperationsFunction =
|
||||
void (*)(blender::nodes::GatherLinkSearchOpParams ¶ms);
|
||||
|
||||
#else
|
||||
typedef void *NodeMultiFunctionBuildFunction;
|
||||
typedef void *NodeGeometryExecFunction;
|
||||
typedef void *NodeDeclareFunction;
|
||||
typedef void *NodeGatherSocketLinkOperationsFunction;
|
||||
typedef void *SocketGetCPPTypeFunction;
|
||||
typedef void *SocketGetGeometryNodesCPPTypeFunction;
|
||||
typedef void *SocketGetGeometryNodesCPPValueFunction;
|
||||
|
@ -284,7 +294,7 @@ typedef struct bNodeType {
|
|||
|
||||
/**
|
||||
* Can this node type be added to a node tree?
|
||||
* \param r_disabled_hint: Optional hint to display in the UI when the poll fails.
|
||||
* \param r_disabled_hint: Hint to display in the UI when the poll fails.
|
||||
* The callback can set this to a static string without having to
|
||||
* null-check it (or without setting it to null if it's not used).
|
||||
* The caller must pass a valid `const char **` and null-initialize it
|
||||
|
@ -325,6 +335,13 @@ typedef struct bNodeType {
|
|||
/* Declaration to be used when it is not dynamic. */
|
||||
NodeDeclarationHandle *fixed_declaration;
|
||||
|
||||
/**
|
||||
* Add to the list of search names and operations gathered by node link drag searching.
|
||||
* Usually it isn't necessary to override the default behavior here, but a node type can have
|
||||
* custom behavior here like adding custom search items.
|
||||
*/
|
||||
NodeGatherSocketLinkOperationsFunction gather_link_search_ops;
|
||||
|
||||
/** True when the node cannot be muted. */
|
||||
bool no_muting;
|
||||
|
||||
|
@ -402,7 +419,7 @@ typedef struct bNodeTreeType {
|
|||
/* Tree update. Overrides `nodetype->updatetreefunc` ! */
|
||||
void (*update)(struct bNodeTree *ntree);
|
||||
|
||||
bool (*validate_link)(struct bNodeTree *ntree, struct bNodeLink *link);
|
||||
bool (*validate_link)(eNodeSocketDatatype from, eNodeSocketDatatype to);
|
||||
|
||||
void (*node_add_init)(struct bNodeTree *ntree, struct bNode *bnode);
|
||||
|
||||
|
@ -943,10 +960,7 @@ bNodePreview *BKE_node_preview_verify(
|
|||
struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create);
|
||||
bNodePreview *BKE_node_preview_copy(struct bNodePreview *preview);
|
||||
void BKE_node_preview_free(struct bNodePreview *preview);
|
||||
void BKE_node_preview_init_tree(struct bNodeTree *ntree,
|
||||
int xsize,
|
||||
int ysize,
|
||||
bool create_previews);
|
||||
void BKE_node_preview_init_tree(struct bNodeTree *ntree, int xsize, int ysize);
|
||||
void BKE_node_preview_free_tree(struct bNodeTree *ntree);
|
||||
void BKE_node_preview_remove_unused(struct bNodeTree *ntree);
|
||||
void BKE_node_preview_clear(struct bNodePreview *preview);
|
||||
|
@ -957,14 +971,6 @@ void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree,
|
|||
struct bNodeTree *from_ntree,
|
||||
bool remove_old);
|
||||
|
||||
/**
|
||||
* Hack warning! this function is only used for shader previews,
|
||||
* and since it gets called multiple times per pixel for Z-transparency we only add the color once.
|
||||
* Preview gets cleared before it starts render though.
|
||||
*/
|
||||
void BKE_node_preview_set_pixel(
|
||||
struct bNodePreview *preview, const float col[4], int x, int y, bool do_manage);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -1153,7 +1159,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
|
|||
#define SH_NODE_SEPRGB 120
|
||||
#define SH_NODE_COMBRGB 121
|
||||
#define SH_NODE_HUE_SAT 122
|
||||
#define NODE_DYNAMIC 123
|
||||
|
||||
#define SH_NODE_OUTPUT_MATERIAL 124
|
||||
#define SH_NODE_OUTPUT_WORLD 125
|
||||
|
@ -1768,6 +1773,18 @@ extern struct bNodeSocketType NodeSocketTypeUndefined;
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
bNodeSocket *node_find_enabled_socket(bNode &node, eNodeSocketInOut in_out, StringRef name);
|
||||
bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name);
|
||||
bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name);
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
#endif
|
||||
|
||||
#define NODE_STORAGE_FUNCS(StorageT) \
|
||||
[[maybe_unused]] static StorageT &node_storage(bNode &node) \
|
||||
{ \
|
||||
|
|
|
@ -91,7 +91,7 @@ typedef struct UndoStep {
|
|||
/** When this is true, undo/memfile read code is allowed to re-use old data-blocks for unchanged
|
||||
* IDs, and existing depsgraphes. This has to be forbidden in some cases (like renamed IDs). */
|
||||
bool use_old_bmain_data;
|
||||
/** For use by undo systems that accumulate changes (text editor, painting). */
|
||||
/** For use by undo systems that accumulate changes (mesh-sculpt & image-painting). */
|
||||
bool is_applied;
|
||||
/* Over alloc 'type->struct_size'. */
|
||||
} UndoStep;
|
||||
|
|
|
@ -124,7 +124,7 @@ set(SRC
|
|||
intern/context.c
|
||||
intern/crazyspace.c
|
||||
intern/cryptomatte.cc
|
||||
intern/curve.c
|
||||
intern/curve.cc
|
||||
intern/curve_bevel.c
|
||||
intern/curve_convert.c
|
||||
intern/curve_decimate.c
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -46,7 +46,7 @@
|
|||
|
||||
struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset)
|
||||
{
|
||||
CurveProfile *profile = (CurveProfile *)MEM_callocN(sizeof(CurveProfile), __func__);
|
||||
CurveProfile *profile = MEM_cnew<CurveProfile>(__func__);
|
||||
|
||||
BKE_curveprofile_set_defaults(profile);
|
||||
profile->preset = preset;
|
||||
|
|
|
@ -1528,7 +1528,7 @@ void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
|
|||
bool doit = false;
|
||||
|
||||
LISTBASE_FOREACH (const DispList *, dl, dispbase) {
|
||||
const int tot = (dl->type == DL_INDEX3) ? dl->nr : dl->nr * dl->parts;
|
||||
const int tot = (ELEM(dl->type, DL_INDEX3, DL_INDEX4)) ? dl->nr : dl->nr * dl->parts;
|
||||
for (const int i : IndexRange(tot)) {
|
||||
minmax_v3v3_v3(min, max, &dl->verts[i * 3]);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_expr_pylike_eval.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string_utils.h"
|
||||
#include "BLI_threads.h"
|
||||
|
@ -864,6 +865,12 @@ void driver_variable_name_validate(DriverVar *dvar)
|
|||
}
|
||||
}
|
||||
|
||||
void driver_variable_unique_name(DriverVar *dvar)
|
||||
{
|
||||
ListBase variables = BLI_listbase_from_link((Link *)dvar);
|
||||
BLI_uniquename(&variables, dvar, dvar->name, '_', offsetof(DriverVar, name), sizeof(dvar->name));
|
||||
}
|
||||
|
||||
DriverVar *driver_add_new_variable(ChannelDriver *driver)
|
||||
{
|
||||
DriverVar *dvar;
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
#include "attribute_access_intern.hh"
|
||||
|
||||
#include "FN_cpp_type_make.hh"
|
||||
|
||||
using blender::float4x4;
|
||||
using blender::Map;
|
||||
using blender::MutableSpan;
|
||||
|
@ -39,6 +41,8 @@ using blender::Span;
|
|||
using blender::VectorSet;
|
||||
using blender::fn::GSpan;
|
||||
|
||||
MAKE_CPP_TYPE(InstanceReference, InstanceReference, CPPTypeFlags::None)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Geometry Component Implementation
|
||||
* \{ */
|
||||
|
|
|
@ -2062,9 +2062,10 @@ static void stampdata(
|
|||
time_t t;
|
||||
|
||||
if (scene->r.stamp & R_STAMP_FILENAME) {
|
||||
const char *blendfile_path = BKE_main_blendfile_path_from_global();
|
||||
SNPRINTF(stamp_data->file,
|
||||
do_prefix ? "File %s" : "%s",
|
||||
G.relbase_valid ? BKE_main_blendfile_path_from_global() : "<untitled>");
|
||||
(blendfile_path[0] != '\0') ? blendfile_path : "<untitled>");
|
||||
}
|
||||
else {
|
||||
stamp_data->file[0] = '\0';
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "BLI_ghash.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
@ -452,8 +453,60 @@ typedef struct LibOverrideGroupTagData {
|
|||
bool is_override;
|
||||
/* Whether we are creating new override, or resyncing existing one. */
|
||||
bool is_resync;
|
||||
|
||||
/* Mapping linked objects to all their instantiating collections (as a linked list).
|
||||
* Avoids calling #BKE_collection_object_find over and over, this function is very expansive. */
|
||||
GHash *linked_object_to_instantiating_collections;
|
||||
MemArena *mem_arena;
|
||||
} LibOverrideGroupTagData;
|
||||
|
||||
static void lib_override_group_tag_data_object_to_collection_init_collection_process(
|
||||
LibOverrideGroupTagData *data, Collection *collection)
|
||||
{
|
||||
LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
|
||||
Object *ob = collection_object->ob;
|
||||
if (!ID_IS_LINKED(ob)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LinkNodePair **collections_linkedlist_p;
|
||||
if (!BLI_ghash_ensure_p(data->linked_object_to_instantiating_collections,
|
||||
ob,
|
||||
(void ***)&collections_linkedlist_p)) {
|
||||
*collections_linkedlist_p = BLI_memarena_calloc(data->mem_arena,
|
||||
sizeof(**collections_linkedlist_p));
|
||||
}
|
||||
BLI_linklist_append_arena(*collections_linkedlist_p, collection, data->mem_arena);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize complex data, `data` is expected to be already initialized with basic pointers and
|
||||
* other simple data.
|
||||
*
|
||||
* NOTE: Currently creates a mapping from linked object to all of their instantiating collections
|
||||
* (as returned by #BKE_collection_object_find). */
|
||||
static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGroupTagData *data)
|
||||
{
|
||||
data->mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
||||
|
||||
data->linked_object_to_instantiating_collections = BLI_ghash_new(
|
||||
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
|
||||
if (data->scene != NULL) {
|
||||
lib_override_group_tag_data_object_to_collection_init_collection_process(
|
||||
data, data->scene->master_collection);
|
||||
}
|
||||
LISTBASE_FOREACH (Collection *, collection, &data->bmain->collections) {
|
||||
lib_override_group_tag_data_object_to_collection_init_collection_process(data, collection);
|
||||
}
|
||||
}
|
||||
|
||||
static void lib_override_group_tag_data_clear(LibOverrideGroupTagData *data)
|
||||
{
|
||||
BLI_ghash_free(data->linked_object_to_instantiating_collections, NULL, NULL);
|
||||
BLI_memarena_free(data->mem_arena);
|
||||
memset(data, 0, sizeof(*data));
|
||||
}
|
||||
|
||||
/* Tag all IDs in dependency relationships within an override hierarchy/group.
|
||||
*
|
||||
* Requires existing `Main.relations`.
|
||||
|
@ -572,7 +625,6 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
|
|||
static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
|
||||
{
|
||||
Main *bmain = data->bmain;
|
||||
Scene *scene = data->scene;
|
||||
ID *id_root = data->id_root;
|
||||
const bool is_resync = data->is_resync;
|
||||
BLI_assert(!data->is_override);
|
||||
|
@ -610,18 +662,26 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
|
|||
Collection *instantiating_collection_override_candidate = NULL;
|
||||
/* Loop over all collections instantiating the object, if we already have a 'locale' one we
|
||||
* have nothing to do, otherwise try to find a 'linked' one that we can override too. */
|
||||
while ((instantiating_collection = BKE_collection_object_find(
|
||||
bmain, scene, instantiating_collection, ob)) != NULL) {
|
||||
/* In (recursive) resync case, if a collection of a 'parent' lib instantiates the linked
|
||||
* object, it is also fine. */
|
||||
if (!ID_IS_LINKED(instantiating_collection) ||
|
||||
(is_resync && ID_IS_LINKED(id_root) &&
|
||||
instantiating_collection->id.lib->temp_index < id_root->lib->temp_index)) {
|
||||
break;
|
||||
}
|
||||
if (ID_IS_LINKED(instantiating_collection) &&
|
||||
(!is_resync || instantiating_collection->id.lib == id_root->lib)) {
|
||||
instantiating_collection_override_candidate = instantiating_collection;
|
||||
LinkNodePair *instantiating_collection_linklist = BLI_ghash_lookup(
|
||||
data->linked_object_to_instantiating_collections, ob);
|
||||
if (instantiating_collection_linklist != NULL) {
|
||||
for (LinkNode *instantiating_collection_linknode =
|
||||
instantiating_collection_linklist->list;
|
||||
instantiating_collection_linknode != NULL;
|
||||
instantiating_collection_linknode = instantiating_collection_linknode->next) {
|
||||
instantiating_collection = instantiating_collection_linknode->link;
|
||||
/* In (recursive) resync case, if a collection of a 'parent' lib instantiates the
|
||||
* linked object, it is also fine. */
|
||||
if (!ID_IS_LINKED(instantiating_collection) ||
|
||||
(is_resync && ID_IS_LINKED(id_root) &&
|
||||
instantiating_collection->id.lib->temp_index < id_root->lib->temp_index)) {
|
||||
break;
|
||||
}
|
||||
if (ID_IS_LINKED(instantiating_collection) &&
|
||||
(!is_resync || instantiating_collection->id.lib == id_root->lib)) {
|
||||
instantiating_collection_override_candidate = instantiating_collection;
|
||||
}
|
||||
instantiating_collection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -724,12 +784,14 @@ static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_roo
|
|||
.missing_tag = LIB_TAG_MISSING,
|
||||
.is_override = false,
|
||||
.is_resync = false};
|
||||
lib_override_group_tag_data_object_to_collection_init(&data);
|
||||
lib_override_linked_group_tag(&data);
|
||||
|
||||
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
|
||||
lib_override_hierarchy_dependencies_recursive_tag(&data);
|
||||
|
||||
BKE_main_relations_free(bmain);
|
||||
lib_override_group_tag_data_clear(&data);
|
||||
|
||||
return BKE_lib_override_library_create_from_tag(bmain, id_root->lib, false);
|
||||
}
|
||||
|
@ -1050,6 +1112,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
|
|||
.missing_tag = LIB_TAG_MISSING,
|
||||
.is_override = true,
|
||||
.is_resync = true};
|
||||
lib_override_group_tag_data_object_to_collection_init(&data);
|
||||
lib_override_overrides_group_tag(&data);
|
||||
|
||||
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
|
||||
|
@ -1140,6 +1203,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
|
|||
lib_override_hierarchy_dependencies_recursive_tag(&data);
|
||||
|
||||
BKE_main_relations_free(bmain);
|
||||
lib_override_group_tag_data_clear(&data);
|
||||
|
||||
/* Make new override from linked data. */
|
||||
/* Note that this call also remaps all pointers of tagged IDs from old override IDs to new
|
||||
|
@ -1532,6 +1596,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
|
|||
|
||||
/* Detect all linked data that would need to be overridden if we had to create an override from
|
||||
* those used by current existing overrides. */
|
||||
LibOverrideGroupTagData data = {.bmain = bmain,
|
||||
.scene = scene,
|
||||
.id_root = NULL,
|
||||
.tag = LIB_TAG_DOIT,
|
||||
.missing_tag = LIB_TAG_MISSING,
|
||||
.is_override = false,
|
||||
.is_resync = true};
|
||||
lib_override_group_tag_data_object_to_collection_init(&data);
|
||||
ID *id;
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
||||
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
|
||||
|
@ -1542,19 +1614,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
|
|||
continue;
|
||||
}
|
||||
|
||||
LibOverrideGroupTagData data = {.bmain = bmain,
|
||||
.scene = scene,
|
||||
.id_root = id->override_library->reference,
|
||||
.tag = LIB_TAG_DOIT,
|
||||
.missing_tag = LIB_TAG_MISSING,
|
||||
.is_override = false,
|
||||
.is_resync = true};
|
||||
data.id_root = id->override_library->reference;
|
||||
lib_override_linked_group_tag(&data);
|
||||
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
|
||||
lib_override_hierarchy_dependencies_recursive_tag(&data);
|
||||
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
|
||||
}
|
||||
FOREACH_MAIN_ID_END;
|
||||
lib_override_group_tag_data_clear(&data);
|
||||
|
||||
/* Now check existing overrides, those needing resync will be the one either already tagged as
|
||||
* such, or the one using linked data that is now tagged as needing override. */
|
||||
|
@ -1787,9 +1854,11 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
|
|||
.missing_tag = LIB_TAG_MISSING,
|
||||
.is_override = true,
|
||||
.is_resync = false};
|
||||
lib_override_group_tag_data_object_to_collection_init(&data);
|
||||
lib_override_overrides_group_tag(&data);
|
||||
|
||||
BKE_main_relations_free(bmain);
|
||||
lib_override_group_tag_data_clear(&data);
|
||||
|
||||
ID *id;
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
/* experimental (faster) normal calculation */
|
||||
// #define USE_ACCUM_NORMAL
|
||||
|
||||
#define MBALL_ARRAY_LEN_INIT 4096
|
||||
|
||||
/* Data types */
|
||||
|
||||
typedef struct corner { /* corner of a cube */
|
||||
|
@ -448,7 +450,7 @@ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4)
|
|||
#endif
|
||||
|
||||
if (UNLIKELY(process->totindex == process->curindex)) {
|
||||
process->totindex += 4096;
|
||||
process->totindex = process->totindex ? (process->totindex * 2) : MBALL_ARRAY_LEN_INIT;
|
||||
process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex);
|
||||
}
|
||||
|
||||
|
@ -946,8 +948,8 @@ static int getedge(EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, in
|
|||
*/
|
||||
static void addtovertices(PROCESS *process, const float v[3], const float no[3])
|
||||
{
|
||||
if (process->curvertex == process->totvertex) {
|
||||
process->totvertex += 4096;
|
||||
if (UNLIKELY(process->curvertex == process->totvertex)) {
|
||||
process->totvertex = process->totvertex ? process->totvertex * 2 : MBALL_ARRAY_LEN_INIT;
|
||||
process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3]));
|
||||
process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3]));
|
||||
}
|
||||
|
@ -1447,6 +1449,16 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa
|
|||
|
||||
/* add resulting surface to displist */
|
||||
if (process.curindex) {
|
||||
|
||||
/* Avoid over-allocation since this is stored in the displist. */
|
||||
if (process.curindex != process.totindex) {
|
||||
process.indices = MEM_reallocN(process.indices, sizeof(int[4]) * process.curindex);
|
||||
}
|
||||
if (process.curvertex != process.totvertex) {
|
||||
process.co = MEM_reallocN(process.co, process.curvertex * sizeof(float[3]));
|
||||
process.no = MEM_reallocN(process.no, process.curvertex * sizeof(float[3]));
|
||||
}
|
||||
|
||||
dl = MEM_callocN(sizeof(DispList), "mballdisp");
|
||||
BLI_addtail(dispbase, dl);
|
||||
dl->type = DL_INDEX4;
|
||||
|
|
|
@ -917,7 +917,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
|
|||
* will have no modifiers. */
|
||||
Object bevel_object = {{nullptr}};
|
||||
if (curve.bevobj != nullptr) {
|
||||
bevel_object = *curve.bevobj;
|
||||
memcpy(&bevel_object, curve.bevobj, sizeof(bevel_object));
|
||||
BLI_listbase_clear(&bevel_object.modifiers);
|
||||
BKE_object_runtime_reset(&bevel_object);
|
||||
curve.bevobj = &bevel_object;
|
||||
|
@ -926,7 +926,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
|
|||
/* Same thing for taper. */
|
||||
Object taper_object = {{nullptr}};
|
||||
if (curve.taperobj != nullptr) {
|
||||
taper_object = *curve.taperobj;
|
||||
memcpy(&taper_object, curve.taperobj, sizeof(taper_object));
|
||||
BLI_listbase_clear(&taper_object.modifiers);
|
||||
BKE_object_runtime_reset(&taper_object);
|
||||
curve.taperobj = &taper_object;
|
||||
|
@ -1065,7 +1065,8 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Object object_for_eval = *object;
|
||||
Object object_for_eval;
|
||||
memcpy(&object_for_eval, object, sizeof(object_for_eval));
|
||||
if (object_for_eval.runtime.data_orig != nullptr) {
|
||||
object_for_eval.data = object_for_eval.runtime.data_orig;
|
||||
}
|
||||
|
@ -1440,7 +1441,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
|
|||
/* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
|
||||
/* TODO(Sybren): the above claim came from 2.7x derived-mesh code (DM_to_mesh);
|
||||
* check whether it is still true with Mesh */
|
||||
Mesh tmp = *mesh_dst;
|
||||
Mesh tmp;
|
||||
memcpy(&tmp, mesh_dst, sizeof(tmp));
|
||||
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
|
||||
bool did_shapekeys = false;
|
||||
eCDAllocType alloctype = CD_DUPLICATE;
|
||||
|
|
|
@ -933,7 +933,7 @@ const char *BKE_modifier_path_relbase(Main *bmain, Object *ob)
|
|||
* - Else if the file has been saved return the blend file path.
|
||||
* - Else if the file isn't saved and the ID isn't from a library, return the temp dir.
|
||||
*/
|
||||
if (G.relbase_valid || ID_IS_LINKED(ob)) {
|
||||
if ((bmain->filepath[0] != '\0') || ID_IS_LINKED(ob)) {
|
||||
return ID_BLEND_PATH(bmain, &ob->id);
|
||||
}
|
||||
|
||||
|
@ -948,7 +948,8 @@ const char *BKE_modifier_path_relbase_from_global(Object *ob)
|
|||
|
||||
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
|
||||
{
|
||||
BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name);
|
||||
const char *blendfile_path = BKE_main_blendfile_path_from_global();
|
||||
BLI_join_dirfile(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -102,6 +102,7 @@ using blender::MutableSpan;
|
|||
using blender::Set;
|
||||
using blender::Span;
|
||||
using blender::Stack;
|
||||
using blender::StringRef;
|
||||
using blender::Vector;
|
||||
using blender::VectorSet;
|
||||
using blender::nodes::FieldInferencingInterface;
|
||||
|
@ -260,8 +261,7 @@ static void ntree_free_data(ID *id)
|
|||
/* XXX hack! node trees should not store execution graphs at all.
|
||||
* This should be removed when old tree types no longer require it.
|
||||
* Currently the execution data for texture nodes remains in the tree
|
||||
* after execution, until the node tree is updated or freed.
|
||||
*/
|
||||
* after execution, until the node tree is updated or freed. */
|
||||
if (ntree->execdata) {
|
||||
switch (ntree->type) {
|
||||
case NTREE_SHADER:
|
||||
|
@ -277,7 +277,7 @@ static void ntree_free_data(ID *id)
|
|||
/* XXX not nice, but needed to free localized node groups properly */
|
||||
free_localized_node_groups(ntree);
|
||||
|
||||
/* unregister associated RNA types */
|
||||
/* Unregister associated RNA types. */
|
||||
ntreeInterfaceTypeFree(ntree);
|
||||
|
||||
BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
|
||||
|
@ -521,7 +521,6 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
|
|||
|
||||
static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
|
||||
{
|
||||
/* actual socket writing */
|
||||
BLO_write_struct(writer, bNodeSocket, sock);
|
||||
|
||||
if (sock->prop) {
|
||||
|
@ -532,7 +531,6 @@ static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
|
|||
}
|
||||
static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
|
||||
{
|
||||
/* actual socket writing */
|
||||
BLO_write_struct(writer, bNodeSocket, sock);
|
||||
|
||||
if (sock->prop) {
|
||||
|
@ -546,8 +544,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
|
|||
{
|
||||
BKE_id_blend_write(writer, &ntree->id);
|
||||
|
||||
/* for link_list() speed, we write per list */
|
||||
|
||||
if (ntree->adt) {
|
||||
BKE_animdata_blend_write(writer, ntree->adt);
|
||||
}
|
||||
|
@ -571,7 +567,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
|
|||
}
|
||||
|
||||
if (node->storage) {
|
||||
/* could be handlerized at some point, now only 1 exception still */
|
||||
if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) &&
|
||||
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) {
|
||||
BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage);
|
||||
|
@ -645,13 +640,13 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
|
|||
}
|
||||
|
||||
if (node->type == CMP_NODE_OUTPUT_FILE) {
|
||||
/* inputs have own storage data */
|
||||
/* Inputs have their own storage data. */
|
||||
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
|
||||
BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage);
|
||||
}
|
||||
}
|
||||
if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
|
||||
/* write extra socket info */
|
||||
/* Write extra socket info. */
|
||||
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
|
||||
BLO_write_struct(writer, NodeImageLayer, sock->storage);
|
||||
}
|
||||
|
@ -747,7 +742,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
|
|||
}
|
||||
|
||||
if (node->storage) {
|
||||
/* could be handlerized at some point */
|
||||
switch (node->type) {
|
||||
case SH_NODE_CURVE_VEC:
|
||||
case SH_NODE_CURVE_RGB:
|
||||
|
@ -1095,21 +1089,18 @@ static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType
|
|||
return;
|
||||
}
|
||||
bNodeSocketTemplate *sockdef;
|
||||
/* bNodeSocket *sock; */ /* UNUSED */
|
||||
|
||||
if (ntype->inputs) {
|
||||
sockdef = ntype->inputs;
|
||||
while (sockdef->type != -1) {
|
||||
/* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
|
||||
|
||||
node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
|
||||
sockdef++;
|
||||
}
|
||||
}
|
||||
if (ntype->outputs) {
|
||||
sockdef = ntype->outputs;
|
||||
while (sockdef->type != -1) {
|
||||
/* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
|
||||
|
||||
node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
|
||||
sockdef++;
|
||||
}
|
||||
}
|
||||
|
@ -1167,8 +1158,7 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
|
|||
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
|
||||
|
||||
/* XXX Warning: context can be nullptr in case nodes are added in do_versions.
|
||||
* Delayed init is not supported for nodes with context-based `initfunc_api` at the moment.
|
||||
*/
|
||||
* Delayed init is not supported for nodes with context-based `initfunc_api` at the moment. */
|
||||
BLI_assert(C != nullptr);
|
||||
ntype->initfunc_api(C, &ptr);
|
||||
}
|
||||
|
@ -1382,18 +1372,6 @@ bNodeType *nodeTypeFind(const char *idname)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static void free_dynamic_typeinfo(bNodeType *ntype)
|
||||
{
|
||||
if (ntype->type == NODE_DYNAMIC) {
|
||||
if (ntype->inputs) {
|
||||
MEM_freeN(ntype->inputs);
|
||||
}
|
||||
if (ntype->outputs) {
|
||||
MEM_freeN(ntype->outputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* callback for hash value free function */
|
||||
static void node_free_type(void *nodetype_v)
|
||||
{
|
||||
|
@ -1403,11 +1381,6 @@ static void node_free_type(void *nodetype_v)
|
|||
* or we'd want to update *all* active Mains, which we cannot do anyway currently. */
|
||||
update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true);
|
||||
|
||||
/* XXX deprecated */
|
||||
if (nodetype->type == NODE_DYNAMIC) {
|
||||
free_dynamic_typeinfo(nodetype);
|
||||
}
|
||||
|
||||
delete nodetype->fixed_declaration;
|
||||
nodetype->fixed_declaration = nullptr;
|
||||
|
||||
|
@ -1522,6 +1495,33 @@ struct bNodeSocket *nodeFindSocket(const bNode *node,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
bNodeSocket *node_find_enabled_socket(bNode &node,
|
||||
const eNodeSocketInOut in_out,
|
||||
const StringRef name)
|
||||
{
|
||||
ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
|
||||
if (!(socket->flag & SOCK_UNAVAIL) && socket->name == name) {
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name)
|
||||
{
|
||||
return node_find_enabled_socket(node, SOCK_IN, name);
|
||||
}
|
||||
|
||||
bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name)
|
||||
{
|
||||
return node_find_enabled_socket(node, SOCK_OUT, name);
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/* find unique socket identifier */
|
||||
static bool unique_identifier_check(void *arg, const char *identifier)
|
||||
{
|
||||
|
@ -1552,7 +1552,7 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
|
|||
/* if no explicit identifier is given, assign a unique identifier based on the name */
|
||||
BLI_strncpy(auto_identifier, name, sizeof(auto_identifier));
|
||||
}
|
||||
/* make the identifier unique */
|
||||
/* Make the identifier unique. */
|
||||
BLI_uniquename_cb(
|
||||
unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier));
|
||||
|
||||
|
@ -1982,10 +1982,7 @@ bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree,
|
|||
return sock;
|
||||
}
|
||||
|
||||
static void node_socket_free(bNodeTree *UNUSED(ntree),
|
||||
bNodeSocket *sock,
|
||||
bNode *UNUSED(node),
|
||||
const bool do_id_user)
|
||||
static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
|
||||
{
|
||||
if (sock->prop) {
|
||||
IDP_FreePropertyContent_ex(sock->prop, do_id_user);
|
||||
|
@ -2020,7 +2017,7 @@ void nodeRemoveSocketEx(struct bNodeTree *ntree,
|
|||
BLI_remlink(&node->inputs, sock);
|
||||
BLI_remlink(&node->outputs, sock);
|
||||
|
||||
node_socket_free(ntree, sock, node, do_id_user);
|
||||
node_socket_free(sock, do_id_user);
|
||||
MEM_freeN(sock);
|
||||
|
||||
node->update |= NODE_UPDATE;
|
||||
|
@ -2035,13 +2032,13 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
|
|||
}
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
|
||||
node_socket_free(ntree, sock, node, true);
|
||||
node_socket_free(sock, true);
|
||||
MEM_freeN(sock);
|
||||
}
|
||||
BLI_listbase_clear(&node->inputs);
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
|
||||
node_socket_free(ntree, sock, node, true);
|
||||
node_socket_free(sock, true);
|
||||
MEM_freeN(sock);
|
||||
}
|
||||
BLI_listbase_clear(&node->outputs);
|
||||
|
@ -2208,9 +2205,8 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
|
|||
const char *idname = nullptr;
|
||||
|
||||
NODE_TYPES_BEGIN (ntype) {
|
||||
/* do an extra poll here, because some int types are used
|
||||
* for multiple node types, this helps find the desired type
|
||||
*/
|
||||
/* Do an extra poll here, because some int types are used
|
||||
* for multiple node types, this helps find the desired type. */
|
||||
const char *disabled_hint;
|
||||
if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree, &disabled_hint))) {
|
||||
idname = ntype->idname;
|
||||
|
@ -2240,9 +2236,8 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
|
|||
}
|
||||
|
||||
sock_dst->stack_index = 0;
|
||||
/* XXX some compositor node (e.g. image, render layers) still store
|
||||
* some persistent buffer data here, need to clear this to avoid dangling pointers.
|
||||
*/
|
||||
/* XXX some compositor nodes (e.g. image, render layers) still store
|
||||
* some persistent buffer data here, need to clear this to avoid dangling pointers. */
|
||||
sock_dst->cache = nullptr;
|
||||
}
|
||||
|
||||
|
@ -2257,7 +2252,7 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree,
|
|||
|
||||
*node_dst = *node_src;
|
||||
|
||||
/* can be called for nodes outside a node tree (e.g. clipboard) */
|
||||
/* Can be called for nodes outside a node tree (e.g. clipboard). */
|
||||
if (ntree) {
|
||||
if (unique_name) {
|
||||
nodeUniqueName(ntree, node_dst);
|
||||
|
@ -2394,7 +2389,7 @@ bNodeLink *nodeAddLink(
|
|||
{
|
||||
bNodeLink *link = nullptr;
|
||||
|
||||
/* test valid input */
|
||||
/* Test valid input. */
|
||||
BLI_assert(fromnode);
|
||||
BLI_assert(tonode);
|
||||
|
||||
|
@ -2433,7 +2428,7 @@ bNodeLink *nodeAddLink(
|
|||
|
||||
void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
|
||||
{
|
||||
/* can be called for links outside a node tree (e.g. clipboard) */
|
||||
/* Can be called for links outside a node tree (e.g. clipboard). */
|
||||
if (ntree) {
|
||||
BLI_remlink(&ntree->links, link);
|
||||
}
|
||||
|
@ -2815,8 +2810,11 @@ bool BKE_node_preview_used(const bNode *node)
|
|||
return (node->typeinfo->flag & NODE_PREVIEW) != 0;
|
||||
}
|
||||
|
||||
bNodePreview *BKE_node_preview_verify(
|
||||
bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create)
|
||||
bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews,
|
||||
bNodeInstanceKey key,
|
||||
const int xsize,
|
||||
const int ysize,
|
||||
const bool create)
|
||||
{
|
||||
bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key);
|
||||
if (!preview) {
|
||||
|
@ -2873,9 +2871,8 @@ void BKE_node_preview_free(bNodePreview *preview)
|
|||
static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
|
||||
bNodeTree *ntree,
|
||||
bNodeInstanceKey parent_key,
|
||||
int xsize,
|
||||
int ysize,
|
||||
bool create_previews)
|
||||
const int xsize,
|
||||
const int ysize)
|
||||
{
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
|
||||
|
@ -2884,17 +2881,16 @@ static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
|
|||
node->preview_xsize = xsize;
|
||||
node->preview_ysize = ysize;
|
||||
|
||||
BKE_node_preview_verify(previews, key, xsize, ysize, create_previews);
|
||||
BKE_node_preview_verify(previews, key, xsize, ysize, false);
|
||||
}
|
||||
|
||||
if (node->type == NODE_GROUP && node->id) {
|
||||
node_preview_init_tree_recursive(
|
||||
previews, (bNodeTree *)node->id, key, xsize, ysize, create_previews);
|
||||
node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool create_previews)
|
||||
void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize)
|
||||
{
|
||||
if (!ntree) {
|
||||
return;
|
||||
|
@ -2904,8 +2900,7 @@ void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool cre
|
|||
ntree->previews = BKE_node_instance_hash_new("node previews");
|
||||
}
|
||||
|
||||
node_preview_init_tree_recursive(
|
||||
ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews);
|
||||
node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize);
|
||||
}
|
||||
|
||||
static void node_preview_tag_used_recursive(bNodeInstanceHash *previews,
|
||||
|
@ -3041,27 +3036,6 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo
|
|||
}
|
||||
}
|
||||
|
||||
void BKE_node_preview_set_pixel(
|
||||
bNodePreview *preview, const float col[4], int x, int y, bool do_manage)
|
||||
{
|
||||
if (preview) {
|
||||
if (x >= 0 && y >= 0) {
|
||||
if (x < preview->xsize && y < preview->ysize) {
|
||||
unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
|
||||
|
||||
if (do_manage) {
|
||||
linearrgb_to_srgb_uchar4(tar, col);
|
||||
}
|
||||
else {
|
||||
rgba_float_to_uchar(tar, col);
|
||||
}
|
||||
}
|
||||
// else printf("prv out bound x y %d %d\n", x, y);
|
||||
}
|
||||
// else printf("prv out bound x y %d %d\n", x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************** Free stuff ********** */
|
||||
|
||||
void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
|
||||
|
@ -3137,12 +3111,12 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
|
|||
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
|
||||
/* Remember, no ID user refcount management here! */
|
||||
node_socket_free(ntree, sock, node, false);
|
||||
node_socket_free(sock, false);
|
||||
MEM_freeN(sock);
|
||||
}
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
|
||||
/* Remember, no ID user refcount management here! */
|
||||
node_socket_free(ntree, sock, node, false);
|
||||
node_socket_free(sock, false);
|
||||
MEM_freeN(sock);
|
||||
}
|
||||
|
||||
|
@ -3238,8 +3212,7 @@ static void free_localized_node_groups(bNodeTree *ntree)
|
|||
/* Only localized node trees store a copy for each node group tree.
|
||||
* Each node group tree in a localized node tree can be freed,
|
||||
* since it is a localized copy itself (no risk of accessing free'd
|
||||
* data in main, see T37939).
|
||||
*/
|
||||
* data in main, see T37939). */
|
||||
if (!(ntree->id.tag & LIB_TAG_LOCALIZED)) {
|
||||
return;
|
||||
}
|
||||
|
@ -3435,7 +3408,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
|
|||
}
|
||||
}
|
||||
|
||||
/* ensures only a single output node is enabled */
|
||||
/* Ensures only a single output node is enabled. */
|
||||
ntreeSetOutput(ntree);
|
||||
|
||||
bNode *node_src = (bNode *)ntree->nodes.first;
|
||||
|
@ -4459,7 +4432,8 @@ static void ntree_validate_links(bNodeTree *ntree)
|
|||
link->flag &= ~NODE_LINK_VALID;
|
||||
}
|
||||
else if (ntree->typeinfo->validate_link) {
|
||||
if (!ntree->typeinfo->validate_link(ntree, link)) {
|
||||
if (!ntree->typeinfo->validate_link((eNodeSocketDatatype)link->fromsock->type,
|
||||
(eNodeSocketDatatype)link->tosock->type)) {
|
||||
link->flag &= ~NODE_LINK_VALID;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ static void init_context(DupliContext *r_ctx,
|
|||
/**
|
||||
* Create sub-context for recursive duplis.
|
||||
*/
|
||||
static void copy_dupli_context(
|
||||
static bool copy_dupli_context(
|
||||
DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index)
|
||||
{
|
||||
*r_ctx = *ctx;
|
||||
|
@ -168,9 +168,11 @@ static void copy_dupli_context(
|
|||
|
||||
if (r_ctx->level == MAX_DUPLI_RECUR - 1) {
|
||||
std::cerr << "Warning: Maximum instance recursion level reached.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
r_ctx->gen = get_dupli_generator(r_ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,7 +260,9 @@ static void make_recursive_duplis(const DupliContext *ctx,
|
|||
/* Simple preventing of too deep nested collections with #MAX_DUPLI_RECUR. */
|
||||
if (ctx->level < MAX_DUPLI_RECUR) {
|
||||
DupliContext rctx;
|
||||
copy_dupli_context(&rctx, ctx, ob, space_mat, index);
|
||||
if (!copy_dupli_context(&rctx, ctx, ob, space_mat, index)) {
|
||||
return;
|
||||
}
|
||||
if (rctx.gen) {
|
||||
ctx->instance_stack->append(ob);
|
||||
rctx.gen->make_duplis(&rctx);
|
||||
|
@ -301,13 +305,13 @@ static void make_child_duplis(const DupliContext *ctx,
|
|||
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (ctx->collection, ob, mode) {
|
||||
if ((ob != ctx->obedit) && is_child(ob, parent)) {
|
||||
DupliContext pctx;
|
||||
copy_dupli_context(&pctx, ctx, ctx->object, nullptr, _base_id);
|
||||
|
||||
/* Meta-balls have a different dupli handling. */
|
||||
if (ob->type != OB_MBALL) {
|
||||
ob->flag |= OB_DONE; /* Doesn't render. */
|
||||
if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, _base_id)) {
|
||||
/* Meta-balls have a different dupli handling. */
|
||||
if (ob->type != OB_MBALL) {
|
||||
ob->flag |= OB_DONE; /* Doesn't render. */
|
||||
}
|
||||
make_child_duplis_cb(&pctx, userdata, ob);
|
||||
}
|
||||
make_child_duplis_cb(&pctx, userdata, ob);
|
||||
}
|
||||
}
|
||||
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
|
||||
|
@ -324,14 +328,14 @@ static void make_child_duplis(const DupliContext *ctx,
|
|||
DEG_OBJECT_ITER_BEGIN (ctx->depsgraph, ob, deg_objects_visibility_flags) {
|
||||
if ((ob != ctx->obedit) && is_child(ob, parent)) {
|
||||
DupliContext pctx;
|
||||
copy_dupli_context(&pctx, ctx, ctx->object, nullptr, persistent_dupli_id);
|
||||
if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, persistent_dupli_id)) {
|
||||
/* Meta-balls have a different dupli-handling. */
|
||||
if (ob->type != OB_MBALL) {
|
||||
ob->flag |= OB_DONE; /* Doesn't render. */
|
||||
}
|
||||
|
||||
/* Meta-balls have a different dupli-handling. */
|
||||
if (ob->type != OB_MBALL) {
|
||||
ob->flag |= OB_DONE; /* Doesn't render. */
|
||||
make_child_duplis_cb(&pctx, userdata, ob);
|
||||
}
|
||||
|
||||
make_child_duplis_cb(&pctx, userdata, ob);
|
||||
}
|
||||
persistent_dupli_id++;
|
||||
}
|
||||
|
@ -893,7 +897,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
|
|||
* between the instances component below and the other components above. */
|
||||
DupliContext new_instances_ctx;
|
||||
if (creates_duplis_for_components) {
|
||||
copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index);
|
||||
if (!copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index)) {
|
||||
return;
|
||||
}
|
||||
instances_ctx = &new_instances_ctx;
|
||||
}
|
||||
|
||||
|
@ -928,7 +934,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
|
|||
mul_m4_m4_pre(collection_matrix, parent_transform);
|
||||
|
||||
DupliContext sub_ctx;
|
||||
copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id);
|
||||
if (!copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
|
||||
break;
|
||||
}
|
||||
|
||||
eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph);
|
||||
int object_id = 0;
|
||||
|
@ -951,8 +959,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
|
|||
mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values);
|
||||
|
||||
DupliContext sub_ctx;
|
||||
copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id);
|
||||
make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true);
|
||||
if (copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
|
||||
make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InstanceReference::Type::None: {
|
||||
|
@ -1609,8 +1618,9 @@ static void make_duplis_particles(const DupliContext *ctx)
|
|||
LISTBASE_FOREACH_INDEX (ParticleSystem *, psys, &ctx->object->particlesystem, psysid) {
|
||||
/* Particles create one more level for persistent `psys` index. */
|
||||
DupliContext pctx;
|
||||
copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid);
|
||||
make_duplis_particle_system(&pctx, psys);
|
||||
if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid)) {
|
||||
make_duplis_particle_system(&pctx, psys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1322,10 +1322,11 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext)
|
|||
|
||||
static int ptcache_path(PTCacheID *pid, char *filename)
|
||||
{
|
||||
const char *blendfile_path = BKE_main_blendfile_path_from_global();
|
||||
Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL;
|
||||
const char *blendfilename = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
|
||||
lib->filepath_abs :
|
||||
BKE_main_blendfile_path_from_global();
|
||||
blendfile_path;
|
||||
size_t i;
|
||||
|
||||
if (pid->cache->flag & PTCACHE_EXTERNAL) {
|
||||
|
@ -1337,7 +1338,7 @@ static int ptcache_path(PTCacheID *pid, char *filename)
|
|||
|
||||
return BLI_path_slash_ensure(filename); /* new strlen() */
|
||||
}
|
||||
if (G.relbase_valid || lib) {
|
||||
if ((blendfile_path[0] != '\0') || lib) {
|
||||
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
|
||||
|
||||
BLI_split_file_part(blendfilename, file, sizeof(file));
|
||||
|
@ -1422,8 +1423,11 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
|
|||
filename[0] = '\0';
|
||||
newname = filename;
|
||||
|
||||
if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
|
||||
return 0; /* save blend file before using disk pointcache */
|
||||
if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
|
||||
const char *blendfile_path = BKE_main_blendfile_path_from_global();
|
||||
if (blendfile_path[0] == '\0') {
|
||||
return 0; /* save blend file before using disk pointcache */
|
||||
}
|
||||
}
|
||||
|
||||
/* start with temp dir */
|
||||
|
@ -1469,8 +1473,11 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
|
|||
return NULL;
|
||||
}
|
||||
#endif
|
||||
if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
|
||||
return NULL; /* save blend file before using disk pointcache */
|
||||
if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
|
||||
const char *blendfile_path = BKE_main_blendfile_path_from_global();
|
||||
if (blendfile_path[0] == '\0') {
|
||||
return NULL; /* save blend file before using disk pointcache */
|
||||
}
|
||||
}
|
||||
|
||||
ptcache_filename(pid, filename, cfra, 1, 1);
|
||||
|
@ -2626,8 +2633,6 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
|
|||
}
|
||||
#endif
|
||||
|
||||
// if (!G.relbase_valid) return; /* Save blend file before using pointcache. */
|
||||
|
||||
/* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
|
||||
switch (mode) {
|
||||
case PTCACHE_CLEAR_ALL:
|
||||
|
@ -3446,8 +3451,9 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
|
|||
{
|
||||
PointCache *cache = pid->cache;
|
||||
int last_exact = cache->last_exact;
|
||||
const char *blendfile_path = BKE_main_blendfile_path_from_global();
|
||||
|
||||
if (!G.relbase_valid) {
|
||||
if (blendfile_path[0] == '\0') {
|
||||
cache->flag &= ~PTCACHE_DISK_CACHE;
|
||||
if (G.debug & G_DEBUG) {
|
||||
printf("File must be saved before using disk cache!\n");
|
||||
|
|
|
@ -257,13 +257,13 @@ void NURBSpline::calculate_knots() const
|
|||
Span<float> NURBSpline::knots() const
|
||||
{
|
||||
if (!knots_dirty_) {
|
||||
BLI_assert(knots_.size() == this->size() + order_);
|
||||
BLI_assert(knots_.size() == this->knots_size());
|
||||
return knots_;
|
||||
}
|
||||
|
||||
std::lock_guard lock{knots_mutex_};
|
||||
if (!knots_dirty_) {
|
||||
BLI_assert(knots_.size() == this->size() + order_);
|
||||
BLI_assert(knots_.size() == this->knots_size());
|
||||
return knots_;
|
||||
}
|
||||
|
||||
|
|
|
@ -819,6 +819,9 @@ void BKE_undosys_step_load_from_index(UndoStack *ustack, bContext *C, const int
|
|||
{
|
||||
UndoStep *us_target = BLI_findlink(&ustack->steps, index);
|
||||
BLI_assert(us_target->skip == false);
|
||||
if (us_target == ustack->step_active) {
|
||||
return;
|
||||
}
|
||||
BKE_undosys_step_load_data(ustack, C, us_target);
|
||||
}
|
||||
|
||||
|
|
|
@ -537,7 +537,7 @@ static void volume_copy_data(Main *UNUSED(bmain),
|
|||
#ifdef WITH_OPENVDB
|
||||
if (volume_src->runtime.grids) {
|
||||
const VolumeGridVector &grids_src = *(volume_src->runtime.grids);
|
||||
volume_dst->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector, grids_src);
|
||||
volume_dst->runtime.grids = MEM_new<VolumeGridVector>(__func__, grids_src);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -551,7 +551,8 @@ static void volume_free_data(ID *id)
|
|||
BKE_volume_batch_cache_free(volume);
|
||||
MEM_SAFE_FREE(volume->mat);
|
||||
#ifdef WITH_OPENVDB
|
||||
OBJECT_GUARDED_SAFE_DELETE(volume->runtime.grids, VolumeGridVector);
|
||||
MEM_delete(volume->runtime.grids);
|
||||
volume->runtime.grids = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -683,7 +684,7 @@ void BKE_volume_init_grids(Volume *volume)
|
|||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
if (volume->runtime.grids == nullptr) {
|
||||
volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
|
||||
volume->runtime.grids = MEM_new<VolumeGridVector>(__func__);
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(volume);
|
||||
|
@ -1129,16 +1130,16 @@ void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, co
|
|||
|
||||
if (!grids->is_loaded()) {
|
||||
/* No grids loaded in CoW datablock, nothing lost by discarding. */
|
||||
OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
|
||||
MEM_delete(grids);
|
||||
}
|
||||
else if (!STREQ(volume->filepath, filepath)) {
|
||||
/* Filepath changed, discard grids from CoW datablock. */
|
||||
OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
|
||||
MEM_delete(grids);
|
||||
}
|
||||
else {
|
||||
/* Keep grids from CoW datablock. We might still unload them a little
|
||||
* later in BKE_volume_eval_geometry if the frame changes. */
|
||||
OBJECT_GUARDED_DELETE(volume->runtime.grids, VolumeGridVector);
|
||||
MEM_delete(volume->runtime.grids);
|
||||
volume->runtime.grids = grids;
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -30,6 +30,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/* Utility functions. */
|
||||
|
||||
void _BLI_assert_print_pos(const char *file, const int line, const char *function, const char *id);
|
||||
void _BLI_assert_print_extra(const char *str);
|
||||
void _BLI_assert_print_backtrace(void);
|
||||
|
|
|
@ -73,27 +73,27 @@ namespace blender {
|
|||
* - Add non RGB spaces/storages ColorXyz.
|
||||
*/
|
||||
|
||||
/* Enumeration containing the different alpha modes. */
|
||||
/** Enumeration containing the different alpha modes. */
|
||||
enum class eAlpha {
|
||||
/* Color and alpha are unassociated. */
|
||||
/** Color and alpha are unassociated. */
|
||||
Straight,
|
||||
/* Color and alpha are associated. */
|
||||
/** Color and alpha are associated. */
|
||||
Premultiplied,
|
||||
};
|
||||
std::ostream &operator<<(std::ostream &stream, const eAlpha &space);
|
||||
|
||||
/* Enumeration containing internal spaces. */
|
||||
/** Enumeration containing internal spaces. */
|
||||
enum class eSpace {
|
||||
/* Blender theme color space (sRGB). */
|
||||
/** Blender theme color space (sRGB). */
|
||||
Theme,
|
||||
/* Blender internal scene linear color space (maps to SceneReference role in OCIO). */
|
||||
/** Blender internal scene linear color space (maps to SceneReference role in OCIO). */
|
||||
SceneLinear,
|
||||
/* Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
|
||||
/** Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
|
||||
SceneLinearByteEncoded,
|
||||
};
|
||||
std::ostream &operator<<(std::ostream &stream, const eSpace &space);
|
||||
|
||||
/* Template class to store RGBA values with different precision, space and alpha association. */
|
||||
/** Template class to store RGBA values with different precision, space and alpha association. */
|
||||
template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGBA {
|
||||
public:
|
||||
ChannelStorageType r, g, b, a;
|
||||
|
@ -153,11 +153,13 @@ template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGB
|
|||
};
|
||||
|
||||
/* Forward declarations of concrete color classes. */
|
||||
|
||||
template<eAlpha Alpha> class ColorSceneLinear4f;
|
||||
template<eAlpha Alpha> class ColorSceneLinearByteEncoded4b;
|
||||
template<typename ChannelStorageType> class ColorTheme4;
|
||||
|
||||
/* Forward declaration of precision conversion methods. */
|
||||
|
||||
BLI_INLINE ColorTheme4<float> BLI_color_convert_to_theme4f(const ColorTheme4<uint8_t> &srgb4b);
|
||||
BLI_INLINE ColorTheme4<uint8_t> BLI_color_convert_to_theme4b(const ColorTheme4<float> &srgb4f);
|
||||
|
||||
|
@ -354,6 +356,7 @@ BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_l
|
|||
}
|
||||
|
||||
/* Internal roles. For convenience to shorten the type names and hide complexity. */
|
||||
|
||||
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
|
||||
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus)
|
||||
extern "C++" {
|
||||
/* Some magic to be sure we don't have reference in the type. */
|
||||
/** Some magic to be sure we don't have reference in the type. */
|
||||
template<typename T> static inline T decltype_helper(T x)
|
||||
{
|
||||
return x;
|
||||
|
|
|
@ -222,7 +222,7 @@ void BLI_delaunay_2d_cdt_free(CDT_result *result);
|
|||
|
||||
namespace blender::meshintersect {
|
||||
|
||||
/* vec2<Arith_t> is a 2d vector with Arith_t as the type for coordinates. */
|
||||
/** #vec2<Arith_t> is a 2d vector with #Arith_t as the type for coordinates. */
|
||||
template<typename Arith_t> struct vec2_impl;
|
||||
template<> struct vec2_impl<double> {
|
||||
typedef double2 type;
|
||||
|
|
|
@ -40,7 +40,7 @@ extern "C" {
|
|||
/** \name Base Structs
|
||||
* \{ */
|
||||
|
||||
/* Basic Layout for a Node */
|
||||
/** Basic Layout for a Node. */
|
||||
typedef struct DLRBT_Node {
|
||||
/* ListBase capabilities */
|
||||
struct DLRBT_Node *next, *prev;
|
||||
|
@ -53,7 +53,7 @@ typedef struct DLRBT_Node {
|
|||
/* ... for nice alignment, next item should usually be a char too... */
|
||||
} DLRBT_Node;
|
||||
|
||||
/* Red/Black defines for tree_col */
|
||||
/** Red/Black defines for tree_col. */
|
||||
typedef enum eDLRBT_Colors {
|
||||
DLRBT_BLACK = 0,
|
||||
DLRBT_RED,
|
||||
|
@ -61,7 +61,7 @@ typedef enum eDLRBT_Colors {
|
|||
|
||||
/* -------- */
|
||||
|
||||
/* The Tree Data */
|
||||
/** The Tree Data. */
|
||||
typedef struct DLRBT_Tree {
|
||||
/* ListBase capabilities */
|
||||
void *first, *last; /* these should be based on DLRBT_Node-s */
|
||||
|
|
|
@ -30,6 +30,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/* BLI_endian_switch_inline.h */
|
||||
|
||||
BLI_INLINE void BLI_endian_switch_int16(short *val) ATTR_NONNULL(1);
|
||||
BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val) ATTR_NONNULL(1);
|
||||
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1);
|
||||
|
@ -40,6 +41,7 @@ BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1);
|
|||
BLI_INLINE void BLI_endian_switch_double(double *val) ATTR_NONNULL(1);
|
||||
|
||||
/* endian_switch.c */
|
||||
|
||||
void BLI_endian_switch_int16_array(short *val, const int size) ATTR_NONNULL(1);
|
||||
void BLI_endian_switch_uint16_array(unsigned short *val, const int size) ATTR_NONNULL(1);
|
||||
void BLI_endian_switch_int32_array(int *val, const int size) ATTR_NONNULL(1);
|
||||
|
|
|
@ -33,6 +33,7 @@ extern "C" {
|
|||
* use bit shifting instead. */
|
||||
|
||||
/* *** 16 *** */
|
||||
|
||||
BLI_INLINE void BLI_endian_switch_int16(short *val)
|
||||
{
|
||||
BLI_endian_switch_uint16((unsigned short *)val);
|
||||
|
@ -48,6 +49,7 @@ BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val)
|
|||
}
|
||||
|
||||
/* *** 32 *** */
|
||||
|
||||
BLI_INLINE void BLI_endian_switch_int32(int *val)
|
||||
{
|
||||
BLI_endian_switch_uint32((unsigned int *)val);
|
||||
|
@ -67,6 +69,7 @@ BLI_INLINE void BLI_endian_switch_float(float *val)
|
|||
}
|
||||
|
||||
/* *** 64 *** */
|
||||
|
||||
BLI_INLINE void BLI_endian_switch_int64(int64_t *val)
|
||||
{
|
||||
BLI_endian_switch_uint64((uint64_t *)val);
|
||||
|
|
|
@ -47,7 +47,7 @@ typedef ssize_t (*FileReaderReadFn)(struct FileReader *reader, void *buffer, siz
|
|||
typedef off64_t (*FileReaderSeekFn)(struct FileReader *reader, off64_t offset, int whence);
|
||||
typedef void (*FileReaderCloseFn)(struct FileReader *reader);
|
||||
|
||||
/* General structure for all FileReaders, implementations add custom fields at the end. */
|
||||
/** General structure for all #FileReaders, implementations add custom fields at the end. */
|
||||
typedef struct FileReader {
|
||||
FileReaderReadFn read;
|
||||
FileReaderSeekFn seek;
|
||||
|
@ -64,16 +64,16 @@ typedef struct FileReader {
|
|||
* take over the base FileReader and will clean it up when their clean() is called.
|
||||
*/
|
||||
|
||||
/* Create FileReader from raw file descriptor. */
|
||||
/** Create #FileReader from raw file descriptor. */
|
||||
FileReader *BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT;
|
||||
/* Create FileReader from raw file descriptor using memory-mapped IO. */
|
||||
/** Create #FileReader from raw file descriptor using memory-mapped IO. */
|
||||
FileReader *BLI_filereader_new_mmap(int filedes) ATTR_WARN_UNUSED_RESULT;
|
||||
/* Create FileReader from a region of memory. */
|
||||
/** Create #FileReader from a region of memory. */
|
||||
FileReader *BLI_filereader_new_memory(const void *data, size_t len) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/* Create FileReader from applying `Zstd` decompression on an underlying file. */
|
||||
/** Create #FileReader from applying `Zstd` decompression on an underlying file. */
|
||||
FileReader *BLI_filereader_new_zstd(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/* Create FileReader from applying `Gzip` decompression on an underlying file. */
|
||||
/** Create #FileReader from applying `Gzip` decompression on an underlying file. */
|
||||
FileReader *BLI_filereader_new_gzip(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -512,7 +512,7 @@ void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
|
|||
|
||||
/* rely on inline api for now */
|
||||
|
||||
/* so we can cast but compiler sees as different */
|
||||
/** Use a GSet specific type so we can cast but compiler sees as different */
|
||||
typedef struct GSetIterator {
|
||||
GHashIterator _ghi
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
|
|
|
@ -74,7 +74,7 @@ int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree,
|
|||
|
||||
int BLI_kdtree_nd_(deduplicate)(KDTree *tree);
|
||||
|
||||
/* Versions of find/range search that take a squared distance callback to support bias. */
|
||||
/** Versions of find/range search that take a squared distance callback to support bias. */
|
||||
int BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
|
||||
const KDTree *tree,
|
||||
const float co[KD_DIMS],
|
||||
|
|
|
@ -48,18 +48,19 @@ typedef void (*LockfreeeLinkNodeFreeFP)(void *link);
|
|||
/* NOTE: These functions are NOT safe for use from threads. */
|
||||
/* NOTE: !!! I REPEAT: DO NOT USE THEM WITHOUT EXTERNAL LOCK !!! */
|
||||
|
||||
/* Make list ready for lock-free access. */
|
||||
/** Make list ready for lock-free access. */
|
||||
void BLI_linklist_lockfree_init(LockfreeLinkList *list);
|
||||
|
||||
/* Completely free the whole list, it is NOT re-usable after this. */
|
||||
/** Completely free the whole list, it is NOT re-usable after this. */
|
||||
void BLI_linklist_lockfree_free(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
|
||||
|
||||
/* Remove all the elements from the list, keep it usable for further
|
||||
* inserts.
|
||||
/**
|
||||
* Remove all the elements from the list, keep it usable for further inserts.
|
||||
*/
|
||||
void BLI_linklist_lockfree_clear(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
|
||||
|
||||
/* Begin iteration of lock-free linked list, starting with a
|
||||
/**
|
||||
* Begin iteration of lock-free linked list, starting with a
|
||||
* first user=defined node. Will ignore the dummy node.
|
||||
*/
|
||||
LockfreeLinkNode *BLI_linklist_lockfree_begin(LockfreeLinkList *list);
|
||||
|
|
|
@ -46,6 +46,11 @@ int BLI_findstringindex(const struct ListBase *listbase,
|
|||
const char *id,
|
||||
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
|
||||
|
||||
/**
|
||||
* Return a ListBase representing the entire list the given Link is in.
|
||||
*/
|
||||
ListBase BLI_listbase_from_link(struct Link *some_link);
|
||||
|
||||
/* Find forwards. */
|
||||
|
||||
/**
|
||||
|
@ -278,6 +283,23 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
|
|||
lb->first = lb->last = (void *)0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality check for ListBase.
|
||||
*
|
||||
* This only shallowly compares the ListBase itself (so the first/last
|
||||
* pointers), and does not do any equality checks on the list items.
|
||||
*/
|
||||
BLI_INLINE bool BLI_listbase_equal(const struct ListBase *a, const struct ListBase *b)
|
||||
{
|
||||
if (a == NULL) {
|
||||
return b == NULL;
|
||||
}
|
||||
if (b == NULL) {
|
||||
return false;
|
||||
}
|
||||
return a->first == b->first && a->last == b->last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a generic list node containing link to provided data.
|
||||
*/
|
||||
|
@ -353,3 +375,10 @@ struct LinkData *BLI_genericNodeN(void *data);
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
BLI_INLINE bool operator==(const ListBase &a, const ListBase &b)
|
||||
{
|
||||
return BLI_listbase_equal(&a, &b);
|
||||
}
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue