天空盒通常用于视频游戏中,以创建遥远的三维背景的错觉。天空盒本质上是一个立方体,立方体的每一侧都有纹理。然后将播放器或摄像机放置在立方体中,以便所有六个纹理都围绕它们,使它们产生它们处于更大环境中的错觉。
Three.js设置
首先,我们将调用来初始化 Three.js。我们将使用一个透视摄像机,其位置缩小得很远,这样我们就可以在跳入之前看到盒子。我们将使用一个 PerspectiveCamera,其位置被缩小了很多,这样我们可以在跳入之前看到该框。我们还将使用 并将其附加到页面主体。最后,该函数将使用我们添加的任何更新处理重新渲染场景.
let scene, camera, renderer, skyboxGeo, skybox;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(
55,
window.innerWidth / window.innerHeight,
45,
30000
);
camera.position.set(1200, -250, 20000);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.domElement.id = “canvas”;
document.body.appendChild(renderer.domElement);
animate();
}
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
init();
导入核心 Three.js 库。
<script src=”https://threejs.org/build/three.min.js”></script>
将主体高度设置为视口高度,并为主体添加灰色背景,以便我们可以看到立方体。
body {
margin: 0;
height: 100vh;
background: #bdc3c7;
}
由于我们还没有添加任何对象,我们现在只会看到灰色背景。
添加 Three.js 盒。 我们可以添加一个带有 、 和设置为 的盒。然后使用对其应用纹理,在这种情况下,它将默认为纯纹理。最后,在函数内调用函数之前将对象添加到场景中。
function init() {
…
skyboxGeo = new THREE.BoxGeometry(10000, 10000, 10000);
skybox = new THREE.Mesh(skyboxGeo);
scene.add(skybox);
animate();
尽管它是一个立方体,但它看起来像一个正方形,因为我们直接观察它。为了验证它是一个立方体,我们可以在函数中添加一个旋转动画:animate
function animate() {
skybox.rotation.x += 0.005;
skybox.rotation.y += 0.005;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
天空盒网格材质
您可以在 opengameart.org 上找到免费的天空盒图像,或者您可以在 Google 上搜索“免费天空盒图像”。应该有六个图像对应于无缝啮合在一起的立方体的每一面。例如,对于 React Native Infinity,六个空间图像对应于不同的边,如下所示。
每张图片要根据对应的边来命名,比如是前图,是右图,是底图。我们需要按照三个步骤将这些图像添加到我们的立方体中:.purplenebula_ft.pngpurplenebula_rt.pngpurplenebula_dn.png
将每个图像加载为纹理
将每个纹理映射到材质数组
将 Material 数组添加到 Skybox 立方体
1.加载图像作为纹理
可以使用函数在 Three.js 中加载纹理。该方法将图像的路径作为参数。我们可以通过创建六个函数来加载每个图像,如下所示:TextureLoader().load()load()TextureLoader()
const ft = new THREE.TextureLoader().load(“purplenebula_ft.jpg”);
const bk = new THREE.TextureLoader().load(“purplenebula_bk.jpg”);
const up = new THREE.TextureLoader().load(“purplenebula_up.jpg”);
const dn = new THREE.TextureLoader().load(“purplenebula_dn.jpg”);
const rt = new THREE.TextureLoader().load(“purplenebula_rt.jpg”);
const lf = new THREE.TextureLoader().load(“purplenebula_lf.jpg”);
但是最好创建一个可重用的函数,为我们循环遍历所有图像。创建一个函数,该函数将从文件图像名称 .createPathStrings()filename 创建路径字符串数组
function createPathStrings(filename) {
const basePath = “./static/skybox/”;
const baseFilename = basePath + filename;
const fileType = “.png”;
const sides = [“ft”, “bk”, “up”, “dn”, “rt”, “lf”];
const pathStings = sides.map(side => {
return baseFilename + “_” + side + fileType;
});
return pathStings;
}
这应该创建一个字符串数组来表示每个图像的路径:
[‘./static/skybox/purplenebula_ft.jpg’, ‘./static/skybox/purplenebula_bk.jpg’, …]
接下来,通过在上面的数组上映射来加载每个纹理。让我们创建另一个函数 ,以生成一个新的加载纹理数组。我们还将参数传入函数.TextureLoader().load()createMaterialArray()filenamecreatePathStrings
let skyboxImage = “purplenebula”;
function createMaterialArray(filename) {
const skyboxImagepaths = createPathStrings(filename);
const materialArray = skyboxImagepaths.map(image => {
let texture = new THREE.TextureLoader().load(image);
return texture;
});
return materialArray;
}
2.将每个Texture映射到一个Mesh数组 Three.js 方法将允许我们将上面的纹理映射到 Three.js 材质。我们可以简单地修改函数以返回 Three.js 材质而不是加载的纹理,而不是创建另一个函数来执行此操作。MeshBasicMaterial()createMaterialArray()
function createMaterialArray(filename) {
const skyboxImagepaths = createPathStrings(filename);
const materialArray = skyboxImagepaths.map(image => {
let texture = new THREE.TextureLoader().load(image);
return new THREE.MeshBasicMaterial({ map: texture, side: THREE.BackSide }); // <—
});
return materialArray;
}
3.在Skybox立方体中添加Mesh阵列 我们终于准备好将我们的网格数组添加到我们上面创建的立方体中。首先,使用基本文件名创建一个变量 。将该变量传递到 以生成我们的网格数组。最后,将该数组传递给函数的第二个参数。skyboxImagecreateMaterialArraynew Three.Mesh()
const skyboxImage = ‘purplenebula’;
function init() {
…
const materialArray = createMaterialArray(skyboxImage);
skyboxGeo = new THREE.BoxGeometry(10000, 10000, 10000);
skybox = new THREE.Mesh(skyboxGeo, materialArray);
scene.add(skybox);
animate();
}
我们的立方体现在应该有网格阵列
将相机放在立方体中 我们可以将 的位置从 更改为将相机放在立方体中。camera z 20000 2000
function init()
…
camera.position.set(1200, -250, 2000);
…
}
轨道控制 虽然上面的方法可以让我们进入立方体,但如果可以用鼠标控制相机并环顾四周会更好。 Three.js 的 Orbit Controls 包允许我们添加标签 import:script
<script src=”https://threejs.org/build/three.min.js”></script>
<script src=”https://threejs.org/examples/js/controls/OrbitControls.js”></script>