ThreeJS 炫酷特效旋转多面体Web页 Demo 01《ThreeJS 炫酷特效制作》

2023-11-06

本案例为一个 threejs 的特效网页,大小球体进行包裹,外球体为透明材质,但是进行了线框渲染,使其能够通过外球踢查看其内球体。
注:案例参考源于互联网,在此做代码解释,侵删
本案例除 ThreeJS 外不适用任何第三方框架,放心食用
懒的同学可以直接下载代码,打赏作者一根精神食粮:https://download.csdn.net/download/A757291228/87871503

请添加图片描述
这是 inscode 的代码,不过渲染有点问题,不过也可以看到大致效果:

一、ThreeJS 三要素

在编写 ThreeJS 前,需要明白 ThreeJS 的三个要素,若对建模、游戏有过了解的同学在学习 ThreeJS 时对知识点理解会更容易接受。

在 ThreeJS 中有三个很关键的对象,分别是 摄像头、场景以及渲染器:

  • 其中 场景 是通过 ThreeJS “搭建”呈现特效的一个“舞台”,创建好一个场景后,即可往这个场景中添加对应的多种物体,例如多边形、粒子、球体等;
  • 创建好场景后我们需要在场景中添加摄像头用于呈现场景中的视觉效果,摄像头在 ThreeJS 中担任 “视觉采集”
    角色,可以通过控制摄像头采集范围(大小)从而采集场景中视觉呈现;
  • 那么完成以上两步后,还需要对场景进行渲染,只有渲染过后才能进行视觉效果的呈现。

可以想象场景为一个场地,摄像头为一个摄像头,渲染器就是渲染器,然后拍成了一段视频或照片。

二、代码中创建三要素

2.1 创建 html

首先创建一个 html 文件,并且引入 CSS 与 JS 文件:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>1_bit ThreeJS 炫酷旋转多面体Web页 Demo</title>
	<link rel="stylesheet" href="./style.css">
</head>

<body>
	<div id="canvas"></div>
	<script src='three.min.js'></script>
	<script src="./1bitDemo.js"></script>
</body>

</html>

在此需要注意,在 body 元素中添加了一个 div 并且 id 为 canvas,该 div 是为了之后在 js 代码中对应这个 div 添加渲染好的元素;除此之外还引入了 three.min.js 依赖,另外一个 js 名为 1bitDemo.js 是我们等下须编写的 js 文件代码。

2.2 css 编写

编写完 html 代码后,创建一个 style.css 文件用于给 html 添加一些基本样式,html 设置背景色,并且给与一个线性渐变,方向向下,随后给与 margin 为0,使其页面边缘贴合,代码过于简单在此不再赘述,css 如下:

html {
  width: 100%;
  height: 100%;
  background: linear-gradient(to bottom, #11e8bb 0%, #8200c9 100%);
  overflow: hidden;
}

body {
  margin: 0;
  padding: 0;
}

此时页面如下:
在这里插入图片描述

2.3 创建三要素

接着做完准备工作后,创建一个 js 文件,在此我的 js 文件名为 1bitDemo.js ,在其中我们将创建 场景、渲染器、摄像头。

由于我们为了一打开页面就进行渲染,所以在此需要创建一个 onload 事件:

window.onload = function () {
	
}

接着创建对应的对象存储三要素(渲染器、场景、摄像头):

var renderer, scene, camera;

渲染器

我们在此先创建渲染器,通过调用 THREE 对象的 WebGLRenderer 对摄像头进行创建,WebGLRenderer 方法接收传入一个渲染器的配置项对象,例如代码为:

renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });

此时传入的配置项:

  • antialias 表示抗锯齿打开,使几何体边缘平滑;
  • alpha 表示渲染器渲染时的画面有透明通道,若不打开将不会存在透明通道,例如 png 图片与 jpg 区别;

接着配置渲染器的渲染大小:

renderer.setSize(window.innerWidth, window.innerHeight);

以上代码中 setSize 方法用于设置渲染器渲染大小,通过 window.innerWidthwindow.innerHeight 传入渲染宽高。

此时就可以通过 js 获取到 canvas 元素,从而添加渲染器到 canvas 窗口即可:

