Das Erstellen eines nahtlosen Bildes in Photoshop ist ganz einfach: Schneiden Sie das Bild zu, greifen Sie nach den zugeschnittenen rechten und unteren Teilen und kleben Sie sie dann mit dem Überblendungswerkzeug nach links und oben. Für die ordnungsgemäße Implementierung nahtloser Rauschkarten müssen Sie jedoch sorgfältig überlegen.Wenn Sie ein grundlegendes Verständnis des Perlin-Rauschens haben , wissen Sie, dass es aus interpolierten Zufallszahlen besteht. Es wird hauptsächlich in zwei Dimensionen verwendet. Es ist aber auch nützlich in einer Dimension (zum Beispiel beim Bewegen), in drei Dimensionen (zylindrische und sphärische Transformation von 3D-Objekten) und sogar in vier oder fünf Dimensionen.Mit vierdimensionalem Rauschen kann ein nahtloses 2D-Bild erstellt werden. Es ist nicht sehr üblich, dass wir in vier Dimensionen denken, daher werden wir jeweils eine Dimension annehmen.In meinen Beispielen habe ich Simplex-Rauschen mit zwei Oktaven verwendet. Simplex-Rauschen ist in großen Dimensionen schneller und sieht aufgrund seiner Dreiecksform besser aus.Ich habe eine kleine Funktion geschrieben drawNoise
, um eine Leinwand zu erstellen und ein Pixelarray in einer Schleife zu verarbeiten.Eindimensionales nahtloses Rauschen
In einer Dimension ist Rauschen eine unendliche glatte Linie (meine Implementierung von Rauschen beginnt mit zwei, daher verwende ich eine Konstante als zweiten Parameter). Hier sehen wir, dass dies nur interpolierte Zufallszahlen sind.
fNoiseScale = .02;
drawNoise(function(i,x,y){
var v = Simplex.noise(
123+x*fNoiseScale
,137
);
return v*iSize>y?255:0;
}).img();
Eindimensionales RauschenSie können dies in der Animation verwenden und den Rauschwert jede Millisekunde neu berechnen. Sie können jedoch auch eine Schleife erstellen und alle Werte im Voraus berechnen. Die Werte im obigen Bild werden nicht um die Kanten geschlungen. Die Implementierung der Wiederholbarkeit ist jedoch recht einfach, nur eine weitere Dimension und Schleife ... oder ein Kreis dafür.Eindimensionale Schleife
Für die meisten von Ihnen sieht Perlins Rauschen ungefähr so aus wie auf dem Bild unten.Wenn wir hier einen Kreis zeichnen und die Rauschwerte auf diesem Kreis zählen würden, würden wir eine eindimensionale Schleife erhalten.Rauschen mit einem Kreis, um eine eindimensionale Schleife zu erstellen.Im Code sieht es so aus:
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);
Sie haben wahrscheinlich schon verstanden, was wir machen werden. Um ein zweidimensionales Bild zu schleifen, benötigen wir eine dreidimensionale (mindestens) Rauschkarte.Zylindrische Karte
Noise Perlin wurde ursprünglich für die kontinuierliche 3D-Texturierung entwickelt (der Film "Tron"). Die Imagemap ist kein Blatt Papier, das um ein Objekt gewickelt ist, sondern wird anhand seiner Position in einem dreidimensionalen Rauschfeld berechnet. Daher können wir beim Schneiden des Objekts weiterhin die Karte für die neu erstellte Oberfläche berechnen.Bevor wir unser endgültiges Ziel eines nahtlosen Bildes erreichen, erstellen wir zunächst ein Bild, das sich nahtlos nach links und rechts verbindet. Dies ähnelt einem zweidimensionalen Kreis für eine eindimensionale Schleife, jedoch mit einer zusätzlichen Dimension: einem Zylinder.
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);
ZylinderrauschkarteSphärisches Kartenbild
Sie könnten denken, dass es bequem wäre, eine Kugel zu verwenden, um ein nahtloses Bild zu erstellen, aber Sie irren sich.Ich werde einen kleinen Exkurs machen und zeigen, wie die sphärische Bildkarte berechnet wird und wie sie aussieht.
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();
Sphärische RauschkarteKugel mit LärmKubische Panoramakarte
Die von uns erstellte Kugel kann auch als Panorama verwendet werden, wenn Sie eine Kamera in der Mitte der Kugel platzieren. Der beste Weg wäre jedoch, ein kubisches Panorama zu verwenden, da es viel weniger Gesichter hat. Die Kugel wird wie in dieser Skizze gezeigt auf die sechs Seiten des Würfels projiziert.Anwenden einer Kugel auf einen WürfelFür jedes Pixel auf der Oberfläche des Würfels müssen wir den Schnittpunkt zwischen dem Ansichtspunkt C in der Mitte und der Kugel berechnen. Es mag kompliziert erscheinen, aber es ist eigentlich ziemlich einfach.Wir können die CA-Linie als Vektor betrachten. Und Vektoren können normalisiert werden, so dass sich ihre Richtung nicht ändert, aber die Länge auf 1 abnimmt. Aus diesem Grund sehen alle Vektoren zusammen wie eine Kugel aus.Die Normalisierung ist auch recht einfach. Wir müssen nur die Werte des Vektors durch xyz durch die Gesamtlänge des Vektors teilen. Die Länge des Vektors kann mit dem Satz von Pythagoras berechnet werden.Im folgenden Code wird die Normalisierungsberechnung zuerst auf einer Seite durchgeführt. Dann wird das Rauschen gleichzeitig für alle sechs Kanten berechnet, da Sie nur die Werte entlang xyz spiegeln müssen, um die Position der nächsten Fläche zu erhalten.
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")});
Hier sind sechs Seiten in einem Bild sowie ein Screenshot davon, wie es aus der Sicht eines Würfels aussieht. Der Quellcode enthält ein 3D-Beispiel, das in drei Sekunden geschrieben ist .Kubische PanoramakarteNahtloses 2D-Bild
Es mag scheinen, dass ein nahtloses 2D-Bild einfach zu implementieren ist, aber es scheint mir, dass dies das schwierigste der im Artikel beschriebenen ist, denn um es zu verstehen, müssen Sie in vier Dimensionen denken. Am nächsten dran war eine zylindrische Karte (mit horizontaler Wiederholung), also werden wir sie als Grundlage nehmen. In der zylindrischen Karte haben wir die horizontale Position des Bildes für den Kreis verwendet; Das heißt, die horizontale Position des Bildes gibt uns zwei Koordinaten x und y im Rauschfeld xyz. Die vertikale Position des Bildes entspricht z im Rauschfeld.Wir möchten, dass das Bild nahtlos und vertikal ist. Wenn wir also eine weitere Dimension hinzufügen, können wir damit einen zweiten Kreis erstellen und den linearen Wert des z-Felds ersetzen. Dies ähnelt der Erzeugung von zwei Zylindern in einem vierdimensionalen Feld. Ich habe versucht, dies auf einer Skizze zu visualisieren, es ist ungenau, aber ich habe versucht, das allgemeine Prinzip zu vermitteln und keinen vierdimensionalen Zylinder zu zeichnen.Eine Skizze von zwei Zylindern in vier DimensionenDer Code ist recht einfach: Dies sind nur zwei Kreise in einem vierdimensionalen Rauschraum.
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);
Und hier ist das Ergebnis: