Code improvements + Mix node #30

Merged
Bogdan Nagirniak merged 18 commits from BogdanNagirniak/blender:matx-code-improvements into matx-export-material 2023-09-22 18:23:13 +02:00
13 changed files with 121 additions and 78 deletions
Showing only changes of commit 276bbbd554 - Show all commits

View File

@ -177,6 +177,36 @@ NodeItem NodeItem::operator^(const NodeItem &other) const
return arithmetic(other, "power", [](float a, float b) { return std::powf(a, b); }); return arithmetic(other, "power", [](float a, float b) { return std::powf(a, b); });
} }
NodeItem NodeItem::operator[](int index) const
{
if (value) {
float v = 0.0f;
switch (type()) {
case Type::Float:
v = value->asA<float>();
break;
case Type::Vector2:
v = value->asA<MaterialX::Vector2>()[index];
case Type::Vector3:
v = value->asA<MaterialX::Vector3>()[index];
break;
case Type::Vector4:
v = value->asA<MaterialX::Vector4>()[index];
break;
case Type::Color3:
v = value->asA<MaterialX::Color3>()[index];
break;
case Type::Color4:
v = value->asA<MaterialX::Color4>()[index];
break;
default:
BLI_assert_unreachable();
}
return val(v);
}
return create_node("extract", Type::Float, {{"in", *this}, {"index", val(index)}});
}
bool NodeItem::operator==(const NodeItem &other) const bool NodeItem::operator==(const NodeItem &other) const
{ {
if (!*this) { if (!*this) {
@ -233,9 +263,8 @@ NodeItem NodeItem::max(const NodeItem &other) const
NodeItem NodeItem::dotproduct(const NodeItem &other) const NodeItem NodeItem::dotproduct(const NodeItem &other) const
{ {
NodeItem d = arithmetic( if (value && other.value) {
other, "dotproduct", [](float a, float b) { return a * b; }, Type::Float); NodeItem d = *this * other;
if (d.value) {
float f = 0.0f; float f = 0.0f;
switch (d.type()) { switch (d.type()) {
case Type::Float: { case Type::Float: {
@ -270,14 +299,32 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const
default: default:
BLI_assert_unreachable(); BLI_assert_unreachable();
} }
d.value = MaterialX::Value::createValue(f); return val(f);
} }
return d;
return create_node("dotproduct", Type::Float, {{"in1", *this}, {"in2", other}});
} }
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const NodeItem NodeItem::mix(const NodeItem &val1, const NodeItem &val2) const
{ {
return (val(1.0f) - *this) * a + *this * b; BLI_assert(type() == Type::Float);
if (value && val1.value && val2.value) {
return (val(1.0f) - *this) * val1 + *this * val2;
}
Type type1 = val1.type();
if (ELEM(type1, Type::BSDF, Type::EDF)) {
BLI_assert(val2.type() == type1);
/* Special case: mix BSDF/EDF shaders */
return create_node("mix", type1, {{}, {}});
};
NodeItem item1 = val1;
NodeItem item2 = val2;
Type to_type = cast_types(item1, item2);
return create_node("mix", to_type, {{"bg", item1}, {"fg", item2}});
} }
NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const
@ -375,7 +422,7 @@ NodeItem NodeItem::convert(Type to_type) const
} }
if (to_type == Type::Float) { if (to_type == Type::Float) {
return extract(0); return (*this)[0];
} }
/* Converting types which requires > 1 iteration */ /* Converting types which requires > 1 iteration */
@ -601,13 +648,6 @@ NodeItem NodeItem::if_else(CompareOp op,
return res; return res;
} }
NodeItem NodeItem::extract(const int index) const
{
/* TODO: Add check if (value) { ... } */
NodeItem res = create_node("extract", Type::Float, {{"in", *this}, {"index", val(index)}});
return res;
}
NodeItem NodeItem::empty() const NodeItem NodeItem::empty() const
{ {
return NodeItem(graph_); return NodeItem(graph_);

View File

@ -73,6 +73,7 @@ class NodeItem {
NodeItem operator/(const NodeItem &other) const; NodeItem operator/(const NodeItem &other) const;
NodeItem operator%(const NodeItem &other) const; NodeItem operator%(const NodeItem &other) const;
NodeItem operator^(const NodeItem &other) const; NodeItem operator^(const NodeItem &other) const;
NodeItem operator[](int index) const;
bool operator==(const NodeItem &other) const; bool operator==(const NodeItem &other) const;
bool operator!=(const NodeItem &other) const; bool operator!=(const NodeItem &other) const;
@ -83,7 +84,7 @@ class NodeItem {
NodeItem min(const NodeItem &other) const; NodeItem min(const NodeItem &other) const;
NodeItem max(const NodeItem &other) const; NodeItem max(const NodeItem &other) const;
NodeItem dotproduct(const NodeItem &other) const; NodeItem dotproduct(const NodeItem &other) const;
NodeItem blend(const NodeItem &a, const NodeItem &b) const; NodeItem mix(const NodeItem &val1, const NodeItem &val2) const;
NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) const; NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) const;
NodeItem clamp(float min_val = 0.0f, float max_val = 1.0f) const; NodeItem clamp(float min_val = 0.0f, float max_val = 1.0f) const;
NodeItem sin() const; NodeItem sin() const;
@ -105,7 +106,6 @@ class NodeItem {
const NodeItem &other, const NodeItem &other,
const NodeItem &if_val, const NodeItem &if_val,
const NodeItem &else_val) const; const NodeItem &else_val) const;
NodeItem extract(const int index) const;
/* Useful functions */ /* Useful functions */
NodeItem empty() const; NodeItem empty() const;

View File

@ -146,13 +146,18 @@ NodeItem NodeParser::empty() const
return NodeItem(graph_); return NodeItem(graph_);
} }
NodeItem NodeParser::texcoord_node() NodeItem NodeParser::texcoord_node(NodeItem::Type type)
{ {
BLI_assert(ELEM(type, NodeItem::Type::Vector2, NodeItem::Type::Vector3));
std::string name = TEXCOORD_NODE_NAME;
if (type == NodeItem::Type::Vector3) {
name += "_vector3";
}
NodeItem res = empty(); NodeItem res = empty();
res.node = graph_->getNode(TEXCOORD_NODE_NAME); res.node = graph_->getNode(name);
if (!res.node) { if (!res.node) {
res = create_node("texcoord", NodeItem::Type::Vector2); res = create_node("texcoord", type);
res.node->setName(TEXCOORD_NODE_NAME); res.node->setName(name);
} }
return res; return res;
} }

View File

@ -59,7 +59,7 @@ class NodeParser {
NodeItem get_input_value(int index, NodeItem::Type to_type); NodeItem get_input_value(int index, NodeItem::Type to_type);
NodeItem empty() const; NodeItem empty() const;
template<class T> NodeItem val(const T &data) const; template<class T> NodeItem val(const T &data) const;
NodeItem texcoord_node(); NodeItem texcoord_node(NodeItem::Type type = NodeItem::Type::Vector2);
private: private:
NodeItem get_default(const bNodeSocket &socket, NodeItem::Type to_type); NodeItem get_default(const bNodeSocket &socket, NodeItem::Type to_type);

View File

@ -31,7 +31,7 @@ NODE_SHADER_MATERIALX_BEGIN
{ {
NodeItem fac = get_input_value("Fac", NodeItem::Type::Float); NodeItem fac = get_input_value("Fac", NodeItem::Type::Float);
NodeItem color = get_input_value("Color", NodeItem::Type::Color3); NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
return fac.blend(color, val(1.0f) - color); return fac.mix(color, val(1.0f) - color);
} }
#endif #endif
NODE_SHADER_MATERIALX_END NODE_SHADER_MATERIALX_END

View File

@ -41,7 +41,7 @@ NODE_SHADER_MATERIALX_BEGIN
res = shader2 * fac; res = shader2 * fac;
} }
else if (shader1 && shader2) { else if (shader1 && shader2) {
res = create_node("mix", to_type_, {{"fg", shader2}, {"bg", shader1}, {"mix", fac}}); res = fac.mix(shader1, shader2);
} }
break; break;
} }

