English 中文(简体)
3D Perlin noise analytical derivative
原标题:

I am currently implementing a 3D Perlin noise bump mapping using Shader Model 4 (DirectX 10 HLSL). Generating the noise itself is not a big problem (there are tons of tutorials and codes around) but what I have not found are analytical derivatives of 3D Perlin noise.

The only sites taking the derivatives into account are Ińigo Quilez s site and a related GameDev.net discussion. The problem is that in the first link the noise is value based, not gradient based (which is a requirement for me), in the second link, there s only 2D gradient noise derivative.

Note that I m not looking for numerical derivatives as those require 4 neighboring noise samples to be generated and that s way too much overhead.

Has anyone calculated these derivatives? Is there a reference implementation that is using them?

最佳回答

I also could not found a solution on the web today, so I tried to derive it.

Firstly the notations of a 3D Perlin noise is defined.

Notation

Assume the 3D Perlin noise is computed by the trilinear interpolation as

n = Lerp(
        Lerp(
            Lerp(dot000, dot100, u),
            Lerp(dot010, dot110, u),
            v), 
        Lerp(
            Lerp(dot001, dot101, u), 
            Lerp(dot011, dot111, u),
            v),
        w)

where u, v, w are the interpolation factors by the quintic polynomial of fraction coordinates (i.e., improved Perlin noise):

x0 = frac(x)
y0 = frac(y)
z0 = frac(z)
x1 = x0 - 1
y1 = y0 - 1
z1 = z0 - 1

u = x0 * x0 * x0 * (x0 * (6 * x0 - 15) + 10)
v = y0 * y0 * y0 * (y0 * (6 * y0 - 15) + 10)
w = z0 * z0 * z0 * (z0 * (6 * z0 - 15) + 10)

and dot___s are dot products of the gradient vectors (gx___, gy___, gz___)s at lattice points and the fraction coordinates:

dot000 = gx000 * x0 + gy000 * y0 + gz000 * z0
dot100 = gx100 * x1 + gy100 * y0 + gz100 * z0
dot010 = gx010 * x0 + gy010 * y1 + gz010 * z0
dot110 = gx110 * x1 + gy110 * y1 + gz110 * z0
dot001 = gx001 * x0 + gy001 * y0 + gz001 * z1
dot101 = gx101 * x1 + gy101 * y0 + gz101 * z1
dot011 = gx011 * x0 + gy011 * y1 + gz011 * z1
dot111 = gx111 * x1 + gy111 * y1 + gz111 * z1

Computing the derivatives

First, compute derivatives of u, v and w

u  = 30 * x0 * x0 * (x0 - 1) * (x0 - 1)
v  = 30 * y0 * y0 * (y0 - 1) * (y0 - 1)
w  = 30 * z0 * z0 * (z0 - 1) * (z0 - 1)

By expanding n with Lerp(a, b, t) = a + (b - a) * t,

n = dot000 
  + u(dot100 - dot000)
  + v(dot010 - dot000)
  + w(dot001 - dot000)
  + uv(dot110 - dot010 - dot100 + dot000)
  + uw(dot101 - dot001 - dot100 + dot000)
  + vw(dot011 - dot001 - dot010 + dot000)
  + uvw(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)

Then take partial derivatives of n,

nx = gx000
   + u   (dot100 - dot000)
   + u   (gx100 - gx000)
   + v   (gx010 - gx000)
   + w   (gx001 - gx000)
   + u v (dot110 - dot010 - dot100 + dot000)
   + uv  (gx110 - gx010 - gx100 + gx000)
   + u w (dot101 - dot001 - dot100 + dot000)
   + uw  (gx101 - gx001 - gx100 - gx000)
   + vw  (gx011 - gx001 - gx010 + gx000)
   + u vw(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)
   + uvw (gx111 - gx011 - gx101 + gx001 - gx110 + gx010 + gx100 - gx000)

,

