JavaScript 3D - 2


O objetivo é ocultar as arestas que ficam atrás do cubo 3D, isso é conseguido facilmente ocultando o ponto que fica no fundo da tela, como foi padronizado o eixo-z positivo para dentro da tela, o ponto oculto é aquele que tem a maior coordenada-z. Para enxergar e compreender o que está acontecento é preciso estudar o ponto no espaço, por isso foi trantado alguns tópicos de geometria analítica.
Embora não tenha sido utilizado o Produto Vetorial, o Produto Escalar e a Direção de Vista do Observador para encontrar o ponto oculto, seus cálculos serão apresentados e também serão os mesmos desenhados no cubo para que possamos observar a dinâmica do que acontesse.

A descrição de um desenho mostra o seu significado ou entendimento. Além de enriquecer o conteúdo e dirime possíveis dúvidas de algum leitor.
Como desenhar em três dimensões com medidas reais em tela de monitor ou em um papel que possuem apenas duas dimensões?
A intenção não é apenas definir ponto, mas discutir essa definição, algo muito importante para o prosseguimento da matéria.
A projeção de um objeto real 3D na tela do monitor (2D) é feita com apenas a coordenada-x e a coordenada-y. A coordenada-z participa normalmente dos cálculos da transformação de pontos, mas não foi utilizada na projeção.

1. Ocultanto Arestas Traseiras
A técnica utilizada é simples, basta encontrar a maior coordenadas-z que esse ponto não terá as três coordenadas na parte de trás do cubo acarretando a não visualização das três faces que o interceptam.

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

<button onclick="faz()">Ok</button><br><br>
 
    <script>
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");
          
                  
        function Point3D(x,y,z) {
          this.x = x; //"this.x =x significa que a variável global x (this.x não declarada até então) é igual a variável interna x que é igual ao parâmtro x"
          this.y = y; //"o parâmtro x poderia ter outro nome, this.x refere se a variavel x com escopo igual onde a função esta inserida"
          this.z = z; //"this.x, this.y e this.z variáveis globais iguais aos parâmetros x, y e z da função Point3D"


            this.rotateZ = function(angle) {// giro do objeto no sentido anti-horario para os tres eixos
                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; //"x, y e z são novas variáveis internas da funcao  e this.x, this.y e this.z são as variáveis x, y e z globais"
                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, z, x;
                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 xc = Math.ceil((601-1)/2);
var yc = Math.ceil((601-1)/2);
var zc = Math.ceil((601-1)/2); //"importantissimo: zc no lado positivo do eixo z"


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));// vertice 0
vertices.push(new Point3D(x1, y1, z1));// vertice 1
vertices.push(new Point3D(x2, y2, z2));// vertice 2
vertices.push(new Point3D(x3, y3, z3));// vertice 3
vertices.push(new Point3D(x4, y4, z4));// vertice 4
vertices.push(new Point3D(x5, y5, z5));// vertice 5
vertices.push(new Point3D(x6, y6, z6));// vertice 6
vertices.push(new Point3D(x7, y7, z7));// vertice 7


var angle2 = -10;//"angulo de rotacao para teste, escolha uma valor compativel"
function faz(){
  
ctx.clearRect(0,0,600,600);
var t = new Array();
        angle2 = angle2+10;// "primeira execucao da funcao terá angle2=0"
        if(angle2==360){angle2=0;} // ao atingir 360 angle2 é igual a zero
            for( var i = 0; i < vertices.length; i++ ) {
                var r = vertices[i].translate(-xc,-yc,-zc).rotateX(angle2).rotateY(angle2).rotateZ(10).translate(xc,yc,zc);
                t.push(r);
              
            }

         
var faces = new Array();
faces.push([t[0],t[1],t[2],t[3]]);//face 0
faces.push([t[4],t[0],t[3],t[7]]);//face 1
faces.push([t[4],t[0],t[1],t[5]]);//face 2
faces.push([t[5],t[1],t[2],t[6]]);//face 3
faces.push([t[2],t[6],t[7],t[3]]);//face 4
faces.push([t[4],t[5],t[6],t[7]]);//face 5       

document.getElementById("ida").innerHTML=angle2;

zoculto=0;//importantissimo para o inicio da comparacao

  for(i=0;i<7;i=i+1){
     
       for(r=0;r<8;r=r+1){ 
      
          if(t[i].z<t[r].z){      if(t[r].z >zoculto){zoculto=t[r].z;a=r;}//"a é variável que guarda o valor  do índice do ponto oculto"
                                  xoculto= t[a].x;
                                  yoculto= t[a].y;
                                  document.getElementById("idzoculto").innerHTML=zoculto;
                                  document.getElementById("idxoculto").innerHTML=xoculto;
                                  document.getElementById("idyoculto").innerHTML=yoculto;
                                  document.getElementById("idr").innerHTML=a;
                                                      
            }//fecha o se

       }//fecha o for interno
     
 switch (a) {      
                                     case 0:
                                   
                                     ctx.beginPath();
                                     ctx.setLineDash([]);
                                     ctx.lineWidth = 2;
                                     ctx.strokeStyle="#000000";
                                     ctx.font = "normal 18px Verdana";                                                    
                                     ctx.moveTo(t[1].x,t[1].y); //face 0
                                     ctx.lineTo(t[2].x,t[2].y);
                                     ctx.lineTo(t[3].x,t[3].y);             
                           

                                     ctx.moveTo(t[4].x,t[4].y); //face 5
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                     ctx.lineTo(t[4].x,t[4].y);
                              
                            
                                     ctx.moveTo(t[3].x,t[3].y); //face1
                                     ctx.lineTo(t[7].x,t[7].y);
                                                  
                                     ctx.moveTo(t[1].x,t[1].y); //face3
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.moveTo(t[2].x,t[2].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                 
                                     ctx.stroke();
                                     ctx.closePath();
                                     break;
                                                  
                                                  
                                     case 1:
                                     ctx.beginPath();
                                     ctx.setLineDash([]);
                                     ctx.lineWidth = 2;
                                     ctx.strokeStyle="#000000";
                                     ctx.font = "normal 18px Verdana";                                                    
                                     ctx.moveTo(t[2].x,t[2].y); //face 0
                                     ctx.lineTo(t[3].x,t[3].y);
                                     ctx.lineTo(t[0].x,t[0].y);             
                                               
                                     ctx.moveTo(t[4].x,t[4].y); //face 5
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                     ctx.lineTo(t[4].x,t[4].y);
                                                  
                                     ctx.moveTo(t[0].x,t[0].y); //face 1
                                     ctx.lineTo(t[4].x,t[4].y);
                                     ctx.moveTo(t[3].x,t[3].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                                  
                                     ctx.moveTo(t[2].x,t[2].y); //face3
                                     ctx.lineTo(t[6].x,t[6].y);

                                    
                                     ctx.stroke();
                                     ctx.closePath();
                                     break;                                       
                                                  
                                     case 2:
                                                  
                                     ctx.beginPath();
                                     ctx.setLineDash([]);
                                     ctx.lineWidth = 2;
                                     ctx.strokeStyle="#000000";
                                     ctx.font = "normal 18px Verdana";                                                    
                                     ctx.moveTo(t[0].x,t[0].y); //face 0
                                     ctx.lineTo(t[1].x,t[1].y);
                                     ctx.moveTo(t[0].x,t[0].y);
                                     ctx.lineTo(t[3].x,t[3].y);

                                     ctx.moveTo(t[4].x,t[4].y); //face 5
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                     ctx.lineTo(t[4].x,t[4].y);
                                                  
                                     ctx.moveTo(t[0].x,t[0].y); //face 1
                                     ctx.lineTo(t[4].x,t[4].y);
                                     ctx.moveTo(t[3].x,t[3].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                                  
                                     ctx.moveTo(t[1].x,t[1].y); //face3
                                     ctx.lineTo(t[5].x,t[5].y);                                  
                                     ctx.stroke();
                                     ctx.closePath();
                                     break;
        
                                    case 3:
                                    ctx.beginPath();
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                    ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                               
                                    ctx.moveTo(t[4].x,t[4].y); //face 5
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.lineTo(t[6].x,t[6].y);
                                    ctx.lineTo(t[7].x,t[7].y);
                                    ctx.lineTo(t[4].x,t[4].y);

                                    ctx.moveTo(t[0].x,t[0].y); //face 1
                                    ctx.lineTo(t[4].x,t[4].y);

                                    ctx.moveTo(t[1].x,t[1].y); //face3
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.moveTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[6].x,t[6].y);
                                                                    
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
                                                  
                                    case 4:
                                    ctx.beginPath();                                   
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                     ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[0].x,t[0].y);
                                    ctx.moveTo(t[5].x,t[5].y); //face 5
                                    ctx.lineTo(t[6].x,t[6].y);
                                    ctx.lineTo(t[7].x,t[7].y);

                                    ctx.moveTo(t[3].x,t[3].y); //face 1
                                    ctx.lineTo(t[7].x,t[7].y);
                  
                                    ctx.moveTo(t[1].x,t[1].y); //face3
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.moveTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[6].x,t[6].y);
                                    
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
                                  
                                    case 5:
                                    ctx.beginPath();
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                    ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[0].x,t[0].y);
               

                                    ctx.moveTo(t[6].x,t[6].y); //face 5
                                    ctx.lineTo(t[7].x,t[7].y);
                                    ctx.lineTo(t[4].x,t[4].y);
                  
                                    ctx.moveTo(t[0].x,t[0].y); //face 1
                                    ctx.lineTo(t[4].x,t[4].y);
                                    ctx.moveTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[7].x,t[7].y);
                  
                                    ctx.moveTo(t[2].x,t[2].y);// face 3
                                    ctx.lineTo(t[6].x,t[6].y);
                                    
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
                                  
                                    case 6:                                                
                                    ctx.beginPath();
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                    ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[0].x,t[0].y);
               
                                    ctx.moveTo(t[7].x,t[7].y); //face 5
                                    ctx.lineTo(t[4].x,t[4].y);
                                    ctx.lineTo(t[5].x,t[5].y);
 
                                    ctx.moveTo(t[0].x,t[0].y); //face 1
                                    ctx.lineTo(t[4].x,t[4].y);
                                    ctx.moveTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[7].x,t[7].y);
                  
                                    ctx.moveTo(t[1].x,t[1].y); //face3
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
      
                                    case 7:           
                                    ctx.beginPath();
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                    ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[0].x,t[0].y);
               

                                    ctx.moveTo(t[4].x,t[4].y); //face 5
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.lineTo(t[6].x,t[6].y);
 
                                    ctx.moveTo(t[0].x,t[0].y); //face 1
                                    ctx.lineTo(t[4].x,t[4].y);
 
                                    ctx.moveTo(t[1].x,t[1].y); //face3
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.moveTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[6].x,t[6].y);   
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
                                   }//"fecha o caso ou switch"                       
                                  
   
    }//fecha o for externo

