Three.js + GreenSock 模拟简单随机动画

什么是three.js

Three.js封装了底层的图形接口,使得程序员可以在无需掌握繁冗的图形学知识的状况下,也能用简单的代码实现三维场景的渲染,相对于webGL,Three.js封装了底层的图形接口,在不了解图形学的状况下,也能用简单的代码实现三维场景的渲染javascript

预览地址html

开始使用

CDN引入java

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
复制代码

建立环境

一个基本的Three.js程序至少要包括渲染器(Renderer)、场景(Scene)、照相机(Camera),以及你在场景中建立的物体。git

  • 场景(Scene) 放置全部物体的空间容器,三维空间。直接new一个Scene类建立调用3d场景的实例 new scene = new THREE.Scene()
  • 照相机(Camera) three.js 采用的是右手坐标系

共有四种:立方相机(Cube Camera)、正交(Orthographic Camera)、透视(Perspective Camera)、立体(Stereo Camera) 经常使用:正投影相机(THREE.OrthographicCamera) 和透视投影相机(THREE.PerspectiveCamera)。

其中 透视投影相机 (PerspectiveCamera)更真实的模仿人眼中的现实世界,本例也将用到程序员

THREE.PerspectiveCamera(fov, aspect, near, far)github

其构造函数接受四个不一样的参数,接受参数类型皆为Numberweb

fov — 摄像机视锥体垂直视野角度
aspect — 摄像机视锥体长宽比
near — 摄像机视锥体近端面
far — 摄像机视锥体远端面
复制代码

透视图

var camera = new THREE.PerspectiveCamera(
                75,//视野纵横比
                window.innerWidth / window.innerHeight,//基于浏览器宽高
                0.1,//近端距离 near
                1000,//远端距离 far
            )
//设置相机在z轴上的位置
    camera.position.z = 5;
复制代码
  • 渲染器(Renderer) 渲染器分别有 webGL| CSS2d | CSS3d | SVG ,其中webGL最灵活强大
var renderer = new THREE.WebGLRenderer({
    antialias: true, //是否反锯齿。默认为false
    /*
    canvas: canvas, //供渲染器绘制其输出的canvas,若是没有传这个参数,会建立一个新canvas
    precision:'highp', // 着色器精度. highp|mediump|lowp|highp(默认)
    alpha: flase, // canvas是否包含alpha (透明度)。默认为 false
    stencil: flase // 绘图缓存是否有模板缓存。默认为true
     */
    });
 renderer.setClearColor("#e5e5e5");
 renderer.setSize(window.innerWidth,window.innerHeight);

复制代码

建立好后把 renderer 生成的 dom 结构(其实就是一个 canvas 标签)append 到 html 里 document.body.appendChild(renderer.domElement);ajax

建立物体

环境布置好了,还差环境里的物体 Three.js 中提供了不少类型的物体,它们都继承自 Object3D 类,包括线段(Line)、骨骼(Bone)、粒子系统(ParticleSystem)。比较常见的是Mesh(网格),网格是由顶点、边、面等组成的物体,网格越多,物体表面越平滑,更接近模仿真实。canvas

任何物体都有形状,材质api

  • 形状geometry 形状有超多种嗷...圆环,球体,柱体,柱体,文字形状...各类各样任君挑选,但都是简单基本模型,复杂模型仍是须要导入的,支持导入*.obj 的外部模型
  • 材质material 材质(Material)是独立于物体顶点信息以外的与渲染效果相关的属性。经过设置材质能够改变物体的颜色、纹理贴图、光照模式 这里采用的是Lambert材质(MeshLambertMaterial)是符合Lambert光照模型的材质。Lambert光照模型的主要特色是只考虑漫反射而不考虑镜面反射的效果,对于大部分物体的漫反射效果都是适用的。
//3d物体包括物理形状和材料
      var geometry = new THREE.BoxGeometry(1, 1, 1);//半径、宽度、圆滑度
      var material = new THREE.MeshLambertMaterial({color: 0xf7f7f7});
      //建立MESH模型
      var mesh = new THREE.Mesh(geometry, material);
复制代码

