JavaScript em 3D


1. Introdução

A computação gráfica em 3D é uma continuação da computação gráfica em 2D, acrescenta-se o eixo-z no sitema de coordenadas. A tela do computador tem apenas duas dimensões, ou seja, é em 2D, porém, ao desenhar um objeto em três dimensões, as suas medidas ficam guardas em variáveis normalmente, porém, para exibir na tela, somente deve desenhar as duas dimensões x e y do ponto P(x,y,z).  Foi utilizado uma forma didática bem simples para que se possa perceber o que se está fazendo, tal como foi utilizado para  o entendimento do cubo de lados iguais a dois.

1.1. Giro no Espaço e Projeção Ortogonal
Conforme a figura do cubo abaixo, um ponto tridimensional P(x,y, 0) com coordenada z = 0, a uma distância constante  r da origem do sistema de coordenadas,  forma um ângulo θ = 90º com o eixo-z e um ângulo constante β com o eixo-x, assim,  x e y terão tamanhos máximos. Quando o ponto P(x,y,0) passa a ocupar a posicão P1(x1,y1,z1) tal que z1 é diferente de zero (θ < 90º), as coordenadas x1 e y1 terão tamanhos menores do que x e y.
As coordenadas do ponto P(x,y,0) serão desenhadas na tela com tamanhos máximo, na projeção ortogonal, repare que a coordenada z1 não será desenhada na tela, pois a tela tem apenas o eixo-x e o eixo-y, porém as coordenadas x1 e y1 serão desenhadas menores que x e y de P(x,y,0) devido a existência da coordenada z1, com isso, cria-se uma ilusão de três dimensões na tela que tem apenas os eixos-x e eixo-y, dessa forma, todas as coordenadas serão desenhadas diretamente na tela, este tipo de projeção se chama ortogonal, pois cada coordenada foi projetada perpendicularmante. Tudo isso é melhor percebido em uma cubo trigonométrica que tem os três eixos (x,y e z).

Cubo de lado igual a dois no centro do sistema de coordenadas.

1.1.2. Para uma ciclo trigonométrica tridimensional tem-se:

Para um ponto P(x,y,z) do objeto terá um ponto P'(x',y') na tela, tal que x' = x e y' = y.
Para um ponto P(x,y,0) do objeto, z = 0, x e z terão valores máximos, pertence ao planoXY.
Para um ponto P(x,y,z) do objeto com z 0, x e z terão valores menor que o máximos.
Imagine P se deslocando com raio r até o eixo-z, sua nova posição será P1, a medida que aumenta o ângulo de rotação θ até atingir o eixo-z, x1 e y1 vão diminuindo e z1 vai aumentando até que z1 ficará com tamanho máximo emcima do eixo-z e x1 e y1 terão tamanho igual a zero, isto é P1(z1,0,0).

1.2. Revisão Círculo Trigonométrico
Um ponto no espaço 3D é composto por duas projeções (pontos) no espaço 2D. O ponto P fica determinado com Px, θ e α.


Para uma ângulo θ do círculo trigonométrico, tem-se:

Reiniciar


2. Revisão 2D
O último código desenvolvido na apostila de JavaScript2D foi a criação, centralização e rotação de um figura no plano XY conforme código abaixo, o primeiro programa em 3D a ser feito em seguida é uma transformação desse código.

O seu browser não suporta o elemento canvas do HTML5. Por favor, actualize o seu browser.

Sera plotado na tela uma simples retângula usando apenas as propriedades do elemento canvas co HTML5, o objetivo neste exercício é conhecer o elemento canvas e converter a coordenada da tela para a coordenada cartesiana.
Escolhas:
- objeto que se quer desenhar.
- tamanho do obejto.
- tamanho do canvas.
- distância da origem do sistema de coordenadas do canvas com a origem de sistema de coorenadas do objeto.
Obs: o sistema de coordenadas do canvas é o sistema de referência, do qual o sistema de coordenadas do objeto se refere. Na verdade o sistema de coordenadas do objeto é imaginário, serve apenas para os cálculos das coordenadas
Calcula-se:
- o centro de coordenadas do objeto que será o mesmo do cubo de lado igual a dois.
- padronização dos vértices do quadrado imaginário com projeções iguais a 1 ou -1.
- calcular as coordenadas do objeto.

Código:
<!DOCTYPE html>
<html>
<head>
    <title></title>

</head>
<body>
    <canvas id="c" width="300" height="200" style="border:1px solid #000000;">
      O seu browser não suporta o elemento canvas do HTML5.
      Por favor, actualize o seu browser.
    </canvas>

<button onclick="faz()">Try it</button>

    <script>
        function Point2D(x,y) {
          this.x = x;
          this.y = y;
          
            this.r = function(angle) { // rotacao de ponto
                var rad, cosa, sina, x, y
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                x = this.x * cosa - this.y * sina
                y = this.x * sina + this.y * cosa
                return new Point2D(x, y)
            }


            this.t1 = function(tx,ty) { // translacao de ponto
                return new Point2D(x - tx,y - ty)
            }   
            this.t2 = function(tx,ty) {
                return new Point2D(x + tx,y + ty)
            }
          
          
        }
       
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");

        ctx.scale(1,-1); //eixo-y negativo abaixo do eixo-x
        ctx.translate(0, -200) //eixo-x desce para a base do canva

var xc = Math.ceil((300-1)/2);
var yc = Math.ceil((200-1)/2);

var w = 200;
var h = 100;
var x1 = (xc + w/2);
var y1 = (yc + h/2);
var x2 = (xc + w/2);
var y2 = (yc - h/2);
var x3 = (xc - w/2);
var y3 = (yc - h/2);
var x4 = (xc - w/2);
var y4 = (yc + h/2);


var coord = new Array();
coord.push(new Point2D(x1, y1));
coord.push(new Point2D(x2, y2));
coord.push(new Point2D(x3, y3));
coord.push(new Point2D(x4, y4));
coord.push(new Point2D(x1, y1));

           var angle = 30;
 function faz() {
           ctx.clearRect(0,0,300,200);
           var t = new Array();
           for( var i = 0; i < coord.length; i++ ) {
                var rr = coord[i].t1(xc,yc).r(angle).t2(xc,yc) ;
                t.push(rr);
           }  
 
            
        angle = angle+10;
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(t[0].x,t[0].y);
               for( var i = 1; i < t.length; i++ ) {
                    ctx.lineTo(t[i].x,t[i].y);
                }


        ctx.stroke();
        ctx.closePath();
 }
    </script>
</body>
</html>
Link para o código acima.

Observação:
var rr = coord[i].t1(xc,yc).r(angle).t2(xc,yc) ;
Esta linha significa:
coord[i]: armazena as coordenadas dos pontos.
t1(-xcyc): translada a figura do seu centro para a origem do sistema de coordenadas.
r(angle): rotaciona os pontos.
t2(xc,yc): translada de volta os pontos do sistema de coordenadas para  o centro da tela.

3. Pontos em 3D

Acrescenta-se o parâmetro z na função Point2D() estudada em 2D, em 3D o ponto é representado pela função por três coordenadas (x,y e z):
function Point3D(x,y,z) {
          this.x = x;
          this.y = y;
          this.z = z;
        }

Códdigo:
O código abaixo armazena os valores das coordenadas do ponto Point3D() num array do tipo Point3D e imprime na tela os seus valores.
<!DOCTYPE html>
<html>
<head>
    <title></title>

</head>
<body>
 
    <script>
        function Point3D(x,y,z) {
          this.x = x;
          this.y = y;
          this.z = z;
        }

