end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

hands-on three.js - display 3d models - obj形式

今回は、

  • STEP 1 - blend 形式の3D モデルを blender で、obj 形式に変換
  • STEP 2 - obj形式のファイルを three.js で表示

します。

前回のentryまで、 Three.js – しめじのネタ帳 を写経していましたが、 今回は、説明が分かりやすい以下を、写経しています。

Three.jsでOBJファイルを読み込む

STEP 1 - blend 形式の3D モデルを blender で、obj 形式に変換

3Dモデルのファイルは、様々なところで配布されています。 今回は、建築家(バウハウス) 3d model - Free3D から blend 形式の3Dモデルをダウンロードし、これを blenderで、obj形式にexportします。

特に難しい点はない為、詳細までは記載しません。

STEP 2 - obj形式のファイルを three.js で表示

f:id:end0tknr:20210822064341p:plain

https://end0tknr.github.io/sandbox/threejs_obj_gltf/test_threejs_obj.html

以下の通りです。

ちなみに以前のentryと異なり、javascript es6の importを使用する為、

<script type="module"></script>

で jsを記載しています。

Three.jsでOBJファイルを読み込む

の説明は分かりやすいのですが、

Three.js – しめじのネタ帳

にある obj形式のentryと併せて、確認することをお勧めします。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Hello Three.js</title>
  <style>
    html, body { margin: 0; height: 100%; }
    #c { width: 100%; height: 100%; display: block; }
  </style>
</head>
<body>
  <canvas id="c"></canvas>
  <script type="module">
    import * as THREE from
    'https://threejsfundamentals.org/threejs/resources/threejs/r127/build/three.module.js';
    import {OrbitControls} from
    'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/controls/OrbitControls.js';
    import {OBJLoader} from
    'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/loaders/OBJLoader.js';

    function main() {
        const canvas = document.querySelector('#c');
        const renderer = new THREE.WebGLRenderer({canvas});
        
        const fov = 45;
        const aspect = 2;  // the canvas default
        const near = 0.1;
        const far = 100;
        const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
        camera.position.set(0, 10, 20);
        
        const controls = new OrbitControls(camera, canvas);
        controls.target.set(0, 5, 0);
        controls.update();
        
        const scene = new THREE.Scene();
        scene.background = new THREE.Color('black');
        
        {
            const planeSize = 40;
            
            const loader = new THREE.TextureLoader();
            const texture = loader.load('https://threejsfundamentals.org/threejs/resources/images/checker.png');
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.magFilter = THREE.NearestFilter;
            const repeats = planeSize / 2;
            texture.repeat.set(repeats, repeats);
            
            const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
            const planeMat = new THREE.MeshPhongMaterial({
                map: texture,
                side: THREE.DoubleSide,
            });
            const mesh = new THREE.Mesh(planeGeo, planeMat);
            mesh.rotation.x = Math.PI * -.5;
            scene.add(mesh);
        }
        
        {
            const skyColor = 0xB1E1FF;  // light blue
            const groundColor = 0xB97A20;  // brownish orange
            const intensity = 1;
            const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
            scene.add(light);
        }
        
        {
            const color = 0xFFFFFF;
            const intensity = 1;
            const light = new THREE.DirectionalLight(color, intensity);
            light.position.set(0, 10, 0);
            light.target.position.set(-5, 0, 0);
            scene.add(light);
            scene.add(light.target);
        }
        
        {
            const objLoader = new OBJLoader();
            objLoader.load(
                './bauhaus.obj',
                // 'https://threejsfundamentals.org/threejs/resources/models/windmill/windmill.obj',
                (root) => {
                    root.scale.set(3, 3, 3);
                    scene.add(root);
                });
        }
        
        function resizeRendererToDisplaySize(renderer) {
            const canvas = renderer.domElement;
            const width = canvas.clientWidth;
            const height = canvas.clientHeight;
            const needResize = canvas.width !== width || canvas.height !== height;
            if (needResize) {
                renderer.setSize(width, height, false);
            }
            return needResize;
        }
        
        function render() {
            
            if (resizeRendererToDisplaySize(renderer)) {
                const canvas = renderer.domElement;
                camera.aspect = canvas.clientWidth / canvas.clientHeight;
                camera.updateProjectionMatrix();
            }
            
            renderer.render(scene, camera);
            
            requestAnimationFrame(render);
        }
        
        requestAnimationFrame(render);
    }
    
    main();
  </script>
</body>
</html>