Shading: Add more operators to Vector Math node.

Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.

The patch doesn't include tests for the new operators. Tests will be added
in a later patch.

Reviewers: brecht, JacquesLucke

Differential Revision: https://developer.blender.org/D5523
This commit is contained in:
OmarSquircleArt 2019-08-21 19:36:33 +02:00
parent 6785da095d
commit 7f4a2fc437
Notes: blender-bot 2023-02-13 22:39:58 +01:00
Referenced by commit bc1781cf6a, EEVEE: Fix broken bump regression
32 changed files with 971 additions and 310 deletions

View File

@ -224,7 +224,9 @@ ForEachMacros:
- LISTBASE_CIRCULAR_BACKWARD_BEGIN
- LISTBASE_CIRCULAR_FORWARD_BEGIN
- LISTBASE_FOREACH
- LISTBASE_FOREACH_BACKWARD
- LISTBASE_FOREACH_MUTABLE
- LISTBASE_FOREACH_BACKWARD_MUTABLE
- MAN2D_ITER_AXES_BEGIN
- MAN_ITER_AXES_BEGIN
- NODE_INSTANCE_HASH_ITER

View File

@ -1481,8 +1481,8 @@ void BlenderSession::update_resumable_tile_manager(int num_samples)
/* Round after doing the multiplications with num_chunks and num_samples_per_chunk
* to allow for many small chunks. */
int rounded_range_start_sample = (int)floor(range_start_sample + 0.5f);
int rounded_range_num_samples = max((int)floor(range_num_samples + 0.5f), 1);
int rounded_range_start_sample = (int)floorf(range_start_sample + 0.5f);
int rounded_range_num_samples = max((int)floorf(range_num_samples + 0.5f), 1);
/* Make sure we don't overshoot. */
if (rounded_range_start_sample + rounded_range_num_samples > num_samples) {

View File

@ -333,9 +333,9 @@ static ShaderNode *add_node(Scene *scene,
}
else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
VectorMathNode *vmath = new VectorMathNode();
vmath->type = (NodeVectorMath)b_vector_math_node.operation();
node = vmath;
VectorMathNode *vector_math_node = new VectorMathNode();
vector_math_node->type = (NodeVectorMathType)b_vector_math_node.operation();
node = vector_math_node;
}
else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);

View File

