当前位置: 首页 > news >正文

使用 Three.js 创建圣诞树场景

今天带大家一起实现一个圣诞树,先看下效果

请添加图片描述

一、导入模块并初始化 Three.js 场景

1. 创建场景

创建场景的目的是构建 3D 空间的容器,用于承载各种 3D 对象和光源。

const scene = new THREE.Scene();

2. 创建相机

创建相机用于定义观察视角,我们使用透视相机(PerspectiveCamera),它能模拟人眼观察场景的效果。

  • 参数含义:
    • 75:视角大小,决定相机的视野范围。
    • window.innerWidth / window.innerHeight:宽高比,保证画面比例正常。
    • 0.11000:近裁剪面和远裁剪面,控制相机可见范围。
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
);

3. 创建渲染器

渲染器用于将 3D 场景绘制到屏幕上。我们选择 WebGLRenderer 并启用抗锯齿功能以优化图形效果。

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);

4. 将渲染器插入到 HTML 页面

将渲染器生成的 <canvas> 元素添加到页面的 #app 容器中,以便显示 3D 场景。

document.getElementById("app").appendChild(renderer.domElement);

完整代码

import * as THREE from "three";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("app").appendChild(renderer.domElement);

二、添加交互控件

为场景添加 OrbitControls 控件,方便用户通过鼠标交互操作场景。

1. 引入 OrbitControls

我们需要从 Three.js 的扩展模块中导入 OrbitControls。

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

2. 初始化控件

OrbitControls 用于添加鼠标交互功能,让用户可以旋转、缩放和拖动场景。

const controls = new OrbitControls(camera, renderer.domElement);

3. 启用惯性效果

为了让交互更加自然,我们启用惯性功能,并设置阻尼系数。

controls.enableDamping = true; // 开启惯性
controls.dampingFactor = 0.05; // 设置惯性阻尼系数

4. 设置初始相机位置

为便于观察场景,设置相机位置为 (0, 5, 10),稍微抬高视角。

camera.position.set(0, 5, 10);
controls.update();

三、创建圣诞树

在这一部分,我们将详细讲解如何创建圣诞树,包括树干、树叶以及装饰的实现过程。

1. 创建树干

  1. 几何体创建
    • 使用 THREE.CylinderGeometry 创建一个圆柱体,表示树干的形状。
    • 圆柱体的底部半径为 0.5,顶部半径为 0.3,高度为 2.5,分段为 32
  2. 材质设置
    • 使用 THREE.MeshPhongMaterial,设置颜色为 0x8b4513(棕色)以模拟木材质感。
    • 增加光泽效果,设置 shininess20
  3. 位置调整
    • 设置 position.y = 1.25,将树干移动到地面以上。
const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.5, 2.5, 32);
const trunkMaterial = new THREE.MeshPhongMaterial({color: 0x8b4513,shininess: 20,
});
const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
trunk.position.y = 1.25;
treeGroup.add(trunk);

2. 创建树叶

在圣诞树中,树叶部分是通过多个圆锥体逐层堆叠实现的。这种设计方法既简单又直观,每一层的大小逐渐减小,高度逐渐增高,从而形成自然的树形结构。

实现思路
  1. 层级控制
    • 设置 levels = 5,生成 5 层树叶,每层逐渐变小且向上移动。
  2. 几何体创建
    • 使用 THREE.ConeGeometry 创建圆锥体,控制半径逐层递减。
  3. 材质设置
    • 使用 THREE.MeshPhongMaterial 设置绿色(0x228b22),并增加光泽。
  4. 位置调整
    • 每层的高度间隔为 1.1,确保层次分明且紧凑。
const levels = 5;
for (let i = 0; i < levels; i++) {const radius = 3 - i * 0.5;const height = 1.2;const coneGeometry = new THREE.ConeGeometry(radius, height, 32);const coneMaterial = new THREE.MeshPhongMaterial({color: 0x228b22,shininess: 30,});const cone = new THREE.Mesh(coneGeometry, coneMaterial);cone.position.y = 2.5 + i * 1.1;treeGroup.add(cone);
}

3. 添加装饰

为圣诞树添加装饰,比如彩球:

  1. 随机生成装饰球
    • 使用 Math.random() 控制彩球的大小、颜色和位置。
    • 设置彩球的数量为 35,大小范围为 0.08 ~ 0.2
  2. 材质优化
    • 彩球以随机颜色为主,设置 30% 的概率为金色(0xffd700)。
  3. 位置控制
    • 使用极坐标 Math.cos(angle)Math.sin(angle) 计算 xz 坐标。
    • 高度范围限定为 2.5 ~ 6.5
