如何用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项目开发,往往会用webpack
或vite
或其它方式配置一个开发环境。
如果只是学习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核心
// 引入three.js
import * as THREE from 'three';
npm安装后,如何引入three.js其他扩展库
除了three.js核心库以外,在threejs文件包中examples/jsm目录下,你还可以看到各种不同功能的扩展库。
一般来说,你项目用到那个扩展库,就引入那个,用不到就不需要引入。
// 引入扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入扩展库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.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目录获取到。
<script src="./build/three.js"></script>
//随便输入一个API,测试下是否已经正常引入three.js
console.log(THREE.Scene);
ES6 import方式引入
给script标签设置type="module",也可以在.html文件中使用import方式引入three.js。
<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"
代码具体写法不用掌握记忆,复制粘贴后,能修改目录就行,你可以去电子书课件或者课件源码中复制。
<!-- 具体路径配置,你根据自己文件目录设置,我的是课件中源码形式 -->
<script type="importmap">
{
"imports": {
"three": "../../../three.js/build/three.module.js"
}
}
</script>
<!-- 配置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/
<script type="importmap">
{
"imports": {
"three": "./three.js/build/three.module.js",
"three/addons/": "./three.js/examples/jsm/"
}
}
</script>
<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中物体由Geometries
和Materials
两部分组成,这就相当于电影中的道具枪一样,它由外形结构(几何体)
和材料颜色(材质)
组成。
5.Cameras
相机就相当于电影中用于拍摄的摄像机,相机拍摄的角度、远近场景的切换等由其控制。
6.Renderers
渲染器相当于电影的后期合成,我场景有了,物体也准备好了,相机拍摄完成了,就需要用渲染器把拍摄的东西通过合成展现出来。
一个简单的实例
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);
如果你发现这篇指南有用,或者有改进建议,请随时联系我们或参与讨论。🎉 🎉 🎉