一,本文解决如下问题
1. 在react脚手架的项目中使用three.js
2. three.js在react中使用动态的纹理贴图遇到的路径问题
3. this.指向的丢失问题
二,在项目中使用three.js(默认你已经掌握创建react项目)
1.在项目中下载three.js第三方包,如果没有版本要求可直接安装,有版本需求可在后面加@版本
mpm i three
2.安装完成后在组建页面中进行使用,在组件的页面中引入下面的代码,这里我的控制器OrbitControls是修改过源码的,所以引入的是本地文件
3.做完下列工作后就可以进行three.js的编写了,这里使用的是jsx语法,类组件编程
3.1在render中添加承载canvas的容器
render() {
return (
{/* 承载canvas */}
<div
ref={this.canvas}
style={
{ width: "780px", height: "720px" }}
></div>
);
}
3.2在构造器中声明 场景,相机,渲染器,控制器,并在下面使用箭头函数的方式创建渲染函数(防止this丢失)
// 构造器
constructor(props) {
super(props);
this.scene = null;
this.camera = null;
this.renderer = null;
this.controls = null;
this.canvas = React.createRef(); //承载canvas的容器
}
// 初始化场景
initScene() {
this.scene = new THREE.Scene();
// 天空盒,可以不写下面的代码
let px = require("../public/skybox/nanji1/px.jpg");
let nx = require("../public/skybox/nanji1/nx.jpg");
let py = require("../public/skybox/nanji1/py.jpg");
let ny = require("../public/skybox/nanji1/ny.jpg");
let pz = require("../public/skybox/nanji1/pz.jpg");
let nz = require("../public/skybox/nanji1/nz.jpg");
//初始化天空盒
this.scene.background = new THREE.CubeTextureLoader().load([
px,
nx,
py,
ny,
pz,
nz,
]);
}
// 初始化相机
initCamera() {
this.camera = new THREE.PerspectiveCamera(
65,
window.innerWidth / window.innerHeight,
0.1,
1000
);
this.camera.position.set(-5, 0, 15);
}
// 初始化渲染器
initRenderer = () => {
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(
this.canvas.current.clientWidth,
this.canvas.current.clientHeight
);
this.renderer.setClearColor(0xeeeeee);
//告诉渲染器需要阴影效果
this.renderer.shadowMap.enabled = true;
// 将场景添加到页面中
this.canvas.current.appendChild(this.renderer.domElement);
};
//初始化控制器
initControls() {
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
//关闭左键拖拽(修改OrbitControls源码版本)
this.controls.enablePan = false;
//关闭可以缩放
this.controls.enableZoom = false;
}
//初始化动画函数
animate = () => {
requestAnimationFrame(this.animate);
this.renderer.render(this.scene, this.camera);
};
// 初始化three.js
init() {
this.initScene();
this.initCamera();
this.initRenderer();
this.initControls();
this.animate();
}
在react的声明周期中调用
// 生命周期,页面渲染完毕后调用
componentDidMount() {
this.init();
}
此时运行项目npm run start 可以在页面中得到下面效果,左边就把天空盒渲染出来了,如果你们不加天空盒,应该是一片黑色
三,解决动态路径问题渲染贴图纹理
1. 在react访问本地文件,路径要用require进行包装
2. require 只能是纯静态 或者 静态+动态的格式
渲染sprite的代码如下
// 只能是纯静态路径或者 静态+变量
url = require("../public/" + url);
// 处理贴图
const texture = new THREE.TextureLoader().load(url);
// 合成模型和材质
const cube = new THREE.BoxGeometry(w, 0, h);
const MeshBasicMaterial = new THREE.MeshBasicMaterial({ map: texture });
const mesh = new THREE.Mesh(cube, MeshBasicMaterial);
// 调整模型的位置
mesh.position.set(0, -20, 0);
this.scene.add(mesh);