在我们已经获得的所有HTML5和相关API中, WebGL可能是最有趣的。 有了它,我们就可以在浏览器中创建出色的3D环境,在本文中,我将向您详细介绍如何做到这一点。
特别是,我们将建立一个地球模型,使我们可以像一个疯狂的人一样旋转,并可以与我们的开发者一起为之赞叹……好吧,至少可以。
在我们开始之前
在本教程中,我们将使用出色的three.js WebGL插件 。 它有点像WebGL的jQuery,它抽象了本机API固有的许多处理丑陋性。 简而言之,three.js使我们的生活更加轻松。
就像我们HTML文档中的任何普通脚本一样,我们可以包括它:
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r63/three.min.js"></script>
在这里,我们使用了CDN,但是您可以使用本地版本。 然后,我们需要确保WebGL可以渲染。 这里我们有一些灵活性:我们可以使用普通的div
或canvas直接将其呈现到HTML中,否则我们可以稍后使用JavaScript创建和附加画布。 我们将采用第一种方法,使事情变得简单一些:
<body>
<div id="container"></div>
<script src="earth.js"></script>
</body>
将链接添加到JavaScript文件后,我们的HTML或多或少已经完成。
设置
Three.js本身往往会像实际的3D桌面程序那样设置内容。 我们有一个生活在其中的场景,一个用来查看它们的相机,一些照明,一个实际渲染事物的渲染器,当然还有3D对象本身。 该列表似乎有些令人生畏,但是所有这些都可以在我们的earth.js
JavaScript文件中作为变量来成形。
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,我们可以轻松实现这些功能,稍后我们将了解它们如何适合我们的项目。
环境
首先,我们需要获取新变量并进行设置,以使我们的地球模型看起来更棒。
我们可以从设置将处理这种环境问题的一切开始:
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);
这是上面代码中发生的情况的描述:
- 我们在HTML中获取对容器的引用
- 我们使用之前声明的变量来设置摄像机(有关摄像机如何在3D模式下工作的更多信息, 请参阅)。
- 我们使用
position.set
设置相机的位置,该参数接受每个尺寸(x,y和z)的参数。 您可能已经猜到了,我们将使用此相机指向我们的3D对象,在这种情况下,这就是我们的地球。 - 接下来,我们设置灯光。 没有这个,渲染所有内容时我们只会得到一个黑屏,因此我们需要非常小心地进行设置。 Three.js的SpotLight对象采用与我们的相机大致相同的参数,但是将颜色添加为十六进制值作为其第一个参数,然后是其余参数。
- 最后,我们设置了渲染器。 难题的另一个重要组成部分,渲染器实际上将我们制作的场景渲染到屏幕上。 再一次,没有它,我们只能看到太空的黑暗。 我们对它进行抗锯齿处理(对于某些平滑屁股表面),并将其作为DOM元素附加到我们的原始容器中。
现在,我们需要通过粘贴在网格中来开始构建地球本身:
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);
在这里,我们创建一个网格,该网格有点像一个对象,我们将其打扮成看起来像地球,并为其提供一些几何形状以及一种材质或纹理来覆盖它。 我们也将其正确放置并像对待其他对象一样将其添加到场景中。
您可以在下面看到我们的设置示例。 这里有一些额外的代码来处理渲染(稍后我们将介绍),但是到目前为止看起来不错!
蓝色星球
现在有趣的部分是剥皮这个家伙。 首先,我们将使用一个漫反射贴图,它将使我们看起来像地球,您可以像这样添加:
// diffuse map
earthMat.map = THREE.ImageUtils.loadTexture('images/earthmap1k.jpg');
如果您需要在此处使用良好的纹理, 可以尝试使用此纹理或在Google上搜索合适的Earth漫射贴图。 分辨率高的东西都可以。
现在看起来还不错,但是我们可以通过在此处引入一些地形来使其更好。 地球上有一些高山,为了确保太阳系的其余部分知道这一点,我们需要使用凹凸贴图 。 在3D中,凹凸贴图是黑白图像,白色的强度表示“凹凸”(在我们的情况下,我们的山脉)的高度。
// bump map
earthMat.bumpMap = THREE.ImageUtils.loadTexture('images/elev_bump_16ka.jpg');
earthMat.bumpScale = 8;
有了这个,我们或多或少就在那里。 再次,在Google上搜索“地震动图”将为您提供很多选择,但是如果您不想狩猎,可以在这里找到一个不错的选择 。 如果运行上面的代码(使用之前的渲染代码),则会得到以下信息:
旋转吧!
现在剩下的就是让地球旋转。 为此,我们需要两个新函数,分别称为render()
和animate()
。
function animate() {
requestAnimationFrame(animate);
render();
}
我们的animate()
函数并不太复杂。 它使用requestAnimationFrame()
连续调用自身,并且每次调用时,都会调用render()
函数。 接下来让我们转到render()
函数:
function render() {
var clock = new THREE.Clock(),
delta = clock.getDelta();
earthMesh.rotation.y += rotationSpeed * delta;
renderer.render(scene, camera);
}
这就是发生的事情。 每次调用render()
,它都会render()
我们的地球在y轴上旋转一点(您可以在此处选择任何旋转角度;在这种情况下,我们将使用带有getDelta()
方法的内置时钟,但您不必)。 然后,它清除了渲染器,这是避免渲染丑陋的必要步骤,并渲染了场景(其中包含所有内容)和相机。
到苦头
当然,我们可以添加一些调整以使我们的地球变得更好。 OrbitControls.js是一个脚本,它将为我们的地球提供一些鼠标驱动的旋转功能,并且在背景中或平流层中的一些云层中添加星星场也不太困难。 如果您是一个真正的惩罚者,甚至可以使用WebGL的着色器为您的星球添加气氛。
您可以在最终的CodePen演示中看到一些带有代码的示例
确保在页面上单击并滚动鼠标滚轮以查看特殊效果(按住shift键可使鼠标滚轮在此页面上运行,或者使用整页演示 )。
结论
WebGL和three.js可能具有挑战性,因为它们要求我们有时使用场景,渲染器和照相机之类的东西像3D艺术家那样思考。
但是结果却是令人印象深刻的东西,如果您热心的话,可能会在浏览器中带来3D有趣的可能性。 坚持下去,您将可以立即实现一些惊人的壮举。