const decorationCount = 35;
for (let i = 0; i < decorationCount; i++) {const size = 0.08 + Math.random() * 0.12;const ballGeometry = new THREE.SphereGeometry(size, 32, 32);const ballMaterial = new THREE.MeshPhongMaterial({color: Math.random() < 0.7 ? Math.random() * 0xffffff : 0xffd700,shininess: 100,});const ball = new THREE.Mesh(ballGeometry, ballMaterial);const angle = Math.random() * Math.PI * 2;const radius = Math.random() * 2.2;const height = Math.random() * 4 + 2.5;ball.position.x = Math.cos(angle) * radius;ball.position.y = height;ball.position.z = Math.sin(angle) * radius;treeGroup.add(ball);
}

4. 添加彩带

通过曲线模拟彩带,为圣诞树增加装饰。

  1. 曲线生成

    • 使用 THREE.CatmullRomCurve3 创建一条随机曲线。
    • 曲线由三个随机控制点构成,起始点在树干顶部附近。
  2. 管道几何体

    • 使用 THREE.TubeGeometry 基于曲线生成管道形状,模拟彩带。
  3. 材质设置

    • 彩带材质为随机红色系(0xff0000),光泽度高。
const ribbonCount = 15;
for (let i = 0; i < ribbonCount; i++) {const curve = new THREE.CatmullRomCurve3([new THREE.Vector3(0, 2.5 + Math.random() * 3, 0),new THREE.Vector3(Math.random() * 2 - 1,2.5 + Math.random() * 3,Math.random() * 2 - 1),new THREE.Vector3(Math.random() * 3 - 1.5,2.5 + Math.random() * 3,Math.random() * 3 - 1.5),]);const ribbonGeometry = new THREE.TubeGeometry(curve, 20, 0.02, 8, false);const ribbonMaterial = new THREE.MeshPhongMaterial({color: Math.random() * 0xff0000,shininess: 80,});const ribbon = new THREE.Mesh(ribbonGeometry, ribbonMaterial);treeGroup.add(ribbon);
}

5. 添加礼物盒

在树底部放置礼物盒,提升整体氛围。

1. 创建礼物盒的容器:THREE.Group
`const giftGroup = new THREE.Group();`;
  • 每个礼物盒由一个 THREE.Group 组成,用来包含盒子和丝带。
  • 使用 THREE.Group 可以方便地对礼物盒整体设置位置和旋转角度。

2. 随机生成盒子的尺寸
const size = 0.4 + Math.random() * 0.3; // 宽度和深度:0.4 到 0.7
const height = 0.4 + Math.random() * 0.3; // 高度:0.4 到 0.7
  • 每个礼物盒的尺寸在一定范围内随机变化:
    • size 控制盒子的宽度和深度。
    • height 控制盒子的高度。
  • 这样可以避免所有盒子大小一致带来的单调感。

3. 创建盒子的几何形状和材质
const boxGeometry = new THREE.BoxGeometry(size, height, size);
const boxMaterial = new THREE.MeshPhongMaterial({color: Math.random() * 0xffffff, // 随机颜色shininess: 50, // 适中的光泽度
});
const box = new THREE.Mesh(boxGeometry, boxMaterial);
  • 使用 THREE.BoxGeometry 定义盒子的几何形状。
  • 使用 THREE.MeshPhongMaterial 定义盒子的材质:
    • 颜色是随机生成的 RGB 值。
    • 设置光泽度为 50,使盒子表面具有柔和的反光效果。

4. 生成丝带
水平丝带
const ribbonWidth = size * 0.1; // 丝带宽度是盒子宽度的 10%
const ribbonGeometry = new THREE.BoxGeometry(size, ribbonWidth, ribbonWidth);
const ribbonMaterial = new THREE.MeshPhongMaterial({color: 0xff0000, // 红色丝带shininess: 80, // 更高的光泽度
});
const ribbonH = new THREE.Mesh(ribbonGeometry, ribbonMaterial);
  • 水平丝带覆盖在盒子的顶部。
  • 宽度和盒子一样,但厚度很薄,确保比例适当。
