点击浏览该文件 点击浏览该文件前几天参考了ox的贴子,总算弄出来了,用了好多ox的东西。。。呵呵
http://bbs.flashempire.net/showthread.php?t=183141&page=2上面这个就是ox在闪帝的长篇大补贴,讨论3D贴图的
很早就看过“小小”做的3D烟盒,很想自己也做个,于是开始学习3D方面的东西,
但是进展很慢,而且断断续续的,在参考了很多源代码之后,终于弄出了个
3D球棍模型
http://www.5dblog.com/user2/jh7086/index.asp?id=19656空间点的基本变换和简单消隐算是搞懂些了,但是还是没弄出贴图来,想到“小小”
的贴图是将图片分割成三角形的,于是我以为,只要能将一个三角形的图片进行
任意的变换
UploadFile/2004-11/20041125201957997.swf就可以贴图了,但是“小小”为什么把每个面分割成4个三角形,而不是2个呢,
直到那天看了ox的帖子才明白:贴图并不是简单的顶点坐标映射,要做真正的
透视贴图,必须按像素级别切割图片,这在Flash里是不现实的,“小小”的每个面
是用4个三角形平行透视后拼成的(不知道为什么会想到要这样做)
楼下的代码中最要害的就是将正方形的MC贴到任意平行四边形那一段,我是直接
引用了ox所写的函数,只做了些小的改动,里面的数学计算和三角形任意变形应该
是相同的(我没具体研究过ox是如何计算的),因为它们的实质都是解决这样一个问题:
已知平面上三个原始点a(ax,ay);b(bx,by);c(cx,cy)和三个目标点d(dx,xy);e(ex,ey);f(fx,fy)
要求通过“平移,缩放,旋转”3种变换的组合来使abc在经过同样的变换后,对应地变成
def。。。
这是我以前建立的方程
点击浏览该文件(将c点和f点都放在原点,只考虑通过缩放1+旋转+缩放2的步骤将ab变换到de),方程是解出来了,但是有很多限制条件,于是就卡住了
而ox的方法似乎是用逆推
//------------------------------------------------------------------------------------------------------------
// 平行透视引擎
// vol 0.03
// 初步完成映射贴图
// 上下左右、PageUp、PageDown旋转画面
//------------------------------------------------------------------------------------------------------------
// 初始化
//坐标:垂直屏幕的方向为z坐标
//顶点表
dot=[];
//平行四边形表,需要三个顶点(第四个顶点由其他3个计算出来)和一个贴图信息,顶点va\vb\vc绕向顺时针为正
Rectlist=[];
CameraCenterX=275; //镜头中心x/y
CameraCenterY=200;
NotRanderPosX=-100000; //把所有不渲染的贴图_x移到这个位置
//开始画一个方形盒子,他有8个顶点,6个面
dot[0]={x:-100,y:50,z:-100};//左下前
dot[1]={x:100,y:50,z:-100};//右下前
dot[2]={x:100,y:-50,z:-100};//右上前
dot[3]={x:-100,y:-50,z:-100};//左上前
dot[4]={x:-100,y:50,z:100};//左下后
dot[5]={x:100,y:50,z:100};//右下后
dot[6]={x:100,y:-50,z:100};//右上后
dot[7]={x:-100,y:-50,z:100};//左上后
Rectlist[0]={va:dot[0],vb:dot[1],vc:dot[2],vd:dot[3],pp_name:"pp_021"}; //前面
Rectlist[1]={va:dot[5],vb:dot[4],vc:dot[7],vd:dot[6],pp_name:"pp_022"}; //后面
Rectlist[2]={va:dot[3],vb:dot[2],vc:dot[6],vd:dot[7],pp_name:"pp_023"}; //上面
Rectlist[3]={va:dot[0],vb:dot[4],vc:dot[5],vd:dot[1],pp_name:"pp_024"}; //下面
Rectlist[4]={va:dot[4],vb:dot[0],vc:dot[3],vd:dot[7],pp_name:"pp_025"}; //左面
Rectlist[5]={va:dot[1],vb:dot[5],vc:dot[6],vd:dot[2],pp_name:"pp_026"}; //右面
//初始化贴图
//所有贴图都必须是100*100的正方形,所有贴图放在"TextureLayer"里面
this.createEmptyMovieClip("TextureLayer",2);
for(var i in Rectlist){
//贴图绑定
Rectlist[i].actable=true; //并且通过检测这个变量,做到尽量不执行AS
var Texturenow=Texturelayer.createEmptyMovieClip("套子"+i,i);
//..............................................................
Rectlist[i].texture2=[]; //"texture2[]"用于指向这个面的4个三角形
for(var j=0;j<4;j++){ //将每个面分割为4个三角形(上-右-下-左)
var Texturenow2=Texturenow.createEmptyMovieClip("三角图"+i+"_"+j,(i+1)*(j+1));
//Texturenow2.j=j;//j为0-1-2-3,分别对应于四个三角形:0上-1右-2下-3左
var pic=Texturenow2.createEmptyMovieClip("pic",0);
//----------建立三角形遮罩-------
var maskMC=pic.createEmptyMovieClip("遮罩",1);
maskMC.lineStyle(0,0);
maskMC.beginFill(0);
maskMC.moveTo(2,2);
maskMC.lineTo(-100,0);
maskMC.lineTo(0,-100);
maskMC.lineTo(1,1);
maskMC.endFill();
var maskedMC=pic.attachMovie(Rectlist[i].pp_name,"pic00",0);//贴上原始图片
maskedMC._rotation=-45-90*j;//原始图片旋转到指定角度
maskedMC.setMask(maskMC);
//------------end---------------
Texturenow2._visible=0;
Rectlist[i].texture2[j]=Texturenow2;
}
//.............................................................
//Texturenow._visible=0; //移出屏幕
//Texturenow._alpha=50;
Rectlist[i].texture=Texturenow;//"texture"用于指向这个面的整个图形
}
//-----------------------------------------------------------------------------------------------
// 渲染函数
// ====================将正方形的MC贴到任意平行四边形====================================
function renderTriTexture(va, vb, vc, textureMC){
var Rander=false;
//a、c相对b的坐标(a,b) (c,d)
var a=va.vx-vb.vx
var b=va.vy-vb.vy
var c=vc.vx-vb.vx
var d=vc.vy-vb.vy
//检验表面方向,假如顶点A、B、C旋向为逆时针则为正面
if (a<0&&d>=c*b/a) Rander=true;
else if (a>0&&d<=c*b/a) Rander=true;
else if (a==0){
if (b>0&&c>=0) Rander=true;
if (b<=0&&c<0) Rander=true;
}
//第三步把图形逆时针转动角Angle3 = 0.5 * arctg( 2(ab+cd) / bb+dd-aa-cc )
if(Rander){
var Angle3=0.5*Math.atan(2*(a*b+c*d)/(b*b+d*d-a*a-c*c));
if (!isFinite(Angle3)) Angle3=1.5707963267949
var cosAngle3=Math.cos(Angle3);
var sinAngle3=Math.sin(Angle3);
//第二步的结果设为(Xa,Ya) ,(0,0) , (Xc,Yc),就是将最终显示顺时针转动Angle3
var Xa=a*cosAngle3-b*sinAngle3;
var Ya=a*sinAngle3+b*cosAngle3;
var Xc=c*cosAngle3-d*sinAngle3;
var Yc=c*sinAngle3+d*cosAngle3;
//要注重某数为0的错误
if(Xa==0&&Xc==0||Ya==0&&Yc==0){
rander=false;
}else if (Yc!=0&&Ya!=0){
var scale=Xa/Yc; //横纵相对缩放率
var reallength=Math.sqrt(Xc*Xc+Yc*Yc*scale*scale)//正方形整体拉伸之后边长
var xscale=reallength/100; //第二步要设置的贴图的_xscale
var yscale=reallength/100*Yc/Xa //和_yscale
//第一步图形顺时针旋转Angle1
var Angleco=180/Math.PI; //弧度->角度转换系数
if ((Ya/scale)<=0) var Angle1=90-Math.atan(Xa/Ya/scale)*Angleco
else if ((Ya/scale)>0) var Angle1=270-Math.atan(Xa/Ya/scale)*Angleco
}else if(Ya==0){
var xscale=Xa/100;
var yscale=Yc/100;
Angle1=180
}else if(Yc==0){
var xscale=Xc/100;
var yscale=Ya/-100;
Angle1=90;
}
}
//开始贴图
//-------------------------------------
if(Rander){
textureMC._visible=1;
textureMC._x=CameraCenterX+vb.vx;
textureMC._y=CameraCenterY+vb.vy;
textureMC._xscale=100*xscale;
textureMC._yscale=100*yscale;
textureMC.pic._rotation=Angle1;
textureMC._rotation=-1*Angle3*Angleco
}else{
textureMC._visible=0;
}
}
//===========================end=======================================
//
//=========================透视贴图映射=================================
function FillTexture(){
for(var i in Rectlist){
var Rectnow=Rectlist[i];
if (Rectnow.actable){ //假如这个面答应渲染
//计算这个面的几何中心的屏幕坐标
var vo={},va={},vb={},vc={};
vo.x=(Rectnow.va.x+Rectnow.vc.x)/2;
vo.y=(Rectnow.va.y+Rectnow.vc.y)/2;
vo.z=(Rectnow.va.z+Rectnow.vc.z)/2;
vb=getOne_toxy(V_d,vo);
for(var j=0;j<4;j++){
var textureMC=Rectnow.texture2[j];
switch (j) { //0上--1左--2下--3右
case 0 :
va=Rectnow.va;
vc=Rectnow.vb;
break;
case 1 :
va=Rectnow.vb;
vc=Rectnow.vc;
break;
case 2 :
va=Rectnow.vc;
vc=Rectnow.vd;
break;
case 3 :
va=Rectnow.vd;
vc=Rectnow.va;
break;
}
renderTriTexture(va, vb, vc, textureMC);
}
}
}
}
//===========================end=======================================
//
// 面排序
function SortPolygon(){
for(var i in Rectlist){
var Rectnow=Rectlist[i];
Rectnow.texture.swapDepths(i-10*(Rectnow.va.z+Rectnow.vc.z));
}
}
// 线框渲染
function RanderByLine(){
createEmptyMovieClip("linelayer",100);
linelayer._x=CameraCenterX;
linelayer._y=CameraCenterY;
linelayer.lineStyle(1,0x504040);
for(var i in Rectlist){
if (!Rectlist[i].actable) continue;
var Rectnow=Rectlist[i]
linelayer.moveTo(Rectnow.va.vx,Rectnow.va.vy);
linelayer.lineTo(Rectnow.vb.vx,Rectnow.vb.vy);
linelayer.lineTo(Rectnow.vc.vx,Rectnow.vc.vy);
linelayer.lineTo(Rectnow.vd.vx,Rectnow.vd.vy);
linelayer.lineTo(Rectnow.va.vx,Rectnow.va.vy);
}
}
//----------------------以上部分为ox老大所作-----------------------------
//----------------------以下部分是自己抄来的-------------------------------
//3d变换部分的函数
//
// 单个空间点旋转变换,xa,ya,za均为角度值,dotArray为存储点集的数组名,num为需要操作的空间点的编号
function dot_rotate(xa, ya, za, dotArray,num) {
var rad = Math.PI/180;
xa *= rad;
ya *= rad;
za *= rad;
var sin_xa = Math.sin(xa);
var cos_xa = Math.cos(xa);
var sin_ya = Math.sin(ya);
var cos_ya = Math.cos(ya);
var sin_za = Math.sin(za);
var cos_za = Math.cos(za);
var px, py, pz, tempx, tempy, tempz;
px = dotArray[num].x;
py = dotArray[num].y;
pz = dotArray[num].z;
tempx = (pz*cos_xa)-(py*sin_xa);
tempy = (px*cos_ya)-(pz*sin_ya);
tempz = (py*cos_za)-(px*sin_za);
//
// dotArray[num].x = (py*sin_za)+(px*cos_za);
dotArray[num].x = (py*sin_za)+(tempy*cos_za);
dotArray[num].y = (pz*sin_xa)+(tempz*cos_xa);
// dotArray[num].z = (pz*cos_xa)-(tempz*sin_xa);
dotArray[num].z = (px*sin_ya)+(tempx*cos_ya);
//
//
}
//整个点集的旋转变换:xa,ya,za均为角度值,dotArray为存储点集的数组名
function dot_rotateAll(xa, ya, za, dotArray) {
for(var i in dotArray){
dot_rotate(xa, ya, za, dotArray,i);
}
}
//将单个空间点透视投影到xy平面,d为视点到投影面的距离,dot为需要作透视投影的点
function getOne_toxy(d,dot) {
var k = 1-dot.z/d;
dot.vx = dot.x/k;
dot.vy = -dot.y/k;
return dot;
}
// 将空间点集透视投影到xy平面,d为视点到投影面的距离,dotArray为存储点集的数组名
function getAll_toxy(d,dotArray) {
for (var i in dotArray) {
var k = 1-dotArray[i].z/d;
dotArray[i].vx = dotArray[i].x/k;
dotArray[i].vy = -dotArray[i].y/k;
}
}
//
//----------------------主程序段--------------------------------------------------------
V_d=500;
dot_rotateAll(0,30,0,dot);
// 按键响应和渲染
onEnterFrame=function(){
if(Key.isDown(Key.LEFT)) dot_rotateAll(0,1,0,dot);
else if(Key.isDown(Key.RIGHT)) dot_rotateAll(0,-1,0,dot);
else if(Key.isDown(Key.UP)) dot_rotateAll(1,0,0,dot);
else if(Key.isDown(Key.DOWN)) dot_rotateAll(-1,0,0,dot);
else if(Key.isDown(Key.PGUP)) dot_rotateAll(0,0,1,dot);
else if(Key.isDown(Key.PGDN)) dot_rotateAll(0,0,-1,dot);
getAll_toxy(V_d,dot);//顶点的透视投影
//RanderByLine();//线框渲染
SortPolygon();//面排序
FillTexture();//贴图
}
//-----------------------主程序完-------------------------------------------------------