ctx.fillText("0", t[0].x, t[0].y); //"escrita do pontos nos vertices"
ctx.fillText("1", t[1].x, t[1].y);
ctx.fillText("2", t[2].x, t[2].y);
ctx.fillText("3", t[3].x, t[3].y);

ctx.fillText("4", t[4].x, t[4].y);
ctx.fillText("5", t[5].x, t[5].y);
ctx.fillText("6", t[6].x, t[6].y);
ctx.fillText("7", t[7].x, t[7].y);

Po="xo="+t[0].x.toFixed(4)+"   yo="+ t[0].y.toFixed(4)+"   zo="+t[0].z.toFixed(4); //"posição dos pontos"
P1="x1="+t[1].x.toFixed(4)+"   y1="+ t[1].y.toFixed(4)+"   z1="+t[1].z.toFixed(4);
P2="x2="+t[2].x.toFixed(4)+"   y2="+ t[2].y.toFixed(4)+"   z2="+t[2].z.toFixed(4);
P3="x3="+t[3].x.toFixed(4)+"   y3="+ t[3].y.toFixed(4)+"   z3="+t[3].z.toFixed(4);
P4="x4="+t[4].x.toFixed(4)+"   y4="+ t[4].y.toFixed(4)+"   z4="+t[4].z.toFixed(4);
P5="x5="+t[5].x.toFixed(4)+"   y5="+ t[5].y.toFixed(4)+"   z4="+t[5].z.toFixed(4);
P6="x6="+t[6].x.toFixed(4)+"   y6="+ t[6].y.toFixed(4)+"   z6="+t[6].z.toFixed(4);
P7="x7="+t[7].x.toFixed(4)+"   y7="+ t[7].y.toFixed(4)+"   z7="+t[7].z.toFixed(4);

ctx.fillText("Po=>"+Po,10,400);
ctx.fillText("P1=>"+P1,10,415);
ctx.fillText("P2=>"+P2,10,430);
ctx.fillText("P3=>"+P3,10,445);
ctx.fillText("P4=>"+P4,10,460);
ctx.fillText("P5=>"+P5,10,475);
ctx.fillText("P6=>"+P6,10,490);
ctx.fillText("P7=>"+P7,10,505);
}// fecha a funcao faz        
</script>


rotação =<span id="ida"></span>º<br>
<br>
Ponto oculto = <span id="idr"></span><br>
Coordenada-Z maior: Zmaior = <span id="idzoculto"></span><br>
Coordenada-X  = <span id="idxoculto"></span><br>
Coordenada-Y  = <span id="idyoculto"></span><br>

</body>
</html>



Link para execução do código acima

Observações:
1) O cubo foi padronizado com o sistema de coordenadas com eixo-y para baixo e eixo-z para dentro da tela.
2) O cubo foi criado com os pontos 0, 1, 2 e 3 formando a base e os pontos 4, 5, 6 e 7 formando o topo. Foram acrescentados as arestas entre os pontos 0 e 4, 1 e 5, 2 e 6, 3 e 7.


Há duas formas para as coordenadas dos pontos Po, P1, P2, P3, P4, P5, P6 e P7:
Po = (Pox,Poy)
Pox = faces[0][0].x e Poy = faces[0][0].x
ou
Pox = t[0].x e Poy = t[0].y

O código abaixo desenha o cubo com todas as arestas, inclusive as ocultas:
Repare que foi construido primeiro a base e o topo com oito pontos, as laterais são ligações entre os pontos da base e do topo.

ctx.beginPath();
ctx.setLineDash([]);
ctx.lineWidth = 2;
ctx.strokeStyle="#000000";
ctx.font = "normal 18px Verdana";   
                                               
ctx.moveTo(t[0].x,t[0].y); //face 0: base
ctx.lineTo(t[1].x,t[1].y);
ctx.lineTo(t[2].x,t[2].y);  
ctx.lineTo(t[3].x,t[3].y);
ctx.lineTo(t[0].x,t[0].y);           
                          

ctx.moveTo(t[4].x,t[4].y); //face 5: topo
ctx.lineTo(t[5].x,t[5].y);
ctx.lineTo(t[6].x,t[6].y);
ctx.lineTo(t[7].x,t[7].y);
ctx.lineTo(t[4].x,t[4].y);                            
                           
ctx.moveTo(t[3].x,t[3].y); //face1
ctx.lineTo(t[7].x,t[7].y);
ctx.moveTo(t[0].x,t[0].y);
ctx.lineTo(t[4].x,t[4].y);
                                                 
ctx.moveTo(t[1].x,t[1].y); //face3
ctx.lineTo(t[5].x,t[5].y);
ctx.moveTo(t[2].x,t[2].y);
ctx.lineTo(t[6].x,t[6].y);
                
ctx.stroke();
ctx.closePath();

1.1. Implementação do Código para Ocultar o Ponto Traseiro e suas Arestas
A lógica consiste em fazer dois looping (for)  para comparar as sete coordenadas-z, o segundo for é interno ao primeiro for, cada coordenada-z é comparada com as demais. O primeiro for pega cada coordenada-z e o segundo for percorrer todas as coordenadas para cada ciclo do primeiro for.
Cada rotação do cubo é pego a maior coordenada-z que corresponderá ao ponto oculto.

Com o ponto oculto achado o cubo será criado sem esse ponto. Será utilizado o comando switch para desenhar o cubo sem o ponto oculto.

angle2=angle2 - 10;
if(angle2==360){angle2=0;}// esta condição zera a variável angle2

zoculto=0;//importantissimo para o funcionamento, após um ciclo de comparação (primeiro for) a variável zoculto inicia com valor zero, ou seja, a cada execução da função faz() o zoculto inicia igual a 0 (zero).
//o primeiro for pega cada ponto e compara com todos os pontos usando o segundo for
  for(i=0;i<7;i=i+1){
       for(r=0;r<8;r=r+1){  
//se ponto anterior menor que o seguinte, e se o ponto seguinte maior que zmaior, zmaior igual ao ponto seguinte.      
          if(t[i].z<t[r].z){      if(t[r].z >zoculto){zoculto=t[r].z;a=r;} // "a é variável que guarda o valor  do índice do ponto oculto"
                                  xoculto= t[a].x;
                                  yoculto= t[a].y;
                                  document.getElementById("idzoculto").innerHTML=zoculto;
                                  document.getElementById("idxoculto").innerHTML=xoculto;
                                  document.getElementById("idr").innerHTML=a;
                                                       
            }//fecha o se

       }//fecha o for interno
      
                                         switch (a) {
                                                    case 0:
                                            
                                                    break;
                                                    case 1:
                                                  
                                                    break;
                                                    case 2:
                                                
                                                    break;
                                                    case 3:
                                                 
                                                    break;
                                                    case 4:
                                                 
                                                    break;
                                                    case 5:
                                                 
                                                    break;
                                                    case 6:
                                                  
                                                    break;
                                                    case 7:
                                                  
                                                    break;
                                                    }
                                                                                       
    
    
    }//fecha o for externo

O primeiro case desenhará o cubo sem as arestas que utilizam o vértice 0 (zero), ou seja, sem as arestas 0 - 1, 0 - 3 e 0 - 4, aplica-se o mesmo raciocínio para dos demais case (1, 2, 3, 4, 5, 6 e 7). Cada case é o índice do respectivo ponto, exemplo, case 1 corresponde ao ponto P1 = (t[1].x, t[1].y), utilize a figura do cubo acima para confirmação.

                                     case 0:
                                     ctx.beginPath();
                                     ctx.setLineDash([]);
                                     ctx.lineWidth = 2;
                                     ctx.strokeStyle="#000000";
                                     ctx.font = "normal 18px Verdana";                                                    
                                     ctx.moveTo(t[1].x,t[1].y); //face 0
                                     ctx.lineTo(t[2].x,t[2].y);
                                     ctx.lineTo(t[3].x,t[3].y);             
                           

                                     ctx.moveTo(t[4].x,t[4].y); //face 5
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                     ctx.lineTo(t[4].x,t[4].y);
                              
                            
                                     ctx.moveTo(t[3].x,t[3].y); //face1
                                     ctx.lineTo(t[7].x,t[7].y);
                                                  
                                     ctx.moveTo(t[1].x,t[1].y); //face3
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.moveTo(t[2].x,t[2].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                 
                                     ctx.stroke();
                                     ctx.closePath();
                                     break;

A cada rotação do angulo angle2, os pontos motificam o seu posicionamento e será desenhado um novo cubo conforme o ponto de maior coordenada-z. Esse ponto corresponderá ao único case que fará o desenho do cubo.
1.2. Implementação do Código para Teste ou Visualização do Resultado
A instrução abaixo colocar (posiciona no canvas) a letra 0 (zero) no vértice 0 (zero), o mesmo foi feito para os demais vértices. Isto ajuda nos testes do código.
ctx.fillText("0", t[0].x, t[0].y); //"escrita do pontos nos vertices"
Idem para os demais vértices ...

A instrução abaixo escreve as coordenadas do vértice 0 (zero), o mesmo foi feito para os demais vértices. Isto ajuda nos testes do código:
Po="xo="+t[0].x.toFixed(4)+"   yo="+ t[0].y.toFixed(4)+"   zo="+t[0].z.toFixed(4); //"posição dos pontos"
Idem para os demais vértices ...

A instrução abaixo coloca (posiciona no canvas) as coordenadas do vértice 0 (zero), o mesmo foi feito para os demais vértices. Isto ajuda nos testes do código:
ctx.fillText("Po=>"+Po,10,400);
Idem para os demais vértices ...


2. Outra Técnica
O próximo código é uma modificação do anterior, a técnica consistem em desenhar primeiro o cubo com todas as arestas e depois redesenhar as aresta ocultas com a mesma cor de fundo da tela (branco). O erro é que as arestas brancas sempre se sobrepõe porque foram desenhadas por último, talvez o uso de inde-z resolva o problema.
Cada case correspondente ao respectivo ponto oculto que possui a variável a1 que guarda os índices correspondentes aos pontos ocultos. Por exemplo. o case 0: corresponde ao a = 0 (ponto 0) e ao a1 = [3,1,4] (pontos 3, 1 e 4 que formam as arestas ocultas). Prossegue da mesma forma para os demais pontos.

zoculto=0;//importantissimo para o funcionamento do código
var a=0;//importantíssimo para o funcionamento do código
  for(i=0;i<7;i=i+1){ //percorre os pontos de 0 a 6
      
       for(r=0;r<8;r=r+1){ percorre os pontos de 0 a 7
       
          if(t[i].z<t[r].z){      if(t[r].z >zoculto){zoculto=t[r].z;a=r;} //compara o primeiro ponto com todos os pontos, depois o segundo ponto com todos os pontos, assim sucessivamente até a comparação do penultimo ponto com todos os pontos.
                                  xoculto= t[a].x;
                                  yoculto= t[a].y;
                                  document.getElementById("idzoculto").innerHTML=zoculto;
                                  document.getElementById("idxoculto").innerHTML=xoculto;
                                  document.getElementById("idyoculto").innerHTML=yoculto;
                                  document.getElementById("idr").innerHTML=a;
                                                       
            }//fecha o se

       }//fecha o for interno
      
                                         switch (a) {
                                                    case 0:
                                                    a1=[3,1,4];
                                                    break;
                                                    case 1:
                                                    a1=[0,2,5];
                                                    break;
                                                    case 2:
                                                    a1=[1,3,6];
                                                    break;
                                                    case 3:
                                                    a1=[2,0,7];
                                                    break;
                                                    case 4:
                                                    a1=[7,5,0];
                                                    break;
                                                    case 5:
                                                    a1=[4,6,1];
                                                    break;
                                                    case 6:
                                                    a1=[5,7,2];
                                                    break;
                                                    case 7:
                                                    a1=[6,4,3];
                                                    break;
                                                    }
                                                                                       
                                    ctx.beginPath();
                                    ctx.strokeStyle="#FFFFFF"; // cor branca
                                    ctx.lineWidth = 2;
                                    ctx.moveTo(t[a].x,t[a].y);
                                    ctx.lineTo(t[a1[0]].x,t[a1[0]].y);
                                    ctx.moveTo(t[a].x,t[a].y);
                                    ctx.lineTo(t[a1[1]].x,t[a1[1]].y);
                                    ctx.moveTo(t[a].x,t[a].y);
                                    ctx.lineTo(t[a1[2]].x,t[a1[2]].y);
                                    ctx.stroke();
                                    ctx.closePath();      
    
    }//fecha o for externo
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
    <canvas id="c" width="601" height="601" style="border:1px solid #000000;">
      O seu browser não suporta o elemento canvas do HTML5.
      Por favor, actualize o seu browser.
    </canvas><br>

<button onclick="faz()">Ok</button><br>
  
    <script>
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");
           
                   
        function Point3D(x,y,z) {
          this.x = x; //"this.x =x significa que a variável global x (não declarada até então) é igual ao "
          this.y = y; //parametro x, o parâmtro x poderia ter outro nome
          this.z = z;


            this.rotateZ = function(angle) {// giro do objeto no sentido anti-horario para os tres eixos
                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; //"x é uma nova variável interna e this.x é a variável x global"
                y = this.x*sina+this.y*cosa;
                return new Point3D(x, y,this.z); // entrada de novos parametros, em vez de this.z poderia ser
            }                                    //"apenas z (this.z = z), mas this.z se refere a variável  global 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, z, x;
                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 xc = Math.ceil((601-1)/2);
var yc = Math.ceil((601-1)/2);
var zc = Math.ceil((601-1)/2); //"zc no lado positivo do eixo z"


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));// vertice 0
vertices.push(new Point3D(x1, y1, z1));// vertice 1
vertices.push(new Point3D(x2, y2, z2));// vertice 2
vertices.push(new Point3D(x3, y3, z3));// vertice 3
vertices.push(new Point3D(x4, y4, z4));// vertice 4
vertices.push(new Point3D(x5, y5, z5));// vertice 5
vertices.push(new Point3D(x6, y6, z6));// vertice 6
vertices.push(new Point3D(x7, y7, z7));// vertice 7


var angle2 = -10;
function faz(){ 
   
ctx.clearRect(0,0,600,600);
var t = new Array();
        angle2 = angle2+10;
        if(angle2==360){angle2=0;}
            for( var i = 0; i < vertices.length; i++ ) {
                var r = vertices[i].translate(-xc,-yc,-zc).rotateX(30).rotateY(angle2).rotateZ(angle2).translate(xc,yc,zc);
                t.push(r);
               
            }

          
var faces = new Array();
faces.push([t[0],t[1],t[2],t[3]]);//face 0
faces.push([t[4],t[0],t[3],t[7]]);//face 1
faces.push([t[4],t[0],t[1],t[5]]);//face 2
faces.push([t[5],t[1],t[2],t[6]]);//face 3
faces.push([t[2],t[6],t[7],t[3]]);//face 4
faces.push([t[4],t[5],t[6],t[7]]);//face 5        


ctx.beginPath(); desenho do cubo com todas as arestas
ctx.setLineDash([]);
ctx.lineWidth = 2;
ctx.strokeStyle="#000000";
ctx.font = "normal 18px Verdana";  
                                              
ctx.moveTo(t[0].x,t[0].y); //face 0: base
ctx.lineTo(t[1].x,t[1].y);
ctx.lineTo(t[2].x,t[2].y); 
ctx.lineTo(t[3].x,t[3].y);
ctx.lineTo(t[0].x,t[0].y);          
                         

ctx.moveTo(t[4].x,t[4].y); //face 5: topo
ctx.lineTo(t[5].x,t[5].y);
ctx.lineTo(t[6].x,t[6].y);
ctx.lineTo(t[7].x,t[7].y);
ctx.lineTo(t[4].x,t[4].y);                           
                          
ctx.moveTo(t[3].x,t[3].y); //face1
ctx.lineTo(t[7].x,t[7].y);
ctx.moveTo(t[0].x,t[0].y);
ctx.lineTo(t[4].x,t[4].y);
                                                
ctx.moveTo(t[1].x,t[1].y); //face3
ctx.lineTo(t[5].x,t[5].y);
ctx.moveTo(t[2].x,t[2].y);
ctx.lineTo(t[6].x,t[6].y);
               
ctx.stroke();
ctx.closePath();
       
zoculto=0;//importantissimo
var a=0;//importantíssimo
  for(i=0;i<7;i=i+1){
      
       for(r=0;r<8;r=r+1){  
       
          if(t[i].z<t[r].z){      if(t[r].z >zoculto){zoculto=t[r].z;a=r;}
                                  xoculto= t[a].x;
                                  yoculto= t[a].y;
                                  document.getElementById("idzoculto").innerHTML=zoculto;
                                  document.getElementById("idxoculto").innerHTML=xoculto;
                                  document.getElementById("idyoculto").innerHTML=yoculto;
                                  document.getElementById("idr").innerHTML=a;
                                                       
            }//fecha o se

       }//fecha o for interno
      
                                         switch (a) {
                                                    case 0:
                                                    a1=[3,1,4];
                                                    break;
                                                    case 1:
                                                    a1=[0,2,5];
                                                    break;
                                                    case 2:
                                                    a1=[1,3,6];
                                                    break;
                                                    case 3:
                                                    a1=[2,0,7];
                                                    break;
                                                    case 4:
                                                    a1=[7,5,0];
                                                    break;
                                                    case 5:
                                                    a1=[4,6,1];
                                                    break;
                                                    case 6:
                                                    a1=[5,7,2];
                                                    break;
                                                    case 7:
                                                    a1=[6,4,3];
                                                    break;
                                                    }
                                                                                       
                                    ctx.beginPath();
                                    ctx.strokeStyle="#FFFFFF"; //cor branca
                                    ctx.lineWidth = 2;
                                    ctx.moveTo(t[a].x,t[a].y);
                                    ctx.lineTo(t[a1[0]].x,t[a1[0]].y);
                                    ctx.moveTo(t[a].x,t[a].y);
                                    ctx.lineTo(t[a1[1]].x,t[a1[1]].y);
                                    ctx.moveTo(t[a].x,t[a].y);
                                    ctx.lineTo(t[a1[2]].x,t[a1[2]].y);
                                    ctx.stroke();
                                    ctx.closePath();      
    
    }//fecha o for externo

ctx.fillText("0", t[0].x, t[0].y); //"escrita do pontos nos vertices"
ctx.fillText("1", t[1].x, t[1].y);
ctx.fillText("2", t[2].x, t[2].y);
ctx.fillText("3", t[3].x, t[3].y);

ctx.fillText("4", t[4].x, t[4].y);
ctx.fillText("5", t[5].x, t[5].y);
ctx.fillText("6", t[6].x, t[6].y);
ctx.fillText("7", t[7].x, t[7].y);

Po="xo="+t[0].x.toFixed(4)+"   yo="+ t[0].y.toFixed(4)+"   zo="+t[0].z.toFixed(4); //"posição dos pontos"
P1="x1="+t[1].x.toFixed(4)+"   y1="+ t[1].y.toFixed(4)+"   z1="+t[1].z.toFixed(4);
P2="x2="+t[2].x.toFixed(4)+"   y2="+ t[2].y.toFixed(4)+"   z2="+t[2].z.toFixed(4);
P3="x3="+t[3].x.toFixed(4)+"   y3="+ t[3].y.toFixed(4)+"   z3="+t[3].z.toFixed(4);
P4="x4="+t[4].x.toFixed(4)+"   y4="+ t[4].y.toFixed(4)+"   z4="+t[4].z.toFixed(4);
P5="x5="+t[5].x.toFixed(4)+"   y5="+ t[5].y.toFixed(4)+"   z4="+t[5].z.toFixed(4);
P6="x6="+t[6].x.toFixed(4)+"   y6="+ t[6].y.toFixed(4)+"   z6="+t[6].z.toFixed(4);
P7="x7="+t[7].x.toFixed(4)+"   y7="+ t[7].y.toFixed(4)+"   z7="+t[7].z.toFixed(4);

ctx.fillText("Po=>"+Po,10,400);
ctx.fillText("P1=>"+P1,10,415);
ctx.fillText("P2=>"+P2,10,430);
ctx.fillText("P3=>"+P3,10,445);
ctx.fillText("P4=>"+P4,10,460);
ctx.fillText("P5=>"+P5,10,475);
ctx.fillText("P6=>"+P6,10,490);
ctx.fillText("P7=>"+P7,10,505);

document.getElementById("ida").innerHTML=angle2;


}// fecha a funcao faz         
</script>

rotação =<span id="ida"></span>º<br>
<br>
Ponto oculto = <span id="idr"></span><br>
Coordenada-Z maior: Zmaior = <span id="idzoculto"></span><br>
Coordenada-X  = <span id="idxoculto"></span><br>
Coordenada-Y  = <span id="idyoculto"></span><br>

</body>
</html>



Link para execução do código acima
Obs: O erro é que as arestas brancas sempre se sobrepõe porque foram desenhadas por último, talvez o uso de inde-z resolva o problema.

3. Produto Escalar, Produto vetorial e Direção de Visualização
O objetivo deste item é calcular o produto vetorial e o produto escalar e plotar (desenhar) o produto vetorial afim de dominar, controlar e entender a dinâmica da rotação de pontos na tela do monitor. Os vértices ocultos podem ser  localizados através do produto vetorial entre duas arestas e o ângulo entre o produto vetorial (entre as duss arestas) e a direção de visualização do observador, porém, não fará parte deste trabalho por motivo de tempo para implementação que até nesta etapa já é considerável.
  
Testar o código significa confirmar a teoria através da demonstração prática, vamos aprender a calcular o produto vetorial e o produto escalar e desenhar o produto escalar  com a finalidade de dominar essa técnica tão útil Para localização do ponto no espaço.

3.1. Ponto
Grandeza escalar: é aquela caracterizada por um número e sua unidade, exemplos: 2 kg de massa, 10 metros de comprimento e 8 km² de área.
Grandeza vetorial: necessidade de uma direção, uma intensidade ou módulo e um sentido para sua determinação, exemplos: força, velocidade.
Vetor é a diferença entre dois pontos (extremidade menos origem), é um segmento de reta orientado, possui módulo, direção e sentido.
Ponto: em termos práticos é a localização de uma região através de suas coordenadas, não possui módulo, difereção ou sentido.

Seja A(ax,ay) e  B(bx,by) dois pontos no primeiro quadrante do sistema cartesiano, então: B - A = AB e B = AB + A
Obs: A - B = - ABBA

Pelo Teorema de pitágoras: |AB| = √(bx-ax)²+(by-ay)²
O vetor AB no ponto A tem módulo igual a zero. O vetor BA no ponto B tem módulo igual a zero.
O vetor OA tem coordenadas iguais ao ponto A, porém, subtração de pontos é diferente da subtração de vetores.

Repare que o sentido surge com a diferença entre as coordenadas de dois pontos.
- Módulo de um vetor é a diferença entre as coordenadas do ponto de extremindade com as coordenadas do ponto de origem do mesmo.
- Um ponto não tem módulo, mas tem coordenadas. Um vetor tem módulo e diferença de coordenadas.
- Subtração de pontos é diferente de subtração de vetores.

Propriedades do Ponto
- Um ponto é determinado por suas coordenadas. As coordenadas são obtidas pela projeção ortogonal do ponto nos eixos catesianos.
- Um ponto tem como referência a origem do sistema de coordenadas.
- Um ponto considerado como vetor possui módulo nulo e tem origem e extremidades coincidentes.
Propriedades do Vetor
- Possui módulo, direção e sentido.
- Fica determidado pela diferença entre o ponto de extremidade e o ponto de origem.
- O sinal de menos (-) para os eixos significa sentido contrário ao sentido positivo (+) ou contrário a seta de direção dos eixos.
- Quando multiplicamos um vetor por menos um (-1) o seu sentido é invertido.
- Dois seguimentos são ditos equipolente se ambos são nulos ou ambos tem a mesma direção, o mesmo sentido e o mesmo comprimento.
- Um vetor é uma classe de equipolência de seguimentos orientados no espaço (E³). Um vetor não é alterado pela sua translação.

Propriedades da Adição de Vetores
- Associativa:
( a  + b ) + c   = a  + ( b   + c
- Soma:
a  = (ax i ,ay j ,az )
b  = (bx i ,by j ,bz )
a  + b  = ((ax+bx) i ,(ay+by) j ,(az+bz) )
- Diferença:
a  - b  = ((ax-bx) i ,(ay-by) j ,(az-bz) )

A propriedade asssossiativa possibilita deslocar qualquer ponto no espaço apenas somando-se vetores ao ponto: B = A + AB
Conforme figura abaixo:  AB = v1 + v2 + v3 + v4 = v3 + v4 + v1 + v2



Paralelogramo


3.2. Projeção no Plano
A visão humana é capaz de ver os objetos em três dimenções, ou seja, o comprimento na horizontal, o comprimento na vertical e comprimento de profundidade.
A projeção de um objeto real (3D) no plano não possui o comprimento de profundidade, isso torna desnecessário o uso da coordenada-z na formação ou plotagem da imagem do objeto na tela. Ao gira um objeto 3D no espaço, as coordenadas projetadas na tela vão mudando, porem, sempre será projetada a coordenada-x e a coordenada-y do ponto, isso cria a aparência de três dimensões. As coordenadas do eixo-z não aparecerão porque são perpendiculares ao plano-xy.

3.2.1. Formação da Imagem
Para um objeto 3D um ponto tem três coordenadas P(x,y,z). Ao protar um objeto 3D na tela do monitor utiliza-se apenas a coordenada-x e a coordenada-y, P(x,y).
A rotação de um ponto em torno do eixo-z gerará um círculo no plano-xy, a rotação de um ponto em torno do eixo-x ou eixo-y a projeção do ponto percorerá uma reta em um sentido de 0º a 180º de rotação e retornará ao ponto de origem (sentido contrário) de 180º a 360º. Isto acontece porque a projeção é feita com apenas a coordenada-x ou a coordenada-y. No plano-xy há duas coordenadas e a projeção é feita normalmente. No plano-xz há apenas a coordenada-x uma vez que a coordenada-z não é plotada. No plano-yz há apenas a coordenada-y uma vez que a coordenada-z não é plotada.

A figura abaixo mostra um ponto que girou 360º no plano-xz de forma que sua projeção formou uma reta, coordenada-y = 0. De 0º a 180º (frente) a projeção deslocou-se para à esquerda e de 180º a 360° (traseira) a projeção deslocou-se para a direita. Isto acontece quanado é utilizado apenas a coordenada-x e a coordenada-y para a projeção de um objeto 3D no plano.




Projeção do Cubo Tridimencional no Plano-XY (tela)
Ignorar a coordenada-z e plotar o objeto 3D no plano-xy equivale a uma imagem em que a direção da vista do observador é exatamente igual a do eixo-z, ou seja, o olho do observador está no eixo-z.

O segredo está em utilizar três coordenadas (x,y e z) reais para os cálculos e plotar (desenhar, projetar) apenas a coordenada-x e a coordenada-y. Isso significa que estamos projetanto o cubo tridimencional no plano-xy. A DESVANTAGEM DESTA TÉCNICA É QUE AS PROJEÇÕES NO PLANO-XZ E PLANO-YZ SERÃO PROJETADAS APENAS A COORDENADA-X E A COORDENADA-Y RESPECTIVAMENTE.

Teste Realizado:
A imgem abaixo mostra a rotação dos pontos em torno dos eixos. A rotação de 10º dos pontos em torno do eixo-x no sentido anti-horário que deslocou as coordenadas-y para baixo. A rotação de 10º dos pontos em torno do eixo-y no sentido anti-horário deslocou as coordenadas-x para à esquerda.

3.3. Perspectiva
Na perspectiva tudo que se desenha pertence ao plano formado pelo eixo-x e pelo eixo-y, até mesmo o eixo-z pertence a esse plano. Na área técnica a dimensão é mais importante do que a visualização, pois a medida deve ser exata, por isso a projeção no eixo-z deve ser real assim como no eixo-x e eixo-y.
Na figura abaixo a primeira face do cubo é real (eixo-x e eixo-y), as coordenadas no eixo-z possuem o tamanho real e foram obtidas da rotação do ponto.
A aparência é de uma paralelepípedo e não de um cubo.
Repare na figura abaixo que tanto a perspectiva quanto um cubo real ao ser rotacionado utilizam a regra da mão direita (no caso da figura abaixo).
As coordenadas em três dimenções do objeto real e as coordenadas em duas dimensões da perspectiva possuem a mesma dinâmica ao rotacionar o objeto real. Ao rotacionar o objeto a coordenada do eixo-z (não visível) passa a ser coordenada do eixo-x e/ou coordenada do eixo-y, portanto projetável na tela. A vantagem desta perspectiva é que cada ponto possui nitidamente as três coordenadas P(x,y,z).


0P9
= b
00' = b
P1P2 = P2P3 = P3P4 = P4P1 = P4P6  = P3P5  = P1P7  = P2P8  = P7P6  = P6P5  = P5P8 = P8P7 = b
â: varia conforme a posição do ponto P1 e do comprimento b.
sen(â) = b/r
ê: se de fato o eixo-z existisse o triângulo OP4P6 seria retângulo e não isóceles. As coordenadas dos pontos 3D existem e são utilizadas para os cálculos que forem necessário normalmete, porém, quando os pontos 3D forem plotados na tela, apenas as coordenadas-x e as coordenadas-y são utilizadas. As coordenadas-z serão formadas no plano 2D pelas ligação dos pontos P(x,y) que correspondem com a respectiva coordenada-z do próprio ponto.

sen(ê/2) = (b/2)/r



3.4. Perspectiva Isométrica
A figura abaixo é uma perspectiva em que o eixo-z e o eixo-x formam 60º com o eixo-y, porém devemos interpretar como 90º. As dimensões do cubo em perspectiva mudam conforme rotacionamos os três eixos.
Esta perspectiva é a projeção real da coodenada-x e da coordenada-y do objeto no plano-xy da tela. Ao girar o objeto a coordenada-z vai se projetanto no plano-xy, ou melhor, as três coordenadas vão mudando de tamanho.

A perspectiva da figura abaixo formou um hexaedro que foi circunscrito por uma circunferência de raio igual ao lado do hexaedro. O graus de realismo depende da espessura e forma das linhas, sombras, degrades, luminosidade, brilho, ofuscamento, tons, cores, fundo, etc.


Obs: Cada ponto da perspectiva acima tem apenas duas coordenadas, mesmo representando um objeto no espaço 3D, ou seja, os pontos estão em um plano.


Esta técnica consistem em desenhar ou plotar o cubo 3D na tela, porém os pontos 3D serão inseridos nas coordenadas da perspectiva. Devemos transformar os pontos do cubo 3D para a perspectiva.

Para o cubo 3D x = y = z = b.

P2'(x2',y2',z2')
cos30º = x2'/x2 => x2' = x2.cos30º
sen30º = y2'/x2' => y2' = x2'.sen30º
z2' = z2 = 0
P2' = (x2.cos30º,x2'.sos30º,0)

