0

I have a Blazor WASM project that I load Babylon scene. When I load a simple scene (drawing a sphere on a plane) everything loads fine. But, I am trying to load an *.obj file, which is stored on storage on Azure and I want to display it in Babylon scene. The page loads without errors but the scene does not load. This is my Babylon code:

        var createMeshScene = async function () {
            var scene = new BABYLON.Scene(engine);
            //Adding a light
            var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(20, 20, 100), scene);
            //Adding an Arc Rotate Camera
            var camera = new BABYLON.ArcRotateCamera("Camera", 0, 1, 0, BABYLON.Vector3.Zero(), scene);
            camera.attachControl(canvas, false);        
            fetch("https://myapp.myorg.appserviceenvironment.us/myFile.obj",
                {
                    mode: "no-cors",
                    headers: {
                        'Content-Type': 'application/octet-stream'
                    },
                }
            ).then((val) => {
                val.blob().then(blob => {
                    const file = new File([blob], "myFile.obj");
                    BABYLON.SceneLoader.ImportMesh("", "", file, scene, function (newMeshes) {
                        // Set the target of the camera to the first imported mesh
                        camera.target = newMeshes[0];
                        newMeshes[0].scaling.scaleInPlace(50);
                    });
                });
            })
            scene.registerBeforeRender(function () {
                light.position = camera.position;
            });
           
            return scene;
        }

In my _Host.cshtml file I load these libraries:

    <script src="https://assets.babylonjs.com/generated/Assets.js"></script>
    <script src="https://cdn.babylonjs.com/recast.js"></script>
    <script src="https://cdn.babylonjs.com/ammo.js"></script>
    <script src="https://cdn.babylonjs.com/havok/HavokPhysics_umd.js"></script>
    <script src="https://cdn.babylonjs.com/cannon.js"></script>
    <script src="https://cdn.babylonjs.com/Oimo.js"></script>
    <script src="https://cdn.babylonjs.com/earcut.min.js"></script>
    <script src="https://cdn.babylonjs.com/babylon.js"></script>
    <script src="https://cdn.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
    <script src="https://cdn.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
    <script src="https://cdn.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
    <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.js"></script>
    <script src="https://cdn.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
    <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script>
    <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>

When the scene loads, in the console, I can see there are no errors and this is displayed:

Babylon.js v6.22.1 - WebGL2 [.WebGL-0000505C0711AA00]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels

I also debug into BABYLON.SceneLoader.ImportMesh and can see the files load fine but nothing is shown.

EDIT For more context, this is the full JS :

window.initializeBabylon = () => {
    var canvas = document.getElementById("renderCanvas");

    var startRenderLoop = function (engine, canvas) {
        engine.runRenderLoop(function () {
            if (sceneToRender && sceneToRender.activeCamera) {
                sceneToRender.render();
            }
        });
    }

    var engine = null;
    var scene = null;
    var sceneToRender = null;
    var createDefaultEngine = function () { return new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true, disableWebGL2Support: false }); };

    var createMeshScene = async function () {
        var scene = new BABYLON.Scene(engine);
        //Adding a light
        var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(20, 20, 100), scene);
        //Adding an Arc Rotate Camera
        var camera = new BABYLON.ArcRotateCamera("Camera", 0, 1, 0, BABYLON.Vector3.Zero(), scene);
        camera.position = new BABYLON.Vector3(500, 500, 500); 

        camera.attachControl(canvas, false);       
        var response = await fetch("assets/MyObj.obj");

        if (!response.ok) throw new Error("Failed to load: MyObj.obj " + response);
        var blob = await response.blob();
        var file = new File([blob], "MyObj.obj");

        BABYLON.SceneLoader.ImportMesh("", "", file, scene, function (newMeshes) {
                    // Set the target of the camera to the first imported mesh
                    camera.target = newMeshes[0];
                    newMeshes.forEach(m => m.scaling.scaleInPlace(0.5));
        });

        scene.registerBeforeRender(function () {
            light.position = camera.position;
            light.intensity = 0.7;
        });
       
        return scene;
    }


    engine = createDefaultEngine();
    if (!engine) throw 'engine should not be null.';
    startRenderLoop(engine, canvas);
    scene = createMeshScene();
    sceneToRender = scene;
};

