马上就要毕业了,实习进入了一个GIS公司,任务要求使用Threejs写个渐变的发光半球小特效,我完成后决定写出这篇文章。给那些刚刚接触Threejs的朋友们。
首先了解过Threejs的朋友们肯定知道threejs最重要的三个对象scene(场景)、camera(相机)、render(渲染)。如果不知道这些也没事,我推荐一个网站,我一开始也是在那里学习的。WebGL中文网看过这个一般对threejs和webGL有了初步的映像。
废话不多说,直接进入代码,我会在代码里写出注释并附上解释。代码非常简单所以就用notepaid++写了,首先加入我们的threejs库。建议下载threejs开源代码,因为里面还有其他模块后面会用到,比如转动镜头等等。
创建一个div叫做ThreeJS让他来存放我们的3维模型。
接下来编写js代码,首先创建scene,camera,render全局对象然后写一个初始化和动画函数。
1、创建场景
scene = new THREE.Scene();
2、创建相机
camera = new THREE.PerspectiveCamera( angle, ASPECT, NEAR, FAR);
第一个参数为俯角度,第二个为相机可视化范围的长宽比,第三个参数为相机离物体的最近距离,第四个参数为相机离物体的最远距离。(注意threejs的坐标系与我们日常用到的不一样,上下为y轴,横向为x轴,里外为z轴)。
之后很重要的一点就是把相机放入到场景中去。
scene.add(camera);
并初始化给他一个观察点。不然还是没有相机的(好比你去拍风景,带了相机去没有拿出来)。
camera.position.set(0,150,400);(注意坐标轴的问题,而且这个camera是全局变量的相机)
camera.lookAt(scene.position);//设置一个观察点
3、创建渲染
renderer = new THREE.WebGLRenderer( {antialias:true} );
其中的属性为抗锯齿效果设置为有效 ,也可以不加。定义完之后我们需要设定渲染的大小以及将其联系到我们的HTML中去。
renderer.setSize(width,height);
container = document.getElementById( 'ThreeJS' );
container.appendChild( renderer.domElement );
上述代码设置了renderer的大小,其次通过appendChild方法将渲染连接到dom元素上去。(container设置成全局变量)。这样我们就创建好了我们三大最基本的ThreeJS元素。接下来我们创建我们的半球。
我们使用球体也就是sphereGeometry,其中有6各参数。
var sphereGeom = new THREE.SphereGeometry( 40, 40, 40 ,0,Math.PI*2,0,Math.PI/2);//半球几何
SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength);radius是球的半径,默认为50;widthSegments是水平分割面的数量(最小为3,默认为8),heightSegments是垂直分割面的数量(最小为2,默认为6)。这个越多就越接近真正的球体。下图可以清楚的分辨2者的不同。
phiStart是水平起始角度,默认为0;phLength是指定水平扫描角度大小,默认是Math.PI*2也就是一整圆;thetaStart为指定垂直的起始角度;最后一个为thetaLength指定垂直扫描角度大小,默认值为Math.PI。为什么不是2PI呢?我猜想是水平已经扫了一个圆,垂直只要半圆就能完成一个球的绘制。反过来垂直扫了整圆,水平也只要半圆就够了。我们完成几何体的创建后只需要在几何外表上铺一层皮才能显示。这里threejs提供了许多不同的“皮”,要选择适合自己的材料。这里我们多用几种,首先是兰伯特网孔材料(MeshLambertMaterial)它是一种自身并不会发光 受光源影响大的一种材料。这里我们创建一个红色半透明的材质。还有其他许多种属性,这里我们就不全部举例。需要的同学可以再官网api上查找,我以我自己的例子为主。
var redMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000, transparent: true, opacity: 0.5 ,side: THREE.DoubleSide});//一个颜色为红色,开启透明度,透明度为0.5,双面渲染的一个半球。
然后创建一个object,类型为Mesh。他的参数使我们之前创的几何模型以及材料
var sphere = new THREE.Mesh(sphereGeom.clone(),redMaterial);
sphere.position.set(0,0,0);
scene.add(sphere);
我们将它坐标设置为0,0,0。并且让场景去加载他。之前也说了兰伯特材料是不发光的,所以要给他一个光源我们才能看到物体。就像黑漆漆的夜晚我们无法看到绚丽多彩的世界。光源的种类也有很多种,官网的例子也丰富多彩。一不小心可能一下午就过去了(〃'▽'〃)。这里我用的是最基础的平行光源,就像太阳照射进来的效果一样。
var directionalLight = new THREE.DirectionalLight( 0xffffff, 100 );
directionalLight.position.set( 0, 1000, 0 );
scene.add( directionalLight );
上述代码是创建一种平行光,100的光照强度位置在0,1000,0的位置,并且场景去添加这个光源。最后我们将场景和相机都渲染出来,这样我们就能看到我们的半球了。代码是
requestAnimationFrame(animate);//不断回调渲染函数
renderer.render( scene, camera );//渲染场景和相机
那么如何去观察半球,以及这半球是不是半透明的呢?
这里我们添加辅助工具,可以控制相机角度的控件以及坐标系的辅助设施。非常简单,我们添加空间的js库然后实例化鼠标控制相机角度的对象就行了。js库为OrbitControls.js。
controls = new THREE.OrbitControls( camera, renderer.domElement );//实例化参数为相机和dom对象。
之后我们就能随意的用鼠标调整相机的位置了,就不用自己去写函数了,是不是非常方便?回到正题我们创建坐标轴的辅助对象,这回不需要控件js。
var helpers = new THREE.Group();//实例化辅助对象组
helpers.add( new THREE.AxesHelper( 200 ) );//添加坐标系控件长度为200
scene.add( helpers );//添加到场景
效果图:
然后我们添加渐变球的效果。我提一个问题考考大家,我双面设置后为啥反面还是黑色的,答案很简单的。
var green = new THREE.SphereGeometry( 40., 100, 100 ,0,Math.PI*2,0,Math.PI/2);//几何体
var greenMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff, vertexColors: THREE.VertexColors,transparent: true, opacity: 0.5 ,side: THREE.DoubleSide } );//创建材质其中将定点颜色设置为THREE.VertexColors
sphere1 = new THREE.Mesh( green, greenMaterial );
sphere1.position.set(0, 0, 0);
sphere1.scale.multiplyScalar(1.07);//等比例放大
scene.add( sphere1 );
创建后最基础的之后我们要把渐变特效给写出来,效果通常是写到不断渲染过程中的。代码如下
最终效果图