three.js教程创建消防场景示例二

先看下最终效果吧

开始   创建多个仓库自定义长宽高

可参考上一节three.js教程创建仓库场景示例一


  addHouse(){
    const house1 = new House(150,80,20,this.scene)
    house1.setPosition(-50, 1, 100)
    house1.addToScene(this.scene)
    this.meshList.push(...house1.instance.children)

    const house2 = new House(80,40,20,this.scene)
    house2.setPosition(90, 1, 120)
    house2.addToScene(this.scene)
    this.meshList.push(...house2.instance.children)

    const house3 = new House(200,100,20,this.scene)
    house3.setPosition(0, 1, -120)
    house3.setRotation(0,-Math.PI/2,0)
    house3.addToScene(this.scene)
    this.meshList.push(...house3.instance.children)
  }


  addBox(){
    let w=6
    let x_length = 0
    let y_length = 0
    let z_length = 0
    let boxgroup = new THREE.Group()
    const geometry = new THREE.BoxBufferGeometry(w,w,w)
    const material = new THREE.MeshLambertMaterial({
      color:0xb99b75
    })
    for (let index = 1; index <= 5; index++) {
      if(index%2 == 0){
        x_length += w
      }else if(index%3 == 0){
        x_length -= w , z_length += w
      }else if(index%4 == 0){
        x_length += w
      }else if(index%5 == 0){
        x_length -= w , y_length += w , z_length -= w
      }else{
        x_length += w/2 , y_length += w/2 , z_length += w/2
      }
      let box = new THREE.Mesh(geometry, material)
      box.name = '盒子'+index
      let edges = new THREE.EdgesHelper( box, 0x000000 );//设置边框,可以旋转
      box.name = '盒子边框'+index
      box.position.set(x_length,y_length,z_length)
      edges.position.set(x_length,y_length,z_length)

      boxgroup.add(box)
      boxgroup.add( edges );
      this.meshList.push(box,edges)
    }
    boxgroup.position.set(30,0,-140)
    this.scene.add(boxgroup)
  }

 添加消防车,模型内容:消防车  消防员

addCar(){
    this.loader.load('./src/assets/gltf/xiaofang/car.gltf', (gltf) => {
      this.carmodel = gltf.scene;
      this.carmodel.scale.set(5, 5, 5); 
      this.carmodel.position.set(this.carX,0,220)
      this.carmodel.rotation.y = Math.PI/2
      this.scene.add(this.carmodel)
    });
  }

 消防车运动起来

animate () {
    // 执行运动动画
    if(this.renderer && this.camera){
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.animate.bind(this))
      
      if(this.carmodel && this.carX <= 20) {
        this.carmodel.position.set(this.carX,0,220)
        this.carX += 0.5
      }
    }
  }

消防车运动结束后消防员下车,创建消防员模型。此时如果看不见人,可能是因为太小了试着放大模型,调用消防员跑步动画,,添加消防路线 ,运动员跟随线跑起来并可转向


  addPerson(){
    this.loader.load('./src/assets/gltf/xiaofang/person.gltf', (gltf) => {
      console.log(gltf);
      this.personmodel = gltf.scene;
      this.personmodel.scale.set(15, 15, 15); 
      this.personmodel.position.set(20,0,200)
      this.personmodel.rotation.y = Math.PI
      this.scene.add(this.personmodel)

      // 调用动画
      var mixer = new THREE.AnimationMixer( gltf.scene.children[0] ); 
      mixer.clipAction( gltf.animations[ 0 ] ).setDuration( 1 ).play();
      this.mixers.push( mixer );
      this.addLine()
    });
  }
personanimate(){
    var delta = this.clock.getDelta();
    for ( var i = 0; i < this.mixers.length; i ++ ) { // 重复播放动画
      this.mixers[ i ].update( delta );
    }
  }
  addLine(){
    this.curve = new THREE.CatmullRomCurve3( [
      new THREE.Vector3( 20,1,200 ),
      new THREE.Vector3( 20, 1, 50 ),
      new THREE.Vector3( 100, 1, 20 ),
      new THREE.Vector3( 0, 1, -60 ),
    ],false ); // 是否闭合
    
    var points = this.curve.getPoints( 50 ); // 值越大越平滑
    var geometry = new THREE.BufferGeometry().setFromPoints( points );
    var material = new THREE.LineBasicMaterial( { color : 0xffffff } );
    
    this.line = new THREE.Line( geometry, material )
    this.scene.add(this.line)
  }
  addRunperson(){
    if (this.progress > 1.0) {
      return; //停留在管道末端,否则会一直跑到起点 循环再跑
    }
    this.progress += 0.0009;  // 控制速度
    let point = this.curve.getPoint(this.progress);
    if (point && point.x) {
      //模型的偏移量
      let offsetAngle = Math.PI;
      //创建一个4维矩阵
      let mtx = new THREE.Matrix4();
      mtx.lookAt(this.personmodel.position.clone(), point, this.personmodel.up);
      mtx.multiply(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, offsetAngle, 0)));
      //计算出需要进行旋转的四元数值
      let toRot = new THREE.Quaternion().setFromRotationMatrix(mtx);
      //根据以上值调整角度
      this.personmodel.quaternion.slerp(toRot, 0.2);
      this.personmodel.position.set(point.x, point.y, point.z);
    }
  }

  
