Rumah  >  Artikel  >  hujung hadapan web  >  Pengenalan asas: Pembangunan WebGL dengan Three.js

Pengenalan asas: Pembangunan WebGL dengan Three.js

WBOY
WBOYasal
2023-08-30 13:25:051485semak imbas

Grafik 3D dalam penyemak imbas telah menjadi topik hangat sejak ia mula diperkenalkan. Tetapi jika anda ingin membuat aplikasi menggunakan WebGL tulen, ia mengambil masa yang lama. Itulah sebabnya beberapa perpustakaan yang sangat berguna telah muncul baru-baru ini. Three.js ialah salah satu yang paling popular, dan dalam siri ini, saya akan menunjukkan kepada anda cara terbaik menggunakannya untuk mencipta pengalaman 3D yang menakjubkan untuk pengguna anda.

Sebelum kita bermula, saya mengharapkan anda mempunyai pemahaman asas tentang ruang 3D sebelum anda mula membaca tutorial ini, kerana saya tidak akan menerangkan perkara seperti koordinat, vektor, dll.


Langkah 1: Persediaan

Pertama, buat tiga fail: index.html, main.js dan style.css. Sekarang, muat turun Three.js (sama ada keseluruhan fail zip dengan contoh dan kod sumber, atau fail JavaScript yang berasingan, pilihan anda). Sekarang, buka index.html dan masukkan kod berikut: index.htmlmain.jsstyle.css。现在,下载 Three.js(带有示例和源代码的整个 zip 文件,或者单独的 JavaScript 文件,您可以选择)。现在,打开 index.html 并插入以下代码:

<!DOCTYPE html>
<html>
<head>
	<link rel="stylesheet" href="./style.css">
	<script src="./three.js"></script>
</head>
<body>
	<script src="./main.js"></script>
</body>
</html>

这就是您在此文件中所需要的全部内容。只是脚本和样式表的声明。所有的魔力都将发生在 main.js 中,但在我们实现这一点之前,我们还需要一个技巧来让应用程序看起来更好。打开 style.css 并插入以下代码:

canvas {
	position: fixed;
	top: 0;
	left: 0;
}

这会将画布定位在左上角,因为默认情况下 body 将具有 8px 的边距。现在我们可以继续处理 JavaScript 代码。


第 2 步:场景和渲染器

Three.js 使用显示列表的概念。这意味着所有对象都存储在列表中,然后绘制到屏幕上。

Three.js 使用显示列表的概念。这意味着所有对象都存储在列表中,然后绘制到屏幕上。在这里,这是一个 THREE.Scene 对象。您需要将想要在屏幕上绘制的任何对象添加到场景中。您可以拥有任意多个场景,但一个渲染器一次只能绘制一个场景(当然您可以切换显示的场景)。

渲染器只是将场景中的所有内容绘制到 WebGL 画布上。 Three.js 还支持在 SVG 或 2D Canvas 上绘图,但我们将重点关注 WebGL。

首先,让我们将窗口的宽度和高度存储在变量中,稍后我们将使用它:

var width = window.innerWidth;
var height = window.innerHeight;

现在定义渲染器和场景:

var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);

var scene = new THREE.Scene;

第一行定义 WebGL 渲染器。您可以将第一个参数中的渲染器选项作为地图传递。这里,我们将 antialias 设置为 true,因为我们希望对象的边缘平滑,而不是锯齿状。

第二行将渲染器大小设置为窗口的大小,在第三行中,我们将渲染器的 canvas 元素添加到文档中(您也可以使用库来执行此操作,例如 jQuery: $( 'body').append(renderer.domElement))。

最后一个定义场景,不需要参数。


第 3 步: 立方体

现在让我们添加要绘制的内容。让它成为一个立方体,因为它是最简单的 3D 对象。在 Three.js 中,屏幕上绘制的对象称为网格。每个网格都必须有自己的几何形状和材料。几何是一组需要连接才能创建对象的点。材质只是覆盖对象的油漆(或绘画,但这不是本教程的主题)。那么,让我们创建我们的立方体。幸运的是,Three.js 中有一些用于创建基元(简单形状)的辅助函数:

var cubeGeometry = new THREE.CubeGeometry(100, 100, 100);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0x1ec876 });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

cube.rotation.y = Math.PI * 45 / 180;

scene.add(cube);

