Плывущие облака
Автор: Евгений Рыжков Дата публикации:
Задача
Сделать плывущие «живые» облака.
Решение
Применяем методику используемую для построения облаков в играх. Это не супер-пупер реалистично, но зато производительно. Метод основан на многослойности объекта. Каждый слой - это текстура, к которой применяются случайные трансформации, что в сумме дает объект неплохо напоминающий облако.
<div id="sky"> <div id="world"></div> </div>
#sky { height: 400px; position: relative; -moz-perspective: 1000px; // глубина сцены -webkit-perspective: 1000px; perspective: 1000px; overflow: hidden; background:-moz-linear-gradient(top, #072ac0, #4466f9); background:-webkit-linear-gradient(top, #072ac0, #4466f9); backround-image: linear-gradient(top, #072ac0, #4466f9); } #world { -webkit-transform-style: preserve-3d; -moz-transform-style: preserve-3d; transform-style: preserve-3d; // объекты поддаются 3d траснформациям position: relative; height: 100%; } #world>div { -webkit-transform-style: preserve-3d; -moz-transform-style: preserve-3d; transform-style: preserve-3d; } .cloud { position: absolute; } .cloudLayer { position: absolute; left: 50%; top: 50%; width: 356px; /* размеры не обязательно подстраивать под размеры текстуры */ height: 356px; margin-left: -178px; margin-top: -178px; -webkit-transition: opacity .5s ease-out; -moz-transition: opacity .5s ease-out; transition: opacity .5s ease-out; }
var world = document.getElementById('world'), // сцена nClouds, // число облаков arrClouds = [], arrLayersClouds = [] nSkyWidth = world.offsetWidth, nSkyHeight = world.offsetHeight; /* чем меньше экран - тем меньше нужно облаков */ if(world.offsetWidth > 1500) nClouds = 5; else nClouds = 3; /* формируем облака */ for(i=0; i<nClouds; i++) { arrClouds.push( createCloud(i) ); } function createCloud(nCloudCount) { var oCloud = document.createElement( 'div'); oCloud.className = 'cloud'; /* стартовое положение облаков */ var nCloudX = nCloudCount*200 - Math.random()*200, // чтобы была нужная кучность + равномерно распределить облака по небу nCloudY = nSkyHeight - ( Math.random() * nSkyHeight ); oCloud.style.left = nCloudX + &apospx;'; oCloud.style.top = nCloudY+'px'; var nCloudSpeed = Math.random()*.15; // скорость движения облаков oCloud.data = { x: nCloudX, speed: nCloudSpeed } world.appendChild( oCloud ); /* формируем слои облака */ var nLayers = 5 + Math.round( Math.random() * 10), // к-во слоев oCloudLayer, sCloudTextrure = 'cloud-3.png', // текстура nCloudLayerX, nCloudLayerY, nCloudLayerZ, nCloudLayerA, nCloudLayerS, nCloudLayerSpeed; for( var j = 0; j < nLayers; j++ ) { oCloudLayer = document.createElement( 'img' ); oCloudLayer.setAttribute( &apossrc;', sCloudTextrure ); oCloudLayer.className = 'cloudLayer'; /* х-ки слоя */ nCloudLayerX = 256 - ( Math.random() * 512 ); nCloudLayerY = 256 - ( Math.random() * 512 ); nCloudLayerZ = 100 - ( Math.random() * 200 ); // nCloudLayerA = Math.random()*360; nCloudLayerS = 1.1 + Math.random(); // чем больше коэффициент, тем облако больше (ближе) if(nCloudLayerS > 0.5) nCloudLayerSpeed = Math.random()*.03; // скорость вращения, чем слой ближе к нам, тем больше скорость вращения else nCloudLayerSpeed = Math.random()*.02; nCloudLayerX *= .2; nCloudLayerY *= .2; oCloudLayer.data = { nCloudLayerX: nCloudLayerX, nCloudLayerY: nCloudLayerY, nCloudLayerZ: nCloudLayerZ, nCloudLayerA: nCloudLayerA, nCloudLayerS: nCloudLayerS, nCloudLayerSpeed: nCloudLayerSpeed }; var t = 'translateX( ' + nCloudLayerX + 'px ) translateY( ' + nCloudLayerY + 'px ) translateZ( ' + nCloudLayerZ + 'px ) rotateZ( ' + nCloudLayerA + 'deg ) scale( ' + nCloudLayerS + ' )'; oCloudLayer.style.webkitTransform = t; oCloudLayer.style.MozTransform = t; oCloudLayer.style.oTransform = t; oCloud.appendChild( oCloudLayer ); arrLayersClouds.push( oCloudLayer ); } return oCloud; } function update (){ for( var j = arrLayersClouds.length; j--; ) { var layer = arrLayersClouds[ j ]; layer.data.nCloudLayerA += layer.data.nCloudLayerSpeed; var t = 'translateX( ' + layer.data.nCloudLayerX + 'px ) translateY( ' + layer.data.nCloudLayerY + 'px ) translateZ( ' + layer.data.nCloudLayerZ + 'px ) rotateZ( ' + layer.data.nCloudLayerA + 'deg ) scale( ' + layer.data.nCloudLayerS + ')'; layer.style.webkitTransform = t; layer.style.MozTransform = t; } for ( var j = arrClouds.length; j--;) { var object = arrClouds[j]; if(object.data.x>nSkyWidth+300) object.data.x = -300; object.data.x+=object.data.speed; var sCloudT = 'translateX('+ object.data.x+'px )'; object.style.webkitTransform = sCloudT; object.style.MozTransform = sCloudT; } requestAnimationFrame( update ); } update();
Живой пример. Работает в:
- IE 10
- Firefox
- Safari 5+
- Chrome
- iOs 4+
- Android 3+
Материалы
- CSS3D Clouds