运用three.js写的漂浮立方
来源:互联网 发布:气动快速接头 淘宝 编辑:程序博客网 时间:2024/06/10 08:43
这是本人在CSDN上的第一篇文章,因为刚刚写了一个three.js的Demo,就传上来了,参考的是国外Karim Maaloul这位大佬的飞机游戏,给了我比较大的启发,和小伙伴们分享下。
three.js
three.js是JavaScript编写的WebGL第三方库。提供了非常多的3D显示功能。 —— [ 百度百科 ]
个人感觉这个库还是比较给力的,运用了图形建模的许多思想,一些在3D建模里的相机、灯光、贴图都被运用到three里,他的引用库文件可以在GitHub上面找到并下载,格式是zip的,解压后在build文件夹的就是,一个压缩,一个没压缩,在练习阶段建议用没压缩的,点进去它的结构一步了然,方便理解原理.
- Demo图
漂浮立方Demo展示
HTML
页面的HTML部分需要引入three.js的库文件:
<script type="text/javascript" src="js/three.js"></script>
下面是HTML部分完整的代码:
<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8"> <title>漂浮立方</title> <style type="text/css"> *{ margin: 0; padding: 0; } #world{ width:100%; height: 100%; position: absolute; overflow: hidden; background: linear-gradient(#A4D3EE,#AEEEEE); } </style></head><body><div id="world"></div></body><script type="text/javascript" src="js/three.min.js"></script></html>
上面的代码在body里嵌套了一层div,three会在这个div里自动添加canvas,我们所有效果就在这里面,在css样式中,使用了两种背景色,作为渐变效果
JavaScript
注意three.js有四大核心要素:场景、相机、渲染器、模型对象,这四样要素缺一不可
- 场景
场景可以理解为舞台,是所有元素运作的环境,所有事物添加到场景中最终才能被我们看到,新建一个场景代码如下:
var scene = new THREE.Scene();
在创建好每个模型后往往用如下方法将模型置入场景中:
scene.add(e);
- 相机
相机有正交、透视、通用三种,可以理解为我们的眼睛,这里我们使用透视相机,代码如下:
var camera = new THREE.PerspectiveCamera(a1,a2,a3,a4);
四个参数:
视角:setFov(fov)设置视角的角度
宽高比:相机所看到的宽和高的比例
near:相机的近视角
far:表示相机的远视角
- 渲染器
三维空间里的物体映射到二维平面的过程被称为三维渲染。 一般来说我们都把进行渲染操作的软件叫做渲染器,渲染器需要加载到DOM节点中,创建渲染器代码如下:
//新建渲染器var renderer = new THREE.WebGLRenderer();//body中加载渲染引擎document.body.appendChild(renderer.domElement);
- 模型对象
对象模型是一种事物的组合:几何体、材质、网格,three使用网格系统来建立几何模型,我们创建一个物体通常先创建相应的几何体,再设置材质,把他们添加到网格中,形成物体,在下面会具体讲解
漂浮立方
首先我们创建一个初始化init()函数,它使得冗长的代码能够以清晰的结构呈现出来,我们主要的函数都会在init里加载
window.addEventListener('load',init,false);function init(){ //场景布局 createScene(); //灯光 createLight(); //场中的对象 //海 createEarth(); //带云的天空 createSky(); //循环函数 loop();}
- 场景布局
场景,相机,渲染器都是在createScene函数中创建,这是我们着手构造“世界”的准备工作,代码如下:
var scene,renderer,camera;function createScene(){ //新建场景 scene = new THREE.Scene(); //新建渲染器(允许透明度、抗锯齿、允许投影) renderer = new THREE.WebGLRenderer({alpha: true,antialias:true,shadowMapEnabled:true}); //重置画板大小 renderer.setSize(window.innerWidth,window.innerHeight); //相机(60度角,满屏宽高,视区1到10000) camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,10000); camera.position.set(0,300,600); camera.lookAt(Sea); camera.lookAt(scene.position); scene.add(camera); //在场景中添加雾效果 scene.fog = new THREE.Fog(0xf7d9aa, 100, 950); //world中加载渲染引擎 var world = document.getElementById('world'); world.appendChild(renderer.domElement); //屏幕监听,在调整视窗时更新渲染器及相机 window.addEventListener('resize',handleWindowResize,false);}
我们通过一个handleWindowResize函数来使得渲染器自适应窗口的大小,在改变视窗时渲染器更新渲染,代码如下:
function handleWindowResize(){ renderer.setSize(window.innerWidth,window.innerHeight); camera.aspect = window.innerWidth/window.innerHeight; camera.updateProjectionMatrix();}
- 灯光
灯光使得我们的物体能被看见,同样使用createLight函数来创建灯光,代码如下:
var hemisphereLight,shadowLight;function createLight(){ //创建半球灯对象 hemisphereLight = new THREE.HemisphereLight(0xaaaaaa,0x000000,0.9); //创建平行光对象 shadowLight = new THREE.DirectionalLight(0xffffff,0.9); shadowLight.position.set(150,350,350); shadowLight.castShadow = true; scene.add(hemisphereLight); scene.add(shadowLight);}
记得将创建好的组件都添加到场景scene中,有时候我们在检查效果时,往往发现组件并没有被使用,相机的位置与视角也是影响效果的重要因素,我们事先都需要设置好
- 场中的对象
我们使用构造函数Earth来构造出场景中的地球类,现在我们开始构造,代码如下:
Earth = function(){ //创建圆(上下半径600、高800、半径数40、垂直段数10) var geom = new THREE.SphereGeometry(600,80,60); //在x轴上旋转圆柱 geom.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI/2)); //创造材质 var mat = new THREE.MeshPhongMaterial({ color:'#104E8B', transparent:true, opacity:0.8, shading:THREE.FlatShading }); //创建网格 this.mesh = new THREE.Mesh(geom,mat); //允许接受阴影 this.mesh.receiveShadow = true; //通过合并定点保证波的连续性 geom.mergeVertices(); //得到顶点数量 var l = geom.vertices.length; //建立一个数组储存与每个顶点相关的新数据 this.waves = []; for (var i = 0;i<l;i++){ //得到每个顶点 var v = geom.vertices[i]; //存储与之相关的数据 this.waves.push({ x: v.x, y: v.y, z: v.z, //随机角 ang:Math.random()*Math.PI*2, //随机距离 amp:5 + Math.random()*15, //0.016到0.048间速度 speed:0.016 + Math.random*0.032 }); }}
为了使得地球看上去更加有意思一点我们使它的的表面凹凸不平,所以我们为它增加一个方法moveWaves,这里用到了原型继承的知识,代码如下:
Earth.prototype.moveWaves = function(){ //得到顶点 var verts = this.mesh.geometry.vertices; var l = verts.length; for (var i=0; i<l; i++){ var v = verts[i]; //获取相关的波数据 var vprops = this.waves[i]; //更新顶点的位置 v.x = vprops.x + Math.cos(vprops.ang)*vprops.amp; v.y = vprops.y + Math.sin(vprops.ang)*vprops.amp; //增加下一帧的角度 vprops.ang += vprops.speed; } earth.mesh.rotation.z += 0.0005;}
moveWaves方法会在循环函数中调用,一次来对每一帧进行渲染,就能模拟出地球表面凹凸不平的效果
下面我们使用createEarth函数来实例化地球类,并设置其位置,代码如下:
var earth;function createEarth(){ earth = new Earth(); //让海洋圆柱在屏幕下方位置 earth.mesh.position.y = -600; earth.mesh.position.z = 500; scene.add(earth.mesh);}
我们用简单的随机立方体来模拟漂浮在天空中的云朵,接下来我们创建Cloud的构造函数,来创建云朵类,代码如下:
Cloud = function(){ //创建一个3D对象用作容器 this.mesh = new THREE.Object3D(); //创建立体几何,用来复制云 var geom = new THREE.BoxGeometry(20,20,20); //材质 var mat = new THREE.MeshPhongMaterial({ color:'#FFFFFF' }); //复制几何,次数随机,造云 //最大6、最小3 var nBlocs = 3 + Math.floor(Math.random()*3); for (var i = 0;i<nBlocs;i++){ //复制网格,用来创建几何图形 var m = new THREE.Mesh(geom,mat); //设置每个方块的位置和旋转量,随机 m.position.x = i*15; m.position.y = Math.random()*10; m.position.z = Math.random()*10; m.rotation.z = Math.random()*Math.PI*2; m.rotation.y = Math.random()*Math.PI*2; //设置方块大小,随机 var s = 0.2 + Math.random()*0.3; m.scale.set(s,s,s); //允许每个方块投影并接受阴影 m.castShadow = true; m.receiveShadow = true; this.mesh.add(m); }}
云朵在天空中是看似随机有规律的的运动着的,我们还需要创建一个天空的构造函数来对云进行分布,代码如下:
Sky = function(){ //3D容器 this.mesh = new THREE.Object3D(); //在天空中选择一些云 this.nClouds = 20; //规定统一角度放置云 var stepAngle = Math.PI*2 / this.nClouds; //创建云 for (var i = 0;i<this.nClouds;i++){ //实例化一个云对象 var c = new Cloud(); //设置每片云的位置和旋转 //利用简单的三角学知识 var a = stepAngle*i;//云的最后一个角度 var h = 650 + Math.random()*100;//轴中心和云的距离(云高),700到950之间 //运用三角函数知识(以轴心为原点r边为h,y = sin(x轴夹角度)*h) //把极坐标转换成笛卡尔坐标 c.mesh.position.y = Math.sin(a)*h; c.mesh.position.x = Math.cos(a)*h; //根据位置旋转云 c.mesh.rotation.z = a + Math.PI/2; //随机云的深度 c.mesh.position.z = -400 - Math.random()*400; //为每片云设置随机规模比例 var s = 1 + Math.random()*2; c.mesh.scale.set(s,s,s); this.mesh.add(c.mesh); }}
从上面的代码中我们使用了三角函数的知识,这需要我们有良好的数学基础,实际上我们在编写的算法就是数学运算,如果在这方面有所欠缺,应该要补一补啦,但建议缺哪里补哪里
下面对天空的构造函数进行实例化,使我们的漂浮立方呈现出来,代码如下:
function createSky(){ sky = new Sky(); sky.mesh.position.y = -600; sky.mesh.position.z = 700; scene.add(sky.mesh);}
写到这里我们的工作基本完成的差不多了,现在我们的立方还不是真正意义上的“漂浮”,我们需要场景里的对象运动起来,所以我们要编写一个loop函数来使得渲染器循环渲染我们的每一帧,我们要是用一个requestAnimationFrame函数来调用渲染器的循环渲染,相当于递归,代码如下:
function loop(){ earth.moveWaves(); sky.mesh.rotation.z += 0.0008; //渲染 renderer.render(scene,camera); //调用循环渲染函数 requestAnimationFrame(loop);}
现在我们的所有的代码已经完成了,具体的效果点击链接可以查看>漂浮立方
这是我在CSDN里的第一篇微博文章,不知道有什么地方写的不好,有很多细节可能都没有写的清除,可以留言我,其实写这篇微博体现最多的就是我们在编写three的效果时的一些实现思路和结构思路,个人认为这是非常重要的事情,这能让我在编写实现时不会发生思维混乱,以至于写着写着就不知道写到哪里,结构化的编程思路是我们需要学习的一种思维,这会让我在理解实现上受益不菲。
- 运用three.js写的漂浮立方
- 网页漂浮的js
- js 立方 平方怎么写
- js实现层的漂浮
- 兼容的漂浮广告(js)
- 一段漂浮广告的js
- Three.js的学习心得
- 33 Three.js的材质THREE.MeshBasicMaterial
- 34 Three.js的材质THREE.MeshDepthMaterial
- 两边漂浮图片的一段JS
- 两边漂浮图片的一段JS
- 跟随滚动条漂浮的JS特效
- 漂浮广告的JS代码(经典)
- 两边漂浮图片的一段JS
- js css3写嵌套立方体动画效果(大立方内套小立方)
- Three.js 是干什么的?
- three.js的接口程序
- 使用Three.js的材质
- Java——Iterator迭代器
- switchHosts!修改hosts后不能立即生效的问题
- Maven学习总结(一)——Maven入门
- 信号量
- OO的五大设计模式原则
- 运用three.js写的漂浮立方
- 用数组模拟链表
- 【雅思备考】Task2——主体段
- 数组元素的逆序输出(改变内存中的数据)
- 【项目管理和构建】——Maven下载、安装和配置(二)
- 【雅思备考】Task2——总阶段
- 命令vmstat查看系统负载
- [学习笔记]Python_字符串
- Codeforces 868F