var xo = 10;
var yo = 20;
var zo = 30;

var x1 = 100;
var y1 = 200;
var z1 = 300;

var coord = new Array();
coord.push(new Point3D(xo, yo, zo));
coord.push(new Point3D(x1, y1, z1));

document.write("Po: ("+coord[0].x+", " +coord[0].y+", "+coord[0].z+")" +'<br>');
document.write("P1: ("+coord[1].x+", " +coord[1].y+", "+coord[1].z+")" +'<br>');
           
    </script>
</body>
</html>
Saída:
Po: (10, 20, 30)
P1: (100, 200, 300)

4. Centralização de pontos em 3D
Da mesma forma que em 2D usar um quadrado de lado igual a dois e coordenadas igual a 1 ou -1, cuja sistema de coordenadas do objeto tem origem no seu centro, em 3D utliza-se um cubo de lado igual a 2, cuja origem do seus sistema de coordenadas encontra-se no seu centro.
4.1. Cubo ou Hexaedro Centralizador
Calcula-se:
- o centro de coordenadas do objeto será o mesmo do cubo de lado igual a dois.
- é  utilizado o sistema de coordenadas da mão direita  como padrão para criação da imagem.

- padronização dos vértices do cubo imaginário com projeções iguais a 1 ou -1.
- calcular as coordenadas do objeto.
Cubo 2x2 (y para cima)
Vértices (mão direita)
0(-1,-1,1)
1(1,-1,1)
2(1,-1,-1)
3(-1,-1,-1)
4(-1,1,1)
5(1,1,1)
6(1,1,-1)
7(-1,1,-1)

Fazendo dois giros de 90º no eixo-x no cubo acima, o eixo-y fica com a mesma disposição da tela do computador, ou seja, positivo para baixo, conforme o cubo abaixo. O eixo-z fica apontado para dentro da tela. Os valores dos vértices não se alteram porque giraram junto com os eixos.
Essa disposição dos eixos será utilizado para a criação da perspectiva.
Cubo 2x2 (y para baixo) Vértices (mão direita)
0(-1,-1,1)
1(1,-1,1)
2(1,-1,-1)
3(-1,-1,-1)
4(-1,1,1)
5(1,1,1)
6(1,1,-1)
7(-1,1,-1)

Vétices
(posição dos pontos em relação a origem do sistema de coordenadas do objeto).
Sistema de coordenadas da mão esquerda é só inverter o sinal da coordenada-z do sistema de coordenadas da mão direita.

Em programação atribui-se um número a cada vértice do cubo, conforme figura acima, escolhe-se a posição dos eixos e o sistema de coordenadas. O centro do cubo coincide com a origem do sistema de coordenadas, (0,0,0). As faces do cubo possuem comprimento igual a 2, com isso, cada coordenada x, y e z dos seus oito vértices são iguais a +1 ou -1.

Cubo: 6 faces, 12 arestas e 8 vértices.
Cria-se uma lógica para a seqüência de pontos, os vértices foram numerado no sentido anti-horário nas faces de topo e base.
As faces foram seqüênciadas como base, topo, frente, lateral esquerda, fundo lateral e lateral esquerda. A numeração das faces pode varia, pode ser qualquer nome, foi utilizado números.
Vértices: 0, 1, 2, 3, 4, 5, 6 e 7.
Faces: 0(0,1,2,3), 1(1,5,4,0), 2(2,6,5,1), 3(3,2,6,7), 4(4,0,3,7) e 5(5,6,7,4)
A seqüência de vértices dentro da face não afeta o desenho da face.
É importante a nomeclatura para facilitar o entendimento quando for fazer o código.

Superfícies
Padronizar seqüência de pontos, da esquerda para direita como se o eixo perpendicular a face girasse para a esquerda, o importante é criar uma sequencia lógica para a criação do desenho.
Superfície da base:
0(-1,-1,1)
1(1,-1,1)
2(1,-1,-1)
3(-1,-1,-1)
0(0,1,2,3)
Superfície do topo:
4(-1,1,1)
5(1,1,1)
6(1,1,-1)
7(-1,1,-1)
5(5,6,7,4)

Frente
1(1,5,4,0)
Lateral direita
2(2,6,5,1)

Lateral fundo
3(3,2,6,7)
Lateral esquerda
4(4,0,3,7)

Repare que a seqüência de pontos das faces formam um quadrado, um após o outro, não pode cruzar os pontos, não importa qual ponto é o primeiro.

4.2. Código centralização da face da frente do cubo na tela
A face da frente possui os seguintes vértices:
0(-1,-1,1)
1(1,-1,1)
4(-1,1,1)
5(1,1,1)

4.2.1. Centro do Canvas
width = hieght =  depth = 200
var xc = Math.ceil((200-1)/2);
var yc = Math.ceil((200-1)/2);
var zc = Math.ceil((200-1)/2);
xc, yc e zc: correspondem ao centro do canvas que tem 200 de width, 200 de hieght e 200 de depth (profundidade).
Observe que o canvas tem apenas duas dimenções, porém para efeito de cálculo deve-se considerar a terceira dimensão.

4.2.2. Coordenadas da face da frente do objeto (cubo de lado igual a 100)

var w = 100;
var h = 100;
var dp = 100;
var xo = (xc - w/2);
var yo = (yc - h/2);
var zo = (zc + dp/2);
var x1 = (xc + w/2);
var y1 = (yc - h/2);
var z1 = (zc + dp/2);
var x4 = (xc - w/2);
var y4 = (yc + h/2);
var z4 = (zc + dp/2);
var x5 = (xc + w/2);
var y5 = (yc + h/2);
var z5 = (zc + dp/2);

Código:
<!DOCTYPE html>
<html>
<head>
    <title></title>

</head>
<body>
    <canvas id="c" width="200" height="200" style="border:1px solid #000000;">
      O seu browser não suporta o elemento canvas do HTML5.
      Por favor, actualize o seu browser.
    </canvas>

<button onclick="faz()">Try it</button>
    

    <script>
        function Point3D(x,y,z) {
          this.x = x;
          this.y = y;
          this.z = z;
        }
        
      
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");

        ctx.scale(1,-1); //eixo-y negativo abaixo do eixo-x
        ctx.translate(0, -200) //eixo-x desce para a base do canva



var xc = Math.ceil((200-1)/2);
var yc = Math.ceil((200-1)/2);
var zc = Math.ceil((200-1)/2);

var w = 100;
var h = 100;
var dp = 100;


var xo = (xc - w/2);
var yo = (yc - h/2);
var zo = (zc + dp/2);
var x1 = (xc + w/2);
var y1 = (yc - h/2);
var z1 = (zc + dp/2);
var x4 = (xc - w/2);
var y4 = (yc + h/2);
var z4 = (zc + dp/2);
var x5 = (xc + w/2);
var y5 = (yc + h/2);
var z5 = (zc + dp/2);


var coord = new Array();
coord.push(new Point3D(xo, yo, zo));
coord.push(new Point3D(x1, y1, z1));
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x4, y4, z4));

function faz(){

                ctx.beginPath();
                ctx.moveTo(coord[0].x,coord[0].y)
                ctx.lineTo(coord[1].x,coord[1].y)
                ctx.lineTo(coord[2].x,coord[2].y)
                ctx.lineTo(coord[3].x,coord[3].y)
                ctx.lineTo(coord[0].x,coord[0].y)
                ctx.stroke();
                ctx.closePath();
           }
    </script>
