Geometry Nodes: new Attribute Sample Texture node

This node allows sampling a texture for every vertex based on some
mapping attribute. Typical attribute names are the name of a uv map
(e.g. "UVMap") and "position". However, every attribute that can be
converted to a vector implicitly is supported.

It should be noted that as of right now, uv map attributes can only be
accessed after a Point Distribute node.

Ref T82584.

Differential Revision: https://developer.blender.org/D10121
This commit is contained in:
Jacques Lucke 2021-01-21 16:47:03 +01:00
parent a92ebab5da
commit 425e706921
Notes: blender-bot 2023-02-14 08:45:09 +01:00
Referenced by issue #82584, Sample Texture Node for trees and flowers scattering
11 changed files with 141 additions and 0 deletions

View File

@ -489,6 +489,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeMix"),
NodeItem("GeometryNodeAttributeColorRamp"),
NodeItem("GeometryNodeAttributeVectorMath"),
NodeItem("GeometryNodeAttributeSampleTexture"),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
NodeItem("ShaderNodeValToRGB"),

View File

@ -24,6 +24,7 @@
#include "BKE_attribute.h"
#include "BLI_color.hh"
#include "BLI_float2.hh"
#include "BLI_float3.hh"
namespace blender::bke {
@ -301,11 +302,13 @@ template<typename T> class TypedWriteAttribute {
using BooleanReadAttribute = TypedReadAttribute<bool>;
using FloatReadAttribute = TypedReadAttribute<float>;
using Float2ReadAttribute = TypedReadAttribute<float2>;
using Float3ReadAttribute = TypedReadAttribute<float3>;
using Int32ReadAttribute = TypedReadAttribute<int>;
using Color4fReadAttribute = TypedReadAttribute<Color4f>;
using BooleanWriteAttribute = TypedWriteAttribute<bool>;
using FloatWriteAttribute = TypedWriteAttribute<float>;
using Float2WriteAttribute = TypedWriteAttribute<float2>;
using Float3WriteAttribute = TypedWriteAttribute<float3>;
using Int32WriteAttribute = TypedWriteAttribute<int>;
using Color4fWriteAttribute = TypedWriteAttribute<Color4f>;

View File

@ -1361,6 +1361,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_ALIGN_ROTATION_TO_VECTOR 1018
#define GEO_NODE_POINT_TRANSLATE 1019
#define GEO_NODE_POINT_SCALE 1020
#define GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE 1021
/** \} */

View File

@ -4747,6 +4747,7 @@ static void registerGeometryNodes(void)
register_node_type_geo_attribute_color_ramp();
register_node_type_geo_point_rotate();
register_node_type_geo_align_rotation_to_vector();
register_node_type_geo_sample_texture();
}
static void registerFunctionNodes(void)

View File

@ -3289,6 +3289,13 @@ static void node_geometry_buts_object_info(uiLayout *layout, bContext *UNUSED(C)
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
static void node_geometry_buts_attribute_sample_texture(uiLayout *layout,
bContext *C,
PointerRNA *ptr)
{
uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL);
}
static void node_geometry_set_butfunc(bNodeType *ntype)
{
switch (ntype->type) {
@ -3343,6 +3350,9 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
case GEO_NODE_OBJECT_INFO:
ntype->draw_buttons = node_geometry_buts_object_info;
break;
case GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE:
ntype->draw_buttons = node_geometry_buts_attribute_sample_texture;
break;
}
}

View File

@ -8862,6 +8862,19 @@ static void def_geo_point_translate(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_attribute_sample_texture(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Texture");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Texture", "Texture to sample values from");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations");
}
static void def_geo_object_info(StructRNA *srna)
{
PropertyRNA *prop;

View File

@ -146,6 +146,7 @@ set(SRC
geometry/nodes/node_geo_attribute_fill.cc
geometry/nodes/node_geo_attribute_math.cc
geometry/nodes/node_geo_attribute_mix.cc
geometry/nodes/node_geo_attribute_sample_texture.cc
geometry/nodes/node_geo_attribute_randomize.cc
geometry/nodes/node_geo_attribute_vector_math.cc
geometry/nodes/node_geo_boolean.cc

View File

@ -47,6 +47,7 @@ void register_node_type_geo_attribute_mix(void);
void register_node_type_geo_attribute_color_ramp(void);
void register_node_type_geo_point_rotate(void);
void register_node_type_geo_align_rotation_to_vector(void);
void register_node_type_geo_sample_texture(void);
#ifdef __cplusplus
}

View File

@ -32,6 +32,8 @@ using bke::BooleanReadAttribute;
using bke::BooleanWriteAttribute;
using bke::Color4fReadAttribute;
using bke::Color4fWriteAttribute;
using bke::Float2ReadAttribute;
using bke::Float2WriteAttribute;
using bke::Float3ReadAttribute;
using bke::Float3WriteAttribute;
using bke::FloatReadAttribute;

View File

@ -289,6 +289,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_m
DefNode(GeometryNode, GEO_NODE_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_to_vector, "ALIGN_ROTATION_TO_VECTOR", AlignRotationToVector, "Align Rotation to Vector", "")
DefNode(GeometryNode, GEO_NODE_POINT_SCALE, def_geo_point_scale, "POINT_SCALE", PointScale, "Point Scale", "")
DefNode(GeometryNode, GEO_NODE_POINT_TRANSLATE, def_geo_point_translate, "POINT_TRANSLATE", PointTranslate, "Point Translate", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, def_geo_attribute_sample_texture, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "")
/* undefine macros */
#undef DefNode

View File

@ -0,0 +1,107 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BLI_compiler_attrs.h"
#include "DNA_texture_types.h"
#include "BKE_texture.h"
#include "RE_texture.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_attribute_sample_texture_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Mapping")},
{SOCK_STRING, N_("Result")},
{-1, ""},
};
static bNodeSocketTemplate geo_node_attribute_sample_texture_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static void execute_on_component(GeometryComponent &component, const GeoNodeExecParams &params)
{
const bNode &node = params.node();
Tex *texture = reinterpret_cast<Tex *>(node.id);
const std::string result_attribute_name = params.get_input<std::string>("Result");
if (texture == nullptr) {
return;
}
const std::string mapping_name = params.get_input<std::string>("Mapping");
if (!component.attribute_exists(mapping_name)) {
return;
}
OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
result_attribute_name, ATTR_DOMAIN_POINT, CD_PROP_COLOR);
if (!attribute_out) {
return;
}
Float3ReadAttribute mapping_attribute = component.attribute_get_for_read<float3>(
mapping_name, ATTR_DOMAIN_POINT, {0, 0, 0});
MutableSpan<Color4f> colors = attribute_out->get_span<Color4f>();
for (const int i : IndexRange(mapping_attribute.size())) {
TexResult texture_result = {0};
const float3 position = mapping_attribute[i];
/* For legacy reasons we have to map [0, 1] to [-1, 1] to support uv mappings. */
const float3 remapped_position = position * 2.0f - float3(1.0f);
BKE_texture_get_value(nullptr, texture, remapped_position, &texture_result, false);
colors[i] = {texture_result.tr, texture_result.tg, texture_result.tb, texture_result.ta};
}
attribute_out.apply_span_and_save();
}
static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
if (geometry_set.has<MeshComponent>()) {
execute_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
}
if (geometry_set.has<PointCloudComponent>()) {
execute_on_component(geometry_set.get_component_for_write<PointCloudComponent>(), params);
}
params.set_output("Geometry", geometry_set);
}
} // namespace blender::nodes
void register_node_type_geo_sample_texture()
{
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE,
"Attribute Sample Texture",
NODE_CLASS_ATTRIBUTE,
0);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_socket_templates(
&ntype, geo_node_attribute_sample_texture_in, geo_node_attribute_sample_texture_out);
ntype.geometry_node_execute = blender::nodes::geo_node_attribute_sample_texture_exec;
nodeRegisterType(&ntype);
}