WIP: Compositor: Add texture coordinate and noise nodes #112733

Draft
Sergey Sharybin wants to merge 2 commits from Sergey/blender:compositor_procedural into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
20 changed files with 416 additions and 3 deletions

View File

@ -25,7 +25,7 @@ class NODE_MT_category_compositor_input(Menu):
node_add_menu.add_node_type(layout, "CompositorNodeImage")
node_add_menu.add_node_type(layout, "CompositorNodeMask")
node_add_menu.add_node_type(layout, "CompositorNodeMovieClip")
node_add_menu.add_node_type(layout, "CompositorNodeTexture")
node_add_menu.add_node_type(layout, "CompositorNodeTextureCoordinate")
if is_group:
layout.separator()
@ -266,6 +266,19 @@ class NODE_MT_category_compositor_transform(Menu):
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_compositor_texture(Menu):
bl_idname = "NODE_MT_category_compositor_texture"
bl_label = "Texture"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "ShaderNodeTexNoise")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeTexture")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_compositor_utilities(Menu):
bl_idname = "NODE_MT_category_compositor_utilities"
bl_label = "Utilities"
@ -331,6 +344,7 @@ class NODE_MT_compositor_node_add_all(Menu):
layout.separator()
layout.menu("NODE_MT_category_compositor_tracking")
layout.separator()
layout.menu("NODE_MT_category_compositor_texture")
layout.menu("NODE_MT_category_compositor_transform")
layout.menu("NODE_MT_category_compositor_utilities")
layout.menu("NODE_MT_category_compositor_vector")
@ -355,6 +369,7 @@ classes = (
NODE_MT_category_compositor_keying,
NODE_MT_category_compositor_mask,
NODE_MT_category_compositor_tracking,
NODE_MT_category_compositor_texture,
NODE_MT_category_compositor_transform,
NODE_MT_category_compositor_utilities,
NODE_MT_category_compositor_vector,

View File

@ -1083,6 +1083,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_COMBINE_XYZ 331
#define CMP_NODE_COMBINE_COLOR 332
#define CMP_NODE_SEPARATE_COLOR 333
#define CMP_NODE_TEXTURE_COORDINATE 334
/* channel toggles */
#define CMP_CHAN_RGB 1

View File

@ -131,6 +131,10 @@ if(WITH_COMPOSITOR_CPU)
nodes/COM_SwitchViewNode.h
nodes/COM_TextureNode.cc
nodes/COM_TextureNode.h
nodes/COM_TextureCoordinateNode.cc
nodes/COM_TextureCoordinateNode.h
nodes/COM_TextureNoiseNode.cc
nodes/COM_TextureNoiseNode.h
nodes/COM_TimeNode.cc
nodes/COM_TimeNode.h
nodes/COM_ValueNode.cc
@ -410,6 +414,10 @@ if(WITH_COMPOSITOR_CPU)
operations/COM_MultilayerImageOperation.h
operations/COM_TextureOperation.cc
operations/COM_TextureOperation.h
operations/COM_TextureCoordinateOperation.cc
operations/COM_TextureCoordinateOperation.h
operations/COM_TextureNoiseOperation.cc
operations/COM_TextureNoiseOperation.h
operations/COM_SocketProxyOperation.cc

View File

@ -94,7 +94,9 @@
#include "COM_SunBeamsNode.h"
#include "COM_SwitchNode.h"
#include "COM_SwitchViewNode.h"
#include "COM_TextureCoordinateNode.h"
#include "COM_TextureNode.h"
#include "COM_TextureNoiseNode.h"
#include "COM_TimeNode.h"
#include "COM_TonemapNode.h"
#include "COM_TrackPositionNode.h"
@ -440,6 +442,12 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_KUWAHARA:
node = new KuwaharaNode(b_node);
break;
case CMP_NODE_TEXTURE_COORDINATE:
node = new TextureCoordinateNode(b_node);
break;
case SH_NODE_TEX_NOISE:
node = new TextureNoiseNode(b_node);
break;
}
return node;
}