</body>
</html>

Link para o arquivo acima

5. Projeção Ortogonal Giro do eixo-z
Os raios de projeção se projetam perpendicularmente na tela, ou seja, a coordenada do ponto do objeto não tem nenhuma modificação no plano de projeção, apenas se ignora a coordenada z do ponto. No item 1.1. estão as explicações.
5.1. Criação do Objeto
É o mesmo objeto do item 4, apenas será acrescentado as transformações de translação do centro do canvas para a origem do sistema de coordenadas , a rotação e a translação de volta para a posição em que se encontrava, ou seja, no centro do canvas.

5.1. Translação do centro até a origem
A teoria encontra-se na apostila de Geometria Analítica. Para fazer uma rotação deve-se transladar a figura até a origem, nessa posição a origem do sitema de coordenadas coincide com a origem do sistema do objeto. O objeto pode rotacionar em torno de si mesmo.

            this.translate = function(tx,ty,tz) {
                return new Point3D(x + tx,y + ty,z + tz)
            }

Do centro para origem
Da  orgem para o centro
tx = -xc
ty = -yc
tx = -zc
tx = xc
ty = yc
tx = zc
xc, yc e zc já foram calculados no item 4.2, é o mesmo objeto.
Os valores são negativo para a translação do centro de coordenadas do objeto para o centro de coordenadas do canvas, e positivo na o caminho inverso.

5.2. Rotação: P' = P.R
A teoria encontra-se na apostila de Geometria Analítica.
Rotação(θ) em torno do eixo-z:
x = xcosθ-ysenθ
y = xsenθ+ycosθ
z = z
Gira apenas a face da frente.

Implementação:
            this.rotateZ = function(angle) {
                var rad, cosa, sina, x, y
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                x = this.x * cosa - this.y * sina
                y = this.x * sina + this.y * cosa
                return new Point3D(x, y, this.z)
            }

5. Código
Giro do eixo-z, gira apenas a face da frente.
<!DOCTYPE html>
<html>
<head>
    <title></title>

</head>
<body>
    <canvas id="c" width="200" height="200" style="border:1px solid #000000;">
      O seu browser não suporta o elemento canvas do HTML5.
      Por favor, actualize o seu browser.
    </canvas>

<button onclick="faz()">Ok</button>
   
    <script>
        function Point3D(x,y,z) {
          this.x = x;
          this.y = y;
          this.z = z;

            this.rotateZ = function(angle) {
                var rad, cosa, sina, x, y;
                rad = angle * Math.PI / 180;
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                x = this.x * cosa - this.y * sina;
                y = this.x * sina + this.y * cosa;
                return new Point3D(x, y, this.z);
            }

            this.translate = function(tx,ty,tz) {
                return new Point3D(x + tx,y + ty,z + tz)
            }
        }
       
     
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");

        ctx.scale(1,-1);
        ctx.translate(0, -200);



var xc = Math.ceil((200-1)/2);
var yc = Math.ceil((200-1)/2);
var zc = Math.ceil((200-1)/2);

var w = 100;
var h = 100;
var dp = 100;



var xo = (xc - w/2);
var yo = (yc - h/2);
var zo = (zc + dp/2);
var x1 = (xc + w/2);
var y1 = (yc - h/2);
var z1 = (zc + dp/2);
var x4 = (xc - w/2);
var y4 = (yc + h/2);
var z4 = (zc + dp/2);
var x5 = (xc + w/2);
var y5 = (yc + h/2);
var z5 = (zc + dp/2);


var coord = new Array();
coord.push(new Point3D(xo, yo, zo));
coord.push(new Point3D(x1, y1, z1));
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x4, y4, z4));
coord.push(new Point3D(xo, yo, zo));

var angle = 30;

function faz(){
           ctx.clearRect(0,0,200,200);
var t = new Array();

            for( var i = 0; i < coord.length; i++ ) {
                var r = coord[i].translate(-xc,-yc,-zc).rotateZ(angle).translate(xc,yc,zc);
                t.push(r);
            }
                
        angle = angle+10;
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(t[0].x,t[0].y);
               for( var i = 1; i < t.length; i++ ) {
                    ctx.lineTo(t[i].x,t[i].y);
                }


        ctx.stroke();
        ctx.closePath();
 }
    </script>
</body>
</html>

Link para o arquivo acima

5.1. Explicação da função faz()
function faz(){
           ctx.clearRect(0,0,200,200); // limpa o canvas para a nova execução da função
var t = new Array();
            for( var i = 0; i < coord.length; i++ ) {
               var r = coord[i].translate(-xc,-yc,-zc).rotateZ(angle).translate(xc,yc,zc); // transformações, cada elemento do ccord recebe a propriedade
               t.push(r); // monta-se um novo array com as transformações
            }
                
        angle = angle+10; // cada execução da função faz realiza um giro de 10º
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(t[0].x,t[0].y); // move o inicio do desenho para o primeiro elemento do array t[]
               for( var i = 1; i < t.length; i++ ) { // este loop constroem as linhas sequencialmente
                    ctx.lineTo(t[i].x,t[i].y);
                }
        ctx.stroke();
        ctx.closePath();
 }

6. Projeção Ortogonal Giro do eixo-x, eixo-y e eixo-z.
Este exercício tem o mesmo raciocínio do anterior, ascrecenta-se apenas as rotações dos eixos-x e eixo-y.
Também deve-se acrescentar as demais coordenadas da faces restante.
6.1. Rotação: P' = P.R
A teoria encontra-se na apostila de Geometria Analítica.
Rotação(θ) em torno do eixo-x:
x = x
y = y.cosθ - z.senθ
z = y.senθ + z.cosθ

Implementação:
            this.rotateX = function(angle) {
                var rad, cosa, sina, y, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                y = this.y * cosa - this.z * sina
                z = this.y * sina + this.z * cosa
                return new Point3D(this.x, y, z)
            }
 Rotação(θ) em torno do eixo-y:
x = x.cosθ+z.senθ
y = y
z = -x.senθ+z.cosθ

Implementação:
            this.rotateY = function(angle) {
                var rad, cosa, sina, x, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                z = this.z * cosa - this.x * sina
                x = this.z * sina + this.x * cosa
                return new Point3D(x,this.y, z)
            }
 Rotação em torno do eixo-z:

x = xcosθ-ysenθ
y = xsenθ+ycosθ
z = z

Implementação:
            this.rotateZ = function(angle) {
                var rad, cosa, sina, x, y
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                x = this.x * cosa - this.y * sina
                y = this.x * sina + this.y * cosa
                return new Point3D(x, y, this.z)
            }

6.2. Cálculos de todas coordenadas do objeto
É muito importante saber o que se esta fazendo. A demonstração encontra-se no item 4.

var xc = Math.ceil((200-1)/2);
var yc = Math.ceil((200-1)/2);
var zc = Math.ceil((200-1)/2);

var w = 100;
var h = 100;
var dp = 100;

var xo = (xc - w/2);
var yo = (yc - h/2);
var zo = (zc + dp/2);
var x1 = (xc + w/2);
var y1 = (yc - h/2);
var z1 = (zc + dp/2);
var x2 = (xc + w/2);
var y2 = (yc - h/2);
var z2 = (zc - dp/2);
var x3 = (xc - w/2);
var y3 = (yc - h/2);
var z3 = (zc - dp/2);
var x4 = (xc - w/2);
var y4 = (yc + h/2);
var z4 = (zc + dp/2);
var x5 = (xc + w/2);
var y5 = (yc + h/2);
var z5 = (zc + dp/2);
var x6 = (xc + w/2);
var y6 = (yc + h/2);
var z6 = (zc - dp/2);
var x7 = (xc - w/2);
var y7 = (yc + h/2);
var z7 = (zc - dp/2);


