Geometry Nodes: Add operation setting to attribute randomize node
This commit adds a drop-down to the attribute randomize node to support a few operations on the values of existing attributes: "Replace/Create" (the existing behavior), "Add", "Subtract", and "Multiply". At this point, the operations are limited by what is simple to implement. More could be added in the future, but there isn't a strong use case for more complex operations anyway, and a second math node can be used. Differential Revision: https://developer.blender.org/D10269
This commit is contained in:
parent
d7c2c889a6
commit
d4fd06d6ce
Notes:
blender-bot
2023-02-13 19:47:51 +01:00
Referenced by issue #84970, Add mode enum to the randomize attribute node
|
@ -39,7 +39,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 7
|
||||
#define BLENDER_FILE_SUBVERSION 8
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
|
|
@ -90,6 +90,16 @@ BLI_INLINE unsigned int BLI_hash_string(const char *str)
|
|||
return i;
|
||||
}
|
||||
|
||||
BLI_INLINE float BLI_hash_int_2d_to_float(uint32_t kx, uint32_t ky)
|
||||
{
|
||||
return (float)BLI_hash_int_2d(kx, ky) / (float)0xFFFFFFFFu;
|
||||
}
|
||||
|
||||
BLI_INLINE float BLI_hash_int_3d_to_float(uint32_t kx, uint32_t ky, uint32_t kz)
|
||||
{
|
||||
return (float)BLI_hash_int_3d(kx, ky, kz) / (float)0xFFFFFFFFu;
|
||||
}
|
||||
|
||||
BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
|
||||
{
|
||||
return BLI_hash_int_2d(k, 0);
|
||||
|
|
|
@ -1704,6 +1704,25 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 293, 8)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
if (ntree->type != NTREE_GEOMETRY) {
|
||||
continue;
|
||||
}
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->type == GEO_NODE_POINT_INSTANCE && node->storage == NULL) {
|
||||
NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
|
||||
sizeof(NodeAttributeRandomize), __func__);
|
||||
data->data_type = node->custom1;
|
||||
data->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE;
|
||||
node->storage = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
|
|
@ -1109,6 +1109,16 @@ typedef struct NodeAttributeMix {
|
|||
uint8_t input_type_b;
|
||||
} NodeAttributeMix;
|
||||
|
||||
typedef struct NodeAttributeRandomize {
|
||||
/* CustomDataType. */
|
||||
uint8_t data_type;
|
||||
/* AttributeDomain. */
|
||||
uint8_t domain;
|
||||
/* GeometryNodeAttributeRandomizeMode. */
|
||||
uint8_t operation;
|
||||
char _pad[1];
|
||||
} NodeAttributeRandomize;
|
||||
|
||||
typedef struct NodeAttributeVectorMath {
|
||||
/* NodeVectorMathOperation */
|
||||
uint8_t operation;
|
||||
|
@ -1637,6 +1647,7 @@ typedef enum GeometryNodeAttributeInputMode {
|
|||
GEO_NODE_ATTRIBUTE_INPUT_VECTOR = 2,
|
||||
GEO_NODE_ATTRIBUTE_INPUT_COLOR = 3,
|
||||
GEO_NODE_ATTRIBUTE_INPUT_BOOLEAN = 4,
|
||||
GEO_NODE_ATTRIBUTE_INPUT_INTEGER = 5,
|
||||
} GeometryNodeAttributeInputMode;
|
||||
|
||||
typedef enum GeometryNodePointDistributeMethod {
|
||||
|
@ -1649,6 +1660,13 @@ typedef enum GeometryNodeRotatePointsType {
|
|||
GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE = 1,
|
||||
} GeometryNodeRotatePointsType;
|
||||
|
||||
typedef enum GeometryNodeAttributeRandomizeMode {
|
||||
GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE = 0,
|
||||
GEO_NODE_ATTRIBUTE_RANDOMIZE_ADD = 1,
|
||||
GEO_NODE_ATTRIBUTE_RANDOMIZE_SUBTRACT = 2,
|
||||
GEO_NODE_ATTRIBUTE_RANDOMIZE_MULTIPLY = 3,
|
||||
} GeometryNodeAttributeRandomizeMode;
|
||||
|
||||
typedef enum GeometryNodeRotatePointsSpace {
|
||||
GEO_NODE_POINT_ROTATE_SPACE_OBJECT = 0,
|
||||
GEO_NODE_POINT_ROTATE_SPACE_POINT = 1,
|
||||
|
|
|
@ -355,6 +355,30 @@ const EnumPropertyItem rna_enum_node_filter_items[] = {
|
|||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem rna_node_geometry_attribute_randomize_operation_items[] = {
|
||||
{GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE,
|
||||
"REPLACE_CREATE",
|
||||
ICON_NONE,
|
||||
"Replace/Create",
|
||||
"Replace the value and data type of an existing attribute, or create a new one"},
|
||||
{GEO_NODE_ATTRIBUTE_RANDOMIZE_ADD,
|
||||
"ADD",
|
||||
ICON_NONE,
|
||||
"Add",
|
||||
"Add the random values to the existing attribute values"},
|
||||
{GEO_NODE_ATTRIBUTE_RANDOMIZE_SUBTRACT,
|
||||
"SUBTRACT",
|
||||
ICON_NONE,
|
||||
"Subtract",
|
||||
"Subtract random values from the existing attribute values"},
|
||||
{GEO_NODE_ATTRIBUTE_RANDOMIZE_MULTIPLY,
|
||||
"MULTIPLY",
|
||||
ICON_NONE,
|
||||
"Multiply",
|
||||
"Multiply the existing attribute values with the random values"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
#ifndef RNA_RUNTIME
|
||||
static const EnumPropertyItem node_sampler_type_items[] = {
|
||||
{0, "NEAREST", 0, "Nearest", ""},
|
||||
|
@ -1921,7 +1945,7 @@ static const EnumPropertyItem *itemf_function_check(
|
|||
|
||||
static bool attribute_random_type_supported(const EnumPropertyItem *item)
|
||||
{
|
||||
return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL);
|
||||
return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL, CD_PROP_INT32);
|
||||
}
|
||||
static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_type_itemf(
|
||||
bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
|
||||
|
@ -1930,15 +1954,47 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_type_itemf(
|
|||
return itemf_function_check(rna_enum_attribute_type_items, attribute_random_type_supported);
|
||||
}
|
||||
|
||||
static bool attribute_random_domain_supported(const EnumPropertyItem *item)
|
||||
{
|
||||
return item->value == ATTR_DOMAIN_POINT;
|
||||
}
|
||||
static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_domain_itemf(
|
||||
bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
|
||||
static const EnumPropertyItem *rna_GeometryNodeAttributeRandomize_operation_itemf(
|
||||
bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
|
||||
{
|
||||
bNode *node = ptr->data;
|
||||
const NodeAttributeRandomize *node_storage = (NodeAttributeRandomize *)node->storage;
|
||||
const CustomDataType data_type = (CustomDataType)node_storage->data_type;
|
||||
|
||||
EnumPropertyItem *item_array = NULL;
|
||||
int items_len = 0;
|
||||
for (const EnumPropertyItem *item = rna_node_geometry_attribute_randomize_operation_items;
|
||||
item->identifier != NULL;
|
||||
item++) {
|
||||
if (data_type == CD_PROP_BOOL) {
|
||||
if (item->value == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) {
|
||||
RNA_enum_item_add(&item_array, &items_len, item);
|
||||
}
|
||||
}
|
||||
else {
|
||||
RNA_enum_item_add(&item_array, &items_len, item);
|
||||
}
|
||||
}
|
||||
RNA_enum_item_end(&item_array, &items_len);
|
||||
|
||||
*r_free = true;
|
||||
return itemf_function_check(rna_enum_attribute_domain_items, attribute_random_domain_supported);
|
||||
return item_array;
|
||||
}
|
||||
|
||||
static void rna_GeometryNodeAttributeRandomize_data_type_update(Main *bmain,
|
||||
Scene *scene,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
bNode *node = ptr->data;
|
||||
NodeAttributeRandomize *node_storage = (NodeAttributeRandomize *)node->storage;
|
||||
|
||||
/* The boolean data type has no extra operations besides,
|
||||
* replace, so make sure the enum value is set properly. */
|
||||
if (node_storage->data_type == CD_PROP_BOOL) {
|
||||
node_storage->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE;
|
||||
}
|
||||
|
||||
rna_Node_socket_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static bool attribute_fill_type_supported(const EnumPropertyItem *item)
|
||||
|
@ -8528,9 +8584,27 @@ static void def_geo_attribute_create_common(StructRNA *srna,
|
|||
|
||||
static void def_geo_attribute_randomize(StructRNA *srna)
|
||||
{
|
||||
def_geo_attribute_create_common(srna,
|
||||
"rna_GeometryNodeAttributeRandom_type_itemf",
|
||||
"rna_GeometryNodeAttributeRandom_domain_itemf");
|
||||
PropertyRNA *prop;
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeAttributeRandomize", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "data_type");
|
||||
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
|
||||
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeRandom_type_itemf");
|
||||
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
|
||||
RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
|
||||
RNA_def_property_update(
|
||||
prop, NC_NODE | NA_EDITED, "rna_GeometryNodeAttributeRandomize_data_type_update");
|
||||
|
||||
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "operation");
|
||||
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_randomize_operation_items);
|
||||
RNA_def_property_enum_funcs(
|
||||
prop, NULL, NULL, "rna_GeometryNodeAttributeRandomize_operation_itemf");
|
||||
RNA_def_property_enum_default(prop, GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE);
|
||||
RNA_def_property_ui_text(prop, "Operation", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||
}
|
||||
|
||||
static void def_geo_attribute_fill(StructRNA *srna)
|
||||
|
|
|
@ -32,6 +32,8 @@ static bNodeSocketTemplate geo_node_attribute_randomize_in[] = {
|
|||
{SOCK_VECTOR, N_("Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX},
|
||||
{SOCK_FLOAT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
|
||||
{SOCK_FLOAT, N_("Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
|
||||
{SOCK_INT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -100000, 100000},
|
||||
{SOCK_INT, N_("Max"), 100.0f, 0.0f, 0.0f, 0.0f, -100000, 100000},
|
||||
{SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000},
|
||||
{-1, ""},
|
||||
};
|
||||
|
@ -46,11 +48,17 @@ static void geo_node_attribute_random_layout(uiLayout *layout,
|
|||
PointerRNA *ptr)
|
||||
{
|
||||
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
|
||||
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static void geo_node_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node)
|
||||
{
|
||||
node->custom1 = CD_PROP_FLOAT;
|
||||
NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
|
||||
sizeof(NodeAttributeRandomize), __func__);
|
||||
data->data_type = CD_PROP_FLOAT;
|
||||
data->domain = ATTR_DOMAIN_POINT;
|
||||
data->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE;
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
static void geo_node_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
|
@ -59,71 +67,97 @@ static void geo_node_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode
|
|||
bNodeSocket *sock_max_vector = sock_min_vector->next;
|
||||
bNodeSocket *sock_min_float = sock_max_vector->next;
|
||||
bNodeSocket *sock_max_float = sock_min_float->next;
|
||||
bNodeSocket *sock_min_int = sock_max_float->next;
|
||||
bNodeSocket *sock_max_int = sock_min_int->next;
|
||||
|
||||
const CustomDataType data_type = static_cast<CustomDataType>(node->custom1);
|
||||
const NodeAttributeRandomize &storage = *(const NodeAttributeRandomize *)node->storage;
|
||||
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
|
||||
nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3);
|
||||
nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3);
|
||||
nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT);
|
||||
nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT);
|
||||
nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32);
|
||||
nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32);
|
||||
}
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
/** Rehash to combine the seed with the "id" hash and a mutator for each dimension. */
|
||||
static float noise_from_index_and_mutator(const int seed, const int hash, const int mutator)
|
||||
template<typename T> T get_random_value(const uint32_t id, const uint32_t seed);
|
||||
|
||||
template<> inline bool get_random_value(const uint32_t id, const uint32_t seed)
|
||||
{
|
||||
const int combined_hash = BLI_hash_int_3d(seed, hash, mutator);
|
||||
return BLI_hash_int_01(combined_hash);
|
||||
return BLI_hash_int_2d_to_float(id, seed) > 0.5f;
|
||||
}
|
||||
|
||||
/** Rehash to combine the seed with the "id" hash. */
|
||||
static float noise_from_index(const int seed, const int hash)
|
||||
template<> inline int get_random_value(const uint32_t id, const uint32_t seed)
|
||||
{
|
||||
const int combined_hash = BLI_hash_int_2d(seed, hash);
|
||||
return BLI_hash_int_01(combined_hash);
|
||||
return BLI_hash_int_2d(id, seed);
|
||||
}
|
||||
|
||||
static void randomize_attribute_bool(BooleanWriteAttribute attribute,
|
||||
Span<uint32_t> hashes,
|
||||
const int seed)
|
||||
template<> inline float get_random_value(const uint32_t id, const uint32_t seed)
|
||||
{
|
||||
MutableSpan<bool> attribute_span = attribute.get_span();
|
||||
for (const int i : IndexRange(attribute.size())) {
|
||||
const bool value = noise_from_index(seed, (int)hashes[i]) > 0.5f;
|
||||
attribute_span[i] = value;
|
||||
return BLI_hash_int_2d_to_float(id, seed);
|
||||
}
|
||||
|
||||
template<> inline float3 get_random_value(const uint32_t id, const uint32_t seed)
|
||||
{
|
||||
const float x = BLI_hash_int_3d_to_float(seed, id, 435109);
|
||||
const float y = BLI_hash_int_3d_to_float(seed, id, 380867);
|
||||
const float z = BLI_hash_int_3d_to_float(seed, id, 1059217);
|
||||
|
||||
return float3(x, y, z);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void randomize_attribute(MutableSpan<T> span,
|
||||
const T min,
|
||||
const T max,
|
||||
Span<uint32_t> ids,
|
||||
const uint32_t seed,
|
||||
const GeometryNodeAttributeRandomizeMode operation)
|
||||
{
|
||||
/* The operations could be templated too, but it doesn't make the code much shorter. */
|
||||
switch (operation) {
|
||||
case GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE:
|
||||
for (const int i : span.index_range()) {
|
||||
const T random_value = get_random_value<T>(ids[i], seed) * (max - min) + min;
|
||||
span[i] = random_value;
|
||||
}
|
||||
break;
|
||||
case GEO_NODE_ATTRIBUTE_RANDOMIZE_ADD:
|
||||
for (const int i : span.index_range()) {
|
||||
const T random_value = get_random_value<T>(ids[i], seed) * (max - min) + min;
|
||||
span[i] = span[i] + random_value;
|
||||
}
|
||||
break;
|
||||
case GEO_NODE_ATTRIBUTE_RANDOMIZE_SUBTRACT:
|
||||
for (const int i : span.index_range()) {
|
||||
const T random_value = get_random_value<T>(ids[i], seed) * (max - min) + min;
|
||||
span[i] = span[i] - random_value;
|
||||
}
|
||||
break;
|
||||
case GEO_NODE_ATTRIBUTE_RANDOMIZE_MULTIPLY:
|
||||
for (const int i : span.index_range()) {
|
||||
const T random_value = get_random_value<T>(ids[i], seed) * (max - min) + min;
|
||||
span[i] = span[i] * random_value;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BLI_assert(false);
|
||||
break;
|
||||
}
|
||||
attribute.apply_span();
|
||||
}
|
||||
|
||||
static void randomize_attribute_float(FloatWriteAttribute attribute,
|
||||
const float min,
|
||||
const float max,
|
||||
Span<uint32_t> hashes,
|
||||
const int seed)
|
||||
static void randomize_attribute_bool(MutableSpan<bool> span,
|
||||
Span<uint32_t> ids,
|
||||
const uint32_t seed,
|
||||
const GeometryNodeAttributeRandomizeMode operation)
|
||||
{
|
||||
MutableSpan<float> attribute_span = attribute.get_span();
|
||||
for (const int i : IndexRange(attribute.size())) {
|
||||
const float value = noise_from_index(seed, (int)hashes[i]) * (max - min) + min;
|
||||
attribute_span[i] = value;
|
||||
BLI_assert(operation == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE);
|
||||
for (const int i : span.index_range()) {
|
||||
const bool random_value = get_random_value<bool>(ids[i], seed);
|
||||
span[i] = random_value;
|
||||
}
|
||||
attribute.apply_span();
|
||||
}
|
||||
|
||||
static void randomize_attribute_float3(Float3WriteAttribute attribute,
|
||||
const float3 min,
|
||||
const float3 max,
|
||||
Span<uint32_t> hashes,
|
||||
const int seed)
|
||||
{
|
||||
MutableSpan<float3> attribute_span = attribute.get_span();
|
||||
for (const int i : IndexRange(attribute.size())) {
|
||||
const float x = noise_from_index_and_mutator(seed, (int)hashes[i], 47);
|
||||
const float y = noise_from_index_and_mutator(seed, (int)hashes[i], 8);
|
||||
const float z = noise_from_index_and_mutator(seed, (int)hashes[i], 64);
|
||||
const float3 value = float3(x, y, z) * (max - min) + min;
|
||||
attribute_span[i] = value;
|
||||
}
|
||||
attribute.apply_span();
|
||||
}
|
||||
|
||||
Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
|
||||
|
@ -168,16 +202,21 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
|
|||
return static_cast<AttributeDomain>(node.custom2);
|
||||
}
|
||||
|
||||
static void randomize_attribute(GeometryComponent &component,
|
||||
const GeoNodeExecParams ¶ms,
|
||||
const int seed)
|
||||
static void randomize_attribute_on_component(GeometryComponent &component,
|
||||
const GeoNodeExecParams ¶ms,
|
||||
StringRef attribute_name,
|
||||
const CustomDataType data_type,
|
||||
const GeometryNodeAttributeRandomizeMode operation,
|
||||
const int seed)
|
||||
{
|
||||
const std::string attribute_name = params.get_input<std::string>("Attribute");
|
||||
if (attribute_name.empty()) {
|
||||
return;
|
||||
/* If the node is not in "replace / create" mode and the attribute
|
||||
* doesn't already exist, don't do the operation. */
|
||||
if (operation != GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) {
|
||||
if (!component.attribute_exists(attribute_name)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const bNode &node = params.node();
|
||||
const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
|
||||
|
||||
const AttributeDomain domain = get_result_domain(component, params, attribute_name);
|
||||
|
||||
OutputAttributePtr attribute = component.attribute_try_get_for_output(
|
||||
|
@ -186,44 +225,75 @@ static void randomize_attribute(GeometryComponent &component,
|
|||
return;
|
||||
}
|
||||
|
||||
fn::GMutableSpan span = (operation == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) ?
|
||||
attribute->get_span_for_write_only() :
|
||||
attribute->get_span();
|
||||
|
||||
Array<uint32_t> hashes = get_geometry_element_ids_as_uints(component, domain);
|
||||
|
||||
switch (data_type) {
|
||||
case CD_PROP_FLOAT: {
|
||||
const float min_value = params.get_input<float>("Min_001");
|
||||
const float max_value = params.get_input<float>("Max_001");
|
||||
randomize_attribute_float(*attribute, min_value, max_value, hashes, seed);
|
||||
case CD_PROP_FLOAT3: {
|
||||
const float3 min = params.get_input<float3>("Min");
|
||||
const float3 max = params.get_input<float3>("Max");
|
||||
randomize_attribute<float3>(span.typed<float3>(), min, max, hashes, seed, operation);
|
||||
break;
|
||||
}
|
||||
case CD_PROP_FLOAT3: {
|
||||
const float3 min_value = params.get_input<float3>("Min");
|
||||
const float3 max_value = params.get_input<float3>("Max");
|
||||
randomize_attribute_float3(*attribute, min_value, max_value, hashes, seed);
|
||||
case CD_PROP_FLOAT: {
|
||||
const float min = params.get_input<float>("Min_001");
|
||||
const float max = params.get_input<float>("Max_001");
|
||||
randomize_attribute<float>(span.typed<float>(), min, max, hashes, seed, operation);
|
||||
break;
|
||||
}
|
||||
case CD_PROP_BOOL: {
|
||||
randomize_attribute_bool(*attribute, hashes, seed);
|
||||
randomize_attribute_bool(span.typed<bool>(), hashes, seed, operation);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case CD_PROP_INT32: {
|
||||
const int min = params.get_input<int>("Min_002");
|
||||
const int max = params.get_input<int>("Max_002");
|
||||
randomize_attribute<int>(span.typed<int>(), min, max, hashes, seed, operation);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
BLI_assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
attribute.save();
|
||||
}
|
||||
attribute.apply_span_and_save();
|
||||
} // namespace blender::nodes
|
||||
|
||||
static void geo_node_random_attribute_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
||||
const std::string attribute_name = params.get_input<std::string>("Attribute");
|
||||
if (attribute_name.empty()) {
|
||||
params.set_output("Geometry", geometry_set);
|
||||
return;
|
||||
}
|
||||
const int seed = params.get_input<int>("Seed");
|
||||
const NodeAttributeRandomize &storage = *(const NodeAttributeRandomize *)params.node().storage;
|
||||
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
|
||||
const GeometryNodeAttributeRandomizeMode operation =
|
||||
static_cast<GeometryNodeAttributeRandomizeMode>(storage.operation);
|
||||
|
||||
geometry_set = geometry_set_realize_instances(geometry_set);
|
||||
|
||||
if (geometry_set.has<MeshComponent>()) {
|
||||
randomize_attribute(geometry_set.get_component_for_write<MeshComponent>(), params, seed);
|
||||
randomize_attribute_on_component(geometry_set.get_component_for_write<MeshComponent>(),
|
||||
params,
|
||||
attribute_name,
|
||||
data_type,
|
||||
operation,
|
||||
seed);
|
||||
}
|
||||
if (geometry_set.has<PointCloudComponent>()) {
|
||||
randomize_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params, seed);
|
||||
randomize_attribute_on_component(geometry_set.get_component_for_write<PointCloudComponent>(),
|
||||
params,
|
||||
attribute_name,
|
||||
data_type,
|
||||
operation,
|
||||
seed);
|
||||
}
|
||||
|
||||
params.set_output("Geometry", geometry_set);
|
||||
|
@ -243,5 +313,7 @@ void register_node_type_geo_attribute_randomize()
|
|||
node_type_update(&ntype, geo_node_attribute_randomize_update);
|
||||
ntype.geometry_node_execute = blender::nodes::geo_node_random_attribute_exec;
|
||||
ntype.draw_buttons = geo_node_attribute_random_layout;
|
||||
node_type_storage(
|
||||
&ntype, "NodeAttributeRandomize", node_free_standard_storage, node_copy_standard_storage);
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue