Page MenuHome

Ocean modifier : expose eigenvectors for use as maps
ClosedPublic

Authored by Phil Stopford (philstopford) on Mar 19 2020, 6:17 PM.

Details

Summary

The eigenvectors in the ocean modifier (plus and minus) can be useful, but are not exposed. Assuming the particle system was capable, for example, the eigenvectors could be used to drive spray emission velocities.

This patch exposes the controls to allow maps to be generated from these eigenvectors. Currently, the values are mapped into a 0-255 range similar to foam.

The names are technical in nature since the terminology is generally understood, but if alternative names are deemed necessary, this is a simple enough change.

Diff Detail

Repository
rB Blender

Event Timeline

I don't think this is generally understood unless you're both familiar with the algorithm and the concept of eigenvalues, which most users wouldn't be.

There does not appear to be a description of what this is the eigenvalue of. It's like saying it's the sum, but not mentioning what you're summing.

As far as I know "eigen plus" and "eigen minus" is not standard math terminology either.

If a velocity can be extracted from this (and potentially some other useful quantities), why not output those directly?

Python indentation reverted prior to diff being generated. Fixed.

Here's an overview video showing why the terminology is open to debate. The eigenvalues come from the mathematical representation and the minus and plus are essentially complementary. I can't really think of a good general name for this, though, in terms of what it represents. It could be labelled, I guess, as spray veolocity, but there's no spray as such without a particle system, so I am uncertain. The underlying equation is a combination of wave folding and collision.

These are vectors so they can't be eigenvalues, which are scalars. I guess these are eigenvectors, which have unit length and are orthogonal to each other?

From the images, to me this look a lot like principal curvature, with these vectors being the principal directions?

Maybe "Wave Direction" could be a good name, and the other might be "Wave Tangent". I'm not sure you even separate values for both, since they seem to be orthogonal.

Phil Stopford (philstopford) retitled this revision from Ocean modifier : expose eigenvalue maps for use to Ocean modifier : expose eigenvectors for use as maps.Mar 19 2020, 10:07 PM
Phil Stopford (philstopford) edited the summary of this revision. (Show Details)

Apologies for the confusion; I was thinking at the individual X->R, Y->G, Z->B level, not as the whole 'vector' - too close to the tree to see the forest. I've tweaked the description to better describe things. I'm very open to whatever label is appropriate and clear. I can live with curvature, but there is an aspect of rate of change to this as well so it might need to be indicated that this is also a rate of change / velocity.

What about 'tension'? Does that perhaps work better?

Later thought : the plus is kind of a 'peak spray data layer map' and the complementary might be something of a 'trough spray data layer map'

Just wondered whether any of those suggested labels might be appropriate.

I think "tension" is usually a scalar. I would go or something simple like "spray direction", and not have the orthogonal direction as its own map, it's easy to compute for someone who's enough of an advanced user to need it, we have nodes that make it easier to rotate vectors 90°.

These UI names are also too long for no good reason, already for foam. I would imagine something simpler like this:

[X] Foam Map              [<name text field>]
                          [Coverage: <value>]
[X] Spray Direction Map   [<name text field>]

Ideally the name text field would also use the vertex color icon with auto completion, similar to the way e.g. dynamic paint output works.

Simplifying UI per feedback.

Just wondering if the proposal and differential make sense now and could be signed off

Is master in a position where this could be merged? :)

Gentle nudge for review :)

Reworked to respond to recent modifier UI code changes.

Last attempt went wrong somewhere. Here's an updated diff responding to the modifier UI changes.

I saw your poke on devtalk and looked into this briefly, just some code quality stuff and small UI changes:

Clang format changes (https://wiki.blender.org/wiki/Tools/ClangFormat):

diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index ed0fc273e15..ea65c8a8dd3 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -120,7 +120,7 @@ static void initData(ModifierData *md)
   omd->bakeend = 250;
   omd->oceancache = NULL;
   omd->foam_fade = 0.98;
-  omd->foamlayername[0] = '\0'; /* layer name empty by default */
+  omd->foamlayername[0] = '\0';  /* layer name empty by default */
   omd->spraylayername[0] = '\0'; /* layer name empty by default */
 
   omd->ocean = BKE_ocean_add();
@@ -420,8 +420,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
           &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername);
 
       MLoopCol *mloopcols_spray;
