pocketmoon

09-06-2002, 12:13 AM

NV30 question of course http://www.opengl.org/discussion_boards/ubb/smile.gif

What,How,Why ?

What,How,Why ?

View Full Version : So what are Fragment Program Partial Derivatives

pocketmoon

09-06-2002, 12:13 AM

NV30 question of course http://www.opengl.org/discussion_boards/ubb/smile.gif

What,How,Why ?

What,How,Why ?

pbrown

09-06-2002, 04:29 AM

Originally posted by pocketmoon:

NV30 question of course http://www.opengl.org/discussion_boards/ubb/smile.gif

What,How,Why ?

Some shading effects want to know how fast a given quantity is changing in X and Y. The DDX and DDY instructions give you this information (or more accurately, approximate it). My background with fancy shading effects is really limited, so here's a trivial example:

The extension SGIX_texture_lod_bias allowed applications to independently bias the "S", "T", and "R" partials used for LOD calculation. Some of the motivations for this approach rather than the simpler constant LOD bias in OpenGL 1.4 include (from the spec):

Examples of textures which can benefit from this LOD control include video-capture images which are filtered differently horizontally and vertically; a texture which appears blurry because it is mapped with a nonuniform scale, such as a road texture which is repeated hundreds of times in one dimension and only once in the other; and textures which had to be magnified to a power-of-two for mipmapping.

NV_fragment_program allows you to emulate this functionality using the following instruction sequence:

# Grab the texture coordinate partials.

DDX R0, f[TEX0];

DDY R1, f[TEX0];

# Scale the partial derivatives of R by 1.5

MUL R0, {1.5, 1.0, 1.0, 1.0};

MUL R1, {1.5, 1.0, 1.0, 1.0};

# Do the lookup with program-specified partials.

TXD f[TEX0], R0, R1, TEX0, 2D;

I'm sure you can do a lot of fancier things. This is a relatively cheesy, but easy-to-understand example.

[This message has been edited by pbrown (edited 09-06-2002).]

NV30 question of course http://www.opengl.org/discussion_boards/ubb/smile.gif

What,How,Why ?

Some shading effects want to know how fast a given quantity is changing in X and Y. The DDX and DDY instructions give you this information (or more accurately, approximate it). My background with fancy shading effects is really limited, so here's a trivial example:

The extension SGIX_texture_lod_bias allowed applications to independently bias the "S", "T", and "R" partials used for LOD calculation. Some of the motivations for this approach rather than the simpler constant LOD bias in OpenGL 1.4 include (from the spec):

Examples of textures which can benefit from this LOD control include video-capture images which are filtered differently horizontally and vertically; a texture which appears blurry because it is mapped with a nonuniform scale, such as a road texture which is repeated hundreds of times in one dimension and only once in the other; and textures which had to be magnified to a power-of-two for mipmapping.

NV_fragment_program allows you to emulate this functionality using the following instruction sequence:

# Grab the texture coordinate partials.

DDX R0, f[TEX0];

DDY R1, f[TEX0];

# Scale the partial derivatives of R by 1.5

MUL R0, {1.5, 1.0, 1.0, 1.0};

MUL R1, {1.5, 1.0, 1.0, 1.0};

# Do the lookup with program-specified partials.

TXD f[TEX0], R0, R1, TEX0, 2D;

I'm sure you can do a lot of fancier things. This is a relatively cheesy, but easy-to-understand example.

[This message has been edited by pbrown (edited 09-06-2002).]

Nakoruru

09-06-2002, 04:54 AM

First, do you know what a partial derivative is?

A partial derivative is the derivative of a multivariate function in only one of its dimensions. e.g., it is how fast a function in x and y is changing in only x or y. This is stuff ussually covered in a third semester Calculus class (which is basically Calculus I but you have to do everything 3 times because you end up having to take the x, y, and z partial deriviatives of a 3d function and then do some calculus I stuff on the 3 results).

If you think of the screen as a function of x and y, then the partial derivative in x or y describes how a fragment changes from pixel to pixel in either the x or y direction.

The fragment values in fragment programs are stored in registers, and you can take the derivative of any register and any particular point in the program.

It basically tells you what the difference between the contents of this register at this point in the program and the contents of this same register at this same point in the program for adjacent pixels.

Or, in other words, by how much will this register will be different when it is run for the pixel one over (dx) or one below (dy)

e.g., if you store a texture lookup result in the register, then take the partial derivative in x, then the result of the derivative will be the difference between the texture lookup this time and the texture lookup for the adjacent pixel. This is how fast the texture is changing.