animate () {
    // 执行运动动画
    if(this.renderer && this.camera){
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.animate.bind(this))
      this.mixers.length>0 && this.personanimate()
      
      if(this.carmodel && this.carX <= 20) {
        this.carmodel.position.set(this.carX,0,220)
        this.carX += 0.5
      }else if(this.carmodel && this.carX > 20){
        !this.exitPerson && !this.personmodel && this.addPerson()
        this.exitPerson = true
      }
      this.line && this.personmodel && this.addRunperson()
    }
  }

完整代码如下

director.js

import Template from "../common/Template"
import * as THREE from 'three'
import House from "../objects/House"
import TWEEN from '@tweenjs/tween.js'
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"
export default class Director extends Template{
  constructor (ele) {
    super()
    this.ele = ele
    this.PCamera.fov = 45
    this.PCamera.far = 10000
    this.PCamera.near = 1
    this.rendererColor = new THREE.Color(0x01031c)
    this.cameraPostion = new THREE.Vector3(300, 200, 0)
    this.clock = new THREE.Clock();
    this.mixers = []
    this.doorstatus = 'close'
    this.loader = new GLTFLoader();
    this.carmodel = undefined
    this.carX = -100
    this.exitPerson = false
    this.personmodel = undefined
    this.line = undefined
    this.curve = undefined
    this.progress = 0

    this.init(this.ele)
    this.addLight() 
    this.addAxesHelper(1000)
    if(this.camera && this.renderer) this.addOrbitControls(this.camera, this.renderer.domElement);
    this.animate()
    this.addGround()
    this.addHouse()
    this.addBox()
    // 监听鼠标点击
    this.onMouseDown(this.addMouseDown.bind(this))
    // 添加消防车人
    this.addCar()
  }
  addRunperson(){
    if (this.progress > 1.0) {
      return; //停留在管道末端,否则会一直跑到起点 循环再跑
    }
    this.progress += 0.0009;  // 控制速度
    let point = this.curve.getPoint(this.progress);
    if (point && point.x) {
      //模型的偏移量
      let offsetAngle = Math.PI;
      //创建一个4维矩阵
      let mtx = new THREE.Matrix4();
      mtx.lookAt(this.personmodel.position.clone(), point, this.personmodel.up);
      mtx.multiply(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, offsetAngle, 0)));
      //计算出需要进行旋转的四元数值
      let toRot = new THREE.Quaternion().setFromRotationMatrix(mtx);
      //根据以上值调整角度
      this.personmodel.quaternion.slerp(toRot, 0.2);
      this.personmodel.position.set(point.x, point.y, point.z);
    }
  }
  addLine(){
    this.curve = new THREE.CatmullRomCurve3( [
      new THREE.Vector3( 20,1,200 ),
      new THREE.Vector3( 20, 1, 50 ),
      new THREE.Vector3( 100, 1, 20 ),
      new THREE.Vector3( 0, 1, -60 ),
    ],false ); // 是否闭合
    
    var points = this.curve.getPoints( 50 ); // 值越大越平滑
    var geometry = new THREE.BufferGeometry().setFromPoints( points );
    var material = new THREE.LineBasicMaterial( { color : 0xffffff } );
    
    this.line = new THREE.Line( geometry, material )
    this.scene.add(this.line)
  }
  addPerson(){
    this.loader.load('./src/assets/gltf/xiaofang/person.gltf', (gltf) => {
      console.log(gltf);
      this.personmodel = gltf.scene;
      this.personmodel.scale.set(15, 15, 15); 
      this.personmodel.position.set(20,0,200)
      this.personmodel.rotation.y = Math.PI
      this.scene.add(this.personmodel)

      // 调用动画
      var mixer = new THREE.AnimationMixer( gltf.scene.children[0] ); 
      mixer.clipAction( gltf.animations[ 0 ] ).setDuration( 1 ).play();
      this.mixers.push( mixer );
      this.addLine()
    });
  }
  personanimate(){
    var delta = this.clock.getDelta();
    for ( var i = 0; i < this.mixers.length; i ++ ) { // 重复播放动画
      this.mixers[ i ].update( delta );
    }
  }
  addCar(){
    this.loader.load('./src/assets/gltf/xiaofang/car.gltf', (gltf) => {
      this.carmodel = gltf.scene;
      this.carmodel.scale.set(5, 5, 5); 
      this.carmodel.position.set(this.carX,0,220)
      this.carmodel.rotation.y = Math.PI/2
      this.scene.add(this.carmodel)
    });
  }
  addMouseDown(){
    console.log(this.intersects);
    // 门特效
    let list = this.intersects.filter((item)=>item.object.name == '门')
    console.log(list[0].object,list[0].object.geometry.parameters.width/2);
    if(list.length > 0){
      if(this.doorstatus == 'close'){
        list[0].object.rotateY(-Math.PI / 2);
        list[0].object.translateOnAxis(new THREE.Vector3(0, 0, 1), list[0].object.geometry.parameters.width/2);
        list[0].object.translateOnAxis(new THREE.Vector3(1, 0, 0), list[0].object.geometry.parameters.width/2);
        this.doorstatus = 'open'
      }else{
        list[0].object.rotateY(Math.PI/2);
        list[0].object.translateOnAxis(new THREE.Vector3(0, 0, 1), -list[0].object.geometry.parameters.width/2);
        list[0].object.translateOnAxis(new THREE.Vector3(1, 0, 0), list[0].object.geometry.parameters.width/2);
        this.doorstatus = 'close'
      }
    }
  }
  addBox(){
    let w=6
    let x_length = 0
    let y_length = 0
    let z_length = 0
    let boxgroup = new THREE.Group()
    const geometry = new THREE.BoxBufferGeometry(w,w,w)
    const material = new THREE.MeshLambertMaterial({
      color:0xb99b75
    })
    for (let index = 1; index <= 5; index++) {
      if(index%2 == 0){
        x_length += w
      }else if(index%3 == 0){
        x_length -= w , z_length += w
      }else if(index%4 == 0){
        x_length += w
      }else if(index%5 == 0){
        x_length -= w , y_length += w , z_length -= w
      }else{
        x_length += w/2 , y_length += w/2 , z_length += w/2
      }
      let box = new THREE.Mesh(geometry, material)
      box.name = '盒子'+index
      let edges = new THREE.EdgesHelper( box, 0x000000 );//设置边框,可以旋转
      box.name = '盒子边框'+index
      box.position.set(x_length,y_length,z_length)
      edges.position.set(x_length,y_length,z_length)

      boxgroup.add(box)
      boxgroup.add( edges );
      this.meshList.push(box,edges)
    }
    boxgroup.position.set(30,0,-140)
    this.scene.add(boxgroup)
  }
  addHouse(){
    const house1 = new House(150,80,20,this.scene)
    house1.setPosition(-50, 1, 100)
    house1.addToScene(this.scene)
    this.meshList.push(...house1.instance.children)

    const house2 = new House(80,40,20,this.scene)
    house2.setPosition(90, 1, 120)
    house2.addToScene(this.scene)
    this.meshList.push(...house2.instance.children)

    const house3 = new House(200,100,20,this.scene)
    house3.setPosition(0, 1, -120)
    house3.setRotation(0,-Math.PI/2,0)
    house3.addToScene(this.scene)
    this.meshList.push(...house3.instance.children)
  }
  addGround(){
    const groundGeometry = new THREE.PlaneGeometry(300,500)
    const groundMaterial = new THREE.MeshLambertMaterial({
      color:0x454942
    })

    let ground = new THREE.Mesh(groundGeometry, groundMaterial)
    ground.rotation.x = -Math.PI/2
    ground.name = '地'
    this.scene.add(ground)
    this.meshList.push(ground)
  }
  addLight(){
    this.addAmbientLight(0x666666)
    this.addDirectionalLight(0xdfebff,{x:50, y:200, z:100},1)
  }
  animate () {
    // 执行运动动画
    if(this.renderer && this.camera){
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.animate.bind(this))
      TWEEN.update();
      this.mixers.length>0 && this.personanimate()
      
      if(this.carmodel && this.carX <= 20) {
        this.carmodel.position.set(this.carX,0,220)
        this.carX += 0.5
      }else if(this.carmodel && this.carX > 20){
        console.log(111111);
        !this.exitPerson && !this.personmodel && this.addPerson()
        this.exitPerson = true
      }
      this.line && this.personmodel && this.addRunperson()
    }
  }
}

House.js和其他template等文件见three.js教程创建仓库场景示例一

three.js教程学习初始化配置

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值