不爱贞子爱爽子
バキューン

1、安装

"three": "^0.155.0",   //主体  主要是这个
"three-obj-mtl-loader": "^1.0.3",  // 加载外部模型
"dat-gui": "^0.5.0",//gui 设置
"@tweenjs/tween.js": "^21.0.0", //动画
2、官网
https://threejs.org/manual/#zh/textures
 
3、引入使用
import * as THREE from "three";
4、简单例子
 1.太阳-地球-月亮
模拟场景与场景之间的联系
<html>
  <head>
    <meta charset="utf-8" />
    <title>太阳系 three.js app</title>
    <style>
      html,
      body {
        margin: 0;
        height: auto;
        overflow-y: auto;
      }
      #c {
        width: 100%;
        height: 100%;
        display: block;
      }
    </style>
  </head>
  <body>
    <canvas id="c"></canvas>
    <div id="ui"></div>
    <script
      async
      src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"
    ></script>

    <script type="importmap">
      {
        "imports": {
          "three": "https://unpkg.com/three@0.155.0/build/three.module.js",
          "three/addons/": "https://unpkg.com/three@0.155.0/examples/jsm/"
        }
      }
    </script>
    <script type="module">
      //导入
      import * as THREE from "three";
      import { GUI } from "three/addons/libs/lil-gui.module.min.js";
      //   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 resizeRendererToDisplaySize(renderer) {
        // const canvas = renderer.domElement;
        const canvas = document.querySelector("#c");
        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 main() {
        const canvas = document.querySelector("#c");

        //创建渲染器
        const renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
        const gui = new GUI();
        // 创建相机
        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.set(0, 50, 0);
        camera.up.set(0, 0, 1);
        camera.lookAt(0, 0, 0);

        // 创建场景
        const scene = new THREE.Scene();

        // 创建灯光
        {
          const color = 0xffffff;
          const intensity = 500;
          const light = new THREE.PointLight(color, intensity);
          scene.add(light);
        }
        // 要更新旋转角度的对象数组
        const objects = [];

        // 创建场景图
        const solarSystem = new THREE.Object3D();
        scene.add(solarSystem);
        objects.push(solarSystem);
        
        // 创建地球场景
        const earthOrbit = new THREE.Object3D();
        earthOrbit.position.x = 10;
        // scene.add(earthOrbit);
        solarSystem.add(earthOrbit);
        objects.push(earthOrbit);

        // 创建月球场景
        const moonOrbit = new THREE.Object3D();
        moonOrbit.position.x = 2;
        // scene.add(moonOrbit);
        earthOrbit.add(moonOrbit);
        objects.push(moonOrbit);

        // 一球多用
        const radius = 1;
        const widthSegments = 6;
        const heightSegments = 6;
        const sphereGeometry = new THREE.SphereGeometry(
          radius,
          widthSegments,
          heightSegments
        );
        //  地球

        //   const textGeometry = new THREE.TextGeometry(text, {
        //     font: font,
        //     size: size,
        //     height: height,
        //     curveSegments: curveSegments,
        //     bevelEnabled: bevelEnabled,
        //     bevelThickness: bevelThickness,
        //     bevelSize: bevelSize,
        //   });
        //   const textMesh = new THREE.Mesh(
        //     textGeometry,
        //     new THREE.MeshPhongMaterial({
        //       side: THREE.DoubleSide,
        //       emissive: 0xffff00,
        //     })
        //   );
        //   scene.add(textMesh);
        {
          // 创建一个太阳
          const sunMaterial = new THREE.MeshPhongMaterial({
            side: THREE.DoubleSide,
            emissive: 0xffff00,
          });
          const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          sunMesh.scale.set(5, 5, 5); // 扩大太阳的大小
          // scene.add(sunMesh);
          solarSystem.add(sunMesh);
          objects.push(sunMesh);

          // 创建地球
          const earthMaterial = new THREE.MeshPhongMaterial({
            color: 0x2233ff,
            emissive: 0x112244,
          });
          const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);

          //   earthMesh.position.x = 10;
          //   scene.add(earthMesh);
          // 将地球变为太阳的子节点
          // sunMesh.add(earthMesh);
          earthOrbit.add(earthMesh);
          objects.push(earthMesh);

          // 创建月球
          const moonMaterial = new THREE.MeshPhongMaterial({
            color: 0x888888,
            emissive: 0x222222,
          });
          const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial);
          moonMesh.scale.set(0.5, 0.5, 0.5);
          moonOrbit.add(moonMesh);
          objects.push(moonMesh);

          class AxisGridHelper {
            constructor(node, units = 10) {
              const axes = new THREE.AxesHelper();
              axes.material.depthTest = false;
              axes.renderOrder = 2; // 在网格渲染之后再渲染
              node.add(axes);

              const grid = new THREE.GridHelper(units, units);
              grid.material.depthTest = false;
              grid.renderOrder = 1;
              node.add(grid);

              this.grid = grid;
              this.axes = axes;
              this.visible = false;
            }
            get visible() {
              return this._visible;
            }
            set visible(v) {
              this._visible = v;
              this.grid.visible = v;
              this.axes.visible = v;
            }
          }

          function makeAxisGrid(node, label, units) {
            const helper = new AxisGridHelper(node, units);
            gui.add(helper, "visible").name(label);
          }

          // makeAxisGrid(solarSystem, "solarSystem", 25);
          // makeAxisGrid(sunMesh, "sunMesh");
          // makeAxisGrid(earthOrbit, "earthOrbit");
          // makeAxisGrid(earthMesh, "earthMesh");
          // makeAxisGrid(moonOrbit, "moonOrbit");
          // makeAxisGrid(moonMesh, "moonMesh");
        }
        function render(time) {
          time *= 0.001; // convert time to seconds

          objects.forEach((obj) => {
            obj.rotation.y = time;

            // const axes = new THREE.AxesHelper();
            // axes.material.depthTest = false;
            // axes.renderOrder = 1;
            // obj.add(axes);
          });

          if (resizeRendererToDisplaySize(renderer)) {
            camera.aspect = canvas.clientWidth / canvas.clientHeight;
            camera.updateProjectionMatrix();
          }
          renderer.render(scene, camera);

          requestAnimationFrame(render);
        }

        requestAnimationFrame(render);
      }

      main();
    </script>
  </body>
