Three.js学習レコード(任意サイズOBJモデルをロード)


任意のサイズのOBJモデルのロード問題は以下のいくつかの方面を通じていかなるサイズのモデルに対して、モデルはすべてホームページの中で合理的に表示することができることを確保します:モデルのロードの割合はすべて1で、カメラのz方向の座標値はモデルのサイズによって動的に調整します;モデルの包囲ボックスを計算し、モデルを世界座標の原点に配置します.ベースライトや平行光源など、適切な光源を選択します.
(1)OBJモデルのロードに使用する外部JavaScriptライブラリをリストする
<script src="../build/three.js"></script>
<script src="js/loaders/MTLLoader.js"></script>
<script src="js/loaders/OBJLoader.js"></script>
<script src="js/controls/TrackballControls.js"></script>
<script src="js/controls/DragControls.js"></script>
<script src="js/libs/stats.min.js"></script>

(2)変数の定義
    let camera, scene, renderer,controls,stats;//    
    let objects =[];//    
    let group = new THREE.Group();//  obj
    let i,m,x,y,z;//     
    let dragControls;//    

(3)レンダラー、シーン、カメラ、ライトを初期化し、カメラはパースカメラを採用し、カメラのz方向座標値はモデルサイズによって決定される.ライトは平行光源とベース光源を使用します.性能モニタリングのためにStatsを追加し,小型OBJモデルではフレーム数が60に達する.
//      
        renderer = new THREE.WebGLRenderer({
     antialias: true});
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild( renderer.domElement );
        renderer.setClearColor(0x000000, 1);

//        
        i=window.innerHeight/window.innerWidth;

//     
        scene = new THREE.Scene();

//     
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100000000);

//     
        let ambientLight = new THREE.AmbientLight(0xcccccc,0.6);
        scene.add(ambientLight);
        let a=1,b=0.6,c=10;
        let directionalLight1 = new THREE.DirectionalLight(0xffffff,b);
        directionalLight1.position.set(-a,-a,a*c).normalize();
        let directionalLight2 = new THREE.DirectionalLight(0xffffff,b);
        directionalLight2.position.set(a,-a,-a*c).normalize();
        let directionalLight3 = new THREE.DirectionalLight(0xffffff,b);
        directionalLight3.position.set(-a,a,-a*c).normalize();
        let directionalLight4 = new THREE.DirectionalLight(0xffffff,b);
        directionalLight4.position.set(a,a,a*c).normalize();
        scene.add(directionalLight1);
        scene.add(directionalLight2);
        scene.add(directionalLight3);
        scene.add(directionalLight4);

//      
        controls = new THREE.OrbitControls(camera);
        controls.rotateSpeed = 3;
        controls.zoomSpeed = 3;
        controls.panSpeed = 3;
        controls.noZoom = false;
        controls.noPan = false;
        controls.staticMoving = true;
        controls.dynamicDampingFactor = 0.3;
        
//        
        stats = new Stats();
        document.body.appendChild( stats.dom );

(4)OBJモデルをロードし,モデルのロード比率はいずれも1であり,カメラz座標を決定する数値を計算することで,どのモデルでもページに適切に表示できることを確保する.
OBJとMTLは互いに組み合わせた2つのフォーマットで、objファイルではモデルが三角パッチからなり、三角パッチの頂点、テクスチャ座標、頂点法ベクトル、面などのデータが格納されている.mtlファイルには、モデルのマテリアルデータが格納されています.
//      obj+mtl
        let objloader = new THREE.OBJLoader();
        let mtlloader = new THREE.MTLLoader();
//    
        Add(objloader,mtlloader, "models/blue");

        function Add(objloader,mtlloader, name) {
     
            mtlloader.load(name + '.mtl', function (materials) {
     
                materials.preload();
                objloader.setMaterials(materials);
                objloader.load(name + '.obj', function (object) {
     
                    object.scale.set(1, 1, 1);
                    object.traverse(function (child) {
     
                        child.castShadow = true;
                        child.receiveShadow = true;
                        objects.push(child);
                    }, {
     normalizeRGB: true});

                    object.position.set(0,0,0);
                    let bbox = new THREE.Box3().setFromObject(object);
                    x=bbox.max.x-bbox.min.x;
                    y=bbox.max.y-bbox.min.y;
                    z=bbox.max.z-bbox.min.z;
                    object.position.set(-(bbox.max.x+bbox.min.x)/2,
                        -(bbox.max.y+bbox.min.y)/2,
                        -(bbox.max.z+bbox.min.z)/2);

                    if(y/x>=i)
                    {
     
                        let h=y;
                        let Fov= camera.fov * Math.PI/180;
                        m=h/(2 * Math.tan(Fov* 0.5) );
                        camera.position.y = 0;
                        camera.position.z = 2*m+(z/2);
                        camera.position.x = 0;
                    }
                    else
                    {
     
                        let w=x;
                        let h=w*i;
                        let Fov= camera.fov * Math.PI/180;
                        m=h/(2 * Math.tan(Fov* 0.5) );
                        camera.position.y = 0;
                        camera.position.z = 2*m+(z/2);
                        camera.position.x = 0;
                    }

                    group.add(object);
                    scene.add(group);
                });
            });
        }