View File

@ -9,6 +9,7 @@
#include "BLI_ghash.h"
#include "BLI_hash.hh"
#include "BLI_math_vector.hh"
#include "BLI_rect.h"
#include "BLI_span.hh"
#include "BLI_threads.h"
@ -650,6 +651,20 @@ class NodeOperation {
/** \} */
inline float read_sampled_float(const float x, const float y, const PixelSampler sampler)
{
float data[4];
read_sampled(data, x, y, sampler);
return data[0];
}
inline float3 read_sampled_float3(const float x, const float y, const PixelSampler sampler)
{
float data[4];
read_sampled(data, x, y, sampler);
return float3(data);
}
protected:
NodeOperation();

View File

@ -0,0 +1,26 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "COM_TextureCoordinateNode.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "COM_TextureCoordinateOperation.h"
namespace blender::compositor {
void TextureCoordinateNode::convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const
{
TextureCoordinateOperation *operation = new TextureCoordinateOperation();
NodeOutput *output = this->get_output_socket(0);
operation->set_render_data(context.get_render_data());
converter.add_operation(operation);
converter.map_output_socket(output, operation->get_output_socket());
}
} // namespace blender::compositor

View File

@ -0,0 +1,18 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "COM_Node.h"
namespace blender::compositor {
class TextureCoordinateNode : public Node {
public:
TextureCoordinateNode(bNode *editor_node) : Node(editor_node) {}
void convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const override;
};
} // namespace blender::compositor

View File

@ -0,0 +1,38 @@
/* SPDX-FileCopyrightText: 2011 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "COM_TextureNoiseNode.h"
#include "COM_TextureNoiseOperation.h"
namespace blender::compositor {
void TextureNoiseNode::convert_to_operations(NodeConverter &converter,
const CompositorContext & /*context*/) const
{
TextureNoiseOperation *color_operation = new TextureNoiseOperation();
converter.add_operation(color_operation);
NodeInput *vector_input = this->get_input_socket(0);
// NodeInput *w_input = this->get_input_socket(1);
NodeInput *scale_input = this->get_input_socket(2);
NodeInput *detail_input = this->get_input_socket(3);
NodeInput *roughness_input = this->get_input_socket(4);
NodeInput *lacunarity_input = this->get_input_socket(5);
NodeInput *distortion_input = this->get_input_socket(6);
// NodeOutput *value_output = this->get_output_socket(0);
NodeOutput *color_output = this->get_output_socket(1);
converter.map_input_socket(vector_input, color_operation->get_input_socket(0));
converter.map_input_socket(scale_input, color_operation->get_input_socket(1));
converter.map_input_socket(detail_input, color_operation->get_input_socket(2));
converter.map_input_socket(roughness_input, color_operation->get_input_socket(3));
converter.map_input_socket(lacunarity_input, color_operation->get_input_socket(4));
converter.map_input_socket(distortion_input, color_operation->get_input_socket(5));
converter.map_output_socket(color_output, color_operation->get_output_socket());
}
} // namespace blender::compositor

View File

@ -0,0 +1,19 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "COM_Node.h"
#include "DNA_node_types.h"
namespace blender::compositor {
class TextureNoiseNode : public Node {
public:
TextureNoiseNode(bNode *editor_node) : Node(editor_node) {}
void convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const override;
};
} // namespace blender::compositor

View File

