文章目录
前言
本文将从threejs引入3d模型讲起,到react fiber引入3d模型结束。
一、threejs引入3d模型(html版本)
1. 完整代码
<!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>3D人像</title>
</head>
<body>
<script src="../libs/build/three.min.js"></script>
<script src="../libs/jsm/loaders/GLTFLoader.js"></script>
<script src="../libs/jsm/controls/OrbitControls.js"></script>
<script src="../libs/jsm/Clock.js"></script>
<script>
// import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
let scene, camera, renderer, controls;
var root;
function initScene() {
//场景
scene = new THREE.Scene();
// 创建一个纹理图片加载器加载图片
var textureLoader = new THREE.TextureLoader();
// 加载背景图片
var texture = textureLoader.load('../images/background.jpg');
// 纹理对象Texture赋值给场景对象的背景属性.background
scene.background = texture;
}
function initCamera() {
//相机
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200);
camera.position.set(0, 15, 50);
}
function initRenderer() {
//渲染器
renderer = new THREE.WebGLRenderer({ antiallias: true });
//设置渲染区域尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function initHilght() {
//环境光
hilght = new THREE.AmbientLight(0x404040, 10);
scene.add(hilght);
}
function initPeople() {
//导入3D模型
let loader = new THREE.GLTFLoader();
loader.load(
'../models/herbalist/scene.gltf',
function (gltf) {
root = gltf.scene;
//模型大小
root.scale.set(0.5, 0.5, 0.5);
//初始位置
root.translateX(-10);
scene.add(root);
renderer.render(scene, camera);
});
}
//渲染
function render() {
renderer.render(scene, camera);//执行渲染操作
requestAnimationFrame(render);//请求再次执行渲染函数render
}
function initControl() {
controls = new THREE.OrbitControls(camera, renderer.domElement)
//监听控制器的鼠标事件,执行渲染内容
controls.addEvemtListener('change', () => {
renderer.render(scene, camera)
})
}
function initLine() {
var geometry = new THREE.BufferGeometry(); //声明一个几何体对象Geometry
//参数:0, 0圆弧坐标原点x,y 100:圆弧半径 0, 2 * Math.PI:圆弧起始角度
var arc = new THREE.ArcCurve(0, 20, 15, 10, 1 * Math.PI);
//getPoints是基类Curve的方法,返回一个vector2对象作为元素组成的数组
var points = arc.getPoints(50);//分段数50,返回51个顶点
// setFromPoints方法从points中提取数据改变几何体的顶点属性vertices
geometry.setFromPoints(points);
//材质对象
var material = new THREE.LineBasicMaterial({
color: 0xffffff
});
//线条模型对象
var line = new THREE.Line(geometry, material);
scene.add(line); //线条对象添加到场景中
}
function init() {
initScene();
initCamera();
initRenderer();
initPeople();
initLine();
initHilght();
render();
}
init();
</script>
</body>
</html>
2. 代码详解
首先参考threejs官方文档中,引入3d模型的内容:
- 官方文档链接: Loading 3D models
关键代码:
- 引入js文件
<script src="../libs/jsm/loaders/GLTFLoader.js"></script>
- 按格式引入gltf文件
function initPeople() {
//导入3D模型
let loader = new THREE.GLTFLoader();
loader.load(
'../models/herbalist/scene.gltf',
function (gltf) {
root = gltf.scene;
//模型大小
root.scale.set(0.5, 0.5, 0.5);
//初始位置
root.translateX(-10);
scene.add(root);
renderer.render(scene, camera);
});
}
二、react fiber引入3d模型(react fiber版本)
1.代码详解
查看drei官方文档
如图所示,是useGLTF的用法/语法:
1.1 引入3d模型的资源
注意:
- 引入资源必须放在public文件夹下,否则会引入失败。(报错如图)
问题一:为什么“资源必须放在public文件夹下”?
引入知识点:
在React中有个Public文件夹可以放静态资源,但是在src目录中同样有个assets文件夹,这个同样也是放静态资源的,这个就很困惑了,为何放置静态资源的地方会有两个?
原因如下:
两者区别就在于是否会被webpack所处理。
- Public文件夹放静态资源
如果您将文件放入该public文件夹,webpack 将不会处理它,在你打包的时候,会将public文件夹直接复制一份到你构建出来的文件夹中。
好处:把一些不会改动的静态文件放到public中,可以:
- 减少文件构建时间,减少构建文件的大小
- 避免首页白屏时间过长
- src目录中assets文件夹放静态资源
资源会被webpack编译,比如图片,如果你的图片小于你在webpack中的loader下设置的limit大小(可配置),它会被编译成base64,从而在实际项目中减少http请求,放置在src/assets目录有以下几点好处:
- 脚本和样式表被缩小并捆绑在一起以避免额外的网络请求。
- 缺少文件会导致编译错误,而不是用户的404错误。
- 结果文件名包含内容哈希,因此您无需担心浏览器缓存旧版本。
问题二:引入 public 文件夹下的图片显示不出来?
注意!!该问题仅限于解决图片加载问题。
- 出现错误如图:无法加载public下的图片文件
- 解决办法:
- 在node_module文件夹下找到react-script/config/webpack.config.js,找到相应代码注释掉,然后重新启动项目,问题解决。(可以ctrl+f查找ModuleScopePlugin 相关的代码)
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
new ModuleScopePlugin(paths.appSrc, [
paths.appPackageJson,
reactRefreshOverlayEntry,
]),
问题三:无法加载 public 文件夹下的3D模型?
报错如图所示:models文件夹在public下,但是引用public下的models文件夹,3d模型引入失败,如图一,路径不存在,却可以引入成功(该问题仍未解决)
引入3d模型的完整代码:
import { useLoader } from '@react-three/fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
export function Man(){
const gltf = useLoader(GLTFLoader,'../../models/table_scene/girl/scene.gltf');
return(
<>
<primitive
object={gltf.scene}
position={[3,18,0]}
rotation={[Math.PI/2, 0, 0]}
scale={3}
/>
</>
);
}
1.2 需要引入的js文件
import { useLoader } from '@react-three/fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
1.3 使用3d模型
在需要使用3d模型的js文件中,用标签形式引用。
例如:我将3d模型建在man.jsx文件中的function Man()
函数中,引用时,
第一步:import { Man } from "../table/man"
第二步:
<Canvas>
{/* 3d模型放置 */}
<Table position={[0, 0, 0]} />
<Man />
<Canvas/>