ThreeJs Demo 之创建星空效果

简介: ThreeJs Demo 之创建星空效果


前言

使用threeJs + dat.GUI实现一个旋转星空的效果,效果如下:

完整代码可以去文章末尾直接拿去使用

image.png

大概步骤

  1. 引入库
  2. 初始化 Three.js 场景、相机和渲染器
  3. 设置 dat.GUI 控件
  4. 创建星星
  5. 将星星添加到场景中
  6. 动画循环
  7. dat.GUI 控制更新
  8. 窗口调整事件

通过本文的学习, 你将会收获:

  • 如何引入和使用 Three.js 和 dat.GUI 库
  • 初始化并配置一个 3D 场景,包括相机和渲染器
  • 创建和添加星星对象到场景中
  • 实现动画效果,使星星不断旋转
  • 使用 dat.GUI 控件动态调整星星的颜色、大小和数量
  • 处理窗口调整事件,确保渲染器和相机的设置随窗口大小变化而更新

具体实现:

1. 引入库

这里直接写在html 里面, 引入了CDN加载. 如果在vue or react等中使用,可使用包管理器进行依赖的下载.

js

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>  <!-- 引入Three.js库 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>  <!-- 引入dat.GUI库 -->

2. 初始化 Three.js 场景、相机和渲染器

  1. 创建一个新的 Three.js 场景 scene
  2. 创建一个透视相机 camera,设置视角、宽高比、近裁剪面和远裁剪面。
  3. 创建一个 WebGL 渲染器 renderer,设置渲染器的尺寸,并将其添加到文档的 body 中。

js

// 初始化场景、相机、渲染器
        const scene = new THREE.Scene();  // 创建一个新的Three.js场景
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);  // 创建透视相机
        const renderer = new THREE.WebGLRenderer();  // 创建WebGL渲染器
        renderer.setSize(window.innerWidth, window.innerHeight);  // 设置渲染器的大小为窗口的内宽和内高
        document.body.appendChild(renderer.domElement);  // 将渲染器的canvas元素添加到HTML文档中

3.设置 dat.GUI 控件

  1. 创建一个包含星星配置的对象 starSettings,包括颜色、大小和数量以及重置方法.
  2. 创建一个 dat.GUI 对象,并创建GUI 控件对象以便后续更新

js

// dat.GUI配置
        const starSettings = {
            color: 0xffffff,  // 初始星星颜色为白色
            size: 1,  // 初始星星大小
            count: 1000,  // 初始星星数量
            // 重置函数
            reset: function () {
                this.color = 0xffffff;  // 重置颜色为白色
                this.size = 1;  // 重置大小为1
                this.count = 1000;  // 重置数量为1000
                updateStars();  // 更新星星 // 同步 GUI 控件的值
                guiControllers.color.setValue(this.color);
                guiControllers.size.setValue(this.size);
                guiControllers.count.setValue(this.count);
            }
        };
       const gui = new dat.GUI();  // 创建dat.GUI对象
        // 创建 GUI 控件并保存引用以便后续更新
        const guiControllers = {
            color: gui.addColor(starSettings, 'color').name('颜色').onChange(updateStars),  // 添加颜色控制
            size: gui.add(starSettings, 'size', 0.1, 10).name('大小').onChange(updateStars),  // 添加大小控制
            count: gui.add(starSettings, 'count', 100, 10000).name('数量').onChange(updateStars),  // 添加数量控制
            reset: gui.add(starSettings, 'reset').name('重置')  // 添加重置按钮
        };

这里使用到的GUI的方法说明:

1. add

add(object, property, [min], [max], [step])

创建一个新的控件,并将其添加到 GUI 中。

  • object:包含要控制属性的对象。
  • property:要控制的属性。
  • min:属性的最小值(可选)。
  • max:属性的最大值(可选)。
  • step:属性的步长(可选)。
  • 返回一个 GUIController 对象。

2. addColor

addColor(object, property)

创建一个颜色选择控件,并将其添加到 GUI 中。

  • object:包含要控制属性的对象。
  • property:要控制的属性。
  • 返回一个 GUIController 对象。

