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 type { Engine, Scene } from "babylonjs";
10 import { ref, onMounted } from "vue";
11
12 type EngineType = Engine | null;
13 type SceneType = Scene | null;
14
15 const renderCanvas2 = ref<HTMLCanvasElement | null>(null);
16 let engine: EngineType = null;
17 let scene: SceneType = null;
18 let sceneToRender: SceneType = null;
19
20 function startRenderLoop(engine: Engine) {
21 /**
22 * runRenderLoop(renderFunction: (() => void)): void
23 * 注册并执行一个渲染循环。引擎可以有多个渲染函数
24 * renderFunction: (() => void) --- 定义要持续执行的函数(不停的执行)
25 */
26 engine.runRenderLoop(() => {
27 console.log("runRenderLoop...");
28 // 如果没有runRenderLoop函数,就无法在移动图像时更新“相机”的数据,简单来说就是图像不会动了。
29 if (sceneToRender && sceneToRender.activeCamera) {
30 /**
31 * render(updateCameras?: boolean, ignoreAnimations?: boolean): void
32 * updateCameras: 定义一个布尔值,指示摄像机是否必须根据其输入进行更新(默认为true)
33 * ignoreAnimations: 定义一个布尔值,指示动画是否不应该执行(默认为false)
34 */
35 sceneToRender.render(); // 如果没有这个不会出现图像;渲染scene
36 }
37 });
38 }
39
40 function createScene() {
41 if (engine === null) return null;
42
43 /**
44 * new Scene(engine: Engine, options?: SceneOptions): Scene
45 * 表示要由引擎渲染的场景。
46 * engine: Engine --- 定义用于渲染此场景的引擎
47 * options: 可选; https://doc.babylonjs.com/typedoc/interfaces/BABYLON.SceneOptions
48 *
49 */
50 // 这创建了一个基本的巴比伦场景对象(非网格)
51 const scene = new BABYLON.Scene(engine);
52
53 /**
54 * 这代表了一种自由类型的相机。它可以在第一人称射击游戏中发挥作用。
55 * 请考虑使用新的万能相机(new UniversalCamera),因为它增加了更多的功能,如手柄。
56 * new FreeCamera(name: string, position: Vector3, scene?: Scene, setActiveOnSceneIfNoneActive?: boolean): FreeCamera
57 * name: 在场景中定义摄像机的名称
58 * position: 定义摄像机在场景中的起始位置
59 * scene: 定义相机所属的场景
60 * setActiveOnSceneIfNoneActive: 定义如果未定义其他活动相机,则是否应将该相机标记为活动的
61 */
62 // 这将创建并定位一个空闲相机(非网格)
63 const camera = new BABYLON.FreeCamera(
64 "camera1",
65 new BABYLON.Vector3(0, 5, -10),
66 scene
67 );
68
69 // 这将相机定位到场景原点
70 camera.setTarget(BABYLON.Vector3.Zero());
71
72 // 这将相机连接到画布上
73 camera.attachControl(renderCanvas2.value, true);
74
75 /**
76 * new HemisphericLight(name: string, direction: Vector3, scene: Scene): HemisphericLight
77 * 根据传递的方向(Vector3)在场景中创建一个半球光对象。
78 半球光模拟周围环境光,所以通过的方向是光的反射方向,而不是入射方向。
79 半球光不能投射阴影。
80 */
81
82 /**
83 * name: 灯光的名字
84 * direction: 光反射的方向
85 * scene: 灯光所属的场景
86 */
87 // 这创建了一个光,瞄准0,1,0 -天空(非网格)
88 const light = new BABYLON.HemisphericLight(
89 "light",
90 /**
91 * new Vector3(x?: number, y?: number, z?: number): Vector3
92 * 从给定的x, y, z (float)坐标创建一个新的Vector3对象。三维向量
93 * x: number; 定义第一个坐标(在X轴上)
94 * y: number
95 * z: number
96 */
97 new BABYLON.Vector3(0, 1, 0),
98 scene
99 );
100
101 /**
102 * 光的强度。
103 注意:默认情况下它是在框架自己的单元中定义的。
104 注:在PBR材料中,intensityMode可用于选择强度的定义单位。
105 */
106 // 默认强度为1。让我们把灯光调暗一点
107 light.intensity = 0.7;
108
109 /**
110 * MeshBuilder 创建物体,CreateSphere中的sphere是可以替换成其他的
111 * sphere是球体
112 * CreateSphere(name: string, options?: { arc?: number; backUVs?: Vector4; diameter?: number; diameterX?: number; diameterY?: number; diameterZ?: number; frontUVs?: Vector4; segments?: number; sideOrientation?: number; slice?: number; updatable?: boolean }, scene?: Nullable<Scene>): Mesh
113 * CreateShape(name, options, scene);
114 * name: 表示这个物体的名称;
115 * options: 选项;https://doc.cnbabylon.com/4-0-discover-basic-elements/
116 * scene: 表示你加入的场景
117 */
118 const sphere = BABYLON.MeshBuilder.CreateSphere(
119 "sphere",
120 {
121 diameter: 2,
122 segments: 32,
123 },
124 scene
125 );
126
127 /**
128 * sphere.position => Vector
129 * 获取或设置y坐标
130 返回数
131 获取或设置y坐标
132 */
133 // 将球体向上移动1/2的高度
134 sphere.position.y = 1;
135
136 /**
137 * Ground: 地面
138 CreateGround(name: string, options?: { height?: number; subdivisions?: number; subdivisionsX?: number; subdivisionsY?: number; updatable?: boolean; width?: number }, scene?: Scene): GroundMesh
139 *
140 * 参数width和height(浮动,默认值1)设置了地面的宽度和高度大小
141 参数subpartitions(正整数)设置每条边的细分数量
142 网格可以设置为可更新的布尔参数updatable(默认为false),如果它的内部几何形状应该在创建后改变
143 *name: 定义网格的名称
144 options: https://doc.babylonjs.com/typedoc/modules/BABYLON#CreateGround-2
145 scene: Scene
146 */
147 const ground = BABYLON.MeshBuilder.CreateGround(
148 "ground",
149 {
150 width: 6,
151 height: 6,
152 },
153 scene
154 );
155
156 return scene;
157 }
158
159 function createDefaultEngine() {
160 /**
161 * new Engine(canvas, antialias, options, adaptToDeviceRatio) 创建一个引擎
162 * canvas: 现实容器,可以是Canvas标签...
163 * antialias: boolean, 默认是false,启动后可以防止图像出现“锯齿”
164 * optiosn: 选项,
165 * adaptToDeviceRatio: false, // 定义是否适应设备的视口特征
166 audioEngine: false, // 定义是否也应该初始化webaudio
167 audioEngineOptions: {}, // 指定音频引擎的选项
168 autoEnableWebVR: false, // 定义是否应该自动启用webvr
169 deterministicLockstep: false, // 定义动画是否应该使用确定性锁定步骤运行
170 * adaptoToDeviceRatio: boolean,默认false;定义是否适应视口
171 ....
172 https://doc.babylonjs.com/typedoc/interfaces/BABYLON.EngineOptions
173 */
174 return new BABYLON.Engine(renderCanvas2.value, true, {});
175 }
176
177 async function initFunction() {
178 async function asyncEngineCreation() {
179 try {
180 return createDefaultEngine(); // 先创建容器
181 } catch (e) {
182 console.log(
183 "the available createEngine function failed. Creating the default engine instead"
184 );
185
186 return createDefaultEngine();
187 }
188 }
189
190 engine = await asyncEngineCreation(); // 先创建容器
191 if (!engine) throw "engine should not be null.";
192 startRenderLoop(engine); // 如果没有这个不会出现图像
193 scene = createScene(); // 再创建渲染场景
194 // 创建容器 ---> 再创建渲染场景放进容器 ---> 再创建"相机","灯光","球体","地面"放进场景
195 scene && scene.render();
196 }
197
198 onMounted(() => {
199 if (renderCanvas2.value) {
200 console.log("ttttt");
201 initFunction().then(() => {
202 sceneToRender = scene;
203 });
204 }
205 });
206 </script>
207
208 <style lang="scss" scoped>
209 .badylon-canvas2 {
210 width: 100%;
211 height: 100%;
212
213 #render-canvas2 {
214 width: 100%;
215 height: 100%;
216 // touch-action 用在触摸屏,缩放
217 touch-action: none;
218 }
219 }
220 </style>