• Nenhum resultado encontrado

Sistemas de coordenadas

N/A
N/A
Protected

Academic year: 2021

Share "Sistemas de coordenadas"

Copied!
11
0
0

Texto

(1)

No artigo passado explicamos como desenhar um simples triângulo na tela. Entretanto, isso foi feito usando o sistema de coordenadas padrão, que mapeia a tela em intervalos de –1 até 1 em cada eixo. Esse sistema, embora simples, não é muito conveniente para o desenho: como a tela é mais larga do que alta, ele acaba não sendo proporcional. Além disso, o ideal seria que conseguíssemos fornecer individualmente as coordenadas de cada objeto e da câmera, em 3D. Tudo isso é possível graças as matrizes de transformação, que serão vistas neste texto.

Sistemas de coordenadas

Antes de falarmos nas transformações, é importante falarmos nos sistemas de coordenadas tradicionalmente encontrados quando criamos um mundo em 3D.

- Coordenadas do modelo: É o sistema de coordenadas que o artista utilizou para desenhar o objeto na ferramenta de modelagem 3D. Nesse sistema, os eixos coordenados estão centralizados no ponto de rotação do modelo, normalmente seu centro. Esse sistema sempre estará alinhado com o modelo, não importanto sua posição no mundo. Ou seja, se x e z forem os eixos do chão, um ponto em +y sempre será estará acima do modelo, em +x

sempre será a esquerda do modelo e em +z sempre estará para frente do modelo.

- Coordenadas do mundo: Trata-se do sistema de coordenadas onde todos os objetos do mundo estão. É nesse sistema que geralmente pensamos ao posicionar objetos na cena. Nesse sistema de coordenadas nos preocupamos com detalhes como a escala dos objetos, a posição de um em relação a outro, etc.

(2)

- Coordenadas da visão: Trata-se do sistema de coordenadas do observador. Esse sistema está centralizado na câmera. A posição onde a camera está passa a ser encarada como a posição (0,0,0) do mundo. A direção para onde a câmera olha passa a ser encarada como o eixo z.

- Coordenadas de projeção: São as coordenadas no sistema final, da WebGL (o mesmo que trabalhamos no artigo passado). Nesse sistema os eixos x, y e z variam no intervalo máximo de –1 até 1. As coordenadas x e y já devem considerar o impacto causado pela transformação do eixo z – portanto, o cálculo de projeção já deverá ter sido realizado. Tudo o que estiver fora desse intervalo não será desenhado.

(3)

Transformando coordenadas

De nada adianta conhecer sobre os sistemas coordenados, se não podemos converter as imagens que estão num sistema em outro. Iremos fornecer nosso triângulo em coordenadas de modelo mas precisamos que, ao desenhá-lo, ele esteja em coordenadas de projeção. A

ferramenta matemática que faz essa tranformação são as matrizes. Cada vértice da cena será transformado pelas matrizes informadas através da multiplicação de sua posição para matriz indicada. Se você não conhece bem como esse processo funciona, leia nossos artigos sobre

matrizes e transformações

.

Em JavaScript, representaremos matrizes através de um Float32Array. Como estamos trabalhando com coordenadas 3D, e precisamos de transformações afins, a WebGL sempre considera matrizes como possuindo dimensão 4x4. Porém, trabalha com matrizes com uma única dimensão. Portanto, os índices 0 até 3 do array representam a primeira linha da matriz, os índices 4 até 7 a segunda linha, 8 até 11 a terceira e 12 até 15 a quarta linha.

Para facilitar o trabalho com matrizes, iremos utilizar a biblioteca de matemática glMatrix, que possui diversas funções convenientes.

Transformação Model –> World

A primeira transformação relevante é a transformação das coordenadas de modelo em

coordenadas do mundo. A matriz responsável por essa transformação é geralmente chamada de matriz Model ou matriz World. É importante ressaltar que haverá uma matriz Model para

cada objeto da cena

. Portanto, podemos concluir que ela faz parte das propriedades da nossa malha. A transformação de modelo é subdividida em três transformações diferentes:

- Translação: A transformação de translação “afasta” o sistema de coordenadas. É através dela que alteramos a posição em que o objeto será desenhado.

- Rotação: Permite que giremos o eixo coordenado. Como consequencia, o objeto desenhado também girará.

- Escala: Permite alterar a distância entre os pontos do eixo coordenado. Como resultado final, a escala do objeto dentro desse eixo também mudará.

(4)

É importante entender que as operações ocorrem sobre os eixos coordenados, não sobre os objetos. O objeto continuará sendo desenhado com os mesmos comandos, usando as mesmas coordenadas originais. Se isso ficou confuso, considere a seguinte as duas formas que você poderia fazer para desenhar um objeto rotacionado:

1. Você poderia desenha-lo já rotacionado. Isto é, adotar novas coordenadas para o objeto;

2. Você poderia desenhá-lo de pé, como sempre desenhou. Porém, antes de fazer o desenho, você rotaciona a folha de papel, ou seja, todo o seu sistema coordenado. Quando a folha for colocada de pé novamente, o objeto estará rotacionado.