4. 创建星星

  • 定义 createStars 函数来创建星星。
  • 在函数中,创建一个几何体 geometry 和一个空的顶点数组 vertices
  • 根据 starSettings.count 循环生成随机的 xyz 坐标,并将它们添加到 vertices 数组中。
  • 使用 THREE.Float32BufferAttribute 将顶点数组添加到几何体中。
  • 创建一个星星材质 material,并结合几何体和材质创建一个 THREE.Points 对象 stars
  • 返回创建的星星对象。

js

function createStars() {
            const geometry = new THREE.BufferGeometry();  // 创建几何体
            const vertices = [];  // 用于存储星星位置的数组
            for (let i = 0; i < starSettings.count; i++) {  // 根据星星数量生成顶点
                const x = THREE.MathUtils.randFloatSpread(2000);  // 随机生成x坐标
                const y = THREE.MathUtils.randFloatSpread(2000);  // 随机生成y坐标
                const z = THREE.MathUtils.randFloatSpread(2000);  // 随机生成z坐标
                vertices.push(x, y, z);  // 将生成的顶点添加到数组中
            }
            console.log(vertices); // 包含3000 个 随机顶点值的数组
            geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));  // 将顶点添加到几何体中
            console.log(geometry.getAttribute('position').count);
            const material = new THREE.PointsMaterial({ color: starSettings.color, size: starSettings.size });  // 创建星星材质
            const stars = new THREE.Points(geometry, material);  // 创建星星物体
            return stars;  // 返回创建的星星
        }
 let stars = createStars();  // 调用createStars函数创建星星
 scene.add(stars);  // 将星星添加到场景中

额外说明:

调用 createStars 方法后,返回的对象 stars 是一个包含 1000 个星星的 THREE.Points 对象。每个星星的位置由顶点数组中的坐标决定。

具体来说,createStars 方法中:

  1. 创建一个新的 THREE.BufferGeometry 对象 geometry
  2. 创建一个包含 3000 个元素的 vertices 数组,每三个元素(x, y, z)表示一个星星的位置。由于 starSettings.count 是 1000,所以会有 1000 个星星,每个星星用 3 个坐标值表示,共计 3000 个值。
  3. vertices 数组设置为 geometry 对象的 position 属性。
  4. 创建一个 THREE.PointsMaterial 对象 material,用于定义星星的材质。
  5. 使用 geometrymaterial 创建一个 THREE.Points 对象 stars,该对象包含了所有的星星。

返回的 stars 对象中包含 1000 个星星,每个星星的位置由顶点数组定义。因此,尽管 createStars 方法返回的是一个对象,但这个对象实际上表示了 1000 个星星的位置和材质。

总体来说:

  • vertices 数组中包含 3000 个值,每三个值表示一个星星的 x, y, z 坐标。
  • geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)) 将这些坐标作为星星的位置属性添加到几何体中。
  • new THREE.Points(geometry, material) 创建了一个包含所有星星的 THREE.Points 对象。
  • 返回的 stars 对象表示 1000 个星星。

因此,返回的 stars 对象是一个包含 1000 个星星的集合。

5. 动画循环

  • 定义 animate 函数,用于执行动画循环。
  • 在每帧中,旋转星星并渲染场景。
  • 使用 requestAnimationFrame 调用 animate 函数,确保动画持续进行。

js

// 动画循环
        function animate() {
            requestAnimationFrame(animate);  // 请求下一帧动画
            stars.rotation.x += 0.001;  // 旋转星星
            stars.rotation.y += 0.002;  // 旋转星星
            renderer.render(scene, camera);  // 渲染场景
        }
        animate();  // 开始动画

额外说明

requestAnimationFrame 方法可以查看这个链接 developer.mozilla.org/zh-CN/docs/…

6. dat.GUI 控制更新

当我们调制控件某个值的大小的就会触发页面的重更新.

  • 定义 updateStars 函数,当用户通过 dat.GUI 修改设置时,更新星星。
  • 从场景中移除旧的星星,创建新的星星,并将其添加到场景中。

js

function updateStars() {
            scene.remove(stars);  // 从场景中移除旧的星星
            stars = createStars();  // 创建新的星星
            scene.add(stars);  // 将新的星星添加到场景中
     }

执行流程

