ToLua学习笔记,创建自定义矩阵类

来源:互联网 发布:数字油画需要什么软件 编辑:程序博客网 时间:2024/05/22 05:01

我突然想到,框架里并没有提供Matrix4x4这个重要的类,所以我参考Quaternion.lua写了一个Matrix4X4.lua

Matrix4X4类内有16个公有的字段,而unity中的Matrix4X4类既可以通过.mXX的方式访问属性,也可以通过索引器Matrix4X4[m][n]的方式来访问,但lua中并没有索引器,

但是,我们可以通过表嵌套实现二维数组,但是一旦设计成嵌套表,那16个属性势必会分散到4个子表中,这时候如果再想直接通过.mXX的方式访问是不行的。这个时候就需要元函数的帮助了,以下是全部代码:

local math= mathlocal tan   = math.tanlocal pow   = math.powlocal setmetatable = setmetatablelocal getmetatable = getmetatablelocal rawget = rawgetlocal rawset = rawsetlocal Vector3 = Vector3local Vector4 = Vector4local order=4 --阶数Matrix4x4 ={}Matrix4x4.__index = function(t, k)local var=rawget(Matrix4x4,k)if var~=nil thenreturn varendif k=="m00" thenreturn t[1][1]elseif k== "m01" thenreturn t[1][2]elseif k== "m02" thenreturn t[1][3]elseif k== "m03" thenreturn t[1][4]elseif k== "m10" thenreturn t[2][1]elseif k== "m11" thenreturn t[2][2]elseif k== "m12" thenreturn t[2][3]elseif k== "m13" thenreturn t[2][4]elseif k== "m20" thenreturn t[3][1]elseif k== "m21" thenreturn t[3][2]elseif k== "m22" thenreturn t[3][3]elseif k== "m23" thenreturn t[3][4]elseif k== "m30" thenreturn t[4][1]elseif k== "m31" thenreturn t[4][2]elseif k== "m32" thenreturn t[4][3]elseif k== "m33" thenreturn t[4][4]endreturn nilendMatrix4x4.__newindex = function(t, k, v)if t[k]~=nil thent[k]=vendendfunction Matrix4x4.New(m00,m01,m02,m03,m10,m11,m12,m13,m20,m21,m22,m23,m30,m31,m32,m33)local m ={{m00 or 0,m01 or 0,m02 or 0,m03 or 0},{m10 or 0,m11 or 0,m12 or 0,m13 or 0},{m20 or 0,m21 or 0,m22 or 0,m23 or 0},{m30 or 0,m31 or 0,m32 or 0,m33 or 0}}setmetatable(m, Matrix4x4)return mendlocal _new=Matrix4x4.NewMatrix4x4.__call = function(t,m00,m01,m02,m03,m10,m11,m12,m13,m20,m21,m22,m23,m30,m31,m32,m33)return _new(m00,m01,m02,m03,m10,m11,m12,m13,m20,m21,m22,m23,m30,m31,m32,m33)end--获取一个单位矩阵function Matrix4x4.identity()return _new(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)endfunction Matrix4x4.zero()return _new(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)end--获取行列式的值function Matrix4x4:DeterminantSelf()return Matrix4x4.Determinant(self)end--获取逆矩阵function Matrix4x4:InverseSelf()return Matrix4x4.Inverse(self)end--是否是单位矩阵function Matrix4x4:isIdentity()return self[1][1]==1 and self[2][2]==1 and self[3][3]==1 and self[4][4]==1end--求nxn的方阵m的行列式的值,order为阶数function Matrix4x4.DeterminantOfOrder(m,order)local sum1,sum2=0,0for col=1,order dolocal product=1for times=0,order-1 doproduct=product*m[1+times][(col+times-1)%order+1]endsum1=sum1+productendfor col=1,order dolocal product=1for times=0,order-1 doproduct=product*m[order-times][(col+times-1)%order+1]endsum2=sum2+productendreturn sum1-sum2end--返回第i列,vector4类型function Matrix4x4:GetColumn(i)return Vector4(self[1][i],self[2][i],self[3][i],self[4][i])end--返回第i行,vector4类型function Matrix4x4:GetRow(i)return Vector4(self[i][1],self[i][2],self[i][3],self[i][4])end--把一个Vector3的坐标(列向量)左乘矩阵转换到另一个坐标系,返回Vector3类型--因为是坐标,所以w默认按1处理function Matrix4x4:MultiplyPoint(v3)local v=Vector4(v3.x,v3.y,v3.z,1)local v2=self:MultiplyVector4(v)if v2.w==0 thenprint("除数无意义")v2.x=0v2.y=0v2.z=0return v2endreturn Vector3(v2.x/v2.w,v2.y/v2.w,v2.z/v2.w)end--把一个Vector4的坐标或向量(列向量)左乘矩阵转换到另一个坐标系,返回Vector4类型function Matrix4x4:MultiplyVector4(v4)local result=Vector4.zero()result.x=v4.x*self[1][1]+v4.y*self[1][2]+v4.z*self[1][3]+v4.w*self[1][4]result.y=v4.x*self[2][1]+v4.y*self[2][2]+v4.z*self[2][3]+v4.w*self[2][4]result.z=v4.x*self[3][1]+v4.y*self[3][2]+v4.z*self[3][3]+v4.w*self[3][4]result.w=v4.x*self[4][1]+v4.y*self[4][2]+v4.z*self[4][3]+v4.w*self[4][4]return resultend--把一个Vector3的向量(列向量)左乘矩阵转换到另一个坐标系,返回Vector3类型--因为是向量,所以w默认按0处理function Matrix4x4:MultiplyVector(v3)local v=Vector4(v3.x,v3.y,v3.z,0)local v2=self:MultiplyVector4(v)if v2.w==0 thenprint("除数无意义")v2.x=0v2.y=0v2.z=0return v2endreturn Vector3(v2.x/v2.w,v2.y/v2.w,v2.z/v2.w)end--设置第i列的值为一个Vector4向量function Matrix4x4:SetColumn(i,v4)self[1][i]=v4.x;self[2][i]=v4.y;self[3][i]=v4.z;self[4][i]=v4.w;end--设置第i行的值为一个Vector4向量function Matrix4x4:SetRow(i,v4)self[i][1]=v4.x;self[i][2]=v4.y;self[i][3]=v4.z;self[i][4]=v4.w;end--设置平移pos(Vector3),旋转q(Quaternion),缩放s(Vector3)矩阵function Matrix4x4:SetTRS(pos,q,s)self=Matrix4x4.TRS(pos,q,s)end--求4x4矩阵m的行列式的值function Matrix4x4.Determinant(m)return Matrix4x4.DeterminantOfOrder(m,order)end--求4x4矩阵m的第i行第j列的余子式的值,i,j从1开始function Matrix4x4.GetCofactor(m,i,j)local cofactor ={{0,0,0},{0,0,0},{0,0,0}}local arow=1for row=1,order-1 doif row>=i then arow=row+1elsearow=rowendlocal acol=1for col=1,order-1 doif col>=j thenacol=col+1 elseacol=colendcofactor[row][col]=m[arow][acol]endendreturn  Matrix4x4.DeterminantOfOrder(cofactor,order-1)end--求4x4矩阵m的第i行第j列的代数余子式的值,i,j从1开始function Matrix4x4.GetAlgebraic(m,i,j)return pow(-1,i+j)*Matrix4x4.GetCofactor(m,i,j)end --求一个4x4矩阵的逆矩阵,如果不可逆,则打印异常function Matrix4x4.Inverse(m)local det=m:DeterminantSelf()if det==0 thenprint("不可逆")return 1e-6endlocal idet=1/detlocal im=Matrix4x4.zero()for row=1,order dofor col=1,order doim[row][col]=m.GetAlgebraic(m,row,col)endendreturn imend--获取正交投影矩阵function Matrix4x4.Ortho(left,right,bottom,top,zNear,zFar)local m=Matrix4x4.zero()local x =2.0/(right - left)local y =2.0/(top - bottom)local z =-2.0/(zFar - zNear)local a = -(right + left) / (right - left)local b = -(top + bottom) / (top - bottom)local c =-(zFar + zNear) / (zFar - zNear)m[1][1] = xm[1][2] = 0m[1][3] = 0m[1][4] = am[2][1] = 0m[2][2] = ym[2][3] = 0m[2][4] = bm[3][1] = 0m[3][2] = 0m[3][3] = zm[3][4] = cm[4][1] = 0m[4][2] = 0m[4][3] = 0m[4][4] = 1return mend--获取透视投影矩阵function Matrix4x4.Perspective(left,  right,  bottom,  top,  zNear,  zFar)local m=Matrix4x4.zero()local x = 2.0 * zNear / (right - left)local y = 2.0 * zNear / (top - bottom)local a = (right + left) / (right - left)local b = (top + bottom) / (top - bottom)local c = -(zFar + zNear) / (zFar - zNear)local d = -(2.0 * zFar * zNear) / (zFar - zNear)local e = -1.0m[1][1] = xm[1][2] = 0m[1][3] = am[1][4] = 0m[2][1] = 0m[2][2] = ym[2][3] = bm[2][4] = 0m[3][1] = 0m[3][2] = 0m[3][3] = cm[3][4] = dm[4][1] = 0m[4][2] = 0m[4][3] = em[4][4] = 0return mend--获取透视投影矩阵function Matrix4x4.Perspective( fov,  aspect,  zNear,  zFar)local top=zNear*tan(fov*0.5)local bottom=-toplocal right=top*aspectlocal left=-rightreturn Matrix4x4.Perspective(left,right,bottom,top,zNear,zFar)end--创建一个平移矩阵,参数v3(Vector3)function Matrix4x4.Translation(v3)local m=Matrix4x4.identity()m[4][1]=v3.xm[4][2]=v3.ym[4][3]=v3.zreturn mend--创建一个绕任意轴旋转的矩阵,q(Quaternion)function Matrix4x4.Spin(q)local m=Matrix4x4.identity()local x2=q.x*q.xlocal y2=q.y*q.ylocal z2=q.z*q.zlocal xy=q.x*q.ylocal xz=q.x*q.zlocal yz=q.y*q.zlocal wx=q.w*q.xlocal wy=q.w*q.ylocal wz=q.w*q.zm[1][1]=1-2*(y2+z2)m[1][2]=2*(xy-wz)m[1][3]=2*(xz+wy)m[2][1]=2*(xy+wz)m[2][2]=1-2*(x2+z2)m[2][3]=2*(yz-wx)m[3][1]=2*(xz-wy)m[3][2]=2*(yz+wx)m[3][3]=1-2*(x2+y2)return mend--创建一个缩放矩阵function Matrix4x4.Scale(v3)local m=Matrix4x4.identity()m[1][1]=v3.xm[2][2]=v3.ym[3][3]=v3.zreturn mend--求转置矩阵function Matrix4x4.Transpose(m)local t=Matrix4x4.zero()for i=1,order dofor j=1,order dot[i][j]=m[j][i]endendreturn tend--创建一个平移pos(Vector3),旋转q(Quaternion),缩放s(Vector3)矩阵--特意说明一点,虽然此unity中此方法的意思是先位移,再旋转,再缩放,但经过测试,他们并不是3个矩阵的连续左乘的结果--而是此函数内的写法,而且经过本人测试,unity中的SetTRS计算出的结果并不正确--原因不清楚,还望高人指点function Matrix4x4.TRS(pos,q,s)local m1=Matrix4x4.Spin(q)local m2=Matrix4x4.Scale(s)local m3=m2*m1m3[1][4]=pos.xm3[2][4]=pos.ym3[3][4]=pos.zreturn m3endMatrix4x4.__add=function(lhs,rhs)local m=Matrix4x4.zero()for i=1,order dofor j=1,order dom[i][j]=lhs[i][j]+rhs[i][j]endendreturn mendMatrix4x4.__sub=function(lhs,rhs)local m=Matrix4x4.zero()for i=1,order dofor j=1,order dom[i][j]=lhs[i][j]-rhs[i][j]endendreturn mend--两个4x4方阵相乘,根据opengl里的左乘Matrix4x4.__mul=function(lhs,rhs)local m=Matrix4x4.zero()for i=1,order dofor j=1,order dolocal sum=0for index=1,order dosum=sum+lhs[i][index]*rhs[index][j]endm[i][j]=sumendendreturn mend--两个4x4方阵相除,根据opengl里的左乘rhs的逆矩阵Matrix4x4.__div=function(lhs,rhs)local m_inv=rhs:Inverse()return lhs*m_invend--判断两个4x4矩阵是否相等Matrix4x4.__eq = function(lhs,rhs)for i=1,order dofor j=1,order doif lhs[i][j]~=rhs[i][j] then return false endendendreturn trueendMatrix4x4.__tostring = function(self)return "["..self[1][1]..self[1][2]..self[1][3]..self[1][4]..self[2][1]..self[2][2]..self[2][3]..self[2][4]..self[3][1]..self[3][2]..self[3][3]..self[3][4]..self[4][1]..self[4][2]..self[4][3]..self[4][4].."]"endfunction isnan(x) return x ~= x endUnityEngine.Matrix4x4 = Matrix4x4setmetatable(Matrix4x4, Matrix4x4)return Matrix4x4
此类所有功能已全部通过测试,可以放心的拿去使用
另外我认为unity中的SetTRS方法还是有问题的,暂时还没搞明白,还请高人指教了
还有一个MutiPoint3x4我觉得没有必要实现了
这个类并没有融入到tolua原有的框架中,Quanation还无法操作本类,但本类可以操作Quanation
另外就是写的过程中,我也查找了大量资料,看了其他的一些源码,还有微软的做法,其实很多地方都可以优化的,不过本人精力有限,就只能用普通方法了
阅读全文
1 0
原创粉丝点击