Autor: Kabeção
GM3D 02 – Projeção e Movimento da Câmera
Assim como os olhos dos seres vivos projetam o ambiente para o cérebro, o jogo também deve ter algo que projete o espaço virtual ao jogador.
Nessa aula vou explicar como criar uma câmera que se movimenta com o mouse.
Essa parte é complicada tanto para aprender quanto para explicar.
Fiquem atentos.
A função d3d_set_projection_ext[/color]
Existem duas funções que usamos para definir como o mundo será visto:
- Código:
-
d3d_set_projection(xfrom,yfrom,zfrom,xto,yto,zto,xup,yup,zup);
d3d_set_projection_ext(xfrom,yfrom,zfrom,xto,yto,zto,xup,yup,zup,angle,aspect,znear,zfar);
A primeira á a forma simples e a segunda é a forma estendida da função. Iremos usar apenas a segunda.
Fazer com que entendam cada argumento será bem complicado, mas eu gosto que tudo seja explicado então prestem bastante atenção e façam testes com cada parâmetro..
- Código:
-
d3d_set_projection_ext(xfrom,yfrom,zfrom,xto,yto,zto,xup,yup,zup,angle,aspect,znear,zfar)
xfrom,yfrom,zfrom,xto,yto,zto – from significa “de” e to “para”. Os três primeiros argumentos são os pontos da câmera, ou seja, o lugar de onde se olha e os três últimos o lugar para onde esta se olhando. Por exemplo:
Você esta no quarto olhando para o computador. A posição dos seus olhos representam “xfrom,yfrom,zfrom” e a posição do computador representa “xto,yto,zto”.
xup,yup,zup – esses argumentos são definidos apenas como false ou true. Neles você especifica o eixo em que a projeção gira. Exemplo:
Você ainda está olhando para o computador.
Levante ou abaixe a cabeça. Pronto! Você acabou de girar a visão em torno do eixo y.
Agora mexa a cabeça para direita ou para a esquerda. Pronto! Você acabou de girar a visão em torno do eixo z.
Girar em torno do eixo x seria como rodar a cabeça em torno de si mesma olhando sempre pra fentre.
Marque como true os eixos que a câmera vai gira.
O padrão usado é “0,0,1”, ou seja, ira girar em torno do eixo z.
angle – este não tem nada a ver com o ângulo da visão e muita gente se confundi com ele. Aqui você deve definir a largura da câmera em graus. Exemplo:
As lentes dos óculos são medidas em graus lembra? Quanto maior o grau, mas as imagens são aumentadas.
Você já viu aquelas câmera que quanto se gira a lente o zoom aumenta ou diminui? Então! O efeito desse argumento é o mesmo.
Quanto maior o valor de angle, maior vai ser o zoom “natural” da projeção.
Um padrão razoável é 45° mas eu estou usando 90° em meus projetos.
aspect – defini o aspecto da tela. Não há muito o que explicar...
Se você esta usando uma dimensão de tela padrão (640x480, 1024x768...), qualquer valor sem ser a divisão desses tamanho causara distorção na imagem.
Defini-o como 640/480 ou simplesmente 1.3.
znear,zfar – de znear a zfar é a região que será desenhada pela câmera. Por exemplo:
znear é 1 e zfar é 10000. Tudo que estiver entre o pixel 1 e o pixel 10000 da projeção será desenhado. Tudo que estiver fora dessas coordenadas não será desenhando.
Nessa figura a primeira linha vertical representa o znear e a segunda linha vertical o zfar. Tudo o que há na parte azul será desenhado e tudo o que há na parte cinza não será desenhando.
O padrão é znear = 1 e zfar = 32000.
A função d3d_set_projection_ortho
[/color]
Se você quer desenhar coisas bidimensionais em modo 3D?
Então terá que usar isso.
Visão ortogonal nada mais é do que a projeção das imagens ignorando a profundidade delas, ou seja, o valor z.
Seria como desenhar um modelo 3D com todas as suas coordenadas z iguais a zero. Ele ficaria achatado. Sem profundidade.
Essa função é extremamente útil, pois podemos desenhar textos e imagens na tela sem dificuldades.
- Código:
-
d3d_set_projection_ortho(x,y,w,h,angle)
x,y,w,h – essa é a região ou tamanho da tela. Note que se for diferente do tamanho da view o que for desenhado na tela vai se esticar em relação a view.
angle – gira o que for desenhado. O ponto de origem é por padrão o meio da area que você definiu.
Para desenhar um texto na tela você pode fazer da seguinte forma:
- Código:
-
draw_set_color(c_black);
d3d_set_projection_ortho(0,0,view_width,view_height,0);
d3d_set_hidden(false);
draw_text(10,10,'FPS: ' + string(fps));
d3d_set_hidden(true);
Essa função deve vir sempre antes de d3d_set_projection_ext ou a cena não será desenhada direito.
Movimentando a câmera[/color]
Agora é hora de aprender como movimentar a câmera no mundo.
Vamos adicionar um exemplo de visão em terceira pessoa onde o personagem é totalmente enquadrado pela câmera no projeto da aula anterior. Depois explicarei como adaptar isso para primeira pessoa que é ver o mundo como se estiver com os olhos do personagem.
Abra a engine que começamos na aula 1. Você também pode baixar o source clicando aqui.
Crie um novo background que será a textura do chão.
Abra o obj1 e defina outra variável para a textura do chão:
- Código:
-
tex2 = background_get_texture(background1);
No evento Draw:
- Código:
-
d3d_draw_floor(0,0,0-16,room_width,room_height,0-16,tex2,5,5);
Isso vai desenhar um chão do tamanho da room e embaixo do cubo.
Agora abra o objCamera e vamos definir todos as variáveis necessários para controlar o movimento no evento Create:
- Código:
-
// Movimento da camera
z = 0; // ponto z
dx = 0; // armazena movimento x da câmera
dy = 0; // armazena movimento y da câmera
dz = 0; // armazena movimento z da câmera
px = 0; // ponto x para onde se esta olhando
py = 0; // ponto y para onde se esta olhando
pz = 0; // ponto z para onde se esta olhando
zoom = 400;
zang = 0; // angulo horizontal da camera
yang = 0; // angulo vertical da camera
// Definir posição do mouse
window_mouse_set(200,200);
// Sem cursor
window_set_cursor(cr_none);
Agora crie um evento Step e:
Primeiro deve-se achar os ângulos da câmera. É o movimento do mouse que vai modar os ângulos então precisamos saber o quanto e para onde ele esta se movendo.
- Código:
-
// Definindo angulos a partir do mouse
zang-=(window_mouse_get_x()-200)/8;
yang-=(window_mouse_get_y()-200)/8;
window_mouse_set(200,200);
yang=median(yang,-89,89);
zang é igual a posição x do mouse -200 dividido por 8. Isso retorna quantos pixels o mouse se moveu em x.
yang é igual a posição y do mouse -200 dividido por 8. Isso retorna quantos pixels o mouse se moveu em y.
O valor 8 é a sensibilidade do mouse. Quanto menor mais rápido o movimento vai ficar.
A função window_mouse_set defini a posição do mouse novamente depois de já achar os ângulos.
A ultima linha de código faz com que yang nunca passe de -89 a 89, ou seja, quanto a câmera estiver em cima ou embaixo do objeto seu ângulo vertical não mudará mais.
Já temos os ângulos vertical e horizontal definidos. Agora precisamos saber o quanto os pontos x,y e z da câmera teriam que mudar para que possa girar em torno do personagem.
- Código:
-
// Animação da camera
// calculando movimento dos vetores da camera
dx=cos(degtorad(zang));
dy=-sin(degtorad(zang));
dz=tan(degtorad(yang));
// normalizar vetores
// torna movimento da camera totalmente esferico.
m=sqrt(sqr(dx)+sqr(dy)+sqr(dz));
dx/=m;
dy/=m;
dz/=m;
Coseno, seno e tangente são operações matemáticas para achar pontos de acordo com um ângulo.
Convertemos os graus em radianos com a função degtorad(ang).
cos retorna quantos pixels o x terá que se mover para estar naquele ângulo.
sin retorna quantos pixels o y terá que se mover para estar no mesmo ângulo que x (ângulo vertical).
E tan retorna quantos pixels o z terá que se mover para estar de acordo com o ângulo vertical.
Por ultimo em tenho que normalizar dx, dy e dz para que o movimento gire de forma perfeitamente esférica em torno do personagem.
Não tem muito o que explicar disso. Aquilo é uma operação para não deixar que o zoom mude automaticamente dependendo do ângulo.
A parte complicada já foi.
Agora é só definir as novas coordenadas da câmera de acordo com dx, dy e dz.
- Código:
-
// Calculando posição da camera no mundo
x = obj1.x+dx*zoom;
y = obj1.y+dy*zoom;
z = obj1.z+dz*zoom;
// Zoom
if keyboard_check(vk_add) zoom += 4;
if keyboard_check(vk_subtract) zoom -= 4;
Ao multiplicar os valores que acho com cos, sin e tan eu estou adicionando uma distancia ao movimento. Essa distancia é o zoom que vale 400 pixels. A câmera ficará a 400 pixels do personagem.
Adicionei também algo para aumentar e diminuir o zoom apertando “+” ou “-“ no teclado.
Finalize o código do evento Step definindo o lugar para onde o câmera vai olhar que no caso é a posição do obj1.
- Código:
-
// Movimento no personagem
px = obj1.x;
py = obj1.y;
pz = obj1.z;
Abra o evento Draw do objCamera, apague o código lá e defina uma nova projeção:
- Código:
-
d3d_set_projection_ext(x,y,z,px,py,pz,0,0,1,90,1.3,1,32000);
Adicione um movimento simples para o obj1. Crie um evento Step nele:
- Código:
-
if keyboard_check(ord('W')) y -= 4;
if keyboard_check(ord('S')) y += 4;
if keyboard_check(ord('A')) x -= 4;
if keyboard_check(ord('D')) x += 4;
Pra finalizar defina a velocidade da room como 60.
Se você quiser fazer um visão em terceira pessoa é simples.
Basta inverter os pontos xfrom, yfrom, zfrom, xto, yto, zto.
- Código:
-
d3d_set_projection_ext(px,py,pz,x,y,z,0,0,1,90,1.3,1,32000);
Não se esqueça de tirar o código que desenha o cubo porque senão a visão vai ficar tampada pela parte de dentro do cubo.
Esse exemplo pronto pode ser baixado clicando aqui.
A próxima aula será sobre como fazer um movimento mas detalhado, animação simples como pulos e noção de como mexer com transformações em D3D que são usadas principalmente para rotacionar os objetos.
Até mais.