three. Introduction to external model loading and controller properties in JS application

Posted by Apenvolkje on Tue, 25 Jan 2022 14:23:38 +0100

Learn three JS, we can naturally present a geometry on the screen according to the official example, although three JS also provides a way to build complex models similar to extrusion and mapping in 3dsMax, but there is no doubt that the model will not be generated by code in production, so it is necessary to load external 3d models.

I. format selection of 3D model

Considering that domestic modeling software 3dsMax is widely used, I use 3dsMax to demonstrate this section. three.js provides many model loaders and supports many model formats, including obj format (. Obj and. mtl,. Obj is the exported geometry file and. mtl is the exported material file), Collada model (. DAE file) and fbx file (. fbx). Obj lattice file is separated from material, too ZZ, and DAE file is a 3d file based on xml format, The advantage is that you can barely read the part (for example, it contains the URL path of the material, which can be modified manually), but the material needs external reference, and the volume of the exported file is too large. When the model is large, the loading will be very slow and may cause the browser to crash. Therefore, fbx file is selected for import.

II. Two pits during model import

1. When using Vue for development, the model file must be in the static folder of public, otherwise it will not be loaded.

2. At the beginning, scholars used 3dsMax to draw simple models and export them. When loading the code, they found that the geometry had no color, but all white models. In fact, it was because there was no material added to the geometry during modeling. Although a color was randomly assigned after drawing the geometry in 3dsMax, the color was to distinguish these geometry, not the material attribute, Therefore, the export is a white model. At this time, you can print the Mesh attribute and check the value of the material attribute to determine whether the problem is here.

III. import and load the code of the model

Importing models in different formats requires different loaders and different js files, The files of the loader are under examples/jsm/loaders (be careful! As mentioned in the previous section, if you use ES5 environment for development, all the imported files are in examples/js instead of examples/jsm. Be careful! Different versions will lead to various errors. Do not use them incorrectly). The code is as follows:

//New is a loader. Be sure to note that if ES5 is used, three is used when new is used here FBXLoader();
let loader = new FBXLoader();
loader.load("../assets/model/N1.fbx", function(result) {
            //Note: result refers to the geometry data read by the loader, because 3dsMax can group the geometry when exporting
            //There is no group, so the result may be a group object or an upper level object. If it is a group, it can be used directly
            //Call traverse(). If not, call the scene attribute first and then call it. For example: let scenegroup = result scene;
            let sceneGroup = result;
            console.log(result);
            sceneGroup.traverse(function (child,index) {
                if(child instanceof THREE.Mesh){
                    //For two-sided rendering, if multiple angles are not turned on, the geometry will disappear at some angles
                    child.material.side = THREE.DoubleSide;
                    //Geometry receives shadows, that is, shadows can be cast on geometry
                    child.receiveShadow = true;
                    //Geometry can produce shadows
                    child.castShadow = true;
                }else {
                    //Remove other elements that are not geometry (lights, cameras, etc.)
                    sceneGroup.remove(child);
                }
            });
            //The read scene is aligned with the center of the self generated scene. If the model file is too large, it is necessary to set the coordinates when grouping loading is adopted
            //want
            sceneGroup.position.x = 0;
            sceneGroup.position.y = 0;
            sceneGroup.position.z = 0;
            //Scale of the model on each axis, note, three y and z in JS are just opposite to those in 3dsMax
            sceneGroup.scale.set(1,1,1);
            scene.add(sceneGroup);
            //Render operation, renderer: renderer, scene: scene object, camera: camera object
            renderer.render(scene,camera);
        },function (xhr) {
            //Print the progress of file loading during loading
            if ( xhr.lengthComputable ) {
                let percentComplete = xhr.loaded / xhr.total * 100;
                console.log( Math.round(percentComplete, 2) + '% downloaded' );
            }
        });

traverse() method can iterate over all child nodes in the group, including geometry and subgroups. However, if modelers nest too many group structures of the model, the array of traverse() method may cross the boundary. Therefore, do not nest too many model group structures during modeling.

IV. scene controller OrbitControls

When we want to add basic interactive effects such as drag and drop, automatic rotation, multi view view and so on to the loaded scene, three JS provides the OrbitControls controller, which is very simple to use:

//Create control object
let controls = new THREE.OrbitControls(camera,renderer.domElement);

//When there is a plane geometry simulating the ground in the scene, if we need to limit the maximum angle of dragging to prevent the viewing angle from appearing in the CF below the ground
//When looking at the phenomenon of ghost skirt bottom, these two parameters can be added to limit the change range of viewing angle
//The maximum angle of turning up and down, the normal direction of the ground
controls.maxPolarAngle = 1.5;
//The minimum angle of turning up and down, the angle close to the ground
controls.minPolarAngle = 0.3;
//Allow mouse wheel to zoom interface
controls.enableZoom = true;
//Although the parameters are strange, in the perspective camera, this is the zoom in and zoom out parameter, which represents the distance from the camera to the lookAt point (the smaller the distance, the more the object
//(large)
controls.minDistance = 1; //100
controls.maxDistance = 270; //500
    
//In an orthogonal camera, the zoom limit and speed are controlled by these two parameters
controls.minZoom = 0.01;
controls.zoomSpeed = 1;
    
//Whether to turn on the function of dragging and panning the camera after pressing the right mouse button
controls.enablePan = true;
    
//Whether to turn on automatic scene rotation and rotation speed
controls.autoRotate = true;
controls.autoRotateSpeed = 0.8;
    
//The speed at which the viewing angle rotates when dragging the interface with the mouse
controls.rotateSpeed = 0.5;
controls.enableRotate = true;
    
//When adjusting the lookAt direction left and right with the mouse, the angle of left and right twisting is limited
minAzimuthAngle = - 0.5 * Math.PI; // radians
maxAzimuthAngle =  0.5 * Math.PI;  // radians
    
//Damping effect when dragging
controls.enableDamping = true;
controls.dampingFactor = 0.5;

//Binding time
controls.addEventListener('change', function(){
    renderer.render(scene,camera);
});

Some of the common parameters of the OrbitControls controller that adds basic effects to the scene are used as shown above, but one thing needs special attention:

Scene changes require the renderer to re render to refresh. The frequency of browser rendering is closely related to the fluency of the picture, but frequent rendering will also lead to excessive performance loss and page jamming. Therefore, in terms of effects that do not involve animation, we bind the change event to the controllers to trigger rendering (as shown above), This can greatly improve the performance, but in the animation that has been rendering, such as automatic rotation, we need to start an animation and constantly update the controls, for example:

//It needs to be called continuously to produce animation effects, so it is called in a requestAnimationFrame loop
function animate(){
    //controls is new three Object generated by orbitcontrols()
    controls.update();
    requestAnimationFrame(animate);
}

There is a big pit in animation, which will be encountered during subsequent geometry monitoring. It will be introduced in the following chapters

Topics: Three.js