如何用三分钟写一个3D地球云层效果?
答案是Threejs
在这篇文章中,我们将学习如何用JavaScript和Three.js创建一个带有云层的地球模型。我们将使用Three.js来创建3D场景、模型和动画效果。下面是如何实现这个效果的代码:
引入Three.js
首先,我们需要引入Three.js库。在这个例子中,我们使用了ES6的模块导入方式。
javascript
import * as THREE from './three.module.js';
创建地球和云层
定义一个函数createSphereMeshcloud
来创建一个带有云层纹理的球体模型。我们使用THREE.TextureLoader
加载云层的纹理图片,并将其作为材质的贴图。我们还将材质的透明度设置为0.8,以便看到地球表面的纹理。接下来,我们定义一个函数createSphereMesh
来创建一个带有地球纹理的球体模型。我们使用THREE.TextureLoader
加载地球的纹理图片,并将其作为材质的贴图。
javascript
function createSphereMesh(R) {
let textureLoader = new THREE.TextureLoader();
let texture = textureLoader.load('earth.jpg');
let geometry = new THREE.SphereBufferGeometry(R, 40, 40);
let material = new THREE.MeshLambertMaterial({
map: texture,
});
let mesh = new THREE.Mesh(geometry, material);
return mesh
}
function createSphereMeshcloud(R) {
let textureLoader = new THREE.TextureLoader();
let texture = textureLoader.load('earthclouds1k.png');
let geometry = new THREE.SphereBufferGeometry(R, 40, 40);
let material = new THREE.MeshLambertMaterial({
map: texture,
transparent: true,
opacity: 0.8,
});
let mesh = new THREE.Mesh(geometry, material);
return mesh
}
在createSphereMesh()
函数中,我们使用THREE.TextureLoader
加载了地球的纹理图片,并将其作为材质的贴图。THREE.SphereBufferGeometry
则用于创建一个球体模型,参数R
为球体的半径,40
和40
分别为水平和垂直方向的细分数,用于控制球体的面数。最后,我们将球体模型和材质对象传递给THREE.Mesh
构造函数,来创建一个球体网格模型。
在createSphereMeshcloud()
函数中,我们使用THREE.TextureLoader
加载了云层的纹理图片,并将其作为材质的贴图。我们还将材质的透明度设置为0.8,以便看到地球表面的纹理。其他部分和createSphereMesh()
函数类似。
javascript
let R = 100;//地球半径
let earth = createSphereMesh(R);// 创建地球mesh
let R2 = 120;//云层半径
let cloud = createSphereMeshcloud(R2);// 创建云层
创建场景
创建一个Three.js场景,将创建好的地球和云层网格模型添加到Three.js场景中。
javascript
let scene = new THREE.Scene();
scene.add(earth);
scene.add(cloud);
定义光源
定义了三个光源:两个平行光和一个环境光。这些光源将照亮地球和云层,使其看起来更加逼真。
javascript
// 光源设置
// 平行光1
let directionalLight = new THREE.DirectionalLight(0xffffff, 0.6);
directionalLight.position.set(400, 200, 300);
scene.add(directionalLight);
// 平行光2
let directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.6);
directionalLight2.position.set(-400, -200, -300);
scene.add(directionalLight2);
// 环境光
let ambient = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambient);
创建相机
创建了一个相机对象,并将其放置在场景中。使用正交投影相机。正交投影相机适合渲染2D图像,因为它不会出现透视效果。
javascript
let width = window.innerWidth; //窗口文档显示区的宽度
let height = window.innerHeight; //窗口文档显示区的高度
let k = width / height;
let s = 150;
let camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(100, 0, 100);
camera.lookAt(0, 0, 0);
在创建好场景和相机之后,我们创建一个Three.js渲染器对象,并将其添加到HTML文档中。并开启了锯齿和背景透明。
javascript
// 创建渲染器对象
let renderer = new THREE.WebGLRenderer({
antialias: true, //开启锯齿
alpha: true //开启背景透明
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height); //设置渲染区域尺寸
renderer.setClearColor(0xb9d3ff, 0); //设置背景颜色
document.body.appendChild(renderer.domElement);
开启渲染
置了一个渲染循环,使地球和云层可以旋转,并通过渲染器对象将场景和相机渲染到屏幕上。
javascript
// 渲染循环
function render() {
earth.rotateY(-0.004);//地球绕y轴旋转动画
cloud.rotateY(-0.001);//云层绕y轴旋转动画
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
自适应窗口
最后,我们通过添加一个事件监听器来响应窗口大小的变化,并更新相机和渲染器的尺寸。
javascript
window.addEventListener('resize', function() {
let width = window.innerWidth; //窗口文档显示区的宽度
let height = window.innerHeight; //窗口文档显示区的高度
let k = width / height;
let s = 150;
camera.left = -s * k;
camera.right = s * k;
camera.top = s;
camera.bottom = -s;
camera.updateProjectionMatrix();
renderer.setSize(width, height); //设置渲染区域尺寸
})
三分钟时间到,看效果。恩,透明度好像有点小问题,先不管了,抽根烟再说。

