Curves: Add RNA access to evaluated normals per control point

Add an RNA API function that gives an array of the normals for every control point.
The normals depend on the `normal_mode` attribute, which can currently be
minumum twist or Z-up, though more options are planned. Normals are currently
evaluated on the evaluated points and then sampled back to the control points.
Because that can be expensive, a normal mode that only does a first evaluation
on control points may be important

The function is intended to be used by Cycles, so it doesn't have to implement
the calculation of normals itself. They can be interpolated between control points
and normalized.

For best performance, the function should only be called once, since it does the
full calculation for every control point every time it is called.

Differential Revision: https://developer.blender.org/D17024
This commit is contained in:
Hans Goudey 2023-01-19 17:43:55 -06:00
parent 203ab983ce
commit 241d87e9f4
5 changed files with 81 additions and 1 deletions

View File

@ -21,6 +21,7 @@ set(INC
set(SRC
intern/curves_add.cc
intern/curves_data.cc
intern/curves_ops.cc
intern/curves_selection.cc
)

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_curves.hh"
#include "BKE_geometry_fields.hh"
#include "ED_curves.h"
float (*ED_curves_point_normals_array_create(const Curves *curves_id))[3]
{
using namespace blender;
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
const int size = curves.points_num();
float3 *data = static_cast<float3 *>(MEM_malloc_arrayN(size, sizeof(float3), __func__));
const bke::CurvesFieldContext context(curves, ATTR_DOMAIN_POINT);
fn::FieldEvaluator evaluator(context, size);
fn::Field<float3> field(std::make_shared<bke::NormalFieldInput>());
evaluator.add_with_destination(std::move(field), {data, size});
evaluator.evaluate();
return reinterpret_cast<float(*)[3]>(data);
}

View File

@ -7,13 +7,27 @@
#pragma once
struct bContext;
struct Curves;
#ifdef __cplusplus
extern "C" {
#endif
/* -------------------------------------------------------------------- */
/** \name C Wrappers
* \{ */
void ED_operatortypes_curves(void);
/**
* Return an owning pointer to an array of point normals the same size as the number of control
* points. The normals depend on the normal mode for each curve and the "tilt" attribute and may be
* calculated for the evaluated points and sampled back to the control points.
*/
float (*ED_curves_point_normals_array_create(const struct Curves *curves_id))[3];
/** \} */
#ifdef __cplusplus
}
#endif

View File

@ -50,6 +50,8 @@ const EnumPropertyItem rna_enum_curve_normal_modes[] = {
# include "DEG_depsgraph.h"
# include "ED_curves.h"
# include "WM_api.h"
# include "WM_types.h"
@ -217,6 +219,14 @@ static void rna_CurveSlice_points_begin(CollectionPropertyIterator *iter, Pointe
rna_iterator_array_begin(iter, co, sizeof(float[3]), size, 0, NULL);
}
static void rna_Curves_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Curves *curves = rna_curves(ptr);
float(*positions)[3] = ED_curves_point_normals_array_create(curves);
const int size = curves->geometry.point_num;
rna_iterator_array_begin(iter, positions, sizeof(float[3]), size, true, NULL);
}
static void rna_Curves_update_data(struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
PointerRNA *ptr)
@ -268,6 +278,20 @@ static void rna_def_curves_point(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Index", "Index of this points");
}
/* Defines a read-only vector type since normals can not be modified manually. */
static void rna_def_read_only_float_vector(BlenderRNA *brna)
{
StructRNA *srna = RNA_def_struct(brna, "FloatVectorValueReadOnly", NULL);
RNA_def_struct_sdna(srna, "vec3f");
RNA_def_struct_ui_text(srna, "Read-Only Vector", "");
PropertyRNA *prop = RNA_def_property(srna, "vector", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_ui_text(prop, "Vector", "3D vector");
RNA_def_property_float_sdna(prop, NULL, "x");
RNA_def_property_array(prop, 3);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_curves_curve(BlenderRNA *brna)
{
StructRNA *srna;
@ -365,6 +389,24 @@ static void rna_def_curves(BlenderRNA *brna)
NULL);
RNA_def_property_update(prop, 0, "rna_Curves_update_data");
rna_def_read_only_float_vector(brna);
prop = RNA_def_property(srna, "normals", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "FloatVectorValueReadOnly");
/* `lookup_int` isn't provided since the entire normals array is allocated and calculated when
* it's accessed. */
RNA_def_property_collection_funcs(prop,
"rna_Curves_normals_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_Curves_position_data_length",
NULL,
NULL,
NULL);
RNA_def_property_ui_text(
prop, "Normals", "The curve normal value at each of the curve's control points");
/* materials */
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");

View File

@ -3239,7 +3239,7 @@ static void rna_def_mesh_polygons(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
/* Defines a read-only vector type since normals should not be modified manually. */
/* Defines a read-only vector type since normals can not be modified manually. */
static void rna_def_normal_layer_value(BlenderRNA *brna)
{
StructRNA *srna = RNA_def_struct(brna, "MeshNormalValue", NULL);