这片云加了特效,Duang Duang Duang
首先,看下效果页面,感受一下。点我
是不是有点炫咧,这就是运用WebGL简单实现的效果,下面我们一起来看看代码吧。
Three.js
一个优秀的WebGL开源框架,官网地址https://github.com/mrdoob/three.js。点进去你会发现有好多酷炫的效果,而且基于这个库可以快速地写出3d程序。上面的镇魔曲手游官网的云海效果就是基于three.js实现的。
刚开始接触到Three.js,好多东西都是一头雾水的,然后官网的文档说明又是英文,阅读起来实在困难。在此强烈推荐一个中文基础教程,个人觉得对各种术语以及图形的构造和渲染理解起来相对简单些。英语厉害的同学可以忽略。
渲染的三大要素
在Three.js中,要渲染物体到网页中,我们需要3个组建:场景(scene)、相机(camera)和渲染器(renderer)。有了这三样东西,才能将物体渲染到网页中去。
所以,先初始化这三个东东。
scene = new THREE.Scene(); //场景,一个物体的容器
camera = new THREE.Camera( 30, w / h, 1, 3000 ); //相机,在场景中取一个合适的景,把它拍下来,可以理解为视角。
renderer = new THREE.WebGLRenderer( { antialias: false } );//渲染器
画云
实现步骤:
- 加载纹理
- 画一个平面
- 为平面赋予纹理坐标
- 将纹理应用于材质
加载纹理
在three.js中,纹理即图片。首先加载一张云的图片,方便后面将此纹理以一定的规则映射到平面上。这里要注意一下,采取相对路径,而且图片资源不能跨域,所以要配置一下fis,不然上线后会报cross-origin的错。
var texture = THREE.ImageUtils.loadTexture( './ignore/cloud10.png' );
画一个平面以及云的对应坐标
随机画出几百个无规律重叠的云,形成一片云海的即视感。
var geometry = new THREE.Geometry();
var plane = new THREE.Mesh( new THREE.Plane( 64, 64 ) ); //一个可在在三维3D空间无限延伸的二维平面。
var cloud_num = 400;
for ( i = 0; i < cloud_num; i++ ) {
plane.position.x = Math.random() * 1000 - 600;
plane.position.y = - Math.random() * Math.random() * 200 - 15;
plane.position.z = 1;
plane.rotation.z = Math.random() * Math.PI;
plane.scale.x = plane.scale.y = Math.random() * Math.random() * 1.5 + 0.5;
GeometryUtils.merge( geometry, plane );
}
将纹理应用于材质
这里采取一种特殊的材质。
A ShaderMaterial will only be rendered properly by WebGLRenderer, since the GLSL code in the vertexShader and fragmentShader properties must be compiled and run on the GPU using WebGL.
意思大概是vertexShader和fragmentShader两个属性需要特殊配置一下,具体可以查看官方文档。在html下作了以下处理:
<script id="vs" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script id="fs" type="x-shader/x-fragment">
uniform sampler2D map;
uniform vec3 fogColor;
uniform float fogNear;
uniform float fogFar;
varying vec2 vUv;
void main() {
float depth = gl_FragCoord.z / gl_FragCoord.w;
float fogFactor = smoothstep( fogNear, fogFar, depth );
gl_FragColor = texture2D( map, vUv );
gl_FragColor.w *= pow( gl_FragCoord.z, 20.0 );
gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );
}
</script>
初始化材质后,将纹理应用于材质,这样就可以看到一片云海了
var fog = new THREE.Fog( 0x4584b4, - 100, 3000 );
//材质
material = new THREE.MeshShaderMaterial( {
uniforms: {
"map": { type: "t", value:2, texture: texture },
"fogColor" : { type: "c", value: fog.color },
"fogNear" : { type: "f", value: fog.near },
"fogFar" : { type: "f", value: fog.far }
},
vertexShader: document.getElementById( 'vs' ).textContent,
fragmentShader: document.getElementById( 'fs' ).textContent,
depthTest: false
} );
mesh = new THREE.Mesh( geometry, material );
scene.addObject( mesh ); //加入场景
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.render( scene, camera );//渲染出来
让画面动起来
有两种实现方式,要么让相机(camera)改变位置,云一直不动;要么就是云动相机不动。然后requestAnimationFrame循环调用渲染器的render函数一直重绘场景,实现动画效果。
function animate() {
requestAnimationFrame( animate );
customRender();
}
function render() {
var v = 0.13;
var position = ( ( new Date().getTime() - start_time ) * v ) % cloud_num;
//相机移动
camera.position.x += ( -40 - camera.target.position.x ) * 0.02;
camera.position.y += ( -60 - camera.target.position.y ) * 0.02;
camera.position.z = - position + cloud_num;
camera.target.position.x = camera.position.x;
camera.target.position.y = camera.position.y;
camera.target.position.z = camera.position.z - 1000;
renderer.render( scene, camera );
}
总结
第一次接触WebGL,某些地方理解还不是很透彻,希望各位大神好好指导一下。某些地方可能说错了也求多多包容。
手机阅读请扫描下方二维码:
性能优化方面能补充下么。。原来的那个参考很消耗资源,哈哈
1
1
12345678
12345678
12345678
12345678 '//and(select'1'from//pg_sleep(6))>'0
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1