初学three 基于tween.js完成聚焦等任务

3,275 阅读3分钟

初入公司,因为公司主要业务是three 3D,所以需要学习three.js,主要学习以视频为主,这里推荐老陈打码的视频,讲的不错,还免费

demo的环境搭建

1、创建文件夹后,npm init  初始化  一路回车

2、下载依赖

2.1、安装parcel  www.parceljs.cn/getting_sta…

parcel 是 Web 应用打包工具,适用于经验不同的开发者。它利用多核处理提供了极快的速度,并且不需要任何配置。

首先通过 Yarn 或者 npm 安装 Parcel :

Yarn:

yarn global add parcel-bundler

npm:

npm install -g parcel-bundler

2.2  three依赖安装 github.com/mrdoob/thre…

npm install three

3、创建文件

这样,我们可以index.html中模块化引入main.js

<body>

    <script src="./main/main.js" type="module"></script>

</body>

4、配置package.json

接着,通过修改你的package.json来添加这些任务脚本

{

  "scripts": {

    "dev": "parcel src/index.html",

    "build": "parcel src/index.html"

  },

}

配置完成后,我们可以通过命令 npm run dev 启动项目或者npm run build进行打包

three初次尝试

我们的主要逻辑写在main.js文件中

1、所需依赖

import * as THREE from 'three'; // three.js

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'// 轨道控制器

const TWEEN = require('@tweenjs/tween.js') // 补间动画

其中tween tweenjs.github.io/tween.js/需要下载,后面需要tween.js控制相机聚焦

npm i @tweenjs/tween.js@^18

2、基础功能:相机、场景、光源、渲染器、控制器

2.1  相机

// 创建相机

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, .1, 10000);

camera.position.set(1000, 520, 760); // 设置相机的坐标

2.2 创建场景

// 创建场景

const scene = new THREE.Scene();

2.3 创建光源

// 环境光

let light = new THREE.AmbientLight(0xadadad); // soft white light

scene.add(light);

// 平行光源

const directionalLight = new THREE.DirectionalLight(0xffffff, 1);

directionalLight.position.set(1000, 1000, 0);

scene.add(directionalLight); 

2.4 创建地板

// 创建地板

const planeGeo = new THREE.PlaneGeometry(900, 900);

const planeMaterial = new THREE.MeshLambertMaterial({

    color: new THREE.Color('#333333'),

    side: THREE.DoubleSide

});

const planeMesh = new THREE.Mesh(planeGeo, planeMaterial);

planeMesh.rotation.x = -Math.PI / 2;

scene.add(planeMesh);

2.5 创建坐标系(可要可不要)

const helper = new THREE.AxesHelper(100);

scene.add(helper);

2.6 渲染器

// 渲染器

const renderer = new THREE.WebGLRenderer();

renderer.setSize(window.innerWidth, window.innerHeight);

document.body.appendChild(renderer.domElement);

2.7 控制器

// 轨道查看器

const controls = new OrbitControls(camera, renderer.domElement);

2.8 

function render() {

    requestAnimationFrame(render);

    TWEEN.update();

    renderer.render(scene, camera);

}

render();

3、制作建筑

以上步骤,已经做好了环境和基础功能,现在我们需要做一些方块表示建筑

// 随机生产大于10的数

function randWidth (width) {

  return Math.random() * width + 10;

}

// 创建若干个建筑物

const buildCount = 50;

const group = new THREE.Group();

for (let i=0; i < buildCount; i++) {

    const x = randWidth(20);

    const y = randWidth(100);

    const z = randWidth(10);

    const boxGeometry = new THREE.BoxBufferGeometry(x, y ,z);

    const positionX = 300 - randWidth(600);

    const positionZ = 300 - randWidth(600);

    boxGeometry.translate(positionX,  y / 2 ,positionZ);

    // 建筑颜色

    const material = new THREE.MeshBasicMaterial( { color: 0x5588aa } );

    const mesh = new THREE.Mesh(boxGeometry, material);

    mesh.isBuild = true;

    group.add(mesh);

}

scene.add(group);

4、用tween.js控制相机实现聚焦效果

聚焦实际上是相机的运动,所以我们只需要控制相机的位置就可以了

/************ tween动画 **************/
// 当前相机所在点位置
const p1 = {
    x: camera.position.x,
    y: camera.position.y,
    z: camera.position.z,
}
// 相机目标位置点
const p2 = {x:-400, y:520, z:760};

function cameraMove(position, time) {

    const tween1 = new TWEEN.Tween(p1).to(position, time).easing(TWEEN.Easing.Quadratic.InOut)

    tween1.onUpdate(() => {

      camera.position.set(p1.x, p1.y, p1.z)

      camera.lookAt(0, 0, 0)

    });

    return tween1;

}

function action() {

    const tweena = cameraMove({ x: 20, y: 100, z: 100 }, 4000);

    tweena.start();

}

5、模型拾取

这里只展示代码和实现,具体参考请看 Three.js的物体点击选中拾取原理剖析

请注意这里是three.js全屏模式下的点击选中拾取原理

addClick();

function addClick () {

    var raycaster = new THREE.Raycaster();//光线投射,用于确定鼠标点击位置

    var mouse = new THREE.Vector2();//创建二维平面

    window.addEventListener("mousedown",mousedown);//页面绑定鼠标点击事件

    //点击方法

    function mousedown(e){

        //将html坐标系转化为webgl坐标系,并确定鼠标点击位置

        mouse.x =  e.clientX / renderer.domElement.clientWidth*2-1;

        mouse.y-(e.clientY / renderer.domElement.clientHeight*2)+1;

        //以camera为z坐标,确定所点击物体的3D空间位置

        raycaster.setFromCamera(mouse,camera);

        //确定所点击位置上的物体数量

        var intersects = raycaster.intersectObjects(scene.children);

        //选中后进行的操作

        if(intersects.length){

            console.log(intersects[0].object);

        }

    }

}

点击建筑打印

我们也可以通过isBuild判断是否是建筑物,监听mousemove更改鼠标样式,

function mousemove(e){

  //将html坐标系转化为webgl坐标系,并确定鼠标点击位置

  mouse.x =  e.clientX / renderer.domElement.clientWidth*2-1;

  mouse.y =  -(e.clientY / renderer.domElement.clientHeight*2)+1;

  //以camera为z坐标,确定所点击物体的3D空间位置

  raycaster.setFromCamera(mouse,camera);

  //确定所点击位置上的物体数量

  var intersects = raycaster.intersectObjects(scene.children);

  //选中后进行的操作

  var body = document.querySelector("body")

  if(intersects.length){

      if (intersects[0].object.isBuild) {

          console.log(intersects[0].object.isBuil)

          body.style.cursor= "move"

      } else {

          body.style.cursor= "auto"

      }     

      } else {

        body.style.cursor= "auto"

  }

}

6、点击模型颜色变更

在上述mousedown监听的方法中,执行setSelected 

if(intersects.length){

  if (intersects[0].object.isBuild) {

    intersects[0].object.material.color.set(0xffffff); // 将建筑设置为白色

  }

}

效果展示

我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!