Ponto V!

Home Matemática e Física Vetores: Guia de Referência
Vinícius Godoy de Mendonça
Vetores: Guia de ReferênciaImprimir
Escrito por Vinícius Godoy de Mendonça

Quando iniciamos com o uso de vetores, muitas vezes, não temos a intuição imediata de que operação vetorial utilizar para atingir determinado resultado. Por isso, elaborei esse pequeno guia, com algumas das operações mais comuns.

Esse texto pressupõe que você já entende o que são vetores e para que servem. Se não é esse seu caso, leia nosso artigo introdutório sobre vetores.

Parte 1: Velocidades e direções

 

Problema 1.1: Representação de Agentes 2D

Problema: Representar corretamente a posição e direção de um veículo, em ambientes 2D.

Solução:

  • Use um vetor para posição (Position);
  • Use um vetor unitário para direção e um float com a velocidade (Direction) ou
  • Use um vetor não unitário que representa ambos, direção e velocidade (Velocity).
  • Se o ator puder girar a cabeça, use um vetor unitário para indicar a direção para qual ele olha (Facing).

Exemplo:

public class Agent {
    public Vector2 Position { get; set;}
    private Vector2 Velocity {get; set;}

    public float Speed { 
        get {
            return Velocity.Length();
        }
    }

    public Vector2 Direction {
        get {
            return Vector2.Normalize(Velocity);
        }
    }
}

 

Problema 1.2: Posições relativas entre A e B sem considerar o giro de A

Problema: Muitas vezes gostaríamos de desenhar um objeto B, em uma posição relativa a um objeto A, considerando apenas a posição de A. Por exemplo, considere um game de nave, onde um escudo gire em torno da nave a uma velocidade fixa. Outro exemplo seria um game horizontal scroller, onde quiséssemos um escudo na parte frontal da nave.

Solução: Dado um vetor A.pos contendo a posição do centro do agente A. E um vetor representando o deslocamento relativo entre o centro de A até a posição desejada de B (offset), a posição final de B será dada pela a soma dos dois vetores.

image

Exemplo:

finalPos = B.offset + A.pos;

 

Problema 1.3: Posições relativas de A e B considerando o giro de A

Problema: Muitas vezes precisamos desenhar um objeto A em relação a outro objeto B, considerando a posição e a rotação de A. Um exemplo dessa situação seria posicionar um canhão rotatório num tanque de guerra.

Solução:

  • Criar um vetor com a posição relativa a partir do centro de A, desconsiderando a rotação;
  • Usar a matriz de transformação de A sobre esse vetor, antes de soma-lo a A.

Exemplo:

finalPos = A.pos + Vector2.Transform(a.Transform, B. relativePos);

 

Problema 1.4: Descobrir a direção que um agente A deve seguir para ir de encontro ao agente B / Descobrir a distância entre dois agentes

Problema: Temos dois agentes na tela, e queremos descobrir a direção entre os agentes A e B e/ou a distância entre eles.

Solução: Subtraia a posição do destino da posição da origem. O vetor resultante representa a trajetória entre eles. Seu comprimento representa a distância entre os dois agentes e sua direção representa o lado que um agente deve seguir para colidir com outro.

image

Exemplo:

Vector2 path = (A.Position – B.Position);
float distance = path.Length();
Vector2 directionToB = Vector2.Normalize(path);

No XNA a distância entre dois vetores pode ser calculada diretamente através da função Vector2.Distance.

 

Problema 1.5: Forçar um vetor a ter um determinado tamanho

Problema: Muitas vezes obtemos um vetor de direção, e gostaríamos de forçá-lo a ter um tamanho determinado, como por exemplo, a velocidade atual do nosso agente.

Solução: Normalize o vetor e multiplique pelo tamanho desejado.

Exemplo:

Vector2 A.Velocity = Vector2.Normalize(path) * A.Speed;

 

Problema 1.6: Criar um vetor com determinada direção e tamanho

Problema: Inicializar um vetor contendo uma direção e tamanho especificados. Isto poderia ser usado para, por exemplo, definir a direção e força do tiro de um canhão.

Solução: O vetor é criado através da fórmula V = (cos(a)*t, sen(a)*t), onde a é o ângulo e t o tamanho desejado.

Exemplo:

Vector2 NewBySizeAngle(float size, float angle) {
    return new Vector2(
        (float)Math.Cos(angle)*size,
        (float)Math.Sin(angle)*size);
}

 

Problema 1.7: Descobrir se um agente está à frente ou atrás de outro (2D)

Problema: Muitas vezes precisamos descobrir se um agente B está na parte à frente ou atrás do agente A. Observe que, quando os objetos giram, o conceito de “frente” e “trás” depende da direção do observador (A).

