Shading: Rewrite Mapping node with dynamic inputs.

This patch rewrites the Mapping node to support dynamic inputs. The
Max and Min options have been removed. They can be added as Min and
Max Vector Math nodes manually.

Texture nodes still use the old matrix-based mapping. A new SVM node
`NODE_TEXTURE_MAPPING` has been added to preserve this functionality.
Similarly, in GLSL, a `mapping_mat4` function has been added.

Reviewers: brecht, JacquesLucke
This commit is contained in:
OmarSquircleArt 2019-09-04 23:17:13 +02:00
parent f098f6df76
commit baaa89a0bc
Notes: blender-bot 2023-02-14 05:44:22 +01:00
Referenced by commit 3e81c1c1d5, Fix (unreported) crash after new mapping node commit.
Referenced by commit 87d0033ea9, Fix node_shader_utils problems with new mapping node
Referenced by issue #67456, Properties Editor's Tabs Hover Popup
24 changed files with 466 additions and 239 deletions

View File

@ -208,24 +208,6 @@ static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping &b_mapping)
mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z();
}
static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping &b_mapping)
{
if (!b_mapping)
return;
mapping->translation = get_float3(b_mapping.translation());
mapping->rotation = get_float3(b_mapping.rotation());
mapping->scale = get_float3(b_mapping.scale());
mapping->type = (TextureMapping::Type)b_mapping.vector_type();
mapping->use_minmax = b_mapping.use_min() || b_mapping.use_max();
if (b_mapping.use_min())
mapping->min = get_float3(b_mapping.min());
if (b_mapping.use_max())
mapping->max = get_float3(b_mapping.max());
}
static ShaderNode *add_node(Scene *scene,
BL::RenderEngine &b_engine,
BL::BlendData &b_data,
@ -357,9 +339,7 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
BL::ShaderNodeMapping b_mapping_node(b_node);
MappingNode *mapping = new MappingNode();
get_tex_mapping(&mapping->tex_mapping, b_mapping_node);
mapping->type = (NodeMappingType)b_mapping_node.vector_type();
node = mapping;
}
else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {

View File

@ -201,6 +201,7 @@ set(SRC_SVM_HEADERS
svm/svm_magic.h
svm/svm_map_range.h
svm/svm_mapping.h
svm/svm_mapping_util.h
svm/svm_math.h
svm/svm_math_util.h
svm/svm_mix.h

View File

@ -16,17 +16,58 @@
#include "stdosl.h"
shader node_mapping(matrix Matrix = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
point mapping_min = point(0.0, 0.0, 0.0),
point mapping_max = point(0.0, 0.0, 0.0),
int use_minmax = 0,
point safe_divide(point a, point b)
{
return point((b[0] != 0.0) ? a[0] / b[0] : 0.0,
(b[1] != 0.0) ? a[1] / b[1] : 0.0,
(b[2] != 0.0) ? a[2] / b[2] : 0.0);
}
matrix euler_to_mat(point euler)
{
float cx = cos(euler[0]);
float cy = cos(euler[1]);
float cz = cos(euler[2]);
float sx = sin(euler[0]);
float sy = sin(euler[1]);
float sz = sin(euler[2]);
matrix mat = matrix(1.0);
mat[0][0] = cy * cz;
mat[0][1] = cy * sz;
mat[0][2] = -sy;
mat[1][0] = sy * sx * cz - cx * sz;
mat[1][1] = sy * sx * sz + cx * cz;
mat[1][2] = cy * sx;
mat[2][0] = sy * cx * cz + sx * sz;
mat[2][1] = sy * cx * sz - sx * cz;
mat[2][2] = cy * cx;
return mat;
}
shader node_mapping(string type = "point",
point VectorIn = point(0.0, 0.0, 0.0),
point Location = point(0.0, 0.0, 0.0),
point Rotation = point(0.0, 0.0, 0.0),
point Scale = point(1.0, 1.0, 1.0),
output point VectorOut = point(0.0, 0.0, 0.0))
{
point p = transform(Matrix, VectorIn);
if (use_minmax)
p = min(max(mapping_min, p), mapping_max);
VectorOut = p;
if (type == "point") {
VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale)) + Location;
}
else if (type == "texture") {
VectorOut = safe_divide(transform(transpose(euler_to_mat(Rotation)), (VectorIn - Location)),
Scale);
}
else if (type == "vector") {
VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale));
}
else if (type == "normal") {
VectorOut = normalize(transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale)));
}
else {
warning("%s", "Unknown Mapping vector type!");
}
}

View File

@ -162,6 +162,7 @@ CCL_NAMESPACE_END
#include "kernel/svm/svm_color_util.h"
#include "kernel/svm/svm_math_util.h"
#include "kernel/svm/svm_mapping_util.h"
#include "kernel/svm/svm_attribute.h"
#include "kernel/svm/svm_gradient.h"
@ -405,8 +406,11 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
#endif /* NODES_GROUP(NODE_GROUP_LEVEL_1) */
#if NODES_GROUP(NODE_GROUP_LEVEL_2)
case NODE_TEXTURE_MAPPING:
svm_node_texture_mapping(kg, sd, stack, node.y, node.z, &offset);
break;
case NODE_MAPPING:
svm_node_mapping(kg, sd, stack, node.y, node.z, &offset);
svm_node_mapping(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
case NODE_MIN_MAX:
svm_node_min_max(kg, sd, stack, node.y, node.z, &offset);

View File

@ -18,7 +18,33 @@ CCL_NAMESPACE_BEGIN
/* Mapping Node */
ccl_device void svm_node_mapping(
ccl_device void svm_node_mapping(KernelGlobals *kg,
ShaderData *sd,
float *stack,
uint type,
uint inputs_stack_offsets,
uint result_stack_offset,
int *offset)
{
uint vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset;
svm_unpack_node_uchar4(inputs_stack_offsets,
&vector_stack_offset,
&location_stack_offset,
&rotation_stack_offset,
&scale_stack_offset);
float3 vector = stack_load_float3(stack, vector_stack_offset);
float3 location = stack_load_float3(stack, location_stack_offset);
float3 rotation = stack_load_float3(stack, rotation_stack_offset);
float3 scale = stack_load_float3(stack, scale_stack_offset);
float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
stack_store_float3(stack, result_stack_offset, result);
}
/* Texture Mapping */
ccl_device void svm_node_texture_mapping(
KernelGlobals *kg, ShaderData *sd, float *stack, uint vec_offset, uint out_offset, int *offset)
{
float3 v = stack_load_float3(stack, vec_offset);

View File

@ -0,0 +1,39 @@
/*
* Copyright 2011-2014 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
CCL_NAMESPACE_BEGIN
ccl_device float3
svm_mapping(NodeMappingType type, float3 vector, float3 location, float3 rotation, float3 scale)
{
Transform rotationTransform = euler_to_transform(rotation);
switch (type) {
case NODE_MAPPING_TYPE_POINT:
return transform_direction(&rotationTransform, (vector * scale)) + location;
case NODE_MAPPING_TYPE_TEXTURE:
return safe_divide_float3_float3(
transform_direction_transposed(&rotationTransform, (vector - location)), scale);
case NODE_MAPPING_TYPE_VECTOR:
return transform_direction(&rotationTransform, (vector * scale));
case NODE_MAPPING_TYPE_NORMAL:
return safe_normalize(
transform_direction(&rotationTransform, safe_divide_float3_float3(vector, scale)));
default:
return make_float3(0.0f, 0.0f, 0.0f);
}
}
CCL_NAMESPACE_END

View File

@ -140,6 +140,7 @@ typedef enum ShaderNodeType {
NODE_IES,
NODE_MAP_RANGE,
NODE_CLAMP,
NODE_TEXTURE_MAPPING,
NODE_TEX_WHITE_NOISE,
} ShaderNodeType;
@ -299,6 +300,13 @@ typedef enum NodeVectorMathType {
NODE_VECTOR_MATH_MAXIMUM,
} NodeVectorMathType;
typedef enum NodeMappingType {
NODE_MAPPING_TYPE_POINT,
NODE_MAPPING_TYPE_TEXTURE,
NODE_MAPPING_TYPE_VECTOR,
NODE_MAPPING_TYPE_NORMAL
} NodeMappingType;
typedef enum NodeVectorTransformType {
NODE_VECTOR_TRANSFORM_TYPE_VECTOR,
NODE_VECTOR_TRANSFORM_TYPE_POINT,

View File

@ -429,4 +429,21 @@ void ConstantFolder::fold_vector_math(NodeVectorMathType type) const
}
}
void ConstantFolder::fold_mapping(NodeMappingType type) const
{
ShaderInput *vector_in = node->input("Vector");
ShaderInput *location_in = node->input("Location");
ShaderInput *rotation_in = node->input("Rotation");
ShaderInput *scale_in = node->input("Scale");
if (is_zero(scale_in)) {
make_zero();
}
else if ((is_zero(location_in) || type == NODE_MAPPING_TYPE_VECTOR ||
type == NODE_MAPPING_TYPE_NORMAL) &&
is_zero(rotation_in) && is_one(scale_in)) {
try_bypass_or_make_constant(vector_in);
}
}
CCL_NAMESPACE_END

View File

@ -66,6 +66,7 @@ class ConstantFolder {
void fold_mix(NodeMix type, bool clamp) const;
void fold_math(NodeMathType type) const;
void fold_vector_math(NodeVectorMathType type) const;
void fold_mapping(NodeMappingType type) const;
};
CCL_NAMESPACE_END

View File

@ -25,6 +25,7 @@
#include "kernel/svm/svm_color_util.h"
#include "kernel/svm/svm_ramp_util.h"
#include "kernel/svm/svm_math_util.h"
#include "kernel/svm/svm_mapping_util.h"
#include "render/osl.h"
#include "render/constant_fold.h"
@ -149,7 +150,7 @@ bool TextureMapping::skip()
void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_out)
{
compiler.add_node(NODE_MAPPING, offset_in, offset_out);
compiler.add_node(NODE_TEXTURE_MAPPING, offset_in, offset_out);
Transform tfm = compute_transform();
compiler.add_node(tfm.x);
@ -1727,9 +1728,18 @@ NODE_DEFINE(MappingNode)
{
NodeType *type = NodeType::add("mapping", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(MappingNode);
static NodeEnum type_enum;
type_enum.insert("point", NODE_MAPPING_TYPE_POINT);
type_enum.insert("texture", NODE_MAPPING_TYPE_TEXTURE);
type_enum.insert("vector", NODE_MAPPING_TYPE_VECTOR);
type_enum.insert("normal", NODE_MAPPING_TYPE_NORMAL);
SOCKET_ENUM(type, "Type", type_enum, NODE_MAPPING_TYPE_POINT);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_POINT(location, "Location", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_POINT(rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_POINT(scale, "Scale", make_float3(1.0f, 1.0f, 1.0f));
SOCKET_OUT_POINT(vector, "Vector");
return type;
@ -1739,22 +1749,42 @@ MappingNode::MappingNode() : ShaderNode(node_type)
{
}
void MappingNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
folder.make_constant(result);
}
else {
folder.fold_mapping((NodeMappingType)type);
}
}
void MappingNode::compile(SVMCompiler &compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderInput *location_in = input("Location");
ShaderInput *rotation_in = input("Rotation");
ShaderInput *scale_in = input("Scale");
ShaderOutput *vector_out = output("Vector");
tex_mapping.compile(
compiler, compiler.stack_assign(vector_in), compiler.stack_assign(vector_out));
int vector_stack_offset = compiler.stack_assign(vector_in);
int location_stack_offset = compiler.stack_assign(location_in);
int rotation_stack_offset = compiler.stack_assign(rotation_in);
int scale_stack_offset = compiler.stack_assign(scale_in);
int result_stack_offset = compiler.stack_assign(vector_out);
compiler.add_node(
NODE_MAPPING,
type,
compiler.encode_uchar4(
vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset),
result_stack_offset);
}
void MappingNode::compile(OSLCompiler &compiler)
{
compiler.parameter("Matrix", tex_mapping.compute_transform());
compiler.parameter_point("mapping_min", tex_mapping.min);
compiler.parameter_point("mapping_max", tex_mapping.max);
compiler.parameter("use_minmax", tex_mapping.use_minmax);
compiler.parameter(this, "type");
compiler.add(this, "node_mapping");
}

View File

@ -391,9 +391,10 @@ class MappingNode : public ShaderNode {
{
return NODE_GROUP_LEVEL_2;
}
void constant_fold(const ConstantFolder &folder);
float3 vector;
TextureMapping tex_mapping;
float3 vector, location, rotation, scale;
NodeMappingType type;
};
class RGBToBWNode : public ShaderNode {

View File

@ -148,6 +148,32 @@ ccl_device_inline Transform make_transform(float a,
return t;
}
ccl_device_inline Transform euler_to_transform(const float3 euler)
{
float cx = cosf(euler.x);
float cy = cosf(euler.y);
float cz = cosf(euler.z);
float sx = sinf(euler.x);
float sy = sinf(euler.y);
float sz = sinf(euler.z);
Transform t;
t.x.x = cy * cz;
t.y.x = cy * sz;
t.z.x = -sy;
t.x.y = sy * sx * cz - cx * sz;
t.y.y = sy * sx * sz + cx * cz;
t.z.y = cy * sx;
t.x.z = sy * cx * cz + sx * sz;
t.y.z = sy * cx * sz - sx * cz;
t.z.z = cy * cx;
t.x.w = t.y.w = t.z.w = 0.0f;
return t;
}
/* Constructs a coordinate frame from a normalized normal. */
ccl_device_inline Transform make_transform_frame(float3 N)
{

View File

@ -27,7 +27,7 @@
* \note Use #STRINGIFY() rather than defining with quotes.
*/
#define BLENDER_VERSION 281
#define BLENDER_SUBVERSION 7
#define BLENDER_SUBVERSION 8
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0

View File

@ -34,12 +34,16 @@
#include "DNA_node_types.h"
#include "DNA_particle_types.h"
#include "DNA_camera_types.h"
#include "DNA_anim_types.h"
#include "BKE_colortools.h"
#include "BKE_animsys.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "MEM_guardedalloc.h"
#include "IMB_colormanagement.h"
#include "BLO_readfile.h"
@ -769,6 +773,141 @@ static void update_noise_node_dimensions(bNodeTree *ntree)
}
}
/* The Mapping node has been rewritten to support dynamic inputs. Previously,
* the transformation information was stored in a TexMapping struct in the
* node->storage member of bNode. Currently, the transformation information
* is stored in input sockets. To correct this, we transfer the information
* from the TexMapping struct to the input sockets.
*
* Additionally, the Minimum and Maximum properties are no longer available
* in the node. To correct this, a Vector Minimum and/or a Vector Maximum
* nodes are added if needed.
*
* Finally, the TexMapping struct is freed and node->storage is set to NULL.
*
* Since the RNA paths of the properties changed, we also have to update the
* rna_path of the FCurves if they exist. To do that, we loop over FCurves
* and check if they control a property of the node, if they do, we update
* the path to be that of the corrsponding socket in the node or the added
* minimum/maximum node.
*
*/
static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
{
bool need_update = false;
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_MAPPING) {
TexMapping *mapping = (TexMapping *)node->storage;
node->custom1 = mapping->type;
node->width = 140.0f;
bNodeSocket *sockLocation = nodeFindSocket(node, SOCK_IN, "Location");
copy_v3_v3(cycles_node_socket_vector_value(sockLocation), mapping->loc);
bNodeSocket *sockRotation = nodeFindSocket(node, SOCK_IN, "Rotation");
copy_v3_v3(cycles_node_socket_vector_value(sockRotation), mapping->rot);
bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
copy_v3_v3(cycles_node_socket_vector_value(sockScale), mapping->size);
bNode *maximumNode = NULL;
if (mapping->flag & TEXMAP_CLIP_MAX) {
maximumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
maximumNode->custom1 = NODE_VECTOR_MATH_MAXIMUM;
if (mapping->flag & TEXMAP_CLIP_MIN) {
maximumNode->locx = node->locx + (node->width + 20.0f) * 2.0f;
}
else {
maximumNode->locx = node->locx + node->width + 20.0f;
}
maximumNode->locy = node->locy;
bNodeSocket *sockMaximumB = BLI_findlink(&maximumNode->inputs, 1);
copy_v3_v3(cycles_node_socket_vector_value(sockMaximumB), mapping->max);
bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sockMappingResult) {
bNodeSocket *sockMaximumResult = nodeFindSocket(maximumNode, SOCK_OUT, "Vector");
nodeAddLink(ntree, maximumNode, sockMaximumResult, link->tonode, link->tosock);
nodeRemLink(ntree, link);
}
}
if (!(mapping->flag & TEXMAP_CLIP_MIN)) {
bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0);
nodeAddLink(ntree, node, sockMappingResult, maximumNode, sockMaximumA);
}
need_update = true;
}
bNode *minimumNode = NULL;
if (mapping->flag & TEXMAP_CLIP_MIN) {
minimumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
minimumNode->custom1 = NODE_VECTOR_MATH_MINIMUM;
minimumNode->locx = node->locx + node->width + 20.0f;
minimumNode->locy = node->locy;
bNodeSocket *sockMinimumB = BLI_findlink(&minimumNode->inputs, 1);
copy_v3_v3(cycles_node_socket_vector_value(sockMinimumB), mapping->min);
bNodeSocket *sockMinimumResult = nodeFindSocket(minimumNode, SOCK_OUT, "Vector");
bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
if (maximumNode) {
bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0);
nodeAddLink(ntree, minimumNode, sockMinimumResult, maximumNode, sockMaximumA);
}
else {
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sockMappingResult) {
nodeAddLink(ntree, minimumNode, sockMinimumResult, link->tonode, link->tosock);
nodeRemLink(ntree, link);
}
}
}
bNodeSocket *sockMinimumA = BLI_findlink(&minimumNode->inputs, 0);
nodeAddLink(ntree, node, sockMappingResult, minimumNode, sockMinimumA);
need_update = true;
}
MEM_freeN(node->storage);
node->storage = NULL;
AnimData *animData = BKE_animdata_from_id(&ntree->id);
if (animData && animData->action) {
const char *nodePath = BLI_sprintfN("nodes[\"%s\"]", node->name);
for (FCurve *fcu = animData->action->curves.first; fcu; fcu = fcu->next) {
if (STRPREFIX(fcu->rna_path, nodePath) &&
!BLI_str_endswith(fcu->rna_path, "default_value")) {
MEM_freeN(fcu->rna_path);
if (BLI_str_endswith(fcu->rna_path, "translation")) {
fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[1].default_value");
}
else if (BLI_str_endswith(fcu->rna_path, "rotation")) {
fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[2].default_value");
}
else if (BLI_str_endswith(fcu->rna_path, "scale")) {
fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[3].default_value");
}
else if (minimumNode && BLI_str_endswith(fcu->rna_path, "min")) {
fcu->rna_path = BLI_sprintfN(
"nodes[\"%s\"].%s", minimumNode->name, "inputs[1].default_value");
}
else if (maximumNode && BLI_str_endswith(fcu->rna_path, "max")) {
fcu->rna_path = BLI_sprintfN(
"nodes[\"%s\"].%s", maximumNode->name, "inputs[1].default_value");
}
}
}
}
}
}
if (need_update) {
ntreeUpdateTree(NULL, ntree);
}
}
void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
{
/* Particle shape shared with Eevee. */
@ -950,4 +1089,13 @@ void do_versions_after_linking_cycles(Main *bmain)
}
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 281, 8)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
update_mapping_node_inputs_and_properties(ntree);
}
}
FOREACH_NODETREE_END;
}
}

