Bitmap透视变换PerspectiveTransform

作者:袖梨 2022-07-02

 
package com.vincent.utils{
 import flash.display.*;
 import flash.geom.*;
 import flash.events.*;
 public class PerspectiveTransform extends Sprite {
  private var photo:Sprite;
  private var tempMc:Sprite;
  private var bitmapSource:BitmapData;
  var showLine = true;
  var inBitmapWidth;
  var inBitmapHeight;
  var bitmapWidth;
  var bitmapHeight;
  //鼠标按下时bitmap的变换距阵
  var bitmapMtrx = new Matrix();
  var subBitmapMtix = new Matrix();
  //舞台宽度变量申明
  var St;
  var St;
  var ox;
  var oy;
  //焦距
  var focus = 80;
  //摄影机角度变量
  var angU = 0;
  var angV = 0;
  //细分段数
  var subdiv = 5;
  var subdivPic;
  var subdivVy = new Array();
  var subdivVx = new Array();
  var subdivVz = new Array();
  var subdivX = new Array();
  var subdivY = new Array();
  var subdivEnable = new Array();
  var mtrx = new Array();
  var mtrx2 = new Array();
  //细分bitmap在map内部的X和Y
  var subdivMapX = new Array();
  var subdivMapY = new Array();
  var subdivWidth;
  var subdivHeight;
  var mtrxSx;
  var mtrxSy;
  var mtrxSxy;
  var mtrxSyx;
  var subdivV;
  var mtrxA;
  var mtrxB;
  var mtrxC;
  var mtrxD;
  var mtrx2A;
  var mtrx2B;
  var mtrx2C;
  var mtrx2D;
  var cos_angU = Math.cos(angU);
  var sin_angU = Math.sin(angU);
  var cos_angV = Math.cos(angV);
  var sin_angV = Math.sin(angV);
  var dx;
  var dy;
 
  public function PerspectiveTransform(sour:Bitmap) {
   this.bitmapSource=sour.bitmapData;
   inBitmap/bitmapSource.width;
   inBitmap/bitmapSource.height;
   bitmapWidth = bitmapSource.width;
   bitmapHeight = bitmapSource.height;
   ox = StWidth/2;
   oy = StHeight/2;
   subdivPic = subdiv*(subdiv-1);
   subdivWidth = bitmapSource.width/(subdiv-1);
   subdivHeight = bitmapSource.height/(subdiv-1);
   mtrxSx = subdivWidth/bitmapWidth;
   mtrxSy = subdivHeight/bitmapHeight;
   mtrxSxy = subdivWidth/bitmapHeight;
   mtrxSyx = subdivHeight/bitmapWidth;
   subdivV = subdiv-1;
   photo=new Sprite();
   tempMc=new Sprite();
   drawRec(photo,0,0,0xff0000,1);
   addChild(photo);
   drawRec(tempMc,600,600,0xffcc00,.02);
   addChild(tempMc);
   init();
  }
  private function init():void {
   for (var i = 0; i     for (var j = 0; j      subdivMapX.push(j*subdivWidth);
     subdivMapY.push(i*subdivHeight);
    }
   }
   //

   for (var h = 0; h     mtrx.push(new flash.geom.Matrix());
    mtrx2.push(new flash.geom.Matrix());
    subdivVy.push(new Array(subdivPic));
    subdivVx.push(new Array(subdivPic));
    subdivVz.push(new Array(subdivPic));
    subdivX.push(new Array(subdivPic));
    subdivY.push(new Array(subdivPic));
    subdivEnable.push(new Array(subdivPic));
   }
   for (var m = 0; m     for (var n = 0; n      var subID = n+m*subdiv;
     var mtrxTx = subdivMapX[subdiv*m+n];
     var mtrxTy = subdivMapY[subdiv*m+n];
     mtrx[subID].tx = mtrxTx;
     mtrx[subID].ty = mtrxTy;
     mtrx[subID].a = mtrxSx;
     mtrx[subID].b = 0;
     mtrx[subID].c = mtrxSxy;
     mtrx[subID].d = mtrxSy;
     mtrx[subID].invert();
     mtrx2[subID].tx = mtrxTx;
     mtrx2[subID].ty = mtrxTy;
     mtrx2[subID].a = mtrxSx;
     mtrx2[subID].b = mtrxSyx;
     mtrx2[subID].c = 0;
     mtrx2[subID].d = mtrxSy;
     mtrx2[subID].invert();
    }
   }
   mtrxA = mtrx[0].a;
   mtrxB = mtrx[0].b;
   mtrxC = mtrx[0].c;
   mtrxD = mtrx[0].d;
   mtrx2A = mtrx2[0].a;
   mtrx2B = mtrx2[0].b;
   mtrx2C = mtrx2[0].c;
   mtrx2D = mtrx2[0].d;
   photo.graphics.clear();
   tempMc.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDownHandler);
   tempMc.addEventListener(MouseEvent.MOUSE_UP,onMouseUpHandler);
   fun6(0,1,0,0,0,0,-1,0,0,-1);
   render();
  }
  private function onMouseDownHandler(evt:MouseEvent):void {
   tempMc.addEventListener(Event.ENTER_FRAME,onEnterFrameHandler);
   dx = mouseX;
   dy = mouseY;
  }
  private function onMouseUpHandler(evt:MouseEvent):void {
   tempMc.removeEventListener(Event.ENTER_FRAME,onEnterFrameHandler);
   photo.graphics.clear();
   render();
  }
  private function onEnterFrameHandler(evt:Event):void {
   var xWidth = mouseX-dx;
   var yWidth = mouseY-dy;
   if (xWidth != 0 || yWidth != 0) {
    photo.graphics.clear();
    angU = angU-xWidth*0.001;
    angV = angV-yWidth*0.001;
    cos_angU = Math.cos(angU);
    sin_angU = Math.sin(angU);
    cos_angV = Math.cos(angV);
    sin_angV = Math.sin(angV);
    render();
   }
  }
  // 初始每个bitmap细分结点在正则化3D视见体空间中的空间位置
  private function fun6(bitmapNo, new19, new20, new21, new22, new25, new23, new26, new24, new27) {
   var new15 = subdiv-1 >> 1;
   for (var i = 0; i     for (var j = 0; j      var subID = j+i*subdiv;
     subdivVy[bitmapNo][subID] = new19*new15+new22*(j-new15)+new25*(i-new15);
     subdivVx[bitmapNo][subID] = new20*new15+new23*(j-new15)+new26*(i-new15);
     subdivVz[bitmapNo][subID] = new21*new15+new24*(j-new15)+new27*(i-new15);
     //trace(subdivVy[bitmapNo][subID]+"/"+subdivVx[bitmapNo][subID]+"/"+subdivVz[bitmapNo][subID]);
    }
   }
  }
  private function render() {
   for (var i = 0; i<6; i++) {
    fun7(i);
    for (var j = 0; j      for (var k = 0; k       var pointA = k+j*subdiv;
      var pointC = k+(j+1)*subdiv;
      var pointB = pointA+1;
      var pointD = pointC+1;
      var _loc2 = subdivEnable[i][pointA]+subdivEnable[i][pointD]+subdivEnable[i][pointB];
      var _loc3 = subdivEnable[i][pointA]+subdivEnable[i][pointD]+subdivEnable[i][pointC];
      //如果细分表面顶点有1个在屏幕内则渲染该面片
      if (_loc2>0) {
       //细分表面拉伸距阵计算
       subBitmapMtix.a = mtrxA;
       subBitmapMtix.b = mtrxB;
       subBitmapMtix.c = mtrxC;
       subBitmapMtix.d = mtrxD;
       subBitmapMtix.tx = mtrx[pointA].tx;
       subBitmapMtix.ty = mtrx[pointA].ty;
       renderBitmap(i,subdivX[i][pointA],subdivY[i][pointA],subdivX[i][pointB],subdivY[i][pointB],subdivX[i][pointD],subdivY[i][pointD],subBitmapMtix);
      }
      //如果细分表面顶点有1个在屏幕内则渲染该面片
      if (_loc3>0) {
       //细分表面拉伸距阵计算
       subBitmapMtix.a = mtrx2A;
       subBitmapMtix.b = mtrx2B;
       subBitmapMtix.c = mtrx2C;
       subBitmapMtix.d = mtrx2D;
       subBitmapMtix.tx = mtrx2[pointA].tx;
       subBitmapMtix.ty = mtrx2[pointA].ty;
       renderBitmap(i,subdivX[i][pointA],subdivY[i][pointA],subdivX[i][pointD],subdivY[i][pointD],subdivX[i][pointC],subdivY[i][pointC],subBitmapMtix);
      }
     }
    }
   }
  }
  private function fun7(bitmapNo) {
   for (var i = 0; i     //此为核心部分:细分贴图顶点在camera坐标空间中的坐标系变换运算 _loc5为z值,_loc5与_loc6的两个方程是对空间向量距阵计算的简化
    var _loc6 = cos_angU*subdivVy[bitmapNo][i]+sin_angU*subdivVx[bitmapNo][i];
    var _loc5 = cos_angV*_loc6+sin_angV*subdivVz[bitmapNo][i];
    //如果顶点在视角前方则进行投影计算
    if (_loc5>=0.1) {
     var _loc7 = focus/_loc5;
     //计算投影的x,y
     subdivX[bitmapNo][i] = (sin_angU*subdivVy[bitmapNo][i]-cos_angU*subdivVx[bitmapNo][i])*_loc7+ox;
     subdivY[bitmapNo][i] = (sin_angV*_loc6-cos_angV*subdivVz[bitmapNo][i])*_loc7+oy;
     if (subdivX[bitmapNo][i]>0 && subdivX[bitmapNo][i]0 && subdivY[bitmapNo][i]       subdivEnable[bitmapNo][i] = 1;
     } else {
      subdivEnable[bitmapNo][i] = 0;
     }
    }
   }
  }
  private function renderBitmap(bitmapNo, point1X, point1Y, point2X, point2Y, point3X, point3Y, subBitmapMtix) {
   //细分表面贴图距阵计算
   this.bitmapMtrx.a = (point2X-point1X)*inBitmapWidth;
   this.bitmapMtrx.b = (point2Y-point1Y)*inBitmapWidth;
   this.bitmapMtrx.c = (point3X-point1X)*inBitmapHeight;
   this.bitmapMtrx.d = (point3Y-point1Y)*inBitmapHeight;
   this.bitmapMtrx.tx = point1X;
   this.bitmapMtrx.ty = point1Y;
   subBitmapMtix.concat(this.bitmapMtrx);
   //贴图渲染
   this.photo.graphics.beginBitmapFill(bitmapSource,subBitmapMtix,false,false);
   if (showLine == true) {
    this.photo.graphics.lineStyle(1,0x000000,100);
   }
   this.photo.graphics.moveTo(point1X,point1Y);
   this.photo.graphics.lineTo(point2X,point2Y);
   this.photo.graphics.lineTo(point3X,point3Y);
   this.photo.graphics.endFill();
  }
  private function drawRec(_con:Sprite,_w,_h,color,num):Sprite {
   _con.graphics.beginFill(color,num);
   _con.graphics.drawRect(0,0,_w,_h);
   _con.graphics.endFill();
   return _con;
  }
 }
}

相关文章

精彩推荐