在我们已经获得的所有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有趣的可能性。 坚持下去,您将可以立即实现一些惊人的壮举。