This gets called in my razor page like this:

 protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSRuntime.InvokeVoidAsync("initializeBabylon");
        }
    }
1
  • Have you tried moving your camera away to make sure you are not inside the mesh? Try using the arrow keys to move away from the camera starting point or change your camera parameters to a more distant starting position (1000 is a good start.) Also, how many meshes are in your newMeshes array inside your SceneLoaderSuccessCallback? It is possible you are only scaling the first which may not even be visible. Commented Oct 5, 2023 at 18:33

1 Answer 1

0

Short answer:

  • Move your camera so it is not inside the mesh.
camera.position = new BABYLON.Vector3(500, 500, 500); 
  • Omit increasing the size of your mesh or even scale it down instead. Also, scale the entire mesh array not just the first mesh.
// newMeshes[0].scaling.scaleInPlace(50);
newMeshes.forEach(m => m.scaling.scaleInPlace(0.5));

Long answer:
I created a test app and here is the code that worked for me. You didn't share you .obj asset so I used a random one off the internet (filing_cabinet.obj download) but that may cause differences in results.

The main issue I had was that my camera was inside my mesh. Changing the camera start location fixed it. Also, I realized the .obj I was using had over 100 meshes that make up the filing cabinet. So, when I was trying to resize the mesh I was only resizing the first mesh which wasn't even visible.

I set up the engine according to the starter doc here.

Here is my scene code, based off of yours, that worked. Mine is in C# but it follows the same pattern as Javascript (aside from some capitalization differences.)

async Task<BABYLON.Scene> CreateMeshScene()
{
    // Creates a basic Babylon Scene object
    var scene = new BABYLON.Scene(engine);
    // Adding a light
    var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(20, 20, 100), scene);
    // Adding an Arc Rotate Camera
    var camera = new BABYLON.ArcRotateCamera("Camera", 0, 1, 0, BABYLON.Vector3.Zero(), scene);
    // Change camera starting position so not inside Mesh
    camera.Position = new BABYLON.Vector3(500, 500, 500);
    // This attaches the camera to the canvas
    camera.AttachControl(canvas, false);
    // load .obj
    // https://free3d.com/3d-model/office-filing-cabinet-341696.html
    var response = await JS.Fetch("assets/filing_cabinet.obj");
    if (!response.Ok) throw new Exception("Failed to load: filing_cabinet.obj");
    var blob = await response.Blob();
    var file = new File([blob], "filing_cabinet.obj");
    BABYLON.SceneLoader.ImportMesh("", "", file, scene, Callback.CreateOne<Array<AbstractMesh>, Array<BaseParticleSystem>, Array<Skeleton>, Array<AnimationGroup>, Array<TransformNode>, Array<Geometry>, Array<Light>>((meshes, particaleSystems, skeletons, animationGroups, transformNodes, geometries, lights) =>
    {
        // Set the target of the camera to the first imported mesh
        camera.Target = meshes[0];
        // Scale to half size (My mesh was rather large)
        meshes.ForEach(m => m.Scaling.ScaleInPlace(0.5));
    }));
    scene.RegisterBeforeRender(SceneBeforeRenderCallback = new ActionCallback(() => {
        light.Position = camera.Position;
    }));
    return scene;
}

For this to work I only needed to load the below files found here
babylon.js
babylonjs.loaders.min.js
babylonjs.materials.min.js

My Demo
My Demo repo (Blazor WASM)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for this extensive response. Unfortunately, it does not seem to help. I am not sure if the issue is with the camera or meshes? Normally when I have the generic Babylon scene (sphere on a plane) the background will turn a dark blue and it will draw. In my example, there is no change to the background either. I have updated my question with my full js code (I call it from blazor jsinterop)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.