ny = gy000
   + u   (gy100 - gy000)
   + v   (dot010 - dot000)
   + v   (gy010 - gy000)
   + w   (gy001 - gy000)
   + uv  (dot110 - dot010 - dot100 + dot000)
   + uv  (gy110 - gy010 - gy100 + gy000)
   + uw  (gy101 - gy001 - gy100 + gy000)
   + v w (dot011 - dot001 - dot010 + dot000)
   + vw  (gy011 - gy001 - gy010 + gy000)
   + uv w(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)
   + uvw (gy111 - gy011 - gy101 + gy001 - gy110 + gy010 + gy100 - gy000)

,

nz = gz000
   + u   (gz100 - gz000)
   + v   (gz010 - gz000)
   + w   (dot001 - dot000)
   + w   (gz001 - gz000)
   + uv  (gz110 - gz010 - gz100 + gz000)
   + uw  (dot101 - dot001 - dot100 + dot000)
   + uw  (gz101 - gz001 - gz100 + gz000)
   + vw  (dot011 - dot001 - dot010 + dot000)
   + vw  (gz011 - gz001 - gz010 + gz000)
   + uvw (dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)
   + uvw (gz111 - gz011 - gz101 + gz001 - gz110 + gz010 + gz100 - gz000)

Then (nx, ny, nz) is the gradient vector (partial derivatives) of the noise function.

Optimization

Some common sub-expression can be factored out, if the compiler cannot handle it. For example:

uv = u * v
vw = v * w
uw = u * w
uvw = uv * w

The coefficients in the expanded n are reused multiple times. They can be computed by:

k0 = dot100 - dot000
k1 = dot010 - dot000
k2 = dot001 - dot000
k3 = dot110 - dot010 - k0
k4 = dot101 - dot001 - k0
k5 = dot011 - dot001 - k1
k6 = (dot111 - dot011) - (dot101 - dot001) - k3

Also the derivatives has similar coefficients,

gxk0 = gx100 - gx000
gxk1 = gx010 - gx000
...

The computation of n can uses the expanded form with k0, ... k6 as well.

Final words

This solution has been verified against central difference method.

Although this solution looks clumsy, my experiment (CPU only, SSE) showed that, computing these derivatives by this solution only incurs about 50% extra time to computing a single 3D Perlin noise sample.

Finite difference will at least need 300% extra time (doing extra 3 samples) or 600% (doing 6 samples for central difference).

Therefore, this solution is better in performance, and should also be more numerically stable.

问题回答

暂无回答




相关问题
3D Engine for Driving Simulation [closed]

Is there any open-source 3D graphics and physics engine specialized in driving simulation? Something like a configurable game engine targeted at games that involve driving, or something more ...

How to rotate 3d object on Z axis only?

We used 3DTools (http://3dtools.codeplex.com) to draw a 3d line, it allows user rotate it by mouse. I have question, how to limit user can rotate it on Z axis only? or on X axis, Y axis only? <...

WPF 3d rotation animations

I have a few 3d rectangles on my screen that I want to pivot around the Y axis. I want to press down with the mouse, and rotate the 3d object to a max rotation, but when the user moves their mouse, ...

Java - Zoom / 3D Data Visualization Libraries

What are the best libraries/frameworks for doing 3D and/or Zoom interfaces in Java? I d like to be able to do some prototyping of creating new types of interfaces for navigating within data and ...

Using Unreal 3 Engine within a .NET application

Now that the Unreal Development Kit for Unreal 3 engine is free I am thinking about utilizing it for an appication. Do you think it is possible to emebedd a Unreal 3 powered 3D window into a .NET (WPF ...

WPF convert 2d mouse click into 3d space

I have several geometry meshes in my Viewport3D, these have bounds of (w:1800, h:500, d:25). When a user clicks in the middle of the mesh, I want the Point3D of (900, 500, 25)... How can I achieve ...

热门标签