{"id":14741,"date":"2024-11-28T08:00:36","date_gmt":"2024-11-27T23:00:36","guid":{"rendered":"http:\/\/www.gisdeveloper.co.kr\/?p=14741"},"modified":"2024-11-28T11:43:21","modified_gmt":"2024-11-28T02:43:21","slug":"babylon-js-tips","status":"publish","type":"post","link":"http:\/\/www.gisdeveloper.co.kr\/?p=14741","title":{"rendered":"Babylon.js &#8211; Tips"},"content":{"rendered":"<h3>\ubc14\ub85c \uc2dc\uc791\ud560 \uc218 \uc788\ub294 \ud504\ub85c\uc81d\ud2b8 \uad6c\uc131<\/h3>\n<p><code>git clone https:\/\/github.com\/GISDEVCODE\/babylonjs-with-javascript-starter.git \uc0dd\uc131\ud560\ud3f4\ub354<\/code><\/p>\n<h3>Mesh\uc758 Bounding Box \ud06c\uae30\uac12<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nconst getParentSize = parent => {\r\n  const sizes = parent.getHierarchyBoundingVectors()\r\n  const size = {\r\n    x: sizes.max.x - sizes.min.x,\r\n    y: sizes.max.y - sizes.min.y,\r\n    z: sizes.max.z - sizes.min.z\r\n  }\r\n  return size\r\n};\r\n<\/pre>\n<h3>HDR, ENV\ub97c \ud1b5\ud55c \uad11\uc6d0 \ubc0f \ubc30\uacbd<\/h3>\n<p>\ub370\uc774\ud130 \ud615\uc2dd\uc5d0 \ub530\ub77c \ucf54\ub4dc\ub3c4 \ub2ec\ub77c\uc9d0. \uba3c\uc800 HDR\uc5d0 \ub300\ud55c \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nconst hdrTexture = new BABYLON.HDRCubeTexture(\"christmas_photo_studio_01_2k.hdr\", this.#scene, 512);\r\nthis.#scene.environmentTexture = hdrTexture;\r\n\/* const skybox = *\/ this.#scene.createDefaultSkybox(this.#scene.environmentTexture);\r\n\/\/ skybox.visibility = 0.1;\r\n<\/pre>\n<p>ENV\uc5d0 \ub300\ud55c \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nthis.#scene.createDefaultEnvironment({\r\n  environmentTexture: \".\/forest.env\", \/\/ as lighting\r\n  skyboxTexture: \".\/forest.env\", \/\/ as background\r\n});\r\n<\/pre>\n<h3>\ub9e4\uc2dc\uc5d0 \ub300\ud55c \ub85c\uceec\uc88c\ud45c\uacc4\ucd95\uc758 \uc6d0\uc810\uc744 \uc720\uc9c0\ud558\uace0 \uc774\ub3d9<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nsphere.setPivotMatrix(BABYLON.Matrix.Translation(2, 2, 0), false);\r\n<\/pre>\n<h3>\uc5ec\ub7ec\uac1c\uc758 \ub9e4\uc2dc\ub85c \uad6c\uc131\ub41c \ubc30\uc5f4(meshes)\ub97c \ud558\ub098\uc758 Mesh\ub85c \ub9cc\ub4dc\ub294 \ucf54\ub4dc<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nconst singleMesh = Mesh.MergeMeshes(meshes as Mesh[], true, true, undefined, false, true);\r\n<\/pre>\n<h3>Three.js\uc758 Group\uc5d0 \ub300\uc751\ud558\ub294 \ud074\ub798\uc2a4\ub294 BABYLON.TransformNode\uc774\ub2e4.<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nasync #createModel() {\r\n  const { meshes } = await BABYLON.SceneLoader.ImportMeshAsync(\"\", \"\/\", \"Barrel_01_2k.gltf\");\r\n\r\n  this.#group = new BABYLON.TransformNode(\"group\", this.#scene);\r\n  meshes[1].parent = this.#group;\r\n  this.#group.position.y = -0.5;\r\n}\r\n<\/pre>\n<h3>WebGPU \ub80c\ub354\ub7ec \uc124\uc815<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nexport default class App {\r\n  #engine;\r\n  #scene;\r\n  #mesh;\r\n  \r\n  constructor() {\r\n    this.#setupBabylon();    \r\n  }\r\n\r\n  async #setupBabylon() {\r\n    const canvas = document.querySelector(\"canvas\");\r\n\r\n    this.#engine = new BABYLON.WebGPUEngine(canvas, { adaptToDeviceRatio: true });\r\n    await this.#engine.initAsync();\r\n    \r\n    this.#scene = new BABYLON.Scene(this.#engine);\r\n\r\n    this.#createCamera();\r\n    this.#createLight();\r\n    this.#createModel();\r\n    this.#setupEvents();\r\n  }\r\n\r\n  ...\r\n<\/pre>\n<h3>\uae30\ubcf8\uc801\uc73c\ub85c \uc0ac\uc6a9\ud558\ub294 \uc88c\ud45c\uacc4\ub294 \uc67c\uc190 \uc88c\ud45c\uacc4\uc774\ub2e4. \ud558\uc9c0\ub9cc \uc624\ub978\uc190 \uc88c\ud45c\uacc4\ub85c\uc758 \uc804\ud658\ub3c4 \uac00\ub2a5\ud55c\ub370 \uc544\ub798\uc758 \ucf54\ub4dc\ub97c \uc2e4\ud589\ud574 \uc8fc\uba74 \ubc14\ub85c \uc624\ub978\uc190 \uc88c\ud45c\uacc4\ub85c \uc804\ud658\ub418\uc5b4 \uc774\ub97c \uae30\uc900\uc73c\ub85c \uac1c\ubc1c\uc774 \uac00\ub2a5\ud558\ub2e4.<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nscene.useRightHandedSystem = true;\r\n<\/pre>\n<h3>glTF \ud615\uc2dd \ub4f1\uc744 \uac00\uc838\uc624\uae30 \uc704\ud574 \uc124\uce58\ud574\uc57c\ud560 \ud328\ud0a4\uc9c0<\/h3>\n<p><code>npm i babylonjs-loaders<\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nimport \"babylonjs-loaders\"\r\n\r\n..\r\n\r\n  #createModel() {\r\n    BABYLON.SceneLoader.ImportMeshAsync(\r\n      \"\", \r\n      \"https:\/\/assets.babylonjs.com\/meshes\/\", \"both_houses_scene.babylon\").then((result) => {\r\n        const house1 = this.#scene.getMeshByName(\"detached_house\");\r\n        house1.position.y = 2;\r\n        const house2 = result.meshes[2];\r\n        house2.position.y = 1;\r\n      }\r\n    );\r\n\r\n    BABYLON.SceneLoader.ImportMesh(\"\", \r\n      Assets.meshes.Yeti.rootUrl, Assets.meshes.Yeti.filename, \r\n      this.#scene, \r\n      (meshes) => {\r\n        meshes[0].scaling = new BABYLON.Vector3(0.1, 0.1, 0.1);\r\n      }\r\n    );\r\n  }\r\n<\/pre>\n<h3>\uc704 \ucf54\ub4dc\uc5d0\uc11c Assets\uc740 \ub2e4\uc74c \ucf54\ub4dc\uac00 \ud544\uc694\ud568<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\n&lt;script src=\"https:\/\/assets.babylonjs.com\/generated\/Assets.js\">&lt;\/script>\r\n<\/pre>\n<h3>\ub3c4 \ub2e8\uc704\ub97c \ub77c\ub514\uc5b8 \ub2e8\uc704\ub85c \ubcc0\uacbd\ud574\uc8fc\ub294 API<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nBABYLON.Tools.ToRadians(45);\r\n<\/pre>\n<h3>\ubb3c\ub9ac\uc5d4\uc9c4 \ud558\ubcf5(Havok)\uc744 \uc0ac\uc6a9\ud558\uae30 \uc704\ud574\uc11c\ub294 \uba3c\uc800 @babylonjs\/havok\ub97c \uc124\uce58\ud558\uace0 node_modules\/@babylonjs\/havok\/lib\/esm\/HavokPhysics.wasm \ud30c\uc77c\uc744 node_modules\/.vite\/deps \uacbd\ub85c\uc5d0 \ubcf5\uc0ac\ud574 \ub450\uc5b4\uc57c \ud55c\ub2e4. \uc544\ub798\ub294 \ucf54\ub4dc\uc608\uc2dc\uc774\ub2e4.<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nimport * as BABYLON from \"babylonjs\"\r\nimport HavokPhysics from \"@babylonjs\/havok\";\r\n\r\nexport default class App {\r\n  #engine;\r\n  #scene;\r\n\r\n  constructor() {\r\n    const canvas = document.querySelector(\"canvas\");\r\n    this.#engine = new BABYLON.Engine(canvas, true, { adaptToDeviceRatio: true });\r\n    this.#scene = new BABYLON.Scene(this.#engine);\r\n\r\n    this.#createCamera();\r\n    this.#createLight();\r\n    this.#createModel();\r\n    this.#setupEvents();\r\n  }\r\n\r\n  #createLight() {\r\n    this.#scene.createDefaultLight();\r\n  }\r\n\r\n  #createCamera() {\r\n    this.#scene.createDefaultCamera(true, false, true);\r\n    const camera = this.#scene.cameras[0];\r\n    camera.position = new BABYLON.Vector3(4, 4, 10);\r\n  }\r\n\r\n  async #createModel() {\r\n    const sphere = BABYLON.MeshBuilder.CreateSphere(\"sphere\", { diameter: 2, segments: 32 }, this.#scene);\r\n    sphere.position.y = 4;\r\n\r\n    const ground = BABYLON.MeshBuilder.CreateGround(\"ground\", { width: 10, height: 10 }, this.#scene);\r\n\r\n    const havokInstance = await HavokPhysics();\r\n    const hk = new BABYLON.HavokPlugin(true, havokInstance);\r\n    this.#scene.enablePhysics(new BABYLON.Vector3(0, -9.8, 0), hk);\r\n\r\n    const sphereAggregate = new BABYLON.PhysicsAggregate(\r\n      sphere, BABYLON.PhysicsShapeType.SPHERE,\r\n      { mass: 1, restitution: 0.75 }, this.#scene\r\n    );\r\n\r\n    const groundAggregate = new BABYLON.PhysicsAggregate(\r\n      ground, BABYLON.PhysicsShapeType.BOX,\r\n      { mass: 0 }, this.#scene\r\n    );\r\n\r\n    const viewer = new BABYLON.Debug.PhysicsViewer(this.#scene);\r\n    for (const mesh of this.#scene.meshes) {\r\n      if (mesh.physicsBody) {\r\n        viewer.showBody(mesh.physicsBody);\r\n      }\r\n    }\r\n  }\r\n\r\n  #setupEvents() {\r\n    window.addEventListener(\"resize\", this.#resize.bind(this));\r\n    this.#scene.registerBeforeRender(this.update.bind(this));\r\n    this.#engine.runRenderLoop(this.render.bind(this))\r\n  }\r\n\r\n  update({ deltaTime }) {\r\n\r\n  }\r\n\r\n  render() {\r\n    this.#scene.render();\r\n  }\r\n\r\n  #resize() {\r\n    this.#engine.resize();\r\n  }\r\n}\r\n<\/pre>\n<h3>Node Material Editor \uc608<\/h3>\n<p><a href='https:\/\/nme.babylonjs.com'><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.gisdeveloper.co.kr\/wp-content\/uploads\/2024\/04\/babylonjs_node_material.png\" alt=\"\" width=\"2558\" height=\"1318\" class=\"aligncenter size-full wp-image-14824\" \/><\/a><\/p>\n<p>\uc704\uc758 \uacb0\uacfc\ub97c JSON\uc73c\ub85c \uc800\uc7a5\ud560 \uc218 \uc788\uc73c\uba70 \ucf54\ub4dc\ub97c \ud1b5\ud574 \uc0ac\uc6a9\ud558\ub294 \uc608\ub294 \uc544\ub798\uc640 \uac19\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nBABYLON.NodeMaterial.ParseFromFileAsync(\"nodeMat\", \".\/nodeMaterial.json\", this.#scene).then((mat) => {\r\n  this.#mesh.material = mat;\r\n});\r\n<\/pre>\n<h3>Node Geometry Editor \uc608<\/h3>\n<p><a href='https:\/\/nge.babylonjs.com'><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.gisdeveloper.co.kr\/wp-content\/uploads\/2024\/04\/babylonjs_node_geometry.png\" alt=\"\" width=\"3892\" height=\"1772\" class=\"aligncenter size-full wp-image-14827\" \/><\/a><\/p>\n<p>\uc704\uc758 \uacb0\uacfc\ub97c JSON\uc73c\ub85c \uc800\uc7a5\ud560 \uc218 \uc788\uc73c\uba70 \ucf54\ub4dc\ub97c \ud1b5\ud574 \uc0ac\uc6a9\ud558\ub294 \uc608\ub294 \uc544\ub798\uc640 \uac19\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\n#createModel() {\r\n  const assetsManager = new BABYLON.AssetsManager(this.#scene);\r\n  const nodeGeometryFile = assetsManager.addTextFileTask(\"file\", \".\/nodeGeometry.json\");\r\n  assetsManager.load();\r\n\r\n  assetsManager.onFinish = async (tasks) => {\r\n    const nodeGeometryJSON = JSON.parse(nodeGeometryFile.text);\r\n    const nodeGeometry = await BABYLON.NodeGeometry.Parse(nodeGeometryJSON);\r\n    nodeGeometry.build();\r\n    \/* const myGeometry = *\/ nodeGeometry.createMesh(\"myGeometry\");\r\n  }\r\n}\r\n<\/pre>\n<h3>ArcRotateCamera\uc758 \ub9c8\uc6b0\uc2a4 \ud720 \uc90c \uae30\ub2a5 \ube44\ud65c\uc131\ud654<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nthis.#scene.createDefaultCamera(true, false, true);\r\nconst camera = this.#scene.cameras[0];\r\ncamera.inputs.removeByType(\"ArcRotateCameraMouseWheelInput\");\r\n<\/pre>\n<h3>scene\uc744 \uad6c\uc131\ud558\ub294 mesh\ub97c \uc81c\uac70\ud558\uae30 \uc704\ud574\uc11c\ub294 dispose \ub9e4\uc11c\ub4dc\ub97c \ud638\ucd9c<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nconst meshes = this.#scene.getMeshesById(\"cannon\");\r\nmeshes[0].dispose();\r\n<\/pre>\n<h3>\uc0ac\uc6a9\ud560 \uce74\uba54\ub77c \uc120\ud0dd\ud558\uae30<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nthis.#scene.activeCamera = myCamera;\r\nthis.#scene.activeCamera.attachControl(true);\r\n\r\n\/\/ \uc704\uc758 \ucf54\ub4dc\ub294 \ub2e4\uc74c \ud55c\uc904\ub85c \ub300\uccb4\uac00\ub2a5\ud568\r\nmyCamera.attachControl(true);\r\n<\/pre>\n<h3>\uc55e\uba74 \ub4b7\uba74 \ubaa8\ub450 \ub80c\ub354\ub9c1\ud558\uae30<\/h3>\n<p>\ubc29\ubc95\uc740 2\uac00\uc9c0 \uc778\ub370 \ub9e4\uc2dc\uc5d0 \ub300\ud574\uc11c sideOrientation: BABYLON.Mesh.DOUBLESIDE\ub97c \uc9c0\uc815\ud558\ub294 \uac83, \ub610\ub294 \uc7ac\uc9c8\uc758 backFaceCulling = false\ub85c \uc9c0\uc815\ud558\ub294 \uac83\uc73c\ub85c \uac00\ub2a5\ud568<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nconst plane = BABYLON.MeshBuilder.CreatePlane(\"wall\", { size: 10, sideOrientation: BABYLON.Mesh.DOUBLESIDE }, this.#scene);\r\nconst planeMaterial = new BABYLON.StandardMaterial(\"planeMat\", this.#scene);\r\nplaneMaterial.backFaceCulling = false;\r\nplane.material = planeMaterial;\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\ubc14\ub85c \uc2dc\uc791\ud560 \uc218 \uc788\ub294 \ud504\ub85c\uc81d\ud2b8 \uad6c\uc131 git clone https:\/\/github.com\/GISDEVCODE\/babylonjs-with-javascript-starter.git \uc0dd\uc131\ud560\ud3f4\ub354 Mesh\uc758 Bounding Box \ud06c\uae30\uac12 const getParentSize = parent => { const sizes = parent.getHierarchyBoundingVectors() const size = { x: sizes.max.x &#8211; sizes.min.x, y: sizes.max.y &#8211; sizes.min.y, z: sizes.max.z &#8211; sizes.min.z } return size }; HDR, ENV\ub97c \ud1b5\ud55c \uad11\uc6d0 \ubc0f \ubc30\uacbd \ub370\uc774\ud130 \ud615\uc2dd\uc5d0 \ub530\ub77c \ucf54\ub4dc\ub3c4 \ub2ec\ub77c\uc9d0. &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/www.gisdeveloper.co.kr\/?p=14741\" class=\"more-link\">\ub354 \ubcf4\uae30<span class=\"screen-reader-text\"> &#8220;Babylon.js &#8211; Tips&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[150],"tags":[],"class_list":["post-14741","post","type-post","status-publish","format-standard","hentry","category-babylon-js"],"_links":{"self":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/14741","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=14741"}],"version-history":[{"count":26,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/14741\/revisions"}],"predecessor-version":[{"id":14934,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/14741\/revisions\/14934"}],"wp:attachment":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=14741"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=14741"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=14741"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}