Hybrid Multifractal bug in formula #55284

Closed
opened 2018-06-01 11:44:58 +02:00 by omgold · 6 comments

I noticed that the behavior of the cycles Musgrave Hybrid Multifractal node is very unexpected when setting Detail to non-integer values. Instead of fading out the last iteration contribution, as the other Musgrave types do, there rather abruptly appear high-amplitude modifications. It can be best seen by setting Detail to something slightly below an integer, like 1.99. The output is discontinous where it reaches the next integer from below.

I could track it back to the code in intern/cycles/kernel/shaders/node_musgrave_texture.osl. In:

  float noise_musgrave_hybrid_multi_fractal(point p, float H, float lacunarity,
                                        float octaves, float offset, float gain)

The line:

      result += rmd * ((safe_noise(p, "signed") + offset) * pwr)

where the contribution of the last, fractional octave is added. Is not consistent with the computation of the contributions inside the iteration loop:

              signal = (safe_noise(p, "signed") + offset) * pwr;
              pwr *= pwHL;
              result += weight * signal;
              weight *= gain * signal;

I believe the line shoud should be:

              result += rmd * ((safe_noise(p, "signed") + offset) * pwr * gain)

Also I believe that for all of Hetero Terrain, Hybrid Multifractal and Ridged Multifractal, the first iteration which has been pulled out of the loop, should be inside the loop, too, otherwise all of these textures show a discontinuity at Detail=1, with the output between 0 and 1 mirroring the one between 1 and 2.

I noticed that the behavior of the cycles Musgrave Hybrid Multifractal node is very unexpected when setting Detail to non-integer values. Instead of fading out the last iteration contribution, as the other Musgrave types do, there rather abruptly appear high-amplitude modifications. It can be best seen by setting Detail to something slightly below an integer, like 1.99. The output is discontinous where it reaches the next integer from below. I could track it back to the code in intern/cycles/kernel/shaders/node_musgrave_texture.osl. In: ``` float noise_musgrave_hybrid_multi_fractal(point p, float H, float lacunarity, float octaves, float offset, float gain) ``` The line: ``` result += rmd * ((safe_noise(p, "signed") + offset) * pwr) ``` where the contribution of the last, fractional octave is added. Is not consistent with the computation of the contributions inside the iteration loop: ``` signal = (safe_noise(p, "signed") + offset) * pwr; pwr *= pwHL; result += weight * signal; weight *= gain * signal; ``` I believe the line shoud should be: ``` result += rmd * ((safe_noise(p, "signed") + offset) * pwr * gain) ``` Also I believe that for all of Hetero Terrain, Hybrid Multifractal and Ridged Multifractal, the first iteration which has been pulled out of the loop, should be inside the loop, too, otherwise all of these textures show a discontinuity at Detail=1, with the output between 0 and 1 mirroring the one between 1 and 2.
Author

Added subscriber: @omgold

Added subscriber: @omgold
Brecht Van Lommel was assigned by Bastien Montagne 2018-07-22 17:42:51 +02:00
Brecht Van Lommel was unassigned by Dalai Felinto 2019-12-23 16:36:11 +01:00

Added subscriber: @brecht

Added subscriber: @brecht

Added subscriber: @LuisPereira

Added subscriber: @LuisPereira

I recently encountered this same bug in 2022, and likewise tracked it to the relevant code, which now resides in intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl,
and is currently replicated over 4 (almost identical) functions (one for each of the 1d,2d,3d,4d cases).

  1. The main issue is that Musgrave Hybrid Multifractal has visual artifacts when Detail is not an integer. This is illustrated in the following images, showing Musgrave Hybrid Multifractal at Details 2.0, 2.9, and 3.0.
    {F13366961}{F13366965}MultiFract3.0.png
    As one can see, details 2.0 and 3.0 differ only slightly and, in fact, they happen to be identical wherever detail 2.0 is negative, so that detail 3.0 only slightly modifies the positive regions of detail 2.0. By contrast, detail 2.9 currently adds wild changes to detail 2.0, and very much affects the negative regions. This is clearly not desired and, if one compares with the behavior of the Musgrave fBm, detail 2.9 should just interpolate details 2.0 and 3.0 (more precisely, it should equal detail 2.0 plus 90% of the new variation in 3.0).

  2. As a secondary issue, detail levels between 0 and 1 simply repeat those between 1 and 2 (I phrase it this way because, once one fixes issue 1 above, it is the levels between 0 and 1 that need a further fix). This is illustrated by the following, where we see that details 0.8 and 1.8 coincide
    MultiFract0.8.png, MultiFract1.8.png