@ -16,34 +16,97 @@
#include "stdosl.h"
float safe_divide(float a, float b)
{
return (b != 0.0) ? a / b : 0.0;
}
vector safe_divide(vector a, vector b)
{
return vector((b[0] != 0.0) ? a[0] / b[0] : 0.0,
(b[1] != 0.0) ? a[1] / b[1] : 0.0,
(b[2] != 0.0) ? a[2] / b[2] : 0.0);
}
vector project(vector v, vector v_proj)
{
float lenSquared = dot(v_proj, v_proj);
return (lenSquared != 0.0) ? (dot(v, v_proj) / lenSquared) * v_proj : vector(0.0);
}
vector snap(vector a, vector b)
{
return floor(safe_divide(a, b)) * b;
}
shader node_vector_math(string type = "add",
vector Vector1 = vector(0.0, 0.0, 0.0),
vector Vector2 = vector(0.0, 0.0, 0.0),
float Scale = 1.0,
output float Value = 0.0,
output vector Vector = vector(0.0, 0.0, 0.0))
{
if (type == "add") {
Vector = Vector1 + Vector2;
Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0;
}
else if (type == "subtract") {
Vector = Vector1 - Vector2;
Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0;
}
else if (type == "average") {
Value = length(Vector1 + Vector2);
Vector = normalize(Vector1 + Vector2);
else if (type == "multiply") {
Vector = Vector1 * Vector2;
}
else if (type == "divide") {
Vector = safe_divide(Vector1, Vector2);
}
else if (type == "cross_product") {
Vector = cross(Vector1, Vector2);
}
else if (type == "project") {
Vector = project(Vector1, Vector2);
}
else if (type == "reflect") {
Vector = reflect(Vector1, normalize(Vector2));
}
else if (type == "dot_product") {
Value = dot(Vector1, Vector2);
}
else if (type == "cross_product") {
vector c = cross(Vector1, Vector2);
Value = length(c);
Vector = normalize(c);
else if (type == "distance") {
Value = distance(Vector1, Vector2);
}
else if (type == "length") {
Value = length(Vector1);
}
else if (type == "scale") {
Vector = Vector1 * Scale;
}
else if (type == "normalize") {
Value = length(Vector1);
Vector = normalize(Vector1);
}
else if (type == "snap") {
Vector = snap(Vector1, Vector2);
}
else if (type == "floor") {
Vector = floor(Vector1);
}
else if (type == "ceil") {
Vector = ceil(Vector1);
}
else if (type == "modulo") {
Vector = mod(Vector1, Vector2);
}
else if (type == "fraction") {
Vector = Vector1 - floor(Vector1);
}
else if (type == "absolute") {
Vector = abs(Vector1);
}
else if (type == "minimum") {
Vector = min(Vector1, Vector2);
}
else if (type == "maximum") {
Vector = max(Vector1, Vector2);
}
else {
warning("%s", "Unknown vector math operator!");
}
}

View File

@ -37,25 +37,29 @@ ccl_device void svm_node_math(KernelGlobals *kg,
ccl_device void svm_node_vector_math(KernelGlobals *kg,
ShaderData *sd,
float *stack,
uint itype,
uint v1_offset,
uint v2_offset,
uint type,
uint inputs_stack_offsets,
uint outputs_stack_offsets,
int *offset)
{
NodeVectorMath type = (NodeVectorMath)itype;
float3 v1 = stack_load_float3(stack, v1_offset);
float3 v2 = stack_load_float3(stack, v2_offset);
float f;
float3 v;
uint value_stack_offset, vector_stack_offset;
uint a_stack_offset, b_stack_offset, scale_stack_offset;
decode_node_uchar4(
inputs_stack_offsets, &a_stack_offset, &b_stack_offset, &scale_stack_offset, NULL);
decode_node_uchar4(outputs_stack_offsets, &value_stack_offset, &vector_stack_offset, NULL, NULL);
svm_vector_math(&f, &v, type, v1, v2);
float3 a = stack_load_float3(stack, a_stack_offset);
float3 b = stack_load_float3(stack, b_stack_offset);
float scale = stack_load_float(stack, scale_stack_offset);
uint4 node1 = read_node(kg, offset);
float value;
float3 vector;
svm_vector_math(&value, &vector, (NodeVectorMathType)type, a, b, scale);
if (stack_valid(node1.y))
stack_store_float(stack, node1.y, f);
if (stack_valid(node1.z))
stack_store_float3(stack, node1.z, v);
if (stack_valid(value_stack_offset))
stack_store_float(stack, value_stack_offset, value);
if (stack_valid(vector_stack_offset))
stack_store_float3(stack, vector_stack_offset, vector);
}
CCL_NAMESPACE_END

View File

@ -16,38 +16,73 @@
CCL_NAMESPACE_BEGIN
ccl_device float average_fac(float3 v)
{
return (fabsf(v.x) + fabsf(v.y) + fabsf(v.z)) / 3.0f;
}
ccl_device void svm_vector_math(
float *Fac, float3 *Vector, NodeVectorMath type, float3 Vector1, float3 Vector2)
float *value, float3 *vector, NodeVectorMathType type, float3 a, float3 b, float scale)
{
if (type == NODE_VECTOR_MATH_ADD) {
*Vector = Vector1 + Vector2;
*Fac = average_fac(*Vector);
}
else if (type == NODE_VECTOR_MATH_SUBTRACT) {
*Vector = Vector1 - Vector2;
*Fac = average_fac(*Vector);
}
else if (type == NODE_VECTOR_MATH_AVERAGE) {
*Vector = safe_normalize_len(Vector1 + Vector2, Fac);
}
else if (type == NODE_VECTOR_MATH_DOT_PRODUCT) {
*Fac = dot(Vector1, Vector2);
*Vector = make_float3(0.0f, 0.0f, 0.0f);
}
else if (type == NODE_VECTOR_MATH_CROSS_PRODUCT) {
*Vector = safe_normalize_len(cross(Vector1, Vector2), Fac);
}
else if (type == NODE_VECTOR_MATH_NORMALIZE) {
*Vector = safe_normalize_len(Vector1, Fac);
}
else {
*Fac = 0.0f;
*Vector = make_float3(0.0f, 0.0f, 0.0f);
switch (type) {
case NODE_VECTOR_MATH_ADD:
*vector = a + b;
break;
case NODE_VECTOR_MATH_SUBTRACT:
*vector = a - b;
break;
case NODE_VECTOR_MATH_MULTIPLY:
*vector = a * b;
break;
case NODE_VECTOR_MATH_DIVIDE:
*vector = safe_divide_float3_float3(a, b);
break;
case NODE_VECTOR_MATH_CROSS_PRODUCT:
*vector = cross(a, b);
break;
case NODE_VECTOR_MATH_PROJECT:
*vector = project(a, b);
break;
case NODE_VECTOR_MATH_REFLECT:
*vector = reflect(a, b);
break;
case NODE_VECTOR_MATH_DOT_PRODUCT:
*value = dot(a, b);
break;
case NODE_VECTOR_MATH_DISTANCE:
*value = distance(a, b);
break;
case NODE_VECTOR_MATH_LENGTH:
*value = len(a);
break;
case NODE_VECTOR_MATH_SCALE:
*vector = a * scale;
break;
case NODE_VECTOR_MATH_NORMALIZE:
*vector = safe_normalize(a);
break;
case NODE_VECTOR_MATH_SNAP:
*vector = floor(safe_divide_float3_float3(a, b)) * b;
break;
case NODE_VECTOR_MATH_FLOOR:
*vector = floor(a);
break;
case NODE_VECTOR_MATH_CEIL:
*vector = ceil(a);
break;
case NODE_VECTOR_MATH_MODULO:
*vector = make_float3(safe_modulo(a.x, b.x), safe_modulo(a.y, b.y), safe_modulo(a.z, b.z));
break;
case NODE_VECTOR_MATH_FRACTION:
*vector = fract(a);
break;
case NODE_VECTOR_MATH_ABSOLUTE:
*vector = fabs(a);
break;
case NODE_VECTOR_MATH_MINIMUM:
*vector = min(a, b);
break;
case NODE_VECTOR_MATH_MAXIMUM:
*vector = max(a, b);
break;
default:
*vector = make_float3(0.0f, 0.0f, 0.0f);
*value = 0.0f;
}
}

View File

@ -271,14 +271,31 @@ typedef enum NodeMathType {
NODE_MATH_SQRT,
} NodeMathType;
typedef enum NodeVectorMath {
typedef enum NodeVectorMathType {
NODE_VECTOR_MATH_ADD,
NODE_VECTOR_MATH_SUBTRACT,
NODE_VECTOR_MATH_AVERAGE,
NODE_VECTOR_MATH_DOT_PRODUCT,
NODE_VECTOR_MATH_MULTIPLY,
NODE_VECTOR_MATH_DIVIDE,
NODE_VECTOR_MATH_CROSS_PRODUCT,
NODE_VECTOR_MATH_NORMALIZE
} NodeVectorMath;
NODE_VECTOR_MATH_PROJECT,
NODE_VECTOR_MATH_REFLECT,
NODE_VECTOR_MATH_DOT_PRODUCT,
NODE_VECTOR_MATH_DISTANCE,
NODE_VECTOR_MATH_LENGTH,
NODE_VECTOR_MATH_SCALE,
NODE_VECTOR_MATH_NORMALIZE,
NODE_VECTOR_MATH_SNAP,
NODE_VECTOR_MATH_FLOOR,
NODE_VECTOR_MATH_CEIL,
NODE_VECTOR_MATH_MODULO,
NODE_VECTOR_MATH_FRACTION,
NODE_VECTOR_MATH_ABSOLUTE,
NODE_VECTOR_MATH_MINIMUM,
NODE_VECTOR_MATH_MAXIMUM,
} NodeVectorMathType;
typedef enum NodeVectorTransformType {
NODE_VECTOR_TRANSFORM_TYPE_VECTOR,

View File

@ -124,7 +124,7 @@ BakeData *BakeManager::init(const int object, const size_t tri_offset, const siz
void BakeManager::set_shader_limit(const size_t x, const size_t y)
{
m_shader_limit = x * y;
m_shader_limit = (size_t)pow(2, ceil(log(m_shader_limit) / log(2)));
m_shader_limit = (size_t)pow(2, std::ceil(log(m_shader_limit) / log(2)));
}
bool BakeManager::bake(Device *device,

View File

@ -359,10 +359,11 @@ void ConstantFolder::fold_math(NodeMathType type) const
}
}
void ConstantFolder::fold_vector_math(NodeVectorMath type) const
void ConstantFolder::fold_vector_math(NodeVectorMathType type) const
{
ShaderInput *vector1_in = node->input("Vector1");
ShaderInput *vector2_in = node->input("Vector2");
ShaderInput *scale_in = node->input("Scale");
switch (type) {
case NODE_VECTOR_MATH_ADD:
@ -380,6 +381,27 @@ void ConstantFolder::fold_vector_math(NodeVectorMath type) const
try_bypass_or_make_constant(vector1_in);
}
break;
case NODE_VECTOR_MATH_MULTIPLY:
/* X * 0 == 0 * X == 0 */
if (is_zero(vector1_in) || is_zero(vector2_in)) {
make_zero();
} /* X * 1 == 1 * X == X */
else if (is_one(vector1_in)) {
try_bypass_or_make_constant(vector2_in);
}
else if (is_one(vector2_in)) {
try_bypass_or_make_constant(vector1_in);
}
break;
case NODE_VECTOR_MATH_DIVIDE:
/* X / 0 == 0 / X == 0 */
if (is_zero(vector1_in) || is_zero(vector2_in)) {
make_zero();
} /* X / 1 == X */
else if (is_one(vector2_in)) {
try_bypass_or_make_constant(vector1_in);
}
break;
case NODE_VECTOR_MATH_DOT_PRODUCT:
case NODE_VECTOR_MATH_CROSS_PRODUCT:
/* X * 0 == 0 * X == 0 */
@ -387,6 +409,21 @@ void ConstantFolder::fold_vector_math(NodeVectorMath type) const
make_zero();
}
break;
case NODE_VECTOR_MATH_LENGTH:
case NODE_VECTOR_MATH_ABSOLUTE:
if (is_zero(vector1_in)) {
make_zero();
}
break;
case NODE_VECTOR_MATH_SCALE:
/* X * 0 == 0 * X == 0 */
if (is_zero(vector1_in) || is_zero(scale_in)) {
make_zero();
} /* X * 1 == X */
else if (is_one(scale_in)) {
try_bypass_or_make_constant(vector1_in);
}
break;
default:
break;
}

View File

@ -65,7 +65,7 @@ class ConstantFolder {
/* Specific nodes. */
void fold_mix(NodeMix type, bool clamp) const;
void fold_math(NodeMathType type) const;
void fold_vector_math(NodeVectorMath type) const;
void fold_vector_math(NodeVectorMathType type) const;
};
CCL_NAMESPACE_END

View File

@ -163,8 +163,10 @@ void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_ou
}
if (type == NORMAL) {
compiler.add_node(NODE_VECTOR_MATH, NODE_VECTOR_MATH_NORMALIZE, offset_out, offset_out);
compiler.add_node(NODE_VECTOR_MATH, SVM_STACK_INVALID, offset_out);
compiler.add_node(NODE_VECTOR_MATH,
NODE_VECTOR_MATH_NORMALIZE,
compiler.encode_uchar4(offset_out, offset_out, offset_out),
compiler.encode_uchar4(SVM_STACK_INVALID, offset_out));
}
}
@ -5496,14 +5498,32 @@ NODE_DEFINE(VectorMathNode)
static NodeEnum type_enum;
type_enum.insert("add", NODE_VECTOR_MATH_ADD);
type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE);
type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
type_enum.insert("multiply", NODE_VECTOR_MATH_MULTIPLY);
type_enum.insert("divide", NODE_VECTOR_MATH_DIVIDE);
type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT);
type_enum.insert("project", NODE_VECTOR_MATH_PROJECT);
type_enum.insert("reflect", NODE_VECTOR_MATH_REFLECT);
type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
type_enum.insert("distance", NODE_VECTOR_MATH_DISTANCE);
type_enum.insert("length", NODE_VECTOR_MATH_LENGTH);
type_enum.insert("scale", NODE_VECTOR_MATH_SCALE);
type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE);
type_enum.insert("snap", NODE_VECTOR_MATH_SNAP);
type_enum.insert("floor", NODE_VECTOR_MATH_FLOOR);
type_enum.insert("ceil", NODE_VECTOR_MATH_CEIL);
type_enum.insert("modulo", NODE_VECTOR_MATH_MODULO);
type_enum.insert("fraction", NODE_VECTOR_MATH_FRACTION);
type_enum.insert("absolute", NODE_VECTOR_MATH_ABSOLUTE);
type_enum.insert("minimum", NODE_VECTOR_MATH_MINIMUM);
type_enum.insert("maximum", NODE_VECTOR_MATH_MAXIMUM);
SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
SOCKET_OUT_FLOAT(value, "Value");
SOCKET_OUT_VECTOR(vector, "Vector");
@ -5521,8 +5541,7 @@ void VectorMathNode::constant_fold(const ConstantFolder &folder)
float3 vector;
if (folder.all_inputs_constant()) {
svm_vector_math(&value, &vector, type, vector1, vector2);
svm_vector_math(&value, &vector, type, vector1, vector2, scale);
if (folder.output == output("Value")) {
folder.make_constant(value);
}
@ -5539,15 +5558,21 @@ void VectorMathNode::compile(SVMCompiler &compiler)
{
ShaderInput *vector1_in = input("Vector1");
ShaderInput *vector2_in = input("Vector2");
ShaderInput *scale_in = input("Scale");
ShaderOutput *value_out = output("Value");
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_MATH,
type,
compiler.stack_assign(vector1_in),
compiler.stack_assign(vector2_in));
int vector1_stack_offset = compiler.stack_assign(vector1_in);
int vector2_stack_offset = compiler.stack_assign(vector2_in);
int scale_stack_offset = compiler.stack_assign(scale_in);
int value_stack_offset = compiler.stack_assign_if_linked(value_out);
int vector_stack_offset = compiler.stack_assign_if_linked(vector_out);
compiler.add_node(
NODE_VECTOR_MATH, compiler.stack_assign(value_out), compiler.stack_assign(vector_out));
NODE_VECTOR_MATH,
type,
compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, scale_stack_offset),
compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
}
void VectorMathNode::compile(OSLCompiler &compiler)