@ -0,0 +1,56 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "COM_TextureCoordinateOperation.h"
#include "BLI_math_base.hh"
#include "BKE_scene.h"
namespace blender::compositor {
TextureCoordinateOperation::TextureCoordinateOperation()
{
this->add_output_socket(DataType::Vector);
}
void TextureCoordinateOperation::execute_pixel_sampled(float output[4],
const float x,
const float y,
const PixelSampler /*sampler*/)
{
const float width = this->get_width();
const float height = this->get_height();
const float side = math::max(width, height);
output[0] = x / side;
output[1] = y / side;
output[2] = 0;
}
void TextureCoordinateOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
// XXX
}
void TextureCoordinateOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
r_area = preferred_area;
if (BLI_rcti_is_empty(&preferred_area)) {
int width, height;
BKE_render_resolution(rd_, false, &width, &height);
r_area.xmax = preferred_area.xmin + width;
r_area.ymax = preferred_area.ymin + height;
}
if (execution_model_ == eExecutionModel::FullFrame) {
/* Determine inputs. */
rcti temp = COM_AREA_NONE;
NodeOperation::determine_canvas(r_area, temp);
}
}
} // namespace blender::compositor

View File

@ -0,0 +1,30 @@
/* SPDX-FileCopyrightText: 2032 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "COM_ConstantOperation.h"
namespace blender::compositor {
class TextureCoordinateOperation : public MultiThreadedOperation {
const RenderData *rd_;
public:
TextureCoordinateOperation();
void set_render_data(const RenderData *rd)
{
rd_ = rd;
}
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
};
} // namespace blender::compositor

View File

@ -0,0 +1,83 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "COM_TextureNoiseOperation.h"
#include "BLI_math_vector.hh"
#include "BLI_noise.hh"
namespace blender::compositor {
TextureNoiseOperation::TextureNoiseOperation()
{
this->add_input_socket(DataType::Vector); // Vector.
this->add_input_socket(DataType::Value); // Scale.
this->add_input_socket(DataType::Value); // Detail.
this->add_input_socket(DataType::Value); // Roughness.
this->add_input_socket(DataType::Value); // Lacunarity.
this->add_input_socket(DataType::Value); // Distortion.
this->add_output_socket(DataType::Color);
this->set_canvas_input_index(0);
}
void TextureNoiseOperation::init_execution()
{
vector_reader_ = this->get_input_socket_reader(0);
scale_reader_ = this->get_input_socket_reader(1);
detail_reader_ = this->get_input_socket_reader(2);
roughness_reader_ = this->get_input_socket_reader(3);
lacunarity_reader_ = this->get_input_socket_reader(4);
distortion_reader_ = this->get_input_socket_reader(5);
}
void TextureNoiseOperation::deinit_execution()
{
vector_reader_ = nullptr;
scale_reader_ = nullptr;
detail_reader_ = nullptr;
roughness_reader_ = nullptr;
lacunarity_reader_ = nullptr;
distortion_reader_ = nullptr;
}
void TextureNoiseOperation::execute_pixel_sampled(float output[4],
const float x,
const float y,
const PixelSampler sampler)
{
const float scale = scale_reader_->read_sampled_float(x, y, sampler);
const float detail = detail_reader_->read_sampled_float(x, y, sampler);
const float roughness = roughness_reader_->read_sampled_float(x, y, sampler);
const float lacunarity = lacunarity_reader_->read_sampled_float(x, y, sampler);
const float distortion = distortion_reader_->read_sampled_float(x, y, sampler);
const float3 vector = vector_reader_->read_sampled_float3(x, y, sampler);
const float3 position_vector = vector * scale;
const float4 position{position_vector[0], position_vector[1], position_vector[2], 0.0f};
const float3 c = noise::perlin_float3_fractal_distorted(
position, detail, roughness, lacunarity, distortion, false);
output[0] = c[0];
output[1] = c[1];
output[2] = c[2];
output[3] = 1.0f;
}
void TextureNoiseOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
// XXX
}
void TextureNoiseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperation::determine_canvas(preferred_area, r_area);
}
} // namespace blender::compositor

View File

@ -0,0 +1,35 @@
/* SPDX-FileCopyrightText: 2032 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "COM_ConstantOperation.h"
namespace blender::compositor {
class TextureNoiseOperation : public MultiThreadedOperation {
SocketReader *vector_reader_ = nullptr;
SocketReader *scale_reader_ = nullptr;
SocketReader *detail_reader_ = nullptr;
SocketReader *roughness_reader_ = nullptr;
SocketReader *lacunarity_reader_ = nullptr;
SocketReader *distortion_reader_ = nullptr;
public:
TextureNoiseOperation();
void init_execution() override;
void deinit_execution() override;
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
protected:
};
} // namespace blender::compositor

View File

@ -8525,6 +8525,8 @@ static void def_cmp_antialiasing(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_cmp_texture_coordinate(StructRNA * /*srna*/) {}
/* -- Texture Nodes --------------------------------------------------------- */
static void def_tex_output(StructRNA *srna)

