Three.js一学就会系列:03 炫酷3D划线

news2024/11/18 7:47:02

系列文章目录

Three.js一学就会系列:01 第一个3D网站
Three.js一学就会系列:02 画线


文章目录

  • 系列文章目录
  • 前言
  • 一、省略部分
  • 二、使用方法
      • 创建一个dom元素
      • 创建初始化方法
      • 线条动起来
  • 效果
  • 总结


前言

最近开始入坑前端3D建站,跟大家一起慢慢深入three.js做网站3D

这篇文章给大家讲下three.js 画线升级版,3D炫酷划线


一、省略部分

官网,介绍,以及引入库,参看文章片头系列文章:01 第一个3D网站

二、使用方法

创建一个dom元素

<div id="container"></div>

创建初始化方法

这里面使用到了我们前几篇文章讲到的,创建场景,创建集合,渲染等这里不再详细讲述


let container;

let camera, scene, renderer;

let line;

const segments = 10000;
const r = 800;
let t = 0;

init();

function init() {

	container = document.getElementById('container');

	camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 4000);
	camera.position.z = 2750;

	scene = new THREE.Scene();

	const geometry = new THREE.BufferGeometry();
	// 材质 顶点着色
	const material = new THREE.LineBasicMaterial({ vertexColors: true });
	// 位置数组
	const positions = [];
	// 随机颜色数组
	const colors = [];

	for (let i = 0; i < segments; i++) {

		const x = Math.random() * r - r / 2;
		const y = Math.random() * r - r / 2;
		const z = Math.random() * r - r / 2;

		// positions

		positions.push(x, y, z);

		// colors

		colors.push((x / r) + 0.5);
		colors.push((y / r) + 0.5);
		colors.push((z / r) + 0.5);

	}

	geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
	geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));

	line = new THREE.Line(geometry, material);
	scene.add(line);

	// 用WebGL渲染出你精心制作的场景
	renderer = new THREE.WebGLRenderer();
	// 设置设备像素比。通常用于避免HiDPI设备上绘图模糊
	renderer.setPixelRatio(window.devicePixelRatio);
	renderer.setSize(window.innerWidth, window.innerHeight);
	container.appendChild(renderer.domElement);

}

知识点:
这里面采用循环,将颜色值和位置通过循环的方式,存储并设置到BufferGeometry对应中,
setAttribute:设置几何属性 'position’位置,'color’颜色
Float32BufferAttribute:第一个参数为数据,第二个参数为分隔数,坐标(x,y,z)所以采用3

线条动起来

let container, clock;

letcamera, scene, renderer;

let line;

const segments = 10000;
const r = 800;
let t = 0;

init();
animate();

function init() {

	container = document.getElementById('container');

	camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 4000);
	camera.position.z = 2750;

	scene = new THREE.Scene();
	// 用于跟踪时间
	clock = new THREE.Clock();

	const geometry = new THREE.BufferGeometry();
	// 材质 顶点着色
	const material = new THREE.LineBasicMaterial({ vertexColors: true });
	// 位置数组
	const positions = [];
	// 随机颜色数组
	const colors = [];

	for (let i = 0; i < segments; i++) {

		const x = Math.random() * r - r / 2;
		const y = Math.random() * r - r / 2;
		const z = Math.random() * r - r / 2;

		// positions

		positions.push(x, y, z);

		// colors

		colors.push((x / r) + 0.5);
		colors.push((y / r) + 0.5);
		colors.push((z / r) + 0.5);

	}

	geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
	geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
	
	// 生成定点位置
	generateMorphTargets(geometry);

	// 计算边界
	geometry.computeBoundingSphere();

	line = new THREE.Line(geometry, material);
	scene.add(line);

	// 用WebGL渲染出你精心制作的场景
	renderer = new THREE.WebGLRenderer();
	// 设置设备像素比。通常用于避免HiDPI设备上绘图模糊
	renderer.setPixelRatio(window.devicePixelRatio);
	renderer.setSize(window.innerWidth, window.innerHeight);
	container.appendChild(renderer.domElement);

	// 监听窗口尺寸变化
	window.addEventListener('resize', onWindowResize);

}

function onWindowResize() {
	// 摄像机视锥体的长宽比,通常是使用画布的宽/画布的高。默认值是1(正方形画布)
	camera.aspect = window.innerWidth / window.innerHeight;
	// 更新摄像机投影矩阵 (参数更新后需要更新)
	camera.updateProjectionMatrix();

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

}

// 渲染循环

function animate() {

	requestAnimationFrame(animate);

	render();

}

// 渲染 动画
function render() {

	const delta = clock.getDelta();
	const time = clock.getElapsedTime();

	line.rotation.x = time * 0.25;
	line.rotation.y = time * 0.5;

	t += delta * 0.5;
	line.morphTargetInfluences[0] = Math.abs(Math.sin(t));
	// line.morphTargetInfluences[0] = 0;

	renderer.render(scene, camera);

}

//  位置
function generateMorphTargets(geometry) {

	const data = [];

	for (let i = 0; i < segments; i++) {

		const x = Math.random() * r - r / 2;
		const y = Math.random() * r - r / 2;
		const z = Math.random() * r - r / 2;

		data.push(x, y, z);

	}

	const morphTarget = new THREE.Float32BufferAttribute(data, 3);
	morphTarget.name = 'target1';

	geometry.morphAttributes.position = [morphTarget];

}

知识点:
为了实现动画效果,除了采用了熏染循环,对line进行了位置更新
generateMorphTargets方法,用于生成随机后的定点 赋值到geometry.morphAttributes.position
computeBoundingSphere:计算边界
Clock:用于计算时间,方便对动画效果支持

完整代码(实例)

<html>

<head>
	<meta charset="utf-8">
	<title>My first three.js app</title>
	<style>
		body {
			margin: 0;
		}
	</style>
</head>

<body>
	<script src="./three.js"></script>
	<div id="container"></div>
	<!-- <script src="https://threejs.org/build/three.js"></script> -->
	<script>
		let container, clock;

		let camera, scene, renderer;

		let line;
		
		const segments = 10000;
		const r = 800;
		let t = 0;

		init();
		animate();

		function init() {

			container = document.getElementById('container');

			camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 4000);
			camera.position.z = 2750;

			scene = new THREE.Scene();
			// 用于跟踪时间
			clock = new THREE.Clock();

			const geometry = new THREE.BufferGeometry();
			// 材质 顶点着色
			const material = new THREE.LineBasicMaterial({ vertexColors: true });
			// 位置数组
			const positions = [];
			// 随机颜色数组
			const colors = [];

			for (let i = 0; i < segments; i++) {

				const x = Math.random() * r - r / 2;
				const y = Math.random() * r - r / 2;
				const z = Math.random() * r - r / 2;

				// positions

				positions.push(x, y, z);

				// colors

				colors.push((x / r) + 0.5);
				colors.push((y / r) + 0.5);
				colors.push((z / r) + 0.5);

			}

			geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
			geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
			
			// 生成定点位置
			generateMorphTargets(geometry);

			// 计算边界
			geometry.computeBoundingSphere();

			line = new THREE.Line(geometry, material);
			scene.add(line);

			// 用WebGL渲染出你精心制作的场景
			renderer = new THREE.WebGLRenderer();
			// 设置设备像素比。通常用于避免HiDPI设备上绘图模糊
			renderer.setPixelRatio(window.devicePixelRatio);
			renderer.setSize(window.innerWidth, window.innerHeight);
			container.appendChild(renderer.domElement);

			// 监听窗口尺寸变化
			window.addEventListener('resize', onWindowResize);

		}

		function onWindowResize() {
			// 摄像机视锥体的长宽比,通常是使用画布的宽/画布的高。默认值是1(正方形画布)
			camera.aspect = window.innerWidth / window.innerHeight;
			// 更新摄像机投影矩阵 (参数更新后需要更新)
			camera.updateProjectionMatrix();

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

		}

		// 渲染循环

		function animate() {

			requestAnimationFrame(animate);

			render();

		}

		// 渲染 动画
		function render() {

			const delta = clock.getDelta();
			const time = clock.getElapsedTime();

			line.rotation.x = time * 0.25;
			line.rotation.y = time * 0.5;

			t += delta * 0.5;
			line.morphTargetInfluences[0] = Math.abs(Math.sin(t));
			// line.morphTargetInfluences[0] = 0;

			renderer.render(scene, camera);

		}

		//  位置
		function generateMorphTargets(geometry) {

			const data = [];

			for (let i = 0; i < segments; i++) {

				const x = Math.random() * r - r / 2;
				const y = Math.random() * r - r / 2;
				const z = Math.random() * r - r / 2;

				data.push(x, y, z);

			}

			const morphTarget = new THREE.Float32BufferAttribute(data, 3);
			morphTarget.name = 'target1';

			geometry.morphAttributes.position = [morphTarget];

		}
	</script>
</body>

</html>

效果

在这里插入图片描述

总结

以上就是今天要讲的内容,本文仅仅简单介绍了three.js的使用,而three.js提供了非常多的3D显示功能,后续文章,我将带大家慢慢深入了解。

如果觉得有用欢迎点赞关注
有问题私信我!!~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/72719.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

磨金石教育摄影技能干货分享|曾毅——尘封的故土,难忘的乡愁

乡愁是远离家乡的游子们&#xff0c;内心对故土美好的执念。我曾经在新疆边境县待过一年&#xff0c;异域的风情的新奇&#xff0c;充满了我的眼睛。我一度觉得这里真不错&#xff0c;在这待一辈子也挺好。 后来有一次去了当地一个汉族村&#xff0c;刚进村子就恍然有一种回家…

C# SuperSocket 手把手教你入门 傻瓜教程---7(自定义SuperSocket内置的命令行协议)

C# SuperSocket 手把手教你入门 傻瓜教程系列教程 C# SuperSocket 手把手教你入门 傻瓜教程---1&#xff08;服务器单向接收客户端发送数据&#xff09; C# SuperSocket 手把手教你入门 傻瓜教程---2&#xff08;服务器和客户端双向通信&#xff09; C# SuperSocket 手把手教…

黑马程序员14套经典IT教程+面试宝典

很多同学对互联网比较感兴趣 &#xff0c;奈何苦恼不知道如何入门。今天免费给大家分享一波&#xff0c;黑马程序员14套经典IT教程程序员面试宝典&#xff01;涉及Java、前端、Python、大数据、软件测试、UI设计、新媒体短视频等。从厌学到学嗨&#xff0c;你只差一套黑马教程&…

ADS1120 备忘

ADS1120 是一个小型、低功耗、16-bit、ΔΣ 模数转换器&#xff08;ADC&#xff09;&#xff1a; 内置 PGA&#xff08;1~128&#xff09;内置参考基准&#xff08;2.048V&#xff09;内置温度传感器内置 2 个已配对的可编程电流源SPI 通讯接口&#xff0c;使用 模式 1 &#…

BHAR事件研究方法stata代码和案例数据

BHAR事件研究方法stata代码和案例数据 1、方法说明&#xff1a; BHAR (Buy and Hold Abnormal Return)&#xff0c;即购入 -持有异常收益法。 无论是短期事件研究,还是长期事件研究,都包含以下六大步骤&#xff0c;即定义事件以及事件研究窗口、选择研究样本、选择望收益模型…

web安全之Webshell管理工具

目录 漏洞原理 工具 中国蚁剑(antsword) weevely(kali) godzilla Behinder 漏洞原理 上传PHP一句话木马到服务器 <?phpheader("Content-type:text/html;charsetgb1232");echo "<pre>";eval($_POST[coleak]); ?> 找到上传路径后通过…

PTE考试写作教程

PTE考试写作教程 由经验丰富的母语教师完成准备教程&#xff0c;以在 PTE 考试的写作部分取得成功 课程英文名&#xff1a;PTE Academic Exam Preparation Writing Mastery (Achieve 79) 此视频教程共10.0小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0…

《MySQL实战45讲》——学习笔记21 “加锁规则、加锁案例、死锁示例“

紧接着上篇介绍可重复读隔离级别下的幻读问题及解决幻读引入的间隙锁和next-key lock的概念&#xff0c;本篇介绍了更新记录时加锁的规则&#xff0c;并用几个案例来说明规则&#xff1b; 通过学习本文&#xff0c;可以帮助通过加锁规则去判断语句的加锁范围&#xff1b;在业务…

ABAP学习笔记之——第九章:ABAP对象

一、类 类(Class)可看做是对象的骨骼 (Template) 或者对象的类型。另外&#xff0c;类是抽象化对象的明细表。即可以说是制作对象的设计书。对象属性由描述对象的状态和行为的构成要素Component)决定。 比较结构化程序和面向对象程序 例&#xff1a; *比较结构化程序 和 面向…

Apache+PHP+MariaDB+MQTT重启指令

启动PHP服务 1.启动 systemctl start php-fpm.service Apache服务 1. 启动、终止、重启 systemctl start httpd.service #启动 systemctl stop httpd.service #停止 systemctl restart httpd.service #重启 2. 设置开机启动/关闭 systemctl enable httpd.service #开机…

Spring【日志文件的打印与输出】

Spring【日志文件的打印与输出】&#x1f34e;一.日志文件&#x1f352;1.1 日志的作用&#x1f352;1.2 怎样查看到日志信息&#x1f34e;二. 打印日志&#x1f352;2.1 自定义打印日志&#x1f352;2.2 ⽇志格式说明&#x1f34e;三.日志级别&#x1f352;3.1 日志级别的作用…

SpringMVC的收参方式?

第一种收取参数方式&#xff1a;数据类型收取参数 第二种收取参数的方式&#xff1a;实体类收取参数&#xff08;传参&#xff09; 第三种收取参数的方式&#xff1a;ajax 收取数组/集合 第四种收取参数的方式&#xff1a;ajax 接收json数据 第五种收取参数的方式&#xff1a;…

全网最牛最全Postman接口测试(五): postman设置接口关联,postman实现参数化

Postman(9): postman设置接口关联 postman设置接口关联 在实际的接口测试中&#xff0c;后一个接口经常需要用到前一个接口返回的结果&#xff0c; 从而让后一个接口能正常执行&#xff0c;这个过程的实现称为关联。 在postman中实现关联操作的步骤如下&#xff1a; 1、利用…

怎样避免软件测试中的漏测

什么是测试漏测&#xff1f; 测试漏测是指软件产品在测试结束后出现了在测试过程中没有被发现的bug。我们知道&#xff0c;漏测是每一个软件测试者最头疼的事&#xff0c;一旦出现漏测&#xff0c;首先给客户带来了非常不好的影响&#xff0c;特别是严重的功能性bug被漏测&…

程序员如何创造睡后收入呢?

程序员作为一个互联网行业的职业&#xff0c;在互联网当道的现在是非常吃香的。 作为程序员&#xff0c;一个基础工资的收入就已经是一笔不菲的收益了。 然而&#xff0c;钱总是不够花的&#xff0c;毕竟捂住口袋有点小难。 这时候&#xff0c;我们只好把视线转向另一边&…

算法面试题——删除链表后第N个节点

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#xff…

C语言百日刷题第十三天

前言 今天是刷题第13天&#xff0c;放弃不难&#xff0c;但坚持一定很酷~ 临近期末&#xff0c;再刷一套模拟题 C语言百日刷题第十三天前言选择题判断题编程题选择题 1.若由定义int*p1,*p2,m5,n;以下赋值语句都正确的选项是&#xff08;&#xff09; A、p1&m;p2&n…

signintech/gopdf功能介绍与代码示例

signintech/gopdf功能介绍与代码示例 PDF相关常识以及signintech/gopdf功能概览 代码示例&#xff1a; 参考&#xff1a;https://gitee.com/ixuer/gopdf_example 代码示例包括&#xff1a; 设置页面配置&#xff0c;如宽度和高度。test/font: 添加ttf字体&#xff0c;并设置…

计算机毕业设计springboot+vue基本微信小程序的快递收发小程序

项目介绍 随着Internet的发展,人们的日常生活已经离不开网络。未来人们的生活与工作将变得越来越数字化、网络化和电子化。本文以实际运用为开发背景,运用软件工程原理和开发方法,它主要是采用java语言技术、springboot框架和微信小程序来完成对系统的设计。整个开发过程首先对…

element-ui的Dropdown下拉菜单,传递多个参数

element-ui的Dropdown下拉菜单&#xff0c;传递多个参数 原因&#xff1a; Dropdown下拉菜单只允许我们传递一个参数 解决步骤: 在允许我们传递一个参数的哪里提前调用方法: 以前&#xff1a;<el-dropdown-item command"a"> 测试 </el-dropdown-item> 现…