本站公告

晚上好😎🫰

今天是2025年1月4日星期六

Santos
Creator @999-Blog.pro
https://github.com/SantosXXXE

Skip to content

如何用Three.js在静态页面显示模型

更新: 2024/12/10 字数: 0 字 时长: 0 分钟

Three.js和webGL的介绍

Three.js

是一款基于原生WebGL封装的Web 3D库,向外提供了许多的接口
它可以运用在在小游戏、产品展示、物联网、数字孪生、智慧城市园区、机械、建筑、全景看房、GIS等各个领域。

WebGL

WebGL(Web 图形库)是一个 JavaScript API,可在任何兼容的 Web 浏览器中渲染高性能的交互式 3D 和 2D 图形,而无需使用插件。WebGL 通过引入一个与 OpenGL ES 2.0 非常一致的 API 来做到这一点,该 API 可以在 HTML5 元素中使用。原生WebGL和图形学是Three.js的底层知识

编辑器与静态服务器

Web3D开发的代码编辑器和平时web前端开发一样,你可以根据自己的喜好选择,本课程选择的代码编辑器是vscode

平时学习Three.js,如果你想预览代码3D效果,咱们需要提供一个本地静态服务器的开发环境,如果你有一定的web前端基础,提到本地静态服务器肯定不陌生。

作为前端工程师,大家都知道,正式的web项目开发,往往会用webpackvite或其它方式配置一个开发环境。

如果只是学习threejs的话,没必要这么麻烦,我最建议的方式就是,通过代码编辑器快速创建本地静态服务器,比如vsocde,安装live-server插件即可。

开发环境如何引入three.js

比如你采用的是Vue + threejs或React + threejs技术栈,这很简单,threejs就是一个js库,直接通过npm命令行安装就行。

npm安装特定版本three.js(注意使用哪个版本,查文档就查对应版本)

npm install three@0.172.0 --save

npm安装后,如何引入three.js

执行import * as THREE from 'three';,ES6语法引入three.js核心

js
// 引入three.js
import * as THREE from 'three';

npm安装后,如何引入three.js其他扩展库

除了three.js核心库以外,在threejs文件包中examples/jsm目录下,你还可以看到各种不同功能的扩展库。

一般来说,你项目用到那个扩展库,就引入那个,用不到就不需要引入。

js
// 引入扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入扩展库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
js
// 扩展库引入——旧版本,比如122, 新版本路径addons替换了examples/jsm
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

学习环境如何引入three.js

如果不是正式开发Web3D项目,只是学习threejs功能,完全没必要用webpack或vite搭建一个开发环境。

学习使用的环境,只要创建一个.html文件,编写threejs代码,最后通过本地静态服务打开.html文件就行

script标签方式引入three.js

你可以像平时开发web前端项目一样,通过script标签把three.js当做一个js库引入你的项目。

three.js库可以在threejs官方文件包下面的build目录获取到。

html
<script src="./build/three.js"></script>
js
//随便输入一个API,测试下是否已经正常引入three.js
console.log(THREE.Scene);

ES6 import方式引入

给script标签设置type="module",也可以在.html文件中使用import方式引入three.js。

html
<script type="module">
// 现在浏览器支持ES6语法,自然包括import方式引入js文件
import * as THREE from './build/three.module.js';
</script>

type="importmap"配置路径

学习环境中,.html文件引入three.js,最好的方式就是参考threejs官方案例,通过配置<script type="importmap">,实现学习环境.html文件和vue或reaact脚手架开发环境一样的写法。这样你实际项目的开发环境复制课程源码,不用改变threejs引入代码。

下面配置的type="importmap"代码具体写法不用掌握记忆,复制粘贴后,能修改目录就行,你可以去电子书课件或者课件源码中复制。

html
<!-- 具体路径配置,你根据自己文件目录设置,我的是课件中源码形式 -->
<script type="importmap">
    {
		"imports": {
			"three": "../../../three.js/build/three.module.js"
		}
	}
</script>
html
<!-- 配置type="importmap",.html文件也能和项目开发环境一样方式引入threejs -->
<script type="module">
    import * as THREE from 'three';
    // 浏览器控制台测试,是否引入成功
    console.log(THREE.Scene);
</script>

type="importmap"配置——扩展库引入

通过配置<script type="importmap">,让学习环境.html文件,也能和vue或react开发环境中一样方式方式引入threejs扩展库。

配置addons/等价于examples/jsm/

html
<script type="importmap">
    {
		"imports": {
			"three": "./three.js/build/three.module.js",
            "three/addons/": "./three.js/examples/jsm/"
		}
	}
</script>
html
<script type="module">
    // three/addons/路径之后对应的是three.js官方文件包`/examples/jsm/`中的js库
    // 扩展库OrbitControls.js
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
    // 扩展库GLTFLoader.js
    import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
    console.log(OrbitControls);
    console.log(GLTFLoader);
</script>

Three.js中的六个重要概念

在使用three.js之前,要先了解three.js中的几个重要概念,分别是场景(Scenes)几何体(Geometries)材质(Materials)物体(Objects)相机(Cameras)渲染器(Renderers)

1.Scenes

场景的概念原本是戏剧、电影中的概念,指的是某一个特定的场面;three.js中的场景其实就是一个特定的场面,想象一下,假如你是导演,要拍一个火车进站的镜头,这就是一个场景

2.Geometries

几何体就是立体图形,如正方体、球、圆等图形;在场景中就相当于一个道具的外形结构;three.js中提供了很多几何体,如立方体(BoxGeometry)圆(CircleGeometry)圆锥(ConeGeometry)等,具体可查看three.js的官方文档

