295 lines
8.1 KiB
C++
295 lines
8.1 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 float3 *points,
|
|
const float *radius,
|
|
BoundBox &bounds) const
|
|
{
|
|
bounds.grow(points[index], radius[index]);
|
|
}
|
|
|
|
void PointCloud::Point::bounds_grow(const float3 *points,
|
|
const float *radius,
|
|
const Transform &aligned_space,
|
|
BoundBox &bounds) const
|
|
{
|
|
float3 P = transform_point(&aligned_space, points[index]);
|
|
bounds.grow(P, radius[index]);
|
|
}
|
|
|
|
void PointCloud::Point::bounds_grow(const float4 &point, BoundBox &bounds) const
|
|
{
|
|
bounds.grow(float4_to_float3(point), point.w);
|
|
}
|
|
|
|
float4 PointCloud::Point::motion_key(const float3 *points,
|
|
const float *radius,
|
|
const float4 *point_steps,
|
|
size_t num_points,
|
|
size_t num_steps,
|
|
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(
|
|
points, radius, point_steps, num_points, num_steps, step, p);
|
|
const float4 next_key = point_for_step(
|
|
points, radius, point_steps, num_points, num_steps, step + 1, p);
|
|
/* Interpolate between steps. */
|
|
return (1.0f - t) * curr_key + t * next_key;
|
|
}
|
|
|
|
float4 PointCloud::Point::point_for_step(const float3 *points,
|
|
const float *radius,
|
|
const float4 *point_steps,
|
|
size_t num_points,
|
|
size_t num_steps,
|
|
size_t step,
|
|
size_t p) const
|
|
{
|
|
const size_t center_step = ((num_steps - 1) / 2);
|
|
if (step == center_step) {
|
|
/* Center step: regular key location. */
|
|
return make_float4(points[p].x, points[p].y, points[p].z, radius[p]);
|
|
}
|
|
else {
|
|
/* Center step is not stored in this array. */
|
|
if (step > center_step) {
|
|
step--;
|
|
}
|
|
const size_t offset = step * num_points;
|
|
return point_steps[offset + p];
|
|
}
|
|
}
|
|
|
|
/* PointCloud */
|
|
|
|
NODE_DEFINE(PointCloud)
|
|
{
|
|
NodeType *type = NodeType::add(
|
|
"pointcloud", create, NodeType::NONE, Geometry::get_node_base_type());
|
|
|
|
SOCKET_POINT_ARRAY(points, "Points", array<float3>());
|
|
SOCKET_FLOAT_ARRAY(radius, "Radius", array<float>());
|
|
SOCKET_INT_ARRAY(shader, "Shader", array<int>());
|
|
|
|
return type;
|
|
}
|
|
|
|
PointCloud::PointCloud() : Geometry(node_type, Geometry::POINTCLOUD) {}
|
|
|
|
PointCloud::~PointCloud() {}
|
|
|
|
void PointCloud::resize(int numpoints)
|
|
{
|
|
points.resize(numpoints);
|
|
radius.resize(numpoints);
|
|
shader.resize(numpoints);
|
|
attributes.resize();
|
|
|
|
tag_points_modified();
|
|
tag_radius_modified();
|
|
tag_shader_modified();
|
|
}
|
|
|
|
void PointCloud::reserve(int numpoints)
|
|
{
|
|
points.reserve(numpoints);
|
|
radius.reserve(numpoints);
|
|
shader.reserve(numpoints);
|
|
attributes.resize(true);
|
|
}
|
|
|
|
void PointCloud::clear(const bool preserve_shaders)
|
|
{
|
|
Geometry::clear(preserve_shaders);
|
|
|
|
points.clear();
|
|
radius.clear();
|
|
shader.clear();
|
|
attributes.clear();
|
|
|
|
tag_points_modified();
|
|
tag_radius_modified();
|
|
tag_shader_modified();
|
|
}
|
|
|
|
void PointCloud::add_point(float3 co, float r, int shader_index)
|
|
{
|
|
points.push_back_reserved(co);
|
|
radius.push_back_reserved(r);
|
|
shader.push_back_reserved(shader_index);
|
|
|
|
tag_points_modified();
|
|
tag_radius_modified();
|
|
tag_shader_modified();
|
|
}
|
|
|
|
void PointCloud::copy_center_to_motion_step(const int motion_step)
|
|
{
|
|
Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
if (attr_mP) {
|
|
float3 *points_data = points.data();
|
|
size_t numpoints = points.size();
|
|
float *radius_data = radius.data();
|
|
|
|
float4 *attrib_P = attr_mP->data_float4() + motion_step * numpoints;
|
|
for (int i = 0; i < numpoints; i++) {
|
|
float3 P = points_data[i];
|
|
float r = radius_data[i];
|
|
attrib_P[i] = make_float4(P.x, P.y, P.z, r);
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
size_t numpoints = points.size();
|
|
|
|
if (numpoints > 0) {
|
|
for (size_t i = 0; i < numpoints; i++) {
|
|
bnds.grow(points[i], radius[i]);
|
|
}
|
|
|
|
Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
if (use_motion_blur && attr) {
|
|
size_t steps_size = points.size() * (motion_steps - 1);
|
|
float4 *point_steps = attr->data_float4();
|
|
|
|
for (size_t i = 0; i < steps_size; i++) {
|
|
bnds.grow(float4_to_float3(point_steps[i]), point_steps[i].w);
|
|
}
|
|
}
|
|
|
|
if (!bnds.valid()) {
|
|
bnds = BoundBox::empty;
|
|
|
|
/* skip nan or inf coordinates */
|
|
for (size_t i = 0; i < numpoints; i++) {
|
|
bnds.grow_safe(points[i], radius[i]);
|
|
}
|
|
|
|
if (use_motion_blur && attr) {
|
|
size_t steps_size = points.size() * (motion_steps - 1);
|
|
float4 *point_steps = attr->data_float4();
|
|
|
|
for (size_t i = 0; i < steps_size; i++) {
|
|
bnds.grow_safe(float4_to_float3(point_steps[i]), point_steps[i].w);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 */
|
|
float3 c0 = transform_get_column(&tfm, 0);
|
|
float3 c1 = transform_get_column(&tfm, 1);
|
|
float3 c2 = transform_get_column(&tfm, 2);
|
|
float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f / 3.0f);
|
|
|
|
/* apply transform to curve keys */
|
|
for (size_t i = 0; i < points.size(); i++) {
|
|
float3 co = transform_point(&tfm, points[i]);
|
|
float r = radius[i] * scalar;
|
|
|
|
/* scale for curve radius is only correct for uniform scale
|
|
*/
|
|
points[i] = co;
|
|
radius[i] = r;
|
|
}
|
|
|
|
if (apply_to_motion) {
|
|
Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
|
|
if (attr) {
|
|
/* apply transform to motion curve keys */
|
|
size_t steps_size = points.size() * (motion_steps - 1);
|
|
float4 *point_steps = attr->data_float4();
|
|
|
|
for (size_t i = 0; i < steps_size; i++) {
|
|
float3 co = transform_point(&tfm, float4_to_float3(point_steps[i]));
|
|
float radius = point_steps[i].w * scalar;
|
|
|
|
/* scale for curve radius is only correct for uniform
|
|
* scale */
|
|
point_steps[i] = float3_to_float4(co);
|
|
point_steps[i].w = radius;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void PointCloud::pack(Scene *scene, float4 *packed_points, uint *packed_shader)
|
|
{
|
|
size_t numpoints = points.size();
|
|
float3 *points_data = points.data();
|
|
float *radius_data = radius.data();
|
|
int *shader_data = shader.data();
|
|
|
|
for (size_t i = 0; i < numpoints; i++) {
|
|
packed_points[i] = make_float4(
|
|
points_data[i].x, points_data[i].y, points_data[i].z, radius_data[i]);
|
|
}
|
|
|
|
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
|