vue-three 3d機(jī)房

<template>
  <div>
    <div id="three"></div>
  </div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
export default {
  data() {
    return {
      scene: {}, // 場(chǎng)景
      camera: {}, // 攝像機(jī)
      renderer: {}, // 渲染器

      labelRenderer: {}, // 
      clock: {},
    };
  },
  mounted(){
    this.threes();
    this.resize(); // 自適應(yīng)
  },
  methods: {
    // 瀏覽器窗口發(fā)生變化時(shí) 自適應(yīng)
    resize(){
      window.addEventListener('resize', () => {

        // 初始化攝像機(jī)
        this.camera.aspect = window.innerWidth/window.innerHeight;

        // 攝像機(jī)矩陣效果
        this.camera.updateProjectionMatrix();

        // 初始化渲染器
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        
        // 文字位置
        this.labelRenderer.setSize( window.innerWidth, window.innerHeight );

      })
    },

    threes() {
      // 創(chuàng)建場(chǎng)景
      this.scene = new THREE.Scene();

      // 創(chuàng)建攝像機(jī) // 參數(shù)含義: 視角、窗口投影長(zhǎng)寬比、攝像機(jī)從哪里開始渲染、距離攝像機(jī)多遠(yuǎn)截至渲染
      this.camera = new THREE.PerspectiveCamera(100, window.innerWidth/window.innerHeight, 0.1, 10000);

      // 創(chuàng)建three渲染器 參數(shù): 去鋸齒
      this.renderer = new THREE.WebGLRenderer({ antialias: true });

      // 開啟陰影,加上陰影渲染
      this.renderer.shadowMapEnabled = true;

      // 設(shè)置渲染器場(chǎng)景大小 參數(shù): 寬,高
      this.renderer.setSize(window.innerWidth, window.innerHeight);
      
      // 把渲染器添加到頁(yè)面中
      document.getElementById('three').appendChild(this.renderer.domElement);

      this.ground() // 地面模型

      this.wall({x: 5060, y: 1500, z: 20}, {x: 0, y: 750, z: -1400})
      this.wall({x: 5060, y: 1500, z: 20}, {x: 0, y: 750, z: 1400})
      this.wall({x: 20, y: 1500, z: 2880}, {x: 2490, y: 750, z: 0})
      this.wall({x: 20, y: 1500, z: 2880}, {x: -2490, y: 750, z: 0})
      this.wall({x: 5060, y: 30, z: 2880}, {x: 0, y: 1500, z: 0})

      // 機(jī)柜
      for(let i = 0; i < 5; i ++){
        this.chartlet((2100 - i * 740), 600, 300)
      }
      this.chartlet(800, 600, -1100)

      // 滅火器
      this.extinguisher(-2300, 150, 1200)

      // 配電柜
      this.power(1400, 240, -1170)

      // 煙感
      this.smokeSensor(200, 1470, 200)
      this.smokeSensor(1400, 1470, 200)
      this.smokeSensor(-1400, 1470, -700)
      
      // 溫濕度
      this.humitureSensor(200, 1470, -700)
      this.humitureSensor(1400, 1470, -700)

      // 監(jiān)控
      this.monitorSentor(2400, 1470, 900)
      this.monitorSentor(2400, 1470, -900)

      // 門
      this.door(-1500, 450, 1395)

      // 精密空調(diào)
      this.stulz(2300, 500, -1050)
      this.stulz(-2100, 500, -1180, 0, 200, 128, 90)

      // 創(chuàng)建光源
      this.createLight()

      // 輔助坐標(biāo)系  參數(shù)表示坐標(biāo)系大小,可以根據(jù)場(chǎng)景大小去設(shè)置
      // this.axesHelper = new THREE.AxesHelper(3000);
      // this.scene.add(this.axesHelper);

      // 攝像機(jī)空間軸位置
      this.camera.position.x = 0
      this.camera.position.y = 3000
      this.camera.position.z = 3000

      // 創(chuàng)建鼠標(biāo)控件對(duì)象
      this.controls = new OrbitControls( this.camera, this.labelRenderer.domElement );
      this.clock = new THREE.Clock();

      this.animate()
    },

    // 添加幀渲染
    animate(){
      requestAnimationFrame(this.animate);

      // 初始化controls
      this.controls.update()
      this.labelRenderer.render( this.scene, this.camera );
      this.render()
    },

    // 渲染器渲染場(chǎng)景和攝像機(jī)
    render(){
      this.renderer.render(this.scene, this.camera)
    },

    // 創(chuàng)建光源
    createLight () {
      // 環(huán)境光
      const ambint = new THREE.AmbientLight(0xffffff)
      this.scene.add(ambint)

      this.pointLight(0xffffff, -3000, 3000, -1000, 10000)
    },

    // 點(diǎn)光燈光源
    pointLight (color, x, y, z, dis) {
      const pointLight = new THREE.PointLight(color)
      pointLight.position.set(x, y, z); // 光源位置
      pointLight.castShadow = true; //開啟燈光投射陰影
      pointLight.intensity = 2; // 強(qiáng)度
      pointLight.penumbra = 1; // 半影
      pointLight.distance = dis; // 距離

      this.scene.add(pointLight)

      // 光源寄托
      // this.createLightView(color, x, y, z)
    },
    
    // 聚光燈光源
    spotLight (color, x, y, z, dis) {
      const spotLight = new THREE.SpotLight(color)
      spotLight.position.set(x, y, z); // 光源位置
      spotLight.castShadow = true; //開啟燈光投射陰影
      spotLight.intensity = 3 // 強(qiáng)度
      spotLight.angle = 0.3; // 角度
      spotLight.penumbra = 1; // 半影
      spotLight.decay = 1; // 衰退
      spotLight.distance = dis; // 距離

      this.scene.add(spotLight)

      // 輔助線
      let spotLightHelper = new THREE.SpotLightHelper(spotLight, 0x976fb6);
      this.scene.add(spotLightHelper)

      // 光源寄托
      // this.createLightView(color, x, y, z)
    },

    // 光源寄托
    createLightView(color, x, y, z){
      let geometry = new THREE.SphereGeometry(30, 30, 30);
      let material = new THREE.MeshPhongMaterial({ color });
      let cube = new THREE.Mesh(geometry, material);
      cube.position.set(x, y, z)
      this.scene.add(cube)
    },
    
    // 平面模型
    ground(){
      let geometry = new THREE.BoxGeometry(5000, 2800, 0);
      let material = new THREE.MeshLambertMaterial({ color: 0x659cae });
      let cube = new THREE.Mesh(geometry, material);
      cube.rotation.x = -0.5 * Math.PI
      cube.position.set(0, 0, 0)
      cube.receiveShadow = true
      this.scene.add(cube)
    },

    // 墻壁
    wall(size, position, opacity = 0.1){
      let data = {
        color: 0x07313F,
        transparent: true,
        opacity
      }
      let geometry = new THREE.BoxGeometry(size.x, size.y,size.z);
      let material = new THREE.MeshLambertMaterial(data);
      let cube = new THREE.Mesh(geometry, material);
      cube.position.set(position.x, position.y, position.z)
      this.scene.add(cube);
    },
    
    // 機(jī)柜
    chartlet(x, y, z){
      let map = new THREE.TextureLoader().load(require('@/assets/three/zhengm.png'));
      let map2 = new THREE.TextureLoader().load(require('@/assets/three/cem.png'));
      let map3 = new THREE.TextureLoader().load(require('@/assets/three/fanm.png'));
      let group = new THREE.Mesh();
      let color = 0x0c0c0c // 0x3C3B42
      let mats = [];
      let matsItems = [
        { map: map2 },
        { map: map2 },
        { color },
        { color },
        { map },
        { map: map3 },
      ]
      matsItems.forEach(item => {
        mats.push(new THREE.MeshPhongMaterial(item))
      })

      let cubeGeom = new THREE.BoxBufferGeometry(700, 1200, 360);
      let cube = new THREE.Mesh(cubeGeom, mats);
      cube.position.set(x, y, z)

      group.add(cube);
      this.scene.add(group)
      let objectContent = [
        {
          name: '名稱:',
          content: '機(jī)柜'
        },
        {
          name: '狀態(tài):',
          content: '正常'
        }
      ]
      this.fontText(cube, objectContent)
    },

    // 配電柜
    power(x = 0, y = 0, z = 0, big = 1){

      // 配電柜平面
      let powerItem = [
        [{x: 440, y: 780, z: 10},{x: 50, y: 150, z: -100}, null], // 后
        [{x: 440, y: 780, z: 10},{x: 50, y: 150, z: 30}, 0x888888], // 前
        [{x: 60, y: 780, z: 10},{x: -150, y: 150, z: 100}, null], // 前左
        [{x: 60, y: 780, z: 10},{x: 250, y: 150, z: 100}, null], // 前右
        [{x: 440, y: 60, z: 10},{x: 50, y: 515, z: 100}, null], // 前上
        [{x: 440, y: 60, z: 10},{x: 50, y: -210, z: 100}, null], // 前下
        [{x: 10, y: 780, z: 210},{x: -170, y: 150, z: 0}, null], // 左
        [{x: 10, y: 780, z: 200},{x: 270, y: 150, z: 0}, null], // 右
        [{x: 450, y: 10, z: 200},{x: 50, y: 540, z: 0}, null], // 上
        [{x: 450, y: 10, z: 200},{x: 50, y: -245, z: 0}, null], // 下
      ]
      for(let i = 0; i < powerItem.length; i ++){
        powerItem[i][1].x += x;
        powerItem[i][1].y += y;
        powerItem[i][1].z += z;
        this.powerItem(powerItem[i][0],powerItem[i][1],powerItem[i][2],powerItem[i][3]);
      }

      // 配電柜指示燈
      this.powerLamp({x: -30 + x, y: 280 + y, z: 35 + z}, 0xe73939)
      this.pointLight(0xe73939, -30 + x, 280 + y, 50 + z, 300)

      this.powerLamp({x: 50 + x, y: 280 + y, z: 35 + z}, 0x15c02d)
      this.pointLight(0x15c02d, 50 + x, 280 + y, 50 + z, 300)

      this.powerLamp({x: 130 + x, y: 280 + y, z: 35 + z}, 0xd1d81e)
      this.pointLight(0xd1d81e, 130 + x, 280 + y, 50 + z, 300)

      // 閃電標(biāo)識(shí)
      let map = new THREE.TextureLoader().load(require('@/assets/three/shand.png'));
      let geometry = new THREE.BoxGeometry(340, 480, 5);
      let material = new THREE.MeshLambertMaterial({map, transparent: true});
      let cube = new THREE.Mesh(geometry, material);
      cube.position.set(50 + x, 50 + y, 100 + z)
      this.scene.add(cube);
      let objectContent = [
        {
          name: '名稱:',
          content: '配電柜'
        },
        {
          name: '狀態(tài):',
          content: '正常',
        },
        {
          name: 'ABC相電壓:',
          content: '35KV / 15KV / 20KV',
          class: 'success'
        },
        {
          name: 'ABC相電流:',
          content: '1100A / 1000A / 1200A',
          class: 'warning'
        }
      ]
      this.fontText(cube, objectContent)

      // 鎖子
      let map2 = new THREE.TextureLoader().load(require('@/assets/three/suoz.png'));
      let geometry2 = new THREE.BoxGeometry(40, 120, 5);
      let material2 = new THREE.MeshLambertMaterial({map: map2, transparent: true});
      let cube2 = new THREE.Mesh(geometry2, material2);
      cube2.position.set(-150 + x, 120 + y, 110 + z)
      this.scene.add(cube2);
    },

    // 配電柜平面
    powerItem(size, position, color){
      let data = {
        color: color ? color : 0xc5c5c3
      }
      let geometry = new THREE.BoxGeometry(size.x, size.y, size.z);
      let material = new THREE.MeshLambertMaterial(data);
      let cube = new THREE.Mesh(geometry, material);
      cube.position.set(position.x, position.y, position.z)
      this.scene.add(cube);

    },

    // 配電柜指示燈
    powerLamp(size, color){
      let sphere = new THREE.SphereGeometry(20, 20, 20);
      let material = new THREE.MeshLambertMaterial({color});
      let cube = new THREE.Mesh(sphere, material);
      cube.position.set(size.x, size.y, size.z)
      this.scene.add(cube);
    },

    // 滅火器
    extinguisher(x, y, z){
      // 圓柱 1
      let cylinder = new THREE.CylinderGeometry( 20, 20, 30, 10 );
      let material0 = new THREE.MeshLambertMaterial({color: 0x333333});
      let cube = new THREE.Mesh(cylinder, material0);
      cube.position.set(x, 340, z)

      // 球體 2
      let sphere = new THREE.SphereGeometry(60, 60, 60);
      let material1 = new THREE.MeshLambertMaterial({color: 0xdb2c1f});
      let cube2 = new THREE.Mesh(sphere, material1);
      cube2.position.set(x, 280, z)

      // 圓柱 3
      let cylinder2 = new THREE.CylinderGeometry( 60, 60, 280, 100 );
      let texture = new THREE.TextureLoader().load(require('@/assets/three/mhq.png'));
      let material2 = new THREE.MeshLambertMaterial({map: texture});
      let cube3 = new THREE.Mesh(cylinder2, material2);
      cube3.position.set(x, y, z)
      cube3.rotation.y -= 1.6

      this.scene.add(cube);
      this.scene.add(cube2);
      this.scene.add(cube3);

      let objectContent = [
        {
          name: '名稱:',
          content: '滅火器'
        }
      ]
      this.fontText(cube2, objectContent)
    },

    // 煙感
    smokeSensor(x, y, z){
      // 柱狀1
      let cylinder = new THREE.CylinderGeometry( 55, 55, 4, 20 );
      let material = new THREE.MeshLambertMaterial({color: 0xd8d8c0, transparent: true, opacity: 0.8});
      let cube = new THREE.Mesh(cylinder, material);
      cube.position.set(x, y + 12, z)
      this.scene.add(cube);

      // 柱狀2
      let cylinder2 = new THREE.CylinderGeometry( 50, 50, 22, 20 );
      let material2 = new THREE.MeshLambertMaterial({color: 0xd8d8c0});
      let cube2 = new THREE.Mesh(cylinder2, material2);
      cube2.position.set(x, y, z)
      this.scene.add(cube2);

      // 柱狀3
      let texture = new THREE.TextureLoader().load(require('@/assets/three/yang.png'));
      let cylinder3 = new THREE.CylinderGeometry( 45, 35, 20, 15 );
      let material3 = new THREE.MeshLambertMaterial({map: texture});
      let cube3 = new THREE.Mesh(cylinder3, material3);
      cube3.position.set(x, y-15, z)
      this.scene.add(cube3);

      let objectContent = [
        {
          name: '名稱:',
          content: '煙感'
        },
        {
          name: '狀態(tài):',
          content: '正常',
          class: 'success'
        }
      ]
      this.fontText(cube3, objectContent)

    },

    // 溫濕度
    humitureSensor(x, y, z){

      // 立方體1
      let data = {
        color: 0xdcdcd9,
        transparent: true,
        opacity: 0.8
      }
      let geometry0 = new THREE.BoxGeometry(90, 4, 90);
      let material0 = new THREE.MeshLambertMaterial(data);
      let cube0 = new THREE.Mesh(geometry0, material0);
      cube0.position.set(x, y + 14, z)
      this.scene.add(cube0);

      // 立方體2
      let map = new THREE.TextureLoader().load(require('@/assets/three/wens.png'));
      let group = new THREE.Mesh();
      let color = 0xdcdcd9
      let mats = [];
      let matsItems = [
        { color },
        { color },
        { color },
        { map },
        { color },
        { color },
      ]
      matsItems.forEach(item => {
        mats.push(new THREE.MeshPhongMaterial(item))
      })

      let cubeGeom = new THREE.BoxBufferGeometry(80, 25, 80);
      let cube = new THREE.Mesh(cubeGeom, mats);
      cube.position.set(x, y, z)

      group.add(cube);
      this.scene.add(group)

      let objectContent = [
        {
          name: '名稱:',
          content: '溫濕度傳感器'
        },
        {
          name: '溫度:',
          content: '24℃',
          class: 'warning'
        },
        {
          name: '濕度:',
          content: '23%',
          class: 'primary'
        }
      ]
      this.fontText(cube, objectContent)
    },

    // 監(jiān)控
    monitorSentor(x, y, z){
      // 柱狀
      let cylinder = new THREE.CylinderGeometry( 30, 30, 10, 20 );
      let material = new THREE.MeshLambertMaterial({color: 0xd8d8c0, opacity: 0.6});
      let cube = new THREE.Mesh(cylinder, material);
      cube.position.set(x, y, z)
      this.scene.add(cube);
      // 柱狀2-1
      let cylinder2 = new THREE.CylinderGeometry( 3, 3, 40, 20 );
      let material2 = new THREE.MeshLambertMaterial({color: 0xd8d8c0});
      let cube2 = new THREE.Mesh(cylinder2, material2);
      cube2.position.set(x, y - 20, z)
      cube2.rotation.z -= 0.3
      this.scene.add(cube2);
      // 柱狀2-2
      let cylinder5 = new THREE.CylinderGeometry( 3, 3, 50, 20 );
      let material5 = new THREE.MeshLambertMaterial({color: 0xd8d8c0});
      let cube5 = new THREE.Mesh(cylinder5, material5);
      cube5.position.set(x - 30, y - 45, z)
      cube5.rotation.z += 5
      this.scene.add(cube5);

      // 柱狀3
      let cylinder3 = new THREE.CylinderGeometry( 35, 35, 70, 20 );
      let material3 = new THREE.MeshLambertMaterial({color: 0xd8d8c0});
      let cube3 = new THREE.Mesh(cylinder3, material3);
      cube3.position.set(x - 70, y - 60, z)
      cube3.rotation.z += 5
      this.scene.add(cube3);

      // 球體
      let sphere = new THREE.SphereGeometry(25, 25, 25);
      let material4 = new THREE.MeshPhongMaterial({color: 0x333333});
      let cube4 = new THREE.Mesh(sphere, material4);
      cube4.position.set(x - 90, y - 65, z)
      this.scene.add(cube4);

      let objectContent = [
        {
          name: '名稱:',
          content: '監(jiān)控'
        },
        {
          name: '狀態(tài):',
          content: '正常',
          class: 'success'
        }
      ]
      this.fontText(cube4, objectContent)
    },

    // 門
    door(x, y, z){
      let data = {
        color: 0x07313F,
        transparent: true,
        opacity: 0.3
      }
      let geometry = new THREE.BoxGeometry(550, 900, 40);
      let material = new THREE.MeshLambertMaterial(data);
      let cube = new THREE.Mesh(geometry, material);
      cube.position.set(x, y, z)
      this.scene.add(cube);
    },
    
    // 精密空調(diào) rotation-旋轉(zhuǎn)度數(shù)
    stulz(x, y, z, x1 = 128, y1 = 200, z1 = 0, rotation = 0){
      let geometry = new THREE.BoxGeometry(250, 1000, 600);
      let material = new THREE.MeshPhongMaterial({color: 0x3e3e3e});
      let cube = new THREE.Mesh(geometry, material);
      cube.position.set(x, y, z)

      rotation = Math.PI/(180/rotation)

      cube.rotation.y -= rotation
      this.scene.add(cube);
      this.stulzDevice(x, y, z, x1, y1, z1, rotation)

      let objectContent = [
        {
          name: '名稱:',
          content: '精密空調(diào)',
          class: 'primary'
        },
        {
          name: '開關(guān)狀態(tài):',
          content: '已開',
          class: 'success'
        },
        {
          name: '溫度:',
          content: '24℃',
          class: 'success'
        },
        {
          name: '濕度:',
          content: '46%',
          class: 'warning'
        },
        {
          name: '報(bào)警信息:',
          content: '暫無報(bào)警信息',
          class: 'danger'
        }
      ]
      this.fontText(cube, objectContent)
    },

    // 精密空調(diào) 顯示器
    stulzDevice(x, y, z, x1, y1, z1, rotation){
      let map = new THREE.TextureLoader().load(require('@/assets/three/jingm.jpg'));
      let geometry = new THREE.BoxGeometry(5, 200, 460);
      let material = new THREE.MeshPhongMaterial({map, transparent: true});
      let cube = new THREE.Mesh(geometry, material);
      
      cube.position.set(x - x1, y + y1, z + z1) 
      
      cube.rotation.y -= rotation
      this.scene.add(cube);
    },

    // 文字
    fontText(moon, contObj = []){

      // 創(chuàng)建文字容器
      const moonDiv = document.createElement( 'div' );
      moonDiv.className = 'label';
      moonDiv.style.marginTop = '3em';
      moonDiv.style.color = '#dddddd';
      moonDiv.style.fontSize = '12px';
      moonDiv.style.padding = '5px';
      moonDiv.style.backgroundColor = 'rgba(0,0,0,0.7)';

      if(contObj.length){
        contObj.forEach(item => {
          let moonTitle = document.createElement( 'span' )
          let moonContent = document.createElement( 'span' )
          let moonBr = document.createElement( 'br' )
          if(item.class) moonContent.className = item.class;
          moonTitle.textContent = item.name
          moonContent.textContent = item.content
          moonDiv.appendChild(moonTitle)
          moonDiv.appendChild(moonContent)
          moonDiv.appendChild(moonBr)
        })
      }

      const moonLabel = new CSS2DObject( moonDiv );
      moonLabel.position.set(0, 0.275, 0);
      moon.add( moonLabel );
   
      // 每次添加div前 先把原有的刪除
      let chArr = document.body.getElementsByClassName("labelRenderer")
      for(let i = 0;i < chArr.length; i++) if (chArr[i] != null) chArr[i].parentNode.removeChild(chArr[i]);

      // 創(chuàng)建2d渲染
      this.labelRenderer = new CSS2DRenderer();
      this.labelRenderer.setSize( window.innerWidth, window.innerHeight );
      this.labelRenderer.domElement.style.position = 'absolute';
      this.labelRenderer.domElement.style.top = '0px';
      this.labelRenderer.domElement.className = 'labelRenderer'
      document.body.appendChild( this.labelRenderer.domElement );
    },
  },
  beforeDestroy(){
    // 頁(yè)面卸載時(shí) 刪除創(chuàng)建的div
    let chArr = document.body.getElementsByClassName("labelRenderer")
    for(let i = 0;i < chArr.length; i++) if (chArr[i] != null) chArr[i].parentNode.removeChild(chArr[i]);
  }
};
</script>