var coord = new Array();
//face0
coord.push(new Point3D(xo, yo, zo));
coord.push(new Point3D(x1, y1, z1));
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x4, y4, z4));
coord.push(new Point3D(xo, yo, zo));

//Faces1(1,5,4,0)
coord.push(new Point3D(x1, y1, z1));
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x4, y4, z4));
coord.push(new Point3D(xo, yo, zo));
coord.push(new Point3D(x1, y1, z1));

//face2 (2,6,5,1)
coord.push(new Point3D(x2, y2, z2));
coord.push(new Point3D(x6, y6, z6));
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x1, y1, z1));
coord.push(new Point3D(x2, y2, z2));

//face3 (3,2,6,7)
coord.push(new Point3D(x3, y3, z3));
coord.push(new Point3D(x2, y2, z2));
coord.push(new Point3D(x6, y6, z6));
coord.push(new Point3D(x6, y6, z6));
coord.push(new Point3D(x7, y7, z7));

//face4 (4,0,3,7) 
coord.push(new Point3D(x4, y4, z4));
coord.push(new Point3D(xo, yo, zo));
coord.push(new Point3D(x3, y3, z3));
coord.push(new Point3D(x7, y7, z7));
coord.push(new Point3D(x4, y4, z4));
//face5 (5,6,7,4)
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x6, y6, z6));
coord.push(new Point3D(x7, y7, z7));
coord.push(new Point3D(x4, y4, z4));
coord.push(new Point3D(x5, y5, z5));

6.3. Código
<!DOCTYPE html>
<html>
<head>
    <title></title>

</head>
<body>
    <canvas id="c" width="200" height="200" style="border:1px solid #000000;">
      O seu browser não suporta o elemento canvas do HTML5.
      Por favor, actualize o seu browser.
    </canvas>

<button onclick="faz()">Ok</button>
   
    <script>

        function Point3D(x,y,z) {
          this.x = x;
          this.y = y;
          this.z = z;

            this.rotateZ = function(angle) {
                var rad, cosa, sina, x, y;
                rad = angle * Math.PI / 180;
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                x = this.x * cosa - this.y * sina;
                y = this.x * sina + this.y * cosa;
                return new Point3D(x, y, this.z);
            }

            this.rotateX = function(angle) {
                var rad, cosa, sina, y, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                y = this.y * cosa - this.z * sina
                z = this.y * sina + this.z * cosa
                return new Point3D(this.x, y, z)
            }
 
            this.rotateY = function(angle) {
                var rad, cosa, sina, x, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                z = this.z * cosa - this.x * sina
                x = this.z * sina + this.x * cosa
                return new Point3D(x,this.y, z)
            }

            this.translate = function(tx,ty,tz) {
                return new Point3D(x + tx,y + ty,z + tz)
            }
        }
       
     
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");

        ctx.scale(1,-1);
        ctx.translate(0, -200);


var xc = Math.ceil((200-1)/2);
var yc = Math.ceil((200-1)/2);
var zc = Math.ceil((200-1)/2);

var w = 100;
var h = 100;
var dp = 100;

var xo = (xc - w/2);
var yo = (yc - h/2);
var zo = (zc + dp/2);
var x1 = (xc + w/2);
var y1 = (yc - h/2);
var z1 = (zc + dp/2);
var x2 = (xc + w/2);
var y2 = (yc - h/2);
var z2 = (zc - dp/2);
var x3 = (xc - w/2);
var y3 = (yc - h/2);
var z3 = (zc - dp/2);
var x4 = (xc - w/2);
var y4 = (yc + h/2);
var z4 = (zc + dp/2);
var x5 = (xc + w/2);
var y5 = (yc + h/2);
var z5 = (zc + dp/2);
var x6 = (xc + w/2);
var y6 = (yc + h/2);
var z6 = (zc - dp/2);
var x7 = (xc - w/2);
var y7 = (yc + h/2);
var z7 = (zc - dp/2);


var coord = new Array();
//face0
coord.push(new Point3D(xo, yo, zo));
coord.push(new Point3D(x1, y1, z1));
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x4, y4, z4));
coord.push(new Point3D(xo, yo, zo));

//Faces1(1,5,4,0)
coord.push(new Point3D(x1, y1, z1));
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x4, y4, z4));
coord.push(new Point3D(xo, yo, zo));
coord.push(new Point3D(x1, y1, z1));

//face2 (2,6,5,1)
coord.push(new Point3D(x2, y2, z2));
coord.push(new Point3D(x6, y6, z6));
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x1, y1, z1));
coord.push(new Point3D(x2, y2, z2));

//face3 (3,2,6,7)
coord.push(new Point3D(x3, y3, z3));
coord.push(new Point3D(x2, y2, z2));
coord.push(new Point3D(x6, y6, z6));
coord.push(new Point3D(x6, y6, z6));
coord.push(new Point3D(x7, y7, z7));

//face4 (4,0,3,7) 
coord.push(new Point3D(x4, y4, z4));
coord.push(new Point3D(xo, yo, zo));
coord.push(new Point3D(x3, y3, z3));
coord.push(new Point3D(x7, y7, z7));
coord.push(new Point3D(x4, y4, z4));
//face5 (5,6,7,4)
coord.push(new Point3D(x5, y5, z5));
coord.push(new Point3D(x6, y6, z6));
coord.push(new Point3D(x7, y7, z7));
coord.push(new Point3D(x4, y4, z4));
coord.push(new Point3D(x5, y5, z5));

var angle = 30;

function faz(){
           ctx.clearRect(0,0,200,200);
var t = new Array();

            for( var i = 0; i < coord.length; i++ ) {
                var r = coord[i].translate(-xc,-yc,-zc).rotateX(angle).rotateY(angle).rotateZ(angle).translate(xc,yc,zc);
                t.push(r);
            }
                
        angle = angle+10;
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(t[0].x,t[0].y);
               for( var i = 1; i < t.length; i++ ) {
                    ctx.lineTo(t[i].x,t[i].y);
                }


        ctx.stroke();
        ctx.closePath();
 }
    </script>
</body>
</html>

Link para o aquivo acima

6.4. Projeção Ortogobal com Faces
O último código a imagem foi criada com uma seqüência de coordenadas, o próximo código é criado usando uma matriz que contem os vértices do cubo.


<!DOCTYPE html>
<html>
<head>
    <title></title>

</head>
<body>
    <canvas id="c" width="200" height="200" style="border:1px solid #000000;">
      O seu browser não suporta o elemento canvas do HTML5.
      Por favor, actualize o seu browser.
    </canvas>

<button onclick="faz()">Ok</button>
   
    <script>
        function Point3D(x,y,z) {
          this.x = x;
          this.y = y;
          this.z = z;


            this.rotateZ = function(angle) {
                var rad, cosa, sina, x, y;
                rad = angle * Math.PI / 180;
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                x = this.x * cosa - this.y * sina;
                y = this.x * sina + this.y * cosa;
                return new Point3D(x, y, this.z);
            }

            this.rotateX = function(angle) {
                var rad, cosa, sina, y, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                y = this.y * cosa - this.z * sina;
                z = this.y * sina + this.z * cosa;
                return new Point3D(this.x, y, z);
            }
 
            this.rotateY = function(angle) {
                var rad, cosa, sina, x, z
                rad = angle * Math.PI / 180;
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                z = this.z * cosa - this.x * sina;
                x = this.z * sina + this.x * cosa;
                return new Point3D(x,this.y, z);
            }

            this.translate = function(tx,ty,tz) {
                return new Point3D(x + tx,y + ty,z + tz)
            }
                           
        }
             
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");

        ctx.scale(1,-1);
        ctx.translate(0, -200);

