Maniphest T101011

Add Signed Noise node to Shader and GN
Confirmed, NormalDESIGN

Assigned To
None
Authored By
Charlie Jolly (charlie)
Sep 12 2022, 3:53 PM
Tags
  • BF Blender
  • Geometry Nodes
  • Nodes & Physics
  • Render & Cycles
Subscribers
Brecht Van Lommel (brecht)
Charlie Jolly (charlie)
Dalai Felinto (dfelinto)
Gerstmann Bradley (Bradley_G)
H.M. Turnbull (hmturnbull)
Iliya Katueshenock (Moder)
Paul Larson (GeorgiaPacific)
Tokens
"Like" token, awarded by dfelinto."Love" token, awarded by HEYPictures."Love" token, awarded by hmturnbull.

Description

The existing Noise texture was originally designed for textures where values in the range 0-1 are useful.

For 3D space used in geometry and volumes it is useful to have signed noise.

After exploring adding a signed noise output to the existing Noise Texture I created the following patches.

D12820: Nodes: Add Vector Distortion node (WIP)

D15947: Nodes: Add Signed output value to the Noise Texture node

D15944: Nodes: Add Signed Noise node

Separate sockets:

Enum (current patch):

I'm currently in favour of D15944 and adding the function as a simple node.

Distortion using just the Signed Noise patch.

The advantage of exposing the base noise function is that it allows users to create their own noise based node groups. It decouples the function from the existing Noise texture and only exposes the noise function for a simple UI.

It is possible to use the existing noise texture for this but it needs the correct values setting plus additional nodes. The underlying code is less efficient.

/* Distortion. */

BLI_INLINE float3 perlin_distortion(float3 position, float strength)
{
  return float3(perlin_signed(position + random_float3_offset(0.0f)) * strength,
                perlin_signed(position + random_float3_offset(1.0f)) * strength,
                perlin_signed(position + random_float3_offset(2.0f)) * strength);
}

/* Positive fractal perlin noise. */

template<typename T> float perlin_fractal_template(T position, float octaves, float roughness)
{
  float fscale = 1.0f;
  float amp = 1.0f;
  float maxamp = 0.0f;
  float sum = 0.0f;
  octaves = CLAMPIS(octaves, 0.0f, 15.0f);
  int n = static_cast<int>(octaves);
  for (int i = 0; i <= n; i++) {
    float t = perlin(fscale * position);
    sum += t * amp;
    maxamp += amp;
    amp *= CLAMPIS(roughness, 0.0f, 1.0f);
    fscale *= 2.0f;
  }
  float rmd = octaves - std::floor(octaves);
  if (rmd == 0.0f) {
    return sum / maxamp;
  }

  float t = perlin(fscale * position);
  float sum2 = sum + t * amp;
  sum /= maxamp;
  sum2 /= maxamp + amp;
  return (1.0f - rmd) * sum + rmd * sum2;
}

vs

/* Perlin signed noise */
r_value = noise::perlin_signed(position);

Event Timeline

Charlie Jolly (charlie) created this task.Sep 12 2022, 3:53 PM
Iliya Katueshenock (Moder) added a subscriber: Iliya Katueshenock (Moder).Sep 12 2022, 4:02 PM
Charlie Jolly (charlie) added a subscriber: Brecht Van Lommel (brecht).Sep 12 2022, 4:12 PM

Comment copied from D15944.

In D15944#433292, @Brecht Van Lommel (brecht) wrote:

Why make this a separate node instead of adding more options to the Noise Texture node?

Main reason was cluttering the UI and adding more code to the noise texture.
Originally I was looking at how to add non-uniform controls to the distortion.

Charlie Jolly (charlie) updated the task description.Sep 12 2022, 5:01 PM
Brecht Van Lommel (brecht) added a comment.Sep 12 2022, 5:25 PM

I believe the Noise Texture reduces to pure Perlin noise when setting Detail, Roughness, Distortion to 0.0. That was by design so that it could also be used as a building block. Changing the domain to -1..1 doesn't seem enough to me to add a new node.

If the main use case is vector distortion, a Vector output could be added that outputs the same as Color but in the range -1..1 instead of 0..1.

Charlie Jolly (charlie) added a comment.EditedSep 12 2022, 5:40 PM
Patch Pros and Cons Comment
D15944: Nodes: Add Signed Noise nodeLow level function. Useful as a building block for node groups. Simple code to maintain.Could be expanded with Unsigned socket
D12820: Nodes: Add Vector Distortion node (WIP)Artists friendly access to distortion function with non-uniform control. Probably too specificNode groups are currently not sharable between GN and Shaders. Having node functionality built in is an advantage here.
D15947: Nodes: Add Signed output value to the Noise Texture nodeSimple patch. Artist friendly access to signed noise. Not decoupled from the fractal noise code. More sockets and code to maintain.There would be an expectation to add similar sockets for other textures.
Do nothingLess code to maintain.Not user friendly, there is the need to always add additional nodes for signed noise.
Charlie Jolly (charlie) added a comment.Sep 12 2022, 6:07 PM
In T101011#1415829, @Brecht Van Lommel (brecht) wrote:

I believe the Noise Texture reduces to pure Perlin noise when setting Detail, Roughness, Distortion to 0.0. That was by design so that it could also be used as a building block. Changing the domain to -1..1 doesn't seem enough to me to add a new node.

It does reduce to Perlin so adding the signed output could be the simplest idea. I've added a patch for that. D15947

If the main use case is vector distortion, a Vector output could be added that outputs the same as Color but in the range -1..1 instead of 0..1.

The use case of the Vector Distort was originally to allow non-uniform distortion but it can be achieved with a node group and using the existing Noise node or D15944. I included a screenshot in the main task description.

The patch for the new node D15944 came from the idea of having access to the basic Perlin noise without the additional overhead of the additional code that the Noise texture uses to detect and generate distortion and so on. There may be a performance case for that with less branching etc

Brecht Van Lommel (brecht) added a comment.Sep 12 2022, 8:48 PM
In T101011#1415861, @Charlie Jolly (charlie) wrote:

It does reduce to Perlin so adding the signed output could be the simplest idea. I've added a patch for that. D15947

I would rather not require users to decide between "Fac" and "Signed" whenever they link something to the Noise Texture node. To me that kind of clutter is worse than adding a Vector output (or maybe having an option in the node), because it's kind of out of the way if you don't use it.

The use case of the Vector Distort was originally to allow non-uniform distortion but it can be achieved with a node group and using the existing Noise node or D15944. I included a screenshot in the main task description.

The patch for the new node D15944 came from the idea of having access to the basic Perlin noise without the additional overhead of the additional code that the Noise texture uses to detect and generate distortion and so on. There may be a performance case for that with less branching etc

I don't think that type of overhead is a problem, and if it was it could be solved internally without adding more nodes for users.

As far as I can tell there is no need to have 3 separate signed noise nodes as in the example setup, a single Noise Texture node with color output would do the same. If you link that with a Vector Displacement node and change the Midlevel, and change the Texture Mapping settings on the Noise Texture node to control scale and offset, it's relatively close with just two nodes.

Iliya Katueshenock (Moder) added a comment.Sep 12 2022, 8:55 PM

I wouldn't mind separating the noise nodes by their main functions, ticks like map generation, map shift and whatever else.
You can often use more than 6 of these generators and the unused offset overhead can be really significant.

Charlie Jolly (charlie) added a comment.Sep 12 2022, 9:24 PM
In T101011#1415928, @Brecht Van Lommel (brecht) wrote:

I would rather not require users to decide between "Fac" and "Signed" whenever they link something to the Noise Texture node. To me that kind of clutter is worse than adding a Vector output (or maybe having an option in the node), because it's kind of out of the way if you don't use it.

That's understandable. It adds an additional enum to the UI.

The patch for the new node D15944 came from the idea of having access to the basic Perlin noise without the additional overhead of the additional code that the Noise texture uses to detect and generate distortion and so on. There may be a performance case for that with less branching etc

I don't think that type of overhead is a problem, and if it was it could be solved internally without adding more nodes for users.

Ok, that's good to know. Does the same apply to GN too?

As far as I can tell there is no need to have 3 separate signed noise nodes as in the example setup, a single Noise Texture node with color output would do the same. If you link that with a Vector Displacement node and change the Midlevel, and change the Texture Mapping settings on the Noise Texture node to control scale and offset, it's relatively close with just two nodes.

Vector Displacement is a shader only node.

The distortion node setup matches the float3 perlin_distortion function used for distortion in the noise texture node. Either way they are both calling perlin three times. It makes the setup simpler but without access to the offset.

float3 perlin_distortion(float3 position, float strength)
{
  return float3(perlin_signed(position + random_float3_offset(0.0f)) * strength,
                perlin_signed(position + random_float3_offset(1.0f)) * strength,
                perlin_signed(position + random_float3_offset(2.0f)) * strength);
}
Charlie Jolly (charlie) added a comment.Sep 12 2022, 9:27 PM
In T101011#1415932, @Iliya Katueshenock (Moder) wrote:

I wouldn't mind separating the noise nodes by their main functions, ticks like map generation, map shift and whatever else.
You can often use more than 6 of these generators and the unused offset overhead can be really significant.

I don't know if the hashed offset call (C++ random_float3_offset) is optimised away by the compiler. If it isn't then it's good to have access to the base function.

H.M. Turnbull (hmturnbull) awarded a token.Sep 12 2022, 11:13 PM
H.M. Turnbull (hmturnbull) added a subscriber: H.M. Turnbull (hmturnbull).
H.M. Turnbull (hmturnbull) added a comment.EditedSep 12 2022, 11:26 PM
In T101011#1415777, @Charlie Jolly (charlie) wrote:

