2013-05-18 15 views
11

Ho scritto un generatore di mappe in javascript, usando gli script classici perlin noise che ho trovato in vari posti, per ottenere la funzionalità che voglio. Ho lavorato in Chrome e non ho riscontrato alcun problema con la mappa. Tuttavia, quando l'ho provato in firefox, è stato incredibilmente lento - quasi sospeso il mio sistema. È andato meglio nella versione notturna, ma ancora 30 volte più lento di Chrome.Perché Firefox 30 volte più lento di Chrome, quando si calcola il rumore Perlin?

È possibile trovare una pagina di prova di esso qui: http://jsfiddle.net/7Gq3s/

Ecco il codice html:

<!DOCTYPE html> 

<html> 
<head> 
<title>PerlinMapTest</title> 
</head> 
<body> 

<canvas id="map" width="100" height="100" style="border: 1px solid red">My Canvas</canvas> 

<script src="//code.jquery.com/jquery-2.0.0.min.js"></script> 
<script> 
$(document).ready(function(){ 
    //Log time in two ways 
    var startTime = new Date().getTime(); 
    console.time("Map generated in: "); 

    var canvas = $("#map")[0]; 
    var ctx = canvas.getContext("2d"); 
    var id = ctx.createImageData(canvas.width, canvas.height); 

    var noiseMap = new PerlinNoise(500); 

    var startx = 0; 
    var starty = 0; 

    var value = 0; 

    for(var i = startx; i < canvas.width; i++){ 
     for(var j = starty; j < canvas.height; j++){ 
      value = noiseMap.noise(i,j, 0, 42); 
      value = linear(value,-1,1,0,255); 
      setPixel(id, i, j, 0,0,0,value); 
     } 
    } 

    ctx.putImageData(id,0,0); 

    var endTime = new Date().getTime(); 
    console.timeEnd("Map generated in: "); 
    alert("Map generated in: " + (endTime - startTime) + "milliseconds"); 

}); 

function setPixel(imageData, x, y, r, g, b, a) { 
    index = (x + y * imageData.width) * 4; 
    imageData.data[index+0] = r; 
    imageData.data[index+1] = g; 
    imageData.data[index+2] = b; 
    imageData.data[index+3] = a; 
} 

//This is a port of Ken Perlin's "Improved Noise" 
//http://mrl.nyu.edu/~perlin/noise/ 

//Originally from http://therandomuniverse.blogspot.com/2007/01/perlin-noise-your-new-best-friend.html 
//but the site appears to be down, so here is a mirror of it 

//Converted from php to javascript by Christian Moe 
//Patched the errors with code from here: http://asserttrue.blogspot.fi/2011/12/perlin-noise-in-javascript_31.html 

var PerlinNoise = function(seed) { 
this._default_size = 64; 
this.seed = seed;  

//Initialize the permutation array. 
this.p = new Array(512); 

this.permutation = [ 151,160,137,91,90,15, 
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 
]; 

for (var i=0; i < 256 ; i++) { 
this.p[256+i] = this.p[i] = this.permutation[i]; 
} 
}; 

PerlinNoise.prototype.noise = function(x,y,z,size) { 

if (size == undefined) 
{ 
size = this._default_size; 
} 

//Set the initial value and initial size 
var value   = 0.0; 
var initialSize  = size; 

//Add finer and finer hues of smoothed noise together 
while(size >= 1) 
{ 
value += this.smoothNoise(x/size, y/size, z/size) * size; 
size /= 2.0; 
} 

//Return the result over the initial size 
return value/initialSize; 

}; 