var xc = Math.ceil((200-1)/2);
var yc = Math.ceil((200-1)/2);
var zc = Math.ceil((200-1)/2);

var w = 100;
var h = 100;
var dp = 100;

var xo = (xc - w/2);
var yo = (yc - h/2);
var zo = (zc + dp/2);
var x1 = (xc + w/2);
var y1 = (yc - h/2);
var z1 = (zc + dp/2);
var x2 = (xc + w/2);
var y2 = (yc - h/2);
var z2 = (zc - dp/2);
var x3 = (xc - w/2);
var y3 = (yc - h/2);
var z3 = (zc - dp/2);
var x4 = (xc - w/2);
var y4 = (yc + h/2);
var z4 = (zc + dp/2);
var x5 = (xc + w/2);
var y5 = (yc + h/2);
var z5 = (zc + dp/2);
var x6 = (xc + w/2);
var y6 = (yc + h/2);
var z6 = (zc - dp/2);
var x7 = (xc - w/2);
var y7 = (yc + h/2);
var z7 = (zc - dp/2);


var vertices = new Array();

vertices.push(new Point3D(xo, yo, zo));
vertices.push(new Point3D(x1, y1, z1));
vertices.push(new Point3D(x2, y2, z2));
vertices.push(new Point3D(x3, y3, z3));
vertices.push(new Point3D(x4, y4, z4));
vertices.push(new Point3D(x5, y5, z5));
vertices.push(new Point3D(x6, y6, z6));
vertices.push(new Point3D(x7, y7, z7));

//face0(0,1,2,3) base
//Faces1(1,5,4,0)
//face2 (2,6,5,1)
//face3 (3,2,6,7)
//face4 (4,0,3,7)  
//face5 (5,6,7,4) topo

var angle = 30;

function faz(){
           ctx.clearRect(0,0,200,200);
var t = new Array();
        angle = angle+10;
            for( var i = 0; i < vertices.length; i++ ) {
                var r = vertices[i].translate(-xc,-yc,-zc).rotateX(angle).rotateY(angle).rotateZ(angle).translate(xc,yc,zc);
                t.push(r);
            }
            
var faces = new Array();
faces.push([t[0],t[1],t[2],t[3]]);
faces.push([t[1],t[5],t[4],t[0]]);
faces.push([t[2],t[6],t[5],t[1]]);
faces.push([t[3],t[2],t[6],t[7]]);
faces.push([t[4],t[0],t[3],t[7]]);
faces.push([t[5],t[6],t[7],t[4]]);          
                                       
        ctx.lineWidth = 2;
        ctx.beginPath();

               for( var i = 0; i < faces.length; i++ ) {
                    ctx.moveTo(faces[i][0].x,faces[i][0].y);
                    ctx.lineTo(faces[i][1].x,faces[i][1].y);
                    ctx.lineTo(faces[i][2].x,faces[i][2].y);
                    ctx.lineTo(faces[i][3].x,faces[i][3].y);
                    
                }
   
        ctx.stroke();
        ctx.closePath();            
 }
    </script>
</body>
</html>


Link para o aquivo acima

6.4.1. Estudo das Coordenadas
No item 6.4. foi visto a rotação de um cubo, o código anterior será modificado para possibilitar a visualização dos vértices. Para isso será feito as seguintes modificações no código:
1) retirada do métodos ctx.scale(1,-1) e ctx.translate(0, -200), porque afetam a visualização de texto, os vértices serão numerados. Com isso, a face da base passa para o topo e o topo para a base, isso porque foi dado dois giros de 90º no eixo-x do cubo, a coordenada-z é direcionada para dentro da tela e a coordenada-y é direcionada para baixo, ou seja, nesma disposição da tela do computados.
vértice 0(-1,-1,1)
vértice 1(1,-1,1)
vértice 2(1,-1,-1)
vértice 3(-1,-1,-1)
vértice 4(-1,1,1)
vértice 5(1,1,1)
vértice 6(1,1,-1)
vértice 7(-1,1,-1)
face de topo: (0,1,2,3), não importa a ordem do vétices na face, serão desenhado na ordem crescente do array faces.
face de base: (5,6,7,4).

Ao fazer o giro de 180º o cubo gira junto com os eixos, logo as coordenadas do ponto não mudam, a face de topo passa para face de base e a face de base passa para face de topo.
<!DOCTYPE html>
<html>
<head>
    <title></title>

</head>
<body>
    <canvas id="c" width="200" height="200" style="border:1px solid #000000;">
      O seu browser não suporta o elemento canvas do HTML5.
      Por favor, actualize o seu browser.
    </canvas>

<button onclick="faz()">Ok</button>
   
    <script>

        function Point3D(x,y,z) {
          this.x = x;
          this.y = y;
          this.z = z;


            this.rotateZ = function(angle) {
                var rad, cosa, sina, x, y;
                rad = angle * Math.PI / 180;
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                x = this.x * cosa - this.y * sina;
                y = this.x * sina + this.y * cosa;
                return new Point3D(x, y, this.z);
            }

            this.rotateX = function(angle) {
                var rad, cosa, sina, y, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                y = this.y * cosa - this.z * sina;
                z = this.y * sina + this.z * cosa;
                return new Point3D(this.x, y, z);
            }

 
            this.rotateY = function(angle) {
                var rad, cosa, sina, x, z
                rad = angle * Math.PI / 180;
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                z = this.z * cosa - this.x * sina;
                x = this.z * sina + this.x * cosa;
                return new Point3D(x,this.y, z);
            }


            this.translate = function(tx,ty,tz) {
                return new Point3D(x + tx,y + ty,z + tz)
            }
                    
        }
       
     
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");


var xc = Math.ceil((200-1)/2);
var yc = Math.ceil((200-1)/2);
var zc = Math.ceil((200-1)/2);

var w = 100;
var h = 100;
var dp = 100;


var xo = (xc - w/2);
var yo = (yc - h/2);
var zo = (zc + dp/2);
var x1 = (xc + w/2);
var y1 = (yc - h/2);
var z1 = (zc + dp/2);
var x2 = (xc + w/2);
var y2 = (yc - h/2);
var z2 = (zc - dp/2);
var x3 = (xc - w/2);
var y3 = (yc - h/2);
var z3 = (zc - dp/2);
var x4 = (xc - w/2);
var y4 = (yc + h/2);
var z4 = (zc + dp/2);
var x5 = (xc + w/2);
var y5 = (yc + h/2);
var z5 = (zc + dp/2);
var x6 = (xc + w/2);
var y6 = (yc + h/2);
var z6 = (zc - dp/2);
var x7 = (xc - w/2);
var y7 = (yc + h/2);
var z7 = (zc - dp/2);


var vertices = new Array();

vertices.push(new Point3D(xo, yo, zo));
vertices.push(new Point3D(x1, y1, z1));
vertices.push(new Point3D(x2, y2, z2));
vertices.push(new Point3D(x3, y3, z3));
vertices.push(new Point3D(x4, y4, z4));
vertices.push(new Point3D(x5, y5, z5));
vertices.push(new Point3D(x6, y6, z6));
vertices.push(new Point3D(x7, y7, z7));