View File

@ -731,37 +731,7 @@ static void node_buts_image_user(uiLayout *layout,
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *row, *col, *sub;
uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, false);
col = uiLayoutColumn(row, true);
uiItemL(col, IFACE_("Location:"), ICON_NONE);
uiItemR(col, ptr, "translation", 0, "", ICON_NONE);
col = uiLayoutColumn(row, true);
uiItemL(col, IFACE_("Rotation:"), ICON_NONE);
uiItemR(col, ptr, "rotation", 0, "", ICON_NONE);
col = uiLayoutColumn(row, true);
uiItemL(col, IFACE_("Scale:"), ICON_NONE);
uiItemR(col, ptr, "scale", 0, "", ICON_NONE);
row = uiLayoutRow(layout, false);
col = uiLayoutColumn(row, true);
uiItemR(col, ptr, "use_min", 0, IFACE_("Min"), ICON_NONE);
sub = uiLayoutColumn(col, true);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
col = uiLayoutColumn(row, true);
uiItemR(col, ptr, "use_max", 0, IFACE_("Max"), ICON_NONE);
sub = uiLayoutColumn(col, true);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE);
}
static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)

View File

@ -318,7 +318,7 @@ static GPUMaterialLibrary gpu_shader_material_light_path_library = {
static GPUMaterialLibrary gpu_shader_material_mapping_library = {
.code = datatoc_gpu_shader_material_mapping_glsl,
.dependencies = {NULL},
.dependencies = {&gpu_shader_material_math_util_library, NULL},
};
static GPUMaterialLibrary gpu_shader_material_map_range_library = {

View File

@ -1,7 +1,27 @@
void mapping(
void mapping_mat4(
vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
{
mat4 mat = mat4(m0, m1, m2, m3);
outvec = (mat * vec4(vec, 1.0)).xyz;
outvec = clamp(outvec, minvec, maxvec);
}
void mapping_point(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
{
result = (euler_to_mat3(rotation) * (vector * scale)) + location;
}
void mapping_texture(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
{
result = safe_divide(transpose(euler_to_mat3(rotation)) * (vector - location), scale);
}
void mapping_vector(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
{
result = euler_to_mat3(rotation) * (vector * scale);
}
void mapping_normal(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
{
result = normalize(euler_to_mat3(rotation) * safe_divide(vector, scale));
}

View File

@ -85,6 +85,30 @@ void vector_normalize(vec3 normal, out vec3 outnormal)
/* Matirx Math */
mat3 euler_to_mat3(vec3 euler)
{
float cx = cos(euler.x);
float cy = cos(euler.y);
float cz = cos(euler.z);
float sx = sin(euler.x);
float sy = sin(euler.y);
float sz = sin(euler.z);
mat3 mat;
mat[0][0] = cy * cz;
mat[0][1] = cy * sz;
mat[0][2] = -sy;
mat[1][0] = sy * sx * cz - cx * sz;
mat[1][1] = sy * sx * sz + cx * cz;
mat[1][2] = cy * sx;
mat[2][0] = sy * cx * cz + sx * sz;
mat[2][1] = sy * cx * sz - sx * cz;
mat[2][2] = cy * cx;
return mat;
}
void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
{
vout = (mat * vec4(vin, 0.0)).xyz;

View File

@ -1169,6 +1169,14 @@ typedef struct NodeDenoise {
#define SHD_AO_INSIDE 1
#define SHD_AO_LOCAL 2
/* Mapping node vector types */
enum {
NODE_MAPPING_TYPE_POINT = 0,
NODE_MAPPING_TYPE_TEXTURE = 1,
NODE_MAPPING_TYPE_VECTOR = 2,
NODE_MAPPING_TYPE_NORMAL = 3,
};
/* math node clamp */
#define SHD_MATH_CLAMP 1

View File

@ -184,6 +184,7 @@ extern const EnumPropertyItem rna_enum_file_sort_items[];
extern const EnumPropertyItem rna_enum_node_socket_in_out_items[];
extern const EnumPropertyItem rna_enum_node_math_items[];
extern const EnumPropertyItem rna_enum_mapping_type_items[];
extern const EnumPropertyItem rna_enum_node_vec_math_items[];
extern const EnumPropertyItem rna_enum_node_filter_items[];

View File

@ -102,6 +102,26 @@ static const EnumPropertyItem node_chunksize_items[] = {
};
#endif
const EnumPropertyItem rna_enum_mapping_type_items[] = {
{NODE_MAPPING_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
{NODE_MAPPING_TYPE_TEXTURE,
"TEXTURE",
0,
"Texture",
"Transform a texture by inverse mapping the texture coordinate"},
{NODE_MAPPING_TYPE_VECTOR,
"VECTOR",
0,
"Vector",
"Transform a direction vector. Location is ignored"},
{NODE_MAPPING_TYPE_NORMAL,
"NORMAL",
0,
"Normal",
"Transform a unit normal vector. Location is ignored"},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_math_items[] = {
{NODE_MATH_ADD, "ADD", 0, "Add", "A + B"},
{NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
@ -3213,13 +3233,6 @@ static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene),
nodeUpdate(ntree, node); /* to update image node sockets */
}
static void rna_Mapping_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNode *node = ptr->data;
BKE_texture_mapping_init(node->storage);
rna_Node_update(bmain, scene, ptr);
}
static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
bNode *node = ptr->data;
@ -4034,68 +4047,13 @@ static void def_sh_output_linestyle(StructRNA *srna)
static void def_sh_mapping(StructRNA *srna)
{
static const EnumPropertyItem prop_vect_type_items[] = {
{TEXMAP_TYPE_TEXTURE,
"TEXTURE",
0,
"Texture",
"Transform a texture by inverse mapping the texture coordinate"},
{TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
{TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
{TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
{0, NULL, 0, NULL, NULL},
};
static float default_1[3] = {1.f, 1.f, 1.f};
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "TexMapping", "storage");
prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, prop_vect_type_items);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "loc");
RNA_def_property_ui_text(prop, "Location", "");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
/* Not PROP_XYZ, this is now in radians, no more degrees */
prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "rot");
RNA_def_property_ui_text(prop, "Rotation", "");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_text(prop, "Scale", "");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "min");
RNA_def_property_ui_text(prop, "Minimum", "Minimum value for clipping");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "max");
RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_ui_text(prop, "Maximum", "Maximum value for clipping");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
prop = RNA_def_property(srna, "use_min", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MIN);
RNA_def_property_ui_text(prop, "Has Minimum", "Whether to use minimum clipping value");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
prop = RNA_def_property(srna, "use_max", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MAX);
RNA_def_property_ui_text(prop, "Has Maximum", "Whether to use maximum clipping value");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_sh_attribute(StructRNA *srna)

View File

@ -465,18 +465,6 @@ static void rna_def_texmapping(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem prop_vect_type_items[] = {
{TEXMAP_TYPE_TEXTURE,
"TEXTURE",
0,
"Texture",
"Transform a texture by inverse mapping the texture coordinate"},
{TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
{TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
{TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem prop_xyz_mapping_items[] = {
{0, "NONE", 0, "None", ""},
{1, "X", 0, "X", ""},
@ -493,7 +481,7 @@ static void rna_def_texmapping(BlenderRNA *brna)
prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, prop_vect_type_items);
RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
RNA_def_property_update(prop, 0, "rna_Texture_mapping_update");

View File

@ -280,7 +280,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
tmat2 = GPU_uniform((float *)texmap->mat[2]);
tmat3 = GPU_uniform((float *)texmap->mat[3]);
GPU_link(mat, "mapping", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
GPU_link(mat, "mapping_mat4", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
if (texmap->type == TEXMAP_TYPE_NORMAL) {
GPU_link(mat, "vector_normalize", in[0].link, &in[0].link);

View File

@ -25,7 +25,10 @@
/* **************** MAPPING ******************** */
static bNodeSocketTemplate sh_node_mapping_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
{SOCK_VECTOR, 1, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, 1, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{SOCK_VECTOR, 1, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
{-1, 0, ""},
};
@ -34,91 +37,27 @@ static bNodeSocketTemplate sh_node_mapping_out[] = {
{-1, 0, ""},
};
static void *node_shader_initexec_mapping(bNodeExecContext *UNUSED(context),
bNode *node,
bNodeInstanceKey UNUSED(key))
{
TexMapping *texmap = node->storage;
BKE_texture_mapping_init(texmap);
return NULL;
}
/* do the regular mapping options for blender textures */
static void node_shader_exec_mapping(void *UNUSED(data),
int UNUSED(thread),
bNode *node,
bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **out)
{
TexMapping *texmap = node->storage;
float *vec = out[0]->vec;
/* stack order input: vector */
/* stack order output: vector */
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
mul_m4_v3(texmap->mat, vec);
if (texmap->flag & TEXMAP_CLIP_MIN) {
if (vec[0] < texmap->min[0]) {
vec[0] = texmap->min[0];
}
if (vec[1] < texmap->min[1]) {
vec[1] = texmap->min[1];
}
if (vec[2] < texmap->min[2]) {
vec[2] = texmap->min[2];
}
}
if (texmap->flag & TEXMAP_CLIP_MAX) {
if (vec[0] > texmap->max[0]) {
vec[0] = texmap->max[0];
}
if (vec[1] > texmap->max[1]) {
vec[1] = texmap->max[1];
}
if (vec[2] > texmap->max[2]) {
vec[2] = texmap->max[2];
}
}
if (texmap->type == TEXMAP_TYPE_NORMAL) {
normalize_v3(vec);
}
}
static void node_shader_init_mapping(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
}
static int gpu_shader_mapping(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
TexMapping *texmap = node->storage;
float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
static float max[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
static const char *names[] = {
[NODE_MAPPING_TYPE_POINT] = "mapping_point",
[NODE_MAPPING_TYPE_TEXTURE] = "mapping_texture",
[NODE_MAPPING_TYPE_VECTOR] = "mapping_vector",
[NODE_MAPPING_TYPE_NORMAL] = "mapping_normal",
};
tmin = GPU_uniform((domin) ? texmap->min : min);
tmax = GPU_uniform((domax) ? texmap->max : max);
tmat0 = GPU_uniform((float *)texmap->mat[0]);
tmat1 = GPU_uniform((float *)texmap->mat[1]);
tmat2 = GPU_uniform((float *)texmap->mat[2]);
tmat3 = GPU_uniform((float *)texmap->mat[3]);
return GPU_stack_link(mat, node, names[node->custom1], in, out);
}
GPU_stack_link(mat, node, "mapping", in, out, tmat0, tmat1, tmat2, tmat3, tmin, tmax);
if (texmap->type == TEXMAP_TYPE_NORMAL) {
GPU_link(mat, "vector_normalize", out[0].link, &out[0].link);
}
return true;
static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node)
{
bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location");
nodeSetSocketAvailability(
sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
}
void register_node_type_sh_mapping(void)
@ -127,11 +66,8 @@ void register_node_type_sh_mapping(void)
sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
node_type_size(&ntype, 320, 160, 360);
node_type_init(&ntype, node_shader_init_mapping);
node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, node_shader_initexec_mapping, NULL, node_shader_exec_mapping);
node_type_gpu(&ntype, gpu_shader_mapping);
node_type_update(&ntype, node_shader_update_mapping);
nodeRegisterType(&ntype);
}