内容简介:看了饿了么小小倩老师的canvas作品,心血来潮,学着做了个3D地球,也算是入坑WebGL了吧。之前有用过原生的canvas画2D的图形,这次则是用了Three.js和stats.js的3D框架,边学边练手,效果还算比较满意...毕竟第一次接触WebGLTalk is cheap show the code!github项目源码地址:
看了饿了么小小倩老师的canvas作品,心血来潮,学着做了个3D地球,也算是入坑WebGL了吧。之前有用过原生的canvas画2D的图形,这次则是用了Three.js和stats.js的3D框架,边学边练手,效果还算比较满意...毕竟第一次接触WebGL
Talk is cheap show the code!
github项目源码地址: github.com/FightingHao…
项目演示地址: fightinghao.github.io/codingDream…
代码还有很多不足,求大神review..
什么是Three.js
随着近几年前端的飞速发展,网页的表现能力越来越强大,浏览器提供了WebGL(Web图形处理库)接口,可以通过调用对应API进行3D图形的绘制, Three.js
则是在此基础接口之上又做了一层封装。 Three.js
是当下最流行的网页3D渲染JS引擎。
Three.js使用方法
准备阶段
- 页面添加canvas元素
<!-- 作为Three.js渲染器输出3D图形 --> <canvas id="webglcanvas"></canvas> 复制代码
- 引入Three.js库文件
- 本地引入
<!-- Three.js库 --> <script src="./libs/three.min.js"></script> 复制代码
- CDN远程引入
<script src='http://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js'></script> 复制代码
- 项目中用到的变量
let canvas, //画布标签 stats, //性能检测器 camera, //相机 scene, //场景 renderer, //渲染器 group, //物体组 mouseX = 0, //鼠标横向位置 mouseY = 0, //鼠标纵向位置 windowHalfX = window.innerWidth / 2, //视口大小的一般 windowHalfY = window.innerHeight / 2; //视口大小的一半 复制代码
创建场景素材
为了让three.js显示,需要三件事情:场景、相机和渲染器
-
场景,可以理解为舞台。因为要绘制3D效果,必须要有一个舞台来演示效果
创建场景 API:
THREE.Scene()
scene = new THREE.Scene() //创建场景 复制代码
-
有了场景,现在需要相机来拍摄出素材出来,所以第二步则是需要创建一个"相机"
创建相机 API:THREE.PerspectiveCamera(fov, aspect, near, far)
- fov 可视角度,可理解为视野,是在显示器上看到的场景的范围,以度为单位。
- aspect 为width/height,通常设置为canvas元素的高宽比。
- near近端距离
- far远端距离
- 只有离相机的距离大于near值,小于far值,且在相机的可视角度之内,才能被相机投影到。
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000) camera.position.z = 500 //相机的远近 复制代码
-
场景和相机都有了,也就是能够拍摄出素材了,但素材需要经过一些PS、美颜等才能变得好看。这时候就需要渲染器。
创建渲染器 API:
THREE.WebGLRenderer({})
renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true, // true/false表示是否开启反锯齿, /* alpha: false, // true/false 表示是否可以设置背景色透明, precision: 'highp', // highp/mediump/lowp 表示着色精度选择, premultipliedAlpha: false, // true/false 表示是否可以设置像素深度(用来度量图像的分辨率), maxLights: 3, // 最大灯光数, stencil: false // false/true 表示是否使用模板字体或图案 */ }) 复制代码
指定渲染器宽高 API: renderer.setSize(window.innerWidth, window.innerHeight)
参数分别为宽和高
创建3D图形
我们已经用相机在场景中拍摄出了素材,但这些素在毕竟还只是2D,现在我们要将该素材由2D变为3D,这时这就需要用一个3D图形作为2D素材的载体。用个吃货的简单理解,就是鸡肉卷外面的卷,开始卷是2D的平面的,把鸡肉到卷面上,用卷包裹起鸡肉,则就由2D的卷变成了3D的鸡肉卷对吧。emmm...解释的好尬。
API:
- 图形形状
THREE.SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)
- radius:球体半径
- widthSegments, heightSegments:水平方向和垂直方向上分段数。widthSegments最小值为3,默认值为8。heightSegments最小值为2,默认值为6。
- phiStart:水平方向上的起始角,默认值0
- phiLenght:水平方向上球体曲面覆盖的弧度,默认Math.PI * 2
- thetaStart : 垂直方向上的起始角, 默认0
- thetaLength: 垂直方向是球体曲面覆盖的弧度,默认值为Math.PI
- 图形材质
THREE.MeshBasicMaterial({})
图形材质有很多种,网上查了查资料,觉得这个总结的挺好,大家可以看一看 blog.csdn.net/qq_30100043… - 图形构成
THREE.Mesh(geometry, material)
- geometry 物体形状
- material 物体材质
let geometry = new THREE.SphereGeometry(200, 20, 20) //形状 let material = new THREE.MeshBasicMaterial({ map: texture }) //材质 let mesh = new THREE.Mesh(geometry, material) //物体 复制代码
- 加载图形
new THREE.TextureLoader().load(img, callback)
将上面的图形加载出来
loader.load('./img/land_ocean_ice_cloud_2048.jpg', function (texture) { let geometry = new THREE.SphereGeometry(200, 20, 20) //形状 let material = new THREE.MeshBasicMaterial({ map: texture }) //材质 let mesh = new THREE.Mesh(geometry, material) //物体 }) 复制代码
创建组合
我们有了3D图形,接下来就是将这些图形组合在一起,变成多样的3D界面
创建组合 API: THREE.Group()
//创建一个组合 group = new THREE.Group() scene.add(group) //将组合添加进场景中渲染 复制代码
将创建好的3D图形添加进组合中
API: group.add(mesh)
- mesh 3D物体
运动起来
3D图形已经在场景中渲染出来了,现在,则需要让它们动起来!
function animate() { // 请求运动帧 requestAnimationFrame(animate) render() } // 地球旋转逻辑函数 function render() { // 更新性能监视器 stats.update(); camera.position.x += (mouseX - camera.position.x) * 0.05 camera.position.y += (mouseX - camera.position.y) * 0.05 // 拍摄角度, 可改变地球视角 camera.lookAt(scene.position) // 地球自转速度 group.rotation.y -= 0.005 // 运动核心 递归调用 renderer.render(scene, camera) } 复制代码
现在已经基本完成了3D地球的自转
什么是stats.js
说了Three.js,现在聊聊什么是stats.js吧。stats.js 是一个 Three.js 开发的辅助库,通过检测动画运行时的帧数,来测试WebGL代码的运行性能
stats.js使用
准备阶段
类似于Three.js,stats.js也需要引入框架库,并由div来渲染显示性能测试界面
<!-- 用于显示和统计图形的性能 --> <div id="stats-output"></div> <!-- 引入stats.js库 --> <script src="./libs/stats.min.js"></script> 复制代码
开始使用
首先需要初始化stats
// stats性能检测器初始化 stats = initStats(); function initStats() { stats = new Stats(); //设置统计模式 stats.setMode(0); // 0: fps, 1: ms //统计信息显示在左上角 stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '10px'; stats.domElement.style.top = '10px'; //将统计对象添加到对应的<div>元素中 document.getElementById("stats-output").appendChild(stats.domElement); return stats; } 复制代码
当场景变换时,也就是3D运动时,需要实时更新stats检测器 API: stats.update();
用于地球旋转时,动态更新检测情况
// 地球旋转逻辑函数 function render() { // 更新性能监视器 stats.update(); camera.position.x += (mouseX - camera.position.x) * 0.05 camera.position.y += (mouseX - camera.position.y) * 0.05 // 拍摄角度, 可改变地球视角 camera.lookAt(scene.position) // 地球自转速度 group.rotation.y -= 0.005 // 核心 递归调用 renderer.render(scene, camera) } 复制代码
可以看到两种检测情况 stats.setMode(0); // 0: fps, 1: ms
参数0 显示FPS
stats.setMode(1); // 0: fps, 1: ms
参数1 显示MS
最后优化
1.通过鼠标可控制地球角度
// 绑定鼠标移动事件 document.addEventListener('mousemove', onDocumentMouseMove, false) // 监听鼠标移动方向, 从而确定地球南北半球 function onDocumentMouseMove(ev) { ev = ev || event mouseX = ev.clientX - windowHalfX mouseY = ev.clientY - windowHalfY } 复制代码
2.响应式
可根据窗口大小自动改变渲染图形大小
// 窗口大小改变监听 window.addEventListener('resize', onWindowResize, false) // 监听窗口大小, 从而根据窗口大小改变地球大小, 类似响应式 function onWindowResize() { windowHalfX = window.innerWidth / 2 windowHalfY = window.innerHeight / 2 camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) } 复制代码
好了,现在3D地球就基本上完成了~
完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>WebGL之3D地球</title> <style> /* 禁止系统默认滚动条 */ html, body { height: 100%; overflow: hidden; } </style> </head> <body> <!-- 用于显示和统计图形的性能 --> <div id="stats-output"></div> <!-- 作为Three.js渲染器输出3D图形 --> <canvas id="webglcanvas"></canvas> <!-- webgl库 --> <script src="./libs/three.min.js"></script> <script src="./libs/stats.min.js"></script> <script> let canvas, //画布标签 绘图API stats, //性能检测器 camera, //相机 scene, //场景 renderer, //渲染器 group, //物体组 mouseX = 0, //鼠标横向位置 mouseY = 0, //鼠标纵向位置 windowHalfX = window.innerWidth / 2, //视口大小的一般 windowHalfY = window.innerHeight / 2; //视口大小的一半 init() //构建地球 animate() //使地球旋转起来 function init() { // 获取canvas画布 canvas = document.getElementById('webglcanvas') // stats性能检测器初始化 stats = initStats(); // 3D绘制 // 相机 camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000) camera.position.z = 500 //相机的远近 // 场景 scene = new THREE.Scene() // 创建一个组合 group = new THREE.Group() scene.add(group) //将组合添加进场景中渲染 // 地球 数学形状 贴图 let loader = new THREE.TextureLoader() loader.load('./img/land_ocean_ice_cloud_2048.jpg', function (texture) { // console.log(texture) let geometry = new THREE.SphereGeometry(200, 20, 20) //形状 let material = new THREE.MeshBasicMaterial({ map: texture }) //材质 let mesh = new THREE.Mesh(geometry, material) //物体 group.add(mesh) }) // 渲染器 renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true, // true/false表示是否开启反锯齿, /* alpha: false, // true/false 表示是否可以设置背景色透明, precision: 'highp', // highp/mediump/lowp 表示着色精度选择, premultipliedAlpha: false, // true/false 表示是否可以设置像素深度(用来度量图像的分辨率), maxLights: 3, // 最大灯光数, stencil: false // false/true 表示是否使用模板字体或图案 */ }) // 指定渲染器宽高 renderer.setSize(window.innerWidth, window.innerHeight) // 绑定鼠标移动事件 document.addEventListener('mousemove', onDocumentMouseMove, false) // 窗口大小改变监听 window.addEventListener('resize', onWindowResize, false) } // 监听鼠标移动方向, 从而确定地球南北半球 function onDocumentMouseMove(ev) { ev = ev || event mouseX = ev.clientX - windowHalfX mouseY = ev.clientY - windowHalfY } // 监听窗口大小, 从而根据窗口大小改变地球大小, 类似响应式 function onWindowResize() { windowHalfX = window.innerWidth / 2 windowHalfY = window.innerHeight / 2 camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) } function animate() { // 请求运动帧 requestAnimationFrame(animate) render() } // 地球旋转逻辑函数 function render() { // 更新性能监视器 stats.update(); camera.position.x += (mouseX - camera.position.x) * 0.05 camera.position.y += (mouseX - camera.position.y) * 0.05 // 拍摄角度, 可改变地球视角 camera.lookAt(scene.position) // 地球自转速度 group.rotation.y -= 0.005 // 核心 递归调用 renderer.render(scene, camera) } function initStats() { stats = new Stats(); //设置统计模式 stats.setMode(0); // 0: fps, 1: ms //统计信息显示在左上角 stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '10px'; stats.domElement.style.top = '10px'; //将统计对象添加到对应的<div>元素中 document.getElementById("stats-output").appendChild(stats.domElement); return stats; } // ecchat 数据可视化 // 平面的世界是错误的, css perspective:1000px transform-style:perserve-3d // Camera Scene render(渲染容器) Light -> canvas </script> </body> </html> 复制代码
图片素材和js库可以到我的github上下载:
github.com/FightingHao…第一次在掘金上发文章,希望大家可以点点赞哈哈~
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 用python模拟地球飞越木星
- 《流浪地球》——程序员的悲哀
- python爬取《流浪地球》16w评论
- OpenATS续篇:搭建自己的卫星地球站
- Python爬取《流浪地球》豆瓣影评与数据分析
- 我爬了《流浪地球》十万个短评得出以下结论
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
游戏化革命:未来商业模式的驱动力
[美]盖布·兹彻曼、[美]乔斯琳·林德 / 应皓 / 中国人民大学出版社有限公司 / 2014-8-1 / CNY 59.00
第一本植入游戏化理念、实现APP互动的游戏化商业图书 游戏化与商业的大融合、游戏化驱动未来商业革命的权威之作 作者被公认为“游戏界的天才”,具有很高的知名度 亚马逊五星级图书 本书观点新颖,游戏化正成为最热门的商业新策略 游戏化是当今最热门的商业新策略,它能帮助龙头企业创造出前所未有的客户和员工的参与度。商业游戏化策略通过利用从游戏设计、忠诚度计划和行为经济学中所汲取......一起来看看 《游戏化革命:未来商业模式的驱动力》 这本书的介绍吧!