Latexluv opened this issue on Jun 04, 2010 · 182 posts
bagginsbill posted Thu, 10 June 2010 at 10:04 PM
Quote - > Quote - ...
In Poser, the Edge_Blend node internally calculates and uses the cosine of the angle of incidence. If you set the parameters to white, black, and 1, then the cos(alpha) is actually what it generates as its output. How nice!
...
BB, I'm a little lost. How do white, black, and 1 end up generating the cosine of alpha in the Edge_Blend node?
I'll need a little time to produce the diagram, but meanwhile I'll answer this question.
The answer is I formed several hypotheses about how Edge_Blend works, designed some tests to distinguish between the possibilities, and thereby discovered exactly what it does.
We know from the start that the EB node interpolates between two colors; Inner_Color and Outer_Color. Interpolation (or Blending) can be done a number of ways, but the most obvious is linear interpolation. In fact, this is what the Blender node does.
Blender(a, b, f) is:
(1-f) * a + f * b
As I said in a previous post, this is also called a weighted sum. The weight given to "a" versus "b" is determined by f. When f is 0, all you get is "a". When f is 1, all you get is "b". When f is .5, we expect the result to be an average of a and b. This is easily verified by examining the formula for those cases.
f = 0: (1-0) * a + 0 * b = 1 * a + 0 = a
f = 1: (1-1) * a + 1 * b = 0 + b = b
f = .5: (1 - .5) * a + .5 * b = .5 * a + .5 * b = .5 * (a + b) = (a + b) / 2
An interesting special case of the Blender node, one we'll get to at the end, is when a = 0 and b = 1.
If a = 0 and b = 1, then we get:
(1-f) * a + f * b
= (1-f) * 0 + f * 1
= f
The relevance of this is about to be revealed, because I'm going to show how, hidden inside, the value of f is cos(alpha).
Now the Edge_Blend node is actually a Blender node with the factor, f, generated internally. The question is, how is it generated?
There are only two reasonable guesses. The angle of incidence, alpha, could be used, or the cosine of the angle, cos(alpha).
The angle itself is the obvious one, and we could assume that if the angle is expressed from 0 to 90, that f is simply alpha/90. Thus when alpha is 0, f = 0. When alpha is 90, f = 1. This would be a reasonable way to go, except that Poser doesn't actually know the angle, at least not easily.
Far easier for Poser is to calculate the cosine of the angle. I don't know if you are familiar with vector math, but it turns out that given two vectors, P and Q, the cosine of the angle between them is trivially given by computing the dot product of P and Q, as long as the vectors are unit length. In math notation, you actually write a dot between them, but I don't know how to type such a thing, so I'll just say P dot Q.
So - why is P dot Q so cheap? Because it is simply:
P.x * Q.x + P.y * Q.y + P.z * Q.z
That's three multiplies and two adds - pretty much free in the world of 3D math.
Given the surface normal, N, which is needed to do any kind of lighting, and the normalized vector towards the camera or viewer, V, the cosine of the angle of incidence, alpha, is just N dot V!! Since N and V are already needed for lots of other things, they don't cost anything when an Edge_Blend node is used. .They're already there. And they're normalized, too, because dot products and cosines of angles are used in lots of lighting calculations.
So Poser has a super trivial way to compute cos(alpha) without doing any transcendental math at all. And this very neatly gives a value of 1 when the surface points straight at the camera, and 0 when it points away to the side. Values in between decrease monotonically from 1 to 0.
So I guessed that Poser was somehow using N dot V, or cos(alpha) to blend Inner_Color and Outer_Color.
There is a third parameter, however, called Attenuation. What is this for?
Since I knew something about how angles are used in shaders, particularly in RSL shaders, I knew that many effects are commonly controlled with respect to a cone of influence by taking the cos(alpha) and raise it to some power, i.e.
cos(alpha) ** P
This has the effect of making any modulation based on cos(alpha) become more weighted towards or away from the center, depending on whether P is more or less than 1.
I then hypothesized, tested for, and verified that the full equation of Edge_Blend is:
Blender(Outer_Color, Inner_Color, cos(alpha) ** Attenuation)
Expanding that out we get this for Edge_Blend:
(1 - cos(alpha) ** Attenuation) * Outer_Color + (cos(alpha) ** Attenuation) * Inner_Color
Now: plug in the values I said: Inner_Color =1 (white), Outer_Color = 0 (black) and Attenuation = 1.
(1 - cos(alpha) ** 1) * 0 + (cos(alpha) ** 1) * 1
Reduce all that, and you're left with:
cos(alpha)
Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)