Material Room Du Node Strange Behaviour (PP2014/Poser 9 Firefly) ?
I've been playing with the Du, dPdu, dNdu, Dv, dPdv and dNdv nodes (
"Firefly: dU, dPdu, and dNdu (and dV, dPdv, and dNdv) nodes - Trying to understand them by playing and thinking out loud..." thread at CGbytes ) and I've run into a pretty basic problem that I just can't make any sense of.
I first noticed it in post #11 of that thread "Failed Attempt At Finding A Simple Equation (Or Units) For Du" - the strange bit seems to be the last observation that "Also I was surprised that the three colours I got were 1/2, 1/4 and 1/8th of full white (i.e. 127, 63, and 31) - looks like some sort of quantization is going on?"
A bit later I created a shader to convert a numeric value into a digital display texture, and used this to try and display the actual numeric value of Du on a plane (post 40 "Looking At Du Again - And There's That Step Function Again..." )
I used the top camera and changed the Scale in steps of 10% from 10% to 120%, did a render at each setting, and noted the value my shader displayed (for most cases the number was very clear, but in some cases (such as the screenshot below) it wasn't and my reading is a bit of a guess - 17369 in this case).
I then plotted a graph of the results (noting which values were unclear), and did additional renders at a few intermediate points.
It's this apparent step function in the middle of an almost linear graph that doesn't make any sense to me. My first thought would be that it's an error in my numeric visualizer shader - except that my initial tests in post 11 of that thread also seemed to indicate some sort of step function, and that simply scaled Du and plugged it into ambient colour, no comp,lex shader to mess things up.
I'm totally confuced by this strange behaviour.
Can anybody shed any light on it ?
Guess not :D
(or maybe my 'explanation' of the 'problem' doesn't make sense to anybody... ;o)
The explanation of the problem makes perfect sense.
I don't have the source code so I can't even tell what it is SUPPOSED to do, let alone what it is doing.
That prompted me to go back and look at what the Poser 9 Reference Manual actually says about the Du node. Chapter 16 "Material Room Nodes", page 349:
"The dU node defines the rate of change of surface parameters as pertains to the current pixel’s location in S space. The ‘d’ indicates a derivative of the ‘U’ parameter."
Q1) I realize that I don't know what 'S space' is. I have a vague idea from somewhere that S is related to U, and T is related to V, but that's it. But I also get the impression from byro.br's investigations at RDNA in 2007 that Du is "...with respect to your output pixels". So maybe S space is the screen/output horizontal axis? Can anybody provide a clear, unambiguous (and correct!) definition of what 'S space' is ?
Q2) The phrase '...rate of change of surface parameters...' begs the question, "which surface parameters?" I'd guess that it's the "...current pixel’s location in S space..." - yes, no?
Stefan himself once told me that dU is rate of change of U with respect to screen space (i.e. rendered pixels). I'm assuming the manual is calling screen space "S". The experiments in the byro 2007 thread support this.
My problem with it is that it is not consistent (which I only casually know, but your graph documents much more clearly) and doesn't seem to be maintained to work with all types of geometry and modifiers.
I did manage to apply it to some good for a flat plane, but found less use in it with curved geometry.
Also, the whining about my "spaghetti" shader complexity goes into the stratosphere when I apply myself to subtle problems such as procedural moiré reduction. There are some (even a Poser ambassador) who pride themselves on simplicity, which is another word for "naïveté". The community we work in is not fond of sophistication or complication.
(I'm just thinking out loud for this post...) With regard to S (and T) p386 of the PP2014 Poser Reference has:
-U Texture Coordinate - The U node returns the S coordinate in texture space of the pixel currently being rendered. It has no user-definable attributes.
-V Texture Coordinate - The V node returns the T coordinate in texture space of the pixel currently being rendered. It has no user-definable attributes.
-Du - The dU node defines the rate of change of surface parameters as pertains to the current pixel’s location in S space. The ‘d’ indicates a derivative of the ‘U’ parameter.
-Dv - The dV node defines the rate of change of surface parameters as pertains to the current pixel’s location in T space. The ‘d’ indicates a derivative of the ‘V’ parameter.
From U/V Texture Coordinate definitions ST is clearly a point in UV (texture) space - the point that represents the pixel being rendered, i.e. the values we use as a lookup into the texture map.
For the Du/Dv definitions S and T are the 'spaces' in which the rates of change of U and V respectively are being calculated. But even knowing that dU is the rate of change of U with respect to screen space I'm still having difficulty visualizing what this actually means, even if I just consider a flat plane perpendicular to the line of sight.
I applied my shader (now uploaded to ShareCG here) to the Poser ground (scaled at 100%) plugged Du x 1,000,000 into it, viewed from the top camera with scale around 800-900% and rendered 3 times with the ground rotated 0, 45, and 90 degrees. I got exactly the same numeric image each time.
So 'S space' seems to be tied to the U direction of the UV mapping of the prop, but mapped onto the output screen.
Another thing just struck me about the numeric textures I'm seeing when I render. For the number to be clearly displayed the input value to the shader (the 'Value_To_Display' input of my compound node) must evaluate to exactly the same value for every pixel on the surface. And usually (at least for the bits that display green) it does.
Here are a few top camera screenshots (different top cam scales) of 1,000,000 x Du driving my shader applied to the groundplane:
In three of those it looks as if Du is being evaluated to at least two different numbers across the surface.
Of course, it could just be my ropey shader. But I think there's more to it...
I've finally got a small number of renders that seem to match what Du is supposed to be doing, and may help to make clear (to me!) exactly how Du is supposed to work.
- PP2014 one-sided square with Du x 1,000,000 plugged into my shader, viewed from the front camera. Square renders to about 316x316 pixels. Du is 0.003040
- Set xRot=60 for the square. It rotates 60 degrees about a horizontal axis through the world origin. The height of the square as viewed from the front camera is exactly half what it was but the height hasn't changed. The value of Du hasn't changed, still 0.003040 and is what I expected
- Set xRot back to zero and set yRot=60. The square rotates 60 degrees about a vertical axis through the world origin. The width of the square as viewed from the front camera is now exactly half what it was. The value of Du has doubled to 0.006081 and is what I expected
- Set yRot back to zero, change the scale of the front camera so that the square renders at half it's original size, 158x158 pixels. Du is 0.006081 and is what I expected
- Set xRot=60 so the height of the square as viewed from the front camera is exactly half what it was but the width hasn't changed The value of Du hasn't changed, still 0.006081 and is what I expected
- Set xRot back to zero and set yRot=60 so the width of the square is now exactly half what it was. The value of Du has doubled to 0.012162 and is what I expected
The value of Du in these tests was inversely proportional to the width of the square in pixels on the render.
I also tried the same tests with Du and got appropriate results - the Dv value started at 0.003040 and doubled when the height halved.
Note that this set of results was rather lucky (at last!) - most things I tried gave me unreadable numbers (as per the previous post) or numbers that refused to change (the step function problem).
Those last three posts were actually supposed to go on my 'thinking out loud' thread at CGbytes thread (I've duplicated them over there in posts [#42]http://www.cgbytes.com/community/forums.aspx?g=posts&m=126979#post126979), #43 and #44 of that thread).
Here's a summary of what I think I've learnt from them regarding how Du and Dv should behave:
1 - from the test where I got doublings of the values of Du (and Dv) as the render dimensions in pixels halved
In the only test so far where I've got Du and Dv to behave in a way that could match what they're supposed to do, and with the following specific caveats based on that test...
a) It's for the specific mesh I was testing with (i.e. the Poser one-sided square, which has just 4 vertices and 1 face)
b) I was viewing from an orthographic camera with square perpendicular to the cameras line of sight.
c) The U mapping direction was horizontal (left to right) on the rendered image and the V mapping direction was vertical (up) on the rendered image
...then a fairly simple equation relates Du, Dv and object size in pixels in the render:
Du = 0.96 / horizontal pixels
Dv = 0.96 / vertical pixels
(Note: The actual value I got isn't precisely 0.96, but between about 0.96064 and 0.96079. My measurements of pixel size are probably not quite right, maybe +/- 1 or 2 pixels, so around 1% error maximum - making the correct figure probably somewhere between 0.95 and 0.97... but unfortunately not a nice round 1.00!)
2 - from the test with the square rotated 0, 45, and 90 degrees around an axis parallel to the camera's line of sight
I have difficulty putting this into words, but Du is related not to actual 'pixels' (which are a grid with horizontal and vertical axes), but to point-to-point distances on the rendered image measured in pixels. Does that make sense? Can somebodty express it in better words?
I'm going to ask if those last four posts of mine can be deleted.
I think they're more appropriate on the CGbytes thread (which is my 'thinking out loud' scratchpad for this Du etc stuff).
I've already posted them over there - and over there I can edit them as my thoughts get clearer.
Once I've got things a bit clearer in my own mind I can post a short summary back here. And I think that would be far more appropriate for this thread.
The explanation of the problem makes perfect sense.
I don't have the source code so I can't even tell what it is SUPPOSED to do, let alone what it is doing.
The last couple of tests I've done, in conjunction with the near certainty that Du and Dv are something to do with rate of change of U and V coordinate mapping with respect to some sort of axis pair in screen (render) space, plus a sudden flash of inspiration from an image on the CGbytes thread (warning: my flashes of inspiration are often wrong!), and I've come up with this as a possible 'what Du and Dv are supposed to be'.
Almost. The .96 isn't intrinsic to the math, it happens to be the width and height of the one sided square's UV coverage.
Like I said (or byro.br did in 2007), if you use a very limited geometry in limited situations it will come out exactly as delta_U / delta_Screen_space_pixels.
If you used a properly made "square" with U going from 0 to 1, then the delta_U would be 1 and you'd exactly get 1 / the rendered width of the square.
Thanks bagginsbill, I didn't even consider that. Just to be 100% certain I went and confirmed for myself (exporting, opening in UV mapper, exporting a map, and checking in GIMP) that the one-sided square's UV mapping is about 97% of the full UV map.
At last I think Du and Dv are beginning to make some sort of sense to me.
Back to the original point of this thread - I think I can now come up with an easy to reproduce test case to demonstrate the strange step function behaviour I've noticed in Du and Dv.
The test is going to have to rely on that numeric visualizer shader, which may have its own problems. But I don't believe that any likely mistake in the shader would account for this step function effect...
Okay, here's a simple repeatable test to demonstrate the behaviour of Du.
It indicates that Du generally produces the correct value, i.e. Du = 1 / (S-space width in pixels), for a simple square prop.
But it also indicates that Du doesn't change smoothly, but in small inconsistently sized steps.
However, I have not yet managed to reproduce the steps with totally incorrect values that I mentioned in the OP. I'm still trying to reproduce that.
~ ~ ~ ~
Here's the repeatable demonstration:
Create a single sided square UV mapped to the full square.
v -0.500000 -0.500000 0.000000
v 0.500000 -0.500000 0.000000
v -0.500000 0.500000 0.000000
v 0.500000 0.500000 0.000000
vt 0.0000 0.0000
vt 1.0000 0.0000
vt 1.0000 1.0000
vt 0.0000 1.0000
f 1/1 2/2 4/3 3/4
Import the OBJ into Poser (I used PP2014 64bit).
Make the Poser ground invisible and move/delete Andy (they get in the way)
Apply my shader ( http://www.sharecg.com/v/85287/gallery/11/Poser/Signed-10-Digit-Integer-Visualizer-MT5 ) to the square
Plug a Du node into the 'Value_To_Display' and set the multiplier to one million.
Set Front Camera DollyX and DollyY to zero and Scale, xScale and yScale to 100%, and then go to Front Camera view.
Set render size to 500 x 500. (the square should just about fill the render area)
Note the number that's rendered on the square (which is 1,000,000 x Du)
Increase the Scale setting of the Front Camera, render, and note the new value.
Repeat with various values of Front Camera Scale (keep it higher than 100% to ensure that the whole square appears in the render).
Here are some results - Front Cam Scale first, then the number displayed on the render.
100% ... 1953
200% ... 3906
400% ... 7812
800% ... 15625
1600% ... (too small to make out the number)
That sequence is almost perfect doubling of the value each time, which is the correct, expected behaviour. Also 1/500 = 0.002, so our first render at 100% which gave Du = 0.001953 was pretty close to the calculated value I'd expect. (I didn't bother actually measuring the square's width in the render for any of these test)
150% ... 3129
300% ... 6298
600% ... 12489
Once again almost perfect doubling (the last digit or two aren't clear)
125% ... 2604
250% ... 5208
500% ... 10416
Doesn't get much more perfect doubling than that.
At this point I began wondering if the problem was all in my head!
So I tried changing scale in 5% steps...
170% ... 3472
175% ... 3472
180% ... 3906
185% ... 3906
190% ... 3906
195% ... 3906
200% ... 3906
205% ... 4166
210% ... 4166
215% ... 4464
220% ... 4464
The value of Du is definitely increasing in steps, not smoothly. Du step sizes are 434, 260, and 298 (divided by a million) for that short sequence. It's possible that these steps are due to IEEE 754 rounding ?
With the tests I've done for this post all the Du values seem to be roughly correct - I haven't yet reproduced my original steps with hugely incorrect values.
I'm totally unable to reproduce that step function with hugely incorrect values in the OP.
I noticed that it occurred in my original graph between correct-seeming Du values of 0.008928 and 0.011363
With my new test I need to set camera scale to between 450% and 550% to get the corresponding range, all other things being equal. Adjusting Front Cam scale in 10% steps from 450 to 550 I got rendered values in sensible steps going 8928 > 9615 > 10416 > 11363
I also tried the same test with the Top Camera (on the highly unlikely off-chance it's camera-related), and in Poser 9. Everything looks sensible. No sign of grossly incorrect values, just those gradual steps following the correct curve
The conclusion I've come to that might explain my OP is that I probably set an incorrect scale resulting in the 4615 reading. When I started taking more readings I was probably adjusting the scale on the wrong camera, thus having no effect. And if that's what I did, I must have done it twice! Once for the 4615 reading, and again for the 17369.
The gradual step size that I''m seeing seems to be inconsitent in magnitude, but always less than 1.1% of the Du (or Dv) value
(I meant 11%, not 1.1%, at the end of that last comment... :) Step size seem to be 6% to 11% of the Du or Dv value)
Remember that FireFly is a REYES renderer - that is, it is chopping your mesh in to a grid of micro polygons. The number of micro polygons created depends on the screen size of the original polygon and on the shading rate. Those steps you see happen every time the number of micro polygons in a grid changes.
To illustrate, it is not the same, but similar in idea to what is demonstrated in this video:
I had to look up Reyes rendering. After reading that I drew the following very simplistic diagram. It's inaccurate, but good enough to show what I'm thinking, and it could indeed explain those steps.
However, between a pair of steps my test indicates that Du evaluates to a fixed value, whereas I'd expect to see Du gradually changing - q.v. the sloping blue line between A and B on the picture.
So I'm sure that I'm missing/misunderstanding something else here.
...of course the number of polygons across the width of the square would be a fixed value between steps, and the step sizes being a fixed percentage of the value would sort-of fit (in this picture each step is 200%, from 2 to 4 to 8).
I'm sure the answer is in what Stefan said, but I'm having a problem trying to visualize it.
Looking at that last graph (with the pink steps) again, I'm now wondering if this is the answer ?
Du = 1 / (S-space 'width' in micropolygons)
Dv = 1 / (T-space 'height' in micropolygons)
(the important change is that I've replaced 'pixels' with 'micropolygons'. S-space and T-space would still be as defined in this previous post. Assuming that the micropolygons are always one pixel (+-6%) in size this might fit...)