Reloading OBJ Format string to show a completely different result

The code here works fine:

However, my application is a configurator and requires that this display be updated each time the user has adjusted parameters. The OBJ format maps perfectly to my problem domain, so my configurator is designed to write OBJ format strings (basically a vertex list and a face list).

My challenge is how to write this code so I can pass in the OBJ data as a parameter and update the display accordingly.

For example, the following playground does not even run:

I have it working pretty much accurately in my development environment using BABYLON.SceneLoader.Append with the code below. However, the code below does not seem to execute the scene.meshes[0] code, probably for two reasons: a) it’s a promise, and the code is not written correctly for that and b) now there are five meshes, not one, so using [0] does not point properly.

I really don’t care about anything pre-existing in the scene. I have no idea why there are now 5 meshes in there according to the Browser inspector. I simply want to wipe it all out and put in a completely new one based on my new OBJ string.

How do I do that?

//**********************************
//This is starting at the top of the script load in the HTML page.

      const canvas = document.getElementById("renderCanvas"); // Get the canvas element
      const engine = new BABYLON.Engine(canvas, true); // Generate the BABYLON 3D engine
      var scene;

      const createScene =  async function (objData) {
          // This creates a basic Babylon Scene object (non-mesh)
          scene = new BABYLON.Scene(engine);
          alert("Inside CreateScene");
          // This creates a light, aiming 0,-1,0 - to the sky (non-mesh)
          var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

          // Default intensity is 1. Let's dim the light a small amount
          light.intensity = 2;

          const mtlContent = `

newmtl emerald
Ka 0.7000 0.0000 0.0000
Kd 0.6000 0.5800 0.3900
Ks 0.8000 0.800 0.800
illum 1
Ns 740.0000
Tr 0.3000
`;

          const mtlBase64 = "data:;base64," + btoa(mtlContent);

          objData = objData.replace("mtllib emerald.mtl", "mtllib " + mtlBase64);

          alert("About to append");
         
                                    //rootURL,sceneFilename,scene,onSuccess
          BABYLON.SceneLoader.Append("", "data:;base64," + btoa(objData), scene, scene => {
              alert("Inside Append with " + scene.meshes.length);

//THIS IS THE CODE THAT WILL NOT EXECUTE PROPERLY
scene.meshes[0].createNormals();
scene.meshes[0].convertToFlatShadedMesh();
scene.meshes[0].material.backFaceCulling = false;

            scene.meshes[0].enableEdgesRendering();
            scene.meshes[0].edgesWidth = 200.0;
            scene.meshes[0].edgesColor = new BABYLON.Color4(1, 1, 0, 1);
            scene.meshes[0].edgesRenderer.lineShader.zOffset = -1;

// THIS IS EVIDENTLY STILL A PROMISE AND NOW THERE ARE 5 MESHES ANYWAY

          }, undefined, undefined, ".obj");
          //onProgress, onError, pluginExtension


        alert("after append");

          scene.createDefaultCamera(true, true, true);
          var mainCamera = scene.activeCamera;
          mainCamera.setPosition(new BABYLON.Vector3(50, 50, 300));

          //const pp = new BABYLON.ScreenSpaceCurvaturePostProcess("scpp", scene, 1, mainCamera);


          return scene;
      };

//*****************
// This function is called by the application based on user actions.
async function Show_Updates() {
alert(“Entering createScene”);
//scene.dispose(); //This does nothing so I commented it out.

//var objData = await Generate_Ridge_OBJ_File(); //The application generates the OBJ string here.
//but since I have not provided the rest of the application, this string could be passed instead:
let objData = `####
mtllib emerald.mtl
usemtl emerald
v 50 50 50
v 0 0 25
v 50 0 0
v 100 0 25
v 100 50 0
v 100 100 25
v 50 100 0
v 0 100 25
v 0 50 0
f 1 3 2
f 1 4 3
f 1 5 4
f 1 6 5
f 1 7 6
f 1 8 7
f 1 9 8
f 1 2 9

End of File

`;

scene = await createScene(objData); //Call the createScene function
alert("afterScene");
// 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();
});

}

It sounds like you might want SceneLoader.ImportMeshAsync instead of SceneLoader.AppendAsync.

Example playground: https://playground.babylonjs.com/#KXRUC9#28

2 Likes

DocEdub:

Thank you so much for your advice. I can see it’s working just great in the playground. Moving it to my application, not so much. I have been unclear from the beginning about where to place 1.const setObjData and 2.createScene in my code. If I put them in the top of my page, none of the rest of the page works but I get nothing on the debugger.

How should I package this code in my application and trigger the refresh from Javascript, not a button click?


I assume at the top of script I place Material and Shape definitions as page variables and refresh these objects from the application. Then what I want is to trigger the refresh via Javascript.

  1. Where does const setObjData = async (scene, data) go?

  2. Where does var createScene = async function go?

  3. Is there a way to simply call the equivalent of
    const button = {click: }
    as via code from Javascript?

  4. I have this as the start of my HTML Page:

Babylon Template
<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>
<canvas id="renderCanvas"></canvas>

<script>
    const canvas = document.getElementById("renderCanvas"); // Get the canvas element
    const engine = new BABYLON.Engine(canvas, true); // Generate the BABYLON 3D engine

Thank you in advance for your very helpful guidance! You guys make this place work! Thank you all!

–Dave

I forgot this piece of code. Where does this go? How is it activated correctly?

    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();
    });

I am totally baffled about when and where to call these things from or to place them in my general html page.

Hi!

Did you have a look at this doc page? There is an example HTML how to do it.