现在让我们一起开始我们的学习。第一步将向您介绍使用Babylon.js创建场景,编写简单模型并将其导出的基础知识。不仅可以使用Babylon.js创建模型,还可以将在其他软件中创建的一系列模型类型导入Babylon.js。我们将展示如何将模型导入场景,并在场景中展示模型。我们将逐步建立一个简单的世界。在旅程的最后,我们将创建一个完善的小村庄场景,展示Babylon.js的功能。
是否想立即试用Babylon.js?每个页面上的示例还通过我们的交互式Playground呈现,您可以在其中编写,查看和尝试代码。可以在Playground上正确地运行的代码,并可以复制粘贴到HTML模板中,用作您的第一个3D Web应用程序。
目录
- 场景和物体
- 网页上的第一个模型
- 导入一个模型和场景
- 第一个3D Web应用
场景和物体
无论您是要创建整个世界,还是只是将一个模型放到网页中,您都需要一个场景(Scene)来包含该世界或模型,一台用于查看该世界或模型的摄像头(Camera),一个照明它的照明灯(Light),以及至少一个可视对象作为一个对象。所有模型,无论是一个简单的盒子还是复杂的人物角色,都是由三角形或四边形的网格(Mesh)组成的。网格(Mesh)是物体的基本组成单位。
显示网格三角形的线框视图
您可以使用代码直接在Babylon.js中创建大量网格,也可以从其他软件创建的网格中将其作为模型导入。让我们从一个制作一个盒子开始。
所有使用Babylon.js引擎的项目都需要一个带有摄像头(Camera)和灯光(Light)的场景。然后,我们再创建我们的盒子。
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 3, new BABYLON.Vector3(0, 0, 0), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
const box = BABYLON.MeshBuilder.CreateBox("box", {}, scene);
像使用MeshBuilder创建的大多数网格物体一样,创建该线框物体时会将其中心定位在原点,并且需要三个参数。这些是“name","options"和”场景(Scene)“。通过将选项保留为没有属性的空对象{},这个现况物体的宽度,高度和深度默认为单位大小。
为了在Playground上可用,我们需要将它们放在一个名为createScene的函数中,该函数必须返回一个scene。
const createScene = () => {
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 3, new BABYLON.Vector3(0, 0, 0));
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0));
const box = BABYLON.MeshBuilder.CreateBox("box", {});
return scene;
}
创建线框物体(Mesh)后,我们可以通过选择“Inspector”,可以保存或导出场景
然后是选择工具,然后选择要导出的类型,.babylon格式或GLB格式。
网页上的第一个模型
如果文件类型是Babylon.js可以识别的文件类型,那么您可以使用< Babylon >元素使用Babylon.js Viewer在网页上显示场景或模型。支持的文件类型包括.babylon,.gltf和glb,建议使用.glb。
使用查看器之前,您需要在< script >元素中将其代码添加到HTML页面中
<script src="https://cdn.babylonjs.com/viewer/babylon.viewer.js"></script>
< bablon >可以自适应容器,将其model属性指向文件路径。
<babylon model="Path to File"></babylon>
导入一个模型和场景
实际上,将模型放入场景中时,就是将其加载到浏览器中。如您所知,当您将任何内容加载到网站中时,它都是异步的。在对模型执行任何操作之前,您需要知道它们已加载。您可以使用做到这一点ImportMeshAsync的方法SceneLoader,它的形式
BABYLON.SceneLoader.ImportMeshAsync(model name, folder path, file name, scene);
scene参数是可选的,并且默认为当前场景。第一个参数可以是三种类型,具体取决于您是要加载所有模型,还是仅加载一个模型或一系列模型。
BABYLON.SceneLoader.ImportMeshAsync("", "/relative path/", "myFile");
//为空表示加载所有模型
BABYLON.SceneLoader.ImportMeshAsync("model1", "/relative path/", "myFile");
//加载一个模型
BABYLON.SceneLoader.ImportMeshAsync(["model1", "model2"], "/relative path/", "myFile");
//使用数组加载多个模型
以上所有内容仅会加载模型,您将无法以任何方式对其进行操作。您已经设置了Promise对象,但是在实现Promise并提供结果之后,没有采取任何措施。在下面的两个游乐场中,是仅导入命名模型的示例演示。
为了对加载的模型进行操作,我们在Promise之后使用then方法,result是含有模型的所有属性,result.meshes包含所有加载的模型。我们可以使用此数组或其名称来操纵每个网格模型。
BABYLON.SceneLoader.ImportMeshAsync("", "/relative path/", "myFile").then((result) => {
result.meshes[1].position.x = 20;
const myMesh_1 = scene.getMeshByName("myMesh_1");
myMesh1.rotation.y = Math.PI / 2;
});
该示例将导入的模型改变了位置并进行旋转。
提醒
不同类型的模型导入的数据的数据结构也不同
-
某些软件会使用rotationQuaternion集保存所有网格,除非您先添加该属性,否则无法使用rotation方法
myMesh.rotationQuaternion = null; //Any version of Babylon.js myMesh.rotation = BABYLON.Vector3(); //babylon.js versions > 4.00
2.以下两种类型是从完全相同的场景导出的,并导入到Babylon.js中。
.babylon 导入的数据结构。
detached_house
ground
semi_house
.glb 导入的数据结构。
_root_
detached_house
detached_house primitive0
detached_house primitive1
ground
semi_house
semi_house primitive0
semi_house primitive1
第一个3D Web应用
导入一个模型示例
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>Babylon Template</title>
<style>
html, body {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#renderCanvas {
width: 100%;
height: 100%;
touch-action: none;
}
</style>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script> <script src="https://code.jquery.com/pep/0.4.3/pep.js"></script> </head>
<body>
<canvas id="renderCanvas" touch-action="none"></canvas> <!-- touch-action="none" for best results from PEP -->
<script>
const canvas = document.getElementById("renderCanvas"); // 获取canvas对象
const engine = new BABYLON.Engine(canvas, true); // 创建BABYLON 3D 引擎
// Add your code here matching the playground format
const createScene = function () {
const scene = new BABYLON.Scene(engine);
BABYLON.SceneLoader.ImportMeshAsync("", "https://assets.babylonjs.com/meshes/", "box.babylon");
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 15, new BABYLON.Vector3(0, 0, 0));
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0));
return scene;
};
const scene = createScene(); //调用createScene方法
// 轮询渲染
engine.runRenderLoop(function () {
scene.render();
});
// 监听浏览器resize事件
window.addEventListener("resize", function () {
engine.resize();
});
</script>
</body>
</html>
使用代码创建一个模型示例
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Babylon Template</title>
<style>
html, body {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#renderCanvas {
width: 100%;
height: 100%;
touch-action: none;
}
</style>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script> <script src="https://code.jquery.com/pep/0.4.3/pep.js"></script> </head>
<body>
<canvas id="renderCanvas" touch-action="none"></canvas> <!-- touch-action="none" for best results from PEP -->
<script>
const canvas = document.getElementById("renderCanvas"); // Get the canvas element const engine = new BABYLON.Engine(canvas, true); // Generate the BABYLON 3D engine
// Add your code here matching the playground format
const createScene = function () {
const scene = new BABYLON.Scene(engine);
BABYLON.MeshBuilder.CreateBox("box", {})
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 15, new BABYLON.Vector3(0, 0, 0));
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0));
return scene;
};
const scene = createScene(); //Call the createScene function
// Register a render loop to repeatedly render the scene
engine.runRenderLoop(function () {
scene.render();
});
// Watch for browser/canvas resize events
window.addEventListener("resize", function () {
engine.resize();
});
</script>
</body>
</html>