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 * 这代表了一种自由类型的相机。它可以在第一人称射击游戏中发挥作用。
58 * 请考虑使用新的万能相机(new UniversalCamera),因为它增加了更多的功能,如手柄。
59 * new FreeCamera(name: string, position: Vector3, scene?: Scene, setActiveOnSceneIfNoneActive?: boolean): FreeCamera
60 * name: 在场景中定义摄像机的名称
61 * position: 定义摄像机在场景中的起始位置
62 * scene: 定义相机所属的场景
63 * setActiveOnSceneIfNoneActive: 定义如果未定义其他活动相机,则是否应将该相机标记为活动的
64 */
65 // const camera = new BABYLON.FreeCamera(
66 // "camera1",
67 // new BABYLON.Vector3(0, 5, -10),
68 // scene
69 // );
70
71 /**
72 * setTarget(target: Vector3): void---定义相机应该看的目标。
73 * attachControl(noPreventDefault?: boolean): void
74 * attachControl(ignored: any, noPreventDefault?: boolean): void---将输入控件附加到要从中获取输入的特定dom元素上。
75 * Vector3.Zero
76 * 返回一个新的Vector3,设为(0.0,0.0,0.0)
77 */
78 // camera.setTarget(BABYLON.Vector3.Zero());
79 // camera.attachControl(renderCanvas2.value, true);
80
81 /**
82 * new ArcRotateCamera(name: string, alpha: number, beta: number, radius: number, target: Vector3, scene?: Scene, setActiveOnSceneIfNoneActive?: boolean): ArcRotateCamera
83 * 在给定的场景中实例化一个新的ArcRotateCamera
84 * name: 名字
85 * alpha: 定义相机沿纵向轴的旋转---一开始显示的角度
86 * beta: 定义相机沿纬度轴的旋转---一开始显示的角度
87 * radius: 定义相机与目标的距离
88 * target: Vector3
89 * setActiveOnSceneIfNoneActive: 定义如果未定义其他活动相机,则是否应将该相机标记为活动的
90 *
91 * new Tools(): Tools
92 * ToRadians(angle: number): number
93 * 将角度的角度转换为弧度
94 */
95 const camera = new BABYLON.ArcRotateCamera(
96 "camera",
97 BABYLON.Tools.ToRadians(90),
98 BABYLON.Tools.ToRadians(65),
99 18,
100 BABYLON.Vector3.Zero(),
101 scene
102 );
103 // https://doc.babylonjs.com/typedoc/classes/BABYLON.ArcRotateCamera#constructor
104 camera.attachControl(renderCanvas2.value, true);
105
106 /**
107 * new HemisphericLight(name: string, direction: Vector3, scene: Scene): HemisphericLight
108 * 根据传递的方向(Vector3)在场景中创建一个半球光对象。
109 半球光模拟周围环境光,所以通过的方向是光的反射方向,而不是入射方向。
110 半球光不能投射阴影。
111 */
112
113 /**
114 * name: 灯光的名字
115 * direction: 光反射的方向
116 * scene: 灯光所属的场景
117 */
118 const light = new BABYLON.HemisphericLight(
119 "light",
120 /**
121 * new Vector3(x?: number, y?: number, z?: number): Vector3
122 * 从给定的x, y, z (float)坐标创建一个新的Vector3对象。三维向量
123 * x: number; 定义第一个坐标(在X轴上)
124 * y: number
125 * z: number
126 */
127 new BABYLON.Vector3(0, 1, 0),
128 scene
129 );
130
131 /**
132 * 光的强度。
133 注意:默认情况下它是在框架自己的单元中定义的。
134 注:在PBR材料中,intensityMode可用于选择强度的定义单位。
135 */
136 light.intensity = 0.7;
137
138 // 创建球
139 /**
140 * MeshBuilder 创建物体,CreateSphere中的sphere是可以替换成其他的
141 * sphere是球体
142 * 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
143 * CreateShape(name, options, scene);
144 * name: 表示这个物体的名称;
145 * options: 选项;https://doc.cnbabylon.com/4-0-discover-basic-elements/
146 * scene: 表示你加入的场景
147 */
148 // const sphere = BABYLON.MeshBuilder.CreateSphere(
149 // "sphere",
150 // {
151 // diameter: 2,
152 // segments: 32,
153 // },
154 // scene
155 // );
156
157 /**
158 * sphere.position => Vector
159 * 获取或设置y坐标
160 返回数
161 获取或设置y坐标
162 */
163 // sphere.position.y = 1;
164
165 // 创建地面
166 /**
167 * Ground: 地面
168 CreateGround(name: string, options?: { height?: number; subdivisions?: number; subdivisionsX?: number; subdivisionsY?: number; updatable?: boolean; width?: number }, scene?: Scene): GroundMesh
169 *
170 * 参数width和height(浮动,默认值1)设置了地面的宽度和高度大小
171 参数subpartitions(正整数)设置每条边的细分数量
172 网格可以设置为可更新的布尔参数updatable(默认为false),如果它的内部几何形状应该在创建后改变
173 *name: 定义网格的名称
174 options: https://doc.babylonjs.com/typedoc/modules/BABYLON#CreateGround-2
175 scene: Scene
176 */
177 const ground = BABYLON.MeshBuilder.CreateGround(
178 "ground",
179 {
180 width: 6,
181 height: 6,
182 },
183 scene
184 );
185
186 /**
187 * 实例化一个新的标准材质。
188 这是在巴比伦使用的默认材料。这是质量之间最好的权衡和表演。
189 * new StandardMaterial(name: string, scene?: Scene): StandardMaterial
190 * name: 名字
191 * scene: 定义素材所属的场景
192 */
193 const groundMaterial = new BABYLON.StandardMaterial("Ground Material", scene);
194
195 ground.material = groundMaterial;
196 // ground.material.diffuseColor = BABYLON.Color3.Red(); // 让地面背景变色
197
198 /**
199 * 这代表了巴比伦的纹理。它可以很容易地从网络、base64或html输入加载。
200 * new Texture(url: Nullable<string>, sceneOrEngine?: Nullable<Scene | ThinEngine>, noMipmapOrOptions?: boolean | ITextureCreationOptions, invertY?: boolean, samplingMode?: number, onLoad?: Nullable<(() => void)>, onError?: Nullable<((message?: string, exception?: any) => void)>, buffer?: Nullable<string | ArrayBufferView | Blob | ArrayBuffer | HTMLImageElement | ImageBitmap>, deleteBuffer?: boolean, format?: number, mimeType?: string, loaderOptions?: any, creationFlags?: number, forcedExtension?: string): Texture
201 * https://doc.babylonjs.com/typedoc/classes/BABYLON.Texture#constructor
202 */
203 const groundTexture = new BABYLON.Texture(
204 Assets.textures.checkerboard_basecolor_png.rootUrl,
205 scene
206 );
207 ground.material.diffuseTexture = groundTexture; // 网格地面
208
209 /**
210 * 读取一个gltf文件
211 * new SceneLoader(): SceneLoader
212 * ImportMesh(meshNames: any, rootUrl: string, sceneFilename?: string | File, scene?: Nullable<Scene>, onSuccess?: Nullable<SceneLoaderSuccessCallback>, onProgress?: Nullable<((event: ISceneLoaderProgressEvent) => void)>, onError?: Nullable<((scene: Scene, message: string, exception?: any) => void)>, pluginExtension?: Nullable<string>): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>
213 *onSuccess: 当导入成功时,一个带有导入网格、particleSystems、skeleton和animationGroups列表的回调函数
214 * Assets.meshes.Yeti.rootUrl,
215 * Assets.meshes.Yeti.filename,
216 * ImportMesh这个方法导入需要3张图片,*.bin,*.glft
217 */
218 BABYLON.SceneLoader.ImportMesh(
219 "",
220 "/src/assets/yeti/",
221 Assets.meshes.Yeti.filename,
222 scene,
223 function (newMeshes) {
224 console.log("newMeshes", newMeshes);
225 newMeshes[0].scaling = new BABYLON.Vector3(0.1, 0.1, 0.1); // 控制图像的缩放的
226 }
227 );
228 return scene;
229 }
230
231 function createDefaultEngine() {
232 /**
233 * new Engine(canvas, antialias, options, adaptToDeviceRatio) 创建一个引擎
234 * canvas: 现实容器,可以是Canvas标签...
235 * antialias: boolean, 默认是false,启动后可以防止图像出现“锯齿”
236 * optiosn: 选项,
237 * adaptToDeviceRatio: false, // 定义是否适应设备的视口特征
238 audioEngine: false, // 定义是否也应该初始化webaudio
239 audioEngineOptions: {}, // 指定音频引擎的选项
240 autoEnableWebVR: false, // 定义是否应该自动启用webvr
241 deterministicLockstep: false, // 定义动画是否应该使用确定性锁定步骤运行
242 * adaptoToDeviceRatio: boolean,默认false;定义是否适应视口
243 ....
244 https://doc.babylonjs.com/typedoc/interfaces/BABYLON.EngineOptions
245 */
246 return new BABYLON.Engine(renderCanvas2.value, true, {});
247 }
248
249 async function initFunction() {
250 async function asyncEngineCreation() {
251 try {
252 return createDefaultEngine(); // 先创建容器
253 } catch (e) {
254 console.log(
255 "the available createEngine function failed. Creating the default engine instead"
256 );
257
258 return createDefaultEngine();
259 }
260 }
261
262 engine = await asyncEngineCreation(); // 先创建容器
263 if (!engine) throw "engine should not be null.";
264 startRenderLoop(engine); // 如果没有这个不会出现图像
265 scene = createScene(); // 再创建渲染场景
266 // 创建容器 ---> 再创建渲染场景放进容器 ---> 再创建"相机","灯光","球体","地面"放进场景
267 scene && scene.render();
268 }
269
270 onMounted(() => {
271 if (renderCanvas2.value) {
272 console.log("ttttt");
273 initFunction().then(() => {
274 sceneToRender = scene;
275 });
276
277 // Resize
278 window.addEventListener("resize", function () {
279 engine && engine.resize();
280 });
281 }
282 });
283 </script>
284
285 <style lang="scss" scoped>
286 .badylon-canvas2 {
287 width: 100%;
288 height: 100%;
289
290 #render-canvas2 {
291 width: 100%;
292 height: 100%;
293 // touch-action 用在触摸屏,缩放
294 touch-action: none;
295 }
296 }
297 </style>