如您所见,首先我们创建几何图形。参数定义立方体的大小:宽度、高度和深度。

接下来,我们定义立方体的材质。 Three.js中有一些材质类型,但是这次我们将使用THREE.MeshLambertMaterial,因为我们稍后想要一些光照(该材质使用兰伯特算法进行光照计算)。您可以将第一个参数中的选项作为映射传递,与渲染器相同 - 这几乎是 Three.js 中更复杂对象的规则。在这里,我们只使用颜色,它以十六进制数字形式传递。

在第三行,我们使用之前创建的几何体和材质创建一个网格。接下来,我们将立方体在 Y 轴上旋转 45 度,使其看起来更好。我们必须将度数更改为弧度,这是通过您可能记得的高中物理课上的方程式来处理的:Math.PI * 45 / 180。最后,立方体被添加到场景中。

现在您可以在浏览器中打开 index.html 来查看结果,但您将看不到任何内容,因为场景尚未渲染。


第 4 步: 相机!

要渲染某些内容,首先我们需要将相机添加到场景中,以便渲染器知道应该从哪个角度渲染内容。 Three.js 中有几种类型的相机,但您可能只会使用 THREE.PerspectiveCamera

var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 10000);

Itu sahaja yang anda perlukan dalam fail ini. Hanya pengisytiharan skrip dan helaian gaya. Semua keajaiban akan berlaku dalam main.js, tetapi sebelum kita boleh melakukannya, kita memerlukan satu lagi helah untuk menjadikan apl kelihatan lebih baik. Buka style.css dan masukkan kod berikut: #🎜🎜#
camera.position.y = 160;
camera.position.z = 400;
#🎜🎜#Ini akan meletakkan kanvas di penjuru kiri sebelah atas kerana body akan mempunyai margin 8px secara lalai. Sekarang kita boleh beralih kepada kod JavaScript. #🎜🎜# #🎜🎜# #🎜🎜# #🎜🎜#Langkah 2: #🎜🎜#Scene and Renderer#🎜🎜#
#🎜🎜# Three.js menggunakan konsep senarai paparan. Ini bermakna semua objek disimpan dalam senarai dan kemudian ditarik ke skrin. #🎜🎜#
#🎜🎜#Three.js menggunakan konsep senarai paparan. Ini bermakna semua objek disimpan dalam senarai dan kemudian ditarik ke skrin. Dalam kes ini, ia ialah objek THREE.Scene. Anda perlu menambah sebarang objek yang anda ingin lukis pada skrin ke tempat kejadian. Anda boleh mempunyai seberapa banyak adegan yang anda suka, tetapi pemapar hanya boleh melukis satu adegan pada satu masa (sudah tentu anda boleh menukar adegan yang dipaparkan). #🎜🎜# #🎜🎜#Penyaji hanya melukis segala-galanya dalam pemandangan ke kanvas WebGL. Three.js juga menyokong lukisan pada SVG atau Kanvas 2D, tetapi kami akan menumpukan pada WebGL. #🎜🎜# #🎜🎜# Pertama, mari simpan lebar dan tinggi tetingkap dalam pembolehubah, kita akan menggunakannya kemudian: #🎜🎜#
scene.add(camera);

renderer.render(scene, camera);
#🎜🎜# Sekarang tentukan pemapar dan adegan: #🎜🎜#
camera.lookAt(cube.position);
#🎜🎜#Baris pertama mentakrifkan pemapar WebGL. Anda boleh lulus pilihan pemapar dalam parameter pertama sebagai peta. Di sini, kami menetapkan antialias kepada benar kerana kami mahu tepi objek menjadi licin, tidak bergerigi. #🎜🎜# #🎜🎜#Baris kedua menetapkan saiz pemapar kepada saiz tetingkap dan dalam baris ketiga kami menambah elemen kanvas pemapar pada dokumen (anda juga boleh menggunakan perpustakaan untuk melakukan ini , seperti jQuery: $( 'body').append(renderer.domElement)). #🎜🎜# #🎜🎜#Adegan definisi terakhir tidak memerlukan parameter. #🎜🎜# #🎜🎜# #🎜🎜# #🎜🎜#Langkah 3: #🎜🎜# Kiub #🎜🎜# #🎜🎜#Sekarang mari tambah apa yang kita mahu lukis. Biarkan ia menjadi kiub, kerana ia adalah objek 3D yang paling mudah. Dalam Three.js, objek yang dilukis pada skrin dipanggil grid. Setiap jaringan mesti mempunyai geometri dan bahannya sendiri. Geometri ialah satu set titik yang perlu disambungkan untuk mencipta objek. Bahan hanyalah cat (atau lukisan, tetapi itu bukan topik tutorial ini) yang merangkumi objek. Jadi, mari kita buat kiub kita. Nasib baik, Three.js mempunyai beberapa fungsi pembantu untuk mencipta primitif (bentuk mudah): #🎜🎜#
var skyboxGeometry = new THREE.CubeGeometry(10000, 10000, 10000);
var skyboxMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, side: THREE.BackSide });
var skybox = new THREE.Mesh(skyboxGeometry, skyboxMaterial);

