相机控制

相机控制

1、平移,pan.js:
import * as THREE from 'three'
/**
 * 鼠标右键, 平移控制
 */
export default class Pan {
  constructor(param) {
    const { camera, dampingFactor, target, domWidth, domHeight, enableDamping } = param
    this.param = param
    this.panOffset = new THREE.Vector3();
    this.panStart = new THREE.Vector2();
    this.panEnd = new THREE.Vector2();
    this.panDelta = new THREE.Vector2();
    this.panSpeed = 1
  }

  setPanStart(x, y) {
    this.panStart.set(x, y)
  }

  setPanEnd(x, y) {
    this.panEnd.set(x, y)
    this.panDelta.subVectors(this.panEnd, this.panStart).multiplyScalar(this.panSpeed)
    this.setPanStart(x, y)
    this.pan(this.panDelta.x, this.panDelta.y);
    this.update()
  }

  panLeft(distance, objectMatrix) {
    var v = new THREE.Vector3();
    v.setFromMatrixColumn(objectMatrix, 0); // get X column of objectMatrix
    v.multiplyScalar(-distance);
    this.panOffset.add(v);
  }

  panUp(distance, objectMatrix) {
    var v = new THREE.Vector3();
    v.setFromMatrixColumn(objectMatrix, 1);
    v.multiplyScalar(distance);
    this.panOffset.add(v);
  }

  pan(deltaX, deltaY) {
    const offset = new THREE.Vector3()
    const { camera, target, domWidth, domHeight } = this.param
    var position = camera.position;
    offset.copy(position).sub(target);
    var targetDistance = offset.length();

    // half of the fov is center to top of screen
    targetDistance *= Math.tan((camera.fov / 2) * Math.PI / 180.0);

    // we use only clientHeight here so aspect ratio does not distort speed
    this.panLeft(2 * deltaX * targetDistance / domWidth, camera.matrix);
    this.panUp(2 * deltaY * targetDistance / domHeight, camera.matrix);
  }

  update() {
    const { camera, target } = this.param
    camera.position.add(this.panOffset)
    target.add(this.panOffset);
    this.panOffset.set(0, 0, 0)
  }
}

2、缩放Dolly.js:
import * as THREE from 'three'
/**
 * 缩放控制
 */
export default class Dolly {
  constructor(param) {
    this.param = param
    this.zoomSpeed = 1
    this.scale = 1
  }

  handle(deltaY) {
    if (deltaY> 0) {
      this.dollyOut(this.getZoomScale())
    } else {
      this.dollyIn(this.getZoomScale())
    }
    this.update()
  }
  dollyOut(dollyScale) {
    this.scale /= dollyScale
  }
  dollyIn(dollyScale) {
    this.scale *= dollyScale
  }

  getZoomScale() {
    return Math.pow(0.95, this.zoomSpeed);
  }

  update() {
    let { target } = this.param

    let spherical = new THREE.Spherical();
    const offset = new THREE.Vector3();
    var position = this.param.camera.position
    offset.copy(position).sub(target);
    spherical.setFromVector3(offset);
    spherical.radius *= this.scale
    this.scale = 1

    offset.setFromSpherical(spherical);
    position.copy(target).add(offset);
  }
}

3、旋转rotation.js
import * as THREE from 'three'
/**
 * 鼠标左键, 旋转控制
 */
export default class Rotation {
  constructor(param) {
    const { camera, dampingFactor, target, domWidth, domHeight, enableDamping } = param
    this.param = param

    this.spherical = new THREE.Spherical();
    this.sphericalDelta = new THREE.Spherical();

    this.rotateStart = new THREE.Vector2();
    this.rotateEnd = new THREE.Vector2();
    this.rotateDelta = new THREE.Vector2();

    this.rotateSpeed = 1.0
    this.quat = new THREE.Quaternion().setFromUnitVectors(this.param.camera.up, new THREE.Vector3(0, 1, 0));
    this.quatInverse = this.quat.clone().invert();
  }

  setRotateEnd(x, y) {
    this.rotateEnd.set(x, y)
    this.rotateDelta.subVectors(this.rotateEnd, this.rotateStart).multiplyScalar(this.rotateSpeed);
    this.rotateLeft(2 * Math.PI * this.rotateDelta.x / this.param.domWidth);
    this.rotateUp(2 * Math.PI * this.rotateDelta.y / this.param.domHeight);
    this.rotateStart.copy(this.rotateEnd);
    this.update()
  }