View File

@ -225,6 +225,7 @@ DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARA
DefNode(CompositorNode, CMP_NODE_SEPARATE_COLOR, def_cmp_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
DefNode(CompositorNode, CMP_NODE_COMBINE_COLOR, def_cmp_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
DefNode(CompositorNode, CMP_NODE_KUWAHARA, def_cmp_kuwahara, "KUWAHARA", Kuwahara, "Kuwahara", "" )
DefNode(CompositorNode, CMP_NODE_TEXTURE_COORDINATE, def_cmp_texture_coordinate, "TEX_COORD", TextureCoordinate, "Texture Coordinate", "" )
DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )

View File

@ -108,6 +108,7 @@ set(SRC
nodes/node_composite_switch.cc
nodes/node_composite_switchview.cc
nodes/node_composite_texture.cc
nodes/node_composite_texture_coordinate.cc
nodes/node_composite_tonemap.cc
nodes/node_composite_trackpos.cc
nodes/node_composite_transform.cc

View File

@ -101,6 +101,7 @@ void register_composite_nodes()
register_node_type_cmp_switch_view();
register_node_type_cmp_switch();
register_node_type_cmp_texture();
register_node_type_cmp_texture_coordinate();
register_node_type_cmp_tonemap();
register_node_type_cmp_trackpos();
register_node_type_cmp_transform();

View File

@ -97,6 +97,7 @@ void register_node_type_cmp_sunbeams();
void register_node_type_cmp_switch_view();
void register_node_type_cmp_switch();
void register_node_type_cmp_texture();
void register_node_type_cmp_texture_coordinate();
void register_node_type_cmp_tonemap();
void register_node_type_cmp_trackpos();
void register_node_type_cmp_transform();

View File

@ -0,0 +1,55 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup cmpnodes
*/
#include "COM_node_operation.hh"
#include "COM_utilities.hh"
#include "node_composite_util.hh"
/* **************** TEXTURE ******************** */
namespace blender::nodes::node_composite_texture_coordinate_cc {
static void cmp_node_texture_coordinate_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>("Generated");
}
using namespace blender::realtime_compositor;
class TextureCoordinateOperation : public NodeOperation {
public:
using NodeOperation::NodeOperation;
void execute() override {}
Domain compute_domain() override
{
return Domain(context().get_compositing_region_size());
}
};
static NodeOperation *get_compositor_operation(Context &context, DNode node)
{
return new TextureCoordinateOperation(context, node);
}
} // namespace blender::nodes::node_composite_texture_coordinate_cc
void register_node_type_cmp_texture_coordinate()
{
namespace file_ns = blender::nodes::node_composite_texture_coordinate_cc;
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TEXTURE_COORDINATE, "Texture Coordinate", NODE_CLASS_INPUT);
ntype.declare = file_ns::cmp_node_texture_coordinate_declare;
ntype.get_compositor_operation = file_ns::get_compositor_operation;
nodeRegisterType(&ntype);
}

View File

@ -40,8 +40,8 @@ static bool sh_fn_poll_default(const bNodeType * /*ntype*/,
const bNodeTree *ntree,
const char **r_disabled_hint)
{
if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree")) {
*r_disabled_hint = TIP_("Not a shader or geometry node tree");
if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree", "CompositorNodeTree")) {
*r_disabled_hint = TIP_("Not a shader, geometry, or compositor node tree");
return false;
}
return true;