</html>

效果:

 2.八大行星

外部模型的加载使用

<html>
  <head>
    <meta charset="utf-8" />
    <title>太阳系八大行星 three.js app</title>
    <style>
      html,
      body {
        margin: 0;
        height: auto;
        overflow-y: auto;
      }
      #c {
        width: 100%;
        height: 100%;
        display: block;
      }
    </style>
  </head>
  <body>
    <canvas id="c"></canvas>
    <div id="ui"></div>
    <script
      async
      src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"
    ></script>

    <script type="importmap">
      {
        "imports": {
          "three": "https://unpkg.com/three@0.155.0/build/three.module.js",
          "three/addons/": "https://unpkg.com/three@0.155.0/examples/jsm/"
        }
      }
    </script>
    <script type="module">
      //导入
      import * as THREE from "three";
      import { GUI } from "three/addons/libs/lil-gui.module.min.js";
      import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
      import { OrbitControls } from "three/addons/controls/OrbitControls.js";
      // 响应式处理
      function resizeRendererToDisplaySize(renderer) {
        // const canvas = renderer.domElement;
        const canvas = document.querySelector("#c");
        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 main() {
        const canvas = document.querySelector("#c");

        //创建渲染器
        const renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
        const gui = new GUI();
        // 创建相机
        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.set(0, 50, 0);
        camera.lookAt(0, 0, 0);

        // 旋转相机
        const controls = new OrbitControls(camera, canvas);
        controls.target.set(0, 5, 0);
        controls.update();

        // 创建场景
        const scene = new THREE.Scene();

        // 创建灯光
        {
          const color = 0xffffff;
          const intensity = 500;
          const light = new THREE.PointLight(color, intensity);
          scene.add(light);
        }
        // 要更新旋转角度的对象数组
        const objects = [];

        // 创建场景图
        const solarSystem = new THREE.Object3D();
        scene.add(solarSystem);
        objects.push(solarSystem);

        // 创建水星场景
        const mercurySystem = new THREE.Object3D();
        mercurySystem.position.x = 3.5;
        solarSystem.add(mercurySystem);
        objects.push(mercurySystem);

        // 创建维纳斯场景
        const venusSystem = new THREE.Object3D();
        venusSystem.position.x = 6;
        solarSystem.add(venusSystem);
        objects.push(venusSystem);

        // 创建地球场景
        const earthOrbit = new THREE.Object3D();
        earthOrbit.position.x = 10;
        solarSystem.add(earthOrbit);
        objects.push(earthOrbit);

        // 创建金星场景
        const marsOrbit = new THREE.Object3D();
        marsOrbit.position.x = 13;
        solarSystem.add(marsOrbit);
        objects.push(marsOrbit);

        // 创建jupiter场景
        const jupiterOrbit = new THREE.Object3D();
        jupiterOrbit.position.x = 15;
        solarSystem.add(jupiterOrbit);
        objects.push(jupiterOrbit);

        // 创建saturn场景
        const saturnOrbit = new THREE.Object3D();
        saturnOrbit.position.x = 20;
        solarSystem.add(saturnOrbit);
        objects.push(saturnOrbit);

        // 创建uranus场景
        const uranusOrbit = new THREE.Object3D();
        uranusOrbit.position.x = 24;
        solarSystem.add(uranusOrbit);
        objects.push(uranusOrbit);

        // 创建neptune场景
        const neptuneOrbit = new THREE.Object3D();
        neptuneOrbit.position.x = 29;
        solarSystem.add(neptuneOrbit);
        objects.push(neptuneOrbit);

        {
          //载入太阳
          const loader = new GLTFLoader();
          // 一球多用
          const radius = 1;
          const widthSegments = 6;
          const heightSegments = 6;
          const sphereGeometry = new THREE.SphereGeometry(
            radius,
            widthSegments,
            heightSegments
          );
          const sunMaterial = new THREE.MeshPhongMaterial({
            side: THREE.DoubleSide,
            emissive: 0xffff00,
          });
          const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          const mercuryMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          const venusMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          const earthMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          const marsMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          const jupiterMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          const saturnMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          const uranusMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          const neptuneMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
          const modelList = [
            {
              path: "model/sun.glb",
              scale: [0.2, 0.2, 0.2],
              fatherObj: solarSystem,
              mesh: sunMesh,
            },
            {
              path: "model/mercury_enhanced_color.glb",
              scale: [0.5, 0.5, 0.5],
              fatherObj: mercurySystem,
              mesh: mercuryMesh,
            },
            {
              path: "model/venus.glb",
              scale: [1, 1, 1],
              fatherObj: venusSystem,
              mesh: venusMesh,
            },
            {
              path: "model/earth.glb",
              scale: [1, 1, 1],
              fatherObj: earthOrbit,
              mesh: earthMesh,
            },
            {
              path: "model/mars.glb",
              scale: [15, 15, 15],
              fatherObj: marsOrbit,
              mesh: marsMesh,
            },
            {
              path: "model/jupiter.glb",
              scale: [1, 1, 1],
              fatherObj: jupiterOrbit,
              mesh: jupiterMesh,
            },
            {
              path: "model/saturn.glb",
              scale: [0.01, 0.01, 0.01],
              fatherObj: saturnOrbit,
              mesh: saturnMesh,
            },
            {
              path: "model/uranus.glb",
              scale: [1, 1, 1],
              fatherObj: uranusOrbit,
              mesh: uranusMesh,
            },
            {
              path: "model/neptune.glb",
              scale: [1, 1, 1],
              fatherObj: neptuneOrbit,
              mesh: neptuneMesh,
            },
          ];
          modelList.forEach((item) => {
            loader.load(
              item.path,
              function (gltf) {
                gltf.scene.traverse(function (child) {
                  if (child.isMesh) {
                    child.frustumCulled = false;
                    //模型阴影
                    child.castShadow = true;
                    //模型自发光
                    child.material.emissive = child.material.color;
                    child.material.emissiveMap = child.material.map;
                  }
                });
                gltf.scene.scale.set(...item.scale);
                item.fatherObj.add(gltf.scene);
                // sunMesh.add(gltf.scene)
                objects.push(gltf.scene);
              },
              undefined,
              function (error) {
                console.error(error);
              }
            );
        //不使用模型 使用球体
            // item.fatherObj.add(item.mesh);
            // // sunMesh.add(gltf.scene)
            // objects.push(item.mesh);
          });

          class AxisGridHelper {
            constructor(node, units = 10) {
              const axes = new THREE.AxesHelper();
              axes.material.depthTest = false;
              axes.renderOrder = 2; // 在网格渲染之后再渲染
              node.add(axes);

              const grid = new THREE.GridHelper(units, units);
              grid.material.depthTest = false;
              grid.renderOrder = 1;
              node.add(grid);

              this.grid = grid;
              this.axes = axes;
              this.visible = false;
            }
            get visible() {
              return this._visible;
            }
            set visible(v) {
              this._visible = v;
              this.grid.visible = v;
              this.axes.visible = v;
            }
          }

          function makeAxisGrid(node, label, units) {
            const helper = new AxisGridHelper(node, units);
            gui.add(helper, "visible").name(label);
          }

          // makeAxisGrid(solarSystem, "solarSystem", 25);
          // makeAxisGrid(sunMesh, "sunMesh");
          // makeAxisGrid(earthOrbit, "earthOrbit");
          // makeAxisGrid(earthMesh, "earthMesh");
          // makeAxisGrid(moonOrbit, "moonOrbit");
          // makeAxisGrid(moonMesh, "moonMesh");
        }
        function render(time) {
          time *= 0.001; // convert time to seconds

          objects.forEach((obj, index) => {
            obj.rotation.y = time;
            // obj.rotation.x = time;

            // const axes = new THREE.AxesHelper();
            // axes.material.depthTest = false;
            // axes.renderOrder = 1;
            // obj.add(axes);
          });

          if (resizeRendererToDisplaySize(renderer)) {
            camera.aspect = canvas.clientWidth / canvas.clientHeight;
            camera.updateProjectionMatrix();
          }
          renderer.render(scene, camera);

          requestAnimationFrame(render);
        }

        requestAnimationFrame(render);
      }

      main();
    </script>
  </body>
</html>

效果:

 

posted on 2023-09-12 17:16  不爱贞子爱爽子  阅读(26)  评论(0编辑  收藏  举报

! !