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); });
}
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
{
if (!*this) {
@ -233,9 +263,8 @@ NodeItem NodeItem::max(const NodeItem &other) const
NodeItem NodeItem::dotproduct(const NodeItem &other) const
{
NodeItem d = arithmetic(
other, "dotproduct", [](float a, float b) { return a * b; }, Type::Float);
if (d.value) {
if (value && other.value) {
NodeItem d = *this * other;
float f = 0.0f;
switch (d.type()) {
case Type::Float: {
@ -270,14 +299,32 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const
default:
BLI_assert_unreachable();
}
d.value = MaterialX::Value::createValue(f);
}
return d;
return val(f);
}
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const
return create_node("dotproduct", Type::Float, {{"in1", *this}, {"in2", other}});
}
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
@ -375,7 +422,7 @@ NodeItem NodeItem::convert(Type to_type) const
}
if (to_type == Type::Float) {
return extract(0);
return (*this)[0];
}
/* Converting types which requires > 1 iteration */
@ -601,13 +648,6 @@ NodeItem NodeItem::if_else(CompareOp op,
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
{
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[](int index) 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 max(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(float min_val = 0.0f, float max_val = 1.0f) const;
NodeItem sin() const;
@ -105,7 +106,6 @@ class NodeItem {
const NodeItem &other,
const NodeItem &if_val,
const NodeItem &else_val) const;
NodeItem extract(const int index) const;
/* Useful functions */
NodeItem empty() const;

View File

@ -146,13 +146,18 @@ NodeItem NodeParser::empty() const
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();
res.node = graph_->getNode(TEXCOORD_NODE_NAME);
res.node = graph_->getNode(name);
if (!res.node) {
res = create_node("texcoord", NodeItem::Type::Vector2);
res.node->setName(TEXCOORD_NODE_NAME);
res = create_node("texcoord", type);
res.node->setName(name);
}
return res;
}

View File

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

View File

@ -41,7 +41,7 @@ NODE_SHADER_MATERIALX_BEGIN
res = shader2 * fac;
}
else if (shader1 && shader2) {
res = create_node("mix", to_type_, {{"fg", shader2}, {"bg", shader1}, {"mix", fac}});
res = fac.mix(shader1, shader2);
}
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;
return convert.extract(index);
return convert[index];
}
#endif
NODE_SHADER_MATERIALX_END

View File

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

View File

@ -160,7 +160,7 @@ class BrickFunction : public mf::MultiFunction {
return (3.0f * ff - 2.0f * ff * f);
}
static float2 brick(float3 p,
static float2 brick(float3 pos,
float mortar_size,
float mortar_smooth,
float bias,
@ -173,17 +173,17 @@ class BrickFunction : public mf::MultiFunction {
{
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) {
brick_width *= (rownum % squash_frequency) ? 1.0f : squash_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 y = p.y - row_height * rownum;
const float x = (pos.x + offset) - brick_width * bricknum;
const float y = pos.y - row_height * rownum;
const float tint = clamp_f(
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) {
/* 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 yi = abs(int(floorf(p.y)));
const int zi = abs(int(floorf(p.z)));
const int xi = abs(int(floorf(pos.x)));
const int yi = abs(int(floorf(pos.y)));
const int zi = abs(int(floorf(pos.z)));
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);
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);
}
#endif

View File

@ -160,21 +160,21 @@ NODE_SHADER_MATERIALX_BEGIN
switch (gradient_type) {
case SHD_BLEND_LINEAR:
res = vector.extract(0);
res = vector[0];
break;
case SHD_BLEND_QUADRATIC:
res = vector.extract(0);
res = vector[0];
res = res * res;
break;
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);
break;
case SHD_BLEND_DIAGONAL:
res = (vector.extract(0) + vector.extract(1)) * val(0.5f);
res = (vector[0] + vector[1]) * val(0.5f);
break;
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;
case SHD_BLEND_QUADRATIC_SPHERE:
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")) {
res = res.extract(3);
res = res[3];
}
return res;
}

View File

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