3.Materials

材质顾名思义就是物体的材料质感,比如颜色、透明度等,在场景中就相当于道具的颜色和材料,three.js中也提供了很多材质类接口,比如基础网格材质(MeshBasicMaterial)等,老规矩,具体的内容还是查看three.js的官方文档

4.Objects

物体也称对象,物体就是客观存在的一种物质,一个物体包括两方面的特性,即它的形状和材质。three.js中物体由GeometriesMaterials两部分组成,这就相当于电影中的道具枪一样,它由外形结构(几何体)材料颜色(材质)组成。

5.Cameras

相机就相当于电影中用于拍摄的摄像机,相机拍摄的角度、远近场景的切换等由其控制。

6.Renderers

渲染器相当于电影的后期合成,我场景有了,物体也准备好了,相机拍摄完成了,就需要用渲染器把拍摄的东西通过合成展现出来。

一个简单的实例

js


	import * as THREE from '../../build/three.module.js';
	window.THREE = THREE;
	
	
	
	// 1. 引入图片
	// import floor from "./images/floor_wood.jpg";
	
	// import { OrbitControls } from '../../examples/jsm/controls/OrbitControls.js'
	// import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r122/build/three.module.js';
	import {OrbitControls} from 'https://threejsfundamentals.org/threejs/resources/threejs/r122/examples/jsm/controls/OrbitControls.js';
	
	
	
	
	// 1. 创建渲染器,指定渲染的分辨率和尺寸,然后添加到body中
	const renderer = new THREE.WebGLRenderer({ antialias: true });
	renderer.pixelRatio = window.devicePixelRatio;
	renderer.setSize(window.innerWidth, window.innerHeight);
	document.body.append(renderer.domElement);
	
	// 2. 创建场景
	const scene = new THREE.Scene();
	
	// 3. 创建相机
	const camera = new THREE.PerspectiveCamera(
	  75,
	  window.innerWidth / window.innerHeight,
	  0.1,
	  1000
	);
	
	camera.position.set(5, 5, 10);
	
	camera.lookAt(0, 0, 0);
	
	// 4. 创建物体
	const axis = new THREE.AxesHelper(5);
	scene.add(axis);
	
	// 添加立方体
	// const geometry = new THREE.BoxGeometry(4, 4, 4);
	// const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
	
	// 1.
	// const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
	
	
	// 2. 初始化纹理加载器
	const textloader = new THREE.TextureLoader();
	
	
	const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
	scene.add(ambientLight);
	
	// 3.
	const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
	directionalLight.position.set(10, 10, 10)
	scene.add(directionalLight);
	
	const geometry = new THREE.BoxGeometry(4, 4, 4);
	const material = [
	  new THREE.MeshBasicMaterial({
	    map: textloader.load('./images/657.jpg')
	  }),
	  new THREE.MeshBasicMaterial({
	    map: textloader.load('./images/657.jpg')
	  }),
	  new THREE.MeshBasicMaterial({
	    map: textloader.load('./images/657.jpg')
	  }),
	  new THREE.MeshBasicMaterial({
	    map: textloader.load('./images/657.jpg')
	  }),
	  new THREE.MeshBasicMaterial({
	    map: textloader.load('./images/657.jpg')
	  }),
	  new THREE.MeshBasicMaterial({
	    map: textloader.load('./images/657.jpg')
	  }),
	];
	const cube = new THREE.Mesh(geometry, material);
	
	
	// const cube = new THREE.Mesh(geometry, material);
	scene.add(cube);
	
	// 1. 渲染器能够渲染阴影效果
	renderer.shadowMap.enabled = true;
	
	// 2. 该方向会投射阴影效果
	directionalLight.castShadow = true;
	
	cube.castShadow = true;
	
	// 4. 
	const planeGeometry = new THREE.PlaneGeometry(20, 20);
	// const planeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });
	
	// 3. 给地板加载纹理
	const planeMaterial = new THREE.MeshStandardMaterial({
	  map: textloader.load('./images/floor_wood.jpg')
	})
	
	const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
	planeMesh.rotation.x = -0.5 * Math.PI;
	planeMesh.position.set(0, -3, 0);
	planeMesh.receiveShadow = true;
	scene.add(planeMesh);
	
	// 5. 方向光的辅助线
	const directionalLightHelper = new THREE.DirectionalLightHelper(
	  directionalLight
	);
	scene.add(directionalLightHelper); // 辅助线
	
	
	cube.rotation.y = Math.PI / 4;
	
	// function animate() {
	//     requestAnimationFrame(animate);
	//     cube.rotation.y += 0.01;
	//     renderer.render(scene, camera);
	//   }
	    
	const controls = new OrbitControls(camera, renderer.domElement);
	controls.update();
	
	
	const clock = new THREE.Clock();
	
	function animate() {
	  requestAnimationFrame(animate);
	
	  const elapsedTime = clock.getElapsedTime(); // 返回已经过去的时间, 以秒为单位
	//   cube.rotation.y = elapsedTime * Math.PI; // 两秒自转一圈
	  cube.rotation.y = elapsedTime * 1; // 两秒自转一圈
	
	  renderer.render(scene, camera);
	}
	
	animate() 
	
	
	// // 5. 渲染
	// renderer.render(scene, camera);

如果你发现这篇指南有用,或者有改进建议,请随时联系我们或参与讨论。🎉 🎉 🎉