As matrizes trabalham é com essa segunda alternativa. É importante entender isso, pois as operações ocorrem sobre os eixos. Por exemplo, ao fazer uma translação, ela ocorrerá sobre o eixo da forma que está configurado. Isso quer dizer, que a ordem de uma translação e uma rotação é relevante, observe:

(5)

Não pense nisso como um problema, mas sim, como uma vantagem. Significa dizer que se você der um comando para desenhar um objeto a direita de outro, ele sempre será desenhado nessa posição. Mesmo que você rotacione o objeto “pai”, a “nova direita” do objeto filho ficará nessa linha rotacionada. Leva-se mesmo um tempo para se acostumar com esse conceito. Por hora, decore a regra prática de que a ordem para realizar as transformações no sistema de coordenadas da mão direita, usado pela WebGL, é a de translação, rotação e escala. No caso do nosso triângulo, vamos criar no método draw matriz chamada Model, que conterá uma translação para direita e uma leve rotação em torno do eixo z:

//Configura a matriz do modelo var model = mat4.create(); mat4.translate(model, model, vec3.fromValues(0.5, 0, 0)); mat4.rotateY(model, model, toRadians(45));

A função mat4.create() da cria uma matriz 4x4 inicializada com a identidade. A matriz

identidade representa a ausência de transformações. A função translate funciona da seguinte maneira:

1. Ela cria uma matriz de translação para o vetor indicado no terceiro parâmetro; 2. Essa matriz é multiplicada pela matriz indicada no segundo parâmetro (matriz de origem);

3. O resultado é armazenado na matriz indicada no primeiro parâmetro.

A função mat4.rotateX() funciona de forma similar. O único detalhe adicional é que o terceiro parâmetro é o ângulo em radianos. Para fornecê-lo, criamos a função t oDegrees

(6)

function toRadians(degrees) { return degrees * Math.PI / 180; }

Transformação

de World –> View

Precisamos agora posicionar nossa câmera em algum local do mundo. A matriz de transformação da câmera é formada a partir de três vetores:

1. A posição onde a camera está, denominado vetor eye;

2. O ponto para onde a câmera está olhando, chamado de vetor look; 3. A direção que representa “para cima” da câmera, conhecido como vetor up;

No caso da nossa cena, é suficiente afastar a câmera um pouco para trás. Como a câmera olha para o –z, significa que devemos afasta-la em +z. Ela continuará olhando para o ponto central da cena, ou seja, a coordenada (0,0,0). Além disso, a direção que representa para cima continua sendo +y, portanto, seu vetor de direção será (0,1,0). A função responsável por criar a matriz da câmera é a função mat4.lookAt(). O primeiro parâmetro dessa função é a matriz que será multiplicada, nesse caso, usaremos a identidade. A função retorna a matriz criada:

//Configura a matriz da camera var view = mat4.lookAt(mat4.create(),

vec3.fromValues(0.0, 0.0, 5.0), //Onde está vec3.fromValues(0.0, 0.0, 0.0), //Para onde olha vec3.fromValues(0.0, 1.0, 0.0) //Onde é "para cima" );

Transformação

View –> Projection

Por fim, precisamos definir qual será a projeção utilizada para transformar as coordenadas 3D em 2D. É nessa etapa que também definimos qual é a área que será visível para a câmera.

Existem dois tipos de projeção:

- Projeção ortogonal: Similar a projeção de games isométricos, onde objetos mais distante não parecem menores em relação a câmera. A área dessa projeção é um cubo, chamado de viewing cube. Um uso comum para esse tipo de projeção é desenhar o

HUD

do jogo (vidas, pontos, bússola, etc). Para isso, mapeamos uma projeção com largura e altura exatamente igual a da tela, fornecendo assim objetos com coordenadas de pixels. Projeções em ortogonais são criadas com a função

mat4.ortho()

(7)

left, right, bottom, top, near e

far

) devem ser fornecidas:

- Projeção em perspectiva: Faz o cálculo do quão menores os objetos parecerão em relação a câmera. A área dessa projeção é uma pirâmide seccionada, chamada

frustum

. Essa projeção é criada com a função mat4.perspective()

e devem ser fornecidos o ângulo de visão em y ( fovy

), a taxa de aspecto (relação entre a altura e largura da cena), a distância mínima (plano near

) e máxima da visão (plano far

).

(8)

Um parâmetro confuso para os iniciantes é o campo de visão. Ele pode ser encarado como a “abertura da câmera”. Quando o campo de visão é largo, mais objetos cabem na cena e, portanto, os objetos parecem menores. Usar um campo de visão muito largo poderá ocasionar uma cena estranha, arrendadoda nos cantos – um efeito conhecido como “lente olho de peixe” e onde o jogador terá a sensação de nunca encostar na parede. Com um campo de visão mais curto, menos objetos cabem na cena, dando a impressão que eles são maiores. Um campo de visão muito estreito dará a impressão de que a câmera está sendo vista em zoom, numa teleobjetiva. Via de regra, bons valores para o campo de visão estão entre 45 e 60 graus. A imagem abaixo compara um campo de visão mais largo com um mais estreito:

