three.js 最小环境搭建

news/2024/7/7 19:01:11

完整目录:
在这里插入图片描述

1、html

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

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <style>
      html,
      body {
        width: 100%;
        height: 100%;
        overflow: hidden;
        margin: 0;
        padding: 0;
      }

      #app {
        width: 100%;
        height: 100%;
      }

    </style>


    <script type="importmap">
    {
      "imports": {
        "three": "./three/three.module.js",
        "three/examples/": "./three/examples/"
      }
    }
  </script>

    <script type="module">
      import * as THREE from 'three'
      import { Stage } from './Stage.js'
      window.THREE = THREE;

      class HelloWorldDemo {
        constructor(stage) {
          this.stage = stage;
          this.addBox(100);
        }

        addBox(size) {
          var geometry = new THREE.BoxGeometry(size, size, size);
          var material = new THREE.MeshBasicMaterial({
            color: 0x63e42a,
            emissive: 0x072534,
            side: THREE.DoubleSide,
          })
          var cube = new THREE.Mesh(geometry, material);
          cube.name = "test_cube"
          this.stage.scene.add(cube);
          return cube;
        }
      }

      window.onload = () => {
        const stage = new Stage("#app", {
          // cameraType: "orthographi"
        });
        stage.run();

        window.stage = stage;
        new HelloWorldDemo(stage);
      };

    </script>

    <div id="app"></div>
  </head>

  <body>
  </body>

</html>

2、Stage.js

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

export class Stage {

  /**
   *
   * @param {*} container
   * @param {*} param
   * @param {* } param.disableControl
   * @param {* } param.cameraType "perspective" / "orthographi"
   * @param {boolean} param.needLight
   */
  constructor(container, param) {
    this.mouse = new THREE.Vector2()
    this.raycaster = new THREE.Raycaster();

    param = param || {}
    param.cameraType = param.cameraType || "perspective"
    param.needLight = param.needLight || true;

    this.fuArr = []
    this.viceCamera = null
    this.tmpTarget = new THREE.Vector3()
    this.orbitControls = null
    this.cameraHelper = null
    this.container = container;
    this.initFlag = false;
    // 场景
    this.scene = new THREE.Scene();
    this.scene.name = "moumade";

    if (param.needLight) {
      // 环境光
      var ambient = new THREE.AmbientLight(0xffffff, 0.5);
      ambient.name = "ambient";
      this.scene.add(ambient);

      let dirLight = new THREE.DirectionalLight(0xffffff, 0.5);
      dirLight.position.set(100, 100, 100);
      dirLight.name = "dirLight";
      this.scene.add(dirLight);
    }


    // 渲染器
    this.containerEle = document.querySelector(container);
    let vW = this.containerEle.clientWidth;
    let vH = this.containerEle.clientHeight;
    this.renderer = new THREE.WebGLRenderer({
      antialias: true,
      alpha: false,
      // preserveDrawingBuffer: true,
      // failIfMajorPerformanceCaveat: true,
    });
    // this.renderer.setClearColor(0x33334c, 1.0);
    this.renderer.setClearColor(0xf8f8f8, 1.0);
    // this.renderer.autoClear = true;
    this.renderer.setSize(vW, vH, false);
    this.renderer.setPixelRatio(window.devicePixelRatio);
    // console.error(vW, vH);

    this.containerEle.appendChild(this.renderer.domElement);
    if (param.cameraType == "perspective") {
      this.camera = new THREE.PerspectiveCamera(45, 1, 1, 500000000)
    } else if (param.cameraType == "orthographi") {
      this.camera = new THREE.OrthographicCamera(-vW / 2, vW / 2, -vH / 2, vH / 2, 0.1, 10000)
    }

    this.camera.lookAt(0, 0, 0)
    this.camera.name = "camera";
    this.scene.add(this.camera);
    this.handleResize = this.handleResize.bind(this)
    this._loop = this._loop.bind(this)
    window.addEventListener("resize", this.handleResize);

    this._isRun = true;
    // window.addEventListener("pointerdown", (event) => {
    //   this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    //   this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    //   this.raycaster.setFromCamera(this.mouse, this.camera)
    //   const intersects = this.raycaster.intersectObjects(this.scene.children);
    //   console.error(intersects[0].point);

    // });
    this.handleResize();
    if (param && param.disableControl) {

    } else {
      this.initControls();
    }
    this.camera.position.set(0, 0, 1000)

    if (!param.disableAxis) {
      // let axis = new THREE.AxesHelper(10000000);
      // this.scene.add(axis);
      // this.axis = axis;
    }


    // @ts-ignore
    // this.stats = new Stats();
    // this.stats.domElement.style.position = 'absolute';
    // this.stats.domElement.style.left = '0px';
    // this.stats.domElement.style.top = '0px';
    // this.stats.domElement.style.width = '100px';
    // this.stats.domElement.id = 'stats';
    // this.containerEle.appendChild(this.stats.dom);

    this._loop()
  }

