Files
workinf_Blender_Wasm/blender-5.2.0/intern/cycles/scene/pointcloud.cpp
2026-08-12 04:47:48 -04:00

273 lines
8.0 KiB
C++

/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#include "bvh/bvh.h"
#include "scene/pointcloud.h"
#include "scene/scene.h"
CCL_NAMESPACE_BEGIN
/* PointCloud Point */
void PointCloud::Point::bounds_grow(const packed_float3 *points,
const float *radius,
BoundBox &bounds) const
{
bounds.grow(points[index], radius[index]);
}
void PointCloud::Point::bounds_grow(const packed_float3 *points,
const float *radius,
const Transform &aligned_space,
BoundBox &bounds) const
{
const float3 P = transform_point(&aligned_space, float3(points[index]));
bounds.grow(P, radius[index]);
}
void PointCloud::Point::bounds_grow(const float4 &point, BoundBox &bounds) const
{
bounds.grow(make_float3(point), point.w);
}
float4 PointCloud::Point::motion_key(const float *radius,
const Attribute *attr_P,
const Attribute *attr_R,
const size_t num_steps,
const float time,
size_t p) const
{
/* Figure out which steps we need to fetch and their
* interpolation factor. */
const size_t max_step = num_steps - 1;
const size_t step = min((size_t)(time * max_step), max_step - 1);
const float t = time * max_step - step;
/* Fetch vertex coordinates. */
const float4 curr_key = point_for_step(radius, attr_P, attr_R, step, p);
const float4 next_key = point_for_step(radius, attr_P, attr_R, step + 1, p);
/* Interpolate between steps. */
return (1.0f - t) * curr_key + t * next_key;
}
float4 PointCloud::Point::point_for_step(const float *radius,
const Attribute *attr_P,
const Attribute *attr_R,
const size_t step,
const size_t p) const
{
const int num_steps = attr_P->num_motion_steps();
const float r = attr_R ? attr_R->data_at_time_step<float>(step, num_steps)[p] : radius[p];
return make_float4(float3(attr_P->data_at_time_step<packed_float3>(step, num_steps)[p]), r);
}
/* PointCloud */
NODE_DEFINE(PointCloud)
{
NodeType *type = NodeType::add(
"pointcloud", create, NodeType::NONE, Geometry::get_node_base_type());
SOCKET_INT_ARRAY(shader, "Shader", array<int>());
return type;
}
PointCloud::PointCloud() : Geometry(get_node_type(), Geometry::POINTCLOUD)
{
add_builtin_attributes();
}
PointCloud::~PointCloud() = default;
void PointCloud::add_builtin_attributes()
{
attributes.add(ATTR_STD_POSITION);
attributes.add(ATTR_STD_RADIUS);
}
void PointCloud::resize(const int numpoints)
{
Attribute *attr_P = attributes.add(ATTR_STD_POSITION);
attr_P->resize(numpoints);
Attribute *attr_R = attributes.add(ATTR_STD_RADIUS);
attr_R->resize(numpoints);
shader.resize(numpoints);
attributes.resize();
tag_position_modified();
tag_radius_modified();
tag_shader_modified();
}
void PointCloud::clear_non_sockets()
{
Geometry::clear(true);
}
void PointCloud::clear(const bool preserve_shaders)
{
Geometry::clear(preserve_shaders);
shader.clear();
attributes.clear();
add_builtin_attributes();
tag_position_modified();
tag_radius_modified();
tag_shader_modified();
}
void PointCloud::copy_center_to_motion_step(const int motion_step)
{
const int attr_step = motion_step + 1;
const size_t numpoints = num_points();
Attribute *attr_P = attributes.find(ATTR_STD_POSITION);
if (attr_P->has_motion()) {
std::copy_n(get_position(), numpoints, attr_P->data_for_write<packed_float3>(attr_step));
}
Attribute *attr_R = attributes.find(ATTR_STD_RADIUS);
if (attr_R->has_motion()) {
std::copy_n(get_radius(), numpoints, attr_R->data_for_write<float>(attr_step));
}
}
void PointCloud::get_uv_tiles(ustring map, unordered_set<int> &tiles)
{
Attribute *attr;
if (map.empty()) {
attr = attributes.find(ATTR_STD_UV);
}
else {
attr = attributes.find(map);
}
if (attr) {
attr->get_uv_tiles(this, ATTR_PRIM_GEOMETRY, tiles);
}
}
void PointCloud::compute_bounds()
{
BoundBox bnds = BoundBox::empty;
const size_t numpoints = num_points();
const packed_float3 *points_data = get_position();
const float *radius_data = get_radius();
if (numpoints > 0) {
for (size_t i = 0; i < numpoints; i++) {
bnds.grow(points_data[i], radius_data[i]);
}
const Attribute *attr_P = attributes.find(ATTR_STD_POSITION);
const Attribute *attr_R = attributes.find(ATTR_STD_RADIUS);
if (use_motion_blur && attr_P->has_motion()) {
for (int attr_step = 1; attr_step < attr_P->num_motion_steps(); attr_step++) {
const packed_float3 *motion_P = attr_P->data<packed_float3>(attr_step);
const float *motion_R = attr_R->data<float>(attr_step);
for (size_t i = 0; i < numpoints; i++) {
bnds.grow(motion_P[i], motion_R[i]);
}
}
}
if (!bnds.valid()) {
bnds = BoundBox::empty;
/* skip nan or inf coordinates */
for (size_t i = 0; i < numpoints; i++) {
bnds.grow_safe(points_data[i], radius_data[i]);
}
if (use_motion_blur && attr_P->has_motion()) {
for (int attr_step = 1; attr_step < attr_P->num_motion_steps(); attr_step++) {
const packed_float3 *motion_P = attr_P->data<packed_float3>(attr_step);
const float *motion_R = attr_R->data<float>(attr_step);
for (size_t i = 0; i < numpoints; i++) {
bnds.grow_safe(motion_P[i], motion_R[i]);
}
}
}
}
}
if (!bnds.valid()) {
/* empty mesh */
bnds.grow(make_float3(0.0f, 0.0f, 0.0f));
}
bounds = bnds;
}
void PointCloud::apply_transform(const Transform &tfm, const bool apply_to_motion)
{
/* compute uniform scale */
const float3 c0 = transform_get_column(&tfm, 0);
const float3 c1 = transform_get_column(&tfm, 1);
const float3 c2 = transform_get_column(&tfm, 2);
const float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f / 3.0f);
/* apply transform to points */
packed_float3 *points_data = get_position_for_write();
float *radius_data = get_radius_for_write();
const size_t numpoints = num_points();
for (size_t i = 0; i < numpoints; i++) {
const float3 co = transform_point(&tfm, points_data[i]);
const float r = radius_data[i] * scalar;
/* scale for radius is only correct for uniform scale */
points_data[i] = co;
radius_data[i] = r;
}
if (apply_to_motion) {
Attribute *attr_P = attributes.find(ATTR_STD_POSITION);
Attribute *attr_R = attributes.find(ATTR_STD_RADIUS);
if (attr_P->has_motion()) {
const bool has_motion_radius = attr_R->has_motion();
for (int step = 1; step <= int(attr_P->motion.size()); step++) {
packed_float3 *motion_P = attr_P->data_for_write<packed_float3>(step);
float *motion_R = has_motion_radius ? attr_R->data_for_write<float>(step) : nullptr;
for (size_t i = 0; i < numpoints; i++) {
motion_P[i] = transform_point(&tfm, motion_P[i]);
if (motion_R) {
/* scale for curve radius is only correct for uniform scale */
motion_R[i] *= scalar;
}
}
}
}
}
}
void PointCloud::pack(Scene *scene, uint *packed_shader)
{
const size_t numpoints = num_points();
int *shader_data = shader.data();
uint shader_id = 0;
uint last_shader = -1;
for (size_t i = 0; i < numpoints; i++) {
if (last_shader != shader_data[i]) {
last_shader = shader_data[i];
Shader *shader = (last_shader < used_shaders.size()) ?
static_cast<Shader *>(used_shaders[last_shader]) :
scene->default_surface;
shader_id = scene->shader_manager->get_shader_id(shader);
}
packed_shader[i] = shader_id;
}
}
PrimitiveType PointCloud::primitive_type() const
{
return has_motion_blur() ? PRIMITIVE_MOTION_POINT : PRIMITIVE_POINT;
}
CCL_NAMESPACE_END