View File

@ -1292,7 +1292,8 @@ class VectorMathNode : public ShaderNode {
float3 vector1;
float3 vector2;
NodeVectorMath type;
float scale;
NodeVectorMathType type;
};
class VectorTransformNode : public ShaderNode {

View File

@ -323,8 +323,8 @@ void QuadDice::dice(SubPatch &sub, EdgeFactors &ef)
float S = 1.0f;
#endif
Mu = max((int)ceil(S * Mu), 2); // XXX handle 0 & 1?
Mv = max((int)ceil(S * Mv), 2); // XXX handle 0 & 1?
Mu = max((int)ceilf(S * Mu), 2); // XXX handle 0 & 1?
Mv = max((int)ceilf(S * Mv), 2); // XXX handle 0 & 1?
/* reserve space for new verts */
int offset = params.mesh->verts.size();

View File

@ -80,9 +80,9 @@ int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend)
Plast = P;
}
int tmin = (int)ceil(Lsum / params.dicing_rate);
int tmax = (int)ceil((params.test_steps - 1) * Lmax /
params.dicing_rate); // XXX paper says N instead of N-1, seems wrong?
int tmin = (int)ceilf(Lsum / params.dicing_rate);
int tmax = (int)ceilf((params.test_steps - 1) * Lmax /
params.dicing_rate); // XXX paper says N instead of N-1, seems wrong?
if (tmax - tmin > params.split_threshold)
return DSPLIT_NON_UNIFORM;
@ -99,7 +99,7 @@ void DiagSplit::partition_edge(
*t1 = T(patch, *P, Pend);
}
else {
int I = (int)floor((float)t * 0.5f);
int I = (int)floorf((float)t * 0.5f);
*P = interp(Pstart, Pend, (t == 0) ? 0 : I / (float)t); /* XXX is t faces or verts */
*t0 = I;
*t1 = t - I;

View File

@ -1163,21 +1163,14 @@ TEST_F(RenderGraph, constant_fold_part_math_pow_1)
TEST_F(RenderGraph, constant_fold_vector_math)
{
EXPECT_ANY_MESSAGE(log);
CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Value to constant (1).");
CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Vector to constant (3, 0, 0).");
CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_float::value_float to constant (1).");
CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (2).");
CORRECT_INFO_MESSAGE(log, "Folding convert_float_to_color::value_color to constant (2, 2, 2).");
builder
.add_node(ShaderNodeBuilder<VectorMathNode>("VectorMath")
.set(&VectorMathNode::type, NODE_VECTOR_MATH_SUBTRACT)
.set("Vector1", make_float3(1.3f, 0.5f, 0.7f))
.set("Vector2", make_float3(-1.7f, 0.5f, 0.7f)))
.add_node(ShaderNodeBuilder<MathNode>("Math").set(&MathNode::type, NODE_MATH_ADD))
.add_connection("VectorMath::Vector", "Math::Value1")
.add_connection("VectorMath::Value", "Math::Value2")
.output_color("Math::Value");
.output_color("VectorMath::Vector");
graph.finalize(scene);
}
@ -1187,7 +1180,7 @@ TEST_F(RenderGraph, constant_fold_vector_math)
* Includes 2 tests: constant on each side.
*/
static void build_vecmath_partial_test_graph(ShaderGraphBuilder &builder,
NodeVectorMath type,
NodeVectorMathType type,
float3 constval)
{
builder
@ -1240,22 +1233,6 @@ TEST_F(RenderGraph, constant_fold_part_vecmath_sub_0)
graph.finalize(scene);
}
/*
* Tests: partial folding for Vector Math Dot Product with known 0.
*/
TEST_F(RenderGraph, constant_fold_part_vecmath_dot_0)
{
EXPECT_ANY_MESSAGE(log);
/* X * 0 == 0 * X == X */
CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to constant (0, 0, 0).");
CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to constant (0, 0, 0).");
CORRECT_INFO_MESSAGE(log, "Folding Out::Vector to constant (0, 0, 0).");
CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode.");
build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_DOT_PRODUCT, make_float3(0, 0, 0));
graph.finalize(scene);
}
/*
* Tests: partial folding for Vector Math Cross Product with known 0.
*/