scene.add(skybox);
#🎜🎜#Seperti yang anda lihat, mula-mula kita cipta geometri. Parameter menentukan saiz kubus: lebar, tinggi dan kedalaman. #🎜🎜# #🎜🎜#Seterusnya, kami menentukan bahan kiub. Terdapat beberapa jenis bahan dalam Three.js, tetapi kali ini kami akan menggunakan THREE.MeshLambertMaterial kerana kami akan mahukan sedikit pencahayaan kemudian (bahan tersebut menggunakan algoritma Lambert untuk pengiraan pencahayaan). Anda boleh lulus pilihan dalam hujah pertama sebagai peta, sama seperti untuk pemapar - ini adalah peraturan untuk objek yang lebih kompleks dalam Three.js. Di sini kita hanya menggunakan warna, yang diluluskan sebagai nombor perenambelasan. #🎜🎜# #🎜🎜#Dalam baris ketiga, kami mencipta jaringan menggunakan geometri dan bahan yang dibuat sebelum ini. Seterusnya, kami memutarkan kubus 45 darjah pada paksi Y untuk menjadikannya kelihatan lebih baik. Kita perlu menukar darjah kepada radian, yang dikendalikan melalui persamaan yang mungkin anda ingat dari kelas fizik sekolah menengah: Math.PI * 45 / 180. Akhirnya, kiub itu ditambah ke tempat kejadian. #🎜🎜# #🎜🎜#Kini anda boleh membuka index.html dalam penyemak imbas anda untuk melihat hasilnya, tetapi anda tidak akan melihat apa-apa kerana adegan itu belum dipaparkan lagi. #🎜🎜# #🎜🎜# #🎜🎜# #🎜🎜#Langkah 4: #🎜🎜# Kamera! #🎜🎜# #🎜🎜#Untuk memaparkan sesuatu, mula-mula kita perlu menambahkan kamera pada adegan supaya pemapar tahu dari sudut mana kandungan itu harus dipaparkan. Terdapat beberapa jenis kamera dalam Three.js, tetapi anda mungkin hanya akan menggunakan THREE.PerspectiveCamera. Kamera jenis ini membentangkan pemandangan dunia seperti yang kita lihat. Mari buat satu: #🎜🎜#
var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 10000);

“要渲染某些内容,首先我们需要将相机添加到场景中,以便渲染器知道应该从哪个角度渲染内容。”

创建相机比我们迄今为止所做的其他事情要复杂一些。第一个参数定义 FOV(视野),即从相机所在位置可以看到的角度。 45 度的 FOV 看起来很自然。接下来,我们定义相机的比率。这始终是渲染器的宽度除以高度,除非您想实现一些特殊效果。最后两个数字定义了对象与要绘制的相机的距离。

现在我们必须稍微向后和向上移动相机,因为在 Three.js 中创建的所有对象都将其位置设置在场景中间(x: 0, y: 0, z: 0)默认:

camera.position.y = 160;
camera.position.z = 400;

z 坐标在观看者的方向上为正,因此具有较高 z 位置的对象会显得离您更近(在这种情况下,由于我们移动了相机,所有对象都会显得更远)来自您)。

现在,让我们将相机添加到场景并渲染它:

scene.add(camera);

renderer.render(scene, camera);

添加相机就像添加立方体一样。下一行使用该相机渲染场景。现在您可以打开浏览器,您应该看到以下内容:

Pengenalan asas: Pembangunan WebGL dengan Three.js