View File

@ -89,7 +89,7 @@ NODE_SHADER_MATERIALX_BEGIN
} }
int index = STREQ(socket_out_->name, "Red") ? 0 : STREQ(socket_out_->name, "Green") ? 1 : 2; int index = STREQ(socket_out_->name, "Red") ? 0 : STREQ(socket_out_->name, "Green") ? 1 : 2;
return convert.extract(index); return convert[index];
} }
#endif #endif
NODE_SHADER_MATERIALX_END NODE_SHADER_MATERIALX_END

View File

@ -95,7 +95,7 @@ NODE_SHADER_MATERIALX_BEGIN
{ {
NodeItem vector = get_input_value("Vector", NodeItem::Type::Vector3); NodeItem vector = get_input_value("Vector", NodeItem::Type::Vector3);
int index = STREQ(socket_out_->name, "X") ? 0 : STREQ(socket_out_->name, "Y") ? 1 : 2; int index = STREQ(socket_out_->name, "X") ? 0 : STREQ(socket_out_->name, "Y") ? 1 : 2;
return vector.extract(index); return vector[index];
} }
#endif #endif
NODE_SHADER_MATERIALX_END NODE_SHADER_MATERIALX_END

View File

@ -160,7 +160,7 @@ class BrickFunction : public mf::MultiFunction {
return (3.0f * ff - 2.0f * ff * f); return (3.0f * ff - 2.0f * ff * f);
} }
static float2 brick(float3 p, static float2 brick(float3 pos,
float mortar_size, float mortar_size,
float mortar_smooth, float mortar_smooth,
float bias, float bias,
@ -173,17 +173,17 @@ class BrickFunction : public mf::MultiFunction {
{ {
float offset = 0.0f; float offset = 0.0f;
const int rownum = int(floorf(p.y / row_height)); const int rownum = int(floorf(pos.y / row_height));
if (offset_frequency && squash_frequency) { if (offset_frequency && squash_frequency) {
brick_width *= (rownum % squash_frequency) ? 1.0f : squash_amount; brick_width *= (rownum % squash_frequency) ? 1.0f : squash_amount;
offset = (rownum % offset_frequency) ? 0.0f : (brick_width * offset_amount); offset = (rownum % offset_frequency) ? 0.0f : (brick_width * offset_amount);
} }
const int bricknum = int(floorf((p.x + offset) / brick_width)); const int bricknum = int(floorf((pos.x + offset) / brick_width));
const float x = (p.x + offset) - brick_width * bricknum; const float x = (pos.x + offset) - brick_width * bricknum;
const float y = p.y - row_height * rownum; const float y = pos.y - row_height * rownum;
const float tint = clamp_f( const float tint = clamp_f(
brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias, 0.0f, 1.0f); brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias, 0.0f, 1.0f);

View File

@ -80,11 +80,11 @@ class NodeTexChecker : public mf::MultiFunction {
mask.foreach_index([&](const int64_t i) { mask.foreach_index([&](const int64_t i) {
/* Avoid precision issues on unit coordinates. */ /* Avoid precision issues on unit coordinates. */
const float3 p = (vector[i] * scale[i] + 0.000001f) * 0.999999f; const float3 pos = (vector[i] * scale[i] + 0.000001f) * 0.999999f;
const int xi = abs(int(floorf(p.x))); const int xi = abs(int(floorf(pos.x)));
const int yi = abs(int(floorf(p.y))); const int yi = abs(int(floorf(pos.y)));
const int zi = abs(int(floorf(p.z))); const int zi = abs(int(floorf(pos.z)));
r_fac[i] = ((xi % 2 == yi % 2) == (zi % 2)) ? 1.0f : 0.0f; r_fac[i] = ((xi % 2 == yi % 2) == (zi % 2)) ? 1.0f : 0.0f;
}); });
@ -118,7 +118,7 @@ NODE_SHADER_MATERIALX_BEGIN
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
vector = (vector * scale) % val(2.0f); vector = (vector * scale) % val(2.0f);
return (vector.extract(0).floor() + vector.extract(1).floor()) return (vector[0].floor() + vector[1].floor())
.if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2); .if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2);
} }
#endif #endif

View File

@ -160,21 +160,21 @@ NODE_SHADER_MATERIALX_BEGIN
switch (gradient_type) { switch (gradient_type) {
case SHD_BLEND_LINEAR: case SHD_BLEND_LINEAR:
res = vector.extract(0); res = vector[0];
break; break;
case SHD_BLEND_QUADRATIC: case SHD_BLEND_QUADRATIC:
res = vector.extract(0); res = vector[0];
res = res * res; res = res * res;
break; break;
case SHD_BLEND_EASING: case SHD_BLEND_EASING:
res = vector.extract(0).clamp(val(0.0f), val(1.0f)); res = vector[0].clamp();
res = res * res * (val(3.0f) - val(2.0f) * res); res = res * res * (val(3.0f) - val(2.0f) * res);
break; break;
case SHD_BLEND_DIAGONAL: case SHD_BLEND_DIAGONAL:
res = (vector.extract(0) + vector.extract(1)) * val(0.5f); res = (vector[0] + vector[1]) * val(0.5f);
break; break;
case SHD_BLEND_RADIAL: case SHD_BLEND_RADIAL:
res = vector.extract(1).atan2(vector.extract(0)) / (val(float(M_PI * 2.0f))) + val(0.5f); res = vector[1].atan2(vector[0]) / (val(float(M_PI * 2.0f))) + val(0.5f);
break; break;
case SHD_BLEND_QUADRATIC_SPHERE: case SHD_BLEND_QUADRATIC_SPHERE:
res = (val(1.0f) - vector.dotproduct(vector).sqrt()).max(val(0.0f)); res = (val(1.0f) - vector.dotproduct(vector).sqrt()).max(val(0.0f));

View File

@ -250,7 +250,7 @@ NODE_SHADER_MATERIALX_BEGIN
} }
if (STREQ(socket_out_->name, "Alpha")) { if (STREQ(socket_out_->name, "Alpha")) {
res = res.extract(3); res = res[3];
} }
return res; return res;
} }

