大魔导师戴戴戴の博文 转载请保留原文链接!

canvas 曲线面片1

写前面

*姐姐篇已完成 传送 canvas曲线面片2
(别跟我说这东西没用 并不想理你!)

什么是曲线面片? 如图

上面这个就是相对简单的双线性面片

可通过4个点来控制  左上角 A点  顺时针依次就是 ABCD 

这个东西 其实就是 BA方向 和 DA 方向的线性插值组合 下图

先沿着DA CB 方向插值 再继续对 BA 方向插值

生成三角坐标的代码:

 1 //初始点
 2     var dot_ar = [
 3       new _$.Vec(0, 0)
 4       ,new _$.Vec(w, 0)
 5       ,new _$.Vec(w, h)
 6       ,new _$.Vec(0, h)
 7     ];
 8 
 9     //ABCD外围向量计算
10     var boundVec =()=>{
11       V['BA'] = {
12         pv: dot_ar[0],
13         v: dot_ar[1].sub(dot_ar[0])
14       };
15 
16       V['CB'] = {
17         pv: dot_ar[1],
18         v: dot_ar[2].sub(dot_ar[1])
19       };
20 
21       V['CD'] = {
22         pv: dot_ar[3],
23         v: dot_ar[2].sub(dot_ar[3])
24       };
25 
26       V['DA'] = {
27         pv: dot_ar[0]
28         , v: dot_ar[3].sub(dot_ar[0])
29       };
30     };
31     //获取N个三角网络坐标
32     var getDots =cb=>{
33       
34       let k = +[];
35       //DA CB
36       for (let i = 0; abs(i - 1) > .000001; i += hn) {
37         //++
38         let s_da = V['DA'].v.scale(i + hn).add(V['DA'].pv);
39         let s_cb = V['CB'].v.scale(i + hn).add(V['CB'].pv);
40 
41         
42         let s_da_ = V['DA'].v.scale(i).add(V['DA'].pv);
43         let s_cb_ = V['CB'].v.scale(i).add(V['CB'].pv);
44 
45        
46         let vecx1 = {
47          
48           v: s_cb_.sub(s_da_)
49          
50           , pv: V['DA'].v.scale(i).add(V['DA'].pv)
51         };
52 
53         let vecx2 = {
54           v: s_cb.sub(s_da),
55           pv: V['DA'].v.scale(i + hn).add(V['DA'].pv)
56         };
57 
58         //再BA方向
59         for (let j = 0; abs(j - 1) > .000001; j += wn) {
60           //  s_ba_   s_ba     *vecx1
61           //  s_ba2_  s_ba2   *vecx2
62           let s_ba = vecx1.v.scale(j + wn).add(vecx1.pv);
63           let s_ba2 = vecx2.v.scale(j + wn).add(vecx2.pv);
64 
65           
66           let s_ba_ = vecx1.v.scale(j).add(vecx1.pv);
67           let s_ba2_ = vecx2.v.scale(j).add(vecx2.pv);
68 
69           //两个三角网络
70           cb && cb({
71             0: { dot_ar: { 0: s_ba_, 1: s_ba, 2: s_ba2_ } },
72             1: { dot_ar: { 0: s_ba2, 1: s_ba2_, 2: s_ba } }
73           }, k);
74 
75           k += 2;
76         };
77       };
78     };

 

拿到坐标后就可以生成三角网络对象了 

 1 var createTrangle = ()=>{
 2       boundVec();
 3       //拿到坐标后 生成三角网络对象
 4       getDots((dot,k)=>{
 5         trangle_ar.push(
 6           TrangleMap({
 7             dot_ar: dot[0].dot_ar,
 8             i: k, wireframe: prop.wireframe,
 9             color: _$.color()
10           })
11           ,TrangleMap({
12             dot_ar: dot[1].dot_ar,
13             i: k + 1, wireframe: prop.wireframe,
14             color: _$.color()
15           })
16         );
17       });
18     };

