Frage

Ich bin die Umsetzung derzeit ein 3D-Perlin Geräusch Bump Mapping Shader Model 4 (DirectX 10 HLSL) verwenden. Erzeugen der Rausch selbst kein großes Problem ist (es gibt Tonnen von Tutorials und Codes um), aber was ich gefunden habe, nicht sind analytische Derivate von 3D Perlin Geräusche.

Die einzigen Websites, um die Derivate zu berücksichtigen sind und ein verwandtes href = "http://www.gamedev.net/community/forums/topic.asp?topic_id=479101"> GameDev.net Diskussion . Das Problem ist, dass in der ersten Verbindung wird das Rauschen Wert basiert, nicht gradientenbasierten (was eine Voraussetzung für mich ist), in dem zweiten Link, gibt es nur 2D-Gradienten Rauschen-Derivat.

Beachten Sie, dass ich nicht für numerische Derivate suchen, wie sie benötigen 4 benachbarten Geräuschproben erzeugt werden, und das ist viel zu viel Aufwand.

Hat jemand diese Derivate berechnet? Gibt es eine Referenz-Implementierung, die sie verwendet?

War es hilfreich?

Lösung

Ich konnte auch nicht gefunden, eine Lösung auf dem Netz heute, so dass ich versuchte, es zu gewinnen.

Zunächst werden die Notationen eines 3D-Perlin Rauschen definiert ist.

Notation

Es sei angenommen Rauschen der 3D Perlin durch die trilineare Interpolation als berechnet

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

wobei u, v, w die Interpolationsfaktoren durch das Polynom fünften Grades der Fraktion Koordinaten sind (das heißt, verbesserte Perlin Rauschen):

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)

und dot___s ist Skalarprodukte des Gradientenvektoren (gx___, gy___, gz___)s an Gitterpunkten, und die Fraktion Koordinaten:

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

Computer die Derivate

Als erstes Rechen Derivate von u, v und 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)

Mit dem n mit Lerp(a, b, t) = a + (b - a) * t Erweiterung

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)

Dann nehmen Sie partiellen Ableitungen von 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)

Dann (nx, ny, nz) ist der Gradientenvektor (partielle Ableitungen) der Rauschfunktion.

Optimierung

Einige gemeinsamen Unterausdruck kann herausgerechnet werden, wenn der Compiler es nicht verarbeiten kann. Zum Beispiel:

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

Die Koeffizienten in der erweiterten n werden mehrfach wiederverwendet werden. Sie können durch berechnet werden:

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

Auch die Derivate hat Ähnliche Koeffizienten,

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

Die Berechnung der n kann verwendet die erweiterte Form mit k0, ... k6 auch.

Abschließende Worte

Diese Lösung hat sich gegen zentrale Differenzverfahren überprüft worden.

Obwohl diese Lösung aussieht unbeholfen, mein Experiment (CPU nur, SSE) hat gezeigt, dass die Berechnung dieser Derivate durch diese Lösung nur erleidet und über 50% mehr Zeit , um die Berechnung einer einzigen 3D Perlin Geräuschprobe.

Finite Differenz benötigt mindestens 300% Verlängerung (tut extra 3 Proben) oder 600% (dabei 6 Proben für die zentralen Unterschied).

Daher ist diese Lösung besser in Leistung und soll auch numerisch stabil sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top