Three实战练习

ThreeJS面向速记部分业务

面向速记涉及的知识点:

1.相机
2.场景
3.渲染器
4.形状、材质、模型
5.位置、旋转、缩放
6.灯光
7.抗锯齿
8.光线投射器(拾取物体对象)
9.动画时间轴(采用第三方插件)

    开始动手之前,先引入两个框架:ThreeJS框架和TweenMax动画插件。

<!-- CDN引入threeJS框架 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>
<!-- CDN引入TimeMax动画插件 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>

    ThreeJS三大的基本:场景、相机、渲染器,因此是我们必须创建它们。

// 创建场景
 var scene = new THREE.Scene();
 // 创建相机,采用透视相机,四个参数
 var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
 //相机位置
 camera.position.set(0, 0, 5);
 
  // 创建WebGL渲染器,渲染器就像好几种类型的渲染器,比如css2D、css3D、SVG等渲染器,性能非常灵活
 var renderer = new THREE.WebGLRenderer({
     antialias: true
}); //创建抗锯齿,为了增加形状的边缘水平或垂直

 // 渲染器:设置背景颜色
 renderer.setClearColor("#e5e5e5"); //灰色
 // 渲染器:设置浏览器窗口的大小
 renderer.setSize(window.innerWidth, window.innerHeight);

    最后如何为创建在HTML文档的canvas元素?首先可以在js中创建为canvas元素,如下图:

// canvas对象相当于返回一个画布元素
document.body.appendChild(renderer.domElement);

    ThreeJS的三大基本已经OK了!接下来是创建形状、材质和模型:

// 创建形状,立方体
 var geometry = new THREE.BoxGeometry(1, 1, 1);
 // 创建面的材质
 var material = new THREE.MeshLambertMaterial({
     color: 0xF7F7F7
 });
// 把形状和材质保存到网格模型中
 var mesh = new THREE.Mesh(geometry, material);
 // 网格模型添加到场景中
 scene.add(mesh);

    根据以上的内容,可以说ThreeJS基本的知识已经完成了。

    接下来是灯光,创建了2个灯光环境方向,光源类型为点光源(PointLight),只是两个灯光的位置不同。一个是原点的位置(0,0,0),另一个是向屏幕画面离的值为25个单位。

// 创建灯光环境方向,增加两个灯光(点光源)
   var light = new THREE.PointLight(0xFFFFFF, 1, 1000);
   light.position.set(0, 0, 0);
   scene.add(light);

    var light = new THREE.PointLight(0xFFFFFF, 2, 1000);
    light.position.set(0, 0, 25);
    scene.add(light);

    但是另外考虑到有些方面,比如需要去监听那些事件,按键盘、窗口大小等,而且看渲染DOM元素是如何的?

    当我把浏览器窗口大小的变化时,发现渲染DOM元素的位置还是不动的,没反应。而且需要去手动刷新才能使渲染DOM元素变化,这样太麻烦了。如下图:
在这里插入图片描述
    因此,需要设置去监听浏览器窗口大小的变化。

// 所以需要监听窗口的大小发生变化
 window.addEventListener('resize', () => {
    // 每次重新调整窗口大小
    renderer.setSize(window.innerWidth, window.innerHeight);
    // 每次重新调整相机的变化
    camera.aspect = window.innerWidth / window.innerHeight;
    // 必须每次在相机上调用更新相机投影矩阵
    camera.updateProjectionMatrix();
})

      另外,为什么需要设置相机大小的变化?如果没有设置相机大小的变化,那么会让整个模型就会发生扭曲或变形。因此,需要设置相机大小的变化。

      接下来是做简单的动画,能不能像做到那种时间轴的实时动画过程,来试下。

      首先需要创建render函数,其实一般的浏览器每次实时刷新,每一秒相当于总是循环60次,也就是说60FPS,最重要的是时间间隔,解决的是通过requestAnimationFrame()提供了这些的需求,例如:大多数渲染的时候间隔是每秒60秒,一般会把每一帧DOM操作集中起来,一般来说频率为每秒60帧。
      简单来说,当每一帧刷新的变化时都会重新绘制渲染一次。

      另外设置给它模型的动画旋转为X轴和Y轴的变化,就像动画时间轴,这样实现动画的效果。

var render = function () {
// 修复形状发生扭曲,并请求动画帧
requestAnimationFrame(render);
// 每次调用渲染器时候都会添加(每秒帧数),就像动画序列一样,看起来很有趣的动画
mesh.rotation.x += 0.03;
mesh.rotation.y += 0.01;

 // renderer.render渲染我们需要渲染的场景和相机保存
 renderer.render(scene, camera);
 }
 //全局加载
 render();

      接下来是光线投射器(拾取物体对象),例如说允许你拖动鼠标在画布上的位置,然后可以确定你点击位置的物体对象并作出行为发生变化。

// 光线投射器
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

    另外还需要设置监听鼠标移动悬停的状态。

//在窗口鼠标移动悬停时的情况下就播放动画物体运动,
//在定义鼠标移动悬停的时候就调用它。
window.addEventListener('mousemove', onMouseMove);

      创建鼠标移动悬停的本身函数,一般在场景中有些不应的物体对象就会默认发生执行事件,所以需要设置preventDefault()。还需要获取鼠标x和y的位置,然后让它们放入光线投射器里面,同时设置鼠标和相机。最后,intersectObjects() 来判断指定对象有没有被光线点击,如果被点击就会返回对象的信息,一般返回类型就是数组的形式。

// 鼠标移动悬停的功能函数
function onMouseMove(event) {
    // 就是防止点击默认事件,例如:点击不应的物体对象就会阻止点击事件。
    event.preventDefault();
    // 直接从文档中获取,所以我们必须获取鼠标x和y的位置
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
     
     // 把它们放入我们的光线投射器,同时从相机设置,通过鼠标和相机。
    raycaster.setFromCamera(mouse, camera);

     // 计算与拾取射线相交的物体
     var intersects = raycaster.intersectObjects(scene.children, true);
     // console.log(scene.children);
     //

    光线投射器Raycaster基础:https://threejs.org/docs/#api/en/core/Raycaster

    接下来是采用TimelineMax第三方动画时间轴插件,主要是为了解决构建复杂的动画时间轴,因此它能使方便地、简单地构建动画时间轴。
    TimelineMax中文手册:https://www.tweenmax.com.cn/api/timelinemax/
    这些部分动画代码放在鼠标移动悬停函数里面,是根据intersectObject()返回类型为数组的形式,所以需要加循环。

// TimelineMax是GreenSock 动画平台
 for (var i = 0; i < intersects.length; i++) {
   // 创建新的时间线动画序列
   this.tl = new TimelineMax();
   // 有四帧动画运动
   this.tl.to(intersects[i].object.scale, 1, { x: 2, ease: Expo.easeOut })
   this.tl.to(intersects[i].object.scale, .5, { x: .5, ease: Expo.easeOut })
   this.tl.to(intersects[i].object.position, .5, { x: 2, ease: Expo.easeOut })
  this.tl.to(intersects[i].object.rotation, .5, { y: Math.PI * .5, ease: Expo.easeOut }, "=-1.5")
}

    大部分的知识点已经差不多完成了!
    还有如果想要多个物体对象的场景,根据已经设置了光线投射器,因此可以实现拾取物体对象。
    我设置了15个模型,所以需要循环15次并任何物体对象随机位置。另外手动刷新的时候,任何物体对象的位置总是会变化的。

效果图:
在这里插入图片描述
参考完整代码示例及效果图:http://192.168.10.26/digitalvisualization/threejs_tutorial/-/blob/master/hjb/shortindex.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值