forked from blender/blender
Code improvements + Mix node #30
@ -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_);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -250,7 +250,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
}
|
||||
|
||||
if (STREQ(socket_out_->name, "Alpha")) {
|
||||
res = res.extract(3);
|
||||
res = res[3];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user