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
new scene = new THREE.Scene()
其中 透视投影相机 (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;
复制代码
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
//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使用的是官方文档里的案例光线投射
参数 | 类型 | 说明 |
---|---|---|
target | Object | 须要动画的对象 |
duration | Number | 动画持续的秒数(或帧) |
vars | Object | 动画参数(CSS属性、延迟、重复次数等) |
position | 插入动画的位置 |
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);
}
复制代码
最后加个标题就完成了
参考:
学习three.js,除了还有官方的文档和案例 还有就是羡辙小姐姐的three.js人门指南。羡辙姐姐是我在GitHub上第一个关注的人,超级喜欢她~
第一次在掘金发文章,但愿你们多多指点 ~