今天小牛云站长给大家带来的是利用css,使3G变换创建一个3D的云的效果,教程中的代码是演示的简化版本,但是主要区别记录在每个部分中。
1. 创造world和camera
首先,我们需要两个div元素:viewport和world。其余所有元素将动态创建。viewport覆盖整个屏幕,并充当相机平面。由于在CSS 3D Transforms中本身没有camera,因此可以将其视为静止的玻璃板,通过它可以看到一个相对于您改变方向的世界。我们将所有camera对象(或scene)放置在其中,这就是将要转换的内容。World是一个div,我们将使用它来锚定所有3D元素。变换(旋转,平移或缩放)world将改变我们所有的元素
2.向我们的世界添加对象
现在我们开始添加真实的3D内容。我们添加一些相对于world定位在空间中的新div。从本质上讲,它是将几个绝对位置的div添加为world的子级。默认情况下,它们位于world中央。对于云,最好将它们居中(通过将左边距左边和顶部边距设置为宽度和高度的负一半)。
3.在我们的对象上添加图层
现在事情开始变得有趣起来。我们向每个.cloudBase添加几个绝对定位的.cloudLayer div元素。这些将保留我们的云纹理。
这就是魔术发生的地方。我们的layers []包含了我们world中每个单层的参考,并且我们有worldXangle和worldYAngle,它们是应用于我们世界的变换的旋转部分。如果我们对每个图层应用相反的旋转,我们将有效地将它们重新对齐到viewpoint。转换顺序非常重要。如果您未按正确的顺序应用它们,则元素的方向将错误!
为了获得最终效果,只需删除调试颜色,然后将.cloudLayer div更改为具有云纹理的img。纹理应为具有Alpha通道的PNG,以正确获得效果。
1. 创造world和camera
首先,我们需要两个div元素:viewport和world。其余所有元素将动态创建。viewport覆盖整个屏幕,并充当相机平面。由于在CSS 3D Transforms中本身没有camera,因此可以将其视为静止的玻璃板,通过它可以看到一个相对于您改变方向的世界。我们将所有camera对象(或scene)放置在其中,这就是将要转换的内容。World是一个div,我们将使用它来锚定所有3D元素。变换(旋转,平移或缩放)world将改变我们所有的元素
Viewport and world container HTML - index.html <div id="viewport" > <div id="world" ></div> </div>接下来是我们的两个CSS定义。将包含场景的div(在我们的情况下为world)居中放置在Viewport 中非常重要,否则场景将偏移显示!
Viewport and world container CSS-index.html #viewport { bottom: 0; left: 0; overflow: hidden; perspective: 400; position: absolute; right: 0; top: 0; } #world { height: 512px; left: 50%; margin-left: -256px; margin-top: -256px; position: absolute; top: 50%; transform-style: preserve-3d; width: 512px; }现在多一点代码。我们初始化对象,连接到mousemove事件并定义updateView():
mousemove and updateView JavaScript-index.html /* Defining our variables world and viewport are DOM elements, worldXAngle and worldYAngle are floats that hold the world rotations, d is an int that defines the distance of the world from the camera */ var world = document.getElementById( 'world' ), viewport = document.getElementById( 'viewport' ), worldXAngle = 0, worldYAngle = 0, d = 0; /* Event listener to transform mouse position into angles from -180 to 180 degress, both vertically and horizontally */ window.addEventListener( 'mousemove', function( e ) { worldYAngle = -( .5 - ( e.clientX / window.innerWidth ) ) * 180; worldXAngle = ( .5 - ( e.clientY / window.innerHeight ) ) * 180; updateView(); } ); /* Changes the transform property of world to be translated in the Z axis by d pixels, rotated in the X axis by worldXAngle degrees and rotated in the Y axis by worldYAngle degrees. */ function updateView() { world.style.transform = 'translateZ( ' + d + 'px ) \ rotateX( ' + worldXAngle + 'deg) \ rotateY( ' + worldYAngle + 'deg)'; }world为红色,Viewport 具有CSS背景以模拟天空,并且有鼠标滚轮事件监听器可修改相机的距离。移动鼠标,注意红色div如何改变方向。
2.向我们的世界添加对象
现在我们开始添加真实的3D内容。我们添加一些相对于world定位在空间中的新div。从本质上讲,它是将几个绝对位置的div添加为world的子级。默认情况下,它们位于world中央。对于云,最好将它们居中(通过将左边距左边和顶部边距设置为宽度和高度的负一半)。
Cloud base styling CSS - index.html .cloudBase { height: 20px; left: 256px; margin-left: -10px; margin-top: -10px; position: absolute; top: 256px; width: 20px; }我们添加了generate()和createCloud()函数来填充world。请注意,random_ {var}不是实数变量,而是实数代码的占位符名称,应返回指定范围之间的随机数。
Create and distribute clouds JavaScript - index.html /* objects is an array of cloud bases layers is an array of cloud layers */ var objects = [], layers = []; /* Clears the DOM of previous clouds bases and generates a new set of cloud bases */ function generate() { objects = []; layers = []; if ( world.hasChildNodes() ) { while ( world.childNodes.length >= 1 ) { world.removeChild( world.firstChild ); } } for( var j = 0; j <; 5; j++ ) { objects.push( createCloud() ); } } /* Creates a single cloud base: a div in world that is translated randomly into world space. Each axis goes from -256 to 256 pixels. */ function createCloud() { var div = document.createElement( 'div' ); div.className = 'cloudBase'; var t = 'translateX( ' + random_x + 'px ) \ translateY( ' + random_y + 'px ) \ translateZ( ' + random_z + 'px )'; div.style.transform = t; world.appendChild( div ); return div; }目前基础的云为略带粉红色的正方形。有一个p变量可以更轻松地更改viewport.style.perspective。再次注意,random_ {var}不是变量。
3.在我们的对象上添加图层
现在事情开始变得有趣起来。我们向每个.cloudBase添加几个绝对定位的.cloudLayer div元素。这些将保留我们的云纹理。
Cloud layers styling CSS - index.html .cloudLayer { height: 256px; left: 50%; margin-left: -128px; margin-top: -128px; position: absolute; top: 50%; width: 256px; }对旧的createCloud()进行了一些更改,以添加随机数量的cloudLayers。
Improved createCloud() to add layers JavaScript - index.html /* Creates a single cloud base and adds several cloud layers. Each cloud layer has random position ( x, y, z ), rotation (a) and rotation speed (s). layers[] keeps track of those divs. */ function createCloud() { var div = document.createElement( 'div' ); div.className = 'cloudBase'; var t = 'translateX( ' + random_x + 'px ) \ translateY( ' + random_y + 'px ) \ translateZ( ' + random_z + 'px )'; div.style.transform = t; world.appendChild( div ); for( var j = 0; j < 5 + Math.round( Math.random() * 10 ); j++ ) { var cloud = document.createElement( 'div' ); cloud.className = 'cloudLayer'; cloud.data = { x: random_x, y: random_y, z: random_z, a: random_a, s: random_s }; var t = 'translateX( ' + random_x + 'px ) \ translateY( ' + random_y + 'px ) \ translateZ( ' + random_z + 'px ) \ rotateZ( ' + random_a + 'deg ) \ scale( ' + random_s + ' )'; cloud.style.transform = t; div.appendChild( cloud ); layers.push( cloud ); } return div; }4.使3D效果生效
这就是魔术发生的地方。我们的layers []包含了我们world中每个单层的参考,并且我们有worldXangle和worldYAngle,它们是应用于我们世界的变换的旋转部分。如果我们对每个图层应用相反的旋转,我们将有效地将它们重新对齐到viewpoint。转换顺序非常重要。如果您未按正确的顺序应用它们,则元素的方向将错误!
Aligning cloud layers with camera JavaScript - index.html /* Iterate layers[], update the rotation and apply the inverse transformation currently applied to the world. Notice the order in which rotations are applied. */ function update (){ for( var j = 0; j < layers.length; j++ ) { var layer = layers[ j ]; layer.data.a += layer.data.speed; var t = 'translateX( ' + layer.data.x + 'px ) \ translateY( ' + layer.data.y + 'px ) \ translateZ( ' + layer.data.z + 'px ) \ rotateY( ' + ( - worldYAngle ) + 'deg ) \ rotateX( ' + ( - worldXAngle ) + 'deg ) \ scale( ' + layer.data.s + ')'; layer.style.transform = t; } requestAnimationFrame( update ); }5.最后的话
为了获得最终效果,只需删除调试颜色,然后将.cloudLayer div更改为具有云纹理的img。纹理应为具有Alpha通道的PNG,以正确获得效果。
当然,您可以使用任何所需的纹理或一组纹理:烟熏,等离子云,绿叶,飞行的烤面包机...只需更改特定种类的云层使用的背景图像。以不同的比例混合不同的纹理可获得有趣的结果。
附上最后的代码:<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> <style> *{ box-sizing: border-box; margin: 0; padding: 0 } body { color: #eee; text-shadow: 0 -1px 0 rgba( 0, 0, 0, .6 ); font-family: 'Open Sans', sans-serif; font-size: 13px; line-height: 16px; overflow: hidden; } #viewport { -webkit-perspective: 1000; -moz-perspective: 1000; -o-perspective: 1000; position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; background-image: linear-gradient(bottom, rgb(69,132,180) 28%, rgb(31,71,120) 64%); background-image: -o-linear-gradient(bottom, rgb(69,132,180) 28%, rgb(31,71,120) 64%); background-image: -moz-linear-gradient(bottom, rgb(69,132,180) 28%, rgb(31,71,120) 64%); background-image: -webkit-linear-gradient(bottom, rgb(69,132,180) 28%, rgb(31,71,120) 64%); background-image: -ms-linear-gradient(bottom, rgb(69,132,180) 28%, rgb(31,71,120) 64%); background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0.28, rgb(69,132,180)), color-stop(0.64, rgb(31,71,120)) ); } #world { position: absolute; left: 50%; top: 50%; margin-left: -256px; margin-top: -256px; height: 512px; width: 512px; -webkit-transform-style: preserve-3d; -moz-transform-style: preserve-3d; -o-transform-style: preserve-3d; } #world div { -webkit-transform-style: preserve-3d; -moz-transform-style: preserve-3d; -o-transform-style: preserve-3d; } .cloudBase { position: absolute; left: 256px; top: 256px; width: 20px; height: 20px; margin-left: -10px; margin-top: -10px; } .cloudLayer { position: absolute; left: 50%; top: 50%; width: 256px; height: 256px; margin-left: -128px; margin-top: -128px; -webkit-transition: opacity .5s ease-out; -moz-transition: opacity .5s ease-out; -o-transition: opacity .5s ease-out; } </style> </head> <body> <div id="viewport" style="perspective: 400px;"> <div id="world"><div class="cloudBase"></div> </div> <script> (function() { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelRequestAnimationFrame = window[vendors[x]+ 'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id) { clearTimeout(id); }; }()) var layers = [], objects = [], world = document.getElementById( 'world' ), viewport = document.getElementById( 'viewport' ), d = 0, p = 400, worldXAngle = 0, worldYAngle = 0; viewport.style.webkitPerspective = p; viewport.style.MozPerspective = p; viewport.style.oPerspective = p; generate(); function createCloud() { var div = document.createElement( 'div' ); div.className = 'cloudBase'; var x = 256 - ( Math.random() * 512 ); var y = 256 - ( Math.random() * 512 ); var z = 256 - ( Math.random() * 512 ); var t = 'translateX( ' + x + 'px ) translateY( ' + y + 'px ) translateZ( ' + z + 'px )'; div.style.webkitTransform = t; div.style.MozTransform = t; div.style.oTransform = t; world.appendChild( div ); for( var j = 0; j < 5 + Math.round( Math.random() * 10 ); j++ ) { var cloud = document.createElement( 'img' ); cloud.style.opacity = 0; var r = Math.random(); var src = './final_files/cloud.png'; ( function( img ) { img.addEventListener( 'load', function() { img.style.opacity = .8; } ) } )( cloud ); cloud.setAttribute( 'src', src ); cloud.className = 'cloudLayer'; var x = 256 - ( Math.random() * 512 ); var y = 256 - ( Math.random() * 512 ); var z = 100 - ( Math.random() * 200 ); var a = Math.random() * 360; var s = .25 + Math.random(); x *= .2; y *= .2; cloud.data = { x: x, y: y, z: z, a: a, s: s, speed: .1 * Math.random() }; var t = 'translateX( ' + x + 'px ) translateY( ' + y + 'px ) translateZ( ' + z + 'px ) rotateZ( ' + a + 'deg ) scale( ' + s + ' )'; cloud.style.webkitTransform = t; cloud.style.MozTransform = t; cloud.style.oTransform = t; div.appendChild( cloud ); layers.push( cloud ); } return div; } window.addEventListener( 'mousewheel', onContainerMouseWheel ); window.addEventListener( 'DOMMouseScroll', onContainerMouseWheel ); window.addEventListener( 'mousemove', onMouseMove ); window.addEventListener( 'touchmove', onMouseMove ); function onMouseMove ( e ) { var x = e.clientX || e.touches[ 0 ].clientX; var y = e.clientY || e.touches[ 0 ].clientY; worldYAngle = -( .5 - ( x / window.innerWidth ) ) * 180; worldXAngle = ( .5 - ( y / window.innerHeight ) ) * 180; updateView(); event.preventDefault(); } function onContainerMouseWheel( event ) { event = event ? event : window.event; d = d - ( event.detail ? event.detail * -5 : event.wheelDelta / 8 ); updateView(); event.preventDefault(); } function generate() { objects = []; if ( world.hasChildNodes() ) { while ( world.childNodes.length >= 1 ) { world.removeChild( world.firstChild ); } } for( var j = 0; j < 5; j++ ) { objects.push( createCloud() ); } } function updateView() { var t = 'translateZ( ' + d + 'px ) rotateX( ' + worldXAngle + 'deg) rotateY( ' + worldYAngle + 'deg)'; world.style.webkitTransform = t; world.style.MozTransform = t; world.style.oTransform = t; } function update (){ for( var j = 0; j < layers.length; j++ ) { var layer = layers[ j ]; layer.data.a += layer.data.speed; var t = 'translateX( ' + layer.data.x + 'px ) translateY( ' + layer.data.y + 'px ) translateZ( ' + layer.data.z + 'px ) rotateY( ' + ( - worldYAngle ) + 'deg ) rotateX( ' + ( - worldXAngle ) + 'deg ) rotateZ( ' + layer.data.a + 'deg ) scale( ' + layer.data.s + ')'; layer.style.webkitTransform = t; layer.style.MozTransform = t; layer.style.oTransform = t; } requestAnimationFrame( update ); } update(); </script> </body> </html>
白云的png照片(自己下载保存)使用时将var src = './final_files/cloud.png';换成白云的照片:

未经允许不得转载:小牛资源网 » 使用CSS 3D变换创建3D的云
发表评论