Issue 2 can be fixed by starting the iteration loop at 0 instead of 1, and adjusting the initialization of the pwr, value and weight variables (the initialization in the current code can be refactored as an iteration step), while issue 1 can be fixed by adjusting the final step (dealing with fractional detail) to match the iteration loop.

I believe the following is a full correction of the Musgrave Hybrid Multifractal function (here in the 3d version, but the only difference between versions is the dimension of the coordinate vector "co")

float noise_musgrave_hybrid_multi_fractal_3d(
    vector3 co, float H, float lacunarity, float octaves, float offset, float gain)
{
  vector3 p = co;
  float pwHL = pow(lacunarity, -H);

  float pwr = 1.0;
  float value = 0.0;
  float weight = 1.0;

  for (int i = 0; (weight > 0.001) && (i < (int)octaves); i++) {
    if (weight > 1.0) {
      weight = 1.0;
    }

    float signal = (safe_snoise(p) + offset) * pwr;
    pwr *= pwHL;
    value += weight * signal;
    weight *= gain * signal;
    p *= lacunarity;
  }

  float rmd = octaves - floor(octaves);
  if ((rmd != 0.0) && (weight > 0.001)) {
    if (weight > 1.0) {
      weight = 1.0;
    }
    float signal = (safe_snoise(p) + offset) * pwr;
    value += rmd * weight * signal;
  }

  return value;
}
I recently encountered this same bug in 2022, and likewise tracked it to the relevant code, which now resides in intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl, and is currently replicated over 4 (almost identical) functions (one for each of the 1d,2d,3d,4d cases). 1) The main issue is that Musgrave Hybrid Multifractal has visual artifacts when Detail is not an integer. This is illustrated in the following images, showing Musgrave Hybrid Multifractal at Details 2.0, 2.9, and 3.0. {[F13366961](https://archive.blender.org/developer/F13366961/MultiFract2.0.png)}{[F13366965](https://archive.blender.org/developer/F13366965/MultiFract2.9.png)}![MultiFract3.0.png](https://archive.blender.org/developer/F13366968/MultiFract3.0.png) As one can see, details 2.0 and 3.0 differ only slightly and, in fact, they happen to be identical wherever detail 2.0 is negative, so that detail 3.0 only slightly modifies the positive regions of detail 2.0. By contrast, detail 2.9 currently adds wild changes to detail 2.0, and very much affects the negative regions. This is clearly not desired and, if one compares with the behavior of the Musgrave fBm, detail 2.9 should just interpolate details 2.0 and 3.0 (more precisely, it should equal detail 2.0 plus 90% of the new variation in 3.0). 2) As a secondary issue, detail levels between 0 and 1 simply repeat those between 1 and 2 (I phrase it this way because, once one fixes issue 1 above, it is the levels between 0 and 1 that need a further fix). This is illustrated by the following, where we see that details 0.8 and 1.8 coincide ![MultiFract0.8.png](https://archive.blender.org/developer/F13367080/MultiFract0.8.png), ![MultiFract1.8.png](https://archive.blender.org/developer/F13367082/MultiFract1.8.png) Issue 2 can be fixed by starting the iteration loop at 0 instead of 1, and adjusting the initialization of the pwr, value and weight variables (the initialization in the current code can be refactored as an iteration step), while issue 1 can be fixed by adjusting the final step (dealing with fractional detail) to match the iteration loop. I believe the following is a full correction of the Musgrave Hybrid Multifractal function (here in the 3d version, but the only difference between versions is the dimension of the coordinate vector "co") ``` float noise_musgrave_hybrid_multi_fractal_3d( vector3 co, float H, float lacunarity, float octaves, float offset, float gain) { vector3 p = co; float pwHL = pow(lacunarity, -H); float pwr = 1.0; float value = 0.0; float weight = 1.0; for (int i = 0; (weight > 0.001) && (i < (int)octaves); i++) { if (weight > 1.0) { weight = 1.0; } float signal = (safe_snoise(p) + offset) * pwr; pwr *= pwHL; value += weight * signal; weight *= gain * signal; p *= lacunarity; } float rmd = octaves - floor(octaves); if ((rmd != 0.0) && (weight > 0.001)) { if (weight > 1.0) { weight = 1.0; } float signal = (safe_snoise(p) + offset) * pwr; value += rmd * weight * signal; } return value; } ```

This issue was referenced by 763cafc2b1

This issue was referenced by 763cafc2b101d3258cb62b9a966b6d7e7629eb85

Changed status from 'Confirmed' to: 'Resolved'

Changed status from 'Confirmed' to: 'Resolved'
Brecht Van Lommel self-assigned this 2022-08-26 17:28:18 +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 project
No Assignees
5 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#55284
No description provided.