修改值 ==> 修改starSettings中的值 ==> 触发updateStars的函数执行 ==> 删除场景 ==> 重新读取starSettings参数并创建对象 ==> 放入场景中

7. 窗口调整事件

添加窗口调整事件监听器,当窗口大小变化时,更新相机的宽高比和渲染器的尺寸。

js

// 窗口大小调整
        window.addEventListener('resize', () => {  // 监听窗口大小变化事件
            camera.aspect = window.innerWidth / window.innerHeight;  // 更新相机的宽高比
            camera.updateProjectionMatrix();  // 更新相机投影矩阵
            renderer.setSize(window.innerWidth, window.innerHeight);  // 更新渲染器大小
        });

完整代码

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js 星空</title>
    <style>
        body {
            margin: 0;
        }
        /* 去掉页面的默认边距 */
        canvas {
            display: block;
        }
        /* 将canvas设置为块级元素,去掉默认内边距 */
    </style>
</head>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <!-- 引入Three.js库 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script> <!-- 引入dat.GUI库 -->
    <script>
        // 初始化场景、相机、渲染器
        const scene = new THREE.Scene();  // 创建一个新的Three.js场景
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);  // 创建透视相机
        const renderer = new THREE.WebGLRenderer();  // 创建WebGL渲染器
        renderer.setSize(window.innerWidth, window.innerHeight);  // 设置渲染器的大小为窗口的内宽和内高
        document.body.appendChild(renderer.domElement);  // 将渲染器的canvas元素添加到HTML文档中
        // dat.GUI配置
        const starSettings = {
            color: 0xffffff,  // 初始星星颜色为白色
            size: 1,  // 初始星星大小
            count: 1000,  // 初始星星数量
            rotationSpeedX: 0.001,  // 初始星星x轴旋转速度
            rotationSpeedY: 0.002,  // 初始星星y轴旋转速度
            // 重置函数
            reset: function () {
                this.color = 0xffffff;  // 重置颜色为白色
                this.size = 1;  // 重置大小为1
                this.count = 1000;  // 重置数量为1000
                // 旋转速度
                this.rotationSpeedY = 0.002;
                this.rotationSpeedX = 0.001;
                updateStars();  // 更新星星 // 同步 GUI 控件的值
                guiControllers.color.setValue(this.color);
                guiControllers.size.setValue(this.size);
                guiControllers.count.setValue(this.count);
                guiControllers.rotationSpeedX.setValue(this.rotationSpeedX);
                guiControllers.rotationSpeedY.setValue(this.rotationSpeedY);
            }
        };
        function createStars() {
            const geometry = new THREE.BufferGeometry();  // 创建几何体
            const vertices = [];  // 用于存储星星位置的数组
            for (let i = 0; i < starSettings.count; i++) {  // 根据星星数量生成顶点
                const x = THREE.MathUtils.randFloatSpread(2000);  // 随机生成x坐标
                const y = THREE.MathUtils.randFloatSpread(2000);  // 随机生成y坐标
                const z = THREE.MathUtils.randFloatSpread(2000);  // 随机生成z坐标
                vertices.push(x, y, z);  // 将生成的顶点添加到数组中
            }
            geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));  // 将顶点添加到几何体中
    
            const material = new THREE.PointsMaterial({ color: starSettings.color, size: starSettings.size });  // 创建星星材质
            const stars = new THREE.Points(geometry, material);  // 创建星星物体
            return stars;  // 返回创建的星星
        }
        let stars = createStars();  // 调用createStars函数创建星星
        scene.add(stars);  // 将星星添加到场景中
        camera.position.z = 5;  // 设置相机位置
        // 动画循环
        function animate() {
            requestAnimationFrame(animate);  // 请求下一帧动画
            stars.rotation.x += starSettings.rotationSpeedX;  // 旋转星星
            stars.rotation.y += starSettings.rotationSpeedY;  // 旋转星星
            renderer.render(scene, camera);  // 渲染场景
        }
        animate();  // 开始动画
        const gui = new dat.GUI();  // 创建dat.GUI对象
        // 创建 GUI 控件并保存引用以便后续更新
        const guiControllers = {
            color: gui.addColor(starSettings, 'color').name('颜色').onChange(updateStars),  // 添加颜色控制
            size: gui.add(starSettings, 'size', 0.1, 10).name('大小').onChange(updateStars),  // 添加大小控制
            count: gui.add(starSettings, 'count', 100, 10000).name('数量').onChange(updateStars),  // 添加数量控制
            // 添加星星的旋转速度
            rotationSpeedX: gui.add(starSettings, 'rotationSpeedX', 0.001, 0.1, 0.001).name('旋转速度X').onChange(updateStars),
            rotationSpeedY: gui.add(starSettings, 'rotationSpeedY', 0.001, 0.1, 0.001).name('旋转速度Y').onChange(updateStars),
            reset: gui.add(starSettings, 'reset').name('重置')  // 添加重置按钮
        };
        function updateStars() {
            scene.remove(stars);  // 从场景中移除旧的星星
            stars = createStars();  // 创建新的星星
            scene.add(stars);  // 将新的星星添加到场景中
        }
        // 窗口大小调整
        window.addEventListener('resize', () => {  // 监听窗口大小变化事件
            camera.aspect = window.innerWidth / window.innerHeight;  // 更新相机的宽高比
            camera.updateProjectionMatrix();  // 更新相机投影矩阵
            renderer.setSize(window.innerWidth, window.innerHeight);  // 更新渲染器大小
        });
    </script>
