Cena Básica

Nossa primeira tarefa é montar uma página HTML básica que será utilizada para exibir os objetos criados. Para isso, devemos inicialmente fazer o download da biblioteca JavaScript do Three.js. A versão minimizada da biblioteca está disponível em: https://github.com/mrdoob/three.js/.

Esse arquivo deve ser colocado junto com os arquivos HTML que forem criados. Uma possível estrutura de diretório pode ser:

- exemplo
    - js
        * three.min.js
    * index.html

Todos os arquivos JavaScript utilizados nos exemplos estarão dentro da pasta js. Essa é apenas uma possível estrutura. Cada um pode organizar os arquivos da maneira que melhor se adeque ao projeto. Nos arquivos disponibilizados no GitHub a organização está um pouco diferente para se adequar à divisão por exemplos.

Criando a página HTML

O arquivo que vai exibir a cena será o arquivo index.html. Vamos criá-lo na pasta raiz do nosso projeto conforme a estrutura apresentada anteriormente. O arquivo index.html é mostrado a seguir:

<!DOCTYPE html>
<html>
    <head>
        <meta charset=utf-8>
        <title>Computação Visual - Three.js - Exemplo 1</title>
        <style>
            body { margin: 0; }
            canvas { width: 100%; height: 100% }
        </style>
    </head>
    <body>
        <script src="js/three.min.js"></script>
    </body>
</html>

O arquivo three.min.js contém toda a API para criação e manipulação dos objetos 3D. Não é preciso acessar e nem alterar esse arquivo. Todos os projetos desenvolvidos serão feitos em arquivos JavaScript distintos. Para o nosso primeiro exemplo, vamos criar o arquivo exemplo1.js dentro da pasta js. Uma vez criado, vamos referencia-lo no arquivo html.

<!DOCTYPE html>
<html>
    <head>
        <meta charset=utf-8>
        <title>Computação Visual - Three.js - Exemplo 1</title>
        <style>
            body { margin: 0; }
            canvas { width: 100%; height: 100% }
        </style>
    </head>
    <body>
        <script src="js/three.min.js"></script>
        <script src="js/exemplo1.js"></script>
    </body>
</html>

Criando o primeiro exemplo: exemplo1.js

O arquivo exemplo1.js vai conter todas as informações para criação dos objetos. Basicamente, precisamos de 3 elementos: uma cena (scene), uma câmera (camera) e um redenrizador (renderer). Os três elementos são criados no código a seguir:

var scene;
var camera;
var renderer;


var init = function() {

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    this.render();

};

window.onload = this.init;

O primeiro passo foi criar uma variável global para cada um dos elementos que precisamos representar. Um scene que representa um container onde vai ser colocado todos os objetos que queremos renderizar. Um camera que representa o campo de visão da cena. E por fim, um renderer que será nosso renderizador dos objetos contidos na cena. Mais detalhes dos atributos e das configurações destes elementos serão dados mais à frente. Neste primeiro exemplo, vamos nos limitar a entender a função deles para o exemplo inicial.

Instanciado os elementos necessários, precisamos de um método que aplique a renderização à cena criada. Vamos criar a função render que é chamada no final da função init.

var render = function() {
    requestAnimationFrame( render );
    renderer.render( scene, camera );
};

Essa função basicamente renderiza a scene usando a camera definida anteriormente. Ela vai criar um loop que faz com que o redenrizador desenhe a cena 60 vezes por segundo. Utilizando os próprios métodos do Three.js para fazer essas operações tem uma série de vantagens. A mais importante é que ele pausa essa tarefa quando o usuário está em uma aba no navegador que não seja a que esteja exibindo a cena. Isso permite uma economia de processamento e bateria. Vale ressaltar que esse método ele vai ser executado em loop. Então, tudo que está dentro dele será executado 60 vezes por segundo.

Executando essas tarefas será possível ver somente uma tela preta no navegador. Isso significa que a sua cena foi criada, mas ainda não colocamos nenhum objeto nela.

Criando um objeto na cena

Criada a cena é hora de inserir um objeto nela. Para isso vamos criar uma função createACube e chamá-la dentro da função init.

var createACube = function() {
    var geometry = new THREE.BoxGeometry( 1, 1, 1 );
    var material = new THREE.MeshBasicMaterial( { color: "red" } );
    cube = new THREE.Mesh( geometry, material );
    scene.add( cube );
};

Para criar um cubo precisamos definir sua forma e sua geometria. Isso é feito através do método THREE.BoxGeometry que recebe como parâmetros a largura, a altura e a profundidade do cubo. Uma vez especificado a forma do objeto, é necessário definir o material no qual esse objeto será renderizado. O material especifica como um objeto irá reagir a luz que é colocada na cena. Basicamente, é possível definir sua cor, refletividade, se é transparente, dentre outras características que serão abordadas em outros exemplos. Para este exemplo inicial, iremos apenas definir a cor do cubo.

Em seguida é necessário combinar esses dois objetos em um só. A função THREE.Mesh faz esse papel. O objeto resultante dessa combinação (var cube) é inserido na cena (scene.add(cube)).

Observe que cube é uma variável global. Ela é deve ser criada no início do documento.

Essa função é chamada dentro da função init antes de renderizar os objetos na cena.

var init = function() {

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    this.createACube();

    camera.position.z = 5;

    this.render();

};

Observe que colocamos uma nova linha que determina a posição da câmera: camera.position.z. Isso acontece porque quando chamamos o método scene.add, o objeto em questão é adicionado na coordenada (0,0,0). Isso faria com que a câmera e o cubo estivessem na mesma posição. Para evitar esse efeito, movimentamos um pouco a câmera sobre o eixo z.

Ao finalizar esse exemplo, é possível visualizar um quadrado vermelho na tela. Mesmo sendo exibido apenas um quadrado, esse objeto é um cubo. Vamos movimentá-lo para que possamos visualizar melhor nosso objeto.

Alt text

Criando uma animação do objeto

Para exemplificar a animação do objeto vamos rotacionar o cubo que foi inserido na cena. Nas próximas aulas vamos detalhar mais alguns aspectos de movimentação da cena, mas para este exemplo vamos apenas alterar as informações de rotação do cubo. Para fazer isso vamos alterar o atributo de rotação no eixo x e no eixo y. Para isso vamos criar uma nova função animateCube como mostrada a seguir:

var animateCube = function() {
    cube.rotation.x += 0.1;
    cube.rotation.y += 0.1;
}

Essa função deve ser chamada dentro da função render. Esse código será executado, como dito anteriormente, 60 vezes por segundo e vai permitir a animação de rotação no cubo. Qualquer coisa que queiramos mover ou mudar enquanto o app está rodando deve ser colocado dentro do render. Como dito, o render ele é um loop que é executado uma quantidade de vezes por segundo.

Pronto!!! Você já tem o seu primeiro objeto 3D animado criado. Nas próximas aulas vamos explorar melhor os conceitos por trás de algumas operações e colocar mais elementos da computação gráfica na nossa cena.

Código final

A seguir você pode ver o arquivo exemplo1.js completo.

var scene;
var camera;
var renderer;

var cube;


var init = function() {

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    this.createACube();

    camera.position.z = 5;

    this.render();

};

var render = function() {
    requestAnimationFrame( render );

    this.animateCube();

    renderer.render( scene, camera );
};

var createACube = function() {
    var geometry = new THREE.BoxGeometry( 1, 1, 1 );
    var material = new THREE.MeshBasicMaterial( { color: "red" } );
    cube = new THREE.Mesh( geometry, material );
    scene.add( cube );
};

var animateCube = function() {
    cube.rotation.x += 0.1;
    cube.rotation.y += 0.1;
};

window.onload = this.init;


Até a próxima aula ;)

D2L