Question

J'exécute actuellement un bump mapping bruit de Perlin 3D à l'aide Shader Model 4 (DirectX 10 HLSL). La génération du bruit lui-même est pas un gros problème (il y a des tonnes de tutoriels et codes autour), mais ce que je ne l'ai pas trouvé sont des dérivés d'analyse du bruit 3D Perlin.

Les seuls sites qui prennent les dérivés en compte sont site Inigo Quilez et lié GameDev.net discussion . Le problème est que dans le premier lien le bruit est axée sur la valeur, et non gradient basé (ce qui est une exigence pour moi), dans le second lien, il n'y a qu'un gradient dérivé du bruit 2D.

Notez que je ne cherche pas des dérivés numériques que ceux nécessitent 4 échantillons de bruit voisins à générer et de trop de frais généraux.

Quelqu'un at-il calculé ces dérivés? Y at-il une implémentation de référence qui les utilise?

Était-ce utile?

La solution

Je ne pouvais pas trouver aussi une solution sur le web d'aujourd'hui, donc j'ai essayé de le déduire.

Tout d'abord les notations d'un bruit de Perlin 3D est défini.

Notation

Supposons que le Perlin 3D est le bruit calculée par l'interpolation trilinéaire comme

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

u, v, w sont les facteurs d'interpolation par le polynôme quintique de coordonnées de la fraction (à savoir, l'amélioration de bruit Perlin):

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)

dot___s sont des produits de points des vecteurs de gradient (gx___, gy___, gz___)s à points de réseau et les coordonnées de la fraction:

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

Calcul des dérivés

En premier lieu, les dérivés de calcul de u, v et 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)

En élargissant n avec 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)

Ensuite, prendre dérivées partielles de 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)

Alors (nx, ny, nz) est le vecteur de gradient (dérivés partielle) de la fonction de bruit.

Optimisation

Certains sous-expression commune peut être factoriser, si le compilateur ne peut pas le manipuler. Par exemple:

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

Les coefficients du n élargi sont réutilisés plusieurs fois. Ils peuvent être calculés par:

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

De plus, les dérivés a des coefficients similaires,

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

Le calcul de n peut utilise la forme développée avec k0, ... k6 ainsi.

Derniers mots

Cette solution a été vérifié contre Procédé central de différence.

Bien que cette apparence de solution maladroite, mon expérience (CPU uniquement, SSE) a montré que, calcul de ces dérivés par cette solution ne encourt sur 50% de temps supplémentaire pour le calcul d'un seul échantillon de bruit 3D Perlin.

différence finie aura besoin d'au moins 300% du temps supplémentaire (faisant supplémentaires 3 échantillons) ou 600% (6 échantillons pour faire la différence central).

Par conséquent, cette solution est une meilleure performance, et devrait également être stable numériquement plus.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top