(5)モデルドラッグ
 //    
        dragControls = new THREE.DragControls(objects, camera, renderer.domElement);
        dragControls.addEventListener('dragstart', function () {
     
                controls.enabled = false;
        });
        dragControls.addEventListener('dragend', function () {
     
                controls.enabled = true;
        });


(6)スクリーンアダプティブおよびレンダリングサイクル
    //     
    window.addEventListener('resize', onWindowResize, false);
    function onWindowResize() {
     
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

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

    //    
    function render() {
     
        camera.updateProjectionMatrix();
        controls.update();
        renderer.render(scene, camera)
        stats.update();
    }

完全なコードは次のとおりです.
<!DOCTYPE html>
<html  lang="en">
<head>
    <title>models</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>
        body {
     
            font-family: Monospace;
            background-color: #fff;
            color: #000;
            margin: 0px;
            overflow: hidden;
        }
    </style>

</head>
<body>

<script src="../build/three.js"></script>
<script src="js/loaders/MTLLoader.js"></script>
<script src="js/loaders/OBJLoader.js"></script>
<script src="js/controls/TrackballControls.js"></script>
<script src="js/controls/DragControls.js"></script>
<script src="js/libs/stats.min.js"></script>

<script >

    let camera, scene, renderer,controls,stats;//    
    let objects =[];//    
    let group = new THREE.Group();//  obj
    let i,m,x,y,z;//     
    let dragControls;//    

    init();
    animate();

    function init() {
     

//      
        renderer = new THREE.WebGLRenderer({
     antialias: true});
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild( renderer.domElement );
        renderer.setClearColor(0x000000, 1);

//        
        i=window.innerHeight/window.innerWidth;

//     
        scene = new THREE.Scene();

//     
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100000000);

//     
        let ambientLight = new THREE.AmbientLight(0xcccccc,0.6);
        scene.add(ambientLight);
        let a=1,b=0.6,c=10;
        let directionalLight1 = new THREE.DirectionalLight(0xffffff,b);
        directionalLight1.position.set(-a,-a,a*c).normalize();
        let directionalLight2 = new THREE.DirectionalLight(0xffffff,b);
        directionalLight2.position.set(a,-a,-a*c).normalize();
        let directionalLight3 = new THREE.DirectionalLight(0xffffff,b);
        directionalLight3.position.set(-a,a,-a*c).normalize();
        let directionalLight4 = new THREE.DirectionalLight(0xffffff,b);
        directionalLight4.position.set(a,a,a*c).normalize();
        scene.add(directionalLight1);
        scene.add(directionalLight2);
        scene.add(directionalLight3);
        scene.add(directionalLight4);

//      
        controls = new THREE.OrbitControls(camera);
        controls.rotateSpeed = 3;
        controls.zoomSpeed = 3;
        controls.panSpeed = 3;
        controls.noZoom = false;
        controls.noPan = false;
        controls.staticMoving = true;
        controls.dynamicDampingFactor = 0.3;

//        
        stats = new Stats();
        document.body.appendChild( stats.dom );

//      obj+mtl
        let objloader = new THREE.OBJLoader();
        let mtlloader = new THREE.MTLLoader();
//    
        Add(objloader,mtlloader, "models/blue");

        function Add(objloader,mtlloader, name) {
     
            mtlloader.load(name + '.mtl', function (materials) {
     
                materials.preload();
                objloader.setMaterials(materials);
                objloader.load(name + '.obj', function (object) {
     
                    object.scale.set(1, 1, 1);
                    object.traverse(function (child) {
     
                        child.castShadow = true;
                        child.receiveShadow = true;
                        objects.push(child);
                    }, {
     normalizeRGB: true});

                    object.position.set(0,0,0);
                    let bbox = new THREE.Box3().setFromObject(object);
                    x=bbox.max.x-bbox.min.x;
                    y=bbox.max.y-bbox.min.y;
                    z=bbox.max.z-bbox.min.z;
                    object.position.set(-(bbox.max.x+bbox.min.x)/2,
                        -(bbox.max.y+bbox.min.y)/2,
                        -(bbox.max.z+bbox.min.z)/2);

                    if(y/x>=i)
                    {
     
                        let h=y;
                        let Fov= camera.fov * Math.PI/180;
                        m=h/(2 * Math.tan(Fov* 0.5) );
                        camera.position.y = 0;
                        camera.position.z = 2*m+(z/2);
                        camera.position.x = 0;
                    }
                    else
                    {
     
                        let w=x;
                        let h=w*i;
                        let Fov= camera.fov * Math.PI/180;
                        m=h/(2 * Math.tan(Fov* 0.5) );
                        camera.position.y = 0;
                        camera.position.z = 2*m+(z/2);
                        camera.position.x = 0;
                    }

                    group.add(object);
                    scene.add(group);
                });
            });
        }
//    
        dragControls = new THREE.DragControls(objects, camera, renderer.domElement);
        dragControls.addEventListener('dragstart', function () {
     
                controls.enabled = false;
        });
        dragControls.addEventListener('dragend', function () {
     
                controls.enabled = true;
        });
    }
    //init()  


    //     
    window.addEventListener('resize', onWindowResize, false);
    function onWindowResize() {
     
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

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

    //    
    function render() {
     
        camera.updateProjectionMatrix();
        controls.update();
        renderer.render(scene, camera)
        stats.update();
    }
</script>
</body>
</html>