场景和物体都有了, 这个时候打开浏览器看到的是一个黑不溜秋的丑丑正方形,好像和3d搭不上边嗷...

其实这里还缺了关键的灯光,不一样的光影效果可让画面更丰富。

Three.js 提供了包括环境光 (AmbientLight)、点光源 (PointLight)、聚光灯 (SpotLight)、方向光 (DirectionalLight)、半球光 (HemisphereLight) 等多种光源。 只要在场景中添加须要的光源,再加上必定的物体旋转就行了。这里用到PointLight,

var light = new THREE.PointLight(0xffffff, 1, 500);//颜色,强度,距离
    light.position.set(0,0,10); //设置光源位置
    scene.add(light);
    mesh.rotation.set(45,45,0);

复制代码

而后页面上的模型效果是这样

制做动画

动效库有不少,这里用使用gasp(green sock)复杂动画序列使用的时间轴插件TimelineMax,详见文档tweenmax中文手册

添加射线

浏览器是一个2d视口,而在里面显示three.js的内容是3d场景,因此,如今有一个问题就是如何将2d视口的x和y坐标转换成three.js场景中的3d坐标。three.js已经有了解决相关问题的方案,那就是THREE.Raycaster射线,用于鼠标去获取在3D世界被鼠标选中的一些物体

//声明raycaster和mouse变量
    var raycaster = new THREE.Raycaster();
    var mouse = new THREE.Vector3();
复制代码

光线投射Raycaster使用的是官方文档里的案例光线投射

TweenMax API

  • .to( target, duration, vars, position)
参数 类型 说明
target Object 须要动画的对象
duration Number 动画持续的秒数(或帧)
vars Object 动画参数(CSS属性、延迟、重复次数等)
position 插入动画的位置
  • ease:过渡效果的速度曲线(缓动效果),在动画的参数中设置各类缓动来控制动画的变化率, Expo :特殊缓动
function onMouseMove(event){
      event.preventDefault();
      // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)            
      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);
          for(let i = 0; i<intersects.length ; i++){
              //选中与射线相交的物体
                  this.tl = new TimelineMax().delay(.3);
                  //添加动效
                  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")//提早-1.5s发生
                }
                }
            render();
            //添加监听事件
            window.addEventListener('mousemove', onMouseMove)
复制代码

这个时候能够看到物体已经动起来了

效果实现

能够看到最后的效果是随机建立一个个模型并分散在页面上的,因此这里循环建立多个模型,经过random改变其在 x , y , z上的position来达到“迎面而来” 动画效果

meshCount = 0;
    for( var i = 0 ;i < 20 ;i++) {
        var mesh = new THREE.Mesh(geometry, material);
        mesh.position.x =( Math.random() - 0.5) *10;
        mesh.position.y =( Math.random() - 0.5) *10;
        mesh.position.z =( Math.random() - 0.5) *10;
        scene.add(mesh);
        meshCount++;
  }
复制代码

这个时候能够看出光是不够的,须要再加一个光源,光源的位置坐标、强度、距离、衰退量能够根据本身的感受调节

var light = new THREE.PointLight(0xffffff, 1, 1000);//颜色,强度,距离
light.position.set(0,0,0);
scene.add(light);
复制代码

多个随机模型 效果如图

响应式

经过浏览器大小自动改变渲染的模型大小

//监听窗口改变同时更新
  window.addEventListener('resize',()=>{
      renderer.setSize(window.innerWidth,window.innerHeight);
      camera.aspect = window.innerWidth / window.innerHeight;
      //注意,最后必定要调用updateProjectionMatrix()方法更新
      camera.updateProjectionMatrix();
  })
  //最后渲染
  var render = function(){
      //不会由于浏览器宽高影响图形
      requestAnimationFrame(render);
      renderer.render(scene,camera);
  }
复制代码

最后加个标题就完成了

最后

参考:

TimelineMax中文手册

three.js文档

three.js入门指南

学习three.js,除了还有官方的文档和案例 还有就是羡辙小姐姐的three.js人门指南。羡辙姐姐是我在GitHub上第一个关注的人,超级喜欢她~

第一次在掘金发文章,但愿你们多多指点 ~

相关文章
相关标签/搜索