Solução:

  • Calcule o vetor de trajetória subtraindo a posição de B da posição de A;
  • Retire o produto escalar do vetor de direção de A, com a trajetória normalizada até B. Essa operação equivale ao cosseno entre A e a trajetória de B.
  • Se o resultado for maior que zero B estará à frente de A. Se for menor que zero, B estará atrás de A. E se for igual a zero, B estará na lateral exata de A.

Exemplo:

Vector2 pathNormal = (B.Position – A.Position);
pathNormal.Normalize();
bool isInFront = Vector2.Dot(A.Direction, pathNormal) > 0;

 

Problema 1.8: Calcular se um agente está no campo de visão de outro (2D)

Problema: Descobrir se o agente A pode ver o agente B.

Solução: Armazenar duas constantes contendo:

  1. O cosseno do ângulo de visão desejado;
  2. A distância máxima da visão.

Proceda da seguinte forma:

  • Calcule o vetor de trajetória subtraindo a posição de B da posição de A;
  • Retire o produto escalar do vetor de direção de A, com a trajetória normalizada até B. Ou seja, o cosseno entre A e a trajetória de B.
  • Se a constante a) for maior que o resultado obtido, o agente B estará fora do campo de visão, portanto, não estará visível;
  • Caso contrário, teste se distância máxima da visão é menor do que o tamanho do vetor da trajetória.

Otimização: Esse processo pode se tornar mais rápido se as distâncias estiverem ao quadrado.

Exemplo:

public bool canSee(Agent other)
    const float VISION_RADIANS = Math.cos(Math.ToRadians(45));
    const float VISION_DISTSQR = 50*50; //in pixels
    Vector2 path = (B.Position – A.Position);
    return VISION_RADIANS <= Vector2.Dot(A.Direction, Vector2.Normalize(path)) &&
           VISION_DISTSQR <= path.LengthSquared();
}

 

Problema 1.9: Deslocamento lateral em 2D

Problema: Achar o vetor de deslocamento lateral de um agente em 2D. Nesse caso, queremos calcular o vetor perpendicular à direção.

Solução: O vetor perpendicular, em 2D, é facilmente calculado da seguinte forma:

a) Inverte-se o valor de x e y;

b) Nega-se o valor de x para girar à esquerda, ou o valor de y para girar à direita.

Exemplo:

Vector2 perp = Vector2(A.Y, -A.X);

 

Problema 1.10: Deslocamento lateral em 3D (Strafe)

Problema: Achar o vetor de deslocamento lateral de um agente em 3D. Neste caso, precisamos do vetor de direção do agente, e do vetor up, que aponta para cima. O vetor de strafe é definido como o produto vetorial entre a direção e o vetor up normalizado.

Exemplo:

Vector3 strafe = Vector3.Cross(A.Direction, A.Up);
strafe.Normalize();

 

Parte 2: Física

 

Problema 2.1: Deslocar um agente numa velocidade constante

Solução: Multiplique o vetor de direção, unitário, pela velocidade desejada, e pelo tempo transcorrido em segundos (secs).

Exemplo:

float secs = (float)gameTime.ElapsedGameTime.TotalSeconds     
A.Position += A.Direction * speed * secs;

Note que direction * speed é o vetor Velocity, portanto, caso você tenha implementado o modelo descrito no Problema 1.1, bastaria fazer:

A.Position += A.Velocity * secs;

Veja o Problema 2.2 para um modelo físico levando em consideração a aceleração.

 

Problema 2.2: Movimentação Newtoniana simples

Problema: Em muitos games, é necessário uma forma simples que lembre a movimentação newtoniana no vácuo.

Solução: A forma abaixo considera a movimentação Newtoniana clássica no vácuo e um sistema de forças, que serão aplicadas ao corpo a cada game loop. A solução é leve o suficiente para ser usada em sistemas de partículas, e dá um bom resultado visual. Entretanto, para Steering Behaviors, considere o modelo proposto por Reynolds.

Você necessitará:

  • Um vetor considerando a direção em que o corpo está se movendo (Velocity). Na física, esse vetor também pode representar a energia de movimento acumulada, portanto, é comum que seja chamado de momentum.
  • A massa do veículo (mass);
  • Um vetor representando a posição do corpo (Position).
  • Uma função, que calcula a soma de todas as forças sendo aplicadas no corpo naquele Game Loop (calculateForces).
  • Um vetor representando a aceleração da gravidade (gravity);
  • O tempo transcorrido entre essa chamada de função e a última em segundos (secs);

O cálculo da posição é dado pela fórmula:

