使用three.js导入外部glb模型实现一个nft产品

2023-10-30

nft数字藏品大火,各家公司都推出自己的app和小程序,那么炫酷的3D藏品到底如何实现的呢?我们来一探究竟!

需求背景

随着各家数字藏品项目上线,我们团队也紧随潮流打算在短期内开发一款数字藏品的产品。主要有哪些需求呢,当然就是别人有什么我们也做什么啦,相同的功能不同的UI。其他的功能都好说,但藏品把玩的3D效果之前未涉及过,但有了解过可以通过three.js来实现。所以,就开始看文档调研吧。

准备工作

首先在项目中安装three.js插件

npm i three
npm i three-orbitcontrols

然后在对应场景引入

import * as THREE from 'three';
import {
	OrbitControls
} from "three/examples/jsm/controls/OrbitControls"; // 鼠标控制器
import {
	GLTFLoader
} from "three/examples/jsm/loaders/GLTFLoader.js"; // glb模型加载器

使用

  1. 创建场景
createScene() {
	// 创建场景
	this.scene = new THREE.Scene();

	// 创建相机
	let width = this.$refs.container.$el.offsetWidth; // 窗口宽度
	let height = this.$refs.container.$el.offsetHeight; // 窗口高度
	this.width = width;
	this.height = height;
	let k = width / height; // 窗口宽高比
	// 初始化相机,参数通俗讲PerspectiveCamera(远近,宽高比,摄像机视锥体近端面(默认0.1),
	// 摄像机视锥体远端面(默认2000,无限大,表示可以看到最远))
	this.camera = new THREE.PerspectiveCamera(60, k, 0.1, 180); // 透视相机
	this.camera.position.set(0, 0, 4); // 设置相机位置
	this.camera.lookAt(this.scene.position); // 指向场景中心

	// 创建渲染器
	this.renderer = new THREE.WebGLRenderer({
		antialias: true, // 抗锯齿
		alpha: true,
	});
	// 设置渲染区域尺寸
	this.renderer.setSize(width, height);
	// 设置背景颜色
	this.renderer.setClearColor(0x1e1e1e, 1);
	// 渲染器开启阴影效果
	this.renderer.shadowMap.enabled = true;
	// 阴影贴图类型
	this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;

	// 添加坐标轴,用于调试,可以直观的展示模型的空间位置
	let axes = new THREE.AxesHelper(1000);
	this.scene.add(axes);

	// 将画布添加到容器中
	document.getElementById("container").appendChild(this.renderer.domElement);
	// 创建相机控件
	this.createOrbitControls();
},
  1. 创建背景
// 创建背景,根据业务需求完善
createUniverse() {
	const BgImg = ""; // 背景图片
	let texture = new THREE.TextureLoader().load(BgImg); // 加载背景贴图
	this.scene.background = texture; // 设置场景背景
},
  1. 创建相机控件
// 创建相机控件
createOrbitControls() {
	// 创建相机控件对象
	this.mouseControls = new OrbitControls(
		this.camera,
		this.renderer.domElement
	);
	// 右键平移拖拽
	this.mouseControls.enablePan = false; // 在移动端是双指拖拽
	// 鼠标缩放功能
	this.mouseControls.enableZoom = true;
	// 相机距离原点的距离范围
	this.mouseControls.minDistance = 0;
	this.mouseControls.maxDistance = 100;

	// 滑动阻尼,鼠标拖拽旋转的灵敏度,阻尼越小越灵敏
	this.mouseControls.enableDamping = true;
	// 阻尼系数(默认0.25)
	this.mouseControls.dampingFactor = 0.5;
	// 上下翻转角度范围
	this.mouseControls.maxPolarAngle = 3; // y旋转角度范围
	this.mouseControls.minPolarAngle = 0;

	// 是否自动旋转
	this.mouseControls.autoRotate = true;
	this.mouseControls.autoRotateSpeed = 5; // 自转速度
	// 加载模型
	this.loadGlbModel();
},
  1. 创建光源
// 创建光源
createLight() {
	// 配置环境光
	this.ambientLight = new THREE.AmbientLight(0x999999);
	// 将环境光添加到场景中
	this.scene.add(this.ambientLight);
	// 配置点光源
	this.pointLight = new THREE.PointLight(0xffffff, 1, 0);
	// 配置点光源的位置
	this.pointLight.position.set(500, 300, 400);
	// 将点光源添加至场景中
	this.scene.add(this.pointLight);
},
  1. 加载模型
// 加载glb、glbf模型
loadGlbModel() {
	let self = this;
	let loader = new GLTFLoader();
	// 本地静态模型调试要放在根目录public中,我们这边用的uniapp就放在static中,不然会出现加载问题
	loader.load(`${this.modelPath}`, (gltf) => {
		console.log('gltf ---->>', gltf);
		let loaderScene = gltf.scene;
		loaderScene.scale.set(1, 1, 1); // 设置模型大小缩放
		loaderScene.position.set(0, -1, 0);
		// 模型加入到场景中
		self.scene.add(loaderScene);
		// 渲染器启动
		this.repeatRender();
	}, (xhr) => {
		console.log(`${ (xhr.loaded / xhr.total) * 100 }%`)
	}, (err) => {
		console.log('error ---->>', err);
	})
},
  1. 渲染器
// 渲染器
repeatRender() {
	let animate = () => {
		// 请求动画帧,屏幕每刷新一次调用一次,绑定屏幕刷新频率
		this.clearAnim = requestAnimationFrame(animate);
		// 实时更新相机控件
		this.mouseControls.update();
		// 渲染场景和相机
		this.renderer.render(this.scene, this.camera);
	};
	animate();
},

完整代码

<template>
	<view class="enlarge">
		<view class="header">
			<view class="header-name">{{ goodsName }}</view>
			<view class="header-auth">
				<view class="auth">创作者:</view>
				<view class="name">{{ goodsAuth }}</view>
			</view>
		</view>
		<view class="container" id="container" ref="container"></view>
		<view class="bottom-box">
			<image class="bottom-box-img" src="@/static/img/share-bg.png" mode="widthFix"></image>
		</view>
	</view>
</template>

<script>
	import * as THREE from 'three';
	import {
		OrbitControls
	} from "three/examples/jsm/controls/OrbitControls"; // 鼠标控制器
	import {
		GLTFLoader
	} from "three/examples/jsm/loaders/GLTFLoader.js"; // 模型加载器
	import {
		FBXLoader
	} from 'three/examples/jsm/loaders/FBXLoader.js';
	export default {
		data() {
			return {
				goodsName: '做前端死路一条',
				goodsAuth: '鲁迅',
				scene: null, // 场景
				camera: null, // 相机
				mouseControls: null, // 相机控件
				renderer: null, // 渲染
				ambientLight: null, // 环境光
				clearAnim: null, // 动画帧
				autoRotate: true, // 是否自转
				autoRotateSpeed: 10, // 自转速度,数值越小速度越慢
				modelPath: "static/model/elvenKing.glb", // 模型路径
				width: null, // 画布宽度
				height: null, // 画布高度
				distance: 60, // 视野距
				near: 1, // 最小视野距
				far: 180, // 最大视野距
			};
		},
		onReady() {
			this.init();
		},
		onUnload() {
			// 组件卸载
			cancelAnimationFrame(this.clearAnim);
			// 场景
			this.scene = null;
			// 相机
			this.camera = null;
			// 相机控件
			this.mouseControls = null;
			// 渲染器
			this.renderer = null;
			// 环境光
			this.ambientLight = null;
			// 动画帧
			this.clearAnim = null;
		},
		methods: {
			init() {
				this.createScene(); // 创建场景
				this.createUniverse(); // 创建背景
				this.createLight(); // 创建光源
			},
			// 初始化步骤
			createScene() {
				// 创建场景
				this.scene = new THREE.Scene();

				// 创建相机
				let width = this.$refs.container.$el.offsetWidth; // 窗口宽度
				let height = this.$refs.container.$el.offsetHeight; // 窗口高度
				this.width = width;
				this.height = height;
				let k = width / height; // 窗口宽高比
				// 初始化相机,参数通俗讲PerspectiveCamera(远近,宽高比,摄像机视锥体近端面(默认0.1),
				// 摄像机视锥体远端面(默认2000,无限大,表示可以看到最远))
				this.camera = new THREE.PerspectiveCamera(this.distance, k, this.near, this.far); // 透视相机
				this.camera.position.set(0, 0, 4); // 设置相机位置
				this.camera.lookAt(this.scene.position); // 指向场景中心

				// 创建渲染器
				this.renderer = new THREE.WebGLRenderer({
					antialias: true, // 抗锯齿
					alpha: true,
				});
				// 设置渲染区域尺寸
				this.renderer.setSize(width, height);
				// 设置背景颜色
				this.renderer.setClearColor(0x1e1e1e, 1);
				// 渲染器开启阴影效果
				this.renderer.shadowMap.enabled = true;
				// 阴影贴图类型
				this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;

				// 添加坐标轴,辅助判断位置,可用于调试
				let axes = new THREE.AxesHelper(1000);
				this.scene.add(axes);

				// 将画布添加到容器中
				document.getElementById("container").appendChild(this.renderer.domElement);
				this.createOrbitControls();
			},
			// 创建背景,根据业务需求完善
			createUniverse() {
				const BgImg = "";
				let texture = new THREE.TextureLoader().load(BgImg); // 加载背景贴图
				this.scene.background = texture; // 设置场景背景
			},
			// 创建相机控件
			createOrbitControls() {
				// 创建相机控件对象
				this.mouseControls = new OrbitControls(
					this.camera,
					this.renderer.domElement
				);
				// 右键平移拖拽
				this.mouseControls.enablePan = false;
				// 鼠标缩放
				this.mouseControls.enableZoom = true;
				// 相机距离原点的距离范围
				this.mouseControls.minDistance = 0;
				this.mouseControls.maxDistance = 100;

				// 滑动阻尼,鼠标拖拽旋转的灵敏度,阻尼越小越灵敏
				this.mouseControls.enableDamping = true;
				// 阻尼系数(默认0.25)
				this.mouseControls.dampingFactor = 0.5;
				// 上下翻转角度范围
				this.mouseControls.maxPolarAngle = 3; // y旋转角度范围
				this.mouseControls.minPolarAngle = 0;

				// 是否自动旋转
				this.mouseControls.autoRotate = this.autoRotate;
				this.mouseControls.autoRotateSpeed = this.autoRotateSpeed; // 自转速度
				// 加载模型
				this.loadGlbModel();
			},
			// 创建光源
			createLight() {
				// 配置环境光
				this.ambientLight = new THREE.AmbientLight(0x999999);
				// 将环境光添加到场景中
				this.scene.add(this.ambientLight);
				// 配置点光源
				this.pointLight = new THREE.PointLight(0xffffff, 1, 0);
				// 配置点光源的位置
				this.pointLight.position.set(500, 300, 400);
				// 将点光源添加至场景中
				this.scene.add(this.pointLight);
			},
			// 加载glb、glbf模型
			loadGlbModel() {
				let self = this;
				let loader = new GLTFLoader();
				loader.load(`${this.modelPath}`, (gltf) => {
					console.log('gltf---->>', gltf);
					let loaderScene = gltf.scene;
					loaderScene.scale.set(1, 1, 1); // 设置模型大小缩放
					loaderScene.position.set(0, -1, 0);

					self.scene.add(loaderScene);
					// 渲染器启动
					this.repeatRender();
				}, (xhr) => {
					console.log(`${ (xhr.loaded / xhr.total) * 100 }%`)
				}, (err) => {
					console.log('error ---->>', err);
				})
			},

			// 渲染器
			repeatRender() {
				let animate = () => {
					// 请求动画帧,屏幕每刷新一次调用一次,绑定屏幕刷新频率
					this.clearAnim = requestAnimationFrame(animate);
					// 实时更新相机控件
					this.mouseControls.update();
					// 渲染场景和相机
					this.renderer.render(this.scene, this.camera);
				};
				animate();
			},
		}
	}
</script>

<style lang="less">
	.enlarge {
		padding: 32rpx;
		width: 100%;
		height: 100%;
		box-sizing: border-box;
		position: fixed;
		top: 0;
		right: 0;
		background-color: #1e1e1e;

		.header {
			position: absolute;
			top: 32rpx;
			left: 32rpx;
			color: #fff;
			background-color: rgba(0, 0, 0, 0);

			.header-name {
				font-size: 40rpx;
			}

			.header-auth {
				font-size: 28rpx;
				display: flex;
				color: #b1b1b1;
				margin-top: 16rpx;
			}
		}

		.container {
			width: 100%;
			height: 100%;
		}

		.bottom-box {
			width: 100%;
			padding: 0 32rpx;
			box-sizing: border-box;
			position: absolute;
			bottom: 160rpx;
			left: 0;
			z-index: -1;

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

使用three.js导入外部glb模型实现一个nft产品 的相关文章

随机推荐

  • gradle更新snapshot的jar

    通常 gradle下载引用的jar文件的话 会缓存到本地 不会重复去下载 但是 我们引用的是snapshot的jar 这种jar文件一般是其他项目组的代码 这种jar一般都进行迭代开发 会重复更新上传到nexus代码仓库中 我们必须在每次启
  • linux-vmware workstation安装

    环境介绍 闲着没事测试下linux vmware workstation linux vmware workstation安装 1 搭建软件仓库 root gby mount dev sr0 mnt mount mnt WARNING de
  • TRON节点验证交易的时间容忍度

    这篇文章主要介绍深入分析TRON的节点配置文件中vm minTimeRatio和vm maxTimeRatio这两个标志的意义 这两个标志的表示的是节点 包括sr和fullnode 验证区块中智能合约交易的时间比例 时间容忍度 注 sr节点
  • 【java】swagger中api接口传多个参数 @ApiImplicitParam和@ApiImplicitParams

    目录 1 ApiImplicitParam 2 ApiImplicitParams 3 Spring Boot项目中集成Swagger knife4j并自定义访问路径 swagger常用注解使用说明 1 ApiImplicitParam 作
  • PI闭环的FPGA实现

    PID闭环的FPGA实现 1 原理分析 最近小张同学在做项目的时候发现PI闭环的FPGA学习资料很少 秉持着 既然没有轮子 那么自己就造一个的原则 于是乎自己写了个PI的Verilog程序 FPGA中实现PI闭环与DSP STM32 arm
  • docker安装kibana报Kibana server is not ready yet解决

    今天通过docker安装了es集群 想再起一个kibana容器进行管理 安装还算方便 直接联网用docker pull与es同版本的kibana镜像下来启动容器即可 奈何用浏览器访问http 127 0 0 1 5601 时一直报Kiban
  • java synchronized用法

    总结一下synchronized的用法 1 修饰静态方法 2 修饰实例方法 3 修饰代码块 一 首先看一下修饰静态方法和修饰实例方法的区别 直接上代码 synchronized 修饰实例方法 修饰静态方法 public class Sync
  • 第十章 Flink

    1 Flink初识 1 1 数据处理架构的发展和演变 流处理和批处理 流处理对应实时计算 批处理对应离线计算 传统事务处理 传统的事务处理 就是最基本的流处理架构 缺点 传统事务处理对表和数据库的设计要求很高 当数据规模越来越庞大 系统越来
  • python中os模块中文帮助文档

    python中os模块中文帮助文档 翻译者 butalnd 翻译于2010 1 7 2010 1 8 个人博客 url http butlandblog appspot com url 注此模块中关于unix中的函数大部分都被略过 翻译主要
  • kafka面试题02

    kafka 消费者是否从指定偏移量开始消费 可以 通过seek指定偏移量后再开始消费 客户端操作kafka消息是采用poll模式 还是push模式 kafka最初考虑的问题是 customer应该从brokes拉取消息还是brokers将消
  • topaz sharpen ai怎么设置为中文

    topaz sharpen ai是一款非常强大的图片锐化处理工具 采用了先进的人工智能技术 即使在手持 夜间或在浅景深拍摄时也可以创建清晰的图像 但该软件默认是英文语言 不支持简体中文语言 让国内许多用户都无从下手 所以小编带来了topaz
  • Oracle的load_balance和failover

    jdbc oracle thin description TRANSPORT CONNECT TIMEOUT 1 address list load balance off failover on address protocol tcp
  • RC并联电路常见应用总结

    阻容串联电路应用可以参考以下链接 链接 https blog csdn net weixin 45633643 article details 107740111
  • 十分钟掌握Keras实现RNN的seq2seq学习

    作者 Francois Chollet 编译 雁惊寒 seq2seq是一种把序列从一个域 例如英语中的句子 转换为另一个域中的序列 例如把相同的句子翻译成法语 的模型训练方法 目前有多种方法可以用来处理这个任务 可以使用RNN 也可以使用一
  • 使用OpenCV和Python,OCR识别数字

    使用OpenCV和Python OCR识别数字 1 效果图 2 原理 2 1 什么是七段显示器 2 2 识别数字步骤 3 源码 参考 这篇博客将演示如何使用OpenCV和Python识别图像中的数字 该方法只适用于七段显示器 通常在数字闹钟
  • 【ChatGPT】如何让 ChatGPT 不再频繁报错,获取更加稳定的体验?

    文章目录 一 问题描述 二 方案1 使用 OpenAI API Key 来访问 ChatGPT 三 方案2 安装 Chrome 插件 3 1 介绍 3 2 安装步骤 3 2 1 插件 脚本安装 3 2 2 解读功能 一 问题描述 最近一段时
  • uni-app真机运行报错:plus is not defined

    前言 使用un app开发Android和IOS原生应用 在浏览器中调试时 报错 plus is not defined 原因 plus是5 Runtime的内部对象 普通浏览器里没有plus环境 只有HBuilder真机运行 打包后 或流
  • Pycharm安装教程以及Pycharm汉化教程,超级详细

    1 下载安装包 去pycharm官网下载安装包pycharm官网 步骤如下 下载完成后点击安装 2 点击安装包开始安装 到此pycharm安装完成 3 开始使用pycharm 点击安装好的pycharm进入 创建项目 选择项目路径 选择需要
  • openlayer 5 MultiLineString 渲染多颜色

    预览图 public GetTraffficSpeed Observable
  • 使用three.js导入外部glb模型实现一个nft产品

    nft数字藏品大火 各家公司都推出自己的app和小程序 那么炫酷的3D藏品到底如何实现的呢 我们来一探究竟 需求背景 随着各家数字藏品项目上线 我们团队也紧随潮流打算在短期内开发一款数字藏品的产品 主要有哪些需求呢 当然就是别人有什么我们也