• 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

  • 相关阅读:
    SAP系统报错
    基金投资
    Reading: 重构相关
    C/C++: static variables
    C/C++: 如何删除本地文件/读取某个目录下符合某种pattern的所有文件路径
    如何在Linux下建立包含lua vm的unit test framwork
    C++实现字符串分割(类似于Python的split方法)
    postMan 汉化
    搞懂MySQL InnoDB事务ACID实现原理
    mysql 索引优化
  • 原文地址:https://www.cnblogs.com/daidaidai/p/5366204.html
Copyright © 2020-2023  润新知