您应该只能看到立方体的顶部。这是因为我们将相机向上移动,但它仍然看起来在它的正前方。这个问题可以通过让相机知道它应该看什么位置来解决。在设置相机位置的行之后添加此行:

camera.lookAt(cube.position);

传入的唯一参数是相机将看到的位置。现在,场景看起来更好了,但立方体仍然是黑色,无论您在创建立方体时设置了什么颜色:

Pengenalan asas: Pembangunan WebGL dengan Three.js


第 5 步: 灯!

立方体是黑色的,因为场景中没有灯光,所以它就像一个完全黑的房间。您会看到白色背景,因为除了立方体之外没有任何东西可以绘制。为了避免这种情况,我们将使用一种称为天空盒的技术。基本上,我们将添加一个大立方体来显示场景的背景(如果是开放空间,通常是一些远处的地形)。那么,让我们创建这个盒子。此代码应位于 renderer.render 调用之前:

var skyboxGeometry = new THREE.CubeGeometry(10000, 10000, 10000);
var skyboxMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, side: THREE.BackSide });
var skybox = new THREE.Mesh(skyboxGeometry, skyboxMaterial);

scene.add(skybox);

此代码与创建多维数据集的代码类似。但这一次的几​​何形状要大得多。我们还使用了 THREE.MeshBasicMaterial 因为我们不需要照亮天空盒。另外,请注意传递给材料的附加参数:side: THREE.BackSide。由于立方体将从内部显示,因此我们必须更改绘制的侧面(通常,Three.js 只绘制外墙)。

现在渲染的场景是全黑的。为了解决这个问题,我们必须向场景添加灯光。我们将使用 THREE.PointLight,它像灯泡一样发出光。在天空盒后添加这些行:

var pointLight = new THREE.PointLight(0xffffff);
pointLight.position.set(0, 300, 200);

scene.add(pointLight);

如您所见,我们创建了白色的点光源,然后将其位置设置为向上和向后一点,以照亮立方体的正面和顶部。最后,灯光像任何其他对象一样添加到场景中。打开浏览器,您应该会看到一个彩色阴影立方体:

Pengenalan asas: Pembangunan WebGL dengan Three.js

但是立方体仍然很无聊。让我们为其添加一些动作。


第 6 步: 行动!

现在我们将为场景添加一些运动。让我们让立方体绕 Y 轴旋转。但首先,我们必须改变渲染场景的方式。一次 renderer.render 调用,渲染场景的当前状态一次。因此,即使我们以某种方式为立方体设置动画,我们也不会看到它移动。要改变这一点,我们必须将渲染循环添加到我们的应用程序中。这可以使用专门为此目的创建的 renderAnimationFrame 函数来实现。大多数主要浏览器都支持它,对于那些不支持它的浏览器,Three.js 附带了自己的 polyfill。那么,让我们改变一下:

renderer.render(scene, camera);

对此:

function render() {
	renderer.render(scene, camera);
	
	requestAnimationFrame(render);
}

render();

实际上,那里没有循环,因为它会冻结浏览器。 requestAnimationFrame 函数的行为有点像 setTimeout,但它会在浏览器准备就绪时调用该函数。因此,显示的场景没有任何变化,立方体仍然没有移动。让我们解决这个问题。 Three.js自带了THREE.Clock,可以用来实现对象的平滑动画。首先在render函数定义之前进行初始化:

var clock = new THREE.Clock;

现在,每次调用 clock.getDelta 时,它都会返回自上次调用以来的时间(以毫秒为单位)。这可以用来旋转立方体,如下所示:

cube.rotation.y -= clock.getDelta();

render 函数中的 renderer.renderrequestAnimationFrame 调用之间添加此行。它只是减去立方体在 Y 轴上旋转所花费的时间(记住它以弧度为单位)来顺时针旋转立方体。现在打开浏览器,您应该看到立方体顺时针平稳旋转。


结论

在本系列的这一部分中,您学习了如何准备场景、添加对象和灯光以及如何为事物设置动画。您可以尝试该应用程序,添加更多或不同的对象、灯光。由你决定。下次我将向您展示如何使用纹理以及如何使用粒子创建一些漂亮的效果。如果遇到任何问题,请不要忘记查看文档。

Atas ialah kandungan terperinci Pengenalan asas: Pembangunan WebGL dengan Three.js. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn