¿Cómo compongo una matriz de rotación con angularjs legibles desde cero?

La única cosa que siempre me ha impedido hacer la progtwigción en 3D es no entender cómo funcionan las matemáticas. Puedo ir bien con las matemáticas bien en el flujo de progtwigción usando métodos y funciones, entonces todo es claro y lógico para mí, pero en notación matemática, simplemente no puedo sacarle cara o cruz.

He estado leyendo sitios web, viendo videos de institutos que tratan de explicar esto, pero todos usan notación matemática y simplemente me pierdo en él, mi mente no lo traducirá a algo comprensible. Puede que tenga un defecto allí.

Además, el simple hecho de usar el código de alguien no me interesa, quiero entender la mecánica detrás de esto, la lógica. Me encantaría usar el código de otra persona, pero realmente quiero entender cómo funciona.

La pregunta

¿Puede explicarme en términos simples sin notación matemática, solo progtwigción de notación / funciones / psuedocode, cómo implementar una transformación de matriz a lo largo de los 3 ejes?

Idealmente, lo que quiero es el material / entendimiento para escribir un método / objeto donde pueda definir los angularjs de 3 ejes similares a glRotate para rotar la colección de quads / triangularjs que tengo. (Estoy intentando progtwigr una rotación 3D de formas de cubo sin tener acceso a las funciones de OpenGL para hacerlo por mí, porque esto se hace en una llamada de extracción cada vez que algo cambia en la lista de visualización).

¿Qué he hecho?

Intenté hacer una función de transformación de 90 grados para obtener el truco de las matemáticas, pero fracasé por completo en la creación de una matriz adecuada que, en teoría, debería haber sido la más simple de hacer. Puedes ver mi bash fallido en todo su esplendor en 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 += '
('+c+').
'; } } 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
 
 

El texto verde es el triángulo original, el punto blanco el punto central, el rojo señala la transformación fallida (creo, porque no está alineado alrededor del punto central). El tutorial en el que estuve pensó en cómo combinar matrices en una matriz combinada, pero creo que lo arruiné en alguna parte.

Como dije, es realmente muy difícil para mí entender la notación matemática y hablar. Y no ayudar es que la mayoría de los maestros omitan partes de la explicación. Me tomó solo 2 horas entender que al multiplicar matrices necesitas agregar cada paso en lugar de solo seguir multiplicando. Yay por explicaciones.

Un ejemplo práctico con el que trabajo / quiero trabajar

Por ejemplo, tengo un cubo, cargado desde un archivo obj de frente de onda ubicado en el mundo en

 x = 50 y = 100 z = 200 

El cubo se dibuja usando quads y algún mapeo uv. No hay problemas aqui Se ve muy bien con todas las texturas que muestran correctamente.

Estas son las coordenadas de ubicación para cada “cara” del cubo que se dibuja utilizando un quad.

 // 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 

Así que esto funciona todo genial. Pero, ¿y si quiero que este cubo gire 90 grados a lo largo del eje xy 45 grados alrededor del eje z? No puedo usar glRotate porque en el momento en que paso los datos al objeto tesselator no puedo hacer ninguna matriz que se pueda transformar a través de las funciones opengl porque solo está tomando los datos, no realmente renderándolos per se.

La forma en que se almacenan los datos es la siguiente:

 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 

Así que cada una de las coordenadas anteriores que di se almacena como una cara del objeto de frente de onda en el grupo “cubo”.

Cuando el cubo se agrega al tesselator, se traduce a las coordenadas de la derecha en el mundo y se convierte en normal.

Sin embargo, siempre rinde lo mismo. Si quisiera que se renderizara en un ángulo, tendría que hacer un objeto de frente de onda separado en este momento para poder hacer eso. En mi opinión, es una locura hacer cuando se puede resolver con algunas matemáticas.

Necesario en la respuesta

  1. Explicación paso a paso sobre cómo construir una matriz de traducción y un bash de explicarme las matemáticas.
  2. Explicación de cómo aplicar la matriz de traducción a los cuadrantes / triangularjs en las caras que mantienen orientadas alrededor del centro de su ubicación

    x = 50.5 y = 100.5 z = 200.5

  3. Un ejemplo / pseudo código para acompañar la explicación.

El lenguaje de progtwigción utilizado para explicar no es realmente relevante siempre que esté en la familia C

Intente mantenerse alejado de la notación matemática / hablar. No sé qué alfa beta, thetha es, sé lo que es el eje x, el eje yy el eje z. Sé cuáles son los angularjs, pero no sé los nombres que los matemáticos encuentran para eso.

Si desea usar nombres matemáticos, explíqueme qué son en el mundo / código 3D y cómo se forman / calculan.

Simplemente quiero hacer un método / objeto a lo largo de las líneas de

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