document.getElementById('canvas').appendChild(renderer.domElement);

以上代码中 renderer.domElement 是得到渲染器渲染出的 canvas。

场景

场景创建很简单,通过 THREEScene 方法即可创建:

scene = new THREE.Scene();

摄像头

接着创建摄像头,透视摄像头创建使用 PerspectiveCamera 方法,代码如下:

camera = new THREE.PerspectiveCamera(100, window.innerWidth / window.innerHeight, 1, 1000);

PerspectiveCamera 方法接收 4 个参数,分别为:

  • 相机可视垂直视野角度(玩过FPS的应该知道有一个视野角度)
  • 相机可视长宽比
  • 相机近端距离
  • 相机远端距离

其中:

  • 相机近端距离为 相机到场景中最近可视物体的距离
  • 相机远端距离为 相机到场景中最远的可视物体的距离

若可视物体小于了 相机近端距离 和 大于了 相机远端距离 都会不可见。

接着我们此时可以移动一下摄像机的 z 轴,代码为:

camera.position.z = 500;

以下为 three 中的坐标系参考图:

在这里插入图片描述

此时 z 轴就是摄像机,或者说人的视窗所距离中心点的位置,若不移动这个距离,在创建几何体时将会无法很好的看见几何体,因为默认位置为这个坐标系的中心点。

最后将这个摄像机添加到场景中即完成三要素创建:

scene.add(camera);

三、几何体创建

3.1 创建二十面缓冲几何体

此时我们创建 2 个二十面的几何体,直接通过 IcosahedronGeometry 方法即可创建,代码为:

var geom = new THREE.IcosahedronGeometry(7, 1);
var geom2 = new THREE.IcosahedronGeometry(15, 1);

以上代码中 IcosahedronGeometry 接受两个参数,分别为:

  • radius 二十面体的半径,默认为1;
  • detail 设置面角,默认为0,值超过1则是球体,超过0小于1则会增加顶点使其转变成非二十面几何体;

3.2 创建二十面体的显示样式

在 three 中要为 二十面体创建显示的样式需要创建材质(Material),在此我们要创建一种可以用来模拟物体表面反射光线的亮度和光滑度的材质,需要通过 MeshPhongMaterial 进行创建,随后在 MeshPhongMaterial 方法中传入对应的配置项即可:

var mat = new THREE.MeshPhongMaterial({
	color: 0xffffff,
	shading: THREE.FlatShading
});
var mat2 = new THREE.MeshPhongMaterial({
	color: 0xffffff,
	wireframe: true,
	side: THREE.DoubleSide
});

