1
votes

I have a web 3D model viewer that uses Three.JS. I'm trying to implement a way to choose different models from a dropdown list, using dat.GUI. I'm trying to accomplish this with a switch statement, as inspired by some examples on the Three.JS website (materials/reflectivity and envmaps/hdr/nodes).

My loader works fine when I'm just trying to load one model. But when I try to connect it to the GUI and switch statement, the model doesn't appear (console log says 100% loaded, but I don't know if that's true or a fault of my load reporter). The console log also returns this error:

Error: THREE.OBJLoader: Unexpected line: "<!DOCTYPE html>" OBJLoader.js:624:12

Googling of the error returns suggestions that the .obj file is broken. I know my models are fine because I've loaded them successfully by themselves. So I can only assume the problem is my variable that I'm having the loader load. I know OBJLoader can load from variables, because I tried just defining one variable as the model (var model = 'my_model.obj', then having the loader load "model"), which worked. So I've narrowed it down to a problem with the GUI code or switch statement.

Here's my script with some irrelevant parts cut out.

var gui;
var camera, scene, renderer;
var species, params;

//3D models to choose from in dropdown list.
var speciesList = {
        'Goldenrod': 'models/solidago_rugosa.obj',
        'Mountain Laurel': 'models/kalmia_latifolia.obj',
        };

//Model loaded by default
params = {
           Species: 'models/solidago_rugosa.obj'
        };

init();
animate();

function init() {
//defining the scene, camera, renderer...

//GUI
gui = new dat.GUI({hideable: false});     
        gui.add(params, 'Species', speciesList)

//controls, window resizer...
       };

//Switch to load a different model.
//speciesCurrent is used by loader.
//No method to remove the previously loaded model yet, but I figure it should be able to load models on top of each other for now.
        var speciesCurrent;
        switch (speciesList) {
                case 'models/solidago_rugosa.obj':
                    speciesCurrent = 'models/solidago_rugosa.obj';
                    break;
                case 'models/kalmia_latifolia.obj':
                    speciesCurrent = 'models/kalmia_latifolia.obj';
                    break;
            };

//Loader
var loader = new THREE.OBJLoader();
loader.load(
   speciesCurrent,
    function(object){
        var material = new THREE.MeshLambertMaterial({color: 0x99a300});
        object.traverse(function (child){
            if (child instanceof THREE.Mesh){
                child.material=material;
                child.material.flatShading = 0;
            }
        });
        scene.add(object);
    },
    function(xhr){
        console.log((xhr.loaded / xhr.total * 100) + '% loaded');
    },
    function(error){
        console.log('An error happened');
    }
);

//Light sources...

//Game loop
function animate(){
            requestAnimationFrame( animate );
                render();
        };

function render(){
    renderer.render(scene,camera);
};

How can I have my loader actually load the model selected from the dropdown list? Thank you.

Update: The network tab of my browser's dev tools show my index file listed twice. The one labeled "xhr" links by stack trace to line 93 of the index file, which is where the loader begins ("loader.load"). Commenting out the switch statement removes that extra html file. What could be causing my loader to perceive the switch statement as html?

1
If the mentioned error pops up, it means you are trying to load a HTML file with OBJLoader. Please ensure with the network tab of the browser's dev tools that you actually load the correct resource from the backend.Mugen87
@Mugen87 I updated the OP. It seems you're right, but what could be causing the loader to perceive html when it was never told to load an html file?Chantal
Maybe a web server related issue. Try to host your app with node.js and http-server and see if it works.Mugen87
I would expect there to be an onChange event listener on the gui select which I don't see in your code. eg. workshop.chromeexperiments.com/examples/gui/#7--Events2pha
Changing the parameter of the switch statement from "speciesList" to "params.Species" got rid of the doctype error. Switching to the STL loader also worked. Still working on linking the dropdown options to the variable I told the loader to load, but I've gotten an onChange function to load the default model when any option is selected.Chantal

1 Answers

0
votes

It's working. I told the loader to load params.Species (the currently selected Species file) and scrapped the switch statement. I also added a function that fires when the GUI is changed and also removes any previously loaded model. Here is the current working code:

var gui;
var camera, scene, renderer;
var species, params;
var loader, mesh

//3D models to choose from in dropdown list
var speciesList = {
        'American Chestnut': 'models/castanea_dentata_dry.stl',
        'Aquilapollenites': 'models/aquilapollenites_quadrilobus.stl',
        'Big Bluestem': 'models/andropogon_gerardii.stl',
        'Eastern Larch': 'models/larix_laricina.stl',
        'Eastern White Pine': 'models/pinus_strobus.stl',
        'Goldenrod': 'models/solidago_rugosa.stl',
        'Japanese Barberry': 'models/berberis_thunbergii.stl',
        'Mountain Laurel': 'models/kalmia_latifolia.stl',
        'Princess Pine': 'models/lycopodium_obscurum.stl',
        'Royal Fern': 'models/osmunda_regalis.stl',
        'Sensitive Fern': 'models/onoclea_sensibilis.stl',
        'Silver Maple': 'models/acer_saccharinum_fresh.stl',
        };

//Model loaded by default
params = {
           Species: 'models/solidago_rugosa.stl'
        };

init();
animate();

function init() {
//Defining the scene, camera, renderer...

//GUI
gui = new dat.GUI({hideable: false});     
gui.add(params, 'Species', speciesList)
.onChange(function(){
    speciesLoad();
});

//Controls, window resizer...
       };

//Function removes old model and loads new one when the dropdown selection changes.
function speciesLoad(){
    if (mesh !== undefined) {
         scene.remove(mesh);
    };

    loader = new THREE.STLLoader();
    loader.load(
            params.Species,
            function(geometry){
            var material = new THREE.MeshLambertMaterial({color: 0x99a300});
            mesh = new THREE.Mesh(geometry, material)
            scene.add(mesh);
    },
    function(xhr){
        console.log((xhr.loaded / xhr.total * 100) + '% loaded');
    },
    function(error){
        console.log('An error happened');
    }
);};

//Light...
//Defining animate & render functions...