  initControls() {
    let control = new OrbitControls(this.camera, this.renderer.domElement);
    this.control = control
    // 使动画循环使用时阻尼或自转 意思是否有惯性
    control.enableDamping = true;
    //动态阻尼系数 就是鼠标拖拽旋转灵敏度
    control.dampingFactor = 0.35;
    //是否可以缩放
    control.enableZoom = true;
    control.zoomSpeed = 0.35;
    //是否自动旋转
    control.autoRotate = false;
    //设置相机距离原点的最远距离
    // control.minDistance = 22; //1000
    //设置相机距离原点的最远距离
    // control.maxDistance = 50; //3000
    //是否开启右键拖拽
    // control.enablePan = false;
  }

  handleResize() {
    // 获取新的大小
    let vpW = this.containerEle.clientWidth;
    let vpH = this.containerEle.clientHeight;
    // 设置场景
    this.renderer.domElement.width = vpW;
    this.renderer.domElement.height = vpH;
    this.renderer.setSize(this.containerEle.clientWidth, this.containerEle.clientHeight);
    // 设置相机
    (this.camera).aspect = vpW / vpH;
    this.camera.updateProjectionMatrix();
  }


  run() {
    // this._loop()
    this._isRun = true;
  }

  stop() {
    this._isRun = false;
  }

  addViceCamera(viceCamera) {
    this.viceCamera = viceCamera
  }

  // setRender(v: any) {
  //   this.state = v
  // }
  onUpdate(fu) {
    this.fuArr.push(fu)
  }

  _loop() {
    // this.stats.update()
    this.camera.updateProjectionMatrix();
    this.camera.updateMatrixWorld()
    this._isRun !== false && this.renderer.render(this.scene, this.camera);

    this.fuArr.forEach(fun => {
      fun()
    });
    this.control && this.control.update()
    requestAnimationFrame(this._loop)
  }
}


http://lihuaxi.xjx100.cn/news/1293869.html

相关文章

split()方法详解

split&#xff08;&#xff09;方法详解 1.split()主要是用于对一个字符串进行分割成多个字符串数组。标准形式为String [] strings str.split(“”); 2.split()方法中括号中的参数可以为一个也可以为多个&#xff0c;每个参数之间用|隔开。并且每个参数之间要紧挨着|。 如&am…

String、StringBuffer和StringBuilder的区别(面试题)

目录 一、介绍String、StringBuffer和StringBuilder三大类 1.String类 2.StringBuffer类 3.StringBuilder类 4.什么是字符串常量池 4.StringBuilder类为什么不需要同步进行同步操作 二、关于String、StringBuffer和StringBuilder常见的面试题 1.为什么String是不可变的…

MyBatis 中,如何实现插件开发?

MyBatis 中&#xff0c;如何实现插件开发&#xff1f; 在 MyBatis 中&#xff0c;可以通过实现拦截器接口 Interceptor 来编写自己的插件。 插件需要实现 Interceptor 接口&#xff0c;并定义拦截行为和拦截对象的类型。实现 Interceptor 接口需要实现三个方法&#xff1a;int…

<List<Map<String, Object>>> List Map 转 List<T>工具类

工具类&#xff1a; package com.itheima.util;import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Map;public class ListMapToBeanUtils {/*** List<Map<String, Object>>转List<T>*/public static &…

【数据挖掘】时间序列模型处理指南(一)

一、说明 序模型是一组按时间排序的数据点,用于预测未来。以下是您需要了解的所有信息。 无论我们希望预测金融市场趋势还是电力消耗,时间都是我们的模型中必须考虑的重要因素。例如,预测电力消耗高峰的时间会很有趣。这对于调整电价或电力生产可能很有用。 二、什么是时序…

C语言:移位操作注意事项

移位操作&#xff1a;因为操作符的原因&#xff0c;注意加括号。还有没必要在移位的时候进行&#xff08;uint32_t&#xff09;转换。 测试程序如下&#xff1a; #include <string.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h>i…

TP6的服务在自定义composer包中如何使用

官方关于Service的说明文档&#xff1a; https://www.kancloud.cn/manual/thinkphp6_0/1037490 做下概念说明&#xff1a; Service和Provider在TP6中扮演着不同的角色。Service是用于封装特定功能的类&#xff0c;而Provider是用于注册和配置Service的类。 这里的Service指的…

基于51单片机的智能教室系统

目录 基于51单片机的智能教室系统一、原理图二、部分代码三、视频演示 基于51单片机的智能教室系统 功能&#xff1a; 1.通过LCD实时温度、光照强度、人数以及手自动模式 2.温度过高且有人的情况下打开空调 3.光强过弱的时候且有人的情况下打开照明灯 4.通过两个运放电路模拟进…