以上代码中的配置项对象值:

  • color 表示颜色;
  • shading 表示网格的渲染方式(之后要使用的网格),在此使用
    FlatShading,表示使用平面着色来渲染网格,渲染的网格将会扁平化;
  • wireframetrue 表示渲染的网格将会呈现线框形式
  • side 设置为 THREE.DoubleSide
    表示双面渲染,即渲染的时候物体双面都会进行渲染,而不是只有一面(性能考虑若想设置只渲染一面设置为 THREE.FrontSide

3.3 创建 Mesh 用于组装 3D 对象

Mesh 在 ThreeJS 的 3D 对象中是必要的,通过 创建 Mesh 组合 3D 对象,创建 Mesh 需要指定对应的几何体以及材质,如以下代码:

var planet = new THREE.Mesh(geom, mat);

其中 geom 为之前所创建的几何体,mat 为之前所创建的材质。

随后我们需要对这个几何体 planet 进行缩放大小显示,在此放大 16 倍:

planet.scale.x = planet.scale.y = planet.scale.z = 16;

接下来我们需要创建一个 Object3D 用于存放这个几何体,通过 Object3D 我们可以方便的对 完整的几何体进行 缩放、移动等。

var center = new THREE.Object3D();
center.add(planet);
scene.add(center);

以上代码中创建了一个 cente rObject3D 对象,把创建好的几何体 planet 添加到 center 中,再把 center 添加到 scene 场景中即可。

渲染

此时若想查看页面是什么样,可以在末尾直接通过渲染器调用 render 方法进行渲染即可,render 方法需要传入场景和摄像头对象,此时代码为:

renderer.render(scene, camera)

但此时渲染出来的画面是黑色的:

在这里插入图片描述

原因是场景中没有添加光源,所以暗淡无光,接下来我们创建光源,但在此之前,我们刚刚创建了两个 MeshPhongMaterial 材质和 IcosahedronGeometry 二十面体对象,我们在此只实现了一个对象的 mesh,我们此时再完成另一个 IcosahedronGeometry mesh 的创建,并且创建 Object3D 对象进行存放:

var planet2 = new THREE.Mesh(geom2, mat2);
planet2.scale.x = planet2.scale.y = planet2.scale.z = 10;
outside = new THREE.Object3D();
outside.add(planet2);
scene.add(outside);

3.4 创建光源

在此我们创建环境光,创建环境光通过方法 AmbientLight,AmbientLight 方法传入环境光颜色即可:

var ambientLight = new THREE.AmbientLight(0x999999);
scene.add(ambientLight);

此时刷新界面如下:

在这里插入图片描述
此时我们还需要创建其他的太阳光。太阳光通过 DirectionalLight 进行创建,是一种平行光,并不会随距离而衰减。DirectionalLight 接受两个参数,一个是光照颜色一个是光照强度,光照强度默认为 1:

var lights1 = new THREE.DirectionalLight(0xffffff, 1);
lights1.position.set(1, 0, 0);
var lights2 = new THREE.DirectionalLight(0x11E8BB, 1);
lights2.position.set(0.75, 1, 0.5);
var lights3 = new THREE.DirectionalLight(0x8200C9, 1);
lights3.position.set(-0.75, -1, 0.5);
scene.add(lights1);
scene.add(lights2);
scene.add(lights3);

刷新界面重新渲染此时界面如下:
在这里插入图片描述

3.5 创建环境物体

接着开始创建环境物体,首先依照惯例创建一个 3D 容器,并且将这个容器添加到场景中:

particle = new THREE.Object3D();
scene.add(particle);

接着创建一个四面体(第一个参数已经就是半径,第二个参数与二十面体一致):

var geometry = new THREE.TetrahedronGeometry(2, 0);

随后创建材质(与之前一致不再赘述):

var material = new THREE.MeshPhongMaterial({
	color: 0xffffff,
	shading: THREE.FlatShading
});

由于环境物体较多,在此直接使用for 循环进行循环创建:

for (var i = 0; i < 1000; i++) {
	var mesh = new THREE.Mesh(geometry, material);
	mesh.position.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize();
	mesh.position.multiplyScalar(90 + (Math.random() * 700));
	mesh.rotation.set(Math.random() * 2, Math.random() * 2, Math.random() * 2);//旋转

	particle.add(mesh);
}

以上代码中首先创建了一个 mesh,随后 通过 mesh.position.set 设置其 x y z 的坐标,接着通过 multiplyScalar 方法对坐标进行放大,此时放大后将会使整体创建的 mesh 位置进行扩大,远离中心点,这样就可以使这些创建的物体发散到其他位置,最后在通过 mesh.rotation.set 设置他们的旋转角度,使创建的物体旋转方向发生改变,否则都是一个面反光并不是很好看,太单一了,最后添加到 particle 即可完成。

此时页面效果如下:
在这里插入图片描述

为啥看起来球那么小?其实大家可以调整视角大小以及远端距离可以拉近与物体的距离,在此我把摄像头视觉方位调成70:

camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);

此时呈现效果确实变大了:
在这里插入图片描述
最后就是完成动画,使其旋转。

3.6 animation 动画

做过 unity 的同学应该很清楚,只需要每帧更改其位置即可,那么此时我们创建一个 animate 方法,设置其 Object3D 对象的 rotation 即可:

function animate() {
	requestAnimationFrame(animate);

	particle.rotation.x += 0.0010;
	particle.rotation.y -= 0.0040;
	inside.rotation.x -= 0.0020;
	inside.rotation.y -= 0.0030;
	outside.rotation.x -= 0.0010;
	outside.rotation.y += 0.0020;
	renderer.clear();

	renderer.render(scene, camera)
};

以上方法中 requestAnimationFrame 为一个循环函数,传入对应的函数名即可重复执行,在此处我们只需要把 这个 animate 函数放到 onload 事件最后一行代码即可,并且删除 onload 中的 renderer 的 render 方法,因为在此处已经写有。

以上代码中的 renderer.clear(); 为清理渲染器的缓存,准备下一次渲染,一般在场景重绘前调用即可,当然 clear 可以指定清理不同的缓冲区,同学们可以之后在了解一下。

以上 animate 方法已经写好了,但是注意 renderer, scene, camera, inside, outside, particle 这些变量需要设置为全局变量,否则调用不到。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ThreeJS 炫酷特效旋转多面体Web页 Demo 01《ThreeJS 炫酷特效制作》 的相关文章

  • 在 SVG 中设置悬停语句样式

    我正在计划一个基于这个 SVG 插图的网络 菜单 我的想法的原则 一个样式为活动的圆圈 一个样式为悬停的圆圈以及一个也需要设置样式的伴随笔画 https i stack imgur com H397o png 当我阅读 SVG 文件的规范时
  • mailto:相当于电话的链接? [复制]

    这个问题在这里已经有答案了 有没有办法使用 html 和 或 JS 链接图像以便拨打电话 类似于 mailto 链接 如果可能的话 这只会让生活变得更加轻松 假设如果一个人有 Skype 是否可以通过一个按钮为他们打开 Skype 并拨打电
  • jQuery能否获取未绘制的动态元素的大小

    我的意思是如果我用 jQuery 和 DOM 创建一个 Element var MainHolder document createElement div addClass box 如果我打电话MainHolder width 如果不在窗口
  • 如何使用 HTML CSS JS 创建滑块/切换来更改屏幕上的字体大小 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 is there any way I can make this gt 所以我想制作一个滑块 切换器 用户可以拖动 滑动它来改变不同的
  • 如何使用 javascript 触发表单验证的本机验证气泡/工具提示?

    我有一个附加了 html5 验证 必需 等 属性的表单 有没有一种方法可以触发本机验证气泡 工具提示的出现 而无需模拟表单的提交按钮上的 单击 正如评论中所述 您可以使用 reportValidity 方法 这是广泛支持 https dev
  • 列表中允许 div 吗? [复制]

    这个问题在这里已经有答案了 我知道DIV inside LI是不允许的 但我最近在许多 大 网站上看到了它 例如粉碎杂志 网页设计师墙 etc 我尝试验证网站 但它们有错误 但没有任何信息DIV in LI 那么我可以在里面使用它吗LI 我
  • 将按键和焦点事件附加到 contenteditable div 内的元素

    我想附上keypress and focusoutcontenteditable 内段落的事件处理程序div 下面的代码似乎不起作用 div p Test p p Test p p Test p div p1 bind keypress f
  • 带有旋转文本的垂直导航

    我正在尝试实现一个包含链接的垂直导航菜单 并且我已使用 css3 将链接文本旋转到 270 度 我旋转了它 因为我希望文本从下到上 问题是当我添加顶部填充时 间距不一致 你可以看到我的代码here http jsbin com ravudu
  • 带滚动条的 HTML 画布

    我正在宽度不等的画布上绘制图表 每个画布可以有自己的滚动条吗 我尝试将所有画布放在一个 div 中并指定最大宽度 但它不起作用 是否有可能所有画布在页面上的可见宽度均为 500 像素 并且每个画布都有其滚动条来查看画布的整个宽度 谢谢 指定
  • 调整离子卡中的图像大小

    我想显示一组图像 并在下面说明 我选择使用 Ionic 卡 我得到这个结果 第一张图片 虽然我想保留现在的相同布局 并添加描述 这是我的代码
  • 如何读取 XML 文件并从中获取值以在 PHP 编码的 HTML 页面中显示

    我有一个 XML 文件 其中有一些重复的标签 其中包含不同的值 我需要获取这些值并显示在我的网页中 请帮助我得到这个 如果您使用 PHP5 可以查看 SimpleXML 您可以在这里找到介绍教程 http www w3schools com
  • 如何在缩放动画中保持原点位于图像中心?

    我有类似的情况fiddle https jsfiddle net ddvn3p1h 3 其中我有一个 CSS3 动画 可以缩放绝对定位在另一个元素中心的元素 但是 当动画发生时 它会偏离中心 如示例中相对于蓝色的红色方块所示 我如何将其居中
  • 动态检测屏幕高度和屏幕宽度,以精简图像的高度和宽度

    我以前可以display a div标签仅在portrait使用下面提到的代码corrl https stackoverflow com users 15388872 corrl in this https stackoverflow co
  • 更改文本框中一个字符的颜色 HTML/CSS [重复]

    这个问题在这里已经有答案了 我正在设计一个网站 我想问一下大家 如何通过CSS改变HTML文本框中字符串中的一个字符的颜色 示例 STACK OVER FLOW 只是 A 字母是红色的 你不能用常规方法做到这一点
  • 如何反转媒体查询中元素的顺序?

    我有两个 div 左和右 但是当屏幕小于 500px 时 左 div 成为底部 div 右 div 成为顶部 div DOM 中的第一个 div 应该显示为第二个 第二个 div 为第一个 I use display flex 然后 div
  • Skrollr 添加空白

    我已经尝试了一切 我在谷歌上阅读了 4 5 页试图找到适合我的修复程序 已经筋疲力尽了 即使我使用 skrollr 示例 我的问题仍然存在 不是说他们做错了什么 我知道我只是没有正确理解它 因此 我上传了一个演示 仅在移动设备上展示这个尴尬
  • 如何使用 HTML5 Javascript Canvas 获取三个碰撞形状的交集并删除不碰撞的部分?

    我最近专门针对 KonvaJs 发布了类似的问题here https stackoverflow com questions 64603077 how can i get the intersection of three shapes c
  • CSS 字体在 Firefox 中不起作用

    我下面有这个字体代码 它在谷歌浏览器中工作正常 但在火狐浏览器中根本不起作用 为什么
  • 如何在 Aframe 中的平面上加载 gif(具有透明度)(故障)?

    大家好 我是 Aframe 的新手 正在尝试在空间网络环境中设置一大堆 gif 我在飞机上加载 gif 时遇到了一些困难 我已经通过 Aframe 的资产文件夹加载了图像 故障 目前它看起来像这样
  • 允许 iframe 跨域链接到目标父框架

    我有 2 个域 域 1 上的一个页面使用 iframe 加载域 2 中的内容 如何允许来自domain2 iframe 内 的链接在domain1 的完整父框架中打开 我一直在关注IE和w3c的新沙箱属性 http www w3 org T

随机推荐

  • Flink standalone配置(血汗注意事项,哭唧唧)

    虚拟机请使用VMware15 win10不支持VMware14 会在导入文件时卡死 JDK flink环境都要配 环境变量如何修改请自行搜索 记得最后source etc profile standalone模式只需要配置flink yam
  • Ratslam信息ROSBAG TOPIC汇总1

    ROSBAG中TOPIC汇总 rostopic list clock irat red camera image compressed irat red odom irat red proximity range0 irat red pro
  • 【Spring Security】UserDetailsService 接口介绍

    文章目录 UserDetailsService 介绍 UserDetailsService 具体操作 UserDetailsService 方法介绍 UserDetailsService 介绍 UserDetailsService 在 Sp
  • C++库函数——map与set

    目录 1 关联式容器是什么 2 键值对 3 set set的介绍 set的模板参数列表 set的构造 set的迭代器 set的容量 set的修改与操作 set的使用举例 4 multiset multiset的介绍 multiset的使用举
  • 内核current宏解析

    内核 current宏解析 Technorati 标签 current thread info 在内核中 可以通过current宏来获得当前执行进程的task struct指针 现在来简要分析以下 最原始的定义如下 define curre
  • sql必知必会一图总结梳理

    关注公众号 JustGoForIt 免费领取sql必知必会电子书
  • 环境准备与小程序首页的运行逻辑

    环境准备 上传云函数 getCustomerOpenid 上传云函数到云环境 xiongyuqingcloud 调用云函数 Promise Cloud callFunction Object object 返回一个 Promise 对象 所
  • Eclipse:The selection cannot be launched,and there are no recent launches

    报错 Eclipse工具启动提示the selection cannot be launched and there are no recent 经网上查找了解 缺少String args 好久没学java了暴露了 修改后run 错误代码
  • 工具篇——1、TMUX

    目录 工具篇 一 TMUX 1 安装 2 概念 3 具体操作 3 1 会话 3 2 窗口 3 3 窗格 4 TMUX 配置 5 结对编程 工具篇 本系列专门用于记录一些软件或者小工具的使用 工欲善其事必先利其器 拥有称心如意的工具 可以大大
  • 来!一起捋一捋机器学习分类算法

    大数据文摘出品 来源 builtin 编译 邢畅 刘兆娜 李雷 钱天培 说起分类算法 相信学过机器学习的同学都能侃上一二 可是 你能够如数家珍地说出所有常用的分类算法 以及他们的特征 优缺点吗 比如说 你可以快速地回答下面的问题么 KNN算
  • 获取PancakeSwap Price

    导入 ethers js 接口文档 ethers js 中文文档 深入浅出区块链
  • 网络层(IP)和数据链路层(以太网)的关系

    目录 一 路由选择 二 IP协议中的路由选择 三 数据链路层协议 以太网 1 负责的工作 2 核心的协议 3 举例说明传输层 网络层 数据链路层之间的关系 4 描述数据使用的不同术语 很少区分 5 以太网帧格式 四 mac地址 数据链路层的
  • 2024王道408数据结构 P144 T11

    2024王道408数据结构 P144 T11 思考过程 题目说要我们找到元素值为x的结点 删除以它为根的子树 并释放相应的空间 这里要注意题目让我们删除的是根的子树包括根 那读明白了题目的意思我们就开始构思 先是要遍历二叉树 找到元素值为x
  • 『Android Studio』用Fragment实现一个简易新闻浏览界面

    Fragment意思为碎片 片段 在Android中有些Activity在手机上看起来很美观 但放在屏幕更大的平板类的设备上 可能就不一样了 而Fragment能在一个Activity中内嵌多个独立的小Activity 有效的解决了app在
  • 海盗分金币问题 编程+思路 C++

    来自招银网络科技笔试测试岗位的一道题目 海滩上有一堆金币 n个海盗来分 第一个海盗把这堆金币平均分成3份 如果不够就从自己口袋拿出来补齐 并拿走了一份 第二个海盗把剩下的金币又平均分成3份 如果不够再从自己口袋补齐 并拿走了一份 第三个 第
  • 利用iText将多张图处转为一个pdf

    项目需要将多张JPG格式的图片转为一个PDF再进行后续处理 百度查资源看博客发现用iText比较简单 也没想到会这么简单 刷新了我的彩虹心 话不多说 直接上code 项目用的是maven进行管理的 所以最开始需要引入依赖 如下
  • ROS STAGE教程4(Melodic Stage-4.3)stage_ros Segmentation fault (core dumped)

    针对以前适用于stage 4 1 ROS Kinetic的world文件无法用于ROS Melodic系统 一致出现问题 Segmentation fault core dumped 然后退出 步骤如下 catkin ws src目录下 g
  • TCP/IP 协议是一个“有层次的协议栈”

    在上一讲中 我简单提到了 TCP IP 协议 它是 HTTP 协议的下层协议 负责具体的数据传输工作 并且还特别说了 TCP IP 协议是一个 有层次的协议栈 在工作中你一定经常听别人谈起什么 四层负载均衡 七层负载均衡 什么 二层转发 三
  • VHDL实现4线-16线译码器

    源代码 library ieee use ieee std logic 1164 all entity decoder4 16 is port i in std logic vector 3 downto 0 y out std logic
  • ThreeJS 炫酷特效旋转多面体Web页 Demo 01《ThreeJS 炫酷特效制作》

    本案例为一个 threejs 的特效网页 大小球体进行包裹 外球体为透明材质 但是进行了线框渲染 使其能够通过外球踢查看其内球体 注 案例参考源于互联网 在此做代码解释 侵删 本案例除 ThreeJS 外不适用任何第三方框架 放心食用 懒的