View File

@ -47,6 +47,7 @@ ccl_device_inline float3 operator/=(float3 &a, float f);
ccl_device_inline bool operator==(const float3 &a, const float3 &b);
ccl_device_inline bool operator!=(const float3 &a, const float3 &b);
ccl_device_inline float distance(const float3 &a, const float3 &b);
ccl_device_inline float dot(const float3 &a, const float3 &b);
ccl_device_inline float dot_xy(const float3 &a, const float3 &b);
ccl_device_inline float3 cross(const float3 &a, const float3 &b);
@ -58,6 +59,9 @@ ccl_device_inline float3 fabs(const float3 &a);
ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t);
ccl_device_inline float3 rcp(const float3 &a);
ccl_device_inline float3 sqrt(const float3 &a);
ccl_device_inline float3 floor(const float3 &a);
ccl_device_inline float3 ceil(const float3 &a);
ccl_device_inline float3 fract(const float3 &a);
#endif /* !__KERNEL_OPENCL__ */
ccl_device_inline float min3(float3 a);
@ -65,10 +69,15 @@ ccl_device_inline float max3(float3 a);
ccl_device_inline float len(const float3 a);
ccl_device_inline float len_squared(const float3 a);
ccl_device_inline float3 reflect(const float3 incident, const float3 normal);
ccl_device_inline float3 project(const float3 v, const float3 v_proj);
ccl_device_inline float3 saturate3(float3 a);
ccl_device_inline float3 safe_normalize(const float3 a);
ccl_device_inline float3 normalize_len(const float3 a, float *t);
ccl_device_inline float3 safe_normalize_len(const float3 a, float *t);
ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b);
ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b);
ccl_device_inline float3 interp(float3 a, float3 b, float t);
ccl_device_inline float3 sqr3(float3 a);
@ -205,6 +214,11 @@ ccl_device_inline bool operator!=(const float3 &a, const float3 &b)
return !(a == b);
}
ccl_device_inline float distance(const float3 &a, const float3 &b)
{
return len(a - b);
}
ccl_device_inline float dot(const float3 &a, const float3 &b)
{
# if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
@ -281,6 +295,29 @@ ccl_device_inline float3 sqrt(const float3 &a)
# endif
}
ccl_device_inline float3 floor(const float3 &a)
{
# ifdef __KERNEL_SSE__
return float3(_mm_floor_ps(a));
# else
return make_float3(floorf(a.x), floorf(a.y), floorf(a.z));
# endif
}
ccl_device_inline float3 ceil(const float3 &a)
{
# ifdef __KERNEL_SSE__
return float3(_mm_ceil_ps(a));
# else
return make_float3(ceilf(a.x), ceilf(a.y), ceilf(a.z));
# endif
}
ccl_device_inline float3 fract(const float3 &a)
{
return a - floor(a);
}
ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t)
{
return a + t * (b - a);
@ -321,6 +358,19 @@ ccl_device_inline float len_squared(const float3 a)
return dot(a, a);
}
ccl_device_inline float3 reflect(const float3 incident, const float3 normal)
{
float3 unit_normal = normalize(normal);
return incident - 2.0f * unit_normal * dot(incident, unit_normal);
}
ccl_device_inline float3 project(const float3 v, const float3 v_proj)
{
float len_squared = dot(v_proj, v_proj);
return (len_squared != 0.0f) ? (dot(v, v_proj) / len_squared) * v_proj :
make_float3(0.0f, 0.0f, 0.0f);
}
ccl_device_inline float3 saturate3(float3 a)
{
return make_float3(saturate(a.x), saturate(a.y), saturate(a.z));
@ -345,6 +395,18 @@ ccl_device_inline float3 safe_normalize_len(const float3 a, float *t)
return (*t != 0.0f) ? a / (*t) : a;
}
ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b)
{
return make_float3((b.x != 0.0f) ? a.x / b.x : 0.0f,
(b.y != 0.0f) ? a.y / b.y : 0.0f,
(b.z != 0.0f) ? a.z / b.z : 0.0f);
}
ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b)
{
return (b != 0.0f) ? a / b : make_float3(0.0f, 0.0f, 0.0f);
}
ccl_device_inline float3 interp(float3 a, float3 b, float t)
{
return a + t * (b - a);

View File

@ -895,7 +895,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_CURVE_RGB 111
#define SH_NODE_CAMERA 114
#define SH_NODE_MATH 115
#define SH_NODE_VECT_MATH 116
#define SH_NODE_VECTOR_MATH 116
#define SH_NODE_SQUEEZE 117
//#define SH_NODE_MATERIAL_EXT 118
#define SH_NODE_INVERT 119

View File

@ -3232,11 +3232,6 @@ void ntreeTagUsedSockets(bNodeTree *ntree)
}
for (link = ntree->links.first; link; link = link->next) {
/* link is unused if either side is disabled */
if ((link->fromsock->flag & SOCK_UNAVAIL) || (link->tosock->flag & SOCK_UNAVAIL)) {
continue;
}
link->fromsock->flag |= SOCK_IN_USE;
link->tosock->flag |= SOCK_IN_USE;
}

View File

