一、THREE.js简介
Three.js是一个基于WebGL的开源JavaScript库,由Ricardo Cabello(也称为Mr.doob)于2010年创建。 在Three.js中,创建3D场景通常涉及以下几个核心组件:
-
场景(Scene):是所有3D对象的容器,可以将其想象成一个虚拟的3D空间,所有的3D对象、光源等都放置在这个空间中。
-
相机(Camera):定义了观察场景的视角。Three.js提供了多种相机类型,最常用的是透视相机(PerspectiveCamera)和正交相机(OrthographicCamera)。
-
渲染器(Renderer):负责将场景和相机中的内容渲染到屏幕上。Three.js支持多种渲染器,包括WebGL渲染器、Canvas渲染器和SVG渲染器。其中,WebGL渲染器是Three.js的主要渲染器,支持硬件加速的3D图形渲染。
-
几何体(Geometry):定义了3D对象的形状。Three.js提供了多种内置几何体,如立方体(BoxGeometry)、球体(SphereGeometry)等。
-
材质(Material):定义了3D对象的外观,包括颜色、纹理等。Three.js提供了多种内置材质,如基础材质(MeshBasicMaterial)、标准材质(MeshStandardMaterial)等。
-
网格(Mesh):是几何体和材质的组合,表示一个具体的3D对象。
二、话不多说先上效果图,防止老铁提前划走(文末有源码)
三项目实现
创建html文件,在head标签部分引入Three.js库
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D 地球</title>
<!-- 画地球 选择框架 加速 -->引入three.js
<script src="https://unpkg.com/three@0.128.0/build/three.min.js"></script>
</head>
body部分
<canvas id="webglcanvas"></canvas>
<script>
// 3d 地球
// 3D 时间就是镜头拍出的世界,导演
let canvas, // 3d 容器
camera, // 镜头
scene, // 场景
renderer, // 渲染器
group; // 组
// 物品
let mouseX = 0, mouseY = 0; // mousemove 坐标
let windowHalfX = window.innerWidth / 2; // 球心
let windowHalfY = window.innerHeight / 2;
全局变量声明:
- `canvas`: 用于渲染3D场景的`<canvas>`元素。
- `camera`: 定义场景的透视相机。
- `scene`: 存储3D场景中的所有对象。
- `renderer`: 用于渲染场景的渲染器。
- `group`: 用于组织和管理场景中的对象。
- `mouseX` 和 `mouseY`: 存储鼠标的当前位置。
- `windowHalfX` 和 `windowHalfY`: 存储窗口宽度和高度的一半。
核心组件(场景,相机,渲染器,几何体,材质,网格)建造
<body>
<canvas id="webglcanvas"></canvas>
<script>
// 3D 地球
// 3D 世界就是镜头拍出的世界,导演
let canvas, // 3D 容器
camera,// 镜头
scene,// 场景
renderer,// 渲染器
group;// 组
// 物品
let mouseX = 0,mouseY = 0;// mousemove 坐标
let windowHalfX = window.innerWidth / 2; // 球心
let windowHalfY = window.innerHeight / 2;// 球心
// 初始化
init ();
// 准备
function init(){
canvas = document.getElementById('webglcanvas');// DOM
camera = new THREE.PerspectiveCamera(60,
window.innerWidth / window.innerHeight,1,2000);// 实例化 相机
// 相机离scene场景的距离
camera.position.z = 500;
scene = new THREE.Scene();// 实例化 场景
scene.background = new THREE.Color(0xffffff);// 背景颜色
group = new THREE.Group();// 组
scene.add(group);// 场景添加组
// 纹理加载器
let loader = new THREE.TextureLoader();// 简单的加载器
loader.load('land_ocean_ice_cloud_2048.jpg',function(texture){
let geometry = new THREE.SphereGeometry(200,20,20);// 球体形状
let material = new THREE.MeshBasicMaterial({map:texture});// 材质
let mesh = new THREE.Mesh(geometry,material);// 网格
group.add(mesh);// 组添加网格
// 渲染器 目标是canvas
renderer = new THREE.WebGLRenderer({
canvas:canvas,
antialias:true
});
renderer.setSize(window.innerWidth,window.innerHeight);
});
}
</script>
</body>
-
场景 (
scene
) :- 使用
new THREE.Scene()
创建了一个新的场景实例,并将其赋值给变量scene
。 - 设置了场景的背景颜色为白色 (
new THREE.Color(0xffffff)
)。
- 使用
-
相机 (
camera
) :- 使用
new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000)
创建了一个透视相机实例,并将其赋值给变量camera
。 - 设置了相机的视角为60度,宽高比为窗口的宽高比,近裁剪面为1,远裁剪面为2000。
- 将相机的位置设置在Z轴上500的位置 (
camera.position.z = 500
)。
- 使用
-
渲染器 (
renderer
) :- 使用
new THREE.WebGLRenderer({ canvas: canvas, antialias: true })
创建了一个WebGL渲染器实例,并将其赋值给变量renderer
。 - 将渲染器的目标设置为
<canvas>
元素 (canvas: canvas
)。 - 启用抗锯齿 (
antialias: true
) 以提高渲染质量。 - 设置渲染器的大小为窗口的宽度和高度 (
renderer.setSize(window.innerWidth, window.innerHeight)
)。
- 使用
-
几何体 (
geometry
) :- 使用
new THREE.SphereGeometry(200, 20, 20)
创建了一个球体几何体实例,并将其赋值给变量geometry
。 - 球体的半径为200,水平和垂直分段数均为20。
- 使用
-
材质 (
material
) :- 使用
new THREE.MeshBasicMaterial({ map: texture })
创建了一个基础材质实例,并将其赋值给变量material
。 - 材质使用了加载的纹理 (
map: texture
)。texture
是加载的land_ocean_ice_cloud_2048.jpg
图片的纹理对象。 (需要自娶)
- 使用
-
网格 (
mesh
) :- 使用
new THREE.Mesh(geometry, material)
将几何体和材质组合成一个网格实例,并将其赋值给变量mesh
。`
- 使用
实例化场景scene处可以注释背景颜色,放一张背景图,效果更佳
scene = new THREE.Scene();// 实例化 场景
//scene.background = new THREE.Color(0xffffff);// 背景颜色(注释掉)
// 设置背景图片
let loader1 = new THREE.TextureLoader();
loader1.load('你的图片地址', function(texture) {
scene.background = texture;
});
本例背景图(需要自娶)
动画效果实现
function render() {
// 更新相机的位置
camera.position.x += (mouseX - camera.position.x) * 0.05;
camera.position.y += (-mouseY - camera.position.y) * 0.05;
// 使相机始终看向场景的中心
camera.lookAt(scene.position);
// 旋转场景中的组
group.rotation.y += 0.005;
// 渲染场景
renderer.render(scene, camera);
}
// 定义animate函数,用于创建动画循环
function animate() {
// 使用requestAnimationFrame方法递归调用animate函数,实现动画循环
requestAnimationFrame(animate);
// 调用render函数,更新场景并渲染到屏幕上
render();
}
平滑效果实现
// 添加鼠标移动事件监听器,当鼠标移动时调用 onDocumentMouseMove 函数
document.addEventListener('mousemove', onDocumentMouseMove, false);
})
/**
* 处理鼠标移动事件的函数
* @param {MouseEvent} event - 鼠标移动事件对象
*/
function onDocumentMouseMove(event) {
// 计算鼠标相对于窗口中心的水平偏移量
mouseX = (event.clientX - windowHalfX);
// 计算鼠标相对于窗口中心的垂直偏移量
mouseY = (event.clientY - windowHalfY);
}
// 结束当前作用域
}
/**
* 动画循环函数,用于更新和渲染场景
*/
function animate() {
// 使用 requestAnimationFrame 递归调用 animate 函数,实现平滑的动画效果
requestAnimationFrame(animate);
// 调用 render 函数,更新场景并渲染到屏幕上
render();
}
防止有的小伙伴不理解,直接上源码,先去实现再慢慢理解
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D 地球</title>
<!-- 画地球 选择框架 加速 -->
<script src="https://unpkg.com/three@0.128.0/build/three.min.js"></script>
</head>
<body>
<canvas id="webglcanvas"></canvas>
<script>
// 3d 地球
// 3D 时间就是镜头拍出的世界,导演
let canvas, // 3d 容器
camera, // 镜头
scene, // 场景
renderer, // 渲染器
group; // 组
// 物品
let mouseX = 0, mouseY = 0; // mousemove 坐标
let windowHalfX = window.innerWidth / 2; // 球心
let windowHalfY = window.innerHeight / 2;
init();
animate();
// 准备
function init() {
canvas = document.getElementById('webglcanvas'); // DOM
camera = new THREE.PerspectiveCamera(60,
window.innerWidth / window.innerHeight, 1, 2000); // 实例化 相机
// 相机离scene场景
camera.position.z = 500;
scene = new THREE.Scene(); // 实例化 场景
// 设置背景图片
let loader1 = new THREE.TextureLoader();
loader1.load('UFO.png', function(texture) {
scene.background = texture;
});
group = new THREE.Group();// 组
scene.add(group);
// 纹理加载器
let loader = new THREE.TextureLoader(); // 简单的加载器
loader.load('land_ocean_ice_cloud_2048.jpg', function(texture) {
let geometry = new THREE.SphereGeometry(200, 20, 20); // 球体
let material = new THREE.MeshBasicMaterial({ // 材质
map: texture
});
let mesh = new THREE.Mesh(geometry, material); // 网格
group.add( mesh );
// 渲染器 目标是canvas
renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
// renderer.render(scene, camera);
document.addEventListener('mousemove',onDocumentMouseMove,false)
})
function onDocumentMouseMove(event) {
mouseX = (event.clientX - windowHalfX) ;
mouseY = (event.clientY - windowHalfY) ;
}
}
function animate() {
// 递归 屏幕的刷帧率 60帧/s
requestAnimationFrame(animate);
render()
}
function render () {
camera.position.x += (mouseX - camera.position.x)*0.05;
camera.position.y += (-mouseY - camera.position.y)*0.05;
camera.lookAt(scene.position);
// camera.lokAt(scene.position)
group.rotation.y += 0.005;
renderer.render(scene, camera);
}
</script>
</body>
</html>
注意
36行代码处,背景图片,要放入你的图片文件名,我这里是UFO.png
let loader1 = new THREE.TextureLoader();
loader1.load('UFO.png', function(texture) {
scene.background = texture;
});
46行代码处,加载纹理,同样放入你的图片文件名,我这里是land_ocean_ice_cloud_2048.jpg
loader.load('land_ocean_ice_cloud_2048.jpg', function(texture) {
let geometry = new THREE.SphereGeometry(200, 20, 20); // 球体
let material = new THREE.MeshBasicMaterial({ // 材质
map: texture
});
图片和erath.html文件同处于一个文件夹。
觉得还行就给个免费的赞吧