var angle = 0;

function faz(){
           ctx.clearRect(0,0,200,200);
var t = new Array();
        angle = angle+2;
            for( var i = 0; i < vertices.length; i++ ) {
                var r = vertices[i].translate(-xc,-yc,-zc).rotateX(5).rotateY(angle).rotateZ(5).translate(xc,yc,zc);
                t.push(r);
            }
           
var faces = new Array();
faces.push([t[0],t[1],t[2],t[3]]);
faces.push([t[1],t[5],t[4],t[0]]);
faces.push([t[2],t[6],t[5],t[1]]);
faces.push([t[3],t[2],t[6],t[7]]);
faces.push([t[4],t[0],t[3],t[7]]);
faces.push([t[5],t[6],t[7],t[4]]);         
           
                           

        ctx.lineWidth = 2;


        ctx.beginPath();

      
                    // face 0
                    ctx.moveTo(faces[0][0].x,faces[0][0].y);
                    ctx.lineTo(faces[0][1].x,faces[0][1].y);
                    ctx.lineTo(faces[0][2].x,faces[0][2].y);
                    ctx.lineTo(faces[0][3].x,faces[0][3].y);

                   
                    //face 1
                    ctx.moveTo(faces[1][0].x,faces[1][0].y);
                    ctx.lineTo(faces[1][1].x,faces[1][1].y);
                    ctx.lineTo(faces[1][2].x,faces[1][2].y);
                    ctx.lineTo(faces[1][3].x,faces[1][3].y);
                   
                    // face 2
                    ctx.moveTo(faces[2][0].x,faces[2][0].y);
                    ctx.lineTo(faces[2][1].x,faces[2][1].y);
                    ctx.lineTo(faces[2][2].x,faces[2][2].y);
                    ctx.lineTo(faces[2][3].x,faces[2][3].y);
                    
                     //face 3
                    ctx.moveTo(faces[3][0].x,faces[3][0].y);
                    ctx.lineTo(faces[3][1].x,faces[3][1].y);
                    ctx.lineTo(faces[3][2].x,faces[3][2].y);
                    ctx.lineTo(faces[3][3].x,faces[3][3].y);
                    
                     //face 4
                    ctx.moveTo(faces[4][0].x,faces[4][0].y);
                    ctx.lineTo(faces[4][1].x,faces[4][1].y);
                    ctx.lineTo(faces[4][2].x,faces[4][2].y);
                    ctx.lineTo(faces[4][3].x,faces[4][3].y);
                    
                    
                     //face5
                    ctx.moveTo(faces[5][0].x,faces[5][0].y);
                    ctx.lineTo(faces[5][1].x,faces[5][1].y);
                    ctx.lineTo(faces[5][2].x,faces[5][2].y);
                    ctx.lineTo(faces[5][3].x,faces[5][3].y);
                   
               
                   
        ctx.stroke();
        ctx.closePath();

       
       
ctx.font      = "normal 18px Verdana";
ctx.fillStyle = "#000000";
//face 0, base
ctx.fillText("4", faces[5][0].x, faces[5][0].y);
ctx.fillText("5", faces[5][1].x, faces[5][1].y);
ctx.fillText("6", faces[5][2].x, faces[5][2].y);
ctx.fillText("7", faces[5][3].x, faces[5][3].y);

 //face 5, topo
ctx.fillText("0", faces[0][0].x, faces[0][0].y);
ctx.fillText("1", faces[0][1].x, faces[0][1].y);
ctx.fillText("2", faces[0][2].x, faces[0][2].y);
ctx.fillText("3", faces[0][3].x, faces[0][3].y);
                   
 }
    </script>
</body>
</html>

Link para o aquivo acima

As faces foram desenhadas uma a uma e depois acrescido a numeração de seus vértices.

        ctx.beginPath();  
                    // face 0
                    ctx.moveTo(faces[0][0].x,faces[0][0].y);
                    ctx.lineTo(faces[0][1].x,faces[0][1].y);
                    ctx.lineTo(faces[0][2].x,faces[0][2].y);
                    ctx.lineTo(faces[0][3].x,faces[0][3].y);

                   
                    //face 1
                    ctx.moveTo(faces[1][0].x,faces[1][0].y);
                    ctx.lineTo(faces[1][1].x,faces[1][1].y);
                    ctx.lineTo(faces[1][2].x,faces[1][2].y);
                    ctx.lineTo(faces[1][3].x,faces[1][3].y);
                   
                    // face 2
                    ctx.moveTo(faces[2][0].x,faces[2][0].y);
                    ctx.lineTo(faces[2][1].x,faces[2][1].y);
                    ctx.lineTo(faces[2][2].x,faces[2][2].y);
                    ctx.lineTo(faces[2][3].x,faces[2][3].y);
                    
                     //face 3
                    ctx.moveTo(faces[3][0].x,faces[3][0].y);
                    ctx.lineTo(faces[3][1].x,faces[3][1].y);
                    ctx.lineTo(faces[3][2].x,faces[3][2].y);
                    ctx.lineTo(faces[3][3].x,faces[3][3].y);
                    
                     //face 4
                    ctx.moveTo(faces[4][0].x,faces[4][0].y);
                    ctx.lineTo(faces[4][1].x,faces[4][1].y);
                    ctx.lineTo(faces[4][2].x,faces[4][2].y);
                    ctx.lineTo(faces[4][3].x,faces[4][3].y);
                    
                    
                     //face5
                    ctx.moveTo(faces[5][0].x,faces[5][0].y);
                    ctx.lineTo(faces[5][1].x,faces[5][1].y);
                    ctx.lineTo(faces[5][2].x,faces[5][2].y);
                    ctx.lineTo(faces[5][3].x,faces[5][3].y);                
        ctx.stroke();
        ctx.closePath();

 Numeração dos vértices           
ctx.font      = "normal 18px Verdana";
ctx.fillStyle = "#000000";
//face 0, base
ctx.fillText("4", faces[5][0].x, faces[5][0].y);
ctx.fillText("5", faces[5][1].x, faces[5][1].y);
ctx.fillText("6", faces[5][2].x, faces[5][2].y);
ctx.fillText("7", faces[5][3].x, faces[5][3].y);

 //face 5, topo
ctx.fillText("0", faces[0][0].x, faces[0][0].y);
ctx.fillText("1", faces[0][1].x, faces[0][1].y);
ctx.fillText("2", faces[0][2].x, faces[0][2].y);
ctx.fillText("3", faces[0][3].x, faces[0][3].y);
                   
7. Perspectiva
Antes de tudo deve-se lembrar que foi utilizado a regra da mão direito para o sistema de coordenada do objeto.
A projeção ortogonal não requereu qualquer transformação do objeto, a projeção perspectiva requer uma transformação das coordenadas x e y do objeto que são diretamente proporcional ao foco e inversamente proporcional a coordenada z do objeto do próprio objeto. As coordenadas de projeção xp e yp são obtidas das coordenadas x e y do objeto respectivamente como será demostrado logo abaixo.
Para a criação da perspertiva é só acrescentar ao código do item 6 a fórmula da perspectiva, pois o código anterior está projetando as coordenadas do objeto perpendicularmente a tela, ou seja, o seu tamanho real.
1.3. Perspectiva
O que foi visto na projeção ortogonal vale também para a projeção em perspectiva, ou seja, para o ponto P(x,y,z) no sistema de coordenadas do objeto quando tiver z mímino, o ponto de projeção P' terá, x' = x e y' = y, a medida que z vai aumentando x' e y' vai diminuindo.
Para criar uma imagem mais realista utiliza-se a projeção perspectiva que leva em consideração a coordenada z do ponto P(x,y,z) e os raios de projeção que não são perpendiculares ao plano de projeção. A coordenada z faz parte de uma razão, quanto maior z menor a projeção, ou seja, z está relacionado com a profundidade da imagem.

