[Three.js]WebGL心形效果

         本文实现效果参考自 Three.jsSparks.js的examples。如果你的浏览器支持WebGL,可以点击 这里查看效果^^。
 
一、垫脚石

         WebGL,浏览器上的3D技术,基于OpenGL ES 2.0。基础教程可见Hi,WebGL!Learning WebGL

         Three.js,WebGL的一个3D引擎库。呃,有需要的,可以看这一篇, Click here
 
二、单刀直入
1 )下载源码
         附件!恩,可以先打开html看看效果。
 
         查看源码发现还有个Stats.js,是左上角统计FPS用的。
 
         浏览388行,运行入口,也基本确定了我们的实现流程。
 
 
  
  1. function threeStart() { 
  2.   initScene(); 
  3.   initParticles(); 
  4.   initShape(); 
  5.   initEmitter(); 
  6.   animate(); 
  7.  
  8. window.addEventListener('load', threeStart, false); 
 
2 )initScene ()
         浏览70行,上方先定义好了方法内要给外部用的变量,之后的方法都会如此。
         基本就这么个流程:camera->scene->renderer[->stats]。
 
3 )initParticles()
3.1)着色器

         浏览121-147行,THREE .ShaderMaterial的定义,其中attributes, uniforms,对应于GLSL内的变量,其type类型,在WebGLRenderer.js内搜索‘switch ( type )’即可找到。Vertex Shader&Fragment Shader如下:

 
  
  1. <!-- 顶点着色器 --> 
  2. <script type="x-shader/x-vertex" id="vertexshader">  
  3.     attribute float size
  4.     attribute vec3 ca; 
  5.  
  6.     varying vec3 vColor; 
  7.  
  8.     void main() { 
  9.         vColor = ca; 
  10.  
  11.         /* 
  12.          * 对于简单构造的粒子,可以用一个Object的各顶点表示粒子。 
  13.          * 利用gl_PointSize属性设置每个粒子大小。更快。 
  14.          */ 
  15.  
  16.         // 变换后的顶点坐标 
  17.         vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); 
  18.         // 顶点大小 
  19.         gl_PointSize = size * (200.0 / length(mvPosition.xyz)); 
  20.         // 输出顶点世界坐标 
  21.         gl_Position = projectionMatrix * mvPosition; 
  22.     } 
  23. </script>  
  24. <!-- 片元着色器 --> 
  25. <script type="x-shader/x-fragment" id="fragmentshader">  
  26.     uniform vec3 color; 
  27.     uniform sampler2D texture; 
  28.  
  29.     varying vec3 vColor; 
  30.      
  31.     void main() { 
  32.         // 用gl_PointCoord设置纹理,不是UV坐标了 
  33.         vec4 outColor = texture2D(texture, gl_PointCoord); 
  34.         // 设定像素颜色 = 纹理颜色 * 顶点颜色 
  35.         gl_FragColor = outColor * vec4(color * vColor.xyz, 1.0); 
  36.  
  37.         // 计算像素世界坐标z值 
  38.         float depth = gl_FragCoord.z / gl_FragCoord.w; 
  39.         // 雾颜色:黑 
  40.         const vec3 fogColor = vec3(0.0, 0.0, 0.0); 
  41.         // const vec3 fogColor = vec3(0xff, 0xff, 0xff); 
  42.         // 雾因素:depth<=200时0,>=600时1 
  43.         float fogFactor = smoothstep(200.0, 600.0, depth); 
  44.         // 混合雾的像素颜色 
  45.         gl_FragColor = mix(gl_FragColor, vec4(fogColor, gl_FragColor.w), fogFactor); 
  46.     } 
  47. </script> 
 
3.2)粒子初始化
         浏览149-178行,创建了一个几何物体,初始定义了10000个顶点,至无限远。当仓库了,拿出来,用完,再放回去(再至为无限远)。
 
4 )initShape()
         221行开始,THREE.Shape()给它整成个心形。之后在365行,render()内,从[0,1]间取出它的位置,并赋值给发射器当前位置,如下:
 
 
  
  1. // 沿形状路线运行 
  2. timeOnShapePath += 0.01; 
  3. if (timeOnShapePath > 1) timeOnShapePath -= 1; 
  4. var pointOnShape = heartShape.getPointAt(timeOnShapePath); 
  5.  
  6. emitterpos.x = pointOnShape.x * 2 - 50; 
  7. emitterpos.y = -pointOnShape.y * 2 + 100; 
 
5 )initEmitter()
         Sparks.js的使用了,237行。没有自己的,就只能用用别人的了。还有它很久没更新了。
 
6 )animate()
         用requestAnimationFrame反复执行。其中render()处理变换,再渲染。stats.update(),即是左上角那插件的更新了。
 
         render()前一部分用以鼠标旋转,与鼠标事件关联。中间即是轨迹移动。还有以下三句,声明顶点、大小、颜色都要更新。
 
 
  
  1. // 设置需要更新 
  2. group.geometry.verticesNeedUpdate = true// 顶点 
  3. attributes.size.needsUpdate = true// 大小 
  4. attributes.ca.needsUpdate = true// 颜色 
 
         其变化在initEmitter()内,Sparks.js的回调里做了。但只有这里声明了需要更新,Three.js才会更新着色器相应的变量值。
 
         最后句,以重复渲染场景。
 
三、说点啥
         说是有节日==。