P3'(x3',y3',z3')
sen60º = x3'/x3 => x3' = x3.sen60º
y3' = y3 + y3.cos30º
z3' = z3 = 0
P3' = (x3.cos30º,y3 + y3.cos30º,0)
...

Com um cubo foi obtido aparentemente um hexaedro com giro de 45º para o eixo-x, 35º para o eixo-y e 0º para o eixo-z.


Na figura abaixo temos o ciclo (ou círculo) trigonométrico com as variações das coordenadas do ponto (cosα,senα), como o círculo tem raio igual a 1 (um), o cosseno e o seno tem valores que variam de -1 a 1.
De 0º a 360º cosseno e seno vão de 1 à -1
De 0º a 180º cosseno vai de 1 a -1. E seno vai de 0 à 1 e de 1 à 0.
Quando um ponto gira com seu centro na origem do sistema de coordenadas, as coordenadas de um eixo  aumentam e as coordenadas do outro do eixo diminuem e vice versa.



Reiniciar



3.5. Rotação de Ponto em Torno do Eixo
A figura abaixo mostra a rotação do ponto P no sentido anti-horário em torno dos três eixos. Os eixos de referências permanecem parados.
O ponto P possui as projeções Px, Py e Pz nos respectivos eixos.


 Ao rotacionar um ponto em torno de um eixo ele o faz através de um raio de circunferência igual a projeção do ponto no plano formado pelos outros dois eixos. Todos os pontos de um objeto seguem esta mesma regra.
O eixo sobre o qual o ponto gira matém a mesma coordenada e as coordenadas dos outros dois eixos mudam.

Uma rotação em torno de um eixo provoca a alteração das coordenadas nos outros dois eixos conforme a circunferência pontilhada. A alteração das coordenadas é no sentidos positivo ou negativo do respectivo eixo conforme sua posição na circunferência de giro do ponto.

Ao girar um ponto:
Suas  projeçãos nos eixos podem deslocar-se no sentido positivo ou negativo conforme a sua posição na circunferência pontilhada.

Sistema de Referência
É o da tela do monitor, eixo-x na horizontal e eixo-y na vertical, o eixo-z é fictício. Ao rotacionar um objeto no espaço 3D a coordenada-z se transformará em coordenada-x e cordenada-y,ou seja, será projetada no plano-xy.
O sistema de coordenadas de referência permanecer sempre parado, pois é uma referência, o que muda é o sistema de coordenadas do objeto que muda junto com ele.

Com a Regra da Mão Direita: par o giro do objeto no espaço 3D.
Rotação
Anti-horário
Horário
do eixo-z
x' = x.cosθ - y.senθ
y' = x.senθ + y.cosθ
x' = x.cosθ + y.senθ
y' = -x.senθ + y.cosθ
do eixo-y
x' = z.cosθ - x.senθ
y' = z.senθ + x.cosθ
x' = z.cosθ + x.senθ
y' = -z.senθ + x.cosθ
do eixo-x
x' = y.cosθ - z.senθ
y' = y.senθ + z.cosθ
x' = y.cosθ + z.senθ
y' = -y.senθ + z.cosθ


Quando eu olho de frente para um objeto no espaço 3D e o rotaciono no sentido anti-horário, para ter este mesmo efeito na tela do monitor eu preciso padronizar o sistema de coordenadas de referência do objeto e da imagem, ou sejam tem que ser o mesmo. Assim, se o objeto gira no sentido anti-horário a imagem tambem gira no sentido anti-horário.

4. Padronização dos Pontos
É preciso criar uma regra lógica para facilitar o entendimento e organizar a disposição dos pontos de forma correta.
Essa disposição dos eixos foi escolhida por representar a tela de um monitor em três dimensões, o eixo-z avança para dentro. Será usado o mesmo sentido do eixo-y da tela para não prejudicar  a edição de textos para indicar os vértices. O cubo possui lado igual a dois (2). O importante é escolher uma disposição dos pontos no cubo igual a configuração da tela do monitor e utilizar a mesma disposição para os cálculos. Os vértices serão representados por letras e números.
Repare que o cubo padrão (2x2) é a base para a criação do cubo de lados w, h e dp, centralizado em C(xc,yc,zc).

Cubo 2x2 (y para baixo) Vértices (mão direita) P(x,y,z)
Po(-1,1,-1)
P1(1,1,-1)
P2(1,1,1)
P3(-1,1,1)
P4(-1,-1,-1)
P5(1,-1,-1)
P6(1,-1,1)
P7(-1,-1,1)

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

5. Versor
É um vetor unário que representa a mesma orientação do seu respectivo eixo, ou seja, mesma direção e sentido.
Pojeção dos Versores
Os versores representam o sentido positivo dos eixos do espaço tridimensional.

Módulo igual a 1:
i = (1,0,0)
j = (0,1,0)
k = (0,0,1)
| i  | = 1
| j  | = 1
| k | = 1
Pelo Teorema de Pitágora: hipotenusa2 = cateto12 + cateto22 podemos calcular a  diagonal de um retângulo qualquer.
As projeções de um vetor v no espaço formam um retângulo cuja diagonal corresponde a seu módulo.
|v | = √x² + y² + z²
Para um cubo de lados iguais a c, sua diagonal d é:
d = c.√3

Discussão:
- Um ponto no espaço pode ocupar qualquer posição e suas projeções não formam necessariamente um cubo no sistema de coordenadas cartesiano.
- Os versores possibilitam trabalhar com apenas os módulos das projeções dos vetores no espaço, despreocupando assim com sua direção e sentido.
- As projeções de um vetor no espaço formam um paralelogramo.

6. Produto Escalar
Adaptando a figura anterior para o produto escalar temos:
( i , j , k)
v = (xv, yv, zv)
u = (xu, yu, zu)

Obs: θ varia de 0º a 180º apenas.

PQ = v - u
PQ = (xv, yv, zv) - (xu, yu, zu) = (xv-xu, yv-yu, zv-zu)
|PQ| =√(xv-xu)² + (yv-yu)² + (zv-zu)²
|PQ|² = (xv-xu)² + (yv-yu)² + (zv-zu)²
|PQ|² = (x²v-2.xv.xu+x²u) + (y²v-2.yv.yu+y²u) + (z²v-2.zv.zu+u)
|PQ|² = (x²v+y²v+z²v) + (x²u+y²u+z²u)  -2[(xv.xu) + (yv.yu) + (zv.zu)]
(x²v+y²v+z²v) = v² e (x²u+y²u+z²u) = u²
|PQ|² = v² + u²  -2[(xv.xu) + (yv.yu) + (zv.zu)] (I) No Espaço

Em qualquer triângulo, o quadrado de um lado é igual à soma dos quadrados dos outros dois, menos duas vezes o produto desses dois lados pelo cosseno do ângulo formado por eles.
|PQ|² = | v - u |² = | v |² + | u |² - 2.| v |.| u |.cosθ (II) No Plano
[(xv.xu) + (yv.yu) + (zv.zu)] = | v |.| u |.cosθ (I) e (II)

Produto Escalar:
v . u = [(xv.xu) + (yv.yu) + (zv.zu)] =  0 se v = 0 ou u = 0
| v |.| u |.cosθ

O produto escalar de dois vetores é a soma dos produtos entre as respectivas coordenadas de cada um é também igual ao produtos de ambos módulos pelo cosseno entre eles.
| v |, | u | e cosθ sendo CONSTANTE no espaço, variando apenas a posição do conjunto, as projeções de ambos variam, porém, o produto escalar é o mesmo.

A soma de dois vetores e a diferença de dois vetores são as diagonais do paralelogramo formado pelos dois vetores.
Também utiliza-se a notação v × u  para v . u

Demonstração
Será considerado nula as coordenadas do eixo-z para facilitar o desenho.
cos60º = 0,5 | sen60º = 0,866 | cos30º = 0,866 | sen30º = 0,5

Dados:
cos60º = 10/v= 0,5 => v = 20
sen60º = vy/20 = 0,866 => vy = 17,32 e vx = 10
sen30º = 15/u = 0,5 => u = 30
cos30º = ux/30 = 0,866 => ux = 25,98
Temos:
20.30.cos30º = 519,6
A soma do produto das respectivas coordenadas é: 17,32 . 15 + 10 . 25,98 = 519,6

7. Produto Vetorial: v ^ou v × u
Para dois vetores linearmente independentes, v  e u , o módulo do produto vetorial entre eles é dado por | v ^ u | que é igual a área do paralelogramo formado entre os dois conforme figura abaixo.

Caso, v  e fossem linearmente dependentes, então: v ^ = 0

Pela figura abaixo pode-se perceber que as coordenadas de v ^ u, v  e u  

(v ^ u) ^  v  =
(v ^ u) ^   = v 


Utiliza-se o sinal "^" acento circunfléxico para o produto vetorial diferenciando do sinal "." ponto para o produdo escalar, porém, é comum utilizar-se o sinal ponto "." para o cálculo de multiplicação dos versores ( i . i  = 0  deveria ser i ^ i  = 0). Também é comum utilizar o sinal de vez "×".


Obs: antes de usar a regra da mão direita verifique esta regra no sistema de coordenadas que você adotou, note que  i ^ j   =
no sistema de coordenadas acima o produto vetorial é no sentido anti-horário.

Para uma base ortogonal positiva ( i , j , k ), v = (xv, yv, zv) e u = (xu, yu, zu)  o produto vetorial entre ambos pode ser  representado pelo determinande da matriaz abaixo.
A definição do produto vetorial nos permite escrever que:
i . i  = j . j  = k . k = 0
i . j  = k       k . i  = j      j . k  = i   ou
i ^ j  = k       k ^ i  = j      j ^ k  = i

Note que as igualdades correspondem a uma permutação circular a partir da primeira.
j . i  = -k       i . k  = - j      k . j  = - i   ou
j ^ i  = -k       i ^ k  = - j      k ^ j  = - i
Note que as igualdades correspondem a uma inversão da ordem dos fatores em relação às igualdades anteriores.

7.1. Escolha do sistema de Coordenadas
É preciso padronizar o sitema de coordenadas para trabalhar com geometria analítica. O eixo-x fica na horizontal com sentido positivo para à esqueda. O eixo-y e o eixo-z deve ser escolhido. Após adotar um sistema não deve mais alterá-lo.
Para saber qual é o primeiro vetor do produto vetorial tome como referência os versores dos eixos (i, j e k) juntamente com o sentido positivo do ângulo. O observador está olhando para o produto vetorial.


7.2. Produto Vetorial (Matriz)
O produto vetorial é a multiplicação um a um das coordenadas do primeiro vetor pelas coordenadas do segundo vetor, observe acima como fica a multiplicação dos versores.
v ^ u = (xv. i , yv. j , zv. k ).(xu. i , yu. j , zu. k ) = xv.yu. k - xv.zu. j  - yv.xu. k  + yv.zu. i  + zv.xu. j   -  zv.yu. i

O determinante abaixo corresponde a mesma expressão acima.

v ^ u = 
i j k
xv yv zv
xu yu zu
Também podemos agrupar a expressão anterior em três parcelas de determinantes de grau dois.

v ^ u = 

yv   zv
yu   zu
 →. i  +
xv   zv
xu   zu
. j  +
xv    yv
xu   yu
. k

v ^ u = ( yv.zu - zv.yu). i   + ( xv.zuzv.xu). j  + ( xv.yu -  yv.xu). k

O determinante abaixo corresponde a mesma expressão acima.
Matriz 3x3

u ^ v = - 
i j k
xv yv zv
xu yu zu

Matriz 2x2

u ^ v = -  

yv   zv
yu   zu
 →. i  -
xv   zv
xu   zu
. j  -
xv    yv
xu   yu
. k

u ^ v = -( yv.zu - zv.yu). i   - ( xv.zuzv.xu). j  - ( xv.yu -  yv.xu). k

v ^ é um vetor ortogonal a  e

( yv.zu - zv.yu)² + ( xv.zuzv.xu)² + ( xv.yu -  yv.xu)² =
v ^ = w
( v ^ ) . v  = | w |.| v |.cosθ
cosθ  = 1 => θ  = 90º

Regra da Mão Direita

Obs:
- Olhando o produto vetorial de frente (figura acima) primeiro vetor é do produto vetorial v ^ u , ou seja, a multiplicação é feita no sentido anti-horário.
- Para o produto vetorial u ^ v , o primeiro vetor é e a multiplicação é feita no sentido horário. Terá sentido oposto ao protudo vetorial v ^ u .


8. Direção de Visualização
Cálculo do ângulo de visualização através do produto escalar: 
Expressão cartesiana do produto escalar: OP•N = |OP|*|N|*cos(ângulo) 
Expressão analítica do produto escalar: OP•N = OP.x * N.x + OP.y * N.y + OP.z * N.z
Conforme figura abaixo OP é o vetor (O -P2) e N é o vetor ('O - P2).

O produto escalar OA•N é Positivo para um polígono de face traseira (vetores com ângulo menor que 90º, face virada para trás, não visível) Negativo para um polígono de face frontal (vetores com ângulo maior que 90º, face virada para a frente) Igual a zero para um polígono de face "lateral" (vetores perpendiculares, face não visível)
Produto Escalar:
v . u = [(xv.xu) + (yv.yu) + (zv.zu)] =  0 se v = 0 ou u  = 0
| v |.| u |.cosθ

Produto Vetorial
v ^ u = (xv. i , yv. j , zv. k ).(xu. i , yu. j , zu. k ) = xv.yu. k - xv.zu. j  - yv.xu. k  + yv.zu. i  + zv.xu. j   -  zv.yu. i

A face de trás tem a distância de seus vértices até o observado maior que a face que fica na frente.

A visibilidade inicial é de acordo com a posição do observador, ou seja, é mais fácil posicionar o objeto com rotação zero (0º) nos três eixos do que calcular tais ângulos para o posicionamento do observador. A direção de observação fará um ângulo com o produto vetorial. O produto vetorial é perpendicular a face cuja arestas o originou.

O olho do observador corresponde ao ponto O. O observador olha para o ponto P2
ox=x5; oy=-500;oz=z5;
fx=x5; fy=y5;fz=z5;




Observações
:

Estudo dos Sinais
O PONTO QUE TEM A COORDENADA-Z MAIOR É O PONTO OCULTO. Ou também quando a coordenada-z do produto vetorial 2 for negativa (conforme teste realizado)
(P3-P2)^(P6-P2)
1º) No sistema acima o produto vetorial (P3-P2)^(P6-P2), o primeiro vetor pelo segundo vetor é no sentido anti-horário, note que pelo sistema o primeiro versor pelo segundo é no sentido horário  i ^ j   = k,  OS VERSORES SERVEM DE REFERÂNCIA PARA SABER QUAL VETOR É O PRIMEIRO NO PRODUTO VETORIAL, LEMBRANDO QUE A INVERSÃO DE MULTIPLICAÇÃO DOS DOIS VETORES INVERTERÁ TAMBÉM O SENTIDO DO PRODUTO VETORIAL. O sistema de coordenadas é adotado, porém é a referência para o produto vetorial.
2°) As faces e arestas que ficam na frente do observador ficarão atrás no plano de projeção, ou seja, o inverso, o ponto mais próximo do obervador é o mais longe do plano de observação.
3º) A projeção 3D é feita com as  coordenadas do eixo-x e as coordenadas do eixo-y, porque a tela do monitor não possui o eixo-z.
4°) A direção de visiblidade é contraria a direção de "projeção" do objeto no plano de visão, logicamente o plano de visão tem de estar entre o observador e o objeto.
5º) O vetor de observação tem origem no ponto observado (P2) e extremidade no ponto de observação (O).

O
: ponto corresponde ao olho do observvador, este ponto se encontra parado.
θ1: é o ângulo entre o vetor normal à face considerada e a direção de observação do ponto considerado (P1), o ângulo de observação de um ponto forma um ângulo de visão máxima de 90º à direita e 90º à esquerda da reta normal N. No detalhe no canto inferior direito da figura acima podemos perceber que à medida que o ponto de obserrvação O for abrindo e girando em torno de N, quando atingir os 90º o círculo formado estará no mesmo plano da face considerada. Portanto, o ângulo de visão máxima é 90º com a direção do observador e mais 90º do outro lado da reta normal com o plano da face considerada.
θ1: determina a visibilidade de três faces e a invisibilitas das faces opostas.

6º) O ponto P2 da figura corresponde ao ponto 2 do cubo padrão, o ponto P3 da figura corresponde ao ponto 3 do cubo padrão, o ponto P6 da figura corresponde ao ponto 6 do cubo padrão.
7º) O ângulo de 90º formado entre a face considerada e a normal a ela pertence a um plano fixo. O ângulo θ1 formado entre a normal e a direção do observador pode fazer um giro em torno da reta normal conforme detalhe no canto inferior direito da figura acima, ou seja, o ponto O pode girar 360º em torno da reta normal com o mesmo ângulo θ1.
8º) O campo de visão é 90º para um lado e 90º para o outro lado da direção de visão.
- Se uma face é visível, a face oposta paralela é invisível e vice versa, com excecão é claro da face perpendicular a direção de visão que é a única face visível.
9º) O ângulo de observação de um ponto é formado pela parcela de 90º correspondente ao produto vetorial (normal) com o plano da face mais  o ângulo θ1 formado entre o produto vetorial (normal) e a direção de observação. Portanto θ1 pode ter no máximo 90º.
10º) Considera-se o objeto opaco. Apenas a superfície é visível.
11º) Embora o ser humano tenha dois olhos, as distância entre os dois é tanto mais desprezada quanto maior é a distância do objeto ao observador.
12º) O foco da visão é apenas um ponto, o outro olho que não faz o foco a imagem aparece ofuscada.
13º) A imagem observada é considerada com apenas um olho.
14º) O campo de visão é um plano perpendicular a direção da visão, será visível todos os pontos do objeto que se projetarem perpendicularmente no plano de visão sem interseccionar o objeto.
15º) Pontos visíveis estão voltados para o plano de visão, ou seja, a reta nornal (produto vetorial) fura o plano de visão.
16º) Determinado o ponto de observação, a direção de observação de um ponto formará três ângulo, um com cada nornal a face visível.
17º) Para não complicar ainda mais não será utilizado o método scale(1,-1) porque ao utilizá-lo o sentido de giro padrão passa a ser horário.
18º) Cubo padrão adotado:


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)

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

9. Produto Escalar
Devemos achar o ângulo entre o produto vetoria (normal a face) e a direção do observador. Isso pode ser feito com a fórmula do produto escalar entre o produto vetorial (normal a face) e a direção do obserrvador.
( i , j , k)
( i ) = (1,0,0)
( j ) = (0,1,0)
( k) = (0,0,1)


v = (xv, yv, zv)
u = (xu, yu, zu)
Fórmula:
v . u  = [(xv.xu) + (yv.yu) + (zv.zu)] = | v |.| u |.cosθ