Entonces, la pregunta es: comprender las matrices de transformación homogénea 4×4

bien, sin las matemáticas detrás, lo único que queda es representación geométrica / significado, que es mucho mejor para la abstracción / comprensión humana.

1. Entonces, ¿qué es la matriz 4×4?

Es la representación de algún sistema de coordenadas cartesianas y está compuesto por:

  1. 3 vectores de base (uno para cada eje) rojo, verde, azul

    Entonces, si los vectores rojo, verde y azul son perpendiculares entre sí, entonces el sistema de coordenadas es ortogonal . Si también son vectores unitarios, entonces es ortonormal (como por ejemplo la matriz unitaria).

  2. punto de origen gris

  3. proyección y lado homogéneo (rest inferior no marcado de la matriz)

    Esta parte está allí solo para permitir la rotación y la traducción a la vez, por lo tanto, el punto utilizado debe ser homogéneo, lo que significa en forma (x,y,z,w=1) . Si fuera solo (x,y,z) entonces la matriz sería 3x3 y eso no es suficiente para la traducción. No utilizaré ninguna proyección que sean difíciles de explicar geométricamente.

Este diseño es de notación OpenGL, también hay una representación transpuesta (los vectores son filas, no columnas)

ahora cómo transformar cualquier punto a / desde este sistema de coordenadas:

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

dónde:

  • M es la matriz de transformación
  • l es M punto de sistema de coordenadas local (LCS)
  • g es el punto del sistema de coordenadas global (GCS)

para la versión transpuesta ( DirectX ) es:

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

Eso es porque la matriz de rotación ortogonal transpuesta también es inversa a la misma

  • para obtener más información, vea transformar la anatomía de la matriz y la tubería gráfica 3D

Matriz de transformación OpenGL

2. cómo visualizarlo

Sí, puedes dibujar los números de la matriz, pero no tienen sentido a primera vista, especialmente si los números están cambiando, así que dibuja los vectores axises como en la imagen de arriba. Donde cada eje es una línea desde el origin hasta el origin + line_size*axis_vector

3. cómo construirlo

Simplemente calcule vectores de ejes y origen y colóquelos dentro de la matriz. Para garantizar la ortogonalidad explotar producto cruzado (pero tenga cuidado con el orden de los multiplicadores para usar la dirección correcta)

4. efectos

  • la rotación se realiza girando los ejes para que pueda calcular cada eje por ecuación de círculo paramétrico …
  • la escala se hace multiplicando ejes por factor de escala
  • sesgar es simplemente usar ejes no perpendiculares

5. rotación

Para la mayoría de los casos, se usa la rotación incremental. Hay dos tipos

  • rotación local M'=M*rotation_matrix gira alrededor de ejes de coordenadas locales como controlarás el avión, el coche o el jugador … La mayoría de los motores / juegos no usan estos y los falsifican con angularjs de euler que son una solución barata (tienen muchas peculiaridades) y problemas) porque la mayoría de las personas que usan OpenGL ni siquiera saben que esto es posible y más bien astackn la lista de llamadas glRotate/glTranslate

  • rotación global M'=Inverse(Inverse(M)*rotation_matrix) gira alrededor de los ejes del sistema de coordenadas globales.

donde rotation_matrix es cualquier matriz de transformación de rotación estándar.

Si tiene un diseño de matriz diferente (transpuesto), las rotaciones locales y globales se calculan al revés …

También puede calcular su rotation_matrix desde 3 angularjs, como:

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

vea las matrices de rotación de Wiki, las Rx,Ry,Rz 3D Rx,Ry,Rz de Basic rotations son lo que necesita. Como puede ver, son solo una ecuación paramétrica de círculo unitario. El orden de la multiplicación cambia la forma en que los angularjs convergen a la posición objective. Esto se llama angularjs de Euler y no lo uso (integro cambios de pasos que no tienen restricciones si se hacen correctamente, por no mencionar que es más simple).

6. glRotate

Si quieres glRotate entonces debes usar quaternions porque ¡eso es rotación alrededor del eje no por 3 angularjs! Hay una solución alternativa:

  1. crear la matriz de transformación N para ese eje
  2. luego transforma tu matriz M a ella
  3. rotar N por ángulo
  4. luego transforma M regreso de N a coordenadas globales

O puede usar Rodrigues_rotation_formula en su lugar

Para transformar Matrix a / de Matrix, en este caso simplemente transforma ejes como puntos y deja el origen como está, pero el origen de N debe ser (0,0,0)

7. uso

Las transformaciones son acumulativas eso significa:

  • p'=M1*M2*M3*M4*p; es lo mismo que M=M1*M2*M3*M4; p'=M*p M=M1*M2*M3*M4; p'=M*p

