Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc')
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc200
1 files changed, 136 insertions, 64 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
index 7e95714a44b..dc924ede3a1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
@@ -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;
- }
- attribute.apply_span();
+ return BLI_hash_int_2d_to_float(id, seed);
}
-static void randomize_attribute_float(FloatWriteAttribute attribute,
- const float min,
- const float max,
- Span<uint32_t> hashes,
- const int seed)
+template<> inline float3 get_random_value(const uint32_t id, const uint32_t seed)
{
- 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;
+ 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_float3(Float3WriteAttribute attribute,
- const float3 min,
- const float3 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<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;
+ 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();
}
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 &params,
- const int seed)
+static void randomize_attribute_on_component(GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ 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);
}