1 <template>
2 <div class="badylon-canvas2">
3 <canvas ref="renderCanvas2" id="render-canvas2"></canvas>
4 </div>
5 </template>
6
7 <script setup lang="ts">
8 import * as BABYLON from "babylonjs";
9 import "babylonjs-loaders";
10 import Assets from "../../utils/babylon/babylon-asset.js";
11 import type { Engine, Scene } from "babylonjs";
12 import { ref, onMounted } from "vue";
13
14 type EngineType = Engine | null;
15 type SceneType = Scene | null;
16
17 const renderCanvas2 = ref<HTMLCanvasElement | null>(null);
18 let engine: EngineType = null;
19 let scene: SceneType = null;
20 let sceneToRender: SceneType = null;
21
22 // 渲染循环
23 function startRenderLoop(engine: Engine) {
24 /**
25 * runRenderLoop(renderFunction: (() => void)): void
26 * 注册并执行一个渲染循环。引擎可以有多个渲染函数
27 * renderFunction: (() => void) --- 定义要持续执行的函数(不停的执行)
28 */
29 engine.runRenderLoop(() => {
30 console.log("runRenderLoop...");
31 // 如果没有runRenderLoop函数,就无法在移动图像时更新“相机”的数据,简单来说就是图像不会动了。
32 if (sceneToRender && sceneToRender.activeCamera) {
33 /**
34 * render(updateCameras?: boolean, ignoreAnimations?: boolean): void
35 * updateCameras: 定义一个布尔值,指示摄像机是否必须根据其输入进行更新(默认为true)
36 * ignoreAnimations: 定义一个布尔值,指示动画是否不应该执行(默认为false)
37 */
38 sceneToRender.render(); // 如果没有这个不会出现图像;渲染scene
39 }
40 });
41 }
42
43 // 创建场景
44 function createScene() {
45 if (engine === null) return null;
46
47 /**
48 * new Scene(engine: Engine, options?: SceneOptions): Scene
49 * 表示要由引擎渲染的场景。
50 * engine: Engine --- 定义用于渲染此场景的引擎
51 * options: 可选; https://doc.babylonjs.com/typedoc/interfaces/BABYLON.SceneOptions
52 *
53 */
54 const scene = new BABYLON.Scene(engine);
55
56 /**
57 * new ArcRotateCamera(name: string, alpha: number, beta: number, radius: number, target: Vector3, scene?: Scene, setActiveOnSceneIfNoneActive?: boolean): ArcRotateCamera
58 * 在给定的场景中实例化一个新的ArcRotateCamera
59 * name: 名字
60 * alpha: 定义相机沿纵向轴的旋转---一开始显示的角度
61 * beta: 定义相机沿纬度轴的旋转---一开始显示的角度
62 * radius: 定义相机与目标的距离
63 * target: Vector3 // 控制相机的视角
64 * setActiveOnSceneIfNoneActive: 定义如果未定义其他活动相机,则是否应将该相机标记为活动的
65 *
66 * new Tools(): Tools
67 * ToRadians(angle: number): number
68 * 将角度的角度转换为弧度
69 */
70 const camera = new BABYLON.ArcRotateCamera(
71 "camera",
72 -Math.PI / 2,
73 Math.PI / 2.5,
74 3,
75 new BABYLON.Vector3(0, 0, 0),
76 scene
77 );
78 // https://doc.babylonjs.com/typedoc/classes/BABYLON.ArcRotateCamera#constructor
79 camera.attachControl(renderCanvas2.value, true);
80
81 /**
82 * new HemisphericLight(name: string, direction: Vector3, scene: Scene): HemisphericLight
83 * 根据传递的方向(Vector3)在场景中创建一个半球光对象。
84 半球光模拟周围环境光,所以通过的方向是光的反射方向,而不是入射方向。
85 半球光不能投射阴影。
86 */
87
88 /**
89 * name: 灯光的名字
90 * direction: 光反射的方向
91 * scene: 灯光所属的场景
92 */
93 const light = new BABYLON.HemisphericLight(
94 "light",
95 /**
96 * new Vector3(x?: number, y?: number, z?: number): Vector3
97 * 从给定的x, y, z (float)坐标创建一个新的Vector3对象。三维向量
98 * x: number; 定义第一个坐标(在X轴上)
99 * y: number
100 * z: number
101 */
102 new BABYLON.Vector3(0, 1, 0),
103 scene
104 );
105
106 /**
107 * 光的强度。
108 注意:默认情况下它是在框架自己的单元中定义的。
109 注:在PBR材料中,intensityMode可用于选择强度的定义单位。
110 */
111 light.intensity = 0.7;
112
113 const box = BABYLON.MeshBuilder.CreateBox("box", {});
114
115 return scene;
116 }
117
118 function createDefaultEngine() {
119 /**
120 * new Engine(canvas, antialias, options, adaptToDeviceRatio) 创建一个引擎
121 * canvas: 现实容器,可以是Canvas标签...
122 * antialias: boolean, 默认是false,启动后可以防止图像出现“锯齿”
123 * optiosn: 选项,
124 * adaptToDeviceRatio: false, // 定义是否适应设备的视口特征
125 audioEngine: false, // 定义是否也应该初始化webaudio
126 audioEngineOptions: {}, // 指定音频引擎的选项
127 autoEnableWebVR: false, // 定义是否应该自动启用webvr
128 deterministicLockstep: false, // 定义动画是否应该使用确定性锁定步骤运行
129 * adaptoToDeviceRatio: boolean,默认false;定义是否适应视口
130 ....
131 https://doc.babylonjs.com/typedoc/interfaces/BABYLON.EngineOptions
132 */
133 return new BABYLON.Engine(renderCanvas2.value, true, {});
134 }
135
136 async function initFunction() {
137 async function asyncEngineCreation() {
138 try {
139 return createDefaultEngine(); // 先创建容器
140 } catch (e) {
141 console.log(
142 "the available createEngine function failed. Creating the default engine instead"
143 );
144
145 return createDefaultEngine();
146 }
147 }
148
149 engine = await asyncEngineCreation(); // 先创建容器
150 if (!engine) throw "engine should not be null.";
151 startRenderLoop(engine); // 如果没有这个不会出现图像
152 scene = createScene(); // 再创建渲染场景
153 // 创建容器 ---> 再创建渲染场景放进容器 ---> 再创建"相机","灯光","球体","地面"放进场景
154 scene && scene.render();
155 }
156
157 onMounted(() => {
158 if (renderCanvas2.value) {
159 console.log("ttttt");
160 initFunction().then(() => {
161 sceneToRender = scene;
162 });
163
164 // Resize
165 window.addEventListener("resize", function () {
166 engine && engine.resize();
167 });
168 }
169 });
170 </script>
171
172 <style lang="scss" scoped>
173 .badylon-canvas2 {
174 width: 100%;
175 height: 100%;
176
177 #render-canvas2 {
178 width: 100%;
179 height: 100%;
180 // touch-action 用在触摸屏,缩放
181 touch-action: none;
182 }
183 }
184 </style>