React + typescript + umi + Babylonjs 搭建基础场景
yarn add --save babylonjs babylonjs-loaders
1、封装基础场景
import { Engine, Scene } from "babylonjs";
import { useEffect,useRef,FC } from "react";
import "./index.less"
type PropsType = {
antalias:any;
engineOptions?:any;
adaptToDeviceRatio?:any;
sceneOptions?:any;
onRender:(scene:Scene)=>void;
onSceneReady:any;
[key:string]:any;
}
const BaseScene:FC<PropsType>=(props)=>{
const {antalias,engineOptions,adaptToDeviceRatio,sceneOptions,onRender,onSceneReady,...rests} = props
// 获取canvas画布
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(()=>{
const {current:canvas} = canvasRef
if(!canvas)return
// 创建babylonjs 引擎
const engine = new Engine(canvas,antalias,engineOptions ,adaptToDeviceRatio);
// 创建场景
const scene = new Scene(engine,sceneOptions)
// 搭建场景
if(scene.isReady()){
onSceneReady(scene)
}else{
scene.onReadyObservable.addOnce((scene)=>onSceneReady(scene))
}
// 帧渲染
engine.runRenderLoop(()=>{
if(typeof onRender === 'function') onRender?.(scene);
scene?.render();
})
const resize=()=>{
scene.getEngine().resize()
}
// 监听画布大小
if(window){
window.addEventListener('resize',resize)
}
// 销毁
return ()=>{
scene.getEngine().dispose()
if(window){
window.removeEventListener('resize',resize)
}
}
},[antalias,engineOptions,adaptToDeviceRatio,sceneOptions,onRender,onSceneReady])
return <canvas ref={canvasRef} className="renderCanvas" {...rests}/>
}
export default BaseScene
2、封装应用场景
import { ArcRotateCamera, HemisphericLight, MeshBuilder, Scene, Vector3 } from "babylonjs";
import 'babylonjs-loaders'
import BaseScene from "./BaseScene";
let box:any;
const onSceneReady=async (scene:Scene)=>{
// 创建相机
const camera = new ArcRotateCamera('camera',0,0.8,100,Vector3.Zero(),scene)
// 设置相机目标
camera.setTarget(Vector3.Zero());
// 获取画布
const canvas = scene.getEngine().getRenderingCanvas();
// 添加控制器
camera.attachControl(canvas,true);
// 框架行为
camera.useFramingBehavior =true;
// 添加灯光
const light = new HemisphericLight('light',new Vector3(0,1,0),scene)
// 设置强度
light.intensity = 0.7;
// 创建box
box = MeshBuilder.CreateBox('box',{size:2},scene)
box.position.y= 1;
// 相机目标
camera.setTarget(box)
MeshBuilder.CreateGround('ground',{width:6,height:6},scene)
}
const onRender=(scene:Scene)=>{
if(box !== undefined){
const deltTime = scene.getEngine().getDeltaTime();
const rpm = 10;
box.rotation.y += (rpm / 60) * Math.PI * 2 * (deltTime / 1000);
}
}
export default ()=>
<BaseScene antalias onSceneReady={onSceneReady} onRender={onRender} id="canvas" />
3、应用场景
import BaseScene from '@/components/Robot';
import { PageContainer } from '@ant-design/pro-components';
import styles from './index.less';
const HomePage: React.FC = () => {
return (
<PageContainer ghost>
<div className={styles.container}>
<BaseScene />
</div>
</PageContainer>
);
};
export default HomePage;