三角对象的代码:

 1 var TrangleMap = prop=>{
 2     // setTransform 中の矩阵
 3     var trans_ar = [
 4      1, 0, 0,
 5      ,1, 0, 0
 6     ];
 7 
 8     var dot_ar = prop.dot_ar;
 9 
10     //拷份初始点
11     var fix_dot = _$.extend([], dot_ar);
12 
13     var color = prop.color || 'black';
14 
15     var draw = Object.create({
16       line(){
17         var ctx = Stg.ctx;
18 
19         ctx.save();
20         ctx.strokeStyle = color;
21         ctx.lineWidth = 2;
22         ctx.beginPath();
23         ctx.moveTo(dot_ar[0].x, dot_ar[0].y);
24         ctx.lineTo(dot_ar[1].x, dot_ar[1].y);
25         ctx.lineTo(dot_ar[2].x, dot_ar[2].y);
26 
27         ctx.closePath();
28 
29         ctx.stroke();
30         ctx.restore();
31       }
32       ,map(){
33         var ctx = Stg.ctx;
34 
35         ctx.save();
36         //clip三角
37         ctx.beginPath();
38         ctx.moveTo(dot_ar[0].x, dot_ar[0].y);
39         ctx.lineTo(dot_ar[1].x, dot_ar[1].y);
40         ctx.lineTo(dot_ar[2].x, dot_ar[2].y);
41         ctx.closePath();
42 
43         ctx.clip();
44 
45         ctx.save();
46 
47         ctx.setTransform.apply(ctx, trans_ar);
48 
49         ctx.beginPath();
50         ctx.drawImage(Pic.map, 0, 0, Pic.width, Pic.height);
51         ctx.closePath();
52         ctx.restore();
53 
54         ctx.restore();
55       }
56     });
57 
58     var _ = Object.create({
59       render(){
60         prop.wireframe && draw.line();
61         draw.map();
62       },
63       transDot(){
64         
65         dot_ar = ar;
66         //X = ax + cy + 1e
67         //Y = bx + dy + 1f
68 
69         var ar = [[fix_dot[0].x, fix_dot[0].y, 1], [fix_dot[1].x, fix_dot[1].y, 1], [fix_dot[2].x, fix_dot[2].y, 1]];
70 
71         //得到 a c e
72         var dtx = _$.Det3(ar, [dot_ar[0].x, dot_ar[1].x, dot_ar[2].x]);
73         //得到 b d f
74         var dty = _$.Det3(ar, [dot_ar[0].y, dot_ar[1].y, dot_ar[2].y]);
75 
76         // a b c d e f
77         trans_ar = [dtx[0], dty[0], dtx[1], dty[1], dtx[2], dty[2]];
78       }
79     });
80 
81     return _;
82   };

到这里确实已经可以形成面片了。。

 

但是 为何有个transDot方法 - -

因为我们还要对面片进行贴图操作 啊~

what? 贴图不是webgl 干的事么 。。 这里canvas2d也可以

一个三角对象就对应一个drawImage  如图:

 

圈的那个三角贴图  是通过原始尺寸clip过的   但是clip又不帮你做拉伸缩放的变换。。

我们还得配合 transform 或者 setTransform api 传递矩阵参数

它内部是这样计算的

X = ax + cy + e 

Y = bx + dy + f

我们要算出abcdef   也就是解个线性方程组

我用矩阵解法(也可用消元法) 我已经封装过了 那个Det3是这样的

 1 Dai.Det3 = function(){
 2       var det = function(a){
 3         return a[0][0]*a[1][1]*a[2][2]
 4           +a[0][1]*a[1][2]*a[2][0]
 5           +a[0][2]*a[1][0]*a[2][1]
 6 
 7           -a[0][2]*a[1][1]*a[2][0]
 8           -a[0][1]*a[1][0]*a[2][2]
 9           -a[0][0]*a[1][2]*a[2][1];
10       };
11       //x x x   //Y
12       //x x x   //Y
13       //x x x   //Y
14       return function(ar,nar){
15         var a,b,c;
16         var D = det(ar);
17 
18         if(D==0) return console.warn('该矩阵不可逆~');
19 
20         var ar1 = _$.extend([],ar);
21         var ar2 = _$.extend([],ar);
22         var ar3 = _$.extend([],ar);
23 
24         ar1[0][0] = nar[0];
25         ar1[1][0] = nar[1];
26         ar1[2][0] = nar[2];
27 
28        
29         ar2[0][1] = nar[0];
30         ar2[1][1] = nar[1];
31         ar2[2][1] = nar[2];
32 
33         ar3[0][2] = nar[0];
34         ar3[1][2] = nar[1];
35         ar3[2][2] = nar[2];
36 
37         var D1 = det(ar1);
38 
39         var D2 = det(ar2);
40 
41         var D3 = det(ar3);
42 
43         return [D1/D,D2/D,D3/D];
44       }
45     }();

好了放出最终DEMO!

DEOM

 

posted @ 2016-04-07 23:54  戴戴戴x  阅读(872)  评论(0编辑  收藏  举报