Hello babylonians,
I’m currently trying to implement my own upload file external assets model by using react typescript and babylonjs.
I have looking through the documentation on Importing your mesh: Importing Meshes | Babylon.js Documentation
when it didn’t work I referred to this part of docs:
Loading Any File Type | Babylon.js Documentation
here is my all code files that are related to what I am trying to accomplish
toolbar.tsx
import { buttonStyles, newProjectBackground, newProjectTitleText, } from "@/ui/pageSections/NewProject"
import { ToggleSwitch, ToolbarSection, AddModel} from "@/ui/pageSections/Editor"
import { SceneFactory } from "@/scene/SceneFactory";
import { InputModel } from "./MeshSection/InputModel";
export const Toolbar = ({ sceneFactory } : {sceneFactory: SceneFactory | null}) => {
return (
<div
className="h-full min-w-[300px] py-5 flex flex-col items-center z-10 overflow-y-scroll"
style={{ background: newProjectBackground.background, boxShadow: newProjectBackground.boxShadow }}
>
<div className="flex w-full justify-center items-center border-b border-gray-whisper pb-4 px-4">
<p className="text-base w-full font-medium font-interMedium tracking-tighter leading-normal text-left" style={{ textShadow: newProjectTitleText.textShadow }}>
<span className="text-white-default">{"Project "}</span>
<span
style={{
background: newProjectTitleText.background,
backgroundClip: newProjectTitleText.backgroundClip,
WebkitTextFillColor: newProjectTitleText.textFillColor,
WebkitBackgroundClip: newProjectTitleText.backgroundClip
}}
>
{"Menu"}
</span>
</p>
</div>
<div className="flex flex-col w-full justify-center items-center divide-y divide-gray-whisper">
<ToolbarSection title="Meshes">
<ToggleSwitch title="add ground" cta={ () => sceneFactory!.toggleGround()}></ToggleSwitch>
<ToggleSwitch title="add sky" cta={ () => sceneFactory!.toggleSky()}></ToggleSwitch>
<AddModel cta={() => sceneFactory!.addCube()} title={"add cube"} disabled={false}></AddModel>
<AddModel title={"add shpere"} disabled={true}></AddModel>
<AddModel title={"add cylinder"} disabled={true}></AddModel>
<AddModel title={"add cone"} disabled={true}></AddModel>
//this code is comment out because I am just trying to importMesh without upload file
//instead just using a button
{/* <InputModel cta = {(file) => sceneFactory!.addModelFromImport(file)}></InputModel> */}
<AddModel cta={() => sceneFactory!.createPlayerMesh()} title={"Import Model"} disabled={false}></AddModel>
</ToolbarSection>
<ToolbarSection title="Lighting">
<ToggleSwitch title="add hemespheric lighting"></ToggleSwitch>
</ToolbarSection>
<ToolbarSection title="Physics"></ToolbarSection>
<ToolbarSection title="Animations"></ToolbarSection>
</div>
</div>
)
}
InputModel.tsx is a component that I made for upload external model file
import { PlusSmIcon } from "@heroicons/react/solid";
import { buttonStyles } from "@/ui/components/Button"
import React, { useEffect, useRef } from "react";
export const InputModel = ({cta} : {cta: (file: any) => void}) => {
const fileReader = useRef<FileReader>(new FileReader());
const reader = fileReader.current;
useEffect(() => {
if(reader){
reader.addEventListener("load", function(){
cta(reader.result);
console.log("after readerResult");
}, false)
}
}, [])
const handleUploadFile = (e : React.ChangeEvent<HTMLInputElement> ) => {
const file = e.target.files;
if(file){
reader.readAsDataURL(file[0]);
}
}
return(
<div>
<input type="file"
name="inputFile"
id="input"
className={`"opacity-50 pointer-events-none" : "cursor-pointer"} w-auto cta-button flex flex-row justify-center items-center bg-gray-dark_charcoal rounded border h-min px-2 py-1`}
onChange={handleUploadFile}
accept=".glb, .gltf"
/>
</div>
)
}
SceneFactory.ts is where all the code related to Babylon.js
import {
Scene,
Mesh,
MeshBuilder,
Color3,
StandardMaterial,
AbstractMesh,
Size,
SceneLoader,
} from "@babylonjs/core";
import { SkyMaterial } from "@babylonjs/materials";
import "@babylonjs/loaders/glTF";
export class SceneFactory {
private _scene: Scene;
constructor(scene: Scene) {
this._scene = scene
}
public addCube() : void {
const cubeMaterial = new StandardMaterial("cubeMat", this._scene)
cubeMaterial.diffuseColor = Color3.Red()
const cube = MeshBuilder.CreateBox("new cube", {size: 5}, this._scene)
cube.material = cubeMaterial
cube.position.y = 2.5
}
public toggleGround() : void {
const ground = this.getMeshByName("ground")
if (ground) {
this.disposeMesh(ground)
return;
}
this.addGround()
}
public toggleSky() : void {
const sky = this.getMeshByName("sky")
if (sky) {
this.disposeMesh(sky)
return
}
this.addSky()
}
private addGround() : void {
const groundMaterial = new StandardMaterial("groundMaterial", this._scene)
groundMaterial.diffuseColor = new Color3(53, 54, 58)
groundMaterial.alpha = 0.5
const ground: Mesh = MeshBuilder.CreateGround("ground", {width: 200, height: 200, subdivisions:250}, this._scene)
ground.material = groundMaterial
}
private addSky() : void {
const skyMaterial = new SkyMaterial("skyMaterial", this._scene);
skyMaterial.backFaceCulling = false;
skyMaterial.turbidity = 1
const sky = MeshBuilder.CreateBox("sky", {size:200}, this._scene);
sky.material = skyMaterial;
}
private getMeshByName(name: string) : AbstractMesh | undefined {
return this._scene.meshes.filter((mesh) => mesh.name === name)[0]
}
private disposeMesh(mesh: AbstractMesh) : void {
mesh.dispose()
}
// public addModelFromImport(file: string) {
// console.log("before uploaded!")
// SceneLoader.LoadAssetContainerAsync(file).then((container) => {
// console.log("inside upload")
// container.addAllToScene();
// });
// console.log("after uploaded!")
// }
//this function is I wa
public createPlayerMesh() {
const mesh: any = SceneLoader.ImportMesh(
"",
'./models/',
'Dog.glb',
this._scene
);
return mesh;
}
}
Note: to point out again any code that is comment is because it was related to upload/import file. i thought it would start by importing mesh first in my public/models file path, then after I successfully able to import a mesh. I will work on code that is comment.
what I am trying to accomplish now? whenever I click a button it’s able to import mesh that is saved in my react project locally.
Here are the errors that I am encountering currently.
I think it’s something to do how I am importing babylonjs. I’m not sure what I am doing wrong. If anyone Could help me? it would be greatly appreciate it. Thank you in Advance.