@ -171,12 +171,21 @@ struct LinkData *BLI_genericNodeN(void *data);
#define LISTBASE_FOREACH(type, var, list) \
for (type var = (type)((list)->first); var != NULL; var = (type)(((Link *)(var))->next))
#define LISTBASE_FOREACH_BACKWARD(type, var, list) \
for (type var = (type)((list)->last); var != NULL; var = (type)(((Link *)(var))->prev))
/** A version of #LISTBASE_FOREACH that supports removing the item we're looping over. */
#define LISTBASE_FOREACH_MUTABLE(type, var, list) \
for (type var = (type)((list)->first), *var##_iter_next; \
((var != NULL) ? ((void)(var##_iter_next = (type)(((Link *)(var))->next)), 1) : 0); \
var = var##_iter_next)
/** A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over. */
#define LISTBASE_FOREACH_BACKWARD_MUTABLE(type, var, list) \
for (type var = (type)((list)->last), *var##_iter_prev; \
((var != NULL) ? ((void)(var##_iter_prev = (type)(((Link *)(var))->prev)), 1) : 0); \
var = var##_iter_prev)
#ifdef __cplusplus
}
#endif

View File

@ -45,6 +45,11 @@
#include "BLO_readfile.h"
#include "readfile.h"
static bool socket_is_used(bNodeSocket *sock)
{
return sock->flag & SOCK_IN_USE;
}
static float *cycles_node_socket_float_value(bNodeSocket *socket)
{
bNodeSocketValueFloat *socket_data = socket->default_value;
@ -57,6 +62,12 @@ static float *cycles_node_socket_rgba_value(bNodeSocket *socket)
return socket_data->value;
}
static float *cycles_node_socket_vector_value(bNodeSocket *socket)
{
bNodeSocketValueVector *socket_data = socket->default_value;
return socket_data->value;
}
static IDProperty *cycles_properties_from_ID(ID *id)
{
IDProperty *idprop = IDP_GetProperties(id, false);
@ -426,6 +437,325 @@ static void update_math_node_single_operand_operators(bNodeTree *ntree)
}
}
/* The Value output of the Vector Math node is no longer available in the Add
* and Subtract operators. Previously, this Value output was computed from the
* Vector output V as follows:
*
* Value = (abs(V.x) + abs(V.y) + abs(V.z)) / 3
*
* Or more compactly using vector operators:
*
* Value = dot(abs(V), (1 / 3, 1 / 3, 1 / 3))
*
* To correct this, if the Value output was used, we are going to compute
* it using the second equation by adding an absolute and a dot node, and
* then connect them appropriately.
*/
static void update_vector_math_node_add_and_subtract_operators(bNodeTree *ntree)
{
bool need_update = false;
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_VECTOR_MATH) {
bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
if (socket_is_used(sockOutValue) &&
ELEM(node->custom1, NODE_VECTOR_MATH_ADD, NODE_VECTOR_MATH_SUBTRACT)) {
bNode *absNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
absNode->custom1 = NODE_VECTOR_MATH_ABSOLUTE;
absNode->locx = node->locx + node->width + 20.0f;
absNode->locy = node->locy;
bNode *dotNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
dotNode->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
dotNode->locx = absNode->locx + absNode->width + 20.0f;
dotNode->locy = absNode->locy;
bNodeSocket *sockDotB = BLI_findlink(&dotNode->inputs, 1);
bNodeSocket *sockDotOutValue = nodeFindSocket(dotNode, SOCK_OUT, "Value");
copy_v3_fl(cycles_node_socket_vector_value(sockDotB), 1 / 3.0f);
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sockOutValue) {
nodeAddLink(ntree, dotNode, sockDotOutValue, link->tonode, link->tosock);
nodeRemLink(ntree, link);
}
}
bNodeSocket *sockAbsA = BLI_findlink(&absNode->inputs, 0);
bNodeSocket *sockDotA = BLI_findlink(&dotNode->inputs, 0);
bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
bNodeSocket *sockAbsOutVector = nodeFindSocket(absNode, SOCK_OUT, "Vector");
nodeAddLink(ntree, node, sockOutVector, absNode, sockAbsA);
nodeAddLink(ntree, absNode, sockAbsOutVector, dotNode, sockDotA);
need_update = true;
}
}
}
if (need_update) {
ntreeUpdateTree(NULL, ntree);
}
}
/* The Vector output of the Vector Math node is no longer available in the Dot
* Product operator. Previously, this Vector was always zero initialized. To
* correct this, we zero out any socket the Vector Output was connected to.
*/
static void update_vector_math_node_dot_product_operator(bNodeTree *ntree)
{
bool need_update = false;
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_VECTOR_MATH) {
bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
if (socket_is_used(sockOutVector) && node->custom1 == NODE_VECTOR_MATH_DOT_PRODUCT) {
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sockOutVector) {
switch (link->tosock->type) {
case SOCK_FLOAT:
*cycles_node_socket_float_value(link->tosock) = 0.0f;
break;
case SOCK_VECTOR:
copy_v3_fl(cycles_node_socket_vector_value(link->tosock), 0.0f);
break;
case SOCK_RGBA:
copy_v4_fl(cycles_node_socket_rgba_value(link->tosock), 0.0f);
break;
}
nodeRemLink(ntree, link);
}
}
need_update = true;
}
}
}
if (need_update) {
ntreeUpdateTree(NULL, ntree);
}
}
/* Previously, the Vector output of the cross product operator was normalized.
* To correct this, a Normalize node is added to normalize the output if used.
* Moreover, the Value output was removed. This Value was equal to the length
* of the cross product. To correct this, a Length node is added if needed.
*/
static void update_vector_math_node_cross_product_operator(bNodeTree *ntree)
{
bool need_update = false;
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_VECTOR_MATH) {
if (node->custom1 == NODE_VECTOR_MATH_CROSS_PRODUCT) {
bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
if (socket_is_used(sockOutVector)) {
bNode *normalizeNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
normalizeNode->custom1 = NODE_VECTOR_MATH_NORMALIZE;
normalizeNode->locx = node->locx + node->width + 20.0f;
normalizeNode->locy = node->locy;
bNodeSocket *sockNormalizeOut = nodeFindSocket(normalizeNode, SOCK_OUT, "Vector");
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sockOutVector) {
nodeAddLink(ntree, normalizeNode, sockNormalizeOut, link->tonode, link->tosock);
nodeRemLink(ntree, link);
}
}
bNodeSocket *sockNormalizeA = BLI_findlink(&normalizeNode->inputs, 0);
nodeAddLink(ntree, node, sockOutVector, normalizeNode, sockNormalizeA);
need_update = true;
}
bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
if (socket_is_used(sockOutValue)) {
bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH;
lengthNode->locx = node->locx + node->width + 20.0f;
if (socket_is_used(sockOutVector)) {
lengthNode->locy = node->locy - lengthNode->height - 20.0f;
}
else {
lengthNode->locy = node->locy;
}
bNodeSocket *sockLengthOut = nodeFindSocket(lengthNode, SOCK_OUT, "Value");
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sockOutValue) {
nodeAddLink(ntree, lengthNode, sockLengthOut, link->tonode, link->tosock);
nodeRemLink(ntree, link);
}
}
bNodeSocket *sockLengthA = BLI_findlink(&lengthNode->inputs, 0);
nodeAddLink(ntree, node, sockOutVector, lengthNode, sockLengthA);
need_update = true;
}
}
}
}
if (need_update) {
ntreeUpdateTree(NULL, ntree);
}
}
/* The Value output of the Vector Math node is no longer available in the
* Normalize operator. This Value output was equal to the length of the
* the input vector A. To correct this, we either add a Length node or
* convert the Normalize node into a Length node, depending on if the
* Vector output is needed.
*/
static void update_vector_math_node_normalize_operator(bNodeTree *ntree)
{
bool need_update = false;
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_VECTOR_MATH) {
bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
if (node->custom1 == NODE_VECTOR_MATH_NORMALIZE && socket_is_used(sockOutValue)) {
bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
if (socket_is_used(sockOutVector)) {
bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH;
lengthNode->locx = node->locx + node->width + 20.0f;
lengthNode->locy = node->locy;
bNodeSocket *sockLengthValue = nodeFindSocket(lengthNode, SOCK_OUT, "Value");
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sockOutValue) {
nodeAddLink(ntree, lengthNode, sockLengthValue, link->tonode, link->tosock);
nodeRemLink(ntree, link);
}
}
bNodeSocket *sockA = BLI_findlink(&node->inputs, 0);
bNodeSocket *sockLengthA = BLI_findlink(&lengthNode->inputs, 0);
if (sockA->link) {
bNodeLink *link = sockA->link;
nodeAddLink(ntree, link->fromnode, link->fromsock, lengthNode, sockLengthA);
}
else {
copy_v3_v3(cycles_node_socket_vector_value(sockLengthA),
cycles_node_socket_vector_value(sockA));
}
need_update = true;
}
else {
node->custom1 = NODE_VECTOR_MATH_LENGTH;
}
}
}
}
if (need_update) {
ntreeUpdateTree(NULL, ntree);
}
}
/* The Vector Math operator types didn't have an enum, but rather, their
* values were hard coded into the code. After the enum was created and
* after more vector operators were added, the hard coded values needs
* to be remapped to their correct enum values. To fix this, we remap
* the values according to the following rules:
*
* Dot Product Operator : 3 -> 7
* Normalize Operator : 5 -> 11
*
* Additionally, since the Average operator was removed, it is assigned
* a value of -1 just to be identified later in the versioning code:
*
* Average Operator : 2 -> -1
*
*/
static void update_vector_math_node_operators_enum_mapping(bNodeTree *ntree)
{
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_VECTOR_MATH) {
switch (node->custom1) {
case 2:
node->custom1 = -1;
break;
case 3:
node->custom1 = 7;
break;
case 5:
node->custom1 = 11;
break;
}
}
}
}
/* The Average operator is no longer available in the Vector Math node.
* The Vector output was equal to the normalized sum of input vectors while
* the Value output was equal to the length of the sum of input vectors.
* To correct this, we convert the node into an Add node and add a length
* node or a normalize node if needed.
*/
static void update_vector_math_node_average_operator(bNodeTree *ntree)
{
bool need_update = false;
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_VECTOR_MATH) {
/* See update_vector_math_node_operators_enum_mapping. */
if (node->custom1 == -1) {
node->custom1 = NODE_VECTOR_MATH_ADD;
bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
if (socket_is_used(sockOutVector)) {
bNode *normalizeNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
normalizeNode->custom1 = NODE_VECTOR_MATH_NORMALIZE;
normalizeNode->locx = node->locx + node->width + 20.0f;
normalizeNode->locy = node->locy;
bNodeSocket *sockNormalizeOut = nodeFindSocket(normalizeNode, SOCK_OUT, "Vector");
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sockOutVector) {
nodeAddLink(ntree, normalizeNode, sockNormalizeOut, link->tonode, link->tosock);
nodeRemLink(ntree, link);
}
}
bNodeSocket *sockNormalizeA = BLI_findlink(&normalizeNode->inputs, 0);
nodeAddLink(ntree, node, sockOutVector, normalizeNode, sockNormalizeA);
need_update = true;
}
bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
if (socket_is_used(sockOutValue)) {
bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH;
lengthNode->locx = node->locx + node->width + 20.0f;
if (socket_is_used(sockOutVector)) {
lengthNode->locy = node->locy - lengthNode->height - 20.0f;
}
else {
lengthNode->locy = node->locy;
}
bNodeSocket *sockLengthOut = nodeFindSocket(lengthNode, SOCK_OUT, "Value");
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sockOutValue) {
nodeAddLink(ntree, lengthNode, sockLengthOut, link->tonode, link->tosock);
nodeRemLink(ntree, link);
}
}
bNodeSocket *sockLengthA = BLI_findlink(&lengthNode->inputs, 0);
nodeAddLink(ntree, node, sockOutVector, lengthNode, sockLengthA);
need_update = true;
}
}
}
}
if (need_update) {
ntreeUpdateTree(NULL, ntree);
}
}
void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
{
/* Particle shape shared with Eevee. */
@ -458,6 +788,15 @@ void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bm
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 281, 3)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
update_vector_math_node_operators_enum_mapping(ntree);
}
}
FOREACH_NODETREE_END;
}
}
void do_versions_after_linking_cycles(Main *bmain)
@ -576,4 +915,17 @@ void do_versions_after_linking_cycles(Main *bmain)
}
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 281, 3)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
update_vector_math_node_add_and_subtract_operators(ntree);
update_vector_math_node_dot_product_operator(ntree);
update_vector_math_node_cross_product_operator(ntree);
update_vector_math_node_normalize_operator(ntree);
update_vector_math_node_average_operator(ntree);
}
}
FOREACH_NODETREE_END;
}
}

