zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    LeetCode 977 有序数组的平方
    LeetCode 24 两两交换链表中的节点
    LeetCode 416 分割等和子集
    LeetCode 142 环形链表II
    LeetCode 106 从中序与后序遍历序列构造二叉树
    LeetCode 637 二叉树的层平均值
    LeetCode 117 填充每个节点的下一个右侧节点
    LeetCode 75 颜色分类
    redhat 7.4 挂载ntfs格式的u盘并且使用
    redhat 查看CPU frequency scaling(CPU频率缩放)
  • 原文地址:https://www.cnblogs.com/daidaidai/p/5366204.html
Copyright © 2011-2022 走看看