我如何用从零开始的可读angular度来组合旋转matrix?

一直以来阻碍我进行3D编程的一件事就是无法理解math是如何工作的。 我可以用编程stream程中的math方法和函数来处理math,那么对我来说,这一切都是清楚而合乎逻辑的,但是在math符号中,我只是无法从中得出正面和反面的结论。

我一直在阅读网站,一些试图解释这个问题的研究机构的video,但他们都使用math符号,我只是迷失在其中,我的头脑不会把它翻译成可以理解的东西。 我可能有一个缺陷。

另外,仅仅使用别人的代码不是我的兴趣,我想了解它背后的机制,逻辑。 我很乐意使用别人的代码,但我真的想知道它是如何工作的。

这个问题

你可以用简单的术语来解释一下, 没有math符号,只是编程符号/函数/伪代码,如何在所有3个轴上实现matrix变换?

理想情况下,我想要的是写一个方法/对象的材料/理解,我可以定义类似于glRotate的三个轴的angular度来旋转我所拥有的四边形/三angular形的集合。 (我正在尝试编程一个立方体形状的3D旋转,而无需访问OpenGL函数来完成这个工作,因为每当显示列表发生变化时,都会在一次绘制调用中完成)。

我做了什么?

我试图做出一个90度的转换函数来获得math的诀窍,但却完全没有做出一个理论上应该是最简单的适当的matrix。 你可以在http://jsfiddle.net/bLfg0tj8/5/上看到我失败的尝试