View File

@ -1220,7 +1220,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
case SH_NODE_VECT_MATH:
case SH_NODE_VECTOR_MATH:
ntype->draw_buttons = node_shader_buts_vect_math;
break;
case SH_NODE_VECT_TRANSFORM:

View File

@ -400,46 +400,118 @@ void map_range(
}
}
void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 + v2;
outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
vec3 safe_divide(vec3 a, vec3 b) {
return vec3((b.x != 0.0) ? a.x / b.x : 0.0,
(b.y != 0.0) ? a.y / b.y : 0.0,
(b.z != 0.0) ? a.z / b.z : 0.0);
}
void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
void vector_math_add(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outvec = v1 - v2;
outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
outVector = a + b;
}
void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
void vector_math_subtract(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outvec = v1 + v2;
outval = length(outvec);
outvec = normalize(outvec);
}
void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
{
outvec = strength * v1 + (1 - strength) * v2;
outVector = a - b;
}
void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
void vector_math_multiply(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outvec = vec3(0);
outval = dot(v1, v2);
outVector = a * b;
}
void vec_math_cross(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
void vector_math_divide(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outvec = cross(v1, v2);
outval = length(outvec);
outvec /= outval;
outVector = safe_divide(a, b);
}
void vec_math_normalize(vec3 v, out vec3 outvec, out float outval)
void vector_math_cross(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outval = length(v);
outvec = normalize(v);
outVector = cross(a, b);
}
void vector_math_project(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
float lenSquared = dot(b, b);
outVector = (lenSquared != 0.0) ? (dot(a, b) / lenSquared) * b : vec3(0.0);
}
void vector_math_reflect(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = reflect(a, normalize(b));
}
void vector_math_dot(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outValue = dot(a, b);
}
void vector_math_distance(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outValue = distance(a, b);
}
void vector_math_length(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outValue = length(a);
}
void vector_math_scale(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = a * scale;
}
void vector_math_normalize(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = normalize(a);
}
void vector_math_snap(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = floor(safe_divide(a, b)) * b;
}
void vector_math_floor(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = floor(a);
}
void vector_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = ceil(a);
}
void vector_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
math_modulo(a.x, b.x, outVector.x);
math_modulo(a.y, b.y, outVector.y);
math_modulo(a.z, b.z, outVector.z);
}
void vector_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = fract(a);
}
void vector_math_absolute(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = abs(a);
}
void vector_math_minimum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = min(a, b);
}
void vector_math_maximum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
outVector = max(a, b);
}
void vector_math_mix(float strength, vec3 a, vec3 b, out vec3 outVector)
{
outVector = strength * a + (1 - strength) * b;
}
void vec_math_negate(vec3 v, out vec3 outv)

