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:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2018-07-18 15:13:02 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2018-07-18 15:13:16 +0300
commit3d67819a1709e35b2fb42a9d554b30136a72eec9 (patch)
treeda74b41c52fab9592ee12e3db0c046bf70d85d5a /source/blender
parent257d072317f21861cdb7c168a60497bcb74d73d4 (diff)
parent5078b9d2d08a34ae3786100c2301ea960165e7f2 (diff)
Merge branch 'master' into blender2.8
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_node.h8
-rw-r--r--source/blender/blenkernel/intern/node.c2
-rw-r--r--source/blender/blenlib/BLI_hash_mm3.h40
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/hash_mm3.c147
-rw-r--r--source/blender/blenloader/intern/readfile.c4
-rw-r--r--source/blender/blenloader/intern/writefile.c7
-rw-r--r--source/blender/compositor/CMakeLists.txt5
-rw-r--r--source/blender/compositor/intern/COM_Converter.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cpp121
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.h38
-rw-r--r--source/blender/compositor/operations/COM_CryptomatteOperation.cpp75
-rw-r--r--source/blender/compositor/operations/COM_CryptomatteOperation.h40
-rw-r--r--source/blender/editors/include/UI_interface.h1
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c1
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c89
-rw-r--r--source/blender/editors/interface/interface_intern.h1
-rw-r--r--source/blender/editors/interface/interface_ops.c1
-rw-r--r--source/blender/editors/interface/interface_templates.c18
-rw-r--r--source/blender/editors/space_node/drawnode.c31
-rw-r--r--source/blender/editors/space_node/node_edit.c90
-rw-r--r--source/blender/editors/space_node/node_intern.h2
-rw-r--r--source/blender/editors/space_node/node_ops.c3
-rw-r--r--source/blender/makesdna/DNA_node_types.h13
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c90
-rw-r--r--source/blender/nodes/CMakeLists.txt2
-rw-r--r--source/blender/nodes/NOD_composite.h1
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.c302
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c132
31 files changed, 1231 insertions, 42 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index e72c6c14bfb..cf55885a5ef 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -796,6 +796,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, c
#define SH_NODE_DISPLACEMENT 198
#define SH_NODE_VECTOR_DISPLACEMENT 199
#define SH_NODE_VOLUME_PRINCIPLED 200
+/* 201..700 occupied by other node types, continue from 701 */
+#define SH_NODE_BSDF_HAIR_PRINCIPLED 701
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
@@ -944,6 +946,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_NODE_PLANETRACKDEFORM 320
#define CMP_NODE_CORNERPIN 321
#define CMP_NODE_SWITCH_VIEW 322
+#define CMP_NODE_CRYPTOMATTE 323
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -996,6 +999,11 @@ void ntreeCompositOutputFileUniqueLayer(struct ListBase *list, struct bNodeSocke
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
+void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *ntree, bNode *node);
+void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *ntree, bNode *node);
+struct bNodeSocket *ntreeCompositCryptomatteAddSocket(struct bNodeTree *ntree, struct bNode *node);
+int ntreeCompositCryptomatteRemoveSocket(struct bNodeTree *ntree, struct bNode *node);
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 7aa0ecdad87..c81f5f425d8 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -3432,6 +3432,7 @@ static void registerCompositNodes(void)
register_node_type_cmp_doubleedgemask();
register_node_type_cmp_keyingscreen();
register_node_type_cmp_keying();
+ register_node_type_cmp_cryptomatte();
register_node_type_cmp_translate();
register_node_type_cmp_rotate();
@@ -3520,6 +3521,7 @@ static void registerShaderNodes(void)
register_node_type_sh_bsdf_velvet();
register_node_type_sh_bsdf_toon();
register_node_type_sh_bsdf_hair();
+ register_node_type_sh_bsdf_hair_principled();
register_node_type_sh_emission();
register_node_type_sh_holdout();
register_node_type_sh_volume_absorption();
diff --git a/source/blender/blenlib/BLI_hash_mm3.h b/source/blender/blenlib/BLI_hash_mm3.h
new file mode 100644
index 00000000000..93bf963c9a4
--- /dev/null
+++ b/source/blender/blenlib/BLI_hash_mm3.h
@@ -0,0 +1,40 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_HASH_MM3_H__
+#define __BLI_HASH_MM3_H__
+
+/** \file BLI_hash_mm3.h
+ * \ingroup bli
+ */
+
+#include "BLI_sys_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint32_t BLI_hash_mm3(const unsigned char *data, size_t len, uint32_t seed);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_HASH_MM2A_H__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 61f53f938e2..9621a759f3c 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -74,6 +74,7 @@ set(SRC
intern/gsqueue.c
intern/hash_md5.c
intern/hash_mm2a.c
+ intern/hash_mm3.c
intern/jitter_2d.c
intern/lasso_2d.c
intern/list_sort_impl.h
@@ -158,6 +159,7 @@ set(SRC
BLI_hash.h
BLI_hash_md5.h
BLI_hash_mm2a.h
+ BLI_hash_mm3.h
BLI_heap.h
BLI_iterator.h
BLI_jitter_2d.h
diff --git a/source/blender/blenlib/intern/hash_mm3.c b/source/blender/blenlib/intern/hash_mm3.c
new file mode 100644
index 00000000000..5ead9ceca63
--- /dev/null
+++ b/source/blender/blenlib/intern/hash_mm3.c
@@ -0,0 +1,147 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Copyright (C) 2018 Blender Foundation.
+ *
+ */
+
+/** \file blender/blenlib/intern/hash_mm3.c
+ * \ingroup bli
+ *
+ * Functions to compute Murmur3 hash key.
+ *
+ * This Code is based on alShaders/Cryptomatte/MurmurHash3.h:
+ *
+ * MurmurHash3 was written by Austin Appleby, and is placed in the public
+ * domain. The author hereby disclaims copyright to this source code.
+ *
+ */
+
+#include "BLI_compiler_compat.h"
+#include "BLI_compiler_attrs.h"
+#include "BLI_hash_mm3.h" /* own include */
+
+#if defined(_MSC_VER)
+# include <stdlib.h>
+# define ROTL32(x,y) _rotl(x,y)
+# define BIG_CONSTANT(x) (x)
+
+/* Other compilers */
+#else /* defined(_MSC_VER) */
+static inline uint32_t rotl32(uint32_t x, int8_t r)
+{
+ return (x << r) | (x >> (32 - r));
+}
+# define ROTL32(x,y) rotl32(x,y)
+# define BIG_CONSTANT(x) (x##LLU)
+#endif /* !defined(_MSC_VER) */
+
+/* Block read - if your platform needs to do endian-swapping or can only
+ * handle aligned reads, do the conversion here
+ */
+
+BLI_INLINE uint32_t getblock32(const uint32_t * p, int i)
+{
+ return p[i];
+}
+
+BLI_INLINE uint64_t getblock64(const uint64_t * p, int i)
+{
+ return p[i];
+}
+
+/* Finalization mix - force all bits of a hash block to avalanche */
+
+BLI_INLINE uint32_t fmix32(uint32_t h)
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+
+ return h;
+}
+
+BLI_INLINE uint64_t fmix64(uint64_t k)
+{
+ k ^= k >> 33;
+ k *= BIG_CONSTANT(0xff51afd7ed558ccd);
+ k ^= k >> 33;
+ k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
+ k ^= k >> 33;
+
+ return k;
+}
+
+uint32_t BLI_hash_mm3(const unsigned char *in, size_t len, uint32_t seed)
+{
+ const uint8_t *data = (const uint8_t*)in;
+ const int nblocks = len / 4;
+
+ uint32_t h1 = seed;
+
+ const uint32_t c1 = 0xcc9e2d51;
+ const uint32_t c2 = 0x1b873593;
+
+ /* body */
+
+ const uint32_t *blocks = (const uint32_t *)(data + nblocks*4);
+
+ for (int i = -nblocks; i; i++) {
+ uint32_t k1 = getblock32(blocks,i);
+
+ k1 *= c1;
+ k1 = ROTL32(k1,15);
+ k1 *= c2;
+
+ h1 ^= k1;
+ h1 = ROTL32(h1,13);
+ h1 = h1*5+0xe6546b64;
+ }
+
+ /* tail */
+
+ const uint8_t *tail = (const uint8_t*)(data + nblocks*4);
+
+ uint32_t k1 = 0;
+
+ switch (len & 3) {
+ case 3:
+ k1 ^= tail[2] << 16;
+ ATTR_FALLTHROUGH;
+ case 2:
+ k1 ^= tail[1] << 8;
+ ATTR_FALLTHROUGH;
+ case 1:
+ k1 ^= tail[0];
+ k1 *= c1;
+ k1 = ROTL32(k1,15);
+ k1 *= c2;
+ h1 ^= k1;
+ };
+
+ /* finalization */
+
+ h1 ^= len;
+
+ h1 = fmix32(h1);
+
+ return h1;
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index ab94b5334bd..b878932e3dd 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3343,6 +3343,10 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
direct_link_curvemapping(fd, node->storage);
else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
((ImageUser *)node->storage)->ok = 1;
+ else if (node->type==CMP_NODE_CRYPTOMATTE) {
+ NodeCryptomatte *nc = (NodeCryptomatte *) node->storage;
+ nc->matte_id = newdataadr(fd, nc->matte_id);
+ }
}
else if ( ntree->type==NTREE_TEXTURE) {
if (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME)
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index a215b013b2a..552f5420e8d 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1103,6 +1103,13 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree)
}
writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
+ else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) {
+ NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
+ if (nc->matte_id) {
+ writedata(wd, DATA, strlen(nc->matte_id) + 1, nc->matte_id);
+ }
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ }
else {
writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index a141495e5ae..261a1218d2d 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -183,6 +183,11 @@ set(SRC
operations/COM_SunBeamsOperation.cpp
operations/COM_SunBeamsOperation.h
+ nodes/COM_CryptomatteNode.cpp
+ nodes/COM_CryptomatteNode.h
+ operations/COM_CryptomatteOperation.cpp
+ operations/COM_CryptomatteOperation.h
+
nodes/COM_CornerPinNode.cpp
nodes/COM_CornerPinNode.h
nodes/COM_PlaneTrackDeformNode.cpp
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp
index 58e0da04e5e..c9181905908 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cpp
@@ -55,6 +55,7 @@ extern "C" {
#include "COM_Converter.h"
#include "COM_CornerPinNode.h"
#include "COM_CropNode.h"
+#include "COM_CryptomatteNode.h"
#include "COM_DefocusNode.h"
#include "COM_DespeckleNode.h"
#include "COM_DifferenceMatteNode.h"
@@ -406,6 +407,9 @@ Node *Converter::convert(bNode *b_node)
case CMP_NODE_SUNBEAMS:
node = new SunBeamsNode(b_node);
break;
+ case CMP_NODE_CRYPTOMATTE:
+ node = new CryptomatteNode(b_node);
+ break;
}
return node;
}
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
new file mode 100644
index 00000000000..bc115e66c20
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Lukas Stockner
+ * Stefan Werner
+ */
+
+#include "COM_CryptomatteNode.h"
+#include "COM_CryptomatteOperation.h"
+#include "COM_SetAlphaOperation.h"
+#include "COM_ConvertOperation.h"
+#include "BLI_string.h"
+#include "BLI_hash_mm3.h"
+#include "BLI_assert.h"
+#include <iterator>
+
+CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode)
+{
+ /* pass */
+}
+
+/* This is taken from the Cryptomatte specification 1.0. */
+static inline float hash_to_float(uint32_t hash)
+{
+ uint32_t mantissa = hash & (( 1 << 23) - 1);
+ uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
+ exponent = max(exponent, (uint32_t) 1);
+ exponent = min(exponent, (uint32_t) 254);
+ exponent = exponent << 23;
+ uint32_t sign = (hash >> 31);
+ sign = sign << 31;
+ uint32_t float_bits = sign | exponent | mantissa;
+ float f;
+ /* Bit casting relies on equal size for both types. */
+ BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float and uint32_t are not the same size")
+ ::memcpy(&f, &float_bits, sizeof(float));
+ return f;
+}
+
+void CryptomatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
+{
+ NodeInput *inputSocketImage = this->getInputSocket(0);
+ NodeOutput *outputSocketImage = this->getOutputSocket(0);
+ NodeOutput *outputSocketMatte = this->getOutputSocket(1);
+ NodeOutput *outputSocketPick = this->getOutputSocket(2);
+
+ bNode *node = this->getbNode();
+ NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage;
+
+ CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets()-1);
+ if (cryptoMatteSettings) {
+ if (cryptoMatteSettings->matte_id) {
+ /* Split the string by commas, ignoring white space. */
+ std::string input = cryptoMatteSettings->matte_id;
+ std::istringstream ss(input);
+ while (ss.good()) {
+ std::string token;
+ getline(ss, token, ',');
+ /* Ignore empty tokens. */
+ if (token.length() > 0) {
+ size_t first = token.find_first_not_of(' ');
+ size_t last = token.find_last_not_of(' ');
+ if (first == std::string::npos || last == std::string::npos) {
+ break;
+ }
+ token = token.substr(first, (last - first + 1));
+ if (*token.begin() == '<' && *(--token.end()) == '>') {
+ operation->addObjectIndex(atof(token.substr(1, token.length() - 2).c_str()));
+ }
+ else {
+ uint32_t hash = BLI_hash_mm3((const unsigned char*)token.c_str(), token.length(), 0);
+ operation->addObjectIndex(hash_to_float(hash));
+ }
+ }
+ }
+ }
+ }
+
+ converter.addOperation(operation);
+
+ for (int i = 0; i < getNumberOfInputSockets()-1; ++i) {
+ converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
+ }
+
+ SeparateChannelOperation *separateOperation = new SeparateChannelOperation;
+ separateOperation->setChannel(3);
+ converter.addOperation(separateOperation);
+
+ SetAlphaOperation *operationAlpha = new SetAlphaOperation();
+ converter.addOperation(operationAlpha);
+
+ converter.addLink(operation->getOutputSocket(0), separateOperation->getInputSocket(0));
+ converter.addLink(separateOperation->getOutputSocket(0), operationAlpha->getInputSocket(1));
+
+ SetAlphaOperation *clearAlphaOperation = new SetAlphaOperation();
+ converter.addOperation(clearAlphaOperation);
+ converter.addInputValue(clearAlphaOperation->getInputSocket(1), 1.0f);
+
+ converter.addLink(operation->getOutputSocket(0), clearAlphaOperation->getInputSocket(0));
+
+ converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
+ converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0));
+ converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0));
+ converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0));
+
+}
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.h b/source/blender/compositor/nodes/COM_CryptomatteNode.h
new file mode 100644
index 00000000000..5251b57d8af
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Lukas Stockner
+ */
+
+#ifndef _COM_CryptomatteNode_h_
+#define _COM_CryptomatteNode_h_
+
+#include "COM_Node.h"
+
+/**
+ * @brief CryptomatteNode
+ * @ingroup Node
+ */
+class CryptomatteNode : public Node {
+public:
+ CryptomatteNode(bNode *editorNode);
+ void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+};
+
+#endif
+
diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp b/source/blender/compositor/operations/COM_CryptomatteOperation.cpp
new file mode 100644
index 00000000000..9dd36863d37
--- /dev/null
+++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor: Lukas Stockner, Stefan Werner
+ */
+
+#include "COM_CryptomatteOperation.h"
+
+CryptomatteOperation::CryptomatteOperation(size_t num_inputs) : NodeOperation()
+{
+ for(size_t i = 0; i < num_inputs; i++) {
+ this->addInputSocket(COM_DT_COLOR);
+ }
+ inputs.resize(num_inputs);
+ this->addOutputSocket(COM_DT_COLOR);
+ this->setComplex(true);
+}
+
+void CryptomatteOperation::initExecution()
+{
+ for (size_t i = 0; i < inputs.size(); i++) {
+ inputs[i] = this->getInputSocketReader(i);
+ }
+}
+
+void CryptomatteOperation::addObjectIndex(float objectIndex)
+{
+ if (objectIndex != 0.0f) {
+ m_objectIndex.push_back(objectIndex);
+ }
+}
+
+void CryptomatteOperation::executePixel(float output[4],
+ int x,
+ int y,
+ void *data)
+{
+ float input[4];
+ output[0] = output[1] = output[2] = output[3] = 0.0f;
+ for (size_t i = 0; i < inputs.size(); i++) {
+ inputs[i]->read(input, x, y, data);
+ if (i == 0) {
+ /* Write the frontmost object as false color for picking. */
+ output[0] = input[0];
+ uint32_t m3hash;
+ ::memcpy(&m3hash, &input[0], sizeof(uint32_t));
+ /* Since the red channel is likely to be out of display range,
+ * setting green and blue gives more meaningful images. */
+ output[1] = ((float) ((m3hash << 8)) / (float) UINT32_MAX);
+ output[2] = ((float) ((m3hash << 16)) / (float) UINT32_MAX);
+ }
+ for(size_t i = 0; i < m_objectIndex.size(); i++) {
+ if (m_objectIndex[i] == input[0]) {
+ output[3] += input[1];
+ }
+ if (m_objectIndex[i] == input[2]) {
+ output[3] += input[3];
+ }
+ }
+ }
+}
diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.h b/source/blender/compositor/operations/COM_CryptomatteOperation.h
new file mode 100644
index 00000000000..9ce02c048b3
--- /dev/null
+++ b/source/blender/compositor/operations/COM_CryptomatteOperation.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor: Lukas Stockner, Stefan Werner
+ */
+
+#ifndef _COM_CryptomatteOperation_h
+#define _COM_CryptomatteOperation_h
+#include "COM_NodeOperation.h"
+
+
+class CryptomatteOperation : public NodeOperation {
+private:
+ std::vector<float> m_objectIndex;
+public:
+ std::vector<SocketReader *> inputs;
+
+ CryptomatteOperation(size_t num_inputs = 6);
+
+ void initExecution();
+ void executePixel(float output[4], int x, int y, void *data);
+
+ void addObjectIndex(float objectIndex);
+
+};
+#endif
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 07259b91b86..087e0c4ab7b 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1069,6 +1069,7 @@ void uiTemplateCurveMapping(
bool levels, bool brush, bool neg_slope);
void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool value_slider, bool lock, bool lock_luminosity, bool cubic);
void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool color);
+void uiTemplateCryptoPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateLayers(
uiLayout *layout, struct PointerRNA *ptr, const char *propname,
PointerRNA *used_ptr, const char *used_propname, int active_layer);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index eb8fff471e2..424019995ad 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -82,6 +82,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
/* assign to operators */
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color_crypto");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 73efc59feb7..ff8aa56f0d5 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -36,6 +36,7 @@
#include "DNA_screen_types.h"
#include "BLI_math_vector.h"
+#include "BLI_string.h"
#include "BKE_context.h"
#include "BKE_main.h"
@@ -72,6 +73,8 @@ typedef struct Eyedropper {
bool accum_start; /* has mouse been pressed */
float accum_col[3];
int accum_tot;
+
+ bool accumulate; /* Color picking for cryptomatte, without accumulation. */
} Eyedropper;
static bool eyedropper_init(bContext *C, wmOperator *op)
@@ -80,6 +83,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
Eyedropper *eye;
op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
+ eye->accumulate = !STREQ(op->type->idname, "UI_OT_eyedropper_color_crypto");
UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
@@ -207,29 +211,30 @@ static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3
RNA_property_update(C, &eye->ptr, eye->prop);
}
-/* set sample from accumulated values */
-static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye)
-{
- float col[3];
- mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot);
- eyedropper_color_set(C, eye, col);
-}
-
-/* single point sample & set */
static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
{
+ /* Accumulate color. */
float col[3];
eyedropper_color_sample_fl(C, mx, my, col);
- eyedropper_color_set(C, eye, col);
-}
-static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my)
-{
- float col[3];
- eyedropper_color_sample_fl(C, mx, my, col);
- /* delay linear conversion */
- add_v3_v3(eye->accum_col, col);
- eye->accum_tot++;
+ if (eye->accumulate) {
+ add_v3_v3(eye->accum_col, col);
+ eye->accum_tot++;
+ }
+ else {
+ copy_v3_v3(eye->accum_col, col);
+ eye->accum_tot = 1;
+ }
+
+ /* Apply to property. */
+ float accum_col[3];
+ if (eye->accum_tot > 1) {
+ mul_v3_v3fl(accum_col, eye->accum_col, 1.0f / (float)eye->accum_tot);
+ }
+ else {
+ copy_v3_v3(accum_col, eye->accum_col);
+ }
+ eyedropper_color_set(C, eye, accum_col);
}
static void eyedropper_cancel(bContext *C, wmOperator *op)
@@ -254,29 +259,24 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (eye->accum_tot == 0) {
eyedropper_color_sample(C, eye, event->x, event->y);
}
- else {
- eyedropper_color_set_accum(C, eye);
- }
eyedropper_exit(C, op);
return OPERATOR_FINISHED;
case EYE_MODAL_SAMPLE_BEGIN:
/* enable accum and make first sample */
eye->accum_start = true;
- eyedropper_color_sample_accum(C, eye, event->x, event->y);
+ eyedropper_color_sample(C, eye, event->x, event->y);
break;
case EYE_MODAL_SAMPLE_RESET:
eye->accum_tot = 0;
zero_v3(eye->accum_col);
- eyedropper_color_sample_accum(C, eye, event->x, event->y);
- eyedropper_color_set_accum(C, eye);
+ eyedropper_color_sample(C, eye, event->x, event->y);
break;
}
}
- else if (event->type == MOUSEMOVE) {
+ else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
if (eye->accum_start) {
/* button is pressed so keep sampling */
- eyedropper_color_sample_accum(C, eye, event->x, event->y);
- eyedropper_color_set_accum(C, eye);
+ eyedropper_color_sample(C, eye, event->x, event->y);
}
}
@@ -321,20 +321,9 @@ static int eyedropper_exec(bContext *C, wmOperator *op)
static bool eyedropper_poll(bContext *C)
{
- PointerRNA ptr;
- PropertyRNA *prop;
- int index_dummy;
- uiBut *but;
-
- /* Only color buttons */
- if ((CTX_wm_window(C) != NULL) &&
- (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
- (but->type == UI_BTYPE_COLOR))
- {
- return 1;
- }
-
- return 0;
+ /* Actual test for active button happens later, since we don't
+ * know which one is active until mouse over. */
+ return (CTX_wm_window(C) != NULL);
}
void UI_OT_eyedropper_color(wmOperatorType *ot)
@@ -353,6 +342,22 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+}
+
+void UI_OT_eyedropper_color_crypto(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Cryptomatte Eyedropper";
+ ot->idname = "UI_OT_eyedropper_color_crypto";
+ ot->description = "Pick a color from Cryptomatte node Pick output image";
- /* properties */
+ /* api callbacks */
+ ot->invoke = eyedropper_invoke;
+ ot->modal = eyedropper_modal;
+ ot->cancel = eyedropper_cancel;
+ ot->exec = eyedropper_exec;
+ ot->poll = eyedropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index f0060cd5758..fa60ac0552b 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -843,6 +843,7 @@ struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf);
/* interface_eyedropper_color.c */
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
+void UI_OT_eyedropper_color_crypto(struct wmOperatorType *ot);
/* interface_eyedropper_colorband.c */
void UI_OT_eyedropper_colorband(struct wmOperatorType *ot);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 96128aa29f0..ec10fc9d494 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1359,6 +1359,7 @@ void ED_operatortypes_ui(void)
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
+ WM_operatortype_append(UI_OT_eyedropper_color_crypto);
WM_operatortype_append(UI_OT_eyedropper_colorband);
WM_operatortype_append(UI_OT_eyedropper_colorband_point);
WM_operatortype_append(UI_OT_eyedropper_id);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 6110d5f3466..2dcc18af4ea 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -3043,6 +3043,24 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
}
}
+void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname)
+{
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+ uiBlock *block;
+ uiBut *but;
+
+ if (!prop) {
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ block = uiLayoutGetBlock(layout);
+
+ but = uiDefIconTextButO(block, UI_BTYPE_BUT, "UI_OT_eyedropper_color_crypto", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, RNA_property_ui_name(prop), 0, 0, UI_UNIT_X, UI_UNIT_Y, RNA_property_ui_description(prop));
+ but->rnapoin = *ptr;
+ but->rnaprop = prop;
+ but->rnaindex = -1;
+}
/********************* Layer Buttons Template ************************/
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 10532f3ac7d..d1ad8cb396c 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1025,6 +1025,11 @@ static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), Pointer
uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
}
+static void node_shader_buts_principled_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "parametrization", 0, "", ICON_NONE);
+}
+
static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *row;
@@ -1207,6 +1212,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_BSDF_HAIR:
ntype->draw_buttons = node_shader_buts_hair;
break;
+ case SH_NODE_BSDF_HAIR_PRINCIPLED:
+ ntype->draw_buttons = node_shader_buts_principled_hair;
+ break;
case SH_NODE_SCRIPT:
ntype->draw_buttons = node_shader_buts_script;
ntype->draw_buttons_ex = node_shader_buts_script_ex;
@@ -2473,6 +2481,25 @@ static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
+static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col = uiLayoutColumn(layout, true);
+
+ uiItemL(col, IFACE_("Matte Objects:"), ICON_NONE);
+
+ uiLayout *row = uiLayoutRow(col, true);
+ uiTemplateCryptoPicker(row, ptr, "add");
+ uiTemplateCryptoPicker(row, ptr, "remove");
+
+ uiItemR(col, ptr, "matte_id", 0, "", ICON_NONE);
+}
+
+static void node_composit_buts_cryptomatte_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
+{
+ uiItemO(layout, IFACE_("Add Crypto Layer"), ICON_ZOOMIN, "NODE_OT_cryptomatte_layer_add");
+ uiItemO(layout, IFACE_("Remove Crypto Layer"), ICON_ZOOMOUT, "NODE_OT_cryptomatte_layer_remove");
+}
+
static void node_composit_buts_brightcontrast(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
@@ -2705,6 +2732,10 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_SUNBEAMS:
ntype->draw_buttons = node_composit_buts_sunbeams;
break;
+ case CMP_NODE_CRYPTOMATTE:
+ ntype->draw_buttons = node_composit_buts_cryptomatte;
+ ntype->draw_buttons_ex = node_composit_buts_cryptomatte_ex;
+ break;
case CMP_NODE_BRIGHTCONTRAST:
ntype->draw_buttons = node_composit_buts_brightcontrast;
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 1a6710035c2..edab76cd7e1 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -2548,3 +2548,93 @@ void NODE_OT_clear_viewer_border(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/* ****************** Cryptomatte Add Socket ******************* */
+
+static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ PointerRNA ptr = CTX_data_pointer_get(C, "node");
+ bNodeTree *ntree = NULL;
+ bNode *node = NULL;
+
+ if (ptr.data) {
+ node = ptr.data;
+ ntree = ptr.id.data;
+ }
+ else if (snode && snode->edittree) {
+ ntree = snode->edittree;
+ node = nodeGetActive(snode->edittree);
+ }
+
+ if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+
+ snode_notify(C, snode);
+
+ return OPERATOR_FINISHED;
+}
+
+void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Cryptomatte Socket";
+ ot->description = "Add a new input layer to a Cryptomatte node";
+ ot->idname = "NODE_OT_cryptomatte_layer_add";
+
+ /* callbacks */
+ ot->exec = node_cryptomatte_add_socket_exec;
+ ot->poll = composite_node_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ****************** Cryptomatte Remove Socket ******************* */
+
+static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ PointerRNA ptr = CTX_data_pointer_get(C, "node");
+ bNodeTree *ntree = NULL;
+ bNode *node = NULL;
+
+ if (ptr.data) {
+ node = ptr.data;
+ ntree = ptr.id.data;
+ }
+ else if (snode && snode->edittree) {
+ ntree = snode->edittree;
+ node = nodeGetActive(snode->edittree);
+ }
+
+ if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!ntreeCompositCryptomatteRemoveSocket(ntree, node)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ snode_notify(C, snode);
+
+ return OPERATOR_FINISHED;
+}
+
+void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Cryptomatte Socket";
+ ot->description = "Remove layer from a Crytpomatte node";
+ ot->idname = "NODE_OT_cryptomatte_layer_remove";
+
+ /* callbacks */
+ ot->exec = node_cryptomatte_remove_socket_exec;
+ ot->poll = composite_node_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 1a0f738ab8a..ed7379acca9 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -229,6 +229,8 @@ void NODE_GGT_backdrop_crop(struct wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_sun_beams(struct wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_corner_pin(struct wmGizmoGroupType *gzgt);
+void NODE_OT_cryptomatte_layer_add(struct wmOperatorType *ot);
+void NODE_OT_cryptomatte_layer_remove(struct wmOperatorType *ot);
extern const char *node_context_dir[];
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 2a585c42395..dccc999b2d1 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -129,6 +129,9 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_tree_socket_add);
WM_operatortype_append(NODE_OT_tree_socket_remove);
WM_operatortype_append(NODE_OT_tree_socket_move);
+
+ WM_operatortype_append(NODE_OT_cryptomatte_layer_add);
+ WM_operatortype_append(NODE_OT_cryptomatte_layer_remove);
}
void ED_operatormacros_node(void)
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index ca01ffc2b29..31a5931dde4 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -905,6 +905,14 @@ typedef struct NodeSunBeams {
float ray_length;
} NodeSunBeams;
+typedef struct NodeCryptomatte {
+ float add[3];
+ float remove[3];
+ char *matte_id;
+ int num_inputs;
+ int pad;
+} NodeCryptomatte;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -953,6 +961,11 @@ typedef struct NodeSunBeams {
#define SHD_HAIR_REFLECTION 0
#define SHD_HAIR_TRANSMISSION 1
+/* principled hair parametrization */
+#define SHD_PRINCIPLED_HAIR_REFLECTANCE 0
+#define SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION 1
+#define SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION 2
+
/* blend texture */
#define SHD_BLEND_LINEAR 0
#define SHD_BLEND_QUADRATIC 1
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index c0eda3dc053..e672ae0e6f7 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2874,6 +2874,48 @@ static void rna_NodeColorBalance_update_cdl(Main *bmain, Scene *scene, PointerRN
rna_Node_update(bmain, scene, ptr);
}
+static void rna_NodeCryptomatte_matte_get(PointerRNA *ptr, char *value)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *nc = node->storage;
+
+ strcpy(value, (nc->matte_id) ? nc->matte_id : "");
+}
+
+static int rna_NodeCryptomatte_matte_length(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *nc = node->storage;
+
+ return (nc->matte_id) ? strlen(nc->matte_id) : 0;
+}
+
+static void rna_NodeCryptomatte_matte_set(PointerRNA *ptr, const char *value)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *nc = node->storage;
+
+ if (nc->matte_id)
+ MEM_freeN(nc->matte_id);
+
+ if (value && value[0])
+ nc->matte_id = BLI_strdup(value);
+ else
+ nc->matte_id = NULL;
+}
+
+static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ ntreeCompositCryptomatteSyncFromAdd(ptr->id.data, ptr->data);
+ rna_Node_update(bmain, scene, ptr);
+}
+
+static void rna_NodeCryptomatte_update_remove(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ ntreeCompositCryptomatteSyncFromRemove(ptr->id.data, ptr->data);
+ rna_Node_update(bmain, scene, ptr);
+}
+
/* ******** Node Socket Types ******** */
static PointerRNA rna_NodeOutputFile_slot_layer_get(CollectionPropertyIterator *iter)
@@ -3297,6 +3339,13 @@ static const EnumPropertyItem node_hair_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static const EnumPropertyItem node_principled_hair_items[] = {
+ {SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION, "ABSORPTION", 0, "Absorption coefficient", "Directly set the absorption coefficient sigma_a. This is not the most intuitive way to color hair."},
+ {SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION, "MELANIN", 0, "Melanin concentration", "Define the melanin concentrations below to get the most realistic-looking hair. You can get the concentrations for different types of hair online."},
+ {SHD_PRINCIPLED_HAIR_REFLECTANCE, "COLOR", 0, "Direct coloring", "Choose the color of your preference, and the shader will approximate the absorption coefficient to render lookalike hair."},
+ {0, NULL, 0, NULL, NULL}
+};
+
static const EnumPropertyItem node_script_mode_items[] = {
{NODE_SCRIPT_INTERNAL, "INTERNAL", 0, "Internal", "Use internal text data-block"},
{NODE_SCRIPT_EXTERNAL, "EXTERNAL", 0, "External", "Use external .osl or .oso file"},
@@ -4295,6 +4344,21 @@ static void def_hair(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+/* RNA initialization for the custom property. */
+static void def_hair_principled(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "parametrization", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_ui_text(prop, "Color parametrization", "Select the shader's color parametrization");
+ RNA_def_property_enum_items(prop, node_principled_hair_items);
+ RNA_def_property_enum_default(prop, SHD_PRINCIPLED_HAIR_REFLECTANCE);
+ /* Upon editing, update both the node data AND the UI representation */
+ /* (This effectively shows/hides the relevant sockets) */
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
+}
+
static void def_sh_uvmap(StructRNA *srna)
{
PropertyRNA *prop;
@@ -6905,6 +6969,32 @@ static void def_cmp_sunbeams(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_cryptomatte(StructRNA *srna)
+{
+ PropertyRNA *prop;
+ static float default_1[3] = {1.f, 1.f, 1.f};
+
+ RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
+ prop = RNA_def_property(srna, "matte_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_NodeCryptomatte_matte_get", "rna_NodeCryptomatte_matte_length",
+ "rna_NodeCryptomatte_matte_set");
+ RNA_def_property_ui_text(prop, "Matte Objects", "List of object and material crypto IDs to include in matte");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+
+ prop = RNA_def_property(srna, "add", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_array_default(prop, default_1);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Add", "Add object or material to matte, by picking a color from the Pick output");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_add");
+
+ prop = RNA_def_property(srna, "remove", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_array_default(prop, default_1);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Remove", "Remove object or material from matte, by picking a color from the Pick output");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_remove");
+}
+
/* -- Texture Nodes --------------------------------------------------------- */
static void def_tex_output(StructRNA *srna)
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 67c86180188..8df114afa24 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -60,6 +60,7 @@ set(SRC
composite/nodes/node_composite_composite.c
composite/nodes/node_composite_cornerpin.c
composite/nodes/node_composite_crop.c
+ composite/nodes/node_composite_cryptomatte.c
composite/nodes/node_composite_curves.c
composite/nodes/node_composite_despeckle.c
composite/nodes/node_composite_doubleEdgeMask.c
@@ -168,6 +169,7 @@ set(SRC
shader/nodes/node_shader_bsdf_transparent.c
shader/nodes/node_shader_bsdf_velvet.c
shader/nodes/node_shader_bsdf_hair.c
+ shader/nodes/node_shader_bsdf_hair_principled.c
shader/nodes/node_shader_bump.c
shader/nodes/node_shader_emission.c
shader/nodes/node_shader_fresnel.c
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index dfcb83b873a..a728d1e228d 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -109,6 +109,7 @@ void register_node_type_cmp_luma_matte(void);
void register_node_type_cmp_doubleedgemask(void);
void register_node_type_cmp_keyingscreen(void);
void register_node_type_cmp_keying(void);
+void register_node_type_cmp_cryptomatte(void);
void register_node_type_cmp_translate(void);
void register_node_type_cmp_rotate(void);
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 83a5f5c5bf1..2f466b0296c 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -111,6 +111,7 @@ void register_node_type_sh_volume_absorption(void);
void register_node_type_sh_volume_scatter(void);
void register_node_type_sh_volume_principled(void);
void register_node_type_sh_bsdf_hair(void);
+void register_node_type_sh_bsdf_hair_principled(void);
void register_node_type_sh_subsurface_scattering(void);
void register_node_type_sh_mix_shader(void);
void register_node_type_sh_add_shader(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index cf974132961..22c2afcc466 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -85,6 +85,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BS
DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TOON, def_toon, "BSDF_TOON", BsdfToon, "Toon BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_HAIR, def_hair, "BSDF_HAIR", BsdfHair, "Hair BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_HAIR_PRINCIPLED, def_hair_principled, "BSDF_HAIR_PRINCIPLED", BsdfHairPrincipled, "Principled Hair BSDF", "")
DefNode( ShaderNode, SH_NODE_SUBSURFACE_SCATTERING, def_sh_subsurface, "SUBSURFACE_SCATTERING",SubsurfaceScattering,"Subsurface Scattering","")
DefNode( ShaderNode, SH_NODE_VOLUME_ABSORPTION, 0, "VOLUME_ABSORPTION", VolumeAbsorption, "Volume Absorption", "" )
DefNode( ShaderNode, SH_NODE_VOLUME_SCATTER, 0, "VOLUME_SCATTER", VolumeScatter, "Volume Scatter", "" )
@@ -215,6 +216,7 @@ DefNode( CompositorNode, CMP_NODE_PIXELATE, 0, "PIXEL
DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
DefNode( CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" )
DefNode( CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
+DefNode( CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE", Cryptomatte, "Cryptomatte", "" )
DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
new file mode 100644
index 00000000000..0231e4717b2
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
@@ -0,0 +1,302 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Stockner, Stefan Werner
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_cryptomatte.c
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.h"
+#include "BLI_assert.h"
+#include "BLI_dynstr.h"
+#include "BLI_hash_mm3.h"
+#include "BLI_utildefines.h"
+
+/* this is taken from the cryptomatte specification 1.0 */
+
+static inline float hash_to_float(uint32_t hash)
+{
+ uint32_t mantissa = hash & (( 1 << 23) - 1);
+ uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
+ exponent = MAX2(exponent, (uint32_t) 1);
+ exponent = MIN2(exponent, (uint32_t) 254);
+ exponent = exponent << 23;
+ uint32_t sign = (hash >> 31);
+ sign = sign << 31;
+ uint32_t float_bits = sign | exponent | mantissa;
+ float f;
+ /* Bit casting relies on equal size for both types. */
+ BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float and uint32_t are not the same size")
+ memcpy(&f, &float_bits, sizeof(float));
+ return f;
+}
+
+static void cryptomatte_add(NodeCryptomatte* n, float f)
+{
+ /* Turn the number into a string. */
+ char number[32];
+ BLI_snprintf(number, sizeof(number), "<%.9g>", f);
+
+ /* Search if we already have the number. */
+ if (n->matte_id && strlen(n->matte_id) != 0) {
+ size_t start = 0;
+ const size_t end = strlen(n->matte_id);
+ size_t token_len = 0;
+ while (start < end) {
+ /* Ignore leading whitespace. */
+ while (start < end && n->matte_id[start] == ' ') {
+ ++start;
+ }
+
+ /* Find the next seprator. */
+ char* token_end = strchr(n->matte_id+start, ',');
+ if (token_end == NULL || token_end == n->matte_id+start) {
+ token_end = n->matte_id+end;
+ }
+ /* Be aware that token_len still contains any trailing white space. */
+ token_len = token_end - (n->matte_id + start);
+
+ /* If this has a leading bracket, assume a raw floating point number and look for the closing bracket. */
+ if (n->matte_id[start] == '<') {
+ if (strncmp(n->matte_id+start, number, strlen(number)) == 0) {
+ /* This number is already there, so continue. */
+ return;
+ }
+ }
+ else {
+ /* Remove trailing white space */
+ size_t name_len = token_len;
+ while (n->matte_id[start+name_len] == ' ' && name_len > 0) {
+ name_len--;
+ }
+ /* Calculate the hash of the token and compare. */
+ uint32_t hash = BLI_hash_mm3((const unsigned char*)(n->matte_id+start), name_len, 0);
+ if (f == hash_to_float(hash)) {
+ return;
+ }
+ }
+ start += token_len+1;
+ }
+ }
+
+ DynStr *new_matte = BLI_dynstr_new();
+ if (!new_matte) {
+ return;
+ }
+
+ if(n->matte_id) {
+ BLI_dynstr_append(new_matte, n->matte_id);
+ MEM_freeN(n->matte_id);
+ }
+
+ if(BLI_dynstr_get_len(new_matte) > 0) {
+ BLI_dynstr_append(new_matte, ",");
+ }
+ BLI_dynstr_append(new_matte, number);
+ n->matte_id = BLI_dynstr_get_cstring(new_matte);
+ BLI_dynstr_free(new_matte);
+}
+
+static void cryptomatte_remove(NodeCryptomatte*n, float f)
+{
+ if (n->matte_id == NULL || strlen(n->matte_id) == 0) {
+ /* Empty string, nothing to remove. */
+ return;
+ }
+
+ /* This will be the new string without the removed key. */
+ DynStr *new_matte = BLI_dynstr_new();
+ if (!new_matte) {
+ return;
+ }
+
+ /* Turn the number into a string. */
+ static char number[32];
+ BLI_snprintf(number, sizeof(number), "<%.9g>", f);
+
+ /* Search if we already have the number. */
+ size_t start = 0;
+ const size_t end = strlen(n->matte_id);
+ size_t token_len = 0;
+ bool is_first = true;
+ while (start < end) {
+ bool skip = false;
+ /* Ignore leading whitespace or commas. */
+ while (start < end && ((n->matte_id[start] == ' ') || (n->matte_id[start] == ','))) {
+ ++start;
+ }
+
+ /* Find the next seprator. */
+ char* token_end = strchr(n->matte_id+start+1, ',');
+ if (token_end == NULL || token_end == n->matte_id+start) {
+ token_end = n->matte_id+end;
+ }
+ /* Be aware that token_len still contains any trailing white space. */
+ token_len = token_end - (n->matte_id + start);
+
+ if (token_len == 1) {
+ skip = true;
+ }
+ /* If this has a leading bracket, assume a raw floating point number and look for the closing bracket. */
+ else if (n->matte_id[start] == '<') {
+ if (strncmp(n->matte_id+start, number, strlen(number)) == 0) {
+ /* This number is already there, so skip it. */
+ skip = true;
+ }
+ }
+ else {
+ /* Remove trailing white space */
+ size_t name_len = token_len;
+ while (n->matte_id[start+name_len] == ' ' && name_len > 0) {
+ name_len--;
+ }
+ /* Calculate the hash of the token and compare. */
+ uint32_t hash = BLI_hash_mm3((const unsigned char*)(n->matte_id+start), name_len, 0);
+ if (f == hash_to_float(hash)) {
+ skip = true;
+ }
+ }
+ if (!skip) {
+ if (is_first) {
+ is_first = false;
+ }
+ else {
+ BLI_dynstr_append(new_matte, ", ");
+ }
+ BLI_dynstr_nappend(new_matte, n->matte_id+start, token_len);
+ }
+ start += token_len+1;
+ }
+
+ if(n->matte_id) {
+ MEM_freeN(n->matte_id);
+ n->matte_id = NULL;
+ }
+ if(BLI_dynstr_get_len(new_matte) > 0) {
+ n->matte_id = BLI_dynstr_get_cstring(new_matte);
+ }
+ BLI_dynstr_free(new_matte);
+}
+
+static bNodeSocketTemplate outputs[] = {
+ { SOCK_RGBA, 0, N_("Image")},
+ { SOCK_FLOAT, 0, N_("Matte")},
+ { SOCK_RGBA, 0, N_("Pick")},
+ { -1, 0, "" }
+};
+
+void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeCryptomatte *n = node->storage;
+ if (n->add[0] != 0.0f) {
+ cryptomatte_add(n, n->add[0]);
+ n->add[0] = 0.0f;
+ n->add[1] = 0.0f;
+ n->add[2] = 0.0f;
+ }
+}
+
+void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeCryptomatte *n = node->storage;
+ if (n->remove[0] != 0.0f) {
+ cryptomatte_remove(n, n->remove[0]);
+ n->remove[0] = 0.0f;
+ n->remove[1] = 0.0f;
+ n->remove[2] = 0.0f;
+ }
+}
+
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
+{
+ NodeCryptomatte *n = node->storage;
+ char sockname[32];
+ n->num_inputs++;
+ BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs-1);
+ bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, sockname);
+ return sock;
+}
+
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
+{
+ NodeCryptomatte *n = node->storage;
+ if (n->num_inputs < 2) {
+ return 0;
+ }
+ bNodeSocket *sock = node->inputs.last;
+ nodeRemoveSocket(ntree, node, sock);
+ n->num_inputs--;
+ return 1;
+}
+
+static void init(bNodeTree *ntree, bNode *node)
+{
+ NodeCryptomatte *user = MEM_callocN(sizeof(NodeCryptomatte), "cryptomatte user");
+ node->storage = user;
+
+
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
+
+ /* Add three inputs by default, as recommended by the Cryptomatte specification. */
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+}
+
+static void node_free_cryptomatte(bNode *node)
+{
+ NodeCryptomatte *nc = node->storage;
+
+ if (nc) {
+ if (nc->matte_id) {
+ MEM_freeN(nc->matte_id);
+ }
+
+ MEM_freeN(nc);
+ }
+}
+
+static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
+{
+ NodeCryptomatte *src_nc = src_node->storage;
+ NodeCryptomatte *dest_nc = MEM_dupallocN(src_nc);
+
+ if (src_nc->matte_id)
+ dest_nc->matte_id = MEM_dupallocN(src_nc->matte_id);
+
+ dest_node->storage = dest_nc;
+}
+
+void register_node_type_cmp_cryptomatte(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, NULL, outputs);
+ node_type_init(&ntype, init);
+ node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
new file mode 100644
index 00000000000..5fff2548ba1
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
@@ -0,0 +1,132 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Stockner, L. E. Segovia
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+/* Color, melanin and absorption coefficient default to approximately same brownish hair. */
+static bNodeSocketTemplate sh_node_bsdf_hair_principled_in[] = {
+ { SOCK_RGBA, 1, N_("Color"), 0.017513f, 0.005763f, 0.002059f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Melanin"), 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Melanin Redness"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, N_("Tint"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 1, N_("Absorption Coefficient"), 0.245531f, 0.52f, 1.365f, 0.0f, 0.0f, 1000.0f},
+ { SOCK_FLOAT, 1, N_("Roughness"), 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Radial Roughness"), 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Coat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("IOR"), 1.55f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
+ { SOCK_FLOAT, 1, N_("Offset"), 2.f*((float)M_PI)/180.f, 0.0f, 0.0f, 0.0f, -M_PI_2, M_PI_2, PROP_ANGLE},
+ { SOCK_FLOAT, 1, N_("Random Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Random Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { -1, 0, "" },
+};
+
+static bNodeSocketTemplate sh_node_bsdf_hair_principled_out[] = {
+ { SOCK_SHADER, 0, N_("BSDF")},
+ { -1, 0, "" }
+};
+
+/* Initialize the custom Parametrization property to Color. */
+static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_PRINCIPLED_HAIR_REFLECTANCE;
+}
+
+/* Triggers (in)visibility of some sockets when changing Parametrization. */
+static void node_shader_update_hair_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock;
+ int parametrization = node->custom1;
+
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Color")) {
+ if (parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE) {
+ sock->flag &= ~SOCK_UNAVAIL;
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
+ }
+ }
+ else if (STREQ(sock->name, "Melanin")) {
+ if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) {
+ sock->flag &= ~SOCK_UNAVAIL;
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
+ }
+ }
+ else if (STREQ(sock->name, "Melanin Redness")) {
+ if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) {
+ sock->flag &= ~SOCK_UNAVAIL;
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
+ }
+ }
+ else if (STREQ(sock->name, "Tint")) {
+ if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) {
+ sock->flag &= ~SOCK_UNAVAIL;
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
+ }
+ }
+ else if (STREQ(sock->name, "Absorption Coefficient")) {
+ if (parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION) {
+ sock->flag &= ~SOCK_UNAVAIL;
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
+ }
+ }
+ else if (STREQ(sock->name, "Random Color")) {
+ if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) {
+ sock->flag &= ~SOCK_UNAVAIL;
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
+ }
+ }
+ }
+}
+
+/* node type definition */
+void register_node_type_sh_bsdf_hair_principled(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER, 0);
+ node_type_socket_templates(&ntype, sh_node_bsdf_hair_principled_in, sh_node_bsdf_hair_principled_out);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_init(&ntype, node_shader_init_hair_principled);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_update(&ntype, node_shader_update_hair_principled, NULL);
+
+ nodeRegisterType(&ntype);
+}