Repare na figura abaixo, onde o objeto (cubo), tem sistema de coordenadas do objeto livre, ele pode rotacionar livremente. O sistema de coordenada do observador tem a direção apontada para a origem do sistema de coordenadas do objeto. Para facilitar o entendimento foi padronizado o sistema de coordenadas da mão direita com o eixo-y direcionada para baixo, assim fica com a mesma disposição da tela do computado, não necessitando alterá-lo. O observador está localizado na orgem do sistema de coordenadas da tela do computador, logo ambos sistema de coordenadas se coincidem.

f: distância focal (>0)
d: distância da tela (>0)
xp=f .x/z
xp = f.x/z
yp/f = y/z
yp = f.y/z

Etapa 1: criação do objeto no sistema de coordenadas da não direito com o eixo-y voltado para baixo.
Etapa 2: centralização do objeto na tela do computador.
Etapa 2: translação do objeto a uma distância qualquer da tela de projeção, afastando-se do observador, esta distância é positiva. Se não for feito essa translação, a projeção perspectiva ficará distorsida.
Etapa 2: distância focal, é a distância do olho do observador até a tela de projeção. Esta distância é positiva.
Para a figura abaixo o ponto P(x,y,z) do objeto toma como referência o centro da câmera.
Não confundir o sistema de coordenadas da tela do computador, usada para criar o objeto, com o sitema de coordenadas do observador, que é apenas um posicionamento da câmera ou olho do observador.

Raciocínio:
- O foco é sempre positivo, não existe distância negativa nem comprimento negativo. O objeto foi criado e dever ser sempre criado tomando como base a coordenada da tela do computador que tem apenas o primeiro quadrante visível.
- Tela do Computado
Há uma certa redundância no termo tela do computador para não confundir com tela de projeção. O sistema de coordenadas do objeto e a tela de projeção são uma abstração, uma criação imaginária que tem como referência o sistema de coordenadas da tela do computador. O sistema de coordenadas do objeto e a tela de projeção servem como base para os cálculos.
Quando um objeto é transladado significa que seus pontos são transladados, como as coordenadas dos pontos estão guardadas em variáveis o que muda são apenas os sinais das coordenadas, por exemplo: um objeto é feito usando a coordenadas da tela do computador para ser exibido, a área visível é o primeiro quadrante desse sistema de coordenadas, um objeto transladado para outro quadrante não é visível, porém, continua a ser o mesmo objeto, porém, com coordenadas desse quadrante.
- Para facilitar a imaginação é melhor padronizar os sistemas de coordenadas semelhante ao sistema da tela do computador, isso para a projeção em perspectiva, assim facilitar a interpretação dos pontos na tela de projeção.
- Tenha em mente que a tela de projeção serve para os cálculos, a projeção será exibida na tela do computador.
Repare na figura abaixo:


A figura abaixo mostra os cálculos das projeções da tela, repare que o cálculo não muda com a disposição do eixo-y voltado para cima porque ao girar o sistema de coordenadas os pontos também giram.

