Babylon.js 支援多種 3D 檔案格式,但建議優先使用glTF (.gltf
) / GLB (.glb
),以下是幾種常見的檔案類型。
glTF(.gltf
) 被譽為「3D 界的 JPEG」。glTF 本身是一個 JSON 檔案,包含一個 .bin
檔案加上多個紋理圖片檔。它是一個為了在網路上高效傳輸和載入 3D 場景而設計的開放標準格式。它支援 PBR (物理基礎渲染)和動畫高效、可擴展、可互通的 3D 內容網路標準格式。不僅僅包含模型的外觀,還可以打包:
GLB(.glb
)是將所有glTF相關內容打包成一個檔案。對於網頁應用,建議使用GLB。
OBJ (.obj
)是個比較老的格式,不支援 PBR (物理基礎渲染)、不支援動畫。不適合需要動畫或複雜材質的網頁應用。
Babylon (.babylon
)是元老級的 Babylon.js 專案用的原生場景檔案格式,這種檔案格式會 包含3D 場景的所有細節,且只支援Babylon.js 的專案。在官網教學裡有時會看到這種格式的範例,但目前官方與社群都強烈推薦使用 glTF (.gltf
)。知道這個是就範例就好,請盡量不要使用。
就像寫網頁可以用css畫出圖案,也可以使用圖檔一樣。模型來源有兩種:引入外部模型 或 用基本模型去組裝。一般由於效能和藝術細節複雜度考量,主要會用引入外部模型 的方式。
模型是由建模軟體製作出來,常聽到的有Blender、Maya、3ds Max、Cinema 4D、SketchUp。
或是有像是在Sketchfab或TurboSquid 這樣龐大的 3D 模型市集,提供了數百萬個現成的模型。這讓開發者可以快速地搭建場景,而不需要事事都從零開始。
https://sketchfab.com/feed
3D模型的檔案格式並不能像jpg檔一樣直接用瀏覽器開啟。使用之前可以丟進babylon.js模型預覽沙盒確認模型正確性。也可以透過他直接將 FBX, OBJ, STL 等多種格式的檔案拖曳進去,自動轉換匯出為 .glb
檔案來使用。
babylon.js模型預覽沙盒:https://sandbox.babylonjs.com/
在上傳的時候要注意要把整個資料夾的檔案都框起來,拖曳丟進去一次上傳就應該要能讀出來。
我們延續(Feature - 單元一)的範例二程式碼,並做以下修改,執行後我們可以看到一個房子:
// 註解這段
// BABYLON.MeshBuilder.CreateBox("box", {});
// 加上這段
BABYLON.ImportMeshAsync("https://assets.babylonjs.com/meshes/both_houses_scene.babylon", scene, {
meshNames: "semi_house"
});
ImportMeshAsync是個常見用來載入3D模型最主要、最常用的指令。
這邊可以注意它是**回傳Promise,**目的就是確保先把模型先載入完成,因為模型比較大卻同時是主要要互動的對象,等他好再開始也是合理的吧。引入的方法參數中,
ImportMeshAsync(
source: SceneSource,
scene: Scene,
options?: ImportMeshOptions,
): Promise<ISceneLoaderAsyncResult>
interface ImportMeshOptions {
meshNames?: null | string | readonly string[];
name?: string;
onProgress?: (event: ISceneLoaderProgressEvent) => void;
pluginExtension?: string;
pluginOptions?: {
bvh?: { enabled?: boolean; loopMode?: number };
gltf?: {
alwaysComputeBoundingBox?: boolean;
alwaysComputeSkeletonRootNode?: boolean;
animationStartMode?: GLTFLoaderAnimationStartMode;
capturePerformanceCounters?: boolean;
compileMaterials?: boolean;
compileShadowGenerators?: boolean;
coordinateSystemMode?: GLTFLoaderCoordinateSystemMode;
createInstances?: boolean;
customRootNode?: Nullable<TransformNode>;
enabled?: boolean;
extensionOptions?: {
EXT_lights_ies?: { enabled?: boolean };
EXT_lights_image_based?: { enabled?: boolean };
EXT_materials_diffuse_roughness?: { enabled?: boolean };
EXT_mesh_gpu_instancing?: { enabled?: boolean };
EXT_meshopt_compression?: { enabled?: boolean };
EXT_texture_avif?: { enabled?: boolean };
EXT_texture_webp?: { enabled?: boolean };
ExtrasAsMetadata?: { enabled?: boolean };
KHR_animation_pointer?: { enabled?: boolean };
KHR_draco_mesh_compression?: { enabled?: boolean };
KHR_interactivity?: { enabled?: boolean };
KHR_lights_punctual?: { enabled?: boolean };
KHR_materials_anisotropy?: { enabled?: boolean };
KHR_materials_clearcoat?: { enabled?: boolean };
KHR_materials_diffuse_transmission?: { enabled?: boolean };
KHR_materials_dispersion?: { enabled?: boolean };
KHR_materials_emissive_strength?: { enabled?: boolean };
KHR_materials_ior?: { enabled?: boolean };
KHR_materials_iridescence?: { enabled?: boolean };
KHR_materials_pbrSpecularGlossiness?: { enabled?: boolean };
KHR_materials_sheen?: { enabled?: boolean };
KHR_materials_specular?: { enabled?: boolean };
KHR_materials_transmission?: { enabled?: boolean };
KHR_materials_unlit?: { enabled?: boolean };
KHR_materials_variants?: {
defaultVariant?: string;
enabled?: boolean;
onLoaded?: (controller: MaterialVariantsController) => void;
};
KHR_materials_volume?: { enabled?: boolean };
KHR_mesh_quantization?: { enabled?: boolean };
KHR_node_hoverability?: { enabled?: boolean };
KHR_node_selectability?: { enabled?: boolean };
KHR_node_visibility?: { enabled?: boolean };
KHR_texture_basisu?: { enabled?: boolean };
KHR_texture_transform?: { enabled?: boolean };
KHR_xmp_json_ld?: { enabled?: boolean };
MSFT_audio_emitter?: { enabled?: boolean };
MSFT_lod?: { enabled?: boolean; maxLODsToLoad?: number };
MSFT_minecraftMesh?: { enabled?: boolean };
MSFT_sRGBFactors?: { enabled?: boolean };
[key: string]: undefined | { enabled?: boolean; [key: string]: unknown };
};
loadAllMaterials?: boolean;
loadMorphTargets?: boolean;
loadNodeAnimations?: boolean;
loadOnlyMaterials?: boolean;
loadSkins?: boolean;
loggingEnabled?: boolean;
onCameraLoaded?: (camera: Camera) => void;
onMaterialLoaded?: (material: Material) => void;
onMeshLoaded?: (mesh: AbstractMesh) => void;
onParsed?: (loaderData: IGLTFLoaderData) => void;
onSkinLoaded?: (node: TransformNode, skinnedNode: TransformNode) => void;
onTextureLoaded?: (texture: BaseTexture) => void;
onValidated?: (results: IGLTFValidationResults) => void;
preprocessUrlAsync?: (url: string) => Promise<string>;
skipMaterials?: boolean;
targetFps?: number;
transparencyAsCoverage?: boolean;
useClipPlane?: boolean;
useGltfTextureNames?: boolean;
useRangeRequests?: boolean;
useSRGBBuffers?: boolean;
validate?: boolean;
};
obj?: {
computeNormals?: boolean;
enabled?: boolean;
importVertexColors?: boolean;
invertTextureY?: boolean;
invertY?: boolean;
materialLoadingFailsSilently?: boolean;
optimizeNormals?: boolean;
optimizeWithUV?: boolean;
skipMaterials?: boolean;
useLegacyBehavior?: boolean;
UVScaling?: Vector2;
};
splat?: { enabled?: boolean; flipY?: boolean; keepInRam?: boolean };
stl?: { enabled?: boolean };
[key: string]: undefined | { enabled?: boolean; [key: string]: unknown };
};
rootUrl?: string;
}
接下來下篇來說說用基本模型組裝的模型。