[Three.js]WebGL心形效果
本文实现效果参考自 、 的examples。如果你的浏览器支持WebGL,可以点击 查看效果^^。
一、垫脚石
WebGL,浏览器上的3D技术,基于OpenGL ES 2.0。基础教程可见、。
Three.js,WebGL的一个3D引擎库。呃,有需要的,可以看这一篇, !
二、单刀直入
1 )下载源码
附件!恩,可以先打开html看看效果。
查看源码发现还有个Stats.js,是左上角统计FPS用的。
浏览388行,运行入口,也基本确定了我们的实现流程。
- function threeStart() {
- initScene();
- initParticles();
- initShape();
- initEmitter();
- animate();
- }
- 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如下:
- <!-- 顶点着色器 -->
- <script type="x-shader/x-vertex" id="vertexshader">
- attribute float size;
- attribute vec3 ca;
- varying vec3 vColor;
- void main() {
- vColor = ca;
- /*
- * 对于简单构造的粒子,可以用一个Object的各顶点表示粒子。
- * 利用gl_PointSize属性设置每个粒子大小。更快。
- */
- // 变换后的顶点坐标
- vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
- // 顶点大小
- gl_PointSize = size * (200.0 / length(mvPosition.xyz));
- // 输出顶点世界坐标
- gl_Position = projectionMatrix * mvPosition;
- }
- </script>
- <!-- 片元着色器 -->
- <script type="x-shader/x-fragment" id="fragmentshader">
- uniform vec3 color;
- uniform sampler2D texture;
- varying vec3 vColor;
- void main() {
- // 用gl_PointCoord设置纹理,不是UV坐标了
- vec4 outColor = texture2D(texture, gl_PointCoord);
- // 设定像素颜色 = 纹理颜色 * 顶点颜色
- gl_FragColor = outColor * vec4(color * vColor.xyz, 1.0);
- // 计算像素世界坐标z值
- float depth = gl_FragCoord.z / gl_FragCoord.w;
- // 雾颜色:黑
- const vec3 fogColor = vec3(0.0, 0.0, 0.0);
- // const vec3 fogColor = vec3(0xff, 0xff, 0xff);
- // 雾因素:depth<=200时0,>=600时1
- float fogFactor = smoothstep(200.0, 600.0, depth);
- // 混合雾的像素颜色
- gl_FragColor = mix(gl_FragColor, vec4(fogColor, gl_FragColor.w), fogFactor);
- }
- </script>
3.2)粒子初始化
浏览149-178行,创建了一个几何物体,初始定义了10000个顶点,至无限远。当仓库了,拿出来,用完,再放回去(再至为无限远)。
4 )initShape()
221行开始,THREE.Shape()给它整成个心形。之后在365行,render()内,从[0,1]间取出它的位置,并赋值给发射器当前位置,如下:
- // 沿形状路线运行
- timeOnShapePath += 0.01;
- if (timeOnShapePath > 1) timeOnShapePath -= 1;
- var pointOnShape = heartShape.getPointAt(timeOnShapePath);
- emitterpos.x = pointOnShape.x * 2 - 50;
- emitterpos.y = -pointOnShape.y * 2 + 100;
5 )initEmitter()
Sparks.js的使用了,237行。没有自己的,就只能用用别人的了。还有它很久没更新了。
6 )animate()
用requestAnimationFrame反复执行。其中render()处理变换,再渲染。stats.update(),即是左上角那插件的更新了。
render()前一部分用以鼠标旋转,与鼠标事件关联。中间即是轨迹移动。还有以下三句,声明顶点、大小、颜色都要更新。
- // 设置需要更新
- group.geometry.verticesNeedUpdate = true; // 顶点
- attributes.size.needsUpdate = true; // 大小
- attributes.ca.needsUpdate = true; // 颜色
其变化在initEmitter()内,Sparks.js的回调里做了。但只有这里声明了需要更新,Three.js才会更新着色器相应的变量值。
最后句,以重复渲染场景。
三、说点啥
说是有节日==。