Vec3 = function(x,y,z) { this.x = x; this.y = y; this.z = z; } Matrix = function Matrix() { this.matrixPoints = new Array(); this.rotationPoint = new Vec3(0,0,0); this.rotationAngle = 90; } Matrix.prototype.addVector = function(vector) { this.matrixPoints.push(vector); } Matrix.prototype.setRotationPoint = function(vector) { this.rotationPoint = vector; } Matrix.prototype.setRotationAngle = function(angle) { this.rotationAngle = angle; } Matrix.prototype.populate = function() { translateToOrigin = [[1,0,0-this.rotationPoint.x], [0,1,0-this.rotationPoint.y], [0,0,0-this.rotationPoint.z]]; rotationMatrix = [[0,-1,0], [0,1,0], [0,0,1]]; translateEnd = [[1,0,this.rotationPoint.x], [0,1,this.rotationPoint.y], [0,0,this.rotationPoint.z]]; currentColumn = 0; currentRow = 0; this.combomatrix = this.mergeMatrices(this.mergeMatrices(translateEnd,rotationMatrix), translateToOrigin); } Matrix.prototype.transform = function() { newmatrix = new Array(); for(c = 0;c<this.matrixPoints.length;c++) { newmatrix.push(this.applyToVertex(this.matrixPoints[c])); } return newmatrix; } Matrix.prototype.applyToVertex = function(vertex) { ret = new Vec3(vertex.x,vertex.y,vertex.z); ret.x = ret.x + this.combomatrix[0][0] * vertex.x + this.combomatrix[0][1] * vertex.y + this.combomatrix[0][2] * vertex.z; ret.y = ret.y + this.combomatrix[1][0] * vertex.x + this.combomatrix[1][1] * vertex.y + this.combomatrix[1][2] * vertex.z; ret.z = ret.z + this.combomatrix[2][0] * vertex.x + this.combomatrix[2][1] * vertex.y + this.combomatrix[2][2] * vertex.z; return ret; } Matrix.prototype.mergeMatrices = function(lastStep, oneInFront) { step1 = [[0,0,0],[0,0,0],[0,0,0]]; step1[0][0] = lastStep[0][0] * oneInFront[0][0] + lastStep[0][1] * oneInFront[1][0] + lastStep[0][2] * oneInFront[2][0]; step1[0][1] = lastStep[0][0] * oneInFront[0][1] + lastStep[0][1] * oneInFront[1][1] + lastStep[0][2] * oneInFront[2][1]; step1[0][2] = lastStep[0][0] * oneInFront[0][2] + lastStep[0][1] * oneInFront[1][2] + lastStep[0][2] * oneInFront[2][2]; //============================================================ step1[1][0] = lastStep[1][0] * oneInFront[0][0] + lastStep[1][1] * oneInFront[1][0] + lastStep[1][2] * oneInFront[2][0]; step1[1][1] = lastStep[1][0] * oneInFront[0][1] + lastStep[1][1] * oneInFront[1][1] + lastStep[1][2] * oneInFront[2][1]; step1[1][2] = lastStep[1][0] * oneInFront[0][2] + lastStep[1][1] * oneInFront[1][2] + lastStep[1][2] * oneInFront[2][2]; //============================================================ step1[2][0] = lastStep[2][0] * oneInFront[0][0] + lastStep[2][1] * oneInFront[1][0] + lastStep[2][2] * oneInFront[2][0]; step1[2][1] = lastStep[2][0] * oneInFront[0][1] + lastStep[2][1] * oneInFront[1][1] + lastStep[2][2] * oneInFront[2][1]; step1[2][2] = lastStep[2][0] * oneInFront[0][2] + lastStep[2][1] * oneInFront[1][2] + lastStep[2][2] * oneInFront[2][2]; return step1; } Matrix.prototype.getCurrentMatrix = function() { return this.matrixPoints; } myvectors = [new Vec3(50,50,0), new Vec3(20,80,0), new Vec3(80, 80, 0)]; function drawVectors(vectors,color) { for(c=0;c<vectors.length;c++) { document.getElementById("whoa").innerHTML += '<div style="color:'+color+';position:absolute;left:'+vectors[c].x+'px; top:'+vectors[c].y+'px;z-index:'+vectors[c].z+';">('+c+').</div>'; } } matrix = new Matrix(); for(c=0;c<myvectors.length;c++) { matrix.addVector(myvectors[c]); } matrix.setRotationPoint(new Vec3(50,70,0)); matrix.populate(); somematrix = matrix.transform(); drawVectors(matrix.getCurrentMatrix(),"lime"); // draw current matrix that was hand coded drawVectors([matrix.rotationPoint],'white'); // draw rotation point drawVectors(somematrix,"red"); // transformed matrix... somehow two points merge 
 <div id="whoa" style="position:relative;top:50px;left:150px;background-color:green;color:red;width:400px;height:300px;"> &nbsp; </div> 

绿色的文字是原来的三angular形,白色的点指向中心,红色指向失败的转换(我认为,因为它没有围绕中心点alignment)。 我在教程中认为如何将matrix组合成一个组合matrix,但我想我搞砸了某个地方。

正如我所说,我真的很难理解math符号和说话。 而不是帮助是大多数教师跳过部分的解释。 花了我2个小时的时间去了解乘法matrix时,你需要将每一步添加到一起,而不是继续繁殖。 耶解释。

一个实际的例子,我与/愿意合作

例如,我有一个立方体,从位于世界的wavefront obj文件加载

 x = 50 y = 100 z = 200 

立方体是使用四边形和一些UV映射绘制的。 这里没有问题。 它呈现精美的所有纹理正确显示。

这些是使用四边形绘制的立方体的每个“面”的位置坐标。

 // Front face -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, // Back face -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, // Top face -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, // Bottom face -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, // Right face 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, // Left face -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0 

所以这个工作非常棒。 但是如果我想让这个立方体沿着X轴旋转90度而绕着Z轴旋转45度呢? 我不能使用glRotate,因为此刻我将数据传递给tesselator对象,我不能通过opengl函数对它进行任何matrix转换,因为它只是接收数据,而不是实际上呈现它本身。

数据存储方式如下:

 WaveFrontObject() | |-> Groups(String groupname) | |-> Faces() | |-> Vertex(float x, float y, float z)[] |-> Float UVmap[] corresponding to each vertex |-> drawFace() // Draws the face as a quad or triangle 

因此,我给出的每个上述坐标都存储为组“立方体”中波前对象的一个​​面。

当多维数据集添加到tesselator它被翻译成世界上的正确的坐标,它呈现正常。

它总是呈现相同的。 如果我想让它以某个angular度呈现,那么我现在必须做出一个单独的波前对象才能做到这一点。 在我看来,疯狂的时候可以用一些math来解决。

需要答案

  1. 逐步解释如何build立一个翻译matrix,并尝试向我解释math。
  2. 解释如何将平移matrix应用到面中的四边形/三angular形,并保持面向其位置的中心

    x = 50.5 y = 100.5 z = 200.5

  3. 一些例子/伪代码去解释。

用来解释的编程语言只要在C系列中就没有真正的相关性

请尽量远离math符号/说话。 我不知道alpha beta是什么,thetha是,我知道x轴,y轴和z轴是什么。 我知道什么angular度,但是我不知道math家为它find的名字。

如果你想使用math名称,请向我解释他们在3D世界/代码中是什么,以及它们是如何形成/计算的。

我只是想做一个方法/对象沿线

 Matrix.transformVertices(vertices[], 90deg x, 45 deg y, 0 deg z); 

所以这个问题真的是理解4×4同质变换matrix

没有math背后唯一剩下的就是几何表示/意义,这对人类的抽象/理解来说要好得多。

那么4x4matrix是什么?

它是一些笛卡尔坐标系的表示,它由以下部分组成:

  1. 3基本向量(每个轴一个)红色,绿色,蓝色

    所以如果红色,绿色,蓝色vector彼此垂直,则坐标系是正交的 。 如果它们也是单位向量,那么它是正交的 (例如单位matrix)。

  2. 原点灰色

  3. 投影和均匀的一面(matrix底部没有标记)

    这个部分只是为了使旋转和平移一次,因此使用的点必须是forms(x,y,z,w=1)同质。 如果它只是(x,y,z)那么matrix将是3x3 ,这不足以进行翻译。 我不会用任何难以解释的预测来解释几何。

这个布局是从OpenGL的符号,也有转置表示(向量是行而不是列)

现在如何转换任何点到这个坐标系:

 g=M*l; l=Inverse(M)*g; 

哪里:

  • M是变换matrix
  • lM局部坐标系点(LCS)
  • g是全球坐标系统点(GCS)

对于转置版本( DirectX ),它是:

 l=M*g; g=Inverse(M)*l; 

那是因为转置的正交旋转matrix本身也是相反的

  • 欲了解更多信息,请参阅变换matrix解剖和3Dgraphicspipe道

OpenGL变换矩阵

2.如何形象化

是的,你可以绘制matrix的数字,但他们没有任何意义,特别是如果数字正在改变,所以绘制轴向量在上面的图像。 其中每个轴是从originorigin + line_size*axis_vector一条直线origin + line_size*axis_vector

3.如何构build它

只需计算轴vector和原点,并将它们放入matrix中即可。 为了保证正交性利用交叉乘积 (但要注意乘数的顺序来使用正确的方向)

4.效果

  • 旋转是通过旋转轴来完成的,所以你可以通过参数圆方程计算每个轴…
  • 缩放是通过将轴乘以缩放因子来完成的
  • 倾斜只是使用非垂直轴

5.旋转

对于大多数情况下使用增量旋转。 有两种types

  • 本地旋转 M'=M*rotation_matrixmatrix它围绕本地坐标M'=M*rotation_matrix旋转,就像您将控制飞机或汽车或玩家一样…大多数引擎/游戏不使用这些,而是​​用欧拉angular度来代替这是一个便宜的解决scheme(有许多怪癖和问题),因为大多数使用OpenGL的人甚至不知道这是可能的,而是glRotate/glTranslate调用栈列表…

  • 全局旋转 M'=Inverse(Inverse(M)*rotation_matrix)matrixM'=Inverse(Inverse(M)*rotation_matrix)它围绕全局坐标系轴旋转。

其中rotation_matrix是任何标准的旋转变换matrix。

如果你有不同的matrix布局(转置),那么本地和全球的旋转是相反的方式计算…

你也可以从3angular度来计算你的rotation_matrix ,比如:

 rotation_matrix=rotation_around_x(ax)*rotation_around_y(ay)*rotation_around_z(az); 

请参阅Wiki旋转matrix Rx,Ry,Rz Basic rotations中的3D Rx,Ry,Rz是您所需要的。 正如你所看到的,他们真的只是单位圆参数方程。 乘法的顺序改变了angular度收敛到目标位置的方式。 这就是所谓的欧拉angular ,我不使用它(我整合了步骤改变,而不是没有限制,如果正确的话不要说更简单)。

6. glRotate

如果你想glRotate那么你应该使用四元数,因为这是围绕轴旋转而不是3个angular度! 有解决办法:

  1. 为该轴创build变换matrixN
  2. 然后把你的matrixM转换成它
  3. 按angular度旋转N
  4. 然后将MN转换回全局坐标

或者你也可以使用Rodrigues_rotation_formula

在这种情况下,要将Matrix转换为Matrix,只需将轴转换为点,并将原点保持原样,但N的原点必须是(0,0,0)!

7.用法

转换是累积的,意味着:

  • p'=M1*M2*M3*M4*p;M=M1*M2*M3*M4; p'=M*p M=M1*M2*M3*M4; p'=M*p

所以,如果你有很多点要转换,那么你预先计算所有转换到单个matrix,并使用它。 所有后续的matrix不需要乘以点。 好了现在的概念:

你应该有3坐标系:

  • 相机C
  • 世界(通常是单位matrix)
  • 对象O (每个对象都有自己的matrix)

所以如果你有8顶点p0,...,p7立方体p0,...,p7那么你必须执行从对象本地坐标到相机本地坐标的每个点的变换。 一些gfx API做了一些,所以你只应用你所需要的,所以你真的需要:

  • p(i)'=inverse(C)*unit*M*p(i);

变换是累积的,单位matrix不会改变任何东西:

  • Q=inverse(C)*M; p(i)'=Q*p(i);

所以在为绘制对象绘制计算Q之后,取对象的每个点p(i)并计算变换后的p(i)'并绘制/使用变换的对象… p(i)'在本地相机坐标系(屏幕的x,y),但没有任何透视图,所以在绘图之前,您还可以添加任何投影matrix,并在最后用z坐标来划分。投影也是累积的,所以它也可以在Q

C ++的例子

 //$$---- Form CPP ---- //--------------------------------------------------------------------------- // apart from math.h include you can ignore this machine generated VCL related code #include <vcl.h> #pragma hdrstop #include "win_main.h" #include <math.h> //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TMain *Main; // pointer to main window ... //--------------------------------------------------------------------------- // Here is the important stuff some math first //--------------------------------------------------------------------------- const double deg=M_PI/180.0; double divide(double x,double y); void matrix_mul (double *c,double *a,double *b); // c[16] = a[16] * b[16] void matrix_mul_vector(double *c,double *a,double *b); // c[ 4] = a[16] * b[ 4] void matrix_subdet (double *c,double *a); // c[16] = all subdets of a[16] double matrix_subdet ( double *a,int r,int s);// = subdet(r,s) of a[16] double matrix_det ( double *a); // = det of a[16] double matrix_det ( double *a,double *b); // = det of a[16] and subdets b[16] void matrix_inv (double *c,double *a); // c[16] = a[16] ^ -1 //--------------------------------------------------------------------------- double divide(double x,double y) { if (!y) return 0.0; return x/y; } void matrix_mul (double *c,double *a,double *b) { double q[16]; q[ 0]=(a[ 0]*b[ 0])+(a[ 1]*b[ 4])+(a[ 2]*b[ 8])+(a[ 3]*b[12]); q[ 1]=(a[ 0]*b[ 1])+(a[ 1]*b[ 5])+(a[ 2]*b[ 9])+(a[ 3]*b[13]); q[ 2]=(a[ 0]*b[ 2])+(a[ 1]*b[ 6])+(a[ 2]*b[10])+(a[ 3]*b[14]); q[ 3]=(a[ 0]*b[ 3])+(a[ 1]*b[ 7])+(a[ 2]*b[11])+(a[ 3]*b[15]); q[ 4]=(a[ 4]*b[ 0])+(a[ 5]*b[ 4])+(a[ 6]*b[ 8])+(a[ 7]*b[12]); q[ 5]=(a[ 4]*b[ 1])+(a[ 5]*b[ 5])+(a[ 6]*b[ 9])+(a[ 7]*b[13]); q[ 6]=(a[ 4]*b[ 2])+(a[ 5]*b[ 6])+(a[ 6]*b[10])+(a[ 7]*b[14]); q[ 7]=(a[ 4]*b[ 3])+(a[ 5]*b[ 7])+(a[ 6]*b[11])+(a[ 7]*b[15]); q[ 8]=(a[ 8]*b[ 0])+(a[ 9]*b[ 4])+(a[10]*b[ 8])+(a[11]*b[12]); q[ 9]=(a[ 8]*b[ 1])+(a[ 9]*b[ 5])+(a[10]*b[ 9])+(a[11]*b[13]); q[10]=(a[ 8]*b[ 2])+(a[ 9]*b[ 6])+(a[10]*b[10])+(a[11]*b[14]); q[11]=(a[ 8]*b[ 3])+(a[ 9]*b[ 7])+(a[10]*b[11])+(a[11]*b[15]); q[12]=(a[12]*b[ 0])+(a[13]*b[ 4])+(a[14]*b[ 8])+(a[15]*b[12]); q[13]=(a[12]*b[ 1])+(a[13]*b[ 5])+(a[14]*b[ 9])+(a[15]*b[13]); q[14]=(a[12]*b[ 2])+(a[13]*b[ 6])+(a[14]*b[10])+(a[15]*b[14]); q[15]=(a[12]*b[ 3])+(a[13]*b[ 7])+(a[14]*b[11])+(a[15]*b[15]); for(int i=0;i<16;i++) c[i]=q[i]; } void matrix_mul_vector(double *c,double *a,double *b) { double q[3]; q[0]=(a[ 0]*b[0])+(a[ 1]*b[1])+(a[ 2]*b[2])+(a[ 3]); q[1]=(a[ 4]*b[0])+(a[ 5]*b[1])+(a[ 6]*b[2])+(a[ 7]); q[2]=(a[ 8]*b[0])+(a[ 9]*b[1])+(a[10]*b[2])+(a[11]); for(int i=0;i<3;i++) c[i]=q[i]; } void matrix_subdet (double *c,double *a) { double q[16]; int i,j; for (i=0;i<4;i++) for (j=0;j<4;j++) q[j+(i<<2)]=matrix_subdet(a,i,j); for (i=0;i<16;i++) c[i]=q[i]; } double matrix_subdet ( double *a,int r,int s) { double c,q[9]; int i,j,k; k=0; // q = sub matrix for (j=0;j<4;j++) if (j!=s) for (i=0;i<4;i++) if (i!=r) { q[k]=a[i+(j<<2)]; k++; } c=0; c+=q[0]*q[4]*q[8]; c+=q[1]*q[5]*q[6]; c+=q[2]*q[3]*q[7]; c-=q[0]*q[5]*q[7]; c-=q[1]*q[3]*q[8]; c-=q[2]*q[4]*q[6]; if (int((r+s)&1)) c=-c; // add signum return c; } double matrix_det ( double *a) { double c=0; c+=a[ 0]*matrix_subdet(a,0,0); c+=a[ 4]*matrix_subdet(a,0,1); c+=a[ 8]*matrix_subdet(a,0,2); c+=a[12]*matrix_subdet(a,0,3); return c; } double matrix_det ( double *a,double *b) { double c=0; c+=a[ 0]*b[ 0]; c+=a[ 4]*b[ 1]; c+=a[ 8]*b[ 2]; c+=a[12]*b[ 3]; return c; } void matrix_inv (double *c,double *a) { double d[16],D; matrix_subdet(d,a); D=matrix_det(a,d); if (D) D=1.0/D; for (int i=0;i<16;i++) c[i]=d[i]*D; } //--------------------------------------------------------------------------- // now the object representation //--------------------------------------------------------------------------- const int pnts=8; double pnt[pnts*3]= // Vertexes for 100x100x100 cube centered at (0,0,0) { -100.0,-100.0,-100.0, -100.0,+100.0,-100.0, +100.0,+100.0,-100.0, +100.0,-100.0,-100.0, -100.0,-100.0,+100.0, -100.0,+100.0,+100.0, +100.0,+100.0,+100.0, +100.0,-100.0,+100.0, }; const int facs=6; int fac[facs*4]= // faces (index of point used) no winding rule { 0,1,2,3, 4,5,6,7, 0,1,5,4, 1,2,6,5, 2,3,7,6, 3,0,4,7, }; double rep[16]= // 4x4 transform matrix of object (unit from start) at (0,0,+100) { 1.0,0.0,0.0, 0.0, 0.0,1.0,0.0, 0.0, 0.0,0.0,1.0,100.0, 0.0,0.0,0.0,1.0, }; double eye[16]= // 4x4 transform matrix of camera at (0,0,-150) { 1.0,0.0,0.0, 0.0, 0.0,1.0,0.0, 0.0, 0.0,0.0,1.0,-150.0, 0.0,0.0,0.0,1.0, }; //--------------------------------------------------------------------------- // this is how to draw it //--------------------------------------------------------------------------- void obj(double *pnt,int pnts,int *fac,int facs,double *rep,double *ieye) { // variables for drawing int i; double p0[3],p1[3],p2[3],p3[3],m[16],d; // gfx api variables (change to your stuff) Main is the main form of this application TCanvas *scr=Main->bmp->Canvas; double xs2=Main->ClientWidth/2,ys2=Main->ClientHeight/2; double v=xs2*tan(30.0*deg); // 60 degree viewing angle perspective projection matrix_mul(m,ieye,rep); // cumulate all needed transforms for (i=0;i<facs*4;) // go through all faces { // convert all points of face matrix_mul_vector(p0,m,&pnt[fac[i]*3]); i++; matrix_mul_vector(p1,m,&pnt[fac[i]*3]); i++; matrix_mul_vector(p2,m,&pnt[fac[i]*3]); i++; matrix_mul_vector(p3,m,&pnt[fac[i]*3]); i++; // here goes perspective divide by z coordinate if needed d=divide(v,p0[2]); p0[0]*=d; p0[1]*=d; d=divide(v,p1[2]); p1[0]*=d; p1[1]*=d; d=divide(v,p2[2]); p2[0]*=d; p2[1]*=d; d=divide(v,p3[2]); p3[0]*=d; p3[1]*=d; // here is viewport transform (just translate (0,0) to middle of screen in this case p0[0]+=xs2; p0[1]+=ys2; p1[0]+=xs2; p1[1]+=ys2; p2[0]+=xs2; p2[1]+=ys2; p3[0]+=xs2; p3[1]+=ys2; // draw quad // I use VCL GDI TCanvas you use what you have ... // and wireframe only to keep this simple (no Z buffer,winding culling,...) scr->Pen->Color=clAqua; // perimeter wireframe scr->MoveTo(p0[0],p0[1]); scr->LineTo(p1[0],p1[1]); scr->LineTo(p2[0],p2[1]); scr->LineTo(p3[0],p3[1]); scr->LineTo(p0[0],p0[1]); // scr->Pen->Color=clBlue; // face cross to visualy check if I correctly generate the fac[] // scr->MoveTo(p0[0],p0[1]); // scr->LineTo(p2[0],p2[1]); // scr->MoveTo(p1[0],p1[1]); // scr->LineTo(p3[0],p3[1]); } } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void TMain::draw() { if (!_redraw) return; bmp->Canvas->Brush->Color=clBlack; bmp->Canvas->FillRect(TRect(0,0,xs,ys)); // compute inverse of camera need to compute just once for all objects double ieye[16]; matrix_inv(ieye,eye); // draw all objects obj(pnt,pnts,fac,facs,rep,ieye); Main->Canvas->Draw(0,0,bmp); _redraw=false; } //--------------------------------------------------------------------------- __fastcall TMain::TMain(TComponent* Owner) : TForm(Owner) { // window constructor you can ignore this ... (just create a backbuffer bitmap here) bmp=new Graphics::TBitmap; bmp->HandleType=bmDIB; bmp->PixelFormat=pf32bit; pyx=NULL; } //--------------------------------------------------------------------------- void __fastcall TMain::FormDestroy(TObject *Sender) { // window destructor release memory ... also ignoe this if (pyx) delete pyx; delete bmp; } //--------------------------------------------------------------------------- void __fastcall TMain::FormResize(TObject *Sender) { // on resize event ... just resize/redraw backbuffer also can ignore this xs=ClientWidth; xs2=xs>>1; ys=ClientHeight; ys2=ys>>1; bmp->Width=xs; bmp->Height=ys; if (pyx) delete pyx; pyx=new int*[ys]; for (int y=0;y<ys;y++) pyx[y]=(int*) bmp->ScanLine[y]; _redraw=true; } //--------------------------------------------------------------------------- void __fastcall TMain::FormPaint(TObject *Sender) { // repaint event can ignore _redraw=true; } //--------------------------------------------------------------------------- void __fastcall TMain::tim_redrawTimer(TObject *Sender) { // timer event to animate the cube ... _redraw=true; // rotate the object to see it in motion double ang,c,s; ang=5.0*deg; c=cos(ang); s=sin(ang); // rotate baround z by 5 degrees per timer step double rz[16]= { c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; ang=1.0*deg; c=cos(ang); s=sin(ang); // rotate baround x by 1 degrees per timer step double rx[16]= { 1, 0, 0, 0, 0, c, s, 0, 0,-s, c, 0, 0, 0, 0, 1 }; matrix_mul(rep,rep,rz); matrix_mul(rep,rep,rx); draw(); } //--------------------------------------------------------------------------- 

这里是这样的:

立方体示例

和背面剔除GIFanimation:

动画

[笔记]

如果你有更多的问题,然后评论我…

基本的3Dvector操作经常需要[Edit2]

如果您不知道如何计算vector运算(如交叉/点积或绝对值),请参阅:

 // cross product: W = U x V Wx=(Uy*Vz)-(Uz*Vy) Wy=(Uz*Vx)-(Ux*Vz) Wz=(Ux*Vy)-(Uy*Vx) // dot product: a = (UV) a=Ux*V.x+Uy*V.y+Uz*Vz // abs of vector a = |U| a=sqrt((Ux*Ux)+(Uy*Uy)+(Uz*Uz)) 

[Edit3]通过键盘控制相机和对象的局部旋转

由于这个问题最近在这里有很多例子,

  • 固定摄像机视图控制(部分伪逆matrix)
  • 相机和播放器控制(逆matrix)
  • 如何通过累积变换保持精度(完全伪逆matrix)