Pf = P0 + m * t + a * t² / 2

E a atualização do momento, que deve ocorrer a seguir, é dada por:

m = a * t;

Onde:

  • Pf = Posição final
  • P0 = Posição atual
  • m = Vetor de momento linear
  • t = tempo
  • a = Vetor aceleração

Exemplo:

double secs = (float)GameTime.ElapsedGameTime.TotalSeconds;
Vector2D acceleration = CalculateForces() / mass;
Vector2D accelSecs = acceleration * secs;
position += (momentum + accelSecs/2) * secs;
momentum += accelSecs;

 

Problema 2.3: Atração gravitacional simples

Problema: Calcular o vetor de força que representa a atração gravitacional entre dois agentes.

Solução:

  • Calcular o vetor de trajetória entre o objeto sendo atraído (B) e o objeto que atrai (A);
  • Calcular a intensidade da força gravitacional, através da fórmula:
    image
    Onde:
  1. Fg = Força da gravidade resultante
  2. G = Constante gravitacional universal. Na física real, equivale a 6,67428*10-11 m3/kg1s2. Em games, esse valor pode ser calibrado pelo game designer, para representar o quanto de “atratividade” ele gostaria para o planeta.
  3. m1 e m2: As massas dos agentes A e B, respectivamente
  4. d2: Distância ao quadrado entre o centro de massa dos dois corpos.
  • Multiplicar o resultado pela trajetória normalizada.

Exemplo:

public Vector3 calculateGravityForce(Planet a, Ship b) {
    Vector3 path = b.Position – a.Position;
    float intensity = (a.g * a.mass * b.mass) / path.LengthSquared();
    path.Normalize();
    path *= intensity;
    return path;
}

 

Problema 2.4: Reflexo, colisão elástica e colisão inelástica

Problema: Calcular o vetor resultante da colisão elástica de um objeto contra a superfície. Essa Fórmula também pode ser aplicada para o reflexo da luz contra um espelho perfeitamente plano.

Solução: Para o cálculo será necessário:

  • n: O vetor normal perpendicular à superfície. Esse vetor aponta para o local de onde o objeto vem;
  • I: O vetor de incidência (geralmente a Velocity do agente);

O cálculo é demonstrado pela figura:

image

Exemplo (reflexo e colisão elástica):

public Vector2 reflex(Vector2 incident, Vector2 normal) {
   return incident – 2*normal.dot(Incident)*normal;
}

No caso do XNA, a função Vector2.Reflex realiza essa operação.

Variação: Para colisão inelástica, substituir o valor 2 por (1+C) onde C é o coeficiente de restituição (um número de 0 até 1, indicando o percentual de força que é restituído).

Exemplo (colisão inelástica):

public Vector2 reflex(Vector2 incident, Vector2 normal, float restituion=1) {
   return incident – (1+restitution)*normal.dot(Incident)*normal;
}

Problema 2.4: Descobrir o vetor normal a partir dos vértices de uma face

Problema: Calcular automaticamente a normal de uma face, baseado na posição de seus vértices.

Solução:

  • Dados os três vértices, v1, v2 e v3, obter os vetores dos lados através da subtração de v3-v1 e v2-v1;
  • Obter o vetor perpendicular a face é obtido obtendo-se o produto vetorial entre os dois vetores resultantes.
  • Normalize o resultado.

O gráfico abaixo demonstra o cálculo:

image

Exemplo:

public Vector3 CalculateNormal(Vector3 v1, Vector3 v2, Vector3 v3) {
    Vector3 normal = Vector3.Cross(v2 – v1, v3 – v1);
    normal.normalize();
    return normal;
}

 

Finalizando

Nesse guia, procurei reunir as situações mais comuns para as primeiras aplicações envolvendo vetores. Logicamente, existem muitas outras situações em que os vetores seriam aplicáveis, especialmente se você decidir se aprofundar em computação gráfica ou física.  Entretanto, se você ainda não usa essa fantástica ferramenta matemática, espero que o texto torne seu caminho muito mais fácil a partir de agora.

Se você gostou desse artigo e gostaria de se aprofundar mais ainda, confira também nosso material sobre matrizes e transformações (parte1 e parte 2).

Em caso de dúvidas poste uma mensagem ou entre em contato!