I'm currently in favour of D15944 and adding the function as a simple node.

I agree. No need to clutter up existing Noise Texture when the point is to add lower-level building blocks. It seems to me adding signed noise as its own node would be better for performance, which is super important when it comes to designing custom noise textures.

Brecht Van Lommel (brecht) added a comment.Sep 13 2022, 12:48 AM
In T101011#1415937, @Charlie Jolly (charlie) wrote:

That's understandable. It adds an additional enum to the UI.

If it's an option then the Color output should turn into a Vector when the option is set to signed, since color outputs are expected to be in the 0..1 range.

Ok, that's good to know. Does the same apply to GN too?

It's even less of a problem for GN due to batch processing.

The distortion node setup matches the float3 perlin_distortion function used for distortion in the noise texture node. Either way they are both calling perlin three times. It makes the setup simpler but without access to the offset.

Color output calls fractal noise 3 times, so it should be the same thing.

In T101011#1415971, @H.M. Turnbull (hmturnbull) wrote:

It seems to me adding signed noise as its own node would be better for performance

No, specialization is possible even with a single node. And even ignoring that, it's not obviously true when taking into account things like instruction caches.

Charlie Jolly (charlie) added a comment.EditedSep 13 2022, 1:14 AM

@Brecht Van Lommel (brecht) Good to know that performance is not an issue. This might be the better solution in that case.

Updated D15947 with enum for signed/unsigned type.

Omar Emara (OmarSquircleArt) changed the task status from Needs Triage to Confirmed.Sep 13 2022, 11:06 AM
Omar Emara (OmarSquircleArt) changed the subtype of this task from "Report" to "Design".
HEYPictures (HEYPictures) awarded a token.Sep 14 2022, 3:58 PM
Dalai Felinto (dfelinto) added a subscriber: Dalai Felinto (dfelinto).Sep 21 2022, 3:04 PM

@Charlie Jolly (charlie) can you update the task description with this latest image?

Charlie Jolly (charlie) updated the task description.Sep 21 2022, 4:20 PM
Dalai Felinto (dfelinto) awarded a token.Sep 21 2022, 4:43 PM
Paul Larson (GeorgiaPacific) added a subscriber: Paul Larson (GeorgiaPacific).Sep 23 2022, 7:19 AM
Brecht Van Lommel (brecht) added a comment.Sep 26 2022, 11:19 PM

To me the design from D15947 seems fine, but would be good if the geometry nodes team could weigh in.

Hans Goudey (HooglyBoogly) added projects: Nodes & Physics, Render & Cycles.Oct 21 2022, 4:09 AM
Hans Goudey (HooglyBoogly) moved this task from Backlog/Bugs to Community Tasks on the Geometry Nodes board.Dec 22 2022, 7:06 PM
Gerstmann Bradley (Bradley_G) added a subscriber: Gerstmann Bradley (Bradley_G).Dec 23 2022, 1:04 PM

Sorry to bother.
According to what I understand, the main purpose is to allow noise output to equally cover the negative ranges so that mesh can be deformed more in both negative and positive side in a 3D space.
The most common way to resolve this problem in current Geometry Nodes is to "subtract value by 0.5".
This method is essentially to achieve "Mid-Level" option in the Displacement modifier.
Thinking about real practical case in which we want to use any type of texture to do the displacement, I think implementing Mid-Level is what we really should do.

Talking about Down Side of current proposals:

  1. If we add a new socket, people will be confused which one to use. AND, if we add Signed in Float, we also need Signed in Color. it's 2 more sockets which make the node unnecessarily big.
  2. If we add an enum list, it will be unaccessible inside the node group. (I also don't suggest to turn Color into Vector upon changing the enum, it's already a common sense that color and vector are numerically inter-changeble. Changing data type sometimes also make the linkage disappear in Blender.)
  3. If we add a new node, what if I want a signed voronoi? Then are we going to implement another new signed texture?

On the contrary, These are the advantages of Mid-level:

  1. Implementing a mid-level is as simple as just subtracting 0.5 at the end of the output of "Texture". It shouldn't impact any code related to "Distortion", "Roughness", etc.
  2. The slider of mid-level also provides more detailed controls compared to the enum list. It's also just a single slider, compared to two more output-sockets, or a completely new node. The node size if nearly the same as the original node.
  3. This implementation should be easily doable in both Geometry Nodes and Shader Nodes imo.

Here's a problem with "Mid-Level" Implementation.
I think this implementation should be done on every texture node if possible. (noise, voronoi, etc.)
I don't suggest implement it on "Set Position", because it's possible that we want to use signed noise in other places, "Translate Instance", "rotate Instance", etc.