The nvidia docs say its impossible to take a second derivative, which breeds some doubt into my thinking, because it seems I could just store the result of my partial derivative into another register and then take its derivative again.

A partial derivative is the derivative of a multivariate function in only one of its dimensions. e.g., it is how fast a function in x and y is changing in only x or y. This is stuff ussually covered in a third semester Calculus class (which is basically Calculus I but you have to do everything 3 times because you end up having to take the x, y, and z partial deriviatives of a 3d function and then do some calculus I stuff on the 3 results).

If you think of the screen as a function of x and y, then the partial derivative in x or y describes how a fragment changes from pixel to pixel in either the x or y direction.

The fragment values in fragment programs are stored in registers, and you can take the derivative of any register and any particular point in the program.

It basically tells you what the difference between the contents of this register at this point in the program and the contents of this same register at this same point in the program for adjacent pixels.

Or, in other words, by how much will this register will be different when it is run for the pixel one over (dx) or one below (dy)

e.g., if you store a texture lookup result in the register, then take the partial derivative in x, then the result of the derivative will be the difference between the texture lookup this time and the texture lookup for the adjacent pixel. This is how fast the texture is changing.

The nvidia docs say its impossible to take a second derivative, which breeds some doubt into my thinking, because it seems I could just store the result of my partial derivative into another register and then take its derivative again.

pocketmoon

09-06-2002, 05:02 AM

Thanks, I'm happy with the definition of a partial derivative. I was really wondering what application it could have.

I suppose if your generating things like procedural textures where your not getting a nice filtered texel value from a texture map, it would be handy to know how fast you procedural texture is changing ?? To smooth things out ???

I suppose if your generating things like procedural textures where your not getting a nice filtered texel value from a texture map, it would be handy to know how fast you procedural texture is changing ?? To smooth things out ???

Nakoruru

09-06-2002, 06:07 AM

Yeah, if you take the derivative of your texture coordinates, you can get the projected area of the texture on the screen, which can be used to determine the sample kernel size.

if s and t are texture coordinates then

ds * dt = texel_area

texel_area is how many texels have been squished (minified) into the current screen pixel. Of course, if its being magnified, then texel_area will be less than one.

if s and t are texture coordinates then

ds * dt = texel_area

texel_area is how many texels have been squished (minified) into the current screen pixel. Of course, if its being magnified, then texel_area will be less than one.

mcraighead

09-06-2002, 12:12 PM

Actually, the area should be computed as the area of a parallelogram. You want a 2D cross product. But that's another story...

- Matt

- Matt

davepermen

09-06-2002, 12:34 PM

hehe http://www.opengl.org/discussion_boards/ubb/biggrin.gif

Nakoruru

09-06-2002, 01:36 PM

maybe '*' meant 'x', how can you tell, yeah, that's the ticket ^_^

