4. 导入gltf文件

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

 

posted @ 2022-10-18 14:18  sky-su  阅读(220)  评论(0)    收藏  举报