La création d'une image transparente dans Photoshop est simple: recadrez l'image, saisissez les parties découpées droite et inférieure, puis collez-les à gauche et en haut à l'aide de l'outil Fondu. Mais pour la bonne mise en œuvre de cartes de bruit homogènes, vous devez bien réfléchir.Si vous avez une compréhension de base du bruit Perlin , vous savez qu'il se compose de nombres aléatoires interpolés. Il est principalement utilisé en deux dimensions. Mais il est également utile en une dimension (par exemple lors d'un déplacement), en trois dimensions (transformation cylindrique et sphérique d'objets 3D), et même en quatre ou cinq dimensions.Le bruit en quatre dimensions peut être utilisé pour créer une image 2D transparente. Il n'est pas très courant pour nous de penser en quatre dimensions, nous allons donc prendre une dimension à la fois.Dans mes exemples, j'ai utilisé du bruit simplex à deux octaves. Le bruit simplex est plus rapide dans les grandes dimensions et, en raison de sa nature triangulaire, il semble meilleur.J'ai écrit une petite fonction drawNoise
pour créer une toile et traiter un tableau de pixels en boucle.Bruit homogène unidimensionnel
Dans une dimension, le bruit est une ligne lisse infinie (mon implémentation du bruit commence par deux, donc j'utilise une constante comme deuxième paramètre). Ici, nous voyons que ce ne sont que des nombres aléatoires interpolés.
fNoiseScale = .02;
drawNoise(function(i,x,y){
var v = Simplex.noise(
123+x*fNoiseScale
,137
);
return v*iSize>y?255:0;
}).img();
Bruit unidimensionnelVous pouvez l'utiliser dans l'animation, recalculer la valeur du bruit toutes les millisecondes, mais vous pouvez également créer une boucle et calculer toutes les valeurs à l'avance. Les valeurs de l'image ci-dessus ne bouclent pas sur les bords. Mais la mise en œuvre de la répétabilité est assez simple, juste une dimension et une boucle de plus ... ou un cercle, pour cela.Boucle unidimensionnelle
Pour la plupart d'entre vous, le bruit de Perlin ressemble à l'image ci-dessous.Si nous dessinions un cercle ici et comptions les valeurs de bruit sur ce cercle, nous obtiendrions une boucle unidimensionnelle.Bruit avec un cercle pour créer une boucle unidimensionnelle.En code, cela ressemble à ceci:
drawNoise(function(i,x,y){
var fNX = x/iSize
,fRdx = fNX*2*Math.PI
,a = fRdsSin*Math.sin(fRdx)
,b = fRdsSin*Math.cos(fRdx)
,v = Simplex.noise(
123+a*fNoiseScale
,132+b*fNoiseScale
)
;
return v*iSize>y?255:0;
}).img().div(2);
Vous avez probablement déjà compris ce que nous allons faire. Pour boucler une image bidimensionnelle, nous avons besoin d'une carte de bruit tridimensionnelle (au moins).Carte cylindrique
Noise Perlin a été à l'origine créé pour la texturation 3D continue (le film "Tron"). La carte d'image n'est pas une feuille de papier enroulée autour d'un objet, mais est calculée par son emplacement dans un champ de bruit tridimensionnel. Par conséquent, lors de la découpe de l'objet, nous pouvons toujours calculer la carte pour la surface nouvellement créée.Avant d'atteindre notre objectif ultime d'une image transparente, nous créons d'abord une image qui se joint de manière transparente à gauche et à droite. Ceci est similaire à un cercle bidimensionnel pour une boucle unidimensionnelle, mais avec une dimension supplémentaire: un cylindre.
drawNoise(function(i,x,y){
var fNX = x/iSize
,fRdx = fNX*2*Math.PI
,a = fRdsSin*Math.sin(fRdx)
,b = fRdsSin*Math.cos(fRdx)
,v = Simplex.noise(
123+a*fNoiseScale
,132+b*fNoiseScale
,312+y*fNoiseScale
)
;
return v*255<<0;
}).img().div(2);
Carte de bruit cylindriqueImage de la carte sphérique
Vous pourriez penser qu'il serait pratique d'utiliser une sphère pour créer une image homogène, mais vous vous trompez.Je vais faire une petite digression et montrer comment la carte image sphérique est calculée et à quoi elle ressemble.
document.body.addChild('h2').innerText = 'three dimensional spherical map';
fNoiseScale = .1;
var oSpherical = drawNoise(function(i,x,y){
var fNX = (x+.5)/iSize
,fNY = (y+.5)/iSize
,fRdx = fNX*2*Math.PI
,fRdy = fNY*Math.PI
,fYSin = Math.sin(fRdy+Math.PI)
,a = fRdsSin*Math.sin(fRdx)*fYSin
,b = fRdsSin*Math.cos(fRdx)*fYSin
,c = fRdsSin*Math.cos(fRdy)
,v = Simplex.noise(
123+a*fNoiseScale
,132+b*fNoiseScale
,312+c*fNoiseScale
)
;
return v*255<<0;
}).img();
Carte de bruit sphériqueSphère avec bruitCarte panoramique cubique
La sphère que nous avons créée peut également être utilisée comme panorama si vous placez une caméra au centre de la sphère. Mais la meilleure façon serait d'utiliser un panorama cubique, car il a beaucoup moins de visages. La sphère est projetée sur les six côtés du cube, comme illustré dans ce croquis.Superposition d'une sphère sur un cubePour chaque pixel de la surface du cube, nous devons calculer l'intersection entre le point de vue C au centre et la sphère. Cela peut sembler compliqué, mais c'est en fait assez simple.Nous pouvons considérer la ligne CA comme un vecteur. Et les vecteurs peuvent être normalisés afin que leur direction ne change pas, mais la longueur diminue à 1. Pour cette raison, tous les vecteurs ensemble ressembleront à une sphère.La normalisation est également assez simple, il suffit de diviser les valeurs du vecteur par xyz par la longueur totale du vecteur. La longueur du vecteur peut être calculée en utilisant le théorème de Pythagore.Dans le code ci-dessous, le calcul de normalisation est d'abord effectué sur une face. Ensuite, le bruit est calculé simultanément pour les six arêtes, car pour obtenir la position de la face suivante, il vous suffit de retourner les valeurs le long de xyz.
document.body.addChild('h2').innerText = '3D panoramical cube map';
var mCubemap = document.createElement('canvas')
,iW = 6*iSize;
mCubemap.width = iW;
mCubemap.height = iSize;
var iHSize = iSize/2
,oCtx = mCubemap.getContext('2d')
,oImgData = oCtx.getImageData(0,0,iW,iSize)
,aPixels = oImgData.data
,aa = 123
,bb = 231
,cc = 321
;
for (var i=0,l=iSize*iSize;i<l;i++) {
var x = i%iSize
,y = (i/iSize)<<0
,a = -iHSize + x+.5
,b = -iHSize + y+.5
,c = -iHSize
,fDistanceAB = Math.sqrt(a*a+b*b)
,fDistanceABC = Math.sqrt(fDistanceAB*fDistanceAB+c*c)
,fDrds = .5*fDistanceABC
,v = 1
;
a /= fDrds;
b /= fDrds;
c /= fDrds;
var aNoisePositions = [
[a,b,c]
,[-c,b,a]
,[-a,b,-c]
,[c,b,-a]
,[a,c,-b]
,[a,-c,b]
];
for (var j=0;j<6;j++) {
v = Simplex.noise(
aa + aNoisePositions[j][0]
,bb + aNoisePositions[j][1]
,cc + aNoisePositions[j][2]
);
var pos = 4*(y*iW+j*iSize+x);
aPixels[pos] = aPixels[pos+1] = aPixels[pos+2] = v*255<<0;
aPixels[pos+3] = 255;
}
}
oCtx.putImageData(oImgData,0,0);
document.body.addChild('img',{src:mCubemap.toDataURL("image/jpeg")});
Voici six côtés dans une image, ainsi qu'une capture d'écran de son apparence lorsqu'elle est vue à partir d'un cube. Le code source a un exemple 3D écrit en trois js .Carte panoramique cubiqueImage 2D transparente
Il peut sembler qu'une image 2D transparente soit facile à mettre en œuvre, mais il me semble que c'est la plus difficile des décrites dans l'article, car pour la comprendre, vous devez penser en quatre dimensions. La chose la plus proche était une carte cylindrique (avec répétition horizontale), nous allons donc la prendre comme base. Dans la carte cylindrique, nous avons utilisé la position horizontale de l'image pour le cercle; c'est-à-dire que la position horizontale de l'image nous donne deux coordonnées x et y dans le champ de bruit xyz. La position verticale de l'image correspond à z dans le champ de bruit.Nous voulons que l'image soit transparente et verticale, donc si nous ajoutons une autre dimension, nous pouvons l'utiliser pour créer un deuxième cercle et remplacer la valeur linéaire du champ z. Cela revient à créer deux cylindres dans un champ à quatre dimensions. J'ai essayé de visualiser cela sur un croquis, c'est inexact, mais j'ai essayé de transmettre le principe général et de ne pas dessiner un cylindre à quatre dimensions.Une esquisse de deux cylindres en quatre dimensionsLe code est assez simple: ce ne sont que deux cercles dans un espace de bruit en quatre dimensions.
fNoiseScale = .003;
drawNoise(function(i,x,y){
var fNX = x/iSize
,fNY = y/iSize
,fRdx = fNX*2*Math.PI
,fRdy = fNY*2*Math.PI
,a = fRds*Math.sin(fRdx)
,b = fRds*Math.cos(fRdx)
,c = fRds*Math.sin(fRdy)
,d = fRds*Math.cos(fRdy)
,v = Simplex.noise(
123+a*fNoiseScale
,231+b*fNoiseScale
,312+c*fNoiseScale
,273+d*fNoiseScale
)
;
return (Math.min(Math.max(2*(v -.5)+.5,0),1)*255)<<0;
}).img().div(2,2);
Et voici le résultat: