Mise à jour 1/2017 : J'ai réécrit l'intégralité de la réponse car elle commençait à devenir plutôt confuse, et pour aborder certains des problèmes soulignés dans les commentaires. La réponse originale peut être trouvée ici. La nouvelle réponse contient essentiellement le même code mais amélioré, avec quelques nouvelles techniques, dont une utilise une nouvelle fonctionnalité disponible depuis la publication de cette réponse.
Pour un look "vraiment" aléatoire, nous aurions besoin d'utiliser un rendu au niveau des pixels. Nous pouvons optimiser cela en utilisant des tampons non signés sur 32 bits au lieu de 8 bits, et nous pouvons également désactiver le canal alpha dans les navigateurs plus récents, ce qui accélère l'ensemble du processus (pour les anciens navigateurs, nous pouvons simplement définir un fond opaque noir pour l'élément canvas).
Nous créons un objet ImageData
réutilisable une fois en dehors de la boucle principale, de sorte que le coût principal est uniquement lié à putImageData()
et pas les deux à l'intérieur de la boucle.
var ctx = c.getContext("2d", {alpha: false}); // context without alpha channel.
var idata = ctx.createImageData(c.width, c.height); // create image data
var buffer32 = new Uint32Array(idata.data.buffer); // get 32-bit view
(function loop() {
noise(ctx);
requestAnimationFrame(loop)
})()
function noise(ctx) {
var len = buffer32.length - 1;
while(len--) buffer32[len] = Math.random() < 0.5 ? 0 : -1>>0;
ctx.putImageData(idata, 0, 0);
}
/* pour les navigateurs sans prise en charge du canal alpha 2d */
#c {background:#000}
Une façon très efficace, au prix de quelques ressources mémoire mais avec un coût réduit sur le processeur, est de pré-rendre un canvas hors écran plus grand avec le bruit une fois, puis placer ce canvas dans le principal en utilisant des décalages entiers aléatoires.
Il faut quelques étapes de préparation supplémentaires, mais la boucle peut s'exécuter entièrement sur le GPU.
var w = c.width;
var h = c.height;
var ocanvas = document.createElement("canvas"); // crée un canvas hors écran
ocanvas.width = w<<1; // défini la taille du canvas hors écran x2
ocanvas.height = h<<1;
var octx = ocanvas.getContext("2d", {alpha: false});
var idata = octx.createImageData(ocanvas.width, ocanvas.height);
var buffer32 = new Uint32Array(idata.data.buffer); // get 32-bit view
// rendre le bruit une fois, sur le canvas hors écran
noise(octx);
// la boucle principale dessine le canvas hors écran à des décalages aléatoires
var ctx = c.getContext("2d", {alpha: false});
(function loop() {
var x = (w * Math.random())|0; // forcer des valeurs entières pour la position
var y = (h * Math.random())|0;
ctx.drawImage(ocanvas, -x, -y); // dessine le bruit statique (jeu de mots voulu)
requestAnimationFrame(loop)
})()
function noise(ctx) {
var len = buffer32.length - 1;
while(len--) buffer32[len] = Math.random() < 0.5 ? 0 : -1>>0;
ctx.putImageData(idata, 0, 0);
}
/* pour les navigateurs sans prise en charge du canal alpha 2d */
#c {background:#000}
Il est cependant important de noter qu'avec cette dernière technique, vous pourriez risquer d'obtenir des "gels" où le nouveau décalage aléatoire est similaire au précédent. Pour contourner ce problème, définissez des critères pour la position aléatoire afin de ne pas autoriser des positions trop proches à la suite.
1 votes
window.setInterval('generateNoise(.8)',50);
1 votes
Vous pouvez réduire vos appels
Math.random
etMath.floor
en faisant quelque chose commex = Math.floor(Math.random() * 0xffffff); r = x & 0xff; g = (x & 0xff00) >>> 8; b = (x & 0xff0000) >>> 16;
0 votes
Quelques conseils: 1)
!!!document.createElement('canvas').getContext
en!document.createElement('canvas').getContext
2) mettre en place des instructions conditionnelles pour que les utilisateurs qui n'ont pas de canvas ne reçoivent pas d'erreurs 3) ajouter des espaces entre les virgules et le texte qui suit, et un espace entre(param) {
pour les fonctions0 votes
@PaulS. fais-je fonctionner? je suis complètement un nerb? ça a l'air correct mais je n'arrive pas à le faire fonctionner; nouvelles couleurs: r = Math.floor(Math.random() * 155); g = Math.floor(Math.random() * 255); b = Math.floor(Math.random() * 155);
1 votes
Aussi tout ce que j'ai ajouté était
requestAnimationFrame(generateNoise);
et cela fait ce dont vous avez besoin, placez-le dans la première ligne de la fonction. jsfiddle.net/eS9cc0 votes
Aussi éviter de repeindre un canvas trop souvent, car cela consomme des ressources. Si vous pouvez utiliser la boucle for améliorée cela aidera. Configurez un canvas qui n'a que 10px, et dispersez-le, vous économiserez beaucoup de peinture. Vérifiez les outils de développement de Chrome ou Firebug pour les performances. Quelque chose qui pourrait le rendre vivant est d'utiliser une animation css pour le déplacer très rapidement. Jetez un œil à mon pen et voyez ce que je veux dire. Vous pouvez jouer avec les valeurs et le timing.
0 votes
@IlanBiala, pourriez-vous effectuer les corrections math.random() que Paul S. a mentionnées et fournir une réponse officielle ?
0 votes
@llan Biala, c'est une façon intéressante de le faire, cependant cela semble un peu étrange, pas vraiment comme du bruit réel.
0 votes
@Mouseroot, sauriez-vous pourquoi lorsque je le fais à votre manière, l'opacité ne fonctionne pas?
0 votes
Il se peut que vous itérez sur les positions des pixels x, y tandis que je parcours chaque pixel et ajoute 4 pour r, g, b et alpha. J'utilise 255 (noir) pour les valeurs r, g, b et une valeur aléatoire entre 155 et 254. De plus, je modifie directement les pixels alors que vous placez chaque pixel individuellement. Donc, ma boucle modifie tous les pixels dans le tableau puis les applique, tandis que la vôtre modifie chaque pixel et le règle.
0 votes
@Mouseroot Bien. RAF est génial, mais vous pourriez probablement obtenir le même résultat avec une animation css sur la position de fond du corps. Je pense que RAF n'est pas encore entièrement pris en charge selon caniuse.com/#feat=requestanimationframe
0 votes
@MatthewHarwood tu veux une démo de la mienne ou quelque chose d'autre?
0 votes
Il n'est pas entièrement pris en charge dans tous les navigateurs, mais il existe un polyfill pour les navigateurs qui dépendent encore des préfixes vendeurs et qui utilisent setInterval pour les navigateurs qui ne prennent tout simplement pas en charge rAF.