原翻译:利用javascript和WebGL绘制地球 【翻译】javascript
在咱们全部已知的HTML5API中,WebGL多是最有意思的一个,利用这个API咱们可以在浏览器中创造出炫酷3D场景的能力。本文将完整的向你展现一些炫酷是如何实现的。html
须要特别指出的是,这篇教程咱们将会构建一个地球行星模型,这个模型能够像一个兴奋的人同样环绕的旋转,另外,它可能使咱们能够得到一些其余程序员的称赞,好吧,就这么多了。html5
这篇教程咱们将会用到一个使人着迷的WebGL插件:three.js. 这个插件跟JQuery有点像,不过它是针对WebGL的,它将不少复杂的原生API访问接口进行了抽象,从而让咱们能够更轻易的利用WebGL的特性。java
在HTML中,咱们的能够经过正常的script标签引入这个插件,以下:git
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r63/three.min.js"></script>
此处咱们引用的是CDN版本,若是你有必要,可使用本地的方法引入。而后咱们须要确保WebGL有东西能够在上面进行渲染。这里咱们有个灵活的作法:咱们能够直接将通常的Div或者Canvas写到HTML中,或者咱们能够另外用JS建立而且追加canvas元素到Dom里后再去渲染。这里咱们采用第一种容易点的方法,以下:程序员
<body> <div id="container"></div> <script src="earth.js"></script> </body>
添加完script标签链接到Dom中后,咱们的HTML部分差很少就完成了。github
Tree.js自己是趋向把东西作的很是接近真实的3D桌面程序的。咱们拥有一个场景,有一些东西现场直播,而后经过摄像机去浏览,而后有些灯光,特效,渲染在整场景上面,固然他们自身也全都是3D对象。这个场景的元素列表彷佛有点吓人,在咱们的earth.js文件里,全部的这些元素均可以当成形状变量,Javascript文件以下:web
var scene, camera, light, renderer, earthObject; var WIDTH = window.innerWidth - 30, HEIGHT = window.innerHeight - 30; var angle = 45, aspect = WIDTH / HEIGHT, near = 0.1, far = 3000;
有些额外的变量也定义在这里了,WIDTH,HEIGHT 变量用来获取咱们画布的宽与高,下面的其余变量以后将会用来设置咱们相机的位置。对于几乎全部的3D对象来讲,全部这些元素都是共通的,不管是平台仍是环境,因此在这里咱们习惯性的将这些家伙写到一块儿。然而利用Three.js咱们能够轻松的实现,咱们将看看全部这些元素是如何在同一时刻融合到项目中的。ajax
首先,咱们须要启用新变量并初始化他们,从而使咱们的地球模型能够展现的更炫。咱们能够先设置每一个处理环境因素的变量:canvas
var container = document.getElementById('container'); camera = new THREE.PerspectiveCamera(angle, aspect, near, far); camera.position.set(0, 0, 0); scene = new THREE.Scene(); light = new THREE.SpotLight(0xFFFFFF, 1, 0, Math.PI / 2, 1); light.position.set(4000, 4000, 1500); light.target.position.set (1000, 3800, 1000);
下面是针对上面代码执行状况的描述:
position.set
方法设置camera的位置, 这个方法须要携带一个维度(x, y, z)参数对象, 可能你已经想到了, 咱们将会使用这个camera去定位咱们的3D对象,本教程中的3D对象就是咱们的地球模型。如今咱们须要经过将整个地球粘贴在网上同样的方式来构建自身整个模型。代码以下:
var earthGeo = new THREE.SphereGeometry (30, 40, 400), earthMat = new THREE.MeshPhongMaterial(); var earthMesh = new THREE.Mesh(earthGeo, earthMat); earthMesh.position.set(-100, 0, 0); earthMesh.rotation.y=5; scene.add(earthMesh);
在这里咱们建立了一个网状(Mesh)对象,这个网状是一种能够被用来装扮并看起来像地球形状的对象,而后给这个对象添加一些几何结构,外观包装,或者一些有质感的材料来包裹这个网状体。咱们一样会将这个对象设置适当的在位置,与其余参数对象同样,咱们会而且将Mesh对象添加到咱们的场景(scene)中。
以下有个样例。这里面有些额外的渲染效果,稍后咱们将会讲解。这个样例看起来离咱们想要的愈来愈近了。
接下来有趣的部分是给这个家伙制做皮肤。首先咱们将会使用一张漫反射贴图,它会让这个家伙看起来更像个地图。你能够像下面的方式同样添加:
// diffuse map earthMat.map = THREE.ImageUtils.loadTexture('images/earthmap1k.jpg');
若是你想要质感更好些的话,你能够尝试用这个图片,或者你能够去google搜索一张你想要的图片都行。高分辨率的图均可以。
如今这个模型看起来没那么糟糕了,可是咱们仍然能够经过引用一点地形描绘的方式,使整个模型看起来更真实些。这个地球有一些高山,为了确保区分太阳系的其余星球,咱们须要使用凹凸地图(bump map), 在3D模型中, 凹凸地图是黑白图,使用鲜明的白色去凸显图像凹凸不平的部分(例如咱们示例中的:山脉)。
// bump map earthMat.bumpMap = THREE.ImageUtils.loadTexture('images/elev_bump_16ka.jpg'); earthMat.bumpScale = 8;
使用上面的图片咱们差很少达到了效果,再次强调,使用过Google搜索“Earth bump map”会得到大量的选择,可是若是你感受都很差的话,你能够点击这个链接。 运行了以上的代码,咱们将会看到以下效果:
接下来剩余的事情就是咱们给这个地球模型添加一些动画效果,为此,咱们须要两个新的方法,咱们命名为render()
和animate()
function animate() { requestAnimationFrame(animate); render(); }
咱们的animate()
方法并非很复杂,经过自身递归连续的调用requestAnimationFrame()
方法,anmiate()
会请求咱们的render()
方法,让咱们看看render()
方法的代码:
function render() { var clock = new THREE.Clock(), delta = clock.getDelta(); earthMesh.rotation.y += rotationSpeed * delta; renderer.render(scene, camera); }
咱们看看上面的代码作了些什么工做。每次render()
方法被请求,它便会让地球模型在y轴上缓缓的转动起来(此处你能够选择设置任意的转动次数,咱们在这里利用getDelta()
方法构建一个时钟对象来控制转动次数,固然你能够不使用这种方法)。而后render()
方法会执行清理画布操做,这是防止画布乱掉很重要的步骤,最后它会渲染咱们的场景(以及场景对象中的其余全部对象)和咱们的camera对象。
固然,拥有拖拽操做会让咱们的地球模型的体验更好,OrbitControls.js是一个能够为咱们地球模型提供鼠标驱动旋转效果能力的脚本,而且它为咱们的平流层里添加一些星星或者云做为地球模型的背景一样也并不困难,若是你并不嫌麻烦的话,你甚至能够利用WebGL的着色器(shaders)为你的星球添加一个平流层。
运行代码,你能够看到一个样例,在CodePen中最终的Demo以下:
经过按住鼠标拖动和滚动鼠标滑轮来查看效果(或者点击此处demo
WebGL和Three.js变得愈加的具备挑战性,由于他们偶尔会要求咱们要像3D艺术家同样,利用场景,画布,camera去完成咱们的工做,最终的结果就是作出了一些加使人印象深入的东西。若是你专一于在这个技术上的话,你能够经过在浏览器中使用3D特性创造出一些有趣的可能性。若是坚持它,相信不久你就极可能获取一些非凡的成绩。