공부/threeJS

03_2 원시 모델(primitives)-회전 중앙 정렬

캄성 2022. 11. 28. 21:38

2022.05.17 - [공부/JS] - Three.js 따라 강의 - 00 먼저 알아야 할 것 들

2022.05.17 - [공부/JS] - Three.js 따라 강의 - 01 Threejs 란? (정육면체만들기)

2022.05.18 - [공부/threeJS] - Three.js 따라 강의 - 02 반응형 다자인 (화면 채우기

2022.11.28 - [공부/threeJS] - Three.js 따라 강의 - 03 원시 모델(primitives)- geometry 종류

 

 

 

threejs 웹을 통하여 공부하며 개인적으로 정리한 내용을 개인경험을 추가하여 정리한 곳 입니다.

(예제가 실제 실행되지 않는 것을 고쳐 설명할경 정리하기 위하여 작성)

https://threejs.org/ 에서 제공 하는 Three.js Fundamentals 진행 이후,

유료 강의인 Three.js Journey에 대한 리뷰를 진행 할 예정입니다.

Learn Three.js의 경우 기본 이론의 심화 과정 느낌인데, 학생ID 이용시 무료 로 사용한 Ebook도 있습니다.


원시 모델(primitives) - 예외 경우 

텍스트 작업을 위한 폰트 정보

helvetiker_regular.typeface.json
0.06MB

 Text geometry

기본 코드

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            margin: 0;
            height: 100%;
        }

        #c {
            width: 100%;
            height: 100%;
            display: block;
        }
    </style>

</head>

<body>
    <canvas id="c"></canvas>
    <script type="importmap">{
      "imports": {
          "three": "./three.module.js"
      }
  }</script><!-- Remove this when import maps will be widely supported -->
    <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
    <script type="module">
        import * as THREE from 'three';
        function main() {
            const canvas = document.querySelector('#c');
            const renderer = new THREE.WebGLRenderer({ canvas });


            const fov = 40;
            const aspect = 2;  // the canvas default
            const near = 0.1;
            const far = 1000;
            const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
            camera.position.z = 120;


            const scene = new THREE.Scene();
            scene.background = new THREE.Color(0xAAAAAA);
            {
                const color = 0xFFFFFF;
                const intensity = 1;
                const light = new THREE.DirectionalLight(color, intensity);
                light.position.set(-1, 2, 4);
                scene.add(light);
            }


            // 원시 모델 수정 부분

            const objects = [];
            const spread = 15;

            function addObject(x, y, obj) {
                obj.position.x = x * spread;
                obj.position.y = y * spread;

                scene.add(obj);
                objects.push(obj);
            }

            function createMaterial() {
                const material = new THREE.MeshPhongMaterial({
                    side: THREE.DoubleSide,
                });
                const hue = Math.random();
                const saturation = 1;
                const luminance = .5;
                material.color.setHSL(hue, saturation, luminance);

                return material;
            }

            function addSolidGeometry(x, y, geometry) {
                const mesh = new THREE.Mesh(geometry, createMaterial());
                addObject(x, y, mesh);
            }

            {
                const loader = new THREE.FontLoader();
                // promisify font loading
                function loadFont(url) {
                    return new Promise((resolve, reject) => {
                        loader.load(url, resolve, undefined, reject);
                    });
                }

                async function doit() {
                    const font = await loadFont('./helvetiker_regular.typeface.json');  /* threejs.org: url */
                    const geometry = new THREE.TextGeometry('three.js', {
                        font: font,
                        size: 3.0,
                        height: .2,
                        curveSegments: 12,
                        bevelEnabled: true,
                        bevelThickness: 0.15,
                        bevelSize: .3,
                        bevelSegments: 5,
                    });
                    addSolidGeometry(-.5, 0, geometry);
                    const mesh = new THREE.Mesh(geometry, createMaterial());
                    console.log(geometry)
                    geometry.computeBoundingBox();
                    
                    geometry.boundingBox.getCenter(mesh.position).multiplyScalar(-1);
                    

                    const parent = new THREE.Object3D();
                    parent.add(mesh);

                    addObject(0, 0, parent);
                }
                doit();
            }

            function resizeRendererToDisplaySize(renderer) {
                const canvas = renderer.domElement;
                const pixelRatio = window.devicePixelRatio;
                const width = canvas.clientWidth * pixelRatio | 0;
                const height = canvas.clientHeight * pixelRatio | 0;
                const needResize = canvas.width !== width || canvas.height !== height;
                if (needResize) {
                    renderer.setSize(width, height, false);
                }
                return needResize;
            }

            function render(time) {
                time *= 0.001;  // convert time to seconds

                if (resizeRendererToDisplaySize(renderer)) {
                    const canvas = renderer.domElement;
                    camera.aspect = canvas.clientWidth / canvas.clientHeight;
                    camera.updateProjectionMatrix();
                }

                objects.forEach((obj, ndx) => {
                    const speed = .5 + ndx * .05;
                    const rot = time * speed;
                    obj.rotation.x = rot;
                    obj.rotation.y = rot;
                });


                renderer.render(scene, camera);

                requestAnimationFrame(render);
            }
            requestAnimationFrame(render);

        }
        main();



    </script>
</body>

</html>

 위의 코드중 아래 2코드가 중앙 정렬을 하는 기본 주체 이다.

  • geometry.computeBoundingBox(); 의 경우  BoundingBox 속석은 geometry에 추가 하는 기능
  • geometry.boundingBox.getCenter(mesh.position).multiplyScalar(-1);  의경우 생성된 BoudingBox 속성을 mesh.position에 multiplyScalar(-1)만큼 변화 시켜 속성에 추가
  • 즉 좌표의 기준값을 중앙으로 변경
    geometry.computeBoundingBox();
    geometry.boundingBox.getCenter(mesh.position).multiplyScalar(-1);
    
    const parent = new THREE.Object3D();
    parent.add(mesh);

PointsMaterial

위 코드에서, 시각화 부분만 수정하면 되며, material에 sizeAttenuation 속성에 따라, 거리에 따른 크기변화가 생긴다.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            margin: 0;
            height: 100%;
        }

        #c {
            width: 100%;
            height: 100%;
            display: block;
        }
    </style>

</head>

<body>
    <canvas id="c"></canvas>
    <script type="importmap">{
      "imports": {
          "three": "./three.module.js"
      }
  }</script><!-- Remove this when import maps will be widely supported -->
    <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
    <script type="module">
        import * as THREE from 'three';
        function main() {
            const canvas = document.querySelector('#c');
            const renderer = new THREE.WebGLRenderer({ canvas });


            const fov = 40;
            const aspect = 2;  // the canvas default
            const near = 0.1;
            const far = 1000;
            const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
            camera.position.z = 120;


            const scene = new THREE.Scene();
            scene.background = new THREE.Color(0xAAAAAA);
            {
                const color = 0xFFFFFF;
                const intensity = 1;
                const light = new THREE.DirectionalLight(color, intensity);
                light.position.set(-1, 2, 4);
                scene.add(light);
            }


            // 원시 모델 수정 부분

            const objects = [];
            const spread = 15;

            function addObject(x, y, obj) {
                obj.position.x = x * spread;
                obj.position.y = y * spread;

                scene.add(obj);
                objects.push(obj);
            }

            function createMaterial() {
                const material = new THREE.MeshPhongMaterial({
                    side: THREE.DoubleSide,
                });
                const hue = Math.random();
                const saturation = 1;
                const luminance = .5;
                material.color.setHSL(hue, saturation, luminance);

                return material;
            }

            function addSolidGeometry(x, y, geometry) {
                const mesh = new THREE.Mesh(geometry, createMaterial());
                addObject(x, y, mesh);
            }

            {
                const radius = 7;
                const widthSegments = 12;
                const heightSegments = 8;
                const geometry = new THREE.SphereGeometry(radius, widthSegments, heightSegments);
                const material = new THREE.PointsMaterial({
                    color: 'red',
                    size: 15,     // 글로벌 단위
                    sizeAttenuation: false,
                });
                const points = new THREE.Points(geometry, material);
                addObject(0, 0, points);
            }

        function resizeRendererToDisplaySize(renderer) {
            const canvas = renderer.domElement;
            const pixelRatio = window.devicePixelRatio;
            const width = canvas.clientWidth * pixelRatio | 0;
            const height = canvas.clientHeight * pixelRatio | 0;
            const needResize = canvas.width !== width || canvas.height !== height;
            if (needResize) {
                renderer.setSize(width, height, false);
            }
            return needResize;
        }

        function render(time) {
            time *= 0.001;  // convert time to seconds

            if (resizeRendererToDisplaySize(renderer)) {
                const canvas = renderer.domElement;
                camera.aspect = canvas.clientWidth / canvas.clientHeight;
                camera.updateProjectionMatrix();
            }

            objects.forEach((obj, ndx) => {
                const speed = .5 + ndx * .05;
                const rot = time * speed;
                obj.rotation.x = rot;
                obj.rotation.y = rot;
            });


            renderer.render(scene, camera);

            requestAnimationFrame(render);
        }
        requestAnimationFrame(render);

        }
        main();



    </script>
</body>

</html>