一, 前言
和其他 GUI 系统一样, web 也提供了一个使用 canvas 来绘制图形的基础环境. 利用 canvas 我们可以绘制矩形, 三角形, 直线, 圆弧和曲线等比较复杂的图形. 具体可以参考
使用 canvas 来绘制图形
WebGL 本质上也是在 canvas 上作画, 只不过它基于是一个 3D 的场景. 而在 ThreeJs 中, 提供了一个套 Shape 和 Curve 相关的 API 来帮助我们在 3D 场景中绘制出我们想要的图形.
二, 图形绘制主要流程
图形绘制一般流程为: 构造 Shape, 构造 BufferGeometry , 构造 Mesh 并添加到场景中.
1. 构造 Shape
在构造 Shape 之前, 我们先来了解一下 ThreeJs 中的图形绘制基础.
图形绘制的基础有 3 个比较核心的类: Curve,Path 以及 Shape. 如下是用于进行图形绘制的一个比较全局的类图.
图形绘制类图. jpg
在实际的开发过程中, 我们一般使用 Shape 来绘制出我们想要的形状, 和 canvas 一样, 也可以绘制出矩形, 三角形, 直线, 圆弧等, 甚至可以一并绘制出更复杂的图形, 如鱼形, 剪刀等.
而在上图中, Shape 继承自 Path,Path 又间接继承自 Curve,Path 封装了各种绘制图形的 API 接口, 如 :
lineTo: 绘制直线
quadraticCurveTo: 二次贝塞尔曲线
bezierCurveTo: 三次贝塞尔曲线
arc: 弧线
ellipse: 椭圆
......
在 Path 的各绘制 API 中, 又是进步构造相应的曲线, 如 new 一个 LineCurve,CubicBezierCurve 等, 从而完成曲线的构造.
有了这些图形绘制的 API, 在 3D 场景中, 利用这些 API 不仅可以绘制 2D 的图形, 还可以绘制 3D 的图形. 上面类图中,***Curve 带后缀 3 的都是进行 3D 的图形绘制, 其他自然就都是 2D 的绘制了.
如下, 我们利用 Bezier 来构造一个圆. 关于如何用 Bezier 来构造圆, 就不在这里展开了.
- var circleRadius = 40;
- var circleShape = new THREE.Shape();
- circleShape.moveTo( 0, circleRadius );
- circleShape.quadraticCurveTo( circleRadius, circleRadius, circleRadius, 0 );
- circleShape.quadraticCurveTo( circleRadius, - circleRadius, 0, - circleRadius );
- circleShape.quadraticCurveTo( - circleRadius, - circleRadius, - circleRadius, 0 );
- circleShape.quadraticCurveTo( - circleRadius, circleRadius, 0, circleRadius );
2. 构造 BufferGeometry
上面通过 Shape 构造出了我们想要的图形, 下一步我们需要获取图形的所有点, 并从这些点构造 BufferGeometry.
Shape 是间接继承自 Curve ,Curve 定义了 getPoints() 的基础. Shape 的 getPoints() 的具体实现在 CurvePath 中的实现, 从而获取构造这个图形所需要的点.
- var points = shape.getPoints();
- var geometryPoints = new THREE.BufferGeometry().setFromPoints( subPoints );
3. 构造网格
拿到 BufferGeometry 就可以构造出我们要的物体了. 这里为了效果上表达明显一点, 并且炫酷一点, 就用 Line 逐段逐段绘制出了我们前面所构造的圆.
效果图如下:
画圆的 gif
实现代码如下:
- function addLineShape( shape, color, x, y, z, rx, ry, rz, s ) {
- // lines
- shape.autoClose = true;
- var points = shape.getPoints();
- console.log( "addLineShape", points );
- let length = points.length;
- let val = 0;
- function drawLine( ) {
- if(val == length) return;
- let subPoints1 = points[val];
- let subPoints2 = points[(val + 1) % length];
- let subPoints = [];
- subPoints.push(subPoints1);
- subPoints.push(subPoints2);
- var geometryPoints = new THREE.BufferGeometry().setFromPoints( subPoints );
- // solid line
- var line = new THREE.Line( geometryPoints, new THREE.LineBasicMaterial( { color: color } ) );
- line.position.set( x, y, z );
- line.rotation.set( rx, ry, rz );
- line.scale.set( s, s, s );
- scene.add( line );
- val++;
- setTimeout(drawLine,16);
- }
- drawLine();
- }
代码比较简单, 感兴趣的可以自行分析一下.
三, 总结
文章介绍的内容相对比较简单, 主要大致梳理了 ThreeJs 所提供的绘图 API 以及绘图的主要流程. 其中也以一个实例讲解了整个绘制的过程, 以加深对其的理解.
来源: http://www.jianshu.com/p/a8ec5861147e