Geometry Nodes: Optimize start point case of Points of Curve node

In the node groups for T103730, the "Points of Curve" node is often used to
retrieve the root point of every curve. Since the curve point offsets array
already contains that data directly, we can detect this as a special case and
avoid all the other work.

Differential Revision: https://developer.blender.org/D17128
This commit is contained in:
Hans Goudey 2023-01-27 09:44:30 -06:00
parent e99ae0a75d
commit 000e722c7d
Notes: blender-bot 2023-09-09 19:17:09 +02:00
Referenced by pull request #112185, Fix #112184: Adapt optimized case of Points of Curve node for domain
Referenced by commit 3b44fd3655, Fix #112184: Adapt optimized case of Points of Curve node for domain
1 changed files with 61 additions and 5 deletions

View File

@ -174,6 +174,57 @@ class CurvePointCountInput final : public bke::CurvesFieldInput {
}
};
/**
* The node is often used to retrieve the root point of the curve. If the curve indices are in
* order, the sort weights have no effect, and the sort index is the first point, then we can just
* return the curve offsets as a span directly.
*/
static bool use_start_point_special_case(const Field<int> &curve_index,
const Field<int> &sort_index,
const Field<float> &sort_weights)
{
if (!dynamic_cast<const fn::IndexFieldInput *>(&curve_index.node())) {
return false;
}
if (sort_index.node().depends_on_input() || sort_weights.node().depends_on_input()) {
return false;
}
return fn::evaluate_constant_field(sort_index) == 0;
}
class CurveStartPointInput final : public bke::CurvesFieldInput {
public:
CurveStartPointInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Point of Curve")
{
category_ = Category::Generated;
}
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
const eAttrDomain /*domain*/,
const IndexMask /*mask*/) const final
{
return VArray<int>::ForSpan(curves.offsets());
}
uint64_t hash() const final
{
return 2938459815345;
}
bool is_equal_to(const fn::FieldNode &other) const final
{
if (dynamic_cast<const CurveStartPointInput *>(&other)) {
return true;
}
return false;
}
std::optional<eAttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/)
{
return ATTR_DOMAIN_CURVE;
}
};
static void node_geo_exec(GeoNodeExecParams params)
{
const Field<int> curve_index = params.extract_input<Field<int>>("Curve Index");
@ -185,11 +236,16 @@ static void node_geo_exec(GeoNodeExecParams params)
ATTR_DOMAIN_CURVE)));
}
if (params.output_is_required("Point Index")) {
params.set_output("Point Index",
Field<int>(std::make_shared<PointsOfCurveInput>(
curve_index,
params.extract_input<Field<int>>("Sort Index"),
params.extract_input<Field<float>>("Weights"))));
Field<int> sort_index = params.extract_input<Field<int>>("Sort Index");
Field<int> sort_weight = params.extract_input<Field<float>>("Weights");
if (use_start_point_special_case(curve_index, sort_index, sort_weight)) {
params.set_output("Point Index", Field<int>(std::make_shared<CurveStartPointInput>()));
}
else {
params.set_output("Point Index",
Field<int>(std::make_shared<PointsOfCurveInput>(
curve_index, std::move(sort_index), std::move(sort_weight))));
}
}
}