-      if (omd->flag & MOD_OCEAN_GENERATE_SPRAY)
-      {
+      if (omd->flag & MOD_OCEAN_GENERATE_SPRAY) {
         mloopcols_spray = CustomData_add_layer_named(
             &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->spraylayername);
       }
@@ -435,8 +434,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
           MLoopCol *mlcol = &mloopcols[mp->loopstart];
 
           MLoopCol *mlcolspray;
-          if (omd->flag & MOD_OCEAN_GENERATE_SPRAY)
-          {
+          if (omd->flag & MOD_OCEAN_GENERATE_SPRAY) {
             mlcolspray = &mloopcols_spray[mp->loopstart];
           }

I would also simplify the UI code a bit like this, also tightening up some of the gaps between properties and just setting it inactive if foam is turned off:

diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index ed0fc273e15..ea65c8a8dd3 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -611,7 +609,7 @@ static void foam_panel_draw_header(const bContext *C, Panel *panel)
 
 static void foam_panel_draw(const bContext *C, Panel *panel)
 {
-  uiLayout *col;
+  uiLayout *col, *sub;
   uiLayout *layout = panel->layout;
 
   PointerRNA ptr;
@@ -630,20 +628,13 @@ static void foam_panel_draw(const bContext *C, Panel *panel)
   uiLayoutSetActive(col, use_foam);
   uiItemR(col, &ptr, "foam_layer_name", 0, IFACE_("Data Layer"), ICON_NONE);
 
-  if (use_foam) {
-    uiLayoutSetPropSep(layout, true);
-
-    col = uiLayoutColumn(layout, false);
-    uiLayoutSetActive(col, use_foam);
-    uiItemR(col, &ptr, "gen_spray", 0, IFACE_("Generate Spray"), ICON_NONE);
-    col = uiLayoutColumn(layout, false);
-    uiLayoutSetActive(col, gen_spray);
-    uiItemR(col, &ptr, "invert_spray", 0, IFACE_("Invert Spray"), ICON_NONE);
-
-    col = uiLayoutColumn(layout, true);
-    uiLayoutSetActive(col, gen_spray);
-    uiItemR(col, &ptr, "spray_layer_name", 0, IFACE_("Data Layer"), ICON_NONE);
-  }
+  col = uiLayoutColumn(layout, false);
+  uiLayoutSetActive(col, use_foam);
+  uiItemR(col, &ptr, "gen_spray", 0, IFACE_("Generate Spray"), ICON_NONE);
+  sub = uiLayoutColumn(col, false);
+  uiLayoutSetActive(sub, gen_spray && use_foam);
+  uiItemR(sub, &ptr, "invert_spray", 0, IFACE_("Invert Spray"), ICON_NONE);
+  uiItemR(sub, &ptr, "spray_layer_name", 0, IFACE_("Spray Layer"), ICON_NONE);
 }
 
 static void spectrum_panel_draw(const bContext *C, Panel *panel)

Finally, I had a few compiler warnings that aren't really a big deal, but it's nice to avoid adding more of them:

/home/hans/Documents/Blender-Git/blender/source/blender/modifiers/intern/MOD_ocean.c:468:29: warning: ‘mlcolspray’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  468 |               mlcolspray->g = 0;
      |               ~~~~~~~~~~~~~~^~~
/home/hans/Documents/Blender-Git/blender/source/blender/modifiers/intern/MOD_ocean.c:436:21: note: ‘mlcolspray’ was declared here
  436 |           MLoopCol *mlcolspray;
      |                     ^~~~~~~~~~
/home/hans/Documents/Blender-Git/blender/source/blender/modifiers/intern/MOD_ocean.c:438:24: warning: ‘mloopcols_spray’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  438 |             mlcolspray = &mloopcols_spray[mp->loopstart];
      |             ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/hans/Documents/Blender-Git/blender/source/blender/modifiers/intern/MOD_ocean.c:422:17: note: ‘mloopcols_spray’ was declared here
  422 |       MLoopCol *mloopcols_spray;
      |                 ^~~~~~~~~~~~~~~
source/blender/makesrna/intern/rna_modifier.c
5546

It would probably make more sense to use consistent naming for this property: use_spray instead of gen_spray

5554

Invert spray -> Invert Spray

Hans Goudey (HooglyBoogly) requested changes to this revision.Jun 19 2020, 2:15 PM
This revision now requires changes to proceed.Jun 19 2020, 2:15 PM

Responding to feedback. The uninitialized warnings are meaningless - the variables are defined at outer level for scope, but only used in the conditional blocks where they have been initialized. Not sure how this ought to be handled.

The uninitialized warnings are meaningless - the variables are defined at outer level for scope, but only used in the conditional blocks where they have been initialized. Not sure how this ought to be handled.

Just initializing them to NULL should work, at least to quiet the warnings.

source/blender/modifiers/intern/MOD_ocean.c
631

This is unnecessary, the same call is just a few lines above.

638

I missed this earlier: the manual label is unnecessary here since the property has the same name. Should be:
uiItemR(sub, &ptr, "invert_spray", 0, NULL, ICON_NONE);

Hans, what do you think? Is this OK from your perspective?

Just use consistent names for the properties: spray_layer_name (like foam_layer_name) and use_spray (like use_foam). But other than that, yeah!

The layer data names should already be consistent. I opted for 'generate' rather than 'use' for the spray, as the spray map is generated. It's not actually 'used' by the modifier, so I always felt 'use foam' was wrong - you have to use it somewhere else.

Just following up again - not sure there's anything pending here for me to change.

@Hans Goudey (HooglyBoogly) : is there anything pending? I think your comments are already addressed, unless I missed something. Hoping to move this forward through review. :)

No, it looks good to me, but you'll need @Brecht Van Lommel (brecht) to accept this too.

This revision is now accepted and ready to land.Jul 1 2020, 9:03 PM

@Hans Goudey (HooglyBoogly) feel free to commit this if my last comment is solved.

source/blender/makesrna/intern/rna_modifier.c
5546

This comment was not addressed yet, use use_spray for consistency with foam, and because abbreviations like gen should not be used.

@Brecht Van Lommel (brecht) : I was using gen because this really generates the map rather than 'uses' it; I find 'use_foam' misleading in that sense. I can change it for consistency, but the modifier never really uses these properties; they are used elsewhere (the modifier generates the data)

@Brecht Van Lommel (brecht) : I was using gen because this really generates the map rather than 'uses' it; I find 'use_foam' misleading in that sense. I can change it for consistency, but the modifier never really uses these properties; they are used elsewhere (the modifier generates the data)

Just for some statistics: use_* occurs in Blender RNA around 1000 times, while gen_* is used 4 times.
Anyway, it makes sense, use_spray means the modifier is "using" its spray capability.
So yes, please just use the consistent name.

Change from gen_spray to use_spray per feedback

I ended up putting spray in a subpanel of foam, it made more sense that way since it depends on foam being on.

@Hans Goudey (HooglyBoogly) Can you please elaborate on how to use these Spray maps to drive particle velocity? I figured the foam maps out without any trouble but I can't find a way to drive the velocities from the SPRAY attribute

That's really a question for @Phil Stopford (philstopford). I tried to make sure the naming, code style, etc. made sense here, but I'm not that familiar with the logic of the ocean sim modifier myself.

This was written with the intent that it would work with the upcoming particle system overhaul. That work was postponed so the spray vector maps aren’t immediately usable within blender for driving particles.
The idea is that each channel of RGB drives velocity in XYZ. These velocity representations come directly from the Jacobian inputs to the foam. I left the option for complementary in the spray because it was not immediately clear what would work best with the particle system when it arrived.