View File

@ -1195,6 +1195,33 @@ enum {
NODE_MATH_SQRT = 23,
};
/* Vector Math node operations. */
enum {
NODE_VECTOR_MATH_ADD = 0,
NODE_VECTOR_MATH_SUBTRACT = 1,
NODE_VECTOR_MATH_MULTIPLY = 2,
NODE_VECTOR_MATH_DIVIDE = 3,
NODE_VECTOR_MATH_CROSS_PRODUCT = 4,
NODE_VECTOR_MATH_PROJECT = 5,
NODE_VECTOR_MATH_REFLECT = 6,
NODE_VECTOR_MATH_DOT_PRODUCT = 7,
NODE_VECTOR_MATH_DISTANCE = 8,
NODE_VECTOR_MATH_LENGTH = 9,
NODE_VECTOR_MATH_SCALE = 10,
NODE_VECTOR_MATH_NORMALIZE = 11,
NODE_VECTOR_MATH_SNAP = 12,
NODE_VECTOR_MATH_FLOOR = 13,
NODE_VECTOR_MATH_CEIL = 14,
NODE_VECTOR_MATH_MODULO = 15,
NODE_VECTOR_MATH_FRACTION = 16,
NODE_VECTOR_MATH_ABSOLUTE = 17,
NODE_VECTOR_MATH_MINIMUM = 18,
NODE_VECTOR_MATH_MAXIMUM = 19,
};
/* mix rgb node flags */
#define SHD_MIXRGB_USE_ALPHA 1
#define SHD_MIXRGB_CLAMP 2

View File

