La génération d'une normal map à partir d'une carte de hauteur?
Je suis en train de travailler sur le plan procédural générer des taches de saleté à l'aide d'randomisés fractales pour un jeu vidéo. J'ai déjà généré une hauteur de la carte en utilisant le milieu algorithme de déplacement et l'a sauvé d'une texture. J'ai quelques idées pour les transformer en une texture de normales, mais certains commentaires seront très appréciés.
Ma hauteur, la texture est actuellement 257 x 257 échelle de gris de l'image (hauteur valeurs sont mises à l'échelle pour des raisons de visibilité):
Ma pensée est que chaque pixel de l'image représente un treillis de coordonner dans un 256 x 256 grille (d'où, pourquoi, il y a 257 x 257 hauteurs). Cela voudrait dire que la normale au niveau de coordonnées (i, j) est déterminée par la hauteur d'au (i, j), (i, j + 1), (i + 1, j) et (i + 1, j + 1) (appelons ces A, B, C, et D, respectivement).
Alors donné les coordonnées 3D de A, B, C, et D, ne serait-il judicieux de:
- split quatre en deux triangles ABC et BCD
- calculer les normales de ces deux visages, via la croix-produit
- divisé en deux triangles ACD et ABD
- calculer les normales de ces deux faces
- la moyenne des quatre normales
...ou est-il plus facile, que je suis absent?
- Je ferais les mêmes, sauf que je voudrais utiliser les 4 points (i, j+1), (i+1, j), (i, j-1) et (i-1, j) pour calculer les normales, de sorte que (i, j) est dans le centre d'entre eux. De toute façon, je pense que vous êtes sur la bonne voie 🙂
- Pour le "plus facile" de la méthode, vous devez savoir quelle est la fonction décrit la hauteur de x,y.. quelque chose comme h = f(x,y), et à partir de là, vous pouvez tirer les normales de la fonction en x,y... à Moins d'avoir cette fonction, votre méthode est le meilleur que vous pouvez faire 😉
Vous devez vous connecter pour publier un commentaire.
Exemple GLSL code de mon eau de la surface de rendu shader:
Le résultat est une bosse vecteur: xyz=normal, r=hauteur
vec3 va = normalize(vec3(size.x, s21-s01, size.y)); vec3 vb = normalize(vec3(size.y, s12-s10, -size.x));
lors de changement de Y et Z sont pas une grosse affaire, j'ai pensé qu'il était intéressant que j'ai eu à soustraires21-s01
au lieu des21-s11
comme l'exemple indique. J'ai également eu à niersize.x
dansvb
.va
etvb
doivent être calculées à l'aide de2.0, 0.0
. Pourquoi est-il que nous avons besoin exactement le nombre2
et0
ici, résultant dans des vecteurs(2, 0, s21-s01)
et(0, 2, s12-s10)
. Quelqu'un peut m'expliquer ce mathématiquement?Pas. Chaque pixel de l'image représente un sommet de la grille, de façon intuitive, par symétrie, sa normale est déterminée par les hauteurs des pixels voisins (i-1,j), (i+1,j), (i,j-1), (i,j+1).
Donné une fonction f : ℝ2 → ℝ, qui décrit une surface dans ℝ3, une unité normal à (x,y) est donnée par
v = (−∂f/∂x −∂f/∂y, 1) et n = v/|v|.
Il peut être prouvé que la meilleure approximation de ∂f/∂x par deux échantillons est archivée par:
∂f/∂x(x,y) = (f(x+ε,y) − f(x−ε,y))/(2ε)
Pour obtenir une meilleure approximation que vous devez utiliser au moins quatre points, donc l'ajout d'un troisième point (c'est à dire (x,y)) n'améliore pas le résultat.
Votre hightmap est un échantillonnage de quelques-uns de la fonction f sur une grille régulière. Prendre ε=1, vous obtenez:
2v = (f(x−1,y) − f(x+1,y), f(x,y−1) − f(x,y+1), 2)
Une méthode courante consiste à l'aide d'un Sobel filtre pondérée/lisse dérivés dans chaque direction.
Commencer par échantillonnage d'une zone de 3x3 de hauteurs autour de chaque texel (ici,
[4]
est le pixel nous voulons que la normal).Puis,
Où
scale
peut être ajusté pour correspondre à la heightmap monde réel de la profondeur par rapport à sa taille.const float d = 2.0
et remplacé que pour les 2 dans les calculs et bam, il a fonctionné à merveille.Si vous pensez à chaque pixel comme un sommet plutôt qu'un visage, vous pouvez générer un simple maillage triangulaire.
Chaque point a de coordonnées x et y correspondant à x et y du pixel de la carte. La coordonnée z est basé sur la valeur de la carte à l'emplacement. Les Triangles peuvent être générés, explicitement ou implicitement, par leur position dans la grille.
Ce que vous avez besoin est normal à chaque sommet.
Un vertex normal peut être calculé en prenant une superficie moyenne pondérée de la surface normales pour chacun des triangles qui se rencontrent en ce point.
Si vous avez un triangle dont les sommets
v0
,v1
,v2
, alors vous pouvez utiliser un vecteur de la croix (produit de deux vecteurs qui se trouvent sur les deux côtés du triangle) pour le calcul d'un vecteur dans la direction de la normale et mises à l'échelle proportionnellement à la surface du triangle.Chacun de vos sommets qui ne sont pas sur le bord sera partagé par six triangles. Vous pouvez faire une boucle par le biais de ces triangles, résumant le
contribution
s, puis de normaliser le vecteur somme.Remarque: Vous devez calculer la croix des produits, de manière cohérente, assurez-vous que les normales sont toutes orientées dans la même direction. Toujours choisir des deux côtés, dans le même ordre (dans le sens horaire ou anti-horaire). Si vous mélangez certains d'entre eux, ces contributions sera orienté dans la direction opposée.
Pour les sommets sur le bord, vous vous retrouvez avec une boucle plus courte et beaucoup de cas particuliers. Il est probablement plus facile de créer une bordure autour de votre grille de faux sommets, puis de calculer les normales pour l'intérieur et jeter le faux frontières.
Si vous avez besoin de la normale en un point particulier sur un triangle (autre que l'un des sommets), vous pouvez interpoler en pesant les normales des trois sommets par les coordonnées barycentriques de votre point de vue. C'est de cette façon graphique rasterizers traiter la normale pour l'ombrage. Il permet à un triangle mesh pour apparaître comme lisse, la surface courbe plutôt que d'un tas de côté plat triangles.
Astuce: Pour votre premier essai, utiliser une surface parfaitement plane de la grille et assurez-vous que toutes les valeurs normales sont droites.