xeolabs / xeogl

A WebGL-based 3D engine for technical visualization. Not actively maintained.
http://xeogl.org
Other
1.15k stars 264 forks source link

Model does not dynamically update #326

Closed jalovisko closed 4 years ago

jalovisko commented 4 years ago

Describe the bug I try to update the model dynamically in the importing/stl/gear example. However, instead of updating I get two different models in the same scene (see image below).

image

To Reproduce Steps to reproduce the behavior:

I try to update the model source right after declaring the model as follows:

var model = new xeogl.STLModel({ src: "models/stl/binary/spurGear.stl", smoothNormals: true }); model.src = 'models/stl/binary/pr2_head_pan.stl';

The result is as in the image above. I also get an error: image

Expected behavior I would expect the model to be read from the second source.

Desktop (please complete the following information):

mhoelzner commented 4 years ago

Thats probably because the first model is not fully loaded. This is stated in the documentation of the STL loader like so You can set this to a new file path at any time (except while loading), which will cause the STLModel to load components from the new file (after first destroying any components loaded from a previous file path).

so you have to wait for the first source to be completely loaded, and then set the new source. use function like

model.on("loaded", function() {
        // STLModel has loaded!
    });

to determine when the first source has been loaded and then set the new source.

also consider setting the source right in the first place, if possible

jalovisko commented 4 years ago

I just tried doing it as follows:

var model = new xeogl.STLModel({
                src: "models/stl/binary/spurGear.stl",
                smoothNormals: true
            });

// Hold until the model is loaded

model.on("loaded", function() {
    // STLModel has loaded!
});

model.src = 'models/stl/binary/pr2_head_pan.stl';

But the output seems to be the same.

mhoelzner commented 4 years ago

model.on("loaded", function() {}); is a callback function of an async fetch. so if you really want to change the source of the model you should use it like so

var firstSrc = "models/stl/binary/spurGear.stl";
var nextSrc = 'models/stl/binary/pr2_head_pan.stl';

var model = new xeogl.STLModel({
    src: firstSrc,
    smoothNormals: true
});

model.on("loaded", function () {
    // STLModel has loaded!
    // to prevent recursion check sources before setting new
    if (model.source !== nextSrc) {
        model.src = 'models/stl/binary/pr2_head_pan.stl';
    }
});

to ensure that the first model has been completely loaded before setting a new source

But I still don't understand why you would change the model immediatly after setting its source, why not use the second source in the first place? If you really want to proceed like this, i would suggest to destroy the model previously loaded and load a new instance afterwards like so

model.on("loaded", function () {
    // STLModel has loaded!
    model.destroy()
    // to prevent recursion check sources before setting new
    if (model.source !== nextSrc) {
        model = new xeogl.STLModel({
            src: nextSrc,
            smoothNormals: true
        });
    }
});
jalovisko commented 4 years ago

Thanks! But the output remains the same. As a matter of fact, I don't need the model source to be changed immediately after declaring it. However, I do need a dynamic model update whenever the user uploads a model to my website. And it doesn't seem to be working.

mhoelzner commented 4 years ago

I've edited the gear example to the simples i could think of and it works just fine, at least in a way i understand you would like to have it

<!DOCTYPE html>
<html lang="en">
<head>
    <title>xeogl Example</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">

    <script src="../build/xeogl.js"></script>

    <script src="js/models/STLModel.js"></script>

    <link href="css/styles.css" rel="stylesheet"/>

    <style>
        body {
            background-color: black;
            background-size: 100%;
            background-repeat: repeat;
        }

        canvas {
            position: absolute;
            width: 100%;
            height: 100%;
        }
    </style>

<body>

<div id="info">
    <h1><a href="../docs/classes/STLModel.html" target="_parent">STLModel</a> - importing STL
    </h1>
</div>

<script>

    var model;

    var scene = new xeogl.Scene({
        transparent: true
    });

    xeogl.setDefaultScene(scene);

    new xeogl.CameraControl();

    var cameraFlight = new xeogl.CameraFlightAnimation();

    var camera = scene.camera;

    camera.eye = [37.24, 45.17, -15.02];
    camera.look = [10.90, 10.90, 8];
    camera.up = [-0.58, 0.72, 0.35];

    function updateModel(src, append = true) {

        if (model && append == false) {
            model.destroy();
        }

        model = new xeogl.STLModel({
            src: src,
            smoothNormals: true,
        });

        model.on("loaded", function() {

            console.log(model.id + " loaded");

            cameraFlight.flyTo(model);

        });

    }

</script>
</body>
</html>

to load a model you could simply use the console in you browser and add the following line

updateModel("./models/stl/binary/spurGear.stl");

to load the first model, after its done loading and you see it on the canvas add the following line

updateModel("./models/stl/binary/pr2_head_pan.stl");

to append the second model to the canvas or

updateModel("./models/stl/binary/pr2_head_pan.stl", false);

to destroy the first model and only show the second model

jalovisko commented 4 years ago

It works as I wanted it to, thank you very much!

mhoelzner commented 4 years ago

@xeolabs issue is resolved