(9)

Esteja apenas atento que a função especifica a abertura em y, e não em x, como seria mais natural.

No caso de nossa aplicação, vamos configurar a projeção como:

//Configura a matriz de projeção var projection = mat4.perspective(mat4.create(),

toRadians(45), //Abertura gl.width / gl.height, //Aspecto 0.1, 100.0 //Near e far );

Aplicando as transformações

As três matrizes já estão criadas, mas como aplicá-las em nossa figura? Quem tem o papel de multiplicar as matrizes pela coordenada dos vértices é o Vertex Shader. Como citamos no artigo anterior, essa é a principal tarefa desse shader. Para que ele possa cumpri-la,

precisaremos modificar o shader do artigo passado para receber as três matrizes como parâmetro. Como as matrizes não mudam de vértice para vértice, faremos isso através da

definição de variáveis

uniformes

. A linguagem GLSL suporta o tipo de dado mat4, representando uma matriz 4x4. O código do Vertex Shader em si então deve ser alterado para multiplicar a posição do vértice pelas

matrizes em sequência:

(10)

uProjection; void main(void) { gl_Position = uProjection * uView * uModel * vec4(aVertexPosition, 1.0); }

Como a WebGL trabalha com o sistema de coordenadas da mão direita, observe que a multiplicação de matrizes teve de ser realizada na ordem contrária as transformações.

Agora precisamos alterar o código da função initShaders() para colocar o endereço dessas três variáveis em nosso shader program. Para isso, acrescentamos essas três linhas ao final da função:

shaderProgram.projection = gl.getUniformLocation(shaderProgram, "uProjection"); shaderProgram.view = gl.getUniformLocation(shaderProgram, "uView");

shaderProgram.model = gl.getUniformLocation(shaderProgram, "uModel");

O último passo é fornecer as matrizes model, view e projection para o shader. Fazermos isso na função draw, antes de copiar os dados do buffer para a placa:

//Atualiza os valores do shader gl.uniformMatrix4fv(shaderProgram.projection, false, projection); gl.uniformMatrix4fv(shaderProgram.view, false, view);

gl.uniformMatrix4fv(shaderProgram.model, false, model);

Observe que aqui utilizarmos a função gl.uniformMatrix4fv. Essa função recebe três

parâmetros: O índice da variável do shader que será modificada, um boolean indicando se as coordenadas serão transformadas. Em webgl, esse valor deve ser sempre false. E o último parâmetro refere-se ao array contendo a matriz sendo atribuída.

O nome estranho dessa função segue a uma convenção, que data desde a OpenGL 1.0. O nome da função (uniformMatrix) é seguido da quantidade de parâmetros (4), seu tipo float (f) e o fato de ser um array (indicado pela letra v). Esse padrão é útil pois algumas funções vem em várias versões.

Após essas modificações, o seguinte resultado será obtido:

(11)

Download

Clique no ícone abaixo para fazer o download do código completo. Observe na pasta .js que o arquivo gl-matrix-min.js foi incluído no projeto. Trata-se da biblioteca gl-matrix. Esse arquivo também passou a ser referenciado no source do index.html.

Concluindo

Nesse artigo vimos como utilizar matrizes de transformação para posicionar objetos na cena, configurar nossa câmera. e nossa projeção. Vimos também como aplicar as transformações no Vertex Shader.No próximo artigo veremos como alterar nosso pixel shader para colorir o

Referências

Documentos relacionados

É de extrema relevância que os profissionais de saúde compreendam os fatores que influenciam a incidência de ISC para implementarem ações que possibilitem minimizar os

O objetivo do curso foi oportunizar aos participantes, um contato direto com as plantas nativas do Cerrado para identificação de espécies com potencial

CONCLUSÕES E PROPOSTAS PARA TRABALHOS FUTUROS Nesta dissertação, foi apresentada uma avaliação do desempenho das funções de proteção aplicadas em transformadores de potência,

Portanto, mesmo percebendo a presença da música em diferentes situações no ambiente de educação infantil, percebe-se que as atividades relacionadas ao fazer musical ainda são

Com a entrada em funcionamento daquele Balcão, a Lei n.º 31/2012, de 14 de agosto, passou a poder operar sem quaisquer restrições, assumindo especial relevância,

INIBIÇÃO DO CRESCIMENTO MICELIAL DE Colletotrichum acutatum POR EXTRATO AQUOSO E ÓLEO ESSENCIAL DE Cymbopogon citratus (DC) Stapf e Corymbia citriodora.. Hill

As pontas de contato retas e retificadas em paralelo ajustam o micrômetro mais rápida e precisamente do que as pontas de contato esféricas encontradas em micrômetros disponíveis

Esse traço, segundo o modelo auto-segmental (Clements and Hume, 1995), está preso à raiz e pode espraiar de forma autônoma. Temos então em 2, 3 e 4a fatos que ajudam a sustentar