Comentários (17)
  • Vitor Almeida da Silva  - Muito útil.
    avatar

    Realmente muito útil Vinícius, vai ajudar bastante gente.

  • Vinícius Godoy de Mendonça  - Obrigado
    avatar

    Obrigado, Victor.

  • Matheus
    avatar

    Excelente!!!

    Esse site é o melhor site dev nacional, por favor continuem assim!

    PS: Vocês precisam de algum tipo de ajuda finaceira (ex: para pagar o server)? Eu gostaria de contribuir!

  • Vinícius Godoy de Mendonça
    avatar

    Doações são sempre bem-vindas. Se quiser doar, mande um e-mail para o contato@pontov.com.br e te passamos as contas para o depósito. :)

  • Pigmeu
    avatar

    Sugestão:
    Coloca um botão do paypal pra galera doar, Vinícius! :D

  • Lucas  - Sensacional!
    avatar

    Muito obrigado por esse artigo, vai me ajudar demais com a minha engine :D.

  • Vinícius Godoy de Mendonça
    avatar

    De nada! :)

  • Victor Hugo Viana Santos
    avatar

    Qual matemática uso para programar shaders(GLSL)?
    E um pequena sugestão, vocês poderiam abordar o tema mais tarde.

  • Vinícius Godoy de Mendonça
    avatar

    Está nos meus planos fazer uma série sobre o pipeline programável em opengl. Por enquanto, você pode ler os artigos de shaders do Thiago Pastor na sessão de XNA. Ele explica a matemática envolvida no modelo de iluminação de Phong.

  • Bruno Crivelari Sanches
    avatar

    Só um detalhe: a matemática usada em shaders é 80% vetores, que você encontra vários artigos aqui no PontoV e o resto matrizes e matemática básica (sendo que matrizes você também encontra aqui)

    Os conceitos envolvidos depende do que você pretende fazer, mas os artigos de Shaders na sessão de XNA já cobrm todos os conceitos básicos de iluminação e alguns avançados, como Deferred Lighting. É só adaptar para a sintaxe do GLSL.

  • Renan  - Seno para Radianos
    avatar

    Muito bom o post , só tenho uma pergunta , que nao tem nada a ver com o post , voce poderia me responder se é possivel eu converter um valor de seno em radianos , por exemplo tenho o seno 0,7071067 (45º)
    em radianos ?

  • ViniGodoy  - Seno para radiano
    avatar

    Sim, nas classes que acompanhar o primeiro artigo de vetores existe o método toRadians. É possível fazer essa conversão com a classe MathUtil do C# ou com a classe Math do Java também.

  • Carlos Magno  - Conselho
    avatar

    Primeiramente meus parabéns pelo nível de qualidade dos conteúdos.
    Gostaria de saber se o aprendizado de Fisíca e Matemática é indispensável ou se as engines suprem TODA a falta de conhecimento dos mesmos?
    Pergunto isto pois, ao meu modo de ver, um programador de linguagens de alto nível cosnegue se virar muito bem mesmo sem quaisquer conhecimentos de linguagens de máquina.
    O conselho de vocês seria MUITO valioso, pois não sei se me dedico a reeaprender(e aprender tbem) física e matemática ou partir direto para a programação de jogos 2D.

    Desde já muito obrigado!

  • ViniGodoy
    avatar

    É indispensável, especialmente em jogos 3D.

    Pelo menos, o conceito de vetores e matrizes de transformação é. Você não precisa decorar como as operações são realizadas, mas deve saber exatamente o que fazem.

    Por exemplo, você não precisa saber montar de cabeça uma matriz de rotação, nem saber escrever o algoritmo que calcula a inversa. Mas é importante saber o que essas operações fazem e quando usa-las.

    As engines mais modernas usam fortemente o conceito de transformações. Você vai achar objetos de transformação Java (AffineTransform), em IOS (Transform), em Cocos2D, etc... Vai achar esses conceitos também em engines de física como a Box2D (a classe b2vec, por exemplo, representa um vetor).


    Em 3D, então, nem se fala. Se for usar uma engine 3D, por mais básica que seja, terá que ter um bom conhecimento de matemática.

  • Carlos Magno
    avatar

    Como imaginei...
    Bom, irei, antes de qualquer coisa, ler os livros Álgebra, Geometria 2D e Física da série Use a Cabeça(Por ter uma leitura descontraída e te colocar em uma perspectiva diferente), posteriormente desenvolver joguinhos sem quaisquer engines ou frameworks para ai então me considerar preparado? para o desenvolvimento "sério" de jogos em 2D.
    Em um futuro não tão distante quem sabe me aventurar no 3D.

    Muitíssimo obrigado, não só pela resposta e sim por tudo que fazem por todos!

  • Sarah  - Arquitetura
    avatar

    Qual a importância dos vetores na Arquitetura?

  • Alan  - JPlay
    avatar

    Vcs conhecem o framework JPlay da UFRJ? Não duvido nada que tenham sido vcs que a desenvolveram.

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2  

Busca

Linguagens

Twitter