</body>
</html>


目录
相关文章
|
定位技术
Threejs实现绘制地球,地理位置标注、经纬度转换世界坐标threejs坐标
Threejs实现绘制地球,地理位置标注、经纬度转换世界坐标threejs坐标
2247 0
Threejs实现绘制地球,地理位置标注、经纬度转换世界坐标threejs坐标
|
数据可视化 定位技术
three.js实现烟雾缭绕效果
前言 大家好!我是Fly哥,最近接广告的接的有点多, 感谢大家还是一如既往的支持我!respect, 前几天我在朋友圈分享了一个烟雾缭绕的效果。很多小伙伴都表示非常感兴趣,有的同学说用到了噪声, 有的同学说用到了着色器,还有更过分说用到了ps, 胖虎竟然无语凝噎。其实都是就是简单的贴图。配合一点想象力。我们先看下效果: 然后我就发了一条朋友圈,问这个像什么?? 有的说 云层, 有的说云墨,有的说雾霭, 其实都不是, 我想做的是烟雾。好的话不不多说!, 本篇文章阅读大概5分钟。不耽误大家太多时间,主要是介绍思路, 说太多也没啥意义。如果你对three.js 还没有一点了解都没有,
three.js实现烟雾缭绕效果
Threejs创建天空和太阳
这篇文章讲解了如何使用Three.js中的Sky组件来创建真实的天空与太阳效果,包括调整天空的颜色、太阳的位置以及实现大气散射等技巧。
505 3
|
存储 JavaScript 前端开发
使用JS创造一个3D粒子化星空,十分酷炫,大家快进来看看吧
使用JS创造一个3D粒子化星空,十分酷炫,大家快进来看看吧
Three添加天空盒子
这篇文章详细说明了如何在Three.js中添加天空盒(Skybox)以增强3D场景的真实感和沉浸体验。
486 6
Three添加天空盒子
|
API
【threejs教程】threejs中的边边角角:几何体详解
【8月更文挑战第6天】threejs中的几何体详解
548 4
【threejs教程】threejs中的边边角角:几何体详解
ThreeJs制作管道水流效果
这篇文章详细说明了如何在Three.js中创建具有流动水效果的管道模型,通过使用纹理贴图的动态偏移来模拟水流的视觉效果。
742 3
|
移动开发 JavaScript 前端开发
ThreeJs搭建web3D场景
这篇文章讲解了如何使用Three.js来搭建web端的3D场景,并介绍了创建3D项目的基本要素。
565 2
|
开发框架
threejs做特效:实现物体的发光效果-EffectComposer详解!
【8月更文挑战第7天】实现物体的发光效果-EffectComposer详解!
2225 6
threejs做特效:实现物体的发光效果-EffectComposer详解!
Threejs制作海面效果
这篇文章详细介绍了利用Three.js制作逼真海面效果的过程,包括设置Water材质、调整光照及实现波动动画的步骤。
472 0
Threejs制作海面效果

热门文章

最新文章