• 作者:老汪软件技巧
  • 发表时间:2024-12-28 21:07
  • 浏览量:

你还在为平面而感到没有视觉效果吗?

下面将手把手建立一个3D立体地球,实现自转;那个进行鼠标拖拽以及窗口调整。

直入主题,先想清楚要怎么利用three.js进行搭建

一、制作思路

从拍照视角:在构建一个引人入胜的3D地球展示时,我们首先需要搭建好舞台。这个“舞台”由三个主要元素构成:场景(scene)、相机(camera)和渲染器(renderer)。场景是所有3D对象的容器;相机决定了从哪个视角观察这些对象;而渲染器则负责将整个3D世界转化为2D图像呈现在屏幕上。

从角色视角:为了确保我们的主角——3D地球(earth)能够以最佳状态展现给观众,我们不仅需要精心设置其几何形状和材质,还可能要添加光源(light)来照亮它,以及实现交互功能,比如让地球自转或通过鼠标拖拽来改变视角。这一切都将在createEarth函数中得以实现,该函数负责创建并配置地球模型。

二、使用Three.js进行构建

要在网页上嵌入3D内容,我们需要引入Three.js库。这是通过在HTML文档的头部加入如下脚本来完成的:

<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js">script>

三、实例代码解析1. 初始化场景、相机与光源

初始化是构建3D应用的第一步。在这里,我们将设置场景的背景颜色为白色,并创建一个透视相机,它模拟了人类视觉的效果,使得近大远小。同时,我们还需要设置一个WebGL渲染器,并将其尺寸调整为与浏览器窗口匹配。为了让地球看起来更真实,我们还添加了一个方向光,它模仿太阳光,照亮了整个场景。(细心吧~~)

function init() {
    // 创建场景并设定背景色
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff); // 白色背景
    // 创建透视相机
    const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
    camera.position.z = 500; // 设置相机位置
    // 创建WebGL渲染器
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    // 添加地球到场景
    createEarth(scene);
    // 添加方向光源
    const light = new THREE.DirectionalLight(0xffffff, 1);
    light.position.set(500, 500, 500).normalize();
    scene.add(light);
    // 监听窗口大小变化
    window.addEventListener('resize', () => onWindowResize(camera, renderer), false);
    // 鼠标事件监听
    document.addEventListener('mousemove', (event) => onMouseMove(event, camera), false);
}

监听窗口和鼠标点击事件,后文给出代码

2. 构建地球模型

地球模型的创建依赖于加载外部的纹理图片,这可以通过Three.js提供的TextureLoader来完成。我们将纹理应用到球体几何体上,从而形成一个逼真的地球表面。此外,我们还设置了材质的高光属性,以增强视觉效果。

function createEarth(scene) {
    const loader = new THREE.TextureLoader();
    loader.load('./earth.jpg', (texture) => {
        const geometry = new THREE.SphereGeometry(200, 32, 32); // 增加细分段数提高质量
        const material = new THREE.MeshPhongMaterial({
            map: texture,
            shininess: 50 // 提高高光强度
        });
        const earth = new THREE.Mesh(geometry, material);
        scene.add(earth);
    });
}

平面图,需要放到地球模型框架形成3D。有需要自取:

image.png

3. 窗口大小调整处理

当用户调整浏览器窗口大小时,我们希望3D场景能够自动适应新的尺寸。为此,我们定义了一个onWindowResize函数,它会更新相机的宽高比和投影矩阵,并调整渲染器的大小。

 function onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();// 更新相机投影矩阵
    renderer.setSize(window.innerWidth, window.innerHeight);
}

4. 鼠标交互

为了让用户体验更加生动,我们实现了基于鼠标的交互功能。通过捕捉鼠标移动事件,我们可以平滑地调整相机的位置,从而让用户从不同角度观察地球。

function onMouseMove(event) {
    mouseX = (event.clientX - windowHalfX)/10;
    //使鼠标在窗口中心时 mouseY 的值为0,向上移动时为负值,向下移动时为正值。
    mouseY = (event.clientX - windowHalfX)/10;// y 一半
}

image.png

5. 动画效果

为了让地球“活”起来,我们需要创建动画循环。Three.js提供了requestAnimationFrame方法,它可以确保动画以每秒60帧的速度流畅播放。在这个循环中,我们会调用render函数来更新场景和相机的状态,并最终将它们渲染到屏幕上。

function animate() {
    // 加载动画帧 60桢/s
    requestAnimationFrame(animate);
    render();
}
function render() {
    camera.position.x +=(mouseX-camera.position.x )* 0.05;
    camera.position.y +=(mouseX-camera.position.x )* 0.05;
    camera.lookAt(scene.position); // 相机看向场景
    // 旋转地球
    if (earth) {
        earth.rotation.y -= 0.005;
    }
    // 渲染场景
    renderer.render(scene, camera);
}
// 启动动画
init();
animate();

下面再看看效果

完整代码

快去试一下吧,下面有进行注释解释代码

html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D 411title>
    <style>
        body { margin: 0; }

平面视觉化__平面效果是什么意思

canvas { display: block; }
style> <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js">script> head> <body> <script> 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() { // 创建场景 scene = new THREE.Scene(); scene.background = new THREE.Color(0xffffff); // 白色背景 group = new THREE.Group();// 组 scene.add(group); // 创建相机 camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000); camera.position.z = 500; // 创建渲染器并添加到DOM renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 添加地球 createEarth(); // 添加光源 const light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(500, 500, 500).normalize(); scene.add(light); // 监听窗口大小改变 window.addEventListener('resize', onWindowResize, false); // 鼠标 document.addEventListener('mousemove', onMouseMove, false); } function onMouseMove(event) { mouseX = (event.clientX - windowHalfX)/10; //使鼠标在窗口中心时 mouseY 的值为0,向上移动时为负值,向下移动时为正值。 mouseY = (event.clientX - windowHalfX)/10;// y 一半 } function createEarth() { // 加载地球纹理 const loader = new THREE.TextureLoader(); // 加载指定的纹理图像,并在加载完成后执行回调函数 loader.load('./earch.jpg', function (texture) { // 创建地球几何体和材质 const geometry = new THREE.SphereGeometry(200, 20,20); const material = new THREE.MeshPhongMaterial({ map: texture, // 漫反射贴图 shininess: 10 // 高光 }); // 创建地球网格并添加到场景中 earth = new THREE.Mesh(geometry, material); group.add(earth); }); } function onWindowResize() { windowHalfX = window.innerWidth / 2; windowHalfY = window.innerHeight / 2; camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix();// 更新相机投影矩阵 renderer.setSize(window.innerWidth, window.innerHeight); } function animate() { // 加载动画帧 60桢/s requestAnimationFrame(animate); render(); } function render() { camera.position.x +=(mouseX-camera.position.x )* 0.05; camera.position.y +=(mouseX-camera.position.x )* 0.05; camera.lookAt(scene.position); // 相机看向场景 // 旋转地球 if (earth) { earth.rotation.y -= 0.005; } // 渲染场景 renderer.render(scene, camera); } script> body> html>