@ -136,12 +136,37 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
};
const EnumPropertyItem rna_enum_node_vec_math_items[] = {
{0, "ADD", 0, "Add", ""},
{1, "SUBTRACT", 0, "Subtract", ""},
{2, "AVERAGE", 0, "Average", ""},
{3, "DOT_PRODUCT", 0, "Dot Product", ""},
{4, "CROSS_PRODUCT", 0, "Cross Product", ""},
{5, "NORMALIZE", 0, "Normalize", ""},
{NODE_VECTOR_MATH_ADD, "ADD", 0, "Add", "A + B"},
{NODE_VECTOR_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
{NODE_VECTOR_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "Entrywise multiply"},
{NODE_VECTOR_MATH_DIVIDE, "DIVIDE", 0, "Divide", "Entrywise divide"},
{0, "", ICON_NONE, NULL, NULL},
{NODE_VECTOR_MATH_CROSS_PRODUCT, "CROSS_PRODUCT", 0, "Cross Product", "A cross B"},
{NODE_VECTOR_MATH_PROJECT, "PROJECT", 0, "Project", "Project A onto B"},
{NODE_VECTOR_MATH_REFLECT,
"REFLECT",
0,
"Reflect",
"Reflect A around the normal B. B needn't be normalized"},
{NODE_VECTOR_MATH_DOT_PRODUCT, "DOT_PRODUCT", 0, "Dot Product", "A dot B"},
{0, "", ICON_NONE, NULL, NULL},
{NODE_VECTOR_MATH_DISTANCE, "DISTANCE", 0, "Distance", "Distance between A and B"},
{NODE_VECTOR_MATH_LENGTH, "LENGTH", 0, "Length", "Length of A"},
{NODE_VECTOR_MATH_SCALE, "SCALE", 0, "Scale", "A multiplied by Scale"},
{NODE_VECTOR_MATH_NORMALIZE, "NORMALIZE", 0, "Normalize", "Normalize A"},
{0, "", ICON_NONE, NULL, NULL},
{NODE_VECTOR_MATH_SNAP,
"SNAP",
0,
"Snap",
"Round A to the largest integer multiple of B less than or equal A"},
{NODE_VECTOR_MATH_FLOOR, "FLOOR", 0, "Floor", "Entrywise floor"},
{NODE_VECTOR_MATH_CEIL, "CEIL", 0, "Ceil", "Entrywise ceil"},
{NODE_VECTOR_MATH_MODULO, "MODULO", 0, "Modulo", "Entrywise modulo"},
{NODE_VECTOR_MATH_FRACTION, "FRACTION", 0, "Fraction", "The fraction part of A entrywise"},
{NODE_VECTOR_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Entrywise absolute"},
{NODE_VECTOR_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "Entrywise minimum"},
{NODE_VECTOR_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "Entrywise maximum"},
{0, NULL, 0, NULL, NULL},
};
@ -3873,7 +3898,7 @@ static void def_vector_math(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_vec_math_items);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_rgb_curve(StructRNA *srna)

View File

@ -204,7 +204,7 @@ set(SRC
shader/nodes/node_shader_uvmap.c
shader/nodes/node_shader_valToRgb.c
shader/nodes/node_shader_value.c
shader/nodes/node_shader_vectMath.c
shader/nodes/node_shader_vector_math.c
shader/nodes/node_shader_vectTransform.c
shader/nodes/node_shader_vector_displacement.c
shader/nodes/node_shader_volume_absorption.c

View File

@ -53,7 +53,7 @@ DefNode(ShaderNode, SH_NODE_CAMERA, 0, "CAMERA
DefNode(ShaderNode, SH_NODE_MAP_RANGE, def_map_range, "MAP_RANGE", MapRange, "Map Range", "" )
DefNode(ShaderNode, SH_NODE_CLAMP, 0, "CLAMP", Clamp, "Clamp", "" )
DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode(ShaderNode, SH_NODE_VECT_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )
DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
DefNode(ShaderNode, SH_NODE_SEPRGB, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )

View File

@ -100,7 +100,7 @@ void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int max
BLI_strncpy(label, IFACE_(name), maxlen);
}
void node_vect_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
const char *name;
RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);

View File

@ -71,7 +71,7 @@ extern void *node_initexec_curves(struct bNodeExecContext *context,
void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
void node_vect_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
void node_vector_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
/*** Link Handling */

View File

@ -799,7 +799,7 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
nodeRemLink(ntree, displacement_link);
/* Convert displacement vector to bump height. */
bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECT_MATH);
bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal");
dot_node->custom1 = 3; /* dot product */

View File

@ -114,7 +114,7 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
break;
}
GPU_link(mat, "vec_math_mix", strength, realnorm, negnorm, &out[0].link);
GPU_link(mat, "vector_math_mix", strength, realnorm, negnorm, &out[0].link);
GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
return true;

View File

@ -1,155 +0,0 @@
/*
* 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) 2005 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup shdnodes
*/
#include "node_shader_util.h"
/* **************** VECTOR MATH ******************** */
static bNodeSocketTemplate sh_node_vect_math_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{-1, 0, ""}};
static bNodeSocketTemplate sh_node_vect_math_out[] = {
{SOCK_VECTOR, 0, N_("Vector")}, {SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
static void node_shader_exec_vect_math(void *UNUSED(data),
int UNUSED(thread),
bNode *node,
bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **out)
{
float vec1[3], vec2[3];
nodestack_get_vec(vec1, SOCK_VECTOR, in[0]);
nodestack_get_vec(vec2, SOCK_VECTOR, in[1]);
if (node->custom1 == 0) { /* Add */
out[0]->vec[0] = vec1[0] + vec2[0];
out[0]->vec[1] = vec1[1] + vec2[1];
out[0]->vec[2] = vec1[2] + vec2[2];
out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) /
3.0f;
}
else if (node->custom1 == 1) { /* Subtract */
out[0]->vec[0] = vec1[0] - vec2[0];
out[0]->vec[1] = vec1[1] - vec2[1];
out[0]->vec[2] = vec1[2] - vec2[2];
out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) /
3.0f;
}
else if (node->custom1 == 2) { /* Average */
out[0]->vec[0] = vec1[0] + vec2[0];
out[0]->vec[1] = vec1[1] + vec2[1];
out[0]->vec[2] = vec1[2] + vec2[2];
out[1]->vec[0] = normalize_v3(out[0]->vec);
}
else if (node->custom1 == 3) { /* Dot product */
out[1]->vec[0] = (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]);
}
else if (node->custom1 == 4) { /* Cross product */
out[0]->vec[0] = (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]);
out[0]->vec[1] = (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]);
out[0]->vec[2] = (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]);
out[1]->vec[0] = normalize_v3(out[0]->vec);
}
else if (node->custom1 == 5) { /* Normalize */
/* This one only takes one input, so we've got to choose. */
if (in[0]->hasinput || !in[1]->hasinput) {
out[0]->vec[0] = vec1[0];
out[0]->vec[1] = vec1[1];
out[0]->vec[2] = vec1[2];
}
else {
out[0]->vec[0] = vec2[0];
out[0]->vec[1] = vec2[1];
out[0]->vec[2] = vec2[2];
}
out[1]->vec[0] = normalize_v3(out[0]->vec);
}
}
static int gpu_shader_vect_math(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
static const char *names[] = {
"vec_math_add",
"vec_math_sub",
"vec_math_average",
"vec_math_dot",
"vec_math_cross",
"vec_math_normalize",
};
switch (node->custom1) {
case 0:
case 1:
case 2:
case 3:
case 4:
GPU_stack_link(mat, node, names[node->custom1], in, out);
break;
case 5:
if (in[0].hasinput || !in[1].hasinput) {
/* use only first item and terminator */
GPUNodeStack tmp_in[2];
memcpy(&tmp_in[0], &in[0], sizeof(GPUNodeStack));
memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
}
else {
/* use only second item and terminator */
GPUNodeStack tmp_in[2];
memcpy(&tmp_in[0], &in[1], sizeof(GPUNodeStack));
memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
}
break;
default:
return false;
}
return true;
}
void register_node_type_sh_vect_math(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VECT_MATH, "Vector Math", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_vect_math_in, sh_node_vect_math_out);
node_type_label(&ntype, node_vect_math_label);
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_vect_math);
node_type_gpu(&ntype, gpu_shader_vect_math);
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,113 @@
/*
* 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) 2005 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup shdnodes
*/
#include "node_shader_util.h"
/* **************** VECTOR MATH ******************** */
static bNodeSocketTemplate sh_node_vector_math_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{-1, 0, ""}};
static bNodeSocketTemplate sh_node_vector_math_out[] = {
{SOCK_VECTOR, 0, N_("Vector")}, {SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
static int gpu_shader_vector_math(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
static const char *names[] = {
[NODE_VECTOR_MATH_ADD] = "vector_math_add",
[NODE_VECTOR_MATH_SUBTRACT] = "vector_math_subtract",
[NODE_VECTOR_MATH_MULTIPLY] = "vector_math_multiply",
[NODE_VECTOR_MATH_DIVIDE] = "vector_math_divide",
[NODE_VECTOR_MATH_CROSS_PRODUCT] = "vector_math_cross",
[NODE_VECTOR_MATH_PROJECT] = "vector_math_project",
[NODE_VECTOR_MATH_REFLECT] = "vector_math_reflect",
[NODE_VECTOR_MATH_DOT_PRODUCT] = "vector_math_dot",
[NODE_VECTOR_MATH_DISTANCE] = "vector_math_distance",
[NODE_VECTOR_MATH_LENGTH] = "vector_math_length",
[NODE_VECTOR_MATH_SCALE] = "vector_math_scale",
[NODE_VECTOR_MATH_NORMALIZE] = "vector_math_normalize",
[NODE_VECTOR_MATH_SNAP] = "vector_math_snap",
[NODE_VECTOR_MATH_FLOOR] = "vector_math_floor",
[NODE_VECTOR_MATH_CEIL] = "vector_math_ceil",
[NODE_VECTOR_MATH_MODULO] = "vector_math_modulo",
[NODE_VECTOR_MATH_FRACTION] = "vector_math_fraction",
[NODE_VECTOR_MATH_ABSOLUTE] = "vector_math_absolute",
[NODE_VECTOR_MATH_MINIMUM] = "vector_math_minimum",
[NODE_VECTOR_MATH_MAXIMUM] = "vector_math_maximum",
};
GPU_stack_link(mat, node, names[node->custom1], in, out);
return true;
}
static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node)
{
bNodeSocket *sockB = BLI_findlink(&node->inputs, 1);
bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
bNodeSocket *sockVector = nodeFindSocket(node, SOCK_OUT, "Vector");
bNodeSocket *sockValue = nodeFindSocket(node, SOCK_OUT, "Value");
nodeSetSocketAvailability(sockB,
!ELEM(node->custom1,
NODE_VECTOR_MATH_CEIL,
NODE_VECTOR_MATH_SCALE,
NODE_VECTOR_MATH_FLOOR,
NODE_VECTOR_MATH_LENGTH,
NODE_VECTOR_MATH_ABSOLUTE,
NODE_VECTOR_MATH_FRACTION,
NODE_VECTOR_MATH_NORMALIZE));
nodeSetSocketAvailability(sockScale, node->custom1 == NODE_VECTOR_MATH_SCALE);
nodeSetSocketAvailability(sockVector,
!ELEM(node->custom1,
NODE_VECTOR_MATH_LENGTH,
NODE_VECTOR_MATH_DISTANCE,
NODE_VECTOR_MATH_DOT_PRODUCT));
nodeSetSocketAvailability(sockValue,
ELEM(node->custom1,
NODE_VECTOR_MATH_LENGTH,
NODE_VECTOR_MATH_DISTANCE,
NODE_VECTOR_MATH_DOT_PRODUCT));
}
void register_node_type_sh_vect_math(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_vector_math_in, sh_node_vector_math_out);
node_type_label(&ntype, node_vector_math_label);
node_type_gpu(&ntype, gpu_shader_vector_math);
node_type_update(&ntype, node_shader_update_vector_math);
nodeRegisterType(&ntype);
}