//This function determines what cube the point passed resides in 
//and determines its value. 
PerlinNoise.prototype.smoothNoise = function(x, y, z){ 
//Offset each coordinate by the seed value 
x += this.seed; 
y += this.seed; 
z += this.seed; 

var orig_x = x; 
var orig_y = y; 
var orig_z = z; 

var X = Math.floor(x) & 255,     // FIND UNIT CUBE THAT 
    Y = Math.floor(y) & 255,     // CONTAINS POINT. 
    Z = Math.floor(z) & 255; 

x -= Math.floor(x);        // FIND RELATIVE X,Y,Z 
y -= Math.floor(y);        // OF POINT IN CUBE. 
z -= Math.floor(z); 

var u = this.fade(x),        // COMPUTE FADE CURVES 
     v = this.fade(y),        // FOR EACH OF X,Y,Z. 
     w = this.fade(z); 

var A = this.p[X ]+Y, AA = this.p[A]+Z, AB = this.p[A+1]+Z,  // HASH COORDINATES OF 
    B = this.p[X+1]+Y, BA = this.p[B]+Z, BB = this.p[B+1]+Z;  // THE 8 CUBE CORNERS, 

return this.lerp(w, this.lerp(v, this.lerp(u, this.grad(this.p[AA ], x , y , z ), // AND ADD 
      this.grad(this.p[BA ], x-1, y , z )), // BLENDED 
      this.lerp(u, this.grad(this.p[AB ], x , y-1, z ), // RESULTS 
        this.grad(this.p[BB ], x-1, y-1, z ))),// FROM 8 
        this.lerp(v, this.lerp(u, this.grad(this.p[AA+1], x , y , z-1), // CORNERS 
          this.grad(this.p[BA+1], x-1, y , z-1)), // OF CUBE 
          this.lerp(u, this.grad(this.p[AB+1], x , y-1, z-1), 
            this.grad(this.p[BB+1], x-1, y-1, z-1)))); 
}; 

PerlinNoise.prototype.fade = function(t) { 
return t * t * t * ((t * ((t * 6) - 15)) + 10); 
}; 

PerlinNoise.prototype.lerp = function(t, a, b) { 
//Make a weighted interpolaton between points 
return a + t * (b - a); 
}; 

PerlinNoise.prototype.grad = function(hash, x, y, z) { 
h = hash & 15;      // CONVERT LO 4 BITS OF HASH CODE 
u = h<8 ? x : y;     // INTO 12 GRADIENT DIRECTIONS. 
v = h<4 ? y : (h==12||h==14 ? x : z); 

return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); 
}; 

PerlinNoise.prototype.scale = function(n) { 
return (1 + n)/2; 
}; 

function linear(int, s1, s2, t1, t2) 
{ 
t = [t1, t2]; 
s = [s1, s2]; 

rangeS = s1 - s2; 
rangeT = t1 - t2; 

if((s1 < s2 && t1 > t2) || (s1>s2 && t1<t2)) 
{ 
     interpolated = ((int - s1)/rangeS*rangeT) + t1; 
} 
else 
{ 
     interpolated = ((int - s1)/rangeS)*rangeT + t1; 
} 

if(interpolated > Math.max.apply(Math, t)) 
{ 
     interpolated = Math.max.apply(Math, t); 
} 

if(interpolated < Math.min.apply(Math, t)) 
{ 
     interpolated = Math.min.apply(Math, t); 
} 

return interpolated; 

} 
</script> 
</body> 
</html> 

ottengo 33 ms su Chrome, e 1051ms su Firefox 24 Nightly

I risultati sono incoerenti però. A volte i risultati notturni sono veloci quanto il cromo ...

Sai perché c'è così tanta variazione in questa particolare istanza? Non conosco abbastanza la teoria del rumore perlin per provare a ottimizzare il codice, quindi non so cosa fare.

+0

Ok, sto ottenendo risultati molto incoerenti ... In questo momento Firefox sta restituendo la mappa quasi nello stesso momento in cui cromo - potrebbe essere un problema di ram? – LongInt

+0

Ti mancano molte dichiarazioni 'var' per le variabili locali. – Pointy

+0

Intendi nelle funzioni? Aggiungerò quelli, per ogni evenienza. Potrebbero avere problemi di prestazioni? – LongInt

risposta

14

Ho trovato il colpevole. Il rallentamento si verifica quando Firebug è abilitato. Quell'estensione deve appesantirlo.

+0

Nota che se l'estensione * * è abilitata, ma tutti i pannelli sono disabilitati, non dovrebbe esserci alcun rallentamento (rilevante). –

+0

Sì, lo farei :-) – Pointy

Problemi correlati