# Description of the problem that is addressed in the patch.
The Attribute Math node currently allows the user to use mathematical functions with 1, 2 or 3 variables, and combine multiple such functions together using multiple instances of the same node.
However, a mathematical operation with multiple operators and functions - like `(x * sin(x)^2 - b)*c` - requires at least 4 nodes to implement, and is hard to grok in a node tree with multiple such operations.
# Description of the proposed solution, and a motivation as to why this is the best solution.
The proposed solution adds an Attribute Math Expression node, that accepts arbitrary mathematical expressions using one or more of the functions already available with the Attribute Math node. Additionally a "negate" operation has been added to support the unary minus operation.
# List of alternative solutions, and a motivation as to why these are undesirable.
Parsing mathematical expressions isn't new, and there are multiple implementations of this available. Examples are libmatheval, other similar math calculators, expression parsers using antlr, etc. However, including these with blender would increase the dependencies on other libraries (antlr, yacc/lex, etc) increasing the build time and footprint of Blender which is long enough as it stands.
I have implemented a simple version of the shunting yard algorithm with some modifications to support function calls and multi-parameter functions.
The expression parser has been abstracted externally, and is intended to evolve into a generic class that can use one of multiple possible parsing strategies, like vector math for example.
The expression parser has been abstracted externally, and is intended to evolve to a shell using multiple possible parsing strategies, like vector math for example.
The new node offloads the user entered expression to this parser, and requests evaluatesion of it for each index of the span result. Any errors (exceptions) reported by the parser are relayed to the user using node errors.
The parser itself offloads the execution of individual operands and functions to NOD_math_functions.hh similar to how the Attribute Math node does it.
A similar approach can be used to create a generic Math Expression (the not-Attribute kind) node that can be used in multiple node editors like Geometry and Shader.
If support for new functions is added to blender, it is a matter of creating some additional configurations to leverage them in this parser.
The parser can identify any arbitrary variable names in the expression. The `parse` function currently doesn't report the variable names identified, but that is an easy change.
The `evaluate` function accepts values against the variables for evaluation.
The node itself however currently limits the variables that can be given values, to `a`, `b` and `c`.
So you can enter an expression like `x * sin(x)` but there is no way to give `x` a value. So you need to use `a * sin(a)` and give the `A` socket the corresponding value instead.
Eventually the intention is to be able to directly use attribute names in the expression (like `index` or `position.x`). It would be the node's responsibility to pass the values of these to the `evaluate` function.
The node code can also be updated to identify the number of variables in the expression, and show an appropriate number of input sockets with the right names. However, the user experience for that isn't clear to me. What would the initial input sockets be before an expression is entered?
# List of alternative solutions, and a motivation as to why these are undesirable.
Parsing mathematical expressions isn't new, and there are multiple implementations of this available. Examples are libmatheval, other similar math calculators, expression parsers using antlr, etc. However, including these with blender would increase the dependencies on other libraries (antlr, yacc/lex, etc) increasing the build time and footprint of Blender which is long enough as it stands.
# Limitations of the proposed solution.
I have currently not implement unit tests, as I haven't figure GTest out yet.
The parser is currently a monolith. However it is intended to be a generic implementation that operates against multiple strategies, the Math parser being the first implementation, followed by, say, the Vector Math parser.
Boolean operations are not supported yet.
The parser was not designed to support more generic expressions that include control functions (if/else, ternary, for, while, etc). The target was various kinds of math (floating point, Boolean, vector).
Given that it offloads evaluation of individual functions and operators in the expression to existing code in `NOD_math_functions.hh`, there is scope for optimization of the `evaluate` function.
I've dumbed the parser code down to use floats right now. Ideally we'd use double for accuracy in calculations. However I'm not clear on the implication for nodes, since they currently seem to expose float values only (?).
# Mock-up of the proposed user interface and a description of how users are going to interact with the new feature.
A mockup is provided at:
https://blender.community/c/rightclickselect/Nshbbc/