#include #include #include "cenario.hpp" Cenario::Cenario( FILE *fp ) { // inicializa os totais total_objetos = 0; total_materiais = 0; total_luzes = 0; cor_de_fundo.read( fp ); char filename[80]; fscanf( fp, " %s ", filename ); if (strcmp(filename, "null")) img_de_fundo = new Imagem( filename ); else img_de_fundo = new Imagem (0, 0); } Cenario::~Cenario() { Zera(); if (img_de_fundo) delete img_de_fundo; } void Cenario::Zera() { int i; for (i=0;iValida()) { return cor_de_fundo; } else { return img_de_fundo->GetPixel( lin, col ); } } bool Cenario::InsereObjeto( Objeto_3D *mais_um ) { if( total_objetos+1 == MAXOBJ ) return false; objetos[total_objetos] = mais_um; total_objetos++; return true; } bool Cenario::InsereMaterial( Material *mais_uma ) { if( total_materiais+1 == MAXOBJ ) return false; materiais[total_materiais] = mais_uma; total_materiais++; return true; } bool Cenario::InsereLuz( Luz *mais_uma ) { if( total_luzes+1 == MAXLUZ ) return false; luzes[total_luzes] = mais_uma; total_luzes++; return true; } //------------------------------------------// // Correspondente ao TRACE da transparência // //------------------------------------------// Cor_rgb Cenario::Intercepta( Raio r_vis, int profundidade ) { double t=-1, t_atual, t_min; int i=0, objeto_proximo=-1; Vetor_3D ponto; //Verifico se é o primeiro raio, se for só me interessa o que //estiver depois da tela de projeção //(que tem valor 1 na função paramétrica do raio). if ( profundidade == 0 ) t_min = 1; else t_min = (double)ZERO;//0.0001 para não iterceptar com a própria origem do raio //Percorro todos os objetos perguntando se houve interseção e se //a interseção é mais perto do que a mais perto que eu tiver até o momento. //Quando não há interseção o objeto retorna -1. for(i=0;iIntercepta( r_vis ); if ( (t_atual > t_min) && ( objeto_proximo==-1 || t_atual < t ) ) { t = t_atual; objeto_proximo = i; } } //Houve interseção? (sem interseção: objeto_proximo = -1) if (objeto_proximo>=0) { ponto = r_vis.QualPonto(t); return( CorDoPonto( objeto_proximo, ponto, r_vis, profundidade ) ); } else if (profundidade == 0) return( r_vis.CorDeFundo() ); else return cor_de_fundo; } //------------------------------------------// // Correspondente ao SHADE da transparência // //------------------------------------------// Cor_rgb Cenario::CorDoPonto(int num_obj, Vetor_3D ponto, Raio r_vis, int profundidade) { int i, j=0, bool_sombra, ind_textura; double nl, t, rv, coef_reflexao, nv; static v=0; Cor_rgb final, intermediaria, ilumina; Vetor_3D normal_ponto, direcao_luz, reflexao_luz, direcao_vista, reflexao_vista; Raio sombra, reflexao; //== cálculos iniciais ==// normal_ponto = objetos[num_obj]->Normal(ponto); ind_textura = objetos[num_obj]->Indice_textura(); // calcula a direção da vista normalizada para usar no cálculo da cor especular direcao_vista = r_vis.Origem() - r_vis.Destino() ; direcao_vista.Normaliza(); //=======================// //calcula a cor_ambiente final = materiais[ind_textura]->Ambiente(); //== loop para todas as luzes (cálculo da difusa e especular) ==/ for(i=0;iPosicao(); // Verifica se há sombra para a luz i sombra.Atribui(ponto, direcao_luz); for(j=0;jIntercepta( sombra ); if ( INSIDE(t,ZERO,1) ) //0.00001 para evitar sombra de objetos sobrepostos { bool_sombra = 1; break; } } // Se não houver sombra if ( !bool_sombra ) { //calcula a difusa direcao_luz = direcao_luz - ponto; direcao_luz.Normaliza(); nl = direcao_luz * normal_ponto; // produto escalar intermediaria = luzes[i]->Intensidade() * nl; ilumina = objetos[num_obj]->Cor_difusa(ponto, materiais[ind_textura]) * intermediaria; final = final + ilumina; //calcula a especular (Foley 16.16 & 16.17) reflexao_luz = normal_ponto*(2.0*nl) - direcao_luz; rv = reflexao_luz * direcao_vista; if ( rv > 0.1 ) { rv = (double)pow(rv,materiais[ind_textura]->Indice_especular()); intermediaria = luzes[i]->Intensidade() * materiais[ind_textura]->Coeficiente_especular(); ilumina = rv*intermediaria; final = final + ilumina; } } } //calcula a reflexão coef_reflexao = materiais[ind_textura]->Indice_reflexao(); if ( coef_reflexao > 0 && profundidade < MAX_PROFUNDIDADE ) { nv = direcao_vista*normal_ponto; reflexao_vista= normal_ponto*(nv*2) - direcao_vista + ponto; reflexao.Atribui(ponto,reflexao_vista); intermediaria = (Intercepta( reflexao, profundidade + 1 ))*coef_reflexao; final = final + intermediaria; } return final; }