View File

@ -135,9 +135,9 @@ class WaveFunction : public mf::MultiFunction {
MutableSpan<float> r_fac = params.uninitialized_single_output<float>(8, "Fac"); MutableSpan<float> r_fac = params.uninitialized_single_output<float>(8, "Fac");
mask.foreach_index([&](const int64_t i) { mask.foreach_index([&](const int64_t i) {
float3 p = vector[i] * scale[i]; float3 pos = vector[i] * scale[i];
/* Prevent precision issues on unit coordinates. */ /* Prevent precision issues on unit coordinates. */
p = (p + 0.000001f) * 0.999999f; pos = (pos + 0.000001f) * 0.999999f;
float n = 0.0f; float n = 0.0f;
float val = 0.0f; float val = 0.0f;
@ -146,21 +146,21 @@ class WaveFunction : public mf::MultiFunction {
case SHD_WAVE_BANDS: case SHD_WAVE_BANDS:
switch (bands_direction_) { switch (bands_direction_) {
case SHD_WAVE_BANDS_DIRECTION_X: case SHD_WAVE_BANDS_DIRECTION_X:
n = p.x * 20.0f; n = pos.x * 20.0f;
break; break;
case SHD_WAVE_BANDS_DIRECTION_Y: case SHD_WAVE_BANDS_DIRECTION_Y:
n = p.y * 20.0f; n = pos.y * 20.0f;
break; break;
case SHD_WAVE_BANDS_DIRECTION_Z: case SHD_WAVE_BANDS_DIRECTION_Z:
n = p.z * 20.0f; n = pos.z * 20.0f;
break; break;
case SHD_WAVE_BANDS_DIRECTION_DIAGONAL: case SHD_WAVE_BANDS_DIRECTION_DIAGONAL:
n = (p.x + p.y + p.z) * 10.0f; n = (pos.x + pos.y + pos.z) * 10.0f;
break; break;
} }
break; break;
case SHD_WAVE_RINGS: case SHD_WAVE_RINGS:
float3 rp = p; float3 rp = pos;
switch (rings_direction_) { switch (rings_direction_) {
case SHD_WAVE_RINGS_DIRECTION_X: case SHD_WAVE_RINGS_DIRECTION_X:
rp *= float3(0.0f, 1.0f, 1.0f); rp *= float3(0.0f, 1.0f, 1.0f);
@ -183,7 +183,7 @@ class WaveFunction : public mf::MultiFunction {
if (distortion[i] != 0.0f) { if (distortion[i] != 0.0f) {
n += distortion[i] * n += distortion[i] *
(noise::perlin_fractal(p * dscale[i], detail[i], droughness[i], 2.0f, true) * 2.0f - (noise::perlin_fractal(pos * dscale[i], detail[i], droughness[i], 2.0f, true) * 2.0f -
1.0f); 1.0f);
} }
@ -223,51 +223,55 @@ NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX #ifdef WITH_MATERIALX
{ {
NodeTexWave *tex = (NodeTexWave *)node_->storage; NodeTexWave *tex = (NodeTexWave *)node_->storage;
const int wave_type = tex->wave_type;
const int bands_direction = tex->bands_direction;
const int rings_direction = tex->rings_direction;
const int wave_profile = tex->wave_profile;
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
NodeItem distortion = get_input_value("Distortion", NodeItem::Type::Float) / NodeItem distortion = get_input_value("Distortion", NodeItem::Type::Float);
val(10.0f); // noise adjusment to get result as Cycles NodeItem detail = get_input_default("Detail", NodeItem::Type::Float);
NodeItem detail = get_input_value("Detail", NodeItem::Type::Float); NodeItem detail_scale = get_input_value("Detail Scale", NodeItem::Type::Float);
NodeItem detail_scale = get_input_value("Detail Scale", NodeItem::Type::Float) *
val(10.0f); // noise adjusment to get result as Cycles
NodeItem detail_rough = get_input_value("Detail Roughness", NodeItem::Type::Float); NodeItem detail_rough = get_input_value("Detail Roughness", NodeItem::Type::Float);
NodeItem phase_offset = get_input_value("Phase Offset", NodeItem::Type::Float); NodeItem phase_offset = get_input_value("Phase Offset", NodeItem::Type::Float);
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3); NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3);
if (!vector) { if (!vector) {
vector = texcoord_node(); vector = texcoord_node(NodeItem::Type::Vector3);
} }
NodeItem p = vector * scale; /* adjusment to get result as Cycles */
p = (p + val(0.000001f)) * val(0.999999f); distortion = distortion * val(10.0f);
detail_scale = detail_scale * val(10.0f);
NodeItem pos = vector * scale;
//pos = (pos + val(0.000001f)) * val(0.999999f);
NodeItem fractal = create_node("fractal3d",
NodeItem::Type::Float,
{{"position", pos},
{"octaves", val(int(detail.value->asA<float>()))},
{"lacunarity", val(2.0f)}});
NodeItem n = val(0.0f); NodeItem n = val(0.0f);
NodeItem value = val(0.0f); NodeItem value = val(0.0f);
switch (wave_type) { switch (tex->wave_type) {
case SHD_WAVE_BANDS: case SHD_WAVE_BANDS:
switch (bands_direction) { switch (tex->bands_direction) {
case SHD_WAVE_BANDS_DIRECTION_X: case SHD_WAVE_BANDS_DIRECTION_X:
n = p.extract(0) * val(20.0f); n = pos[0] * val(20.0f);
break; break;
case SHD_WAVE_BANDS_DIRECTION_Y: case SHD_WAVE_BANDS_DIRECTION_Y:
n = p.extract(1) * val(20.0f); n = pos[1] * val(20.0f);
break; break;
case SHD_WAVE_BANDS_DIRECTION_Z: case SHD_WAVE_BANDS_DIRECTION_Z:
n = p.extract(2) * val(20.0f); n = pos[2] * val(20.0f);
break; break;
case SHD_WAVE_BANDS_DIRECTION_DIAGONAL: case SHD_WAVE_BANDS_DIRECTION_DIAGONAL:
n = (p.extract(0) + p.extract(1) + p.extract(2)) * val(10.0f); n = (pos[0] + pos[1] + pos[2]) * val(10.0f);
break; break;
default: default:
BLI_assert_unreachable(); BLI_assert_unreachable();
} }
break; break;
case SHD_WAVE_RINGS: case SHD_WAVE_RINGS:
NodeItem rp = p; NodeItem rp = pos;
switch (rings_direction) { switch (tex->rings_direction) {
case SHD_WAVE_RINGS_DIRECTION_X: case SHD_WAVE_RINGS_DIRECTION_X:
rp = rp * val(MaterialX::Vector3(0.0f, 1.0f, 1.0f)); rp = rp * val(MaterialX::Vector3(0.0f, 1.0f, 1.0f));
break; break;
@ -286,15 +290,9 @@ NODE_SHADER_MATERIALX_BEGIN
n = rp.dotproduct(rp).sqrt() * val(20.0f); n = rp.dotproduct(rp).sqrt() * val(20.0f);
break; break;
} }
n = n + phase_offset; n = n + phase_offset + distortion * detail_scale * fractal;
n = n + distortion * detail_scale *
create_node("fractal3d",
NodeItem::Type::Float,
{{"position", p},
{"octaves", val(int(detail.value->asA<float>()))},
{"lacunarity", val(2.0f)}});
switch (wave_profile) { switch (tex->wave_profile) {
case SHD_WAVE_PROFILE_SIN: case SHD_WAVE_PROFILE_SIN:
value = val(0.5f) + val(0.5f) * (n - val(float(M_PI_2))).sin(); value = val(0.5f) + val(0.5f) * (n - val(float(M_PI_2))).sin();
break; break;