Pp = T.P
Pp: ponto projetado (P')
T: matriz de translação de plano com centro de projeção na origem.
f: distância do foco.
f=this.z
xp/f = x/z
xp = f.x/z
yp/f = y/z
yp = f.y/z
zp = f
Pp = (f.x/z,f.y/z,f)
r = 1/f
Pp = [x/rz  y/rz  0  1]
Pp = .= [x/z  y/z  0 r]

xp = f.x/z
yp = f.y/z
7.1. Valores Padrões da Projeção em Perspectiva
Todos os código anteriores foi criado o objeto no centro da tela, para rotacioná-los tal objeto é transladato até a origem, é feito a rotação e depois é transladado de volta para o centro da tela.
Para a projeção em perspectiva o objeto deve ser transladado para a origem, deslocado a uma distância positiva no eixo-z, tal distância deve ser adequada, quanto mais afastado da tela do computador menor será a imagem projetada na tela de projeção.

O objeto em perspectiva padrão criado na raiz tem os seguintes valores:
viewWidth: largura do canvas.
viewHeight: altura do canvas.
fieldOfView: ângulo de visão.
- distância focal (f): varia de 18mm a 55mm (em câmera fotográfica)
  f= viewWidth/ 2 * ( cos(fieldOfView/2) / sin(fieldOfView/2) ) = 200/2*0.51 = 51
- field-of-view: 55º (tag55º = 1,42815)
- centro perspectiva: viewWidth/2, viewHeight/2
Observação:
tag 26º = 0,488
tag 27º = 0,510
tag 28º = 0,532
f: distãncia focal

f
= viewWidth/ 2 * ( cos(fieldOfView/2) / sin(fieldOfView/2) ) = 200/2*0,51 = 51.

Dados do Canvas
viewWidth = 200
viewHeight = 200
xc = Math.ceil((viewWidth-1)/2);
yc = Math.ceil((viewHeight-1)/2);

Rotina
this.project = function() {
                var fator, x, y, d;
                fator=100/this.z;
                x = this.x*fator;
                y = this.y*fator;
                return new Point3D(x, y, this.z);
            }              

vertices[i].translate(-xc,-yc,-zc).rotateX(angle).rotateY(10).rotateZ(10).translate(0,0,200).project().translate(0,0,-200).translate(xc,yc,zc);  
               

Observações:
- A escala dos eixos e a translação do eixo-x foram retiradas do código para facilitar a interpretação da imagem formada na tela de projeção.
 //ctx.scale(1,-1);
 //ctx.translate(0, -200);
- Não confundir tela do computador com tela de projeção. A tela do computador é uma tela física, a tela de projeção é uma tela teórica, imaginária.
- foco: igual a 100,  calculado de forma teórica e experimental, deve ser mudado conforme a aparência desejada e os testes realizados, corresponde a distância do centro de projeção a tela de projeção.
- Repare que a divisão foco/this.z terá de estar entre 0 e 1 para que as coordenadas x e y diminuam, que é o objetivo da perspectiva, quanto maior z, mais afastado da tela estará o ponto e assim ficará com coordenadas menores. O foco corresponde a distância entre o observador e a tela de projeção, que é diferente de tela do computador,  esta possui o sistema de coordenadas com origem no canto superior esquerdo, eixo-y para baixo e eixo-x para direita.
- translate(-xc,-yc,-zc): o objeto está no centro da tela do computador, para aplicar a perspectiva o objeto terá que ser transladado até  o centro do sistema de coordenadas da tela do computador.
- rotateX(angle).rotateY(10).rotateZ(10): aplica-se as rodações dejadas, sentido anti-horário.
- translate(0,0,200): translada o objeto sobre o eixo-z do sistema de coordenada da tela do computador para que o objeto fique a uma certa distância da tela de projeção, o centro de projeção, o olho do observador e a origem do sistema de coordenadas da tela coincidem.
* Se fizer a primeira translação no eixo-z negativo, ao aplicar a perspectiva e transladar de volta, o efeito será contrário, os pontos mais próximos terão coordenadas menores e os pontos mais longe coordenadas amores, e a rotação positiva será pela esquerda.
project(): aplicação da projeção.
- translate(0,0,-200): translação do objeto de volta para a origem do sistema de coordenadas da tela do computador.
- translate(xc,yc,zc): translação do objeto para o centro da tela do computador.


<!DOCTYPE html>
<html>
<head>
    <title></title>

</head>
<body>
    <canvas id="c" width="200" height="200" style="border:1px solid #000000;">
      O seu browser não suporta o elemento canvas do HTML5.
      Por favor, actualize o seu browser.
    </canvas>

<button onclick="faz()">Ok</button>
   

    <script>

 

        function Point3D(x,y,z) {
          this.x = x;
          this.y = y;
          this.z = z;
         
             //         this.scale = function() {
            //              fator=Math.abs(this.z);
         
            //    x = this.x * 60/fator;
           //     y = this.y * 60/fator;
               
            //    return new Point3D(x, y, this.z)
               
               
           // }
           
    


            this.rotateZ = function(angle) {
                var rad, cosa, sina, x, y;
                rad = angle * Math.PI / 180;
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                x = this.x * cosa - this.y * sina;
                y = this.x * sina + this.y * cosa;
                return new Point3D(x, y, this.z);
            }

            this.rotateX = function(angle) {
                var rad, cosa, sina, y, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                y = this.y * cosa - this.z * sina;
                z = this.y * sina + this.z * cosa;
                return new Point3D(this.x, y, z);
            }
 
            this.rotateY = function(angle) {
                var rad, cosa, sina, x, z
                rad = angle * Math.PI / 180;
                cosa = Math.cos(rad);
                sina = Math.sin(rad);
                z = this.z * cosa - this.x * sina;
                x = this.z * sina + this.x * cosa;
                return new Point3D(x,this.y, z);
            }


            this.translate = function(tx,ty,tz) {
                return new Point3D(x + tx,y + ty,z + tz)
            }
           
                this.project = function() {
                var fator, x, y, d;
                fator=100/this.z;

                x = this.x*fator;
                y = this.y*fator;
                return new Point3D(x, y, this.z);
            }              
        }
       
     
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");

 //       ctx.scale(1,-1);
 //       ctx.translate(0, -200);



var xc = Math.ceil((200-1)/2);
var yc = Math.ceil((200-1)/2);
var zc = Math.ceil((200-1)/2);

var w = 100;
var h = 100;
var dp = 100;


var xo = (xc - w/2);
var yo = (yc - h/2);
var zo = (zc + dp/2);
var x1 = (xc + w/2);
var y1 = (yc - h/2);
var z1 = (zc + dp/2);
var x2 = (xc + w/2);
var y2 = (yc - h/2);
var z2 = (zc - dp/2);
var x3 = (xc - w/2);
var y3 = (yc - h/2);
var z3 = (zc - dp/2);
var x4 = (xc - w/2);
var y4 = (yc + h/2);
var z4 = (zc + dp/2);
var x5 = (xc + w/2);
var y5 = (yc + h/2);
var z5 = (zc + dp/2);
var x6 = (xc + w/2);
var y6 = (yc + h/2);
var z6 = (zc - dp/2);
var x7 = (xc - w/2);
var y7 = (yc + h/2);
var z7 = (zc - dp/2);



var vertices = new Array();

vertices.push(new Point3D(xo, yo, zo));
vertices.push(new Point3D(x1, y1, z1));
vertices.push(new Point3D(x2, y2, z2));
vertices.push(new Point3D(x3, y3, z3));
vertices.push(new Point3D(x4, y4, z4));
vertices.push(new Point3D(x5, y5, z5));
vertices.push(new Point3D(x6, y6, z6));
vertices.push(new Point3D(x7, y7, z7));

//face0(0,1,2,3)
//Face1(1,5,4,0)
//face2 (2,6,5,1)
//face3 (3,2,6,7)
//face4 (4,0,3,7) 
//face5 (5,6,7,4)

var angle = 0;
var colors = [[255,0,0],[0,255,0],[0,0,255],[255,255,0],[0,255,255],[255,0,255]];

function faz(){
angle = angle+2;
           ctx.clearRect(0,0,200,200);
var t = new Array();

            for( var i = 0; i < vertices.length; i++ ) {
 
        var r = vertices[i].translate(-xc,-yc,-zc).rotateX(angle).rotateY(10).rotateZ(10).translate(0,0,200).project().translate(0,0,-200).translate(xc,yc,zc);  
                t.push(r);
            }
           
var faces = new Array();


faces.push([t[0],t[1],t[2],t[3]]);
faces.push([t[1],t[5],t[4],t[0]]);
faces.push([t[2],t[6],t[5],t[1]]);
faces.push([t[3],t[2],t[6],t[7]]);
faces.push([t[4],t[0],t[3],t[7]]);
faces.push([t[5],t[6],t[7],t[4]]); 

               

        ctx.lineWidth = 2;
        ctx.beginPath();

               for( var i = 0; i < faces.length; i++ ) {
                    ctx.fillStyle = "rgb(" +colors[i][0]+","+colors[i][1]+","+colors[i][2]+")";
                    ctx.moveTo(faces[i][0].x,faces[i][0].y);
                    ctx.lineTo(faces[i][1].x,faces[i][1].y);
                    ctx.lineTo(faces[i][2].x,faces[i][2].y);
                    ctx.lineTo(faces[i][3].x,faces[i][3].y);
                    ctx.fill();
                   
                }
               
               // face3 3-2-6-7
                    ctx.moveTo(faces[3][0].x,faces[3][0].y);
                    ctx.lineTo(faces[3][0].x,faces[3][0].y-100);

                    ctx.moveTo(faces[3][1].x,faces[3][1].y);
                    ctx.lineTo(faces[3][1].x,faces[3][1].y-100);
                   

        ctx.stroke();
        ctx.closePath();

 }
    </script>
</body>
</html>

Link para o aquivo acima
Observação:
- Giro no sentido anti-horário.
- Foram desenhado duas retas paralelas ao eixo-y tendo como origem o primeiro ponto (faces[3][0]) e o segundo ponto ([3][1]) da face 3, foi necessário apenas acrescentar o valor 100 na coordenada-y dos vétices. Repare na importancia da classificação dos vértices e da face, bem como se seus índices nos array para saber o que se está fazendo.
               // face3: 3-2-6-7
                    ctx.moveTo(faces[3][0].x,faces[3][0].y);
                    ctx.lineTo(faces[3][0].x,faces[3][0].y-100);

                    ctx.moveTo(faces[3][1].x,faces[3][1].y);
                    ctx.lineTo(faces[3][1].x,faces[3][1].y-100);

Código JavaScript de exemplo:
Exemplo de array de objetos.

ar canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d");

canvas.width = canvas.height = 256;

var shape = [{x:50,y:50}, {x:100, y:100}, {x:100, y:200}, {x:50,y:100}, {x:50, y:50}];
   
ctx.fillStyle = "red";
ctx.strokeStyle = "black";
ctx.lineWidth = 2;

function drawShape(shape, strokeIndex){
    ctx.beginPath();
    ctx.moveTo(shape[0].x, shape[0].y);
   
    for(var i = 1; i < shape.length; i++){
        ctx.lineTo(shape[i].x, shape[i].y);  
    }
    ctx.closePath();
    ctx.fill();
   
    // stroke
    ctx.beginPath();
    ctx.moveTo(shape[strokeIndex-1].x, shape[strokeIndex-1].y);
    ctx.lineTo(shape[strokeIndex].x, shape[strokeIndex].y);
    ctx.stroke();
}

drawShape(shape, 3);