Entonces, si tiene muchos puntos para transformar, debe calcular previamente todas las transformaciones en una sola matriz y usar solo eso. No es necesario multiplicar puntos por todas las matrices posteriores. OK ahora el concepto:

deberías tener 3 sistemas de coordenadas:

  • cámara C
  • mundo (generalmente matriz unitaria)
  • objeto O (cada objeto tiene su propia matriz)

así que si tienes un cubo con 8 vértices p0,...,p7 entonces debes realizar la transformación en cada punto desde las coordenadas locales del objeto hasta las coordenadas locales de la cámara. Algunas aplicaciones de gfx hacen algo así que solo aplicas lo que tienes que hacer para que realmente necesites:

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

las transformadas son acumulativas y la matriz de unidades no cambia nada, así que:

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

entonces, antes de dibujar Q computacional para un objeto dibujado, tome cada punto p(i) del objeto y calcule el p(i)' transformado y dibuje / use el transformado … El p(i)' está en el sistema de coordenadas de la cámara local (x, y de la pantalla) pero no hay perspectiva allí, así que antes de dibujar también puedes agregar cualquiera de las matrices de proyección y dividir por z cordinate al final … La proyección también es acumulativa, por lo que también puede estar dentro de Q

[edit1] Ejemplo de C ++

 //$$---- Form CPP ---- //--------------------------------------------------------------------------- // apart from math.h include you can ignore this machine generated VCL related code #include  #pragma hdrstop #include "win_main.h" #include  //--------------------------------------------------------------------------- #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;iPen->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;yScanLine[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(); } //--------------------------------------------------------------------------- 

así es como se ve:

cubo ejemplo

Y animación GIF con eliminación de caras traseras:

animación

[notas]

Si tiene más preguntas, coménteme …

[Edit2] a menudo se necesitan operaciones básicas de vectores 3D

Si no sabe cómo calcular operaciones vectoriales como productos cruzados / puntos o valor absoluto, consulte:

 // 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)) 

aquí mi matemática vectorial C ++:

 static double vector_tmp[3]; double divide(double x,double y) { if ((y>=-1e-30)&&(y<=+1e-30)) return 0.0; return x/y; } double* vector_ld(double x,double y,double z) { double *p=vector_tmp; p[0]=x; p[1]=y; p[2]=z; return p;} double* vector_ld(double *p,double x,double y,double z) { p[0]=x; p[1]=y; p[2]=z; return p;} void vector_copy(double *c,double *a) { for(int i=0;i<3;i++) c[i]=a[i]; } void vector_abs(double *c,double *a) { for(int i=0;i<3;i++) c[i]=fabs(a[i]); } void vector_one(double *c,double *a) { double l=divide(1.0,sqrt((a[0]*a[0])+(a[1]*a[1])+(a[2]*a[2]))); c[0]=a[0]*l; c[1]=a[1]*l; c[2]=a[2]*l; } void vector_len(double *c,double *a,double l) { l=divide(l,sqrt((a[0]*a[0])+(a[1]*a[1])+(a[2]*a[2]))); c[0]=a[0]*l; c[1]=a[1]*l; c[2]=a[2]*l; } void vector_neg(double *c,double *a) { for(int i=0;i<3;i++) c[i]=-a[i]; } void vector_add(double *c,double *a,double *b) { for(int i=0;i<3;i++) c[i]=a[i]+b[i]; } void vector_sub(double *c,double *a,double *b) { for(int i=0;i<3;i++) c[i]=a[i]-b[i]; } void vector_mul(double *c,double *a,double *b) // cross { double q[3]; q[0]=(a[1]*b[2])-(a[2]*b[1]); q[1]=(a[2]*b[0])-(a[0]*b[2]); q[2]=(a[0]*b[1])-(a[1]*b[0]); for(int i=0;i<3;i++) c[i]=q[i]; } void vector_mul(double *c,double *a,double b) { for(int i=0;i<3;i++) c[i]=a[i]*b; } void vector_mul(double *c,double a,double *b) { for(int i=0;i<3;i++) c[i]=a*b[i]; } double vector_mul( double *a,double *b) { double c=0; for(int i=0;i<3;i++) c+=a[i]*b[i]; return c; } // dot double vector_len(double *a) { return sqrt((a[0]*a[0])+(a[1]*a[1])+(a[2]*a[2])); } double vector_len2(double *a) { return (a[0]*a[0])+(a[1]*a[1])+(a[2]*a[2]); } 

[Editar3] rotaciones locales para controlar la cámara y el objeto a través del teclado

Como esto se ha preguntado mucho últimamente, aquí algunos ejemplos de respuestas mías con demos:

  • control estacionario de la vista de la cámara (matriz pseudo inversa parcial)
  • control de cámara y reproductor (matriz inversa)
  • Cómo preservar la precisión con transformaciones acumuladas a lo largo del tiempo (matriz pseudo inversa completa)