- Ponto de Observação
Para um ponto representado por um vértice v = (xv, yv, zv) e o olho do observador posicionado no ponto Ob = (xob, yob, zob) teremos o seguinte vetor de observação:
Ob = (xob - xv, yob - yv, zob - zv)
|Ob| =√(xob - xv )² + (yob - yv)+ (zob - zv

v . Ob  = [(xv.xob) + (yv.yob) + (zv.zob)] = | v |.|Ob|.cosθ
cosθ = [(xv.xob) + (yv.yob) + (zv.zob)]/| v |.|Ob| => θ = acos([(xv.xob) + (yv.yob) + (zv.zob)]/| v |.|ob|)
O ângulo entre a normal e a a direção de visibilidade com 0 < θ < 90º a face é visível e a contra face é invisível cuja angulo entre sua normal  e a direção de observação (a mesma) forma ângulo igual a 180º < θ <270º.


9.1. Cálculo do Ângulo entre o Produto Vetorial e a Direção de Visualização
Serão feitas algumas alterações no primeiro código.

Produto Vetorial

Para encontrar a reta normal a face basta achar o produto vetorial no vértice foco da observação. Será utilizado a subtração de pontos (vértices) para encontrar os dois vetores que formam o plano da face.
Fórmula: v^u=yv.zu-zv.yu,xv.zu-zv.xu,xv.yu-yv.xu
ou
Fórmula: v1^v2=yv1.zv2-zv1.yv2,zv1.xv2-xv1.zv2,xv1.yv2-yv1.xv2
Produto Vetorial 1: P1-P5^P6-P5:
v1=[t[1].x-t[5].x,t[1].y-t[5].y,t[1].z-t[5].z];
v2=[t[6].x-t[5].x,t[6].y-t[5].y,t[6].z-t[5].z];
produto1=[(v1[1]*v2[2])-(v1[2]*v2[1]),(v1[2]*v2[0])-(v1[0]*v2[2]),(v1[0]*v2[1])-(v1[1]*v2[0])];// face  visível e face  oculta

Produto Vetorial 2: P6-P5^P4-P5"
v3=[t[6].x-t[5].x,t[6].y-t[5].y,t[6].z-t[5].z];
v4=[t[4].x-t[5].x,t[4].y-t[5].y,t[4].z-t[5].z];
produto2=[(v3[1]*v4[2])-(v3[2]*v4[1]),(v3[2]*v4[0])-(v3[0]*v4[2]),(v3[0]*v4[1])-(v3[1]*v4[0])];

Direção de Visualização:
fx=x5; fy=y5; fz=z5;
ox=x5; oy=-500; oz=z5;
var ob= Math.sqrt(Math.pow(ox-x5, 2)+Math.pow(oy-y5, 2)+Math.pow(oz-z5, 2));

Módulo do Produto Vetorial 1:
var prod1 = Math.sqrt(Math.pow(produto1[0], 2)+Math.pow(produto1[1], 2)+Math.pow(produto1[2], 2));

Módulo do Produto Escalar 1:
var cartesiano1 = (produto1[0]*(ox-fx)) + (produto1[1]*(oy-fy)) +(produto1[2]*(oz-fz));
a2 = Math.acos(cartesiano1/(prod1*ob));
a2=180*a2/Math.PI;

Módulo do Produto Vetorial 2:
var prod2 = Math.sqrt(Math.pow(produto2[0], 2)+Math.pow(produto2[1], 2)+Math.pow(produto2[2], 2));
Módulo do Produto Escalar 2:
var cartesiano2 = (produto2[0]*(ox-fx)) + (produto2[1]*(oy-fy)) +(produto2[2]*(oz-fz));
a3 = Math.acos(cartesiano2/(prod2*ob));
a3=180*a3/Math.PI;

Observações:
Math.pow(base, expoente) = baseexpoente
Math.sqrt(número)= 2 numero
Math.acos(número) =  aco-cosseno, é o ângulo em radiano do cosseno, cos(angulo) = numero => acos(numero) = angulo

Desenho do Produto Vetorial e da Direção de Visão:
ctx.beginPath();
ctx.moveTo(t[5].x,t[5].y); // produto1: P5 é o início do vetor Produto Vetorial
ctx.lineTo(produto1[0]+t[5].x,produto1[1]+t[5].y);// o ponto de extremidade é igual ao módulo (coordenada) mais o ponto de início (P5).
                                                         
ctx.moveTo(t[5].x,t[5].y); // produto1: P5 é o início do vetor Produto Vetorial
ctx.lineTo(produto2[0]+t[5].x,produto2[1]+t[5].y); // o ponto de extremidade é igual ao módulo (coordenada) mais o ponto de início (P5).
                   
ctx.moveTo(x5,y5); // direcao vista (escolhido)
ctx.lineTo(ox,oy);
               
ctx.stroke();
ctx.closePath();

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

<button onclick="faz()">Ok</button><br>
  
    <script>
        var c_canvas = document.getElementById("c");
        var ctx = c_canvas.getContext("2d");
           
                   
        function Point3D(x,y,z) {
          this.x = x; //"this.x =x significa que a variável global x (não declarada até então) é igual ao "
          this.y = y; //parametro x, o parâmtro x poderia ter outro nome
          this.z = z;


            this.rotateZ = function(angle) {// giro do objeto no sentido anti-horario para os tres eixos
                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; //"x é uma nova variável interna e this.x é a variável x global"
                y = this.x*sina+this.y*cosa;
                return new Point3D(x, y,this.z); // entrada de novos parametros, em vez de this.z poderia ser
            }                                    //"apenas z (this.z = z), mas this.z se refere a variável  global 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, z, x;
                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 xc = Math.ceil((601-1)/2);
var yc = Math.ceil((601-1)/2);
var zc = Math.ceil((601-1)/2); //"zc no lado positivo do eixo z"


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));// vertice 0
vertices.push(new Point3D(x1, y1, z1));// vertice 1
vertices.push(new Point3D(x2, y2, z2));// vertice 2
vertices.push(new Point3D(x3, y3, z3));// vertice 3
vertices.push(new Point3D(x4, y4, z4));// vertice 4
vertices.push(new Point3D(x5, y5, z5));// vertice 5
vertices.push(new Point3D(x6, y6, z6));// vertice 6
vertices.push(new Point3D(x7, y7, z7));// vertice 7


