Add Floored Modulo to All Implementations of The Math Node. #110728

Merged
Jacques Lucke merged 7 commits from Hoshinova/blender:add-floored-modulo into main 2023-08-08 12:13:08 +02:00
Member

Both the Math node and the Vector Math currently only explicitly support modulo using truncated division which is oftentimes not the type of modulo desired as it behaves differently for negative numbers and positive numbers.

Floored Modulo can be created by either using the Wrap operation or a combination of multiple Math nodes.
However both methods obfuscate the actual intend of the artist and the math operation that is actually used.

This PR adds modulo using floored division to the scalar Math node, explicitly stating the intended math operation and renames the already existing "Modulo" operation to "Truncated Modulo" to avoid confusion.

Comparison:
Left is Truncated Modulo. Right is FLoored Modulo.
Modulo_Differences.png

Both the `Math` node and the `Vector Math` currently only explicitly support [modulo using truncated division](https://en.wikipedia.org/wiki/Modulo) which is oftentimes not the type of modulo desired as it behaves differently for negative numbers and positive numbers. Floored Modulo can be created by either using the `Wrap` operation or a combination of multiple `Math` nodes. However both methods obfuscate the actual intend of the artist and the math operation that is actually used. This PR adds modulo using floored division to the scalar `Math` node, explicitly stating the intended math operation and renames the already existing `"Modulo"` operation to `"Truncated Modulo"` to avoid confusion. Comparison: Left is Truncated Modulo. Right is FLoored Modulo. ![Modulo_Differences.png](/attachments/89952b80-36f7-44f7-9c69-88598c0df420)
Hoshinova added 1 commit 2023-08-02 20:25:11 +02:00
Hoshinova requested review from Brecht Van Lommel 2023-08-02 20:26:15 +02:00
Hoshinova requested review from Jacques Lucke 2023-08-02 20:26:15 +02:00
Hoshinova requested review from Omar Emara 2023-08-02 20:26:16 +02:00
Author
Member

This is mainly just the scalar Math node right now, since I still haven't decided how exactly to go about the Vector Math node https://devtalk.blender.org/t/adding-the-missing-vector-math-node-operations/30541

This is mainly just the scalar `Math` node right now, since I still haven't decided how exactly to go about the `Vector Math` node https://devtalk.blender.org/t/adding-the-missing-vector-math-node-operations/30541
Iliya Katushenock added this to the Nodes & Physics project 2023-08-02 20:31:37 +02:00
Hoshinova reviewed 2023-08-02 21:40:36 +02:00
@ -166,3 +166,3 @@
}
case NODE_MATH_MODULO: {
case NODE_MATH_TRUNCATED_MODULO: {
Author
Member

What editor does this file belong to? The old texture system doesn't seem to have a "math" texture.

What editor does this file belong to? The old texture system doesn't seem to have a "math" texture.
Hoshinova marked this conversation as resolved
Hoshinova reviewed 2023-08-02 21:43:32 +02:00
@ -17,3 +17,3 @@
float safe_modulo(float a, float b)
float safe_truncated_modulo(float a, float b)
{
return (b != 0.0) ? fmod(a, b) : 0.0;
Author
Member

fmod() here works correctly on the CPU and non OSL GPU but always outputs 0.0 when using GPU OptiX OSL (It works correctly in main though).
I looked into it but couldn't find the issue.
@brecht Do you have an idea what might cause this?

`fmod()` here works correctly on the CPU and non OSL GPU but always outputs 0.0 when using GPU OptiX OSL (It works correctly in `main` though). I looked into it but couldn't find the issue. @brecht Do you have an idea what might cause this?
Author
Member

So I found out that changing the name back to safe_modulo solves the issue for some reason.

So I found out that changing the name back to `safe_modulo` solves the issue for some reason.
Omar Emara requested changes 2023-08-03 08:54:39 +02:00
Omar Emara left a comment
Member

I think having floored modulo can make things easier for artists, so it seems like a good addition.

This patch needlessly breaks backward compatibility and the python API. Because you shifted the integer IDs of the operation enums and changed the RNA enum identifier of the existing modulo operation. So just leave existing operations and add a new operation for the floored modulo.

I think having floored modulo can make things easier for artists, so it seems like a good addition. This patch needlessly breaks backward compatibility and the python API. Because you shifted the integer IDs of the operation enums and changed the RNA enum identifier of the existing modulo operation. So just leave existing operations and add a new operation for the floored modulo.
Author
Member

@OmarEmaraDev The UI name and the operation description aren't part of any API right? I think having "Truncated Modulo" and "Floored Modulo" would be better than just "Modulo" and "Floored Modulo".

Should I also leave the other non API things like function names unchanged?

@OmarEmaraDev The UI name and the operation description aren't part of any API right? I think having "Truncated Modulo" and "Floored Modulo" would be better than just "Modulo" and "Floored Modulo". Should I also leave the other non API things like function names unchanged?
Member

Yes, you can safely change those, and you may also leave the other non API things unchanged.

Yes, you can safely change those, and you may also leave the other non API things unchanged.
Author
Member

Left is Truncated Modulo. Right is FLoored Modulo.
Modulo_Differences.png

Left is Truncated Modulo. Right is FLoored Modulo. ![Modulo_Differences.png](/attachments/89952b80-36f7-44f7-9c69-88598c0df420)
Hoshinova added 1 commit 2023-08-03 14:18:02 +02:00
Author
Member

@OmarEmaraDev I rolled back the Truncated Modulo changes, except for the UI part. Now it's pretty much only adding Floored Modulo.

@OmarEmaraDev I rolled back the Truncated Modulo changes, except for the UI part. Now it's pretty much only adding Floored Modulo.
Hoshinova added 1 commit 2023-08-03 14:22:18 +02:00
Hoshinova added 1 commit 2023-08-03 14:24:30 +02:00
Hoshinova added 1 commit 2023-08-03 16:23:23 +02:00
Hoshinova added 1 commit 2023-08-03 21:04:11 +02:00
Member

@blender-bot package

@blender-bot package
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR110728) when ready.
Author
Member

With the latest commit "Truncated Modulo" now also works on GPU OptiX OSL. I tested all implementations of "Truncated Modulo" and "Floored Modulo" and they all work on my machine.

If there are no further requests this PR is be ready to be merged.

With the latest commit "Truncated Modulo" now also works on GPU OptiX OSL. I tested all implementations of "Truncated Modulo" and "Floored Modulo" and they all work on my machine. If there are no further requests this PR is be ready to be merged.
Member

We do already have the Wrap function in the math node which provides a floored modulo albeit with a different name and additional parameter. Wrap was added a while back and was ported from Godot.

float wrap(float a, float b, float c)
{
  float range = b - c;
  return (range != 0.0) ? a - (range * floor((a - c) / range)) : c;
}

vs

void math_floored_modulo(float a, float b, float c, out float result)
{
  result = (b != 0.0) ? a - floor(a / b) * b : 0.0;
}

image

We do already have the `Wrap` function in the math node which provides a floored modulo albeit with a different name and additional parameter. Wrap was added a while back and was ported from Godot. ``` float wrap(float a, float b, float c) { float range = b - c; return (range != 0.0) ? a - (range * floor((a - c) / range)) : c; } ``` vs ``` void math_floored_modulo(float a, float b, float c, out float result) { result = (b != 0.0) ? a - floor(a / b) * b : 0.0; } ``` ![image](/attachments/6a6f7d81-4bba-489b-8655-0c2bc2df86bf)
314 KiB
Author
Member

@CharlieJolly Sure, the Wrap operation may also be able to output the same results, but the additional parameter makes it harder to wrap your head around it.

The math node already has many redundant operations like, Square Root, Inverse Square Root and Exponent, which can all be replaced by just Power.
Compared to that Floored Modulo isn't that big of an offender.

Also I think most users don't even know what Wrap does while Floored Modulo is a much more commonly known operation.
But in the end it's mostly just a convenience thing.

@CharlieJolly Sure, the `Wrap` operation may also be able to output the same results, but the additional parameter makes it harder to wrap your head around it. The math node already has many redundant operations like, `Square Root`, `Inverse Square Root` and `Exponent`, which can all be replaced by just `Power`. Compared to that `Floored Modulo` isn't that big of an offender. Also I think most users don't even know what `Wrap` does while `Floored Modulo` is a much more commonly known operation. But in the end it's mostly just a convenience thing.
Member

@Hoshinova I do agree, prefer to have more explicit ops for readability of the node trees.

@Hoshinova I do agree, prefer to have more explicit ops for readability of the node trees.
Member

The math node already has many redundant operations like, Square Root, Inverse Square Root and Exponent, which can all be replaced by just Power.

Mathematically : yes
User experience wise: no

> The math node already has many redundant operations like, Square Root, Inverse Square Root and Exponent, which can all be replaced by just Power. Mathematically : yes User experience wise: no
Author
Member

@LazyDodo The addition of Floored Modulo is exactly something that makes user experience better so I think were agreeing on that case here.

@LazyDodo The addition of `Floored Modulo` is exactly something that makes user experience better so I think were agreeing on that case here.
Omar Emara approved these changes 2023-08-05 16:58:49 +02:00
Omar Emara left a comment
Member

I think the description of the operators could be improved and be made more user friendly. Otherwise, this is fine. Though you should wait for Brecht or Jacques to review this.

I think the description of the operators could be improved and be made more user friendly. Otherwise, this is fine. Though you should wait for Brecht or Jacques to review this.
Omar Emara changed title from WIP: Add Floored Modulo to All Implementations of The Math Node. to Add Floored Modulo to All Implementations of The Math Node. 2023-08-05 16:59:00 +02:00

I think this is redundant, and just creates the redundancy of operations that the Hoshinova is talking about The math node already has many redundant operations like, Square Root, Inverse Square Root and Exponent, which can all be replaced by just Power.. Yes, and this operation can replaced by floor(size * X).

I think this is redundant, and just creates the redundancy of operations that the Hoshinova is talking about `The math node already has many redundant operations like, Square Root, Inverse Square Root and Exponent, which can all be replaced by just Power.`. Yes, and this operation can replaced by `floor(size * X)`.
Author
Member

@mod_moder Quoting LazyDodo:

Mathematically : yes
User experience wise: no

Unlike Floored Modulo the Wrap operation is a rather uncommon operation. Floored Modulo (a, b) is much more explicit about what is being calculated compared to Wrap (a, b , 0.0).
Blender is mostly used by artists, not mathematicians so our goal when designing the Blender should be to make it as intuitive for the artists to use as possible, not as mathematically general as possible.

In this case I think that the explicitness of Floored Modulo far outweighs the cost of a little redundancy.

@mod_moder Quoting LazyDodo: > Mathematically : yes User experience wise: no Unlike `Floored Modulo` the `Wrap` operation is a rather uncommon operation. `Floored Modulo (a, b)` is much more explicit about what is being calculated compared to `Wrap (a, b , 0.0)`. Blender is mostly used by artists, not mathematicians so our goal when designing the Blender should be to make it as intuitive for the artists to use as possible, not as mathematically general as possible. In this case I think that the explicitness of `Floored Modulo` far outweighs the cost of a little redundancy.
Author
Member

@OmarEmaraDev

I think the description of the operators could be improved and be made more user friendly.

Hmm, not sure what I could add to the description I think The remainder of truncated division pretty much sums it up already.
I mean adding a definition of truncated division would be overkill for a simple description.

@OmarEmaraDev > I think the description of the operators could be improved and be made more user friendly. Hmm, not sure what I could add to the description I think `The remainder of truncated division` pretty much sums it up already. I mean adding a definition of truncated division would be overkill for a simple description.

The simplification for artists should mainly be in new assets, and not in duplicating functionality with the addition of factors, right?

The simplification for artists should mainly be in new assets, and not in duplicating functionality with the addition of factors, right?
Author
Member

@mod_moder I don't see this as a duplication of functionality.
In fact before CharlieJolly pointed it out I didn't even know that you could use Wrap to emulate Floored Modulo and I think that this applies to the vast majority of users.

@mod_moder I don't see this as a duplication of functionality. In fact before CharlieJolly pointed it out I didn't even know that you could use `Wrap` to emulate `Floored Modulo` and I think that this applies to the vast majority of users.

I've been doing this for the last six years with floor and multiplication.

I've been doing this for the last six years with floor and multiplication.
Author
Member

Math is already hard enough for many artists, so I don't see how obfuscating common math operations behind other less common operations is a good idea.

Math is already hard enough for many artists, so I don't see how obfuscating common math operations behind other less common operations is a good idea.

As I see it, you are just putting the multiplication fact into the code. Although it may be a separate node. And it does not require a change in the code.
The example you gave earlier with power functions and Square Root, .... Its difference lies in the fact that the Square Root is a generally accepted, optimized operation implemented on all platforms. And not just a bind for the pow(x, 0.5), made for artists who don't know log-mathematics.

As I see it, you are just putting the multiplication fact into the code. Although it may be a separate node. And it does not require a change in the code. The example you gave earlier with power functions and `Square Root`, .... Its difference lies in the fact that the `Square Root` is a generally accepted, optimized operation implemented on all platforms. And not just a bind for the `pow(x, 0.5)`, made for artists who don't know log-mathematics.
Author
Member

Well of course it's possible to create your own operations out of more elementary operations but with that logic most operations should be removed.
Why need Subtract if you could Multiply by -1.0 then do an Add. We also wouldn't need a Vector Math node as all the operations could theoretically be done using just Separate XYZ and the scalar Math node.

Does it work mathematically? Yes.
Is it good software design? Absolutely not.

Well of course it's possible to create your own operations out of more elementary operations but with that logic most operations should be removed. Why need `Subtract` if you could `Multiply` by `-1.0` then do an `Add`. We also wouldn't need a `Vector Math` node as all the operations could theoretically be done using just `Separate XYZ` and the scalar `Math` node. Does it work mathematically? Yes. Is it good software design? Absolutely not.
Member

@SimonThommes What do you think about adding this new operator to the math node? Would you call it redundant or a convenient addition?

@SimonThommes What do you think about adding this new operator to the math node? Would you call it redundant or a convenient addition?
Member

I think it's perfectly valid to have floored modulo as a low level operation.
However, I think the patch description and therefore also the final commit message should still be improved given the things that have been brought up in the conversation here. The patch description makes it sound like you couldn't achieve the result on the right easily currently.

Lastly, it would be nice for the sake of completeness if you could prepare a .blend file that shows that the new operation behaves the same in all node systems.

I think it's perfectly valid to have floored modulo as a low level operation. However, I think the patch description and therefore also the final commit message should still be improved given the things that have been brought up in the conversation here. The patch description makes it sound like you couldn't achieve the result on the right easily currently. Lastly, it would be nice for the sake of completeness if you could prepare a .blend file that shows that the new operation behaves the same in all node systems.
Author
Member

@JacquesLucke I updated the patch description.

Here's the .blend file you requested:
Modulo_Test.blend

It shows the behavior of all implementations (Shader, Geo, Compositor nodes) for Truncated Modulo and Floored Modulo, except for the old Texture nodes because I have no idea how that node system works.

@JacquesLucke I updated the patch description. Here's the .blend file you requested: [Modulo_Test.blend](/attachments/7e52f0e3-11f3-4c2d-8a2f-a0eaf31f286c) It shows the behavior of all implementations (Shader, Geo, Compositor nodes) for `Truncated Modulo` and `Floored Modulo`, except for the old Texture nodes because I have no idea how that node system works.
Jacques Lucke approved these changes 2023-08-07 22:32:05 +02:00
Jacques Lucke left a comment
Member

LGTM. @brecht guess the is fine for you as well?

LGTM. @brecht guess the is fine for you as well?
@ -3505,7 +3505,6 @@ void CustomData_swap_corners(CustomData *data, const int index, const int *corne
}
}
Member

unrelated change

unrelated change
Author
Member

Pretty sure that was just Clang format, but I'll unchange it.

Pretty sure that was just Clang format, but I'll unchange it.
Brecht Van Lommel approved these changes 2023-08-08 00:01:37 +02:00
Hoshinova added 1 commit 2023-08-08 11:17:18 +02:00
Jacques Lucke merged commit b880485492 into main 2023-08-08 12:13:08 +02:00
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No Assignees
8 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#110728
No description provided.