  setRotateStart(x, y) {
    this.rotateStart.set(x, y)
  }

  rotateLeft(angle) {
    this.sphericalDelta.theta -= angle;
  }

  rotateUp(angle) {
    this.sphericalDelta.phi -= angle;
  }

  update() {
    let { target, dampingFactor, camera, enableDamping } = this.param
    enableDamping = false
    const offset = new THREE.Vector3();
    var position = this.param.camera.position

    offset.copy(position).sub(target);
    // offset.applyQuaternion(this.quat);
    this.spherical.setFromVector3(offset);

    if (enableDamping) {
      this.spherical.theta += this.sphericalDelta.theta * this.dampingFactor;
      this.spherical.phi += this.sphericalDelta.phi * dampingFactor;
    } else {
      this.spherical.theta += this.sphericalDelta.theta;
      this.spherical.phi += this.sphericalDelta.phi;
    }

    offset.setFromSpherical(this.spherical);
    // offset.applyQuaternion(this.quatInverse);

    position.copy(target).add(offset);
    camera.lookAt(target);

    if (enableDamping) {
      this.sphericalDelta.theta *= (1 - dampingFactor);
      this.sphericalDelta.phi *= (1 - dampingFactor);
    } else {
      this.sphericalDelta.set(0, 0, 0);
    }

  }
}

4、使用
import * as THREE from 'three'
import Rotation from './Rotation.js'
import Pan from './Pan.js'
import Dolly from './Dolly.js'

export default class myOrbitControls {
  constructor(camera, domElement) {
    // 全局参数
    this.camera = camera
    this.domElement = domElement
    this.target = new THREE.Vector3(0, 0, 0)

    this.pan = new Pan({
      camera: this.camera,
      target: this.target,
      domWidth: this.domElement.width,
      domHeight: this.domElement.height,
    })

    this.dolly = new Dolly({
      camera: this.camera,
      target: this.target,
      domWidth: this.domElement.width,
      domHeight: this.domElement.height,
    })
    this.rotation = new Rotation({
      camera: this.camera,
      enableDamping: false,
      dampingFactor: 0.05,
      target: this.target,
      domWidth: this.domElement.width,
      domHeight: this.domElement.height,
    })

    // 鼠标参数
    this.mouseState = null
    this.mouseAction = null
    this.onPointerDown = this.onPointerDown.bind(this)
    this.onPointerMove = this.onPointerMove.bind(this)
    this.onPointerUp = this.onPointerUp.bind(this)
    this.onWheel = this.onWheel.bind(this)
    this.initEvent()
  }

  initEvent() {
    this.domElement.addEventListener('pointerdown', this.onPointerDown);
    this.domElement.ownerDocument.addEventListener('pointerup', this.onPointerUp);
    this.domElement.ownerDocument.addEventListener('pointermove', this.onPointerMove);
    this.domElement.addEventListener('contextmenu', this.onContextMenu);
    this.domElement.addEventListener('wheel', this.onWheel);
  }

  onWheel(event) {
    const { deltaY } = event
    this.dolly.handle(deltaY)
  }
  onContextMenu(event) {
    event.preventDefault();
  }
  onPointerMove(event) {
    if (this.mouseState != "down") return
    const mouse = { x: event.clientX, y: event.clientY }

    switch (this.mouseAction) {
      case THREE.MOUSE.ROTATE:
        this.rotation.setRotateEnd(mouse.x, mouse.y)
        break;

      case THREE.MOUSE.PAN:
        this.pan.setPanEnd(mouse.x, mouse.y)
        break
    }
  }

  onPointerUp() {
    this.mouseState = "up"
  }

  onPointerDown(event) {
    this.mouseState = "down"
    event.preventDefault();
    const mouse = { x: event.clientX, y: event.clientY }
    switch (event.button) {
      case 0:
        this.mouseAction = THREE.MOUSE.ROTATE;
        this.rotation.setRotateStart(mouse.x, mouse.y)
        break;

      case 2:
        this.mouseAction = THREE.MOUSE.PAN;
        this.pan.setPanStart(mouse.x, mouse.y)
        break;

      default:
        this.mouseAction = -1;
    }
  }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值