垂直丝带
const ribbonV = new THREE.Mesh(new THREE.BoxGeometry(ribbonWidth, ribbonWidth, size),ribbonMaterial
);
  • 垂直丝带沿着盒子的深度方向包裹盒子。
  • 使用与水平丝带相同的材质,保持统一的红色和光泽效果。
将丝带与盒子组合
giftGroup.add(box, ribbonH, ribbonV);
  • 使用 giftGroup.add 方法将盒子和两条丝带加入到礼物盒组中,形成完整的礼物盒。

5. 设置礼物盒的位置和旋转
const angle = Math.random() * Math.PI * 2; // 随机角度
const radius = 1.5 + Math.random() * 1; // 距离中心点的半径
giftGroup.position.x = Math.cos(angle) * radius; // 计算 x 坐标
giftGroup.position.y = height / 2; // y 坐标为盒子高度的一半
giftGroup.position.z = Math.sin(angle) * radius; // 计算 z 坐标
giftGroup.rotation.y = Math.random() * Math.PI * 2; // 随机旋转角度
  • 位置设置:
    • 使用三角函数 Math.cosMath.sin 将礼物盒沿树底圆周随机分布。
    • radius 确定盒子到树中心的距离,使礼物盒分布在树的底部区域。
    • height / 2 确保盒子底部与地面接触。
  • 旋转设置:
    • 每个礼物盒的朝向通过 rotation.y 随机化,增加随机性。
6. 将礼物盒添加到圣诞树组
treeGroup.add(giftGroup);
  • 使用 treeGroup.add 将每个生成的礼物盒组添加到圣诞树的主组中。
  • 这样礼物盒会随着圣诞树一起移动或旋转。

6. 添加星星

为圣诞树顶部添加金色星星,提升节日气氛。

const starGeometry = new THREE.OctahedronGeometry(0.3, 0);
const starMaterial = new THREE.MeshPhongMaterial({color: 0xffd700,shininess: 100,
});
const star = new THREE.Mesh(starGeometry, starMaterial);
star.position.y = 5.5;
treeGroup.add(star);

四、添加动画

我们将实现圣诞树顶部星星的旋转动画,并更新渲染器。

function animate() {requestAnimationFrame(animate);if (christmasTree.children[christmasTree.children.length - 1]) {christmasTree.children[christmasTree.children.length - 1].rotation.y += 0.01;}controls.update();renderer.render(scene, camera);
}
animate();

完整的圣诞树场景即告完成!

代码

github

https://github.com/calmound/threejs-demo/tree/main/shengdanshu

gitee

https://gitee.com/calmound/threejs-demo/tree/main/shengdanshu


http://www.mrgr.cn/news/81701.html

相关文章:

  • 教育元宇宙的优势与核心功能解析
  • 【Linux 系统负载详情解析】
  • 数据库高安全—openGauss安全整体架构安全认证
  • 家用无线路由器的 2.4GHz 和 5GHz
  • Springboot 整合 Duird
  • 理解神经网络
  • Linux 搭建 nginx+keepalived (主备+双主模式) 高可用 | Nginx反向代理
  • Layui 新增销售单 其中一种 编写逻辑和打开方式
  • linux 中文输入法设置的宏观思路 (****)
  • 数据处理之数据规约
  • 文本数据处理
  • 了解智能运维
  • #渗透测试#漏洞挖掘#红蓝攻防#漏洞挖掘#未授权漏洞-Es未授权漏洞
  • leetcode 27. 移除元素
  • 【和春笋一起学C++】文本输入与读取
  • C# 修改项目类型 应用程序程序改类库
  • 【CSS in Depth 2 精译_094】16.2:CSS 变换在动效中的应用(下)——导航菜单的文本标签“飞入”特效与交错渲染效果的实现
  • CMake技术细节:解决未定义,提供参数
  • 走进人工智能体
  • 【Go】context标准库
  • SpringMVC学习(二)——RESTful API、拦截器、异常处理、数据类型转换
  • esp32学习:用虫洞ESP32S3-EYE开发板快速实现USB摄像头(UVC免驱)
  • 【HENU】河南大学计院2024 计算机网络 期末复习知识点
  • 中关村科金智能客服机器人如何解决客户个性化需求与标准化服务之间的矛盾?
  • Windows 11 中利用 WSL - Linux 虚拟环境部署 ChatTTS-Enhanced 项目教程
  • 动态规划<四> 回文串问题(含对应LeetcodeOJ题)