var angle2 = -10;
function faz(){ 
   
ctx.clearRect(0,0,600,600);
var t = new Array();
        angle2 = angle2+10;
        if(angle2==360){angle2=0;}
            for( var i = 0; i < vertices.length; i++ ) {
                var r = vertices[i].translate(-xc,-yc,-zc).rotateX(20).rotateY(angle2).rotateZ(angle2).translate(xc,yc,zc);
                t.push(r);
               
            }

          
var faces = new Array();
faces.push([t[0],t[1],t[2],t[3]]);//face 0
faces.push([t[4],t[0],t[3],t[7]]);//face 1
faces.push([t[4],t[0],t[1],t[5]]);//face 2
faces.push([t[5],t[1],t[2],t[6]]);//face 3
faces.push([t[2],t[6],t[7],t[3]]);//face 4
faces.push([t[4],t[5],t[6],t[7]]);//face 5        




//"v1^v2=yv1.zv2-zv1.yv2,zv1.xv2-xv1.zv2,xv1.yv2-yv1.xv2"
//"P1-P5^P6-P5"
v1=[t[1].x-t[5].x,t[1].y-t[5].y,t[1].z-t[5].z];
v2=[t[6].x-t[5].x,t[6].y-t[5].y,t[6].z-t[5].z];
produto1=[(v1[1]*v2[2])-(v1[2]*v2[1]),(v1[2]*v2[0])-(v1[0]*v2[2]),(v1[0]*v2[1])-(v1[1]*v2[0])];// face  visível e face  oculta


//"P6-P5^P4-P5"
v3=[t[6].x-t[5].x,t[6].y-t[5].y,t[6].z-t[5].z];
v4=[t[4].x-t[5].x,t[4].y-t[5].y,t[4].z-t[5].z];
produto2=[(v3[1]*v4[2])-(v3[2]*v4[1]),(v3[2]*v4[0])-(v3[0]*v4[2]),(v3[0]*v4[1])-(v3[1]*v4[0])];


fx=x5; fy=y5; fz=z5;
ox=x5; oy=-500; oz=z5;
var ob= Math.sqrt(Math.pow(ox-x5, 2)+Math.pow(oy-y5, 2)+Math.pow(oz-z5, 2));

var prod1 = Math.sqrt(Math.pow(produto1[0], 2)+Math.pow(produto1[1], 2)+Math.pow(produto1[2], 2));
var cartesiano1 = (produto1[0]*(ox-fx)) + (produto1[1]*(oy-fy)) +(produto1[2]*(oz-fz));
a2 = Math.acos(cartesiano1/(prod1*ob));
a2=180*a2/Math.PI;

var prod2 = Math.sqrt(Math.pow(produto2[0], 2)+Math.pow(produto2[1], 2)+Math.pow(produto2[2], 2));
var cartesiano2 = (produto2[0]*(ox-fx)) + (produto2[1]*(oy-fy)) +(produto2[2]*(oz-fz));
a3 = Math.acos(cartesiano2/(prod2*ob));
a3=180*a3/Math.PI;


document.getElementById("ida").innerHTML=angle2;

zoculto=0;//importantissimo para o inicio da comparacao

  for(i=0;i<7;i=i+1){
     
       for(r=0;r<8;r=r+1){ 
      
          if(t[i].z<t[r].z){      if(t[r].z >zoculto){zoculto=t[r].z;a=r;}"a é variável que guarda o valor  do índice do ponto oculto"
                                  xoculto= t[a].x;
                                  yoculto= t[a].y;
                                  document.getElementById("idzoculto").innerHTML=zoculto;
                                  document.getElementById("idxoculto").innerHTML=xoculto;
                                  document.getElementById("idyoculto").innerHTML=yoculto;
                                  document.getElementById("idr").innerHTML=a;
                                                      
            }//fecha o se

       }//fecha o for interno
     
 switch (a) {      
                                     case 0:
                                   
                                     ctx.beginPath();
                                     ctx.setLineDash([]);
                                     ctx.lineWidth = 2;
                                     ctx.strokeStyle="#000000";
                                     ctx.font = "normal 18px Verdana";                                                    
                                     ctx.moveTo(t[1].x,t[1].y); //face 0
                                     ctx.lineTo(t[2].x,t[2].y);
                                     ctx.lineTo(t[3].x,t[3].y);             
                           

                                     ctx.moveTo(t[4].x,t[4].y); //face 5
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                     ctx.lineTo(t[4].x,t[4].y);
                              
                            
                                     ctx.moveTo(t[3].x,t[3].y); //face1
                                     ctx.lineTo(t[7].x,t[7].y);
                                                  
                                     ctx.moveTo(t[1].x,t[1].y); //face3
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.moveTo(t[2].x,t[2].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                 
                                     ctx.stroke();
                                     ctx.closePath();
                                     break;
                                                  
                                                  
                                     case 1:
                                     ctx.beginPath();
                                     ctx.setLineDash([]);
                                     ctx.lineWidth = 2;
                                     ctx.strokeStyle="#000000";
                                     ctx.font = "normal 18px Verdana";                                                    
                                     ctx.moveTo(t[2].x,t[2].y); //face 0
                                     ctx.lineTo(t[3].x,t[3].y);
                                     ctx.lineTo(t[0].x,t[0].y);             
                                               
                                     ctx.moveTo(t[4].x,t[4].y); //face 5
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                     ctx.lineTo(t[4].x,t[4].y);
                                                  
                                     ctx.moveTo(t[0].x,t[0].y); //face 1
                                     ctx.lineTo(t[4].x,t[4].y);
                                     ctx.moveTo(t[3].x,t[3].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                                  
                                     ctx.moveTo(t[2].x,t[2].y); //face3
                                     ctx.lineTo(t[6].x,t[6].y);

                                    
                                     ctx.stroke();
                                     ctx.closePath();
                                     break;                                       
                                                  
                                     case 2:
                                                  
                                     ctx.beginPath();
                                     ctx.setLineDash([]);
                                     ctx.lineWidth = 2;
                                     ctx.strokeStyle="#000000";
                                     ctx.font = "normal 18px Verdana";                                                    
                                     ctx.moveTo(t[0].x,t[0].y); //face 0
                                     ctx.lineTo(t[1].x,t[1].y);
                                     ctx.moveTo(t[0].x,t[0].y); //face 0
                                     ctx.lineTo(t[3].x,t[3].y);

                                     ctx.moveTo(t[4].x,t[4].y); //face 5
                                     ctx.lineTo(t[5].x,t[5].y);
                                     ctx.lineTo(t[6].x,t[6].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                     ctx.lineTo(t[4].x,t[4].y);
                                                  
                                     ctx.moveTo(t[0].x,t[0].y); //face 1
                                     ctx.lineTo(t[4].x,t[4].y);
                                     ctx.moveTo(t[3].x,t[3].y);
                                     ctx.lineTo(t[7].x,t[7].y);
                                                  
                                     ctx.moveTo(t[1].x,t[1].y); //face3
                                     ctx.lineTo(t[5].x,t[5].y);                                  
                                     ctx.stroke();
                                     ctx.closePath();
                                     break;
        
                                    case 3:
                                    ctx.beginPath();
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                    ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                               
                                    ctx.moveTo(t[4].x,t[4].y); //face 5
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.lineTo(t[6].x,t[6].y);
                                    ctx.lineTo(t[7].x,t[7].y);
                                    ctx.lineTo(t[4].x,t[4].y);

                                    ctx.moveTo(t[0].x,t[0].y); //face 1
                                    ctx.lineTo(t[4].x,t[4].y);

                                    ctx.moveTo(t[1].x,t[1].y); //face3
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.moveTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[6].x,t[6].y);
                                                                    
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
                                                  
                                    case 4:
                                    ctx.beginPath();                                   
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                     ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[0].x,t[0].y);
                                    ctx.moveTo(t[5].x,t[5].y); //face 5
                                    ctx.lineTo(t[6].x,t[6].y);
                                    ctx.lineTo(t[7].x,t[7].y);

                                    ctx.moveTo(t[3].x,t[3].y); //face 1
                                    ctx.lineTo(t[7].x,t[7].y);
                  
                                    ctx.moveTo(t[1].x,t[1].y); //face3
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.moveTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[6].x,t[6].y);
                                    
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
                                  
                                    case 5:
                                    ctx.beginPath();
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                    ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[0].x,t[0].y);
               

                                    ctx.moveTo(t[6].x,t[6].y); //face 5
                                    ctx.lineTo(t[7].x,t[7].y);
                                    ctx.lineTo(t[4].x,t[4].y);
                  
                                    ctx.moveTo(t[0].x,t[0].y); //face 1
                                    ctx.lineTo(t[4].x,t[4].y);
                                    ctx.moveTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[7].x,t[7].y);
                  
                                    ctx.moveTo(t[2].x,t[2].y);// face 3
                                    ctx.lineTo(t[6].x,t[6].y);
                                    
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
                                  
                                    case 6:                                                
                                    ctx.beginPath();
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                    ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[0].x,t[0].y);
               
                                    ctx.moveTo(t[7].x,t[7].y); //face 5
                                    ctx.lineTo(t[4].x,t[4].y);
                                    ctx.lineTo(t[5].x,t[5].y);
 
                                    ctx.moveTo(t[0].x,t[0].y); //face 1
                                    ctx.lineTo(t[4].x,t[4].y);
                                    ctx.moveTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[7].x,t[7].y);
                  
                                    ctx.moveTo(t[1].x,t[1].y); //face3
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
      
                                    case 7:           
                                    ctx.beginPath();
                                    ctx.setLineDash([]);
                                    ctx.lineWidth = 2;
                                    ctx.strokeStyle="#000000";
                                    ctx.font = "normal 18px Verdana";                                                    
                                    ctx.moveTo(t[0].x,t[0].y); //face 0
                                    ctx.lineTo(t[1].x,t[1].y);
                                    ctx.lineTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[3].x,t[3].y);
                                    ctx.lineTo(t[0].x,t[0].y);
               

                                    ctx.moveTo(t[4].x,t[4].y); //face 5
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.lineTo(t[6].x,t[6].y);
 
                                    ctx.moveTo(t[0].x,t[0].y); //face 1
                                    ctx.lineTo(t[4].x,t[4].y);
 
                                    ctx.moveTo(t[1].x,t[1].y); //face3
                                    ctx.lineTo(t[5].x,t[5].y);
                                    ctx.moveTo(t[2].x,t[2].y);
                                    ctx.lineTo(t[6].x,t[6].y);   
                                    ctx.stroke();
                                    ctx.closePath();
                                    break;
                                   }//"fecha o caso ou switch"                       
                                  
   
    }//fecha o for externo
 
ctx.beginPath();
ctx.moveTo(t[5].x,t[5].y); // produto1
ctx.lineTo(produto1[0]+t[5].x,produto1[1]+t[5].y);
                                                         
ctx.moveTo(t[5].x,t[5].y); // produto2
ctx.lineTo(produto2[0]+t[5].x,produto2[1]+t[5].y);
                   
ctx.moveTo(x5,y5); // direcao vista
ctx.lineTo(ox,oy);
               
ctx.stroke();
ctx.closePath();
   


ctx.fillText("0", t[0].x, t[0].y); //"escrita do pontos nos vertices"
ctx.fillText("1", t[1].x, t[1].y);
ctx.fillText("2", t[2].x, t[2].y);
ctx.fillText("3", t[3].x, t[3].y);

ctx.fillText("4", t[4].x, t[4].y);
ctx.fillText("5", t[5].x, t[5].y);
ctx.fillText("6", t[6].x, t[6].y);
ctx.fillText("7", t[7].x, t[7].y);

Po="xo="+t[0].x.toFixed(4)+"   yo="+ t[0].y.toFixed(4)+"   zo="+t[0].z.toFixed(4); //"posição dos pontos"
P1="x1="+t[1].x.toFixed(4)+"   y1="+ t[1].y.toFixed(4)+"   z1="+t[1].z.toFixed(4);
P2="x2="+t[2].x.toFixed(4)+"   y2="+ t[2].y.toFixed(4)+"   z2="+t[2].z.toFixed(4);
P3="x3="+t[3].x.toFixed(4)+"   y3="+ t[3].y.toFixed(4)+"   z3="+t[3].z.toFixed(4);
P4="x4="+t[4].x.toFixed(4)+"   y4="+ t[4].y.toFixed(4)+"   z4="+t[4].z.toFixed(4);
P5="x5="+t[5].x.toFixed(4)+"   y5="+ t[5].y.toFixed(4)+"   z4="+t[5].z.toFixed(4);
P6="x6="+t[6].x.toFixed(4)+"   y6="+ t[6].y.toFixed(4)+"   z6="+t[6].z.toFixed(4);
P7="x7="+t[7].x.toFixed(4)+"   y7="+ t[7].y.toFixed(4)+"   z7="+t[7].z.toFixed(4);

ctx.fillText("Po=>"+Po,10,400);
ctx.fillText("P1=>"+P1,10,415);
ctx.fillText("P2=>"+P2,10,430);
ctx.fillText("P3=>"+P3,10,445);
ctx.fillText("P4=>"+P4,10,460);
ctx.fillText("P5=>"+P5,10,475);
ctx.fillText("P6=>"+P6,10,490);
ctx.fillText("P7=>"+P7,10,505);

document.getElementById("idob").innerHTML=ob;
document.getElementById("idprod1").innerHTML=prod1;
document.getElementById("idprod2").innerHTML=prod2;

document.getElementById("idcar1").innerHTML=cartesiano1;
document.getElementById("idcar2").innerHTML=cartesiano2;

document.getElementById("ida2").innerHTML=a2;
document.getElementById("ida3").innerHTML=a3;

document.getElementById("z2").innerHTML=produto1[2];
document.getElementById("z3").innerHTML=produto2[2];

a22=(180*Math.atan(4*x5/5*y5))/Math.PI;
document.getElementById("ida").innerHTML=angle2;


}// fecha a funcao faz         
</script>

Módulo Observador = <span id="idob"></span><br>
Produto1 = <span id="idprod1"></span><br>
cartesiano1 = <span id="idcar1"></span><br>
Ângulo = <span id="ida2"></span><br>
produto1z = <span id="z2"></span><br>
-----<br>
Produto2 = <span id="idprod2"></span><br>
cartesiano2 = <span id="idcar2"></span><br>
Ângulo = <span id="ida3"></span><br>
produto2z = <span id="z3"></span><br>
-----------<br>

rotação =<span id="ida"></span>º<br>
<br>
Ponto oculto = <span id="idr"></span><br>
Coordenada-Z maior: Zmaior = <span id="idzoculto"></span><br>
Coordenada-X  = <span id="idxoculto"></span><br>
Coordenada-Y  = <span id="idyoculto"></span><br>

</body>
</html>







Link para execução do código acima