I was not specifically thinking about it (in very general terms what I said was correct, I just didn't think about details), but indeed, s and t are vectors with respect to x and y and the * is a cross product.

Lets express it more precisely:

texel_area = cross(vec(dx(s), dy(s)), vec(dx(t), dy(t)))

Better?

[This message has been edited by Nakoruru (edited 09-06-2002).]

I was not specifically thinking about it (in very general terms what I said was correct, I just didn't think about details), but indeed, s and t are vectors with respect to x and y and the * is a cross product.

Lets express it more precisely:

texel_area = cross(vec(dx(s), dy(s)), vec(dx(t), dy(t)))

Better?

[This message has been edited by Nakoruru (edited 09-06-2002).]

zeckensack

09-06-2002, 06:43 PM

What's a 2D cross product?

It's commonly only defined for 3D vectors, isn't it?

It's commonly only defined for 3D vectors, isn't it?

SirKnight

09-06-2002, 07:29 PM

Ya at first hearing 2D cross product is like WTF. http://www.opengl.org/discussion_boards/ubb/smile.gif But actually what it is, is where you rotate one vector CCW by 90 degrees and take the dot product between your two vectors. You can use this to determine if a set of points are in say clockwise order.

Oh BTW, I just found a page that talks about this exactly like i say. http://www.opengl.org/discussion_boards/ubb/biggrin.gif Here is the URL: http://www.geocities.com/SiliconValley/2151/math2d.html

-SirKnight

Oh BTW, I just found a page that talks about this exactly like i say. http://www.opengl.org/discussion_boards/ubb/biggrin.gif Here is the URL: http://www.geocities.com/SiliconValley/2151/math2d.html

-SirKnight

mrbill

09-07-2002, 06:07 AM

Originally posted by Nakoruru:

The nvidia docs say its impossible to take a second derivative, which breeds some doubt into my thinking, because it seems I could just store the result of my partial derivative into another register and then take its derivative again.

It's not "impossible." It's definately *possible* to take a second derivative (and third, fourth...) but the language in that spec says doing so "may not yield accurate second derivatives."

So, let's back up from implementation for a moment (and since I don't work for NVIDIA I'd just as soon not get into their implementation details anyway) and back up to the OpenGL machine. (This has come up in GL2 as well.)

So, for the OpenGL machine, we need to document a method for producing an approximate derivative, even though implementations may choose other methods to approximate a derivative.

Let's take a closer look at two obvious methods to produce an approximate derivative.

Forward differencing:

eq. 1a: F(x+dx)-F(x) ~ dFdx(x) * dx

eq. 1b: dFdx(x) ~ ( F(x+dx)-F(x) ) / dx

Backward differencing:

eq. 2a: F(x-dx)-F(x) ~ -dFdx(x) * dx

eq. 2b: dFdx(x) ~ ( F(x)-F(x-dx) ) / dx

Either equation 1b or 2b produces an acceptable approximate derivative, so either can be used, or even *both* can be used. (There might be some invariance restrictions when both are used.)

Imagine now that we've got two neighboring fragments. The first fragment's approximate derivative is calculated by 1b. The second fragment's approximate derivative is calculated by 2b. We'll assume single sampling, and set dx=1.

First fragment:

3a: F(x) = F(x0)

3b: F(x+dx) = F(x1)

Substituting into 1b:

3c: dFdx(x0) ~ ( F(x1)-F(x0) ) / dx

Second fragment:

4a: F(x) = F(x1)

4b: F(x-dx) = F(x0)

Substitution into 2b:

4c: dFdx(x1) ~ ( F(x1)-F(x0) ) / dx

Eek. 3c and 4c are the same!

Take the dFdx again, and what will you get?

Zero. Which isn't a very accurate second derivative. (Or third, or fourth...)

Does this make sense? (Does this make no sense?)

-mr. bill

The nvidia docs say its impossible to take a second derivative, which breeds some doubt into my thinking, because it seems I could just store the result of my partial derivative into another register and then take its derivative again.

It's not "impossible." It's definately *possible* to take a second derivative (and third, fourth...) but the language in that spec says doing so "may not yield accurate second derivatives."

So, let's back up from implementation for a moment (and since I don't work for NVIDIA I'd just as soon not get into their implementation details anyway) and back up to the OpenGL machine. (This has come up in GL2 as well.)

So, for the OpenGL machine, we need to document a method for producing an approximate derivative, even though implementations may choose other methods to approximate a derivative.

Let's take a closer look at two obvious methods to produce an approximate derivative.

Forward differencing:

eq. 1a: F(x+dx)-F(x) ~ dFdx(x) * dx

eq. 1b: dFdx(x) ~ ( F(x+dx)-F(x) ) / dx

Backward differencing:

eq. 2a: F(x-dx)-F(x) ~ -dFdx(x) * dx

eq. 2b: dFdx(x) ~ ( F(x)-F(x-dx) ) / dx

Either equation 1b or 2b produces an acceptable approximate derivative, so either can be used, or even *both* can be used. (There might be some invariance restrictions when both are used.)

Imagine now that we've got two neighboring fragments. The first fragment's approximate derivative is calculated by 1b. The second fragment's approximate derivative is calculated by 2b. We'll assume single sampling, and set dx=1.

First fragment:

3a: F(x) = F(x0)

3b: F(x+dx) = F(x1)

Substituting into 1b:

3c: dFdx(x0) ~ ( F(x1)-F(x0) ) / dx

Second fragment:

4a: F(x) = F(x1)

4b: F(x-dx) = F(x0)

Substitution into 2b:

4c: dFdx(x1) ~ ( F(x1)-F(x0) ) / dx

Eek. 3c and 4c are the same!

Take the dFdx again, and what will you get?

Zero. Which isn't a very accurate second derivative. (Or third, or fourth...)

Does this make sense? (Does this make no sense?)

-mr. bill

Powered by vBulletin® Version 4.2.2 Copyright © 2016 vBulletin Solutions, Inc. All rights reserved.