<style scoped>
body {
  margin: 0;
  padding: 0;
  background-color: #000;
  color: #fff;
  font-family: Monospace;
  font-size: 13px;
  line-height: 24px;
  overscroll-behavior: none;
}
#info {
  position: absolute;
  top: 0px;
  width: 100%;
  padding: 0;
  box-sizing: border-box;
  text-align: center;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
  pointer-events: none;
  z-index: 1; /* TODO Solve this in HTML */
}

</style>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、WebGL與threeJS WebGL是一種3D繪圖協(xié)議,其允許JavaScript和OpenGL ES2.0...
    患者_(dá)閱讀 21,248評(píng)論 1 22
  • 上次說到需要準(zhǔn)備的有了, 這是一種開發(fā)的思路,就是如果做東西的技術(shù)已經(jīng)儲(chǔ)備的沒問題了,那就先想好要做什么,然后再準(zhǔn)...
    剛道閱讀 792評(píng)論 0 0
  • 之前在公司做項(xiàng)目的時(shí)候接到過一個(gè)需求, 因公司業(yè)務(wù)是做IT監(jiān)控,所以客戶要一個(gè)機(jī)房的3D展示,展示環(huán)境啊設(shè)備什么的...
    剛道閱讀 1,587評(píng)論 2 0
  • 機(jī)房的抽象準(zhǔn)備好了,下面該做唄做了, 但是呢,突然有個(gè)想法, 就是,IT項(xiàng)目很多,每個(gè)機(jī)房都不一樣,不可能每個(gè)都寫...
    剛道閱讀 1,129評(píng)論 2 0
  • 由于對(duì)WebGL的興趣,初步接觸Three.js,決定將學(xué)習(xí)過程進(jìn)行記錄,以便于后期復(fù)習(xí)。 初步以實(shí)現(xiàn)3D機(jī)房為目...
    Mr_ZhaiDK閱讀 2,941評(píng)論 0 2

友情鏈接更多精彩內(nèi)容