Curso Professional

518
Curso Professional Lucas Euzébio Machado

description

Curso Professional. Lucas Euzébio Machado. Tópicos do Curso. C++, Algoritmos e Estruturas de Dados (36) Computação Gráfica (36) Programação Distribuída (6) Física (6) Inteligência Artificial (6) Fundamentos de Programação de Jogos (6) Projeto Final (24). - PowerPoint PPT Presentation

Transcript of Curso Professional

Page 1: Curso Professional

Curso Professional

Lucas Euzébio Machado

Page 2: Curso Professional

Tópicos do Curso

C++, Algoritmos e Estruturas de Dados (36) Computação Gráfica (36) Programação Distribuída (6) Física (6) Inteligência Artificial (6) Fundamentos de Programação de Jogos (6) Projeto Final (24)

Page 3: Curso Professional

Tópicos para C++, Algoritmos e Estruturas de Dados

Variáveis, Ponteiros, Referência, Alocação e Liberação de Memória Testes de condições Loops Funções Módulos, Compilação e Link-Edição Orientação a Objetos Classes e Structs Encapsulamento, Herança e Polimorfismo Construtores e Destrutores Exceções Funções e Variáveis estáticas Recursão Lista Encadeada, Fila e Pilha Árvore Binária Grafo Hashtable Templates Operator Overloading Lendo e Gravando Arquivos Multithreading

Page 4: Curso Professional

Variáveis

Page 5: Curso Professional

Ponteiros

Ponteiros são variáveis que armazenam endereços de memória.

Page 6: Curso Professional

Variáveis de referência

Referências servem como um segundo nome para um objeto. Elas permitem acesso indireto de forma semelhante a ponteiros.

Page 7: Curso Professional

Alocação de Memória

Para alocar memória da heap:

Page 8: Curso Professional

Liberando memória

Page 9: Curso Professional

Vetores

Vetores são agregações de elementos de um mesmo tipo que ocupam a memória de forma sequencial e adjacente.

Page 10: Curso Professional

Vetores

Uma variável vetor armazena na realidade o endereço de memória do primeiro elemento do vetor.

Page 11: Curso Professional

Vetores

Vetores podem ser multidimensionais

Page 12: Curso Professional

Testes de Condições

Page 13: Curso Professional

Testes de Condições

Page 14: Curso Professional

Loops

Instruções usada para causar repetições de trechos de código

Page 15: Curso Professional

Loops

Page 16: Curso Professional

Exercício

Crie um programa que gera um buffer de inteiros de 10 posições. Cujos valores sofrem um decremento de 10 até 1.

Adicione um trecho de código que busca pelo numero 4 no vetor e salva o endereço da posição do vetor em um ponteiro.

Page 17: Curso Professional

Exercício

Crie um programa que crie uma matriz 4x4 identidade usando um buffer bidimensional.

Page 18: Curso Professional

Funções

Funções são subprogramas que realizam operações definidas por usuários.

Ferramenta fundamental para redução de complexidade e reuso de código.

Em qualquer projeto, funções serão utilizadas sem que se conheça suas implementações internas.

Page 19: Curso Professional

Funções

Page 20: Curso Professional

Exercício

Crie uma função que adiciona dois vetores de 4 elementos e retorna o resultado em um terceiro vetor

Page 21: Curso Professional

Módulos, Compilação e Link-Edição

Módulos permitem a divisão de um sistema em diferentes partes, cada uma responsável por uma tarefa específica.

Um módulo para nós será definido como um .h e um .cpp.

O arquivo .h possui declarações. O arquivo .cpp possui implementações.

Page 22: Curso Professional

Exemplo de um modulo

Vector3.h

Vector3.cpp

Page 23: Curso Professional

Usando um módulo

Page 24: Curso Professional

Usando Módulos

Ao usar include é incluído todo o arquivo de texto na linha chamada.

Page 25: Curso Professional

Compilação

Ao compilar um arquivo de implementação .cpp é gerado um arquivo .obj com código binário e tabelas com referências externas ainda não resolvidas e símbolos públicos.

Page 26: Curso Professional

Link-Edição

A link edição resolve referências externas e junta todo o código em um só código binário gerando assim o arquivo executável.

Page 27: Curso Professional

Exercício

Implemente um módulo Vector4.h e Vector4.cpp que possui as funções de adição, subtração e multiplicação de vetores de 4 elementos e salvando o resultado em um outro vetor.

Crie um arquivo .cpp com a main e inclua o header do Vector4.h. Compile ambos arquivos .cpp e gere o executável.

Page 28: Curso Professional

Orientação a Objeto

Um objeto é uma entidade(podendo se basear em algo concreto ou abstrato) que possui um comportamento ou representa algo.

Você interage com um objeto através de uma interface formada por funções. Isso permite uma interação bem comportada.

A divisão de um sistema em objetos permite uma enorme redução em complexidade e aumento em reusabilidade.

Page 29: Curso Professional

Exemplo de um sistema dividido em objetos

Page 30: Curso Professional

Classes

Objetos são representados em software através de classes

Page 31: Curso Professional

Encapsulamento

Apenas os membros públicos de uma função podem ser acessados por outros objetos.

Page 32: Curso Professional

Encapsulamento

Fundamental para redução de complexidade. Você chama um método de uma classe e um

problema é resolvido para você. Não há necessidade de saber como o problema foi resolvido.

Permite interação comportada. Como você controla o acesso às variáveis através de funções não é possível partes externas do programa agirem de forma errada com suas variáveis.

Page 33: Curso Professional

Exercício

Implemente a classe AIManager. Essa classe possui duas funções. AddObject e Think. A função AddObject recebe uma string com um nome, uma posição x e uma posição y. A função Think mostra na tela os objetos adicionados.

Page 34: Curso Professional

Herança

Certos objetos compartilham características porém possuem particularidades suficientes de forma que precisam de novos objetos para serem apropriadamente representados.

Page 35: Curso Professional

Herança

Page 36: Curso Professional

Herança

O objeto Person e o objeto Stone são ambos objetos de cena que podem ser desenhados na tela. Então ambos podem pertencer à mesma classe de objetos SceneObject.

Se por exemplo um SceneObject possuir uma posição 3d. Tanto Person quanto Stone possuirão essa variável de posição pois a posição é uma variável que existe em todo objeto da classe SceneObject.

Page 37: Curso Professional

Herança

Page 38: Curso Professional

Exercício

Reimplemente o exercício anterior fazendo o AIManager ter funções para adicionar Dragon e Orc que são classes derivadas de AIEntity. A classe AIEntity possui membros públicos para armazenar um nome e uma posição x e y.

A classe Dragon tem uma string com o tipo de baforada do dragão e a classe Orc possui um inteiro que indica a arma sendo usada.

Implemente a função Think para tratar dos tipos específicos e desenhar suas partes específicas.

Page 39: Curso Professional

Polimorfismo

Quando um conjunto de classes deriva de uma mesma classe base, todo o conjunto compartilha uma interface.

É possível escrever partes de código levando em consideração apenas classes base de determinados objetos.

Isso é vantajoso para aumentar o reúso no código.

Page 40: Curso Professional

Polimorfismo

Page 41: Curso Professional

Polimorfismo

Page 42: Curso Professional

Exercício

Reimplemente o AIManager para receber objetos AIEntity. Crie uma função virtual pura em AIEntity chamada Think que imprime os dados da entidade. Faça a classe Orc e Dragon implementarem a função Think.

Mude o AIManager para fazer uso das funções Think dos objetos.

Page 43: Curso Professional

Construtores e Destrutores

Construtores são métodos de uma classe chamada para “construir” a classe. Todo objeto criado tem seu construtor chamado.

Page 44: Curso Professional

Construtores e Destrutores

É possível definir diferentes tipos de construtores

Page 45: Curso Professional

Construtores e Destrutores

Destrutores fazem o trabalho inverso dos construtores. Eles fazem a destruição do objeto, liberando recursos adquiridos como memória alocada, arquivos abertos, etc.

Page 46: Curso Professional

Construtores e Destrutores

Em classes base use destrutores virtuais. Ao deletar um objeto usando um ponteiro base o comportamento é indefinido caso o destrutor da classe base não seja virtual.

Page 47: Curso Professional

Exceções

Eventos anormais são normais. Programas executam normalmente até que

algum problema ocorra como falta de memória, acesso à uma área de memória ilegal, etc etc etc etc etc etc etc etc etc etc.....

É possível testar esses problemas ou exceções usando ifs ou fazendo uso de ferramentas de C++ criadas específicamente para tratar de exceções.

Page 48: Curso Professional

Exceções

Ao detectar uma anomalia, você gera uma exceção através da operação throw.

Page 49: Curso Professional

Exceções

Um exceção é uma classe

Page 50: Curso Professional

Exceções

Para capturar uma exceção deve-se usar o operador try e catch.

Page 51: Curso Professional

Exercício

Implemente uma classe chamada Buffer que cria um buffer de ints. A classe possui um construtor que recebe o número de elementos, e um destrutor que destroi os elementos.

A classe possui também um função Add que recebe um vetor de ints pra adicionar ao buffer e uma função Remove que recebe n e remove n elementos de buffer.

Jogue exceções caso sejam adicionados mais elementos do que o Buffer suporta ou sejam removidos mais elementos do que existem no buffer.

Page 52: Curso Professional

Funções e Variáveis Estáticas

Apesar de todo o perigo, às vezes acesso à informações globais é necessário e até simplifica designs.

Todos os objetos com um membro estático compartilham a mesma instância desse membro. Ou seja, se um objeto altera a variável estática, isso será visível por todos os outros objetos da mesma classe.

Page 53: Curso Professional

Declarando membros estáticos

Page 54: Curso Professional

Usando membros estáticos

Page 55: Curso Professional

Usando membros estáticos

Page 56: Curso Professional

Variáveis estáticas e constantes

Page 57: Curso Professional

Exercício

Implemente uma classe que possui internamente uma variável estática ponteiro do tipo da própria classe.

Inicialize essa variável para NULL Implemente uma função estática da classe chamada

GetInstance que retorna a variável quando o ponteiro é diferente de NULL, se o ponteiro for NULL é alocada memória para a variável e seu endereço é armazenado no ponteiro.

Page 58: Curso Professional

Recursão

A recursão é uma forma de solucionar certos problemas que envolve fazer uma função chamar a si mesma para resolver o problema.

Page 59: Curso Professional

Exemplo

Page 60: Curso Professional

Exercício

Implemente uma função recursiva que busque em um vetor de inteiros ordenado crescentemente por um determinado valor.

A função deve retornar o índice do valor ou , -1 caso o valor não seja encontrado.

Page 61: Curso Professional

Busca Binária

Page 62: Curso Professional

Complexidade de Algoritmos

Complexidade não é de difícil de entender ... é de difícil de computar.

É nossa missão encontrar os algoritmos mais eficientes para resolver algum problema.

Os algoritmos mais eficientes para resolver algum problema são chamados de algoritmos ótimos.

Page 63: Curso Professional

Complexidade da Busca Linear

No pior caso, é necessário realizar n testes para achar (ou não) um valor.

É usada uma notação O(n) para representar o algoritmo busca linear.

O(n) ~= se você colocar n elementos como input, o custo da função é uma função linear.

Page 64: Curso Professional

Complexidade da Busca Binária

Teste 1 = n elementos Teste 2 = n / 2 elementos Teste 3 = n / 4 elementos Teste final quando você tem 1 elemento. Dado n elementos, quantos testes são feitos? Temos que achar i quando n/2^i = 1. n/2^i = 1 -> n = 2^i log n = log 2^i Log n = i Complexidade = O(log n) Busca binária é melhor que busca linear.

Page 65: Curso Professional

Lista Encadeada, Fila e Pilha

As vezes, não é possível saber o número máximo de elementos que serão adicionados à uma classe.

Quando isso acontece é necessário criar uma estrutura capaz de crescer de acordo com a necessidade.

Lista Encadeada, Fila e Pilha são estruturas de dados fundamentais usadas em diversos algoritmos.

Page 66: Curso Professional

Lista Encadeada

A lista encadeada é uma lista criada dinamicamente que se liga através de ponteiros.

Page 67: Curso Professional

Lista Encadeada - implementação

Uma classe consiste na lista em si. A classe da lista usa outra classe que

representa os nós da lista. Cada nó armazena os dados e o ponteiro para o próximo nó da lista.

O último nó aponta para NULL. A classe da lista aponta para o primeiro

elemento da lista.

Page 68: Curso Professional

Exercício

Implemente uma lista encadeada cujos nós armazenam posições x,y e z em floats e possuem também um id inteiro.

Crie um método na classe para adicionar elementos no final da lista.

Crie método na classe para buscar um nó dado um inteiro, o método deve retornar as posições x, y e z.

Crie um método para imprimir toda a lista.

Page 69: Curso Professional

Lista Encadeada

Page 70: Curso Professional

Lista Encadeada

Page 71: Curso Professional

Fila

Implementada de maneira semelhante à lista encadeada, porém elementos só podem ser inseridos no final e removidos na frente.

Funciona em forma FIFO (First In First Out). Imagine uma fila de cinema!

Page 72: Curso Professional

Pilha

Também implementada de maneira parecida com a lista encadeada porém sua operação é LIFO (Last In First Out).

A pilha mantém um ponteiro para o seu topo. Quando se deseja adicionar um elemento realiza-se um push adicionando um elemento ao topo da lista, quando se deseja remover um elemento, faz-se um pop, removendo o elemento do topo.

Page 73: Curso Professional

Exercício

Implemente uma pilha. A pilha possui um ponteiro chamado top que aponta para o topo da pilha.

Crie o método push que adiciona um elemento ao topo da pilha.

Crie o método pop que remove o elemento do topo da pilha.

Crie o método print para imprimir a pilha.

Page 74: Curso Professional

Árvore Binária de Busca

Estrutura de dados semelhante à uma arvore invertida onde cada nó possui até 2 filhos.

Cada nó possui um id, um ponteiro para o filho esquerdo e um ponteiro para o filho direito.

Cada nó possui a seguinte característica, o filho a esquerda possui um id menor que o id do nó e o filho a direita possui um id maior que o id do nó.

Page 75: Curso Professional

Árvore Binária de Busca

A busca por um valor possui um custo O(h). Se a árvore estiver desbalanceada isso pode

representar O(n) Se a árvore estiver balanceada isso pode

representar O(log n) Uma árvore balanceada é uma árvore em que para

todo nó, suas subárvores à esquerda e à direita diferem no máximo em 1 na altura. Considere uma subárvore vazia como de altura -1.

Folha é um nó sem filhos.

Page 76: Curso Professional

Árvore Binária de Busca

Através de uma árvore balanceada é possível achar uma árvore perfeita de mesma altura.

Árvore perfeita é uma árvore em que todas as folhas possuem a mesma altura e todos os nós possuem 2 ou 0 filhos.

Número de elementos da árvore completa = Somatório(2^i, i varia de 0 até a altura).

n = 1 * (2^(h+1) – 1) / 2 – 1 (somatório de progressão geométrica) n = 2^(h+1) – 1 n + 1 = 2^(h+1) log(n+1) = h + 1 log(n+1) – 1 = h Logo a altura de uma árvore balanceada é um logaritmo de n ... O que

é muito bom!!!!

Page 77: Curso Professional

Exercício

Implemente uma árvore binária onde os nós possuem um id inteiro e armazenam um valor inteiro.

Implemente o método de busca por um id. Implemente o método de busca pelo maior

elemento. Implemente o método de adição de elementos. Implemente o método que desenha na tela os

valores dos nós de maneira ordenada crescentemente por id.

Page 78: Curso Professional

Grafo

Grafos são uma estrutura de dados onde um nó pode apontar para um número qualquer de outros nós.

Grafos podem ser cíclicos se possuirem referências que façam um ciclo (como um filho apontando para um pai).

Caso não existam referências cíclicas, o grafo é definido acíclico e se assemelha à uma árvore n-ária, onde cada nó possui n filhos.

Page 79: Curso Professional

Grafos Acíclicos – Uma Implementação

Cada grafo possui um ponteiro para o pai e uma estrutura de dados(lista encadeada, vetor) que armazena os ponteiros para os filhos.

Se assemelha a uma árvore n-ária.

Page 80: Curso Professional

Exercício

Implemente um grafo acíclico que armazena seus filhos em uma lista encadeada.

Para isso implemente uma classe GraphNode que possui os métodos AddChild e Print. Coloque os GraphNodes possuindo um inteiro internamente.

AddChild adiciona um filho ao nó. Print imprime os nós do grafo. Construa um grafo e o imprima.

Page 81: Curso Professional

Hash Table

É uma estrutura de dados que permite acessos em O(1) .... Ou seja ... Muito rápidos.

Para adicionar um elemento, é utilizada uma chave que identifica o elemento.

Através dessa chave, é calculada a posição do elemento (essa posição geralmente é um índice de um vetor).

A função que pega essa chave e calcula uma posição é chamada de função de hash.

Page 82: Curso Professional

Hash Table - Exemplo

Para armazenar objetos é usado um vetor onde cada elemento desse vetor é um ponteiro para um objeto.

A chave é um inteiro. A posição é calculada achando o resto da divisão da

chave pelo tamanho do vetor de ponteiros. ( index = chave % tam_vec; )

Quando uma chave gerar uma posição que já contém um objeto, outra estrutura de dados é utilizada para salvar os objetos (lista encadeada, arvore binária de busca, outra lista encadeada).

Page 83: Curso Professional

Exercício

Implemente uma hash table com as mesmas características do exemplo anterior. Para salvar objetos na mesma posição do vetor de ponteiros utilize uma lista encadeada.

Crie uma função de inserção que recebe a chave e o objeto e o salva na hash table.

Crie uma função de search que procura pelo objeto dada uma chave.

Page 84: Curso Professional

Template

Templates são como receitas para criar classes que recebem um ou mais tipos como parâmetros.

São úteis para reaproveitar algoritmos em diferentes tipos de dados.

Page 85: Curso Professional

Template

Page 86: Curso Professional

Template

Toda vez que um template é utilizado para um determinado tipo, é criado o código da classe para fazer uso daquele tipo.

Então no exemplo anterior, são criadas 2 classes com a mesma lógica porém só com os tipos int e float diferentes.

Como as classes são geradas em tempo de compilação, é necessário saber a implementação de todos os métodos de cada template. Se um template define seus métodos em um .cpp, outras classes não serão capazes de ver essa implementação e criar as novas classes (você provavelmente terá problemas de link-edição). Por esse motivo, geralmente os templates são criados completamente no .h (incluindo a implementação das funções).

Page 87: Curso Professional

Exercício

Crie uma lista encadeada que consegue armazenar qualquer tipo usando um template.

Page 88: Curso Professional

Operator Overloading

Operadores como +, - , [] , == , etc, podem ter seu comportamento redefinido nas classes.

Isso facilita a programação usando determinados tipos (ex: vetores 3d, strings).

Page 89: Curso Professional

Operator Overloading - Exemplo

Page 90: Curso Professional

Exercício

Implemente uma classe String. Faça overload do operador = que recebe um vetor

de caracteres e armazena na string. Faça overload do operador += que recebe um vetor

de caracteres e adiciona os caracteres ao final da string.

Faça overload do operador == que recebe um ponteiro para caracteres constantes (const char*)

Page 91: Curso Professional

Lendo e Gravando Arquivos

Para ler ou gravar arquivos é necessário criar uma variável ponteiro para FILE. É preciso incluir o stdio.h.

Para abrir um arquivo, usa-se a função fopen da seguinte forma– FILE* fopen(path do arquivo, tipo de abertura)

Page 92: Curso Professional

Lendo e Gravando Arquivos

O tipo de abertura de fopen pode definir diferentes formas de abertura do arquivo:– “r” : abre o arquivo para leitura.– “w”: abre o arquivo para escrita. Se o arquivo já

existir, seu conteúdo é destruído.– “a”: abre o arquivo permitindo a escrita ao final do

arquivo.

Page 93: Curso Professional

Lendo e Gravando Arquivos

Para a escrita de arquivos, usa-se a função fwrite que possui o seguinte protótipo:– size_t fwrite(const void* buffer, size_t size, size_t

count, FILE* stream)

Page 94: Curso Professional

Lendo e Gravando Arquivos

Para ler dados de arquivos, usa-se a função fread:– size_t fread(void* buffer, size_t size, size_t count,

FILE* stream)

Page 95: Curso Professional

Lendo e Gravando Arquivos

Para fechar arquivos usa-se fclose– int fclose(FILE* stream)

Page 96: Curso Professional

Lendo e Gravando Arquivos

Page 97: Curso Professional

Exercício

Crie um programa que salve as seguintes informações do jogador:

Estágio atual Nome do personagem Nível do Personagem Posição x, y e z do personagem E depois crie um outro programa que lê

esses dados e mostra na tela!

Page 98: Curso Professional

Multithreading

Multithreading permite a criação de trechos de código que executam paralelamente.

Se houver um único processador na máquina, as threads concorrem pelo processador.

O sistema operacional dá um time slice para cada thread. Ao término do time slice, o SO interrompe a execução da thread e coloca outra thread para processar.

Page 99: Curso Professional

Multithreading

Isso é útil em máquinas com múltiplos processadores por permitir processamento paralelo.

É útil também quando existem operações que podem bloquear e não é desejável que o sistema bloqueie por essas operações (ex: bloqueio enquanto uma leitura de um arquivo grande é realizada).

Page 100: Curso Professional

Multithreading

Para criar uma thread, utilizar a função _beginthread (incluir o process.h):– uintptr_t _beginthread(função da thread, tamanho

da pilha, ponteiro para a lista de parâmetros)

Page 101: Curso Professional

Multithreading

Page 102: Curso Professional

Multithreading

Variáveis que são acessadas por diferentes threads correm o risco de se tornarem corrompidas.

Imagine um programa onde existe uma lista de jogadores. Uma thread está adicionando um jogador na lista e outra thread está removendo outro jogador da lista. Pode acontecer da lista acabar com um dos jogadores apontando para lixo e até coisas piores.

Por isso é necessário usar funções que permite acesso à regiões críticas.

Page 103: Curso Professional

Multithreading

Para proteger regiões acessadas por múltiplas threads utilize CRITICAL_SECTION (inclua windows.h)

Use a API InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection e DeleteCriticalSection para usar regiões críticas.

Page 104: Curso Professional

Multithreading

Page 105: Curso Professional

Exercício

Crie uma aplicação com 2 threads adicionais. 1 thread incrementa um contador e o imprime na tela 1 thread decrementa esse mesmo contador e o

imprime na tela. Cada thread repete esse processo 50 vezes. A main thread fica em espera ocupada esperando as

threads terminarem. No final ela imprime THE END. Faça testes usando critical sections e sem usar

critical sections.

Page 106: Curso Professional

Tópicos para Computação Gráfica

Aplicações Win32 Pipeline gráfico do Direct3D e Dispositivo Direct3D Buffer de Vértices e Índices Effect Files, Vertex Shaders e Pixel Shaders com Cg Renderizando triângulos Matrizes e Transformações Sistemas de Coordenadas e o Processo de Visualização Renderizando triângulos com perspectiva Renderizando triângulos texturizados Produto Escalar Iluminação Renderizando Objetos com Iluminação por pixel Exportando e carregando modelos de arquivos .X (e renderizando!) Animação usando interpolação entre Key Frames Alpha Blending Volumes de Sombras Bump Mapping Grafos de Cena Culling em cenários usando Octrees

Page 107: Curso Professional

Programando aplicações Win32

Para criar uma aplicação Win32 é preciso incluir o windows.h

O processamento em aplicações Win32 começa na WinMain.

Page 108: Curso Professional

Programando aplicações Win32

hinstance é um handle. Um handle é simplesmente um número que identifica alguma coisa. hinstance é um identificador da aplicação. Esse parâmetro é necessário para alguma funções.

hprevinstance é um parâmetro não mais utilizado e é definido como 0.

cmdline é a linha de comando usada para rodar o programa.

cmdshow indica como o programa deveria ser inicialmente mostrado.

Page 109: Curso Professional

Programando aplicações Win32

Para criar a janela da aplicação é preciso instanciar e preencher a struct WNDCLASS que possui a seguinte cara.

Page 110: Curso Professional

Programando aplicações Win32

Page 111: Curso Professional

Programando aplicações Win32

style: define propriedades da janela. CS_VREDRAW fazem com que a janela seja redesenhada caso haja uma mudança na altura da janela.

lpfnWndProc: recebe a função que trata os eventos enviados para a janela de sua aplicação.

cbClsExtra: número de bytes extras para alocar para a windows class struct. cbWndExtra: número de bytes extras além das instância da janela. hInstance: handle da aplicação. hIcon: handle do ícone usado. hCursor: handle do cursor usado. hbhBackground: handle do pincel usado para pintar o background da janela. lpszMenuName: um nome que identifica o recurso de menu usado na

aplicação. lpszClassName: especifica o nome dessa classe de janela.

Page 112: Curso Professional

Programando aplicações Win32

Após definir as características da classe de janela, é preciso registrá-la.

Page 113: Curso Professional

Programando aplicações Win32

Após o registro da classe de janela, é preciso criar a janela e mostrá-la.

Page 114: Curso Professional

Programando aplicações Win32

Após criar a janela é necessário entrar no loop de captura e envio de mensagens. Nesse loop também são colocadas funções para executar o jogo.

Page 115: Curso Professional

Programando aplicações Win32

A última parte que falta é a parte da função de tratamento de eventos

Page 116: Curso Professional

Exercício

Junte todo o código mostrado e crie uma aplicação win32.

Implemente a aplicação para mostrar a posição x e y do mouse quando o botão esquerdo é pressionado.

Quando a tecla pra cima é pressionada mostrar também.

Page 117: Curso Professional

Dispositivo Direct3D

API Gráfica do DirectX Permite acesso à placas de aceleração

gráfica de maneira única e independente do dispositivo.

Page 118: Curso Professional

Pipeline Gráfico do Direct3D

Page 119: Curso Professional

Pipeline Gráfico do Direct3D

Vertex Data: Dados geométricos dos objetos 3D do cenário. Por exemplo, as posições dos vértices do objeto 3D.

Fixed Function Pipeline: Uma sequência de processamento fixa do Vertex Data. As alterações nessa sequência de processamento são pouco flexíveis.

Programable Pipeline: Se usado, permite a implementação de um programa que processa os vértices. Permite muita mais flexibilidade de processamento dos vértices.

Page 120: Curso Professional

Pipeline Gráfico do Direct3D

Clipping: Esse estágio recorta todas as partes dos triângulos que estão para fora da tela.

Page 121: Curso Professional

Pipeline Gráfico do Direct3D

Back Face Culling: Elimina os triângulos que estão de “costas para a câmera”. Esse estágio elimina triângulos não visíveis em objetos fechados.

Page 122: Curso Professional

Pipeline Gráfico do Direct3D

Rasterization: Nesse estágio, os triângulos são desenhados.

Page 123: Curso Professional

Pipeline Gráfico do Direct3D

Pixel Shader: Se usado, permite ao programador criar um processamento que executa a cada pixel desenhado. Permite grande flexilidade sobre a forma como os pixels são renderizados.

Texture Sampler: Esse estágio, se usado, captura amostras das textura para serem usadas no Pixel Shader.

Page 124: Curso Professional

Pipeline Gráfico do Direct3D

Alpha Test: Esse estágio permite configurar a aceitação de um pixel de acordo com o seu alpha.

Depth Test: Esse estágio permite configurar a aceitação de um pixel de acordo com a sua profundidade.

Stencil Test: Esse estágio permite configurar a aceitação de um pixel de acordo com o Stencil Buffer.

Page 125: Curso Professional

Pipeline Gráfico do Direct3D

Fogging: Esse estágio permite configurar fumaça na cena a medida que os objetos se distanciam.

Alpha Blending: Esse estágio permite que o pixel sendo renderizado seja combinado com o pixel já desenhado no buffer de cor que será apresentado na tela.

Page 126: Curso Professional

Pipeline Gráfico do Direct3D

A geometria dos modelos e cenários passa pelo pipeline do Direct3D e ao final é gerada uma imagem 2D do objeto 3D, que é mostrada na tela.

Page 127: Curso Professional

Integração de Sistemas

Page 128: Curso Professional

Sistemas de Coordenadas

Direct3D usa o sistema de coordenadas da mão esquerda.

Page 129: Curso Professional

O objeto Direct3D

É o primeiro objeto a ser criado e o último a ser liberado.

Page 130: Curso Professional

O dispositivo Direct3D

Objeto principal de renderização. É com esse objeto que passamos a

geometria de modelos para a placa gráfica.

Page 131: Curso Professional

Criando um dispositivo Direct3D

Preencher D3DPRESENT_PARAMETERS

Page 132: Curso Professional

Criando um dispositivo Direct3D

BackBufferWidth, BackBufferHeight: Largura e altura do Backbuffer. BackBufferFormat: Formato do backbuffer. BackBufferCount: Número de Backbuffers. MultiSampleType e MultiSampleQuality: Parâmetros usados para antialiasing. SwapEffect: Maneira como o backbuffer vira o front buffer. hDeviceWindow: handle da janela Windowed: Se a aplicação vai rodar em janela ou full screen. EnableAutoDepthStencil: Permissão se o Direct3D pode gerenciar o seu buffer

de depth e stencil. AutoDepthStencilFormat: O formato do buffer de depth e stencil. Flags: ... FullScreen_RefreshRateInHz: A taxa com que o monitor é atualizado. PresentationInterval: A taxa com que o backbuffer pode ser apresentado na

tela.

Page 133: Curso Professional

Criando um dispositivo Direct3D

Criar o dispositivo usando a função CreateDevice do objeto Direct3D.

Page 134: Curso Professional

Criando um dispositivo Direct3D

Adapter: número que identifica a placa gráfica usada.

DeviceType: O tipo de dispositivo a ser usado (Ex. HAL ou Ref).

hFocusWindow: handle para a janela BehaviorFlags: flags pPresentationParameters: a estrutura

PRESENT_PARAMETERS preenchida anteriormente.

ppReturnedDeviceInterface: retorna o dispositivo Direct3D criado.

Page 135: Curso Professional

Criando um dispositivo

Page 136: Curso Professional

Exercício

Crie um dispositivo Direct3D em 800x600 fullscreen.

Experimente com outros tamanhos. Crie um dispositivo para versão Windowed.

Para isso coloque Windowed = TRUE, e o fullscreen refresh rate = 0.

Page 137: Curso Professional

Cores

As cores no Direct3D são definidas geralmente pela combinação de vermelho, verde e azul.

Um componente chamado alpha também é usado eventualmente e representa o grau de transparência da cor.

Page 138: Curso Professional

Cores

Em Direct3D, cores de vértices são geralmente definidas como números hexadecimais com o seguinte formato:

– 0xalpharedgreenblue 0x00ff0000 = vermelho puro 0x0000ff00 = verde puro 0x000000ff = azul puro 0x00000000 = preto 0x00ffffff = branco

Page 139: Curso Professional

Limpando Buffers

Toda vez que se deseja renderizar um frame, é necessário limpar os buffers de cor e profundidade.

Caso o buffer de cor não seja limpo, partes das cenas de renderizações passadas serão mostradas na tela, já que os backbuffers são reutilizados. Caso um jogo no entando sempre desenha na tela toda, não é necessário limpar esse buffer.

O buffer de profundidade é usado para desenhar corretamente os objetos 3D com relação à distância para a câmera. Basicamente esse buffer garante que objetos 3D que estão na frente de outros objetos, são renderizados corretamente na frente desses objetos. Esse buffer sempre precisa ser limpo a cada nova renderização.

Page 140: Curso Professional

Limpando Buffers

Para limpar os buffers de cor e profundidade é necessário usar a função Clear do dispositivo Direct3D.

Page 141: Curso Professional

Limpando Buffers

Count: Número de retângulos em pRects. pRects: Buffer de retângulos que especificam as

regiões que irão sofrer limpeza. Flags: flags que especificam os buffers que serão

limpos. Color: cor usada para limpar o buffer de cor. Z: valor de profundidade usado para limpar o buffer

de profundidade. Stencil: valor de stencil usado para limpar o buffer

de stencil.

Page 142: Curso Professional

Limpando Buffers

Page 143: Curso Professional

Apresentando Back Buffers

Toda a renderização por default é feita no backbuffer.

Após a renderização é necessário apresentar o backbuffer, fazendo seus dados serem copiados para o front buffer, que é o buffer sendo mostrado na tela.

Page 144: Curso Professional

Apresentando Back Buffers

Para apresentar o back buffer deve ser usada a função Present do dispositivo Direct3D.

Page 145: Curso Professional

Apresentando Back Buffers

pSourceRect: Um retângulo que define a parte que será apresentada do Back Buffer.

pDestRect: Um retângulo que define o local onde será apresentado o back buffer.

hDestWindowOverride: handle da janela onde será apresentado o back buffer.

pDirtyRegion: Define a região que precisa ser atualizada.

Page 146: Curso Professional

Apresentando Back Buffers

Page 147: Curso Professional

Exercício

Crie uma aplicação que limpa o buffer de cor para a cor vermelha (0x00ff0000).

Page 148: Curso Professional

Objetos 3D

Um objeto 3D pode possuir diversas informações que são usadas na sua renderização.

Page 149: Curso Professional

Objetos 3D

Page 150: Curso Professional

Objetos 3D

Objetos 3D podem usar texturas(imagens) para dar detalhe à seus triângulos.

Coordenadas de textura podem ser usadas para aplicar imagens à um objeto 3D.

Page 151: Curso Professional

Objetos 3D

Normais também podem ser usadas para cálculos de iluminação por exemplo.

Page 152: Curso Professional

Objetos 3D (Resumo)

Para desenhar objetos 3D nós podemos usar:– Posições dos vértices– Índices das faces– Coordenadas de textura– Normais dos vértices

Page 153: Curso Professional

Buffer de Vértices e Índices

Objetos 3D são renderizados passando sua informação geométrica para a placa gráfica.

A informação geométrica dos objetos é armazenada em VertexBuffers e IndexBuffers.

Os vértices dos objetos podem possuir variações em seu conteúdo.

Nos VertexBuffers ficam armazenadas informações tipo posição x,y,z, coordenadas de textura u, v, normal, etc.

Page 154: Curso Professional

Criando um Vertex Buffer

Para isso é necessário usar a função CreateVertexBuffer do dispositivo Direct3D.

Page 155: Curso Professional

Criando um Vertex Buffer

Length: tamanho do vertex buffer em bytes. Usage: Flags que indicam usos especiais. FVF: Flags que indicam o conteúdo do vertex buffer. Pool: Memória onde esse buffer ficará armazenado

(Memória de Vídeo, AGP ou RAM normal). ppVertexBuffer: Retorna o vertex buffer. pSharedHandle: colocar NULL. (bacalhau M$)

Page 156: Curso Professional

Criando um Vertex Buffer

Page 157: Curso Professional

Carregando Dados no Vertex Buffer

Para carregar dados em um vertex buffer deve-se usar a função Lock do vertex buffer.

Após carregar os dados, deve-se usar a função Unlock.

Page 158: Curso Professional

Carregando dados no Vertex Buffer

OffsetToLock: Distância do início do vertex buffer onde o carregamento começará.

SizeToLock: Tamanho da região no vertex buffer onde os dados serão carregados.

ppbData: Ponteiro retornado que aponta para o conteúdo do vertex buffer.

Flags: ...

Page 159: Curso Professional

Carregando dados no Vertex Buffer

Page 160: Curso Professional

Vertex Buffers

Vertex buffers podem armazenar diferentes informações sobre um vértice. Ex:– x,y,z– Coordenadas de textura u, v– Normal– Cor do vértice

Page 161: Curso Professional

Exercício

Crie um vertex buffer e carregue dados x,y,z de um triângulo.

Leia esses dados em outro buffer usando o mesmo vertex buffer.

Page 162: Curso Professional

O processo de renderização de primitivas

Page 163: Curso Professional

Processo de renderização de primitivas

As informações de renderização (x,y,z, u, v, ...) do objeto são armazenadas em vertex buffers.

Esses buffers são colocados em uso através da função SetStreamSource do dispositivo Direct3D.

A função DrawPrimitive faz as informações dos buffers serem carregadas juntando a informação completa de um vértice.

Quem define como os vertex buffers são combinados formando um vértice é a declaração do vértice ...

Page 164: Curso Professional

Colocando vertex buffers em uso

Para colocar em uso um vertex buffer, deve-se usar a função SetStreamSource do dispositivo Direct3D.

Page 165: Curso Professional

Colocando vertex buffers em uso

StreamNumber: define o número do vertex buffer, começa em 0.

pStreamData: o vertex buffer OffsetInBytes: a distância em bytes no buffer

onde começa a informação dos vértices. Stride: A distância entre cada componente

do vertex buffer.

Page 166: Curso Professional

Colocando vertex buffers em uso

Page 167: Curso Professional

Exercício

Coloque o vertex buffer criado no exercício anterior para ser usado como o vertex buffer 0.

Crie um vertex buffer para armazenar uma cor para cada um dos vértices do triângulo. Use D3DCOLOR.

Colocar esse vertex buffer com as cores como o vertex buffer 1.

Page 168: Curso Professional

Declarações de Vértices

Os vertex buffers podem conter diferentes informações sobre o vértice.

A declaração do vértice informa ao Direct3D como ele deve processar os vertex buffers usados para adquirir a informação de um vértice.

Declarações de vértices dizem coisas do tipo: “O vertex buffer 0 tem a informação x,y,z do objeto, já o vertex buffer 1 tem a informação u,v do objeto”.

Page 169: Curso Professional

Criando uma declaração de vértices

Uma declaração de vértices é feita através da criação de um buffer onde cada elemento é um D3DVERTEXELEMENT9.

Page 170: Curso Professional

Criando uma declaração de vértices

Stream: o número do vertex buffer. Offset: a distância no vertex buffer onde começa a

informação. Type: O tipo de dado armazenado no buffer. Method: Define como o tesselator vai operar na

informação do vertex buffer. Usage: Define o objetivo do uso do vertex buffer. UsageIndex: Dado adicional ao objetivo do vertex

buffer.

Page 171: Curso Professional

Criando uma declaração de vértices

Page 172: Curso Professional

Criando uma declaração de vértices

Após criar o buffer de D3DVERTEXELEMENT9, uma declaração é criada chamando a função CreateVertexDeclaration do dispositivo Direct3D.

Page 173: Curso Professional

Criando uma declaração de vértices

Page 174: Curso Professional

Usando uma declaração de vértices

Para usar uma declaração de vértices usa-se a função SetVertexDeclaration do dispositivo Direct3D.

Page 175: Curso Professional

Exercício

Crie a vertex declaration para usar os buffers do exercício anterior.

Page 176: Curso Professional

Effect Files

Effect files são arquivos que estabelecem uma configuração do pipeline gráfico para renderizar alguma coisa.

Eles armazenam o vertex e o pixel shader.

Page 177: Curso Professional

Composição de um effect file.

Page 178: Curso Professional

Vertex Shader

É responsável pelo processamento dos vértices. É um programa que executa para cada vértice

passado para o pipeline. Recebe como parâmetro as informações dadas

pelos vertex buffers. O pipeline espera obrigatoriamente pela posição do

vértice. Opcionalmente, é possível enviar outras informações como coordenadas de textura e cores. Essas informações serão interpoladas por toda a face do triângulo sendo desenhado.

Page 179: Curso Professional

Vertex Shader

Ao final do processamento do Vertex Shader, o vértice é passado para o estágio de clipping.

O vértice estará na tela, se estiver entre as coordenadas (-1, -1, 0, 1) e (1, 1, 1, 1).

Se o vértice estiver fora do volume mostrado na imagem, ele fará com que o triângulo a que ele pertence seja clipado.

Page 180: Curso Professional

Vertex Shader

Page 181: Curso Professional

Vertex Shader

Dados de input:– POSITION: define que a variável receberá a informação de

posição dos vertex buffers.– TEXCOORD0: define que a variável receberá a informação

de coordenadas de textura 0 do vertex buffers.

Dados de output:– POSITION: parâmetro de retorno obrigatório. Recebe uma

posição no espaço de clip homogêneo.– TEXCOORD0: recebe uma coordenada de textura que

será interpolada linearmente pela face do triângulo.

Page 182: Curso Professional

Pixel Shader

O parâmetro de retorno obrigatório do pixel shader é a cor final do pixel.

Page 183: Curso Professional

Pixel Shader

Parâmetros de input:– TEXCOORD0: coordenada de textura

interpolada.[

Parâmetros de output:– COLOR: a cor final do pixel. (no exemplo

estamos colocando a cor branca)

Page 184: Curso Professional

Usando Effect files no Direct3D

Para criar um efeito no Direct3D usa-se a função D3DXCreateEffectFromFile.

Page 185: Curso Professional

Usando Effect files no Direct3D

pDevice: o dispositivo Direct3D pSrcFile: path do effect file pDefine: permite a definição de macros do arquivo de efeitos. pInclude: permite a definição de includes no arquivo de efeitos. Flags: ... pPool: Usado para permitir o uso compartilhado de parâmetros

em múltiplos efeitos. ppEffect: retorna o objeto efeito. ppCompilationErrors: retorna uma lista de erros de compilação

do efeito.

Page 186: Curso Professional

Usando Effect files no Direct3D

Page 187: Curso Professional

Renderizando Triângulos

Para renderizar triângulos é preciso usar a função DrawPrimitive do dispositivo Direct3D.

Page 188: Curso Professional

Renderizando Triângulos

PrimitiveType: Define o tipo de primitiva para renderizar. (lista de ponto, de linhas, de triangulos, etc ...)

StartVertex: índice do primeiro vértice a ser carregado para renderização.

PrimitiveCount: número de primitivas a serem renderizadas.

Page 189: Curso Professional

Renderizando Triângulos

Antes de qualquer DrawPrimitive deve ser chamada a função BeginScene do dispositivo Direct3D.

Depois de todas as chamadas de DrawPrimitive deve ser chamada a EndScene do dispositivo Direct3D.

Page 190: Curso Professional

Resumo Básico de Renderização de Objetos 3D

Definir os vertex buffers usados pelo objeto 3d.

Definir a declaração de vértice do objeto 3d. Com isso o Direct3D consegue entender a informação que existe dentro dos buffers.

Renderizar o objeto 3d com a função DrawPrimitive.

Page 191: Curso Professional

Renderizando triângulos

Page 192: Curso Professional

Exercício

Use os vertex buffers e o vertex declaration dos exercícios anteriores e renderize um triângulo.

Para isso é necessário alterar o vertex shader para receber um float4 color : COLOR0 e retornar também um COLOR0.

Altere também o pixel shader para receber esse COLOR0 e colocá-lo na tela.

Implemente um código que mexe o triângulo em x e y baseado nas teclas recebidas.

Page 193: Curso Professional

Matrizes e Transformações

Matrizes são uma parte fundamental na computação gráfica.

Elas permitem:– Posicionar objetos 3D no mundo.– Posicionar câmeras no mundo.– Projetar o cenário 3D em um plano permitindo a

visualização em monitores.

Page 194: Curso Professional

O que são matrizes?

São um conjunto de elementos organizados em linhas e colunas

Page 195: Curso Professional

Operações Básicas

Page 196: Curso Professional

Multiplicação Não é Comutativa

Page 197: Curso Professional

Vetores

Podem ser representados por matrizes 1xN ou Nx1.

Consistem em uma entidade matemática que possui direção e tamanho.

Representado por uma linha com uma ponta de flecha.

Page 198: Curso Professional

Transformações

Matrizes são usadas para realizar transformações em vetores.

Page 199: Curso Professional

Transformações

São operações realizadas em pontos que permitem até alterar o sistema de coordenadas do ponto. (Ex: um ponto 3D vira um ponto 2D).

Page 200: Curso Professional

Transformações

Page 201: Curso Professional

Transformações Simples

Page 202: Curso Professional

Transformações Simples

Matriz Identidade

Matriz de Rotação 2D

Matriz de Escala Uniforme

Como Implementar Translação?

Page 203: Curso Professional

Coordenadas Homogêneas

Coordenadas homogêneas permitem que translações sejam realizadas com multiplicações de matrizes.

As coordenadas homogêneas de um ponto de n dimensões possuem n+1 dimensões.

A coordenada adicional é um escalar que multiplica todas as outras coordenadas.

(x,y,z) = (wx, wy, wz, w)

Page 204: Curso Professional

Coordenadas Homogêneas

Representando um ponto 2D em coordenadas homogêneas:– (x, y) = (x, y, 1) ou (2x, 2y, 2)

Para achar um ponto 2D representado em coordenadas homogêneas:– (2x, 2y, 2) = (2x/2, 2y/2, 2/2) = (x, y, 1)

Page 205: Curso Professional

Adicionando Translação

Para realizar a translação, basta usar o escalar com valor 1.

Page 206: Curso Professional

Sistemas de Coordenadas e Processo de Visualização

O pipeline gráfico pega a geometria dos objetos em 3D e cria uma imagem em 2D a partir dela.

Para gerar uma imagem 2D de um cenário 3D visto de um determinado ângulo é necessário fazer com que os vértices de um objeto passem por vários sistemas de coordenadas.

Page 207: Curso Professional

Sistemas de coordenadas e processo de visualização

Page 208: Curso Professional

Sistema de coordenadas locais ou do objeto ou do modelo

Quando um objeto está sendo modelado, seus vértices em 3D são especificados com relação a alguma origem. Geralmente essa origem fica em alguma região próxima ao objeto ou no centro do objeto.

Page 209: Curso Professional

Sistema de coordenadas do mundo

Os vértices do objeto no espaço precisam ser transformados para que o objeto possa ser posicionado no mundo. Essa transformação é quem permite posicionar um objeto em cima de uma mesa, ou dois orcs lado a lado. Isso se dá através da matriz de mundo.

Após a transformação os vértices estão no espaço do mundo. Todas as transformações são feitas baseadas em uma mesma origem de mundo, por isso elas permitem posicionar os objetos no mundo.

A transformação que transforma uma posição do espaço do objeto para o espaço do mundo é chamada de transformação de mundo.

Page 210: Curso Professional

Sistema de coordenadas de olho ou visão

Após transformar os vértices para o espaço de mundo, eles devem ser transformado para o espaço do olho. Isso se dá com a matriz de visão.

O espaço do olho transforma o mundo de acordo com a posição e orientação da câmera. Ao final da transformação a câmera está na posição 0,0,0 olhando para +z. O mundo é transformado de maneira que a câmera continue a ver o que ela deveria ver em sua posição original. Na imagem, é mostrado como a câmera é posicionada no OpenGL. Em Direct3D a câmera aponta para +z.

Não existe um objeto câmera que é transformado. A posição e orientação da câmera são utilizadas apenas para transformar o mundo de maneira que a câmera fique na posição 0,0,0 e olhando para +z.

Essa transformação faz esse reposicionamento do mundo para permitir que a próxima etapa de visualização aconteça de maneira rápida e eficiente.

Page 211: Curso Professional

Sistema de coordenadas de clipping homogêneo

Após os vértices serem reposicionados levando em consideração a câmera, é hora de projetá-los na tela.

Os vértices são transformados pela matriz de projeção. Após a transformação eles estão num espaço chamado

espaço de clipping homogêneo que permite o pipeline gráfico executar o algoritmo de clipping que remove as partes das primitivas que não são visíveis.

Page 212: Curso Professional

Sistema de coordenadas normalizadas de dispositivo

Após o clipping os vértices têm seu x,y e z divididos por w, o que os deixa no espaço normalizado de dispositivo.

Page 213: Curso Professional

Sistemas de coordenadas da tela

A última transformação é a transformação de viewport. Essa transformação é quem coloca os vértices na posição correta na tela e permite que os triângulos sejam rasterizados.

Page 214: Curso Professional

Transformações principais

As principais transformações que nós trabalharemos serão as transformações de mundo, de visão e de projeção.

Page 215: Curso Professional

Matrizes de Mundo

Essas matrizes variam dependendo da forma como se deseja posicionar os objetos no mundo.

Page 216: Curso Professional

Matrizes de Visão

Essa matriz que coloca a posição da câmera no processamento gráfico.

Page 217: Curso Professional

Matrizes de Projeção

A matriz de projeção vai definir a forma como os vértices serão projetados.

Page 218: Curso Professional

Renderizando triângulos com perspectiva

Após as matrizes de mundo, visão e projeção serem definidas, é preciso multiplicá-las na ordem World * View * Proj e depois passar a matriz resultando para o vertex shader.

No vertex shader, a matriz tem que ser usada para multiplicar as posições dos vértices.

Page 219: Curso Professional

Renderizando triângulos com perspectiva

Page 220: Curso Professional

Renderizando triângulos com perspectiva

Page 221: Curso Professional

Exercício

Renderize 3 triângulos, um atrás do outro. Utilize 1 único vertex buffer para os 3 triângulos. (Dica: Use uma matriz de mundo para cada triângulo).

Posicione a câmera em um ângulo que permita ver os 3 triângulos

Trate o input do teclado e faça a câmera se mover.

Page 222: Curso Professional

Exercício

Anime os 3 triângulos da seguinte forma:– 1 triângulo rotaciona no eixo y fixo na posição 0,

0, 0– 1 triângulo rotaciona no eixo y fixo na posição 10,

0, 0.– 1 triângulo rotaciona no eixo y na posição 20, 0, 0

Page 223: Curso Professional

Renderizando triângulos com textura

Texturas são um dos principais elementos que dão realismo à um cenário 3D.

Texturas são imagens que são colocadas nos modelos 3d que dão detalhes aos modelos.

Page 224: Curso Professional

Renderizando Triângulos com texturas

Para criar texturas, nós usaremos a função D3DXCreateTextureFromFile.

Page 225: Curso Professional

Renderizando Triângulos com texturas

Na hora de renderizar, usamos a função SetTexture do efeito.

Page 226: Curso Professional

Renderizando triângulos com textura

Temos que definir as coordenadas de textura, carregar o vertex buffer e definir o vertex declaration.

Page 227: Curso Professional

Renderizando triângulos com textura

Page 228: Curso Professional

Exercício

Coloque os triângulos do exercício anterior usando texturas.

Use texturas diferentes para cada triângulo.

Page 229: Curso Professional

Produto Escalar

•Vamos achar o tamanho de b, usando os lados a e c e o ângulo entre a e c?•a^2 = h^2 + c1^2 .... b^2 = h^2 + c2^2 ... h^2 = a^2 – c1^2•b^2 = a^2 – c1^2 + c2^2 .... c = c1 + c2•b^2 = a^2 – c1^2 + (c-c1)^2•b^2 = a^2 – c1^2 + c^2 – 2cc1 + c1^2 ... cos theta = c1/a•b^2 = a^2 + c^2 – 2cc1 ... b^2 = a^2 + c^2 – 2ca cos theta

Page 230: Curso Professional

Lei dos Cosenos

A fórmula achada é a lei dos cosenos. Ela permite achar o tamanho de b usando os

lados a e c e o ângulo entre eles. b^2 = a^2 + c^2 – 2*a*c*cos(ab)

Page 231: Curso Professional

Antes uma informação ...

|a| = tamanho do vetor a |a| = raiz(ax^2 + ay^2 + az^2)

Page 232: Curso Professional

Usando vetores

|b-a|^2 = |a|^2 + |b|^2 – 2*|a|*|b|*cos (ab) |b-a|^2 - |a|^2 - |b|^2 = -2*|a|*|b|*cos(ab)(bx-ax)^2 + (by-ay)^2 + (bz-az)^2 – ax^2 – ay^2 – az^2 – bx^2 – by^2 – bz^2bx^2 – 2bxax + ax2 + by^2 – 2byay + ay^2 + bz^2 – 2bzaz + az^2 - ...-2bxax - 2byay – 2bzaz = -2*|a|*|b|*cos(ab)axbx + ayby + azbz = |a|*|b|*cos(ab)

Produto escalar: a * b = axbx + ayby + azbz. Ou seja, o produto escalar entre 2 vetores calcula uma informação de ângulo entre os vetores. Se os 2 vetores tiverem tamanho 1, o produto escalar dá o coseno entre os vetores.

Page 233: Curso Professional

Projetando um vetor em outro

O que acontece quando um dos vetores possui tamanho 1?

a * b = |a| * cos (ab) Nesse caso a * b dá o tamanho do vetor a

projetado no vetor b. Então para achar o vetor projetado de a em

b basta achar o a * b e multiplicar pelo vetor b .... a * b = t .... proj_a = multiplicar(b, t)

Page 234: Curso Professional

Exercício

Crie uma classe Vector3d com x,y e z como floats. Crie a função Length que acha o tamanho do vetor Crie a função Normalize que normaliza esse vetor

(Basta dividir os componentes pelo tamanho do vetor)

Crie a função Dot que acha o produto escalar entre 2 vetores

Ache o vetor projetado de um vetor em outro normalizado.

Page 235: Curso Professional

Produto Vetorial

Outra ferramenta extremamente importante para programadores gráficos é o produto vetorial.

O produto vetorial entre dois vetores não paralelos é outro vetor perpendicular aos dois vetores.

O produto vetorial é escrito como:– a x b = c

Onde a, b e c são vetores e c é perpendicular aos vetores a e b.

Page 236: Curso Professional

Como calcular o produto vetorial?

Abaixo a * b significa o produto escalar entre os vetores a e b.

a * (a x b) = 0 b * (a x b) = 0 Ou seja: axcx + aycy + azcz = 0 bxcx + bycy + bzcz = 0

Page 237: Curso Professional

Calculando o produto vetorial

Multiplicando a primeira linha por bx/ax:– bxcx + bxaycy/ax + bxazcz/ax = 0

Subtraindo a linha acima da segunda linha:– bxcx + bycy + bzcz – bxcx – bxaycy/ax –

bxazcz/ax = 0– bycy + bzcz = bxaycy/ax + bxazcz/ax– axbycy + axbzcz = bxaycy + bxazcz– axbycy – bxaycy = bxazcz – axbzcz– (axby – bxay)cy = (bxaz – axbz)cz

Page 238: Curso Professional

Calculando o produto vetorial

Multiplicando a primeira linha por by/ay:– byaxcx/ay + bycy + byazcz/ay = 0

Subtraindo da segunda linha:– bxcx + bycy + bzcz – byaxcx/ay – bycy –

byazcz/ay = 0– bxcx + bzcz = byaxcx/ay + byazcz/ay– aybxcx + aybzcz = byaxcx + byazcz– aybxcx – byaxcx = byazcz – aybzcz– (aybx – byax)cx = (byaz – aybz)cz

Page 239: Curso Professional

Logo...

(axby – bxay)cy = (bxaz – axbz)cz (aybx – byax)cx = (byaz – aybz)cz Vamos alterar a segunda linha: -1*(axby – bxay)cx = (byaz – aybz)cz (axby – bxay)cx = (aybz – byaz)cz

Page 240: Curso Professional

Logo .... (parte 2)

(axby – bxay)cy = (bxaz – axbz)cz (axby – bxay)cx = (aybz – byaz)cz Queremos encontrar cx, cy e cz que são nossas

incógnitas. Que valores cx, cy e cz possuem? Ele podem possuir infinitos valores ... Porém se você

selecionar um valor qualquer ... Coisas ruins podem acontecer ... como divisão por zero ... ouch.

Page 241: Curso Professional

Logo .... (parte 3)

(axby – bxay)cy = (bxaz – axbz)cz (axby – bxay)cx = (aybz – byaz)cz E se selecionarmos cz = axby – bxay? Nesse caso:

– cy = bxaz – axbz– cx = aybz – byaz

Para achar as incógnitas não precisa de nenhuma divisão ... o que é bom.

Portanto, o produto vetorial entre vetores a x b:– a x b = c = (aybz – byaz, bxaz – axbz, axby – bxay)

Page 242: Curso Professional

Exercício

Adicione o calculo vetorial no último exercício e faça testes

Page 243: Curso Professional

Iluminação

Iluminação permite a geração de cenas mais interessantes e realistas.

Existem diversas formas de calcular a iluminação de uma cena. Nós utilizaremos um modelo de iluminação semelhante ao Direct3D e OpenGL, porém usaremos o cálculo de iluminação por pixel.

Page 244: Curso Professional

Iluminação

A cor de um pixel é calculada da seguinte forma:

Cor = Contribuição Emissiva + Contribuição Ambiente + Contribuição Diffusa + Contribuição Especular.

Page 245: Curso Professional

Contribuição Emissiva

Essa contribuição representa a luz emitida pelo próprio objeto.

Page 246: Curso Professional

Contribuição Ambiente

Consiste no quanto o objeto reflete a iluminação espalhada pelo ambiente.

A contribuição ambiente é calculada da seguinte forma:– Material Ambiente * Iluminação Ambiente– Material Ambiente representa o quanto da

iluminação ambiente o objeto reflete.

Page 247: Curso Professional

Contribuição Difusa

Essa contribuição representa o quanto o objeto reflete para todos os lados a iluminação direta das luzes.

A contribuição difusa é calculada da seguinte forma:– Max((N * L),0) * Material Diffuso * Iluminação Diffusa– N = Normal normalizada do ponto em que está sendo

calculada a iluminação.– L = Vetor para luz normalizado.– Material Diffuso representa o quanto da iluminação diffusa

o objeto reflete.

Page 248: Curso Professional

Contribuição Especular

A contribuição especular representa o quanto de luz direta é refletida na direção principal de reflexão de uma luz.

A contribuição especular é calculada da seguinte forma:

– Max((H * N),0)^shininess * Material Especular * Iluminação Especular

– H = vetor da luz + vetor do olho – shininess define o quão brilhoso é o objeto.– Material Especular define o quanto o objeto reflete a

iluminação especular.

Page 249: Curso Professional

Renderizando objetos com iluminação por pixel

Page 250: Curso Professional

Renderizando objetos com iluminação por pixel

Page 251: Curso Professional

Transformando Normais

Para transformar normais é necessário multiplicá-las pela inversa da transposta da matriz de mundo.

Ou seja: n’ = n * (world^t)^-1

Page 252: Curso Professional

Compreendendo Transformações de Normais*

Primeiro: Estudar equação do plano (ver parte do ppt de física)

[nx ny nz –nP0] * [px py pz 1]^t = 0 q * p^t = 0 q * M * (p * R)^t = 0 q * M * R^t * p^t = 0 M * R^t = Identidade M = (R^t)^-1

Page 253: Curso Professional

Exercício

Implemente o exemplo anterior usando iluminação por pixel.

Page 254: Curso Professional

Exportando, Carregando e Renderizando modelos .X

Criar objetos 3D no código é relativamente extraordinariamente complexo de se fazer quando algo sofisticado é desejado.

A maneira correta de se criar cenários e objetos 3d é modelando-os em programas como o 3D Studio Max.

O problema é que o 3D Studio Max pode exportar em qualquer formato desejado (Se você implementar plugins).

Logo precisamos definir um formato com o qual trabalharemos.

Page 255: Curso Professional

Arquivo .X (O modelo, não a série)

Arquivos .X são interessantes porque a micro$oft já se deu o trabalho de implementar um carregador.

Nós precisamos no entanto achar um plugin para o 3ds que exporte arquivos .X. (Procure no google por Panda DirectX Exporter).

Nós iremos carregar o modelo usando a API do DirectX e depois extrairemos a informação geométrica, e com isso, iremos renderizar na tela modelos realmente interessantes...

Page 256: Curso Professional

Carregando Arquivos .X (Para pipeline fixo)

Page 257: Curso Professional

Renderizando Malhas DirectX (Usando pipeline fixo)

Page 258: Curso Professional

Exercício

Exporte um modelo no 3D Studio Max e carregue-o e renderize-o usando pipeline fixo.

(Para casa) Exporte um arquivo .ASE e tente escrever um parser dele.

Page 259: Curso Professional

Preparando malhas para uso em shaders

Page 260: Curso Professional

Preparando malhas para uso em shaders

Após carregar a malha, nós criamos uma nova malha com um formato compatível com o nosso vertex shader.

Nesse formato apenas um vertex buffer deve ser usado. (tentei com mais de 1 e não deu).

Page 261: Curso Professional

Renderizando a malha com shaders

Page 262: Curso Professional

Exercício

Renderize a malha usando shaders.

Page 263: Curso Professional

Animação utilizando interpolação entre keyframes

Nesse tipo de animação, um personagem é modelado em diferentes posições (como as imagens de desenhos animados) e para renderizar uma posição intermediária entre 2 key frames é feita uma interpolação linear entre 2 frames:

– Frame1.pos * (1-t) + Frame2.pos * t– t define a posição intermediária da animação. 0 representa

o frame 1 e 1 representa o frame 2. Um t = 0.5 representa uma posição no meio do caminho entre os frames 1 e 2.

Page 264: Curso Professional

Animação utilizando interpolação linear entre keyframes

Para conseguirmos fazer a interpolação de maneira rápida (na GPU) precisamos enviar as posições dos dois keyframes para o vertex shader interpolar.

Para isso usaremos coordenadas de texturas.

Page 265: Curso Professional

Animação usando interpolação entre keyframes

Page 266: Curso Professional

Animação usando interpolação entre keyframes

Page 267: Curso Professional

Animação usando interpolação entre keyframes

Page 268: Curso Professional

Animação usando interpolação entre keyframes

Page 269: Curso Professional

Exercício

Implemente um exemplo que anima um triângulo.

Page 270: Curso Professional

Alpha Blending

Usado para renderizar objetos com transparência.

Quando o alpha blending está habilitado, a cor final de um pixel após renderizar uma primitiva é calculada da seguinte maneira:

Final Color = (New Color * SourceBlendFactor) + (Pixel Color * DestBlendFactor)

Page 271: Curso Professional

Alpha Blending

O resultado do pixel shader é uma cor. Essa cor possui os componentes rgba. Nós trabalhos com os componentes rgb até agora para dar

a cor aos objetos. O componente alpha permite definir um nível de

transparência quando alpha blending está habilitado. Geralmente 1 representará um pixel totalmente opaco, e 0

um pixel totalmente transparente. Para definir o componente alpha da cor gerada pelo pixel

shader use:

Page 272: Curso Professional

Alpha Blending

Para habilitar alpha blending:

Page 273: Curso Professional

Alpha Blending

Para definir os fatores de blending:

Page 274: Curso Professional

Exercício

Renderize o triângulo da cena de forma transparente

(enigma) Se o triângulo transparente for renderizado antes do chão e do objeto .x ele terá sua cor calculada com o fundo preto, como fazer a cena aparecer transparente atrás do triângulo?

(dica) Utilize um único float para definir o alpha do triângulo.

Page 275: Curso Professional

Volumes de sombras

Sombras são muito importantes para posicionar objetos em um ambiente 3d. Através das sombras é possível saber a relação espacial entre os objetos.

A técnica de volume de sombras gera sombras através da criação de um volume de sombras gerado através da malha do objeto e o stencil buffer.

Page 276: Curso Professional

Volume de sombras

O volume de sombra é um objeto 3d que representa a região em sombra de outro objeto.

Page 277: Curso Professional

Stencil Buffer

É necessário usar o stencil buffer para a técnica de volumes de sombra.

O stencil buffer é um buffer que permite um controle à nível de pixel sobre o que é renderizado na tela.

Quando o stencil buffer está habilitado, um pixel só é renderizado quando ele passa na seguinte operação:

(StencilRef & StencilMask) CompFunc (StencilBufferValue & StencilMask)

Todos esses elementos são customizáveis e o StencilBufferValue é o valor do stencil buffer.

Page 278: Curso Professional

O Algoritmo

Limpar o Stencil Buffer para 0 Gerar o volume de sombras através da malha do objeto e da

posição da luz. Renderizar o volume de sombra sem back face culling e sem

z-writing. Por toda a região de todas as faces de frente do volume de

sombra, adicionar 1 ao stencil buffer. Por toda a região de todas as faces de trás do volume de

sombras, remover 1 do stencil buffer. Se um determinado pixel falhar em z, não alterar o stencil

buffer. Renderizar um Quad ocupando toda a tela, naquelas regiões

do stencil que forem diferentes de 0, escurecer.

Page 279: Curso Professional

O Algoritmo

Limpar o Stencil Buffer para 0

Page 280: Curso Professional

O Algoritmo

Gerar o volume de sombras através da malha e da posição da luz.

Para isso, usaremos uma malha especial.

Page 281: Curso Professional

O Algoritmo

Durante a criação do vertex buffer do volume de sombras para cada aresta do objeto definir triângulos da seguinte forma:

(triangulos da aresta v1v2) = {v1,~v2, ~v1, v1, v2, ~v2} .

~v1 é igual a v1 só que com o w = 0. ~v2 tem a mesma relação com v2.

Page 282: Curso Professional

O Algoritmo

Durante a renderização do volume de sombras, todos os vértices com w = 0 são afastados da luz uma certa distância e depois transformados.

Os vértices com w != 0 são transformados normalmente.

Page 283: Curso Professional

O Algoritmo

Para renderizar o volume sem back face culling e sem z-writing.

Page 284: Curso Professional

O Algoritmo

Para permitir que o stencil buffer faça uma operação com as faces da frente e outra operação com as faces de trás.

Page 285: Curso Professional

O Algoritmo

Para definir a adição no stencil buffer para todas as faces de frente e subtração para todas as faces de trás.

Page 286: Curso Professional

O Algoritmo

Use alpha blending para renderizar volumes transparentes!

Page 287: Curso Professional

O Algoritmo

Nesse momento o stencil buffer só possui valores diferentes de zero nas regiões de sombra. Para renderizar apenas nessas regiões:

Page 288: Curso Professional

Exercício

Coloque o triângulo renderizando com um volume de sombras.

Page 289: Curso Professional

Bump Mapping

Bump mapping é uma técnica que aumenta o realismo das cenas ao dar a aparência de mais detalhe em malhas geométricas.

Para implementar a técnica, deve ser usada uma textura especial que define como é a superfície de um determinado triângulo de uma malha.

Essa informação de superfície é usada na hora de calcular iluminação, e com isso o objeto parece ter muito mais detalhe do que ele possui.

Page 290: Curso Professional

Bump Mapping

Page 291: Curso Professional

Bump Mapping

A textura de bump mapping que nós utilizaremos armazenará as normais da superfície dos triângulos.

Quando nós calcularmos a iluminação por pixel, nós usaremos a normal adquirida pelo bump map e com isso daremos riqueza de detalhe à superfície.

Page 292: Curso Professional

Um problemão no entanto

As normais da textura estão num espaço próprio delas. Chamado de espaço tangente.

Ou nós convertemos a normal para o espaço de mundo, ou nós convertemos os outros vetores para o espaço tangente.

Vamos converter todos os vetores para o espaço tangente.

Page 293: Curso Professional

Matriz de mudança de base

A matriz de mudança de base é quem vai converter do espaço do mundo (onde a gente tem calculado a iluminação até agora) para o espaço tangente.

Ela é composta por 3 componentes:– Vetor normal: A normal do triângulo.– Vetor tangente: É um vetor novo, que deve vir em cada

vértice, e deve ser tangente à face do triângulo. O vetor tangente é perpendicular à normal.

– Vetor Binormal: É calculado usando um produto vetorial entre a normal e a tangente.

Todos esses vetores são normalizados.

Page 294: Curso Professional

Matriz de mudança de base

A cara da matriz é a seguinte:– (tx, nx, bx)– (ty, ny, by)– (tz, nz, bz)

Os vetores (da luz, do olho etc) são multiplicados por essa matriz da seguinte forma:

– (tx, nx, bx)– (ty, ny, by)– (lx, ly, lz) * (tz, nz, bz)

O exemplo acima multiplicou o vetor da luz no espaço de mundo pela matriz.

O resultado é o vetor da luz no espaço tangente que nós podemos usar para calcular a iluminação normalmente.

Mas porque essa matriz faz isso?

Page 295: Curso Professional

Matriz de mudança de base

O vetor resulta da multiplicação anterior é composto por 3 operações:– x = dot(L,T)– y = dot(L,N)– z = dot(L,B)

Lembra que ao fazer o dot de 2 vetores sendo que 1 é normalizado, você acha a projeção do outro vetor no vetor normalizado? (T, N e B são normalizados...)

dot(L,T) calcula a projeção de L no vetor tangente. dot(L,N) calcula a projeção de L no vetor normal. dot(L,B) calcula a projeção de L no vetor binormal. Essas projeções geram um vetor nos eixos x, y e z se a tangente

representar o eixo x, a normal representar o eixo y e a binormal representar o eixo z.

Page 296: Curso Professional

Matriz de mudança de base

Digamos que as normais são feitas da seguinte maneira:– O mapa está deitado no eixo x,z – As normais sem inclinação apontam para o eixo y.– Esse é o espaço tangente.

Os vetores Tangente, Normal e Binormal representam os vetores x,y e z porém no espaço de mundo.

Ao projetar L no vetor tangente, você acha um valor que representa o tamanho de L no vetor tangente. Esse tamanho é o mesmo no eixo x. Logo ao projetar L em T, você acha L em x.

Repetindo, T,N e B TEM QUE ESTAR NORMALIZADOS.

Page 297: Curso Professional

Vértices

Além da posição, da normal, e da coordenada de textura, você agora precisa adicionar a tangente e, caso desejado, mais uma coordenada de textura para o bump map.

Page 298: Curso Professional

Vertex Shader

Page 299: Curso Professional

Pixel Shader

Page 300: Curso Professional

Exercício

Implementar um triângulo com bump mapping.

Experimente gerar proceduralmente um mapa normal com algum formato.

Page 301: Curso Professional

Grafos de Cena

Grafos de cena são estruturas de dados muito importantes que são utilizadas para diferentes propósitos.

O propósito mais importantes do grafo de cena é hierarquia de transformações.

Um grafo de cena geralmente tem o formato de uma árvore n-ária.

Page 302: Curso Professional

Grafo de Cena

Por exemplo, digamos que você queira colocar uma arma no braço de um guerreiro.

Para colocar o guerreiro no ambiente 3d, ele é transformado por sua matriz de mundo.

Para colocar a arma no mundo, primeiro a arma é tranformada para a posição do guerreiro, e depois é transformada para a posição da mão do guerreiro.

Page 303: Curso Professional

Grafo de Cena

Page 304: Curso Professional

Grafo de Cena

Page 305: Curso Professional

Grafo de Cena

Node: é a classe que permite implementar a hierarquia de transformações. Possui uma transformação como membro e uma lista de filhos.

Mesh: é uma classe que implementa a renderização de algum objeto.

Page 306: Curso Professional

Grafo de Cena

No exemplo da arma, poderíamos ter 2 malhas, uma representando o torso do guerreiro e outra representando a arma.

A transformação da arma poderia ser uma translação +5 em x.

Após definir a transformação de mundo do guerreiro, é renderizada a malha do guerreiro. Depois essa transformação é usada para calcular a transformação de mundo da arma.

Page 307: Curso Professional

Culling em cenários usando octrees

Os cenários dos jogos de hoje são complexos e detalhados. Logo, são pesados para renderizar.

Porque enviar todo o cenário para a placa gráfica a cada frame, se na maioria das vezes você só consegue ver parte do cenário?

A octree é uma estrutura de dados que permite reduzir o custo de renderização pois com ela é possível cálcular as regiões do cenário que são visíveis.

A octree é uma árvore onde cada nó possui 8 filhos.

Page 308: Curso Professional

Culling usando octrees

Page 309: Curso Professional

Equação do plano

A equação de um plano é definida geralmente de duas formas: (P – P0) * n = 0. Nesse caso P é um ponto qualquer, P0 é um

ponto no plano e n é a normal normalizada do plano. Se P – P0 (que gera um vetor) dot n resultar em 0 é porque o ponto está no plano. Essa equação após distribuir os dots vira:

– P * n – P0 * n = 0 Ax + By + Cz + D = 0. Nesse caso A, B, C e D definem o plano.

Se você colocar um ponto (x,y,z) nessa fórmula e ela der zero é porque o ponto está no plano. A,B,C correspondem aos componentes da normal e D = - P0 * n.

Page 310: Curso Professional

Calculando a distância de um ponto à um plano

O que representa P * n e P0 * n na equação P * n – P0 * n ?

Page 311: Curso Professional

Calculando a distância de um ponto à um plano

P0 * n = | P0 | * cos (theta) | P0 | * cos (theta) = tamanho de P0 projetado na normal =

distância do plano à origem. P * n = | P | * cos (theta) | P | * cos (theta) = tamanho de P projetado na normal. P * n – P0 * n = Distância de P ao plano. Logo se essa distância for 0, o ponto está no plano. Se essa distância for positiva, o ponto está no lado do plano

em que aponta a normal. Se essa distância for negativa, o ponto está no lado oposto ao

qual a normal aponta.

Page 312: Curso Professional

Calculando a interseção de uma AABB com um plano

A idéia do algoritmo é calcular na AABB um mínimo e um máximo baseado na posição do plano e a seguir verificar as distâncias dos pontos min e max com relação ao plano.

Page 313: Curso Professional

Calculando a interseção de uma AABB com um plano

Page 314: Curso Professional

Verificando se uma AABB está dentro de um Frustum

Page 315: Curso Professional

Calculando um frustum

Page 316: Curso Professional

Calculando um frustum

Page 317: Curso Professional

Criando a Octree

Page 318: Curso Professional

Criando a octree

Page 319: Curso Professional

Criando a Octree

Page 320: Curso Professional

Criando a octree

Page 321: Curso Professional

Renderizando com a octree

Page 322: Curso Professional

Adicionando objetos à octree

Page 323: Curso Professional

Exercício

Implemente um código que calcula uma AABB em um objeto e só renderiza esse objeto se sua AABB estiver interceptando o frustum.

Implemente uma octree e adicione esse objeto à octree. Renderize usando a octree.

Page 324: Curso Professional

Quaternions

Quaternions são ferramentas importantes para realizar rotações.

Com multiplicação de quaternions você pode realizar rotações.

Realizar uma interpolação entre duas rotações é “relativamente” simples com quaternions.

Page 325: Curso Professional

Quaternions

Para entender quaternions, precisamos primeiro aprender sobre números complexos.

Com o conjunto dos números reais dá pra representar uma quantidade considerável de números.

Nós no entanto não conseguimos representar a raiz de -4. Porque nenhum número vezes ele mesmo dá um número negativo.

Page 326: Curso Professional

Números complexos

Números complexos possuem uma parte real e uma parte imaginária como escrito abaixo:

a + bi a = parte real. bi = parte imaginária. Então os números abaixo são todos números

complexos: 4 + 2i 1 + 10i 5 4i

Page 327: Curso Professional

Números complexos

A parte imaginária possui uma peculiaridade: i^2 = -1 Ou seja: 2i * 2i = 4i^2 = -4 Com isso nós podemos encontrar a raiz de

números negativos: raiz de -4 = raiz de 4 * i^2 = 2i raiz de -1 = raiz de i^2 = i

Page 328: Curso Professional

Quaternions

Quaternions são números hiper-complexos (sério!).

Eles possuem 3 partes imaginárias e são escritos como:

a + bi + cj + dk Então o número abaixo é um quaternion: 2 + 3i + 4j + 5k

Page 329: Curso Professional

Quaternions

Assim como números complexos: i^2 = j^2 = k^2 = -1 Porém números complexos possuem algumas definições

adicionais (aqui começa a loucura). i * j = k j * i = -k j * k = i k * j = -i k * i = j i * k = -j i * j * k = (i * j) * k = i * (j * k) = -1

Page 330: Curso Professional

Multiplicando dois quaternions

q0*q1 = (w0 + x0*i + y0*j + z0*k) * (w1 + x1*i + y1*j + z1*k).

Vamos aplicar multiplicação distributiva: w0*w1 + w0*x1*i + w0*y1*j + w0*z1*k + x0*i*w1 +

x0*i*x1*i + x0*i*y1*j + x0*i*z1*k + y0*j*w1 + y0*j*x1*i + y0*j*y1*j + y0*j*z1*k + z0*k*w1 + z0*k*x1*i + z0*k*y1*j + z0*k*z1*k

(w0*w1 – x0*x1 – y0*y1 – z0*z1) + w0*(x1*i + y1*j + z1*k) + w1*(x0*i + y0*j + z0*k) + x0*y1*k - x0*z1*j – y0*x1*k + y0*z1*i + z0*x1*j - z0*y1*i

Page 331: Curso Professional

Definições para facilitar a vida:

Um quaternion: q0 = (w0 + x0*i + y0*j + z0*k) = (w0 + v0)

Ou seja: v0 = (x0*i + y0*j + z0*k) Outro quaternion: q1 = (w1 + x1*i + y1*j + z1*k) =

(w1 + v1) Produto escalar: v0 * v1 = (x0*x1 + y0*y1 + z0*z1) Produto vetorial: v0 x v1 = (y0*z1*i – z0*y1*i +

z0*x1*j – x0*z1*j + x0*y1*k – y0*x1*k) Escala: a * v0 = (a*x0*i + a*y0*j + a*z0*k)

Page 332: Curso Professional

Usando nossas definições

q0*q1 = (w0*w1 – x0*x1 – y0*y1 – z0*z1) + w0*(x1*i + y1*j + z1*k) + w1*(x0*i + y0*j + z0*k) + x0*y1*k - x0*z1*j – y0*x1*k + y0*z1*i + z0*x1*j - z0*y1*i

Torna-se: q0*q1 = w0*w1 – v0*v1 + w0*v1 + w1*v0 +

v0 x v1

Page 333: Curso Professional

O conjugado de um quaternion

O conjugado de um quaternion é definido como:– q0 = (w0 + v0) – quaternion normal– q0* = (w0 – v0) – conjugado do quaternion

Page 334: Curso Professional

Rotacionando vetores

Crie 1 quaternion com w = 0 e com os componentes x,y e z do próprio vetor que você quer rotacionar:

– (x, y, z) -> (0, x, y, z) = v Crie outro quaternion onde w = cos(theta/2), o x,y,z

é o eixo de rotação normalizado e escalado por sin(theta/2):

– q = (cos(theta/2) + sin(theta/2)d) A multiplicação qvq* gera um quaternion cujos

elementos x,y,z são o vetor 3D rotacionado pelo eixo d do quaternion q por theta graus.

Page 335: Curso Professional

Rotacionando vetores

Ou seja, digamos que queremos rotacionar o vetor (1, 0, 0) no sentido anti-horário do eixo (0, 0, 1). Queremos rotacionar 90 graus gerando o vetor (0, 1, 0).

Vamos criar dois quaternions v e q: v = (0, 1, 0, 0) q = (cos(45) + sin(45)(0, 0, 1)) = (cos(45), 0, 0,

sin(45)) Logo: qvq* = (0, 0, 1, 0) = Rotacionamos o vetor!

Page 336: Curso Professional

Porque isso funciona?

Para entender porque quaternions funcionam precisamos primeiro aprender como criar uma matriz que rotaciona um vetor dado um eixo qualquer.

Page 337: Curso Professional

Rotacionando vetores pelo eixo z

Para rotacionar um vetor em xy usando o eixo z usamos a matriz:

(cos(theta) sin(theta) 0) (-sin(theta) cos(theta) 0) (vx vy vz) * (0 0 1) Como podemos fazer para rotacionar um

vetor por um eixo qualquer?

Page 338: Curso Professional

Matriz de Mudança de Base

Assim como no bump mapping vamos criar uma matriz que projeta o vetor em 3 outros vetores normalizados que formam uma base orthonormal.

Um desses vetores base é o eixo de rotação. Os outros dois vetores podem ser dois vetores quaisquer ortogonais entre si.

Page 339: Curso Professional

O Algoritmo

Criar a matriz de vetores base sendo que o vetor base que representa o eixo de rotação precisa ser a última coluna gerando o valor em z. A matriz abaixo mostra os vetores base a, b e rot, todos normalizados e rot é o eixo de rotação.

(ax bx rotx) (ay by roty) (vx vy vz) * (az bz rotz) = (v*a v*b v*rot) Com essas projeções é possível achar o vetor em nosso espaço x,y,z padrão. Sendo que

o eixo de rotação passa a representar o eixo z. Depois de multiplicar o vetor pela matriz acima, nós o multiplicamos pela matriz de

rotação no eixo z mostrada anteriormente. Com isso o vetor rotaciona no eixo z que representa o eixo de rotação rot.

Depois de rotacionar nosso vetor no eixos x,y,z padrão, devemos calcular como fica esse vetor rotacionado usando como vetores base os vetores a, b e rot. Para achar isso podemos calcular na mão, multiplicando os vetores a, b e rot pelos valores achados em x, y e z após a rotação:

– vfinal = vx * a + vy * b + vz * rot Ou podemos multiplicar o vetor rotacionado pela matriz inversa da matriz formada por a,b

e rot.

Page 340: Curso Professional

O Algoritmo (Resumidamente)

V = vetor que queremos rotacionar RV = vetor rotacionado MB = Matriz criada a partir de A, B e Rot RotZ = Matriz que rotaciona pelo eixo Z MB^t = Matriz transposta da MB. Matriz

Transposta = Inversa para rotações. O Algoritmo aplica a seguinte fórmula: RV = V * MB * RotZ * MB^t

Page 341: Curso Professional

Código

Page 342: Curso Professional

Código sem problemas de cosseno

Page 343: Curso Professional

Analisando a matriz de rotação

Vamos assumir que:– cos(theta) = c– sin(theta) = s

R = (ax bx rotx) (c s 0) (ax ay az) (ay by roty) (-s c 0) (bx by bz) (az bz rotz) (0 0 1) (rotx roty rotz)

R = (a^t b^t rot^t) (c s 0) (a) (-s c 0) (b) (0 0 1) (rot) R = (a^t b^t rot^t) (c*a+s*b) (-s*a+c*b) (rot) R = a^t(c*a+s*b) + b^t(-s*a+c*b) + rot^t*rot R = c*(a^t*a + b^t*b) + s*(a^t*b – b^t*a) + rot^t*rot

Page 344: Curso Professional

Algumas fórmulas

v = (a*v)*a + (b*v)*b + (rot*v)*rot = x0*a + x1*b + x2*rot

rot x v = rot x (x0*a + x1*b + x2*rot) = x0*(rot x a) + x1*(rot x b) + x2*(rot x rot)

rot x v = x0*(rot x a) + x1*(rot x b) = x0*b – x1*a rot x v = x0*b – x1*a = (a*v)*b - (b*v)*a rot x v = (v*a^t)*b – (v*b^t)*a rot x v = v*(a^t*b – b^t*a)

Page 345: Curso Professional

Algumas Fórmulas

v * I = v v * I = (a*v)a + (b*v)b + (rot*v)rot v * I = (v*a^t)a + (v*b^t)b + (v*rot^t)rot v * I = v*(a^t*a + b^t*b + rot^t*rot) I = a^t*a + b^t*b + rot^t*rot Voltando a nossa fórmula original: R = c*(a^t*a + b^t*b) + s*(a^t*b – b^t*a) + rot^t*rot R = c*(I – rot^t*rot) + s*(a^t*b – b^t*a) + rot^t*rot R = cI – c*rot^*rot + s*(a^t*b – b^t*a) + rot^t*rot R = cI + s*(a^t*b – b^t*a) + (1 – c)rot^t*rot

Page 346: Curso Professional

Algumas fórmulas

rot x (rot x v) = rot x (x0*b – x1*a) = x0*(rot x b) – x1*(rot x a) = -x0*a –x1*b

v = (a*v)*a + (b*v)*b + (rot*v)*rot = x0*a + x1*b + x2*rot -x*a – x1*b = x2*rot – v = (rot*v)*rot - v rot x (rot x v) = (rot*v)*rot – v = v*(rot^t*rot) – v rot x (rot x v) + v = v*(rot^t*rot) Voltando à formula: R = cI + s*(a^t*b – b^t*a) + (1 – c)rot^t*rot Se a gente multiplicar um vetor por essa matriz: vR = cv*I + sv*(a^t*b – b^t*a) + (1 – c)*v*(rot^t*rot) vR = cv*I + s*(rot x v) + (1 – c)*(rot x (rot x v) + v) vR = cv + s*(rot x v) + (1 – c)*(rot x (rot x v)) + (1 – c)v vR = cv + s*(rot x v) + (1 – c)*(rot x (rot x v)) + v – cv vR = v + sin(theta)*(rot x v) + (1 – cos(theta))*(rot x (rot x v))

Page 347: Curso Professional

Ou Seja

Quando você multiplica um vetor pela matriz RV abaixo:

RV = V * MB * RotZ * MB^t Você está fazendo na realidade o seguinte

cálculo: vR = v + sin(theta)*(rot x v) + (1 – cos(theta))*(rot x

(rot x v))

Page 348: Curso Professional

Código de rotação mais rápido

Page 349: Curso Professional

Voltando aos quaternions...

Foi dito que:– dado um vetor v = (x, y, z) armazenado em um

quaternion q0 = (0 + v)– Um eixo de rotação normalizado r = (rx, ry, rz)

armazenado em um quaternion da seguinte forma: q1 = (cos(theta/2) + sin(theta/2)*r)

– A multiplicação: q1q0q1* gera um quaternion cujos componente x, y, z consistem no vetor v rotacionado pelo eixo r por theta graus.

Page 350: Curso Professional

Vamos analisar essa multiplicação

Vamos considerar:– s = sin(theta/2)– c = cos(theta/2)

Lembrando:– q0*q1 = w0*w1 – v0*v1 + w0*v1 + w1*v0 + v0 x v1

q1q0q1* = (c + s*d)(0 + v)(c – s*d) q1q0q1* = (-s*d*v + c*v + s*d x v)(c – s*d) q1q0q1* = [-s*c*d*v – (c*v + s*d x v)*(-s*d)] + (-s*d*v)*(-s*d) + c*(c*v +

s*d x v) + (c*v + s*d x v) x (-s*d) -s*c*d*v + s*c*d*v + s^2*(d x v)*d + s^2*(d*v)*d + c^2*v + s*c*(d x v) -

s*c*(v x d) - s^2*(d x v) x d s^2*(d*v)*d + c^2*v + s*c*(d x v) + s*c*(d x v) - s^2*(d x v) x d s^2*(d*v)*d + c^2*v + 2*s*c*(d x v) - s^2*(d x v) x d s^2*(d*v)*d + c^2*v + 2*s*c*(d x v) + s^2*d x (d x v)

Page 351: Curso Professional

Continuando a análise

s^2*(d*v)*d + c^2*v + 2*s*c*(d x v) + s^2*d x (d x v) (1 – s^2)*v + 2*s*c*(d x v) + s^2*[(d*v)*d + d x (d x

v)] v – s^2*v + 2*s*c*(d x v) + s^2[(d*v)*d + d x (d x v)] v + 2*s*c*(d x v) + s^2[(d*v)*d – v + d x (d x v)] Porém: d x (d x v) = (d*v)*d – (d*d)*v = (d*v)*d – v.

Logo: q1q0q1* = v + 2*s*c*(d x v) + 2*s^2*d x (d x v)

Page 352: Curso Professional

Continuando

2*s*c = 2*sen(theta/2)*cos(theta/2) = ? Para resolver essa fórmula vamos provar a

seguinte fórmula: sin(a + b) = sin(a)cos(b) + sin(b)cos(a)

Page 353: Curso Professional

Prova da identidade trigonométrica

RPQ = pi/2 – RQP = pi/2 – (pi/2 – RQO) = RQO = a OP = 1 PQ = sin(b) OQ = cos(b) AQ/OQ = sin(a). AQ = sin(a)cos(b). AQ = RB. PR/PQ = cos(a). PR = cos(a)sin(b) sin(a + b) = PB = RB + PR = sin(a)cos(b) + cos(a)sin(b) Logo: sin(theta) = sin(theta/2)cos(theta/2) + cos(theta/2)sin(theta/2) sin(theta) = 2sin(theta/2)cos(theta/2)

Page 354: Curso Professional

Outra Prova

OP = 1 PQ = sin(b) OQ = cos(b) OA/OQ = cos(a). OA = cos(a)cos(b). RQ/PQ = sin(a). RQ = sin(a)sin(b). RQ = BA. cos(a + b) = OB = OA – BA = cos(a)cos(b) – sin(a)sin(b) Logo cos(theta) = cos(theta/2)cos(theta/2) – sin(theta/2)sin(theta/2) cos(theta) = cos^2(theta/2) – sin^2(theta/2) E Ainda: cos(theta) = (1 – sin^2(theta/2)) – sin^2(theta/2) cos(theta) = 1 – 2*sin^2(theta/2) 1 – cos(theta) = 2*sin^2(theta/2)

Page 355: Curso Professional

Voltando à fórmula do quaternion

q1q0q1* = v + 2*s*c*(d x v) + 2*s^2*d x (d x v) q1q0q1*= v + sin(theta)*(d x v) + (1 – cos(theta))*d x

(d x v) Comparando à fórmula de rotação por um eixo

qualquer: vR = v + sin(theta)*(rot x v) + (1 – cos(theta))*(rot x (rot x v)) Podemos ver então que a multiplicação de quaternions

q1q0q1* resulta na mesma equação da rotação de vetores por um eixo qualquer mostrada anteriormente.

Page 356: Curso Professional

Exercício

Rotacione um vetor usando multiplicação de quaternions.

Page 357: Curso Professional

Tópicos para Programação Distribuída

Fundamentos de Distribuição Técnicas de Distribuição para Jogos

Page 358: Curso Professional

Modelos de Distribuição

Cliente / Servidor

Page 359: Curso Professional

Modelos de Distribuição

Peer to Peer

Page 360: Curso Professional

Cliente / Servidor

Capaz de manter milhares de jogadores no mesmo jogo (Utilizado em Massively Multiplayer Games).

Há necessidade de manter um servidor (Custos podem ser elevados).

Page 361: Curso Professional

Peer to Peer (Ponto a Ponto)

Armazena (geralmente) menos jogadores por instância de jogo.

Não requer servidor de grande poder computacional.

Page 362: Curso Professional

TCP – Transmission Control Protocol

Protocolo complexo que implementa a comunicação como um fluxo de bytes que trafega entre dois pontos (Circuito Virtual).

Garante a chegada das mensagens As mensagens chegam de forma ordenada Algoritmos para redução do número de

mensagens Comunicação 1 x 1

Page 363: Curso Professional

TCP - Conexão

Há necessidade de estabelecer conexão

Função connect() da API dos sockets.

Page 364: Curso Professional

TCP – Envio de Mensagens

Garantia de chegada

Page 365: Curso Professional

TCP – Término da conexão

Ocorre quando a função closesocket() é chamada.

Page 366: Curso Professional

UDP – User Datagram Protocol

Protocolo simples que implementa comunicação como um envio de mensagens de forma atômica.

Não há garantia de chegada Mensagens podem chegar desordenada ou

duplicadas Permite realização de broadcasts ou multicast

(comunicação 1 x N) Não há necessidade de se conectar.

Page 367: Curso Professional

Sockets

API criada para abstrair a conexão entre computadores em diferentes sistemas operacionais.

Um socket é formado pela união IP + Porta, que define unicamente uma parte de uma conexão.

Page 368: Curso Professional

Função socket()

Função que cria um socket. SOCKET socket(int family, int type, int protocol) family: Define a família de protocolos utilizados.

AF_INET = Protocolos convencionais da internet. type: Define o tipo de socket. SOCK_STREAM ou

SOCK_DGRAM. protocol: Define o tipo de protocolo dentro da família.

IPPROTO_TCP = TCP, IPPROTO_UDP = UDP.

Page 369: Curso Professional

Função socket()

Exemplo:

SOCKET s = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP).

Page 370: Curso Professional

Função connect()

Estabelece conexão int connect(SOCKET socket, const struct

sockaddr *serveraddr, int addrlen) socket: O socket do cliente serveraddr: O endereço (IP+Porta) do

servidor. addrlen: O tamanho da estrutura serveraddr.

Page 371: Curso Professional

Estrutura sockaddr_in

Estrutura passada para a função connect.

struct sockaddr_in {   

short sin_family;    //AF_INET

unsigned short sin_port;   

struct   in_addr sin_addr;   

char sin_zero[8];

}; Define o endereço de um socket remoto

Page 372: Curso Professional

Estrutura in_addr

Page 373: Curso Professional

Função connect()

SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

sockaddr_in addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(SERVER_PORT);addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);connect(s, (const sockaddr*)&addr,

sizeof(addr));

Page 374: Curso Professional

Função bind()

Função usada pelo servidor para definir um socket local

int bind(SOCKET s, const sockaddr *localaddr, int addrlen);

s: o socket do servidor localaddr: o endereço local addrlen: o tamanho do endereço

Page 375: Curso Professional

Função bind()

SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

sockaddr_in addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(LIST_PORT);addr.sin_addr.s_addr = htonl(INADDR_ANY);bind(server, (const serveraddr*)&addr,

sizeof(addr));

Page 376: Curso Professional

Função listen()

Define um socket como passivo. Informa o S.O. que deve aceitar conexões direcionadas à esse socket.

int listen(SOCKET s, int backlog); s: o socket do servidor backlog: O número de conexões que podem

ficar pendentes para esse socket.

Page 377: Curso Professional

Função listen()

//continuação do código da bind()

listen(server, 8);

Page 378: Curso Professional

Função accept()

Chamada por um servidor TCP para retornar a próxima conexão completa do ínicio da fila de conexões completas.

SOCKET accept(SOCKET s, struct sockaddr * addr, int * addrlen);

s: o socket do servidor addr: o endereço do novo cliente addrlen: o tamanho do endereço Essa função retorna o socket do novo cliente e

bloqueia quando não há conexões terminadas.

Page 379: Curso Professional

Função accept()

while(true) {

addrlen = sizeof(addr);

cli_socket = accept(server, (...)&addr, &addrlen);

ProcessClientSocket(cli_socket);

}

Page 380: Curso Professional

Função closesocket()

Libera os recursos alocados ao socket. int closesocket(SOCKET s);

Page 381: Curso Professional

Função send()

função que envia bytes usando um socket conectado.

int send(SOCKET s, const char * buffer, int len, int flags);

s: o socket conectado por onde enviar os dados buffer: os bytes a serem enviados len: o número de bytes a serem enviados flags: Flags

Page 382: Curso Professional

Função send()

//continuando o código da connect

char msg[]= “coéeee!”;

send(s, msg, strlen(msg)+1, 0);

Page 383: Curso Professional

Função recv()

Função usada para receber dados de uma conexão.

int recv(SOCKET s, char * buffer, int len, int flags);

Page 384: Curso Professional

Função recv()

//continuando o codigo da send()

char reply[64];

recv(s, reply, 64, 0);

cout << reply;

Page 385: Curso Professional

Função sendto()

Usada com sockets UDP não conectados int sendto(SOCKET s, const char *buf, int

len, int flags, const struct *destaddr, int addrlen);

Page 386: Curso Professional

Função recvfrom()

Função usada em servidores UDP sem conexões.

int recvfrom(SOCKET s, char * buffer, int len, int flags, sockaddr *addr, int *addrlen);

Page 387: Curso Professional

Para usar a API de sockets no windows

Para inicializar a DLL do sockets use:

Para finalizar a DLL:

Inclua a lib: ws2_32.lib Header file: winsock2.h

Page 388: Curso Professional

Exercício

Implementar uma aplicação cliente / servidor usando TCP onde o cliente envia uma string para o servidor e o servidor escreve na tela aquilo que recebeu. O servidor só aceita 1 cliente de cada vez.

Page 389: Curso Professional

Exercício

Implementar uma aplicação cliente / servidor semelhante ao exercício 1 porém usando UDP.

Page 390: Curso Professional

Livros Importantes

TCP/IP Illustrated, Vol 1 Unix Network Programming, Vol 1

(Ambos do W. Richard Stevens!)

Page 391: Curso Professional

Técnicas de Distribuição para Jogos

Page 392: Curso Professional

Multithreading (Revisão)

Conhecimento fundamental (Xbox 360). Thread = Parte de um programa que executa

concorrentemente ou paralelamente a outras partes do programa. Comunicação entre partes é feita através de variáveis compartilhadas.

Um game = Thread Principal (Main) + Outras Threads

Page 393: Curso Professional

Multithreading

Múltiplas threads parecem executar paralelamente mesmo em um único processador devido ao time slicing.

Page 394: Curso Professional

Multithreading (Exemplo)

Page 395: Curso Professional

Criando uma thread

uintptr_t _beginthread( void( *start_address )( void * ), unsigned stack_size, void *arglist ); start_address: endereço de uma função que inicia a

execução da thread. stack_size: tamanho da pilha da nova thread. arglist: ponteiro para parâmetro passado para

thread.

Page 396: Curso Professional

Criando uma thread

int A = 0;

void Add(void * data){

A++;}

void main(){

_beginthread(Add, 0, NULL);

//tente comentar essa linhaSleep(1000);

cout << A;

char c;

cin >> c;}

Page 397: Curso Professional

Case Study: Project Gotham Racing

Core Thread Software threads

00 Update, physics, rendering, UI

1 Audio update, networking

10 Crowd update, texture decompression

1 Texture decompression

20 XAudio

1

Page 398: Curso Professional

Exercício

Evolua o exercício 1 de forma que o servidor se torne capaz de processar múltiplos clientes simultaneamente.

Utilize 1 thread por cliente.

Page 399: Curso Professional

Técnicas usando TCP, UDP e Sockets

Page 400: Curso Professional

Entendendo TCP

O Algoritmo de Naggle e o Delayed Ack.

Desligando o algoritmoBOOL b = TRUE;

setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&b, sizeof(bool));

Page 401: Curso Professional

Usando sockets UDP conectados

sendto() em alguns sistemas operacionais realiza conexão, envio e desconexão.

Permite receber mensagens ICMP.

Page 402: Curso Professional

Enviando múltiplos buffers em Sockets

WSABUF MsgBuf[2];

MsgBuf[0].buf = &Cabecalho;

MsgBuf[0].len = sizeof(Cabecalho);

MsgBuf[1].buf = MsgChat;

MsgBuf[1].len = strlen(MsgChat);

WSASend(Socket, MsgBuf, 2, &BytesSent, Flags, NULL, NULL);

Page 403: Curso Professional

Implementando Garantia de Chegada

Como calcular o RTO (Retransmission Timeout Timer) ?– Levar em consideração o tempo estimado de

round trip time (SRTT) e a variação estimada dos tempos de round trip time (VARRTT).

Page 404: Curso Professional

Implementando Garantia de Chegada

Calculando RTT estimado (SRTT):– delta = RTT – SRTT– SRTT = SRTT + (delta / RTTINF)

Calculando variação de RTT (VARRTT):– VARRTT = VARRTT + ((| delta | - VARRTT) /

VARRTTINF) Calculando RTO:

– RTO = SRTT + VARRTT * VARINC

Page 405: Curso Professional

Exercício (Para casa)

Implemente um protocol de reliable UDP.

Page 406: Curso Professional

Técnicas para Ambientes Virtuais Distribuídos

Page 407: Curso Professional

Dead-Reckoning

O conceito de Dead-Reckoning Forma normalmente usada: pos = pos0 + (vel * dir) * deltat

Com Dead-Reckoning baseado a objetivos há a possibilidade de redução ainda maior no número de mensagens trocadas. – Ex: “Desejo ir para o destino x,y”.

Page 408: Curso Professional

Sincronização baseada em tempo de comando

Alterando velocidades é possível fazer uma sincronização visual.

T 0s T 1s

T 2s

Page 409: Curso Professional

Eliminando Informações Desnecessárias

Geralmente, não há necessidade de enviar informações sobre objetos não perceptíveis.

Page 410: Curso Professional

Balanceamento

Para conseguir processar um MMORPG é necessário quebrar o processamento entre diversos servidores.

Page 411: Curso Professional

Outras técnicas

Nível de detalhe Agregação de Mensagens

Page 412: Curso Professional

Exemplo de Servidor MMORPG

Page 413: Curso Professional

Construindo a Rede de servidores

A ferramenta permite dividir responsabilidades entre os servidores

Page 414: Curso Professional

Diagrama de Classes

Page 415: Curso Professional

Outras características

IOCP Culling usando Grid Balanceamento usando retângulos Reliable UDP + Last Update Sincronização por Tempo de Comando Dead Reckoning baseado em objetivos

Page 416: Curso Professional

Resultados

Page 417: Curso Professional

Exercício

Implemente uma demo onde existem 2 retângulos e cada retângulo sobre movimentação de um cliente diferente. Ao mover um retângulo, o outro cliente deve ver a movimentação.

Implemente dead reckoning para reduzir o número de mensagens trocadas.

Page 418: Curso Professional

Tópicos para Física

Teste de Interseção Raio – Plano Teste de Interseção Raio - Triângulo Teste de Interseção Esfera – Esfera Teste de Interseção Elipsóide - Elipsóide Teste de Interseção AABB – AABB Detecção de Colisão em cenário estático usando elipsóides Resposta à Colisão Picking Otimizando a colisão com Binary Space Partition Trees. Dinâmica Linear Dinâmica Rotacional

Page 419: Curso Professional

Interseção Raio - Plano

Um plano pode ser expressado através da fórmula:– N dot (P – P0) = 0

Onde N é a normal do plano, P é um ponto qualquer e P0 é um ponto no plano. Qualquer P colocado na fórmula que dê zero como resultado está no plano.

Page 420: Curso Professional

Interseção Raio - Plano

Um raio pode ser expressado através da seguinte fórmula:– O + tD

Onde O é a origem do raio, D é a direção normalizada e t é um valor que permite achar qualquer ponto na extensão do raio.

Page 421: Curso Professional

Interseção Raio - Plano

Devemos achar um t que gere um ponto que quando utilizado na fórmula do plano resulte em zero. Ou seja, devemos achar um t que resulte em um ponto no plano.

t vai indicar a distância percorrida da origem ao local de interseção.

Page 422: Curso Professional

Interseção Raio - Plano

O + tD = P N dot (P – P0) = 0 N dot (O + tD – P0) = 0 N*O + tN*D – N*P0 = 0 tN*D = N*P0 – N*O t = (N*P0 – N*O) / N*D t = N*(P0 – O) / N*D Quando N*D for igual a zero, o raio é paralelo ao

plano.

Page 423: Curso Professional

Interseção Raio - Plano

Page 424: Curso Professional

Interseção Raio - Triângulo

Ache a interseção do raio com o plano do triângulo.

Ache uma componente na normal diferente de zero, projete em um plano do eixo alinhado de acordo com a componente isso transforma nosso problema em 2D.

Use os coeficientes angulares entre o ponto e os vértices para verificar se o ponto está dentro do triângulo.

Page 425: Curso Professional

Interseção Raio - Triângulo

Para achar a relação entre o coeficiente angular do ponto e uma aresta, testa-se a seguinte condição:

(v2y–v1y) / (v2x–v1x) < (py–v1y) / (px–v1x) (v2y-v1y)*(px-v1x) < (py-v1y)*(v2x-v1x) 0 < (py-v1y)*(v2x-v1x) - (v2y-v1y)*(px-v1x)

Page 426: Curso Professional

Interseção Raio - Triângulo

Page 427: Curso Professional

Interseção Raio - Triângulo

Page 428: Curso Professional

Interseção Esfera - Esfera

Um esfera é representada computacionalmente através de uma posição C que define o centro da esfera e um tamanho r que define o raio da esfera.

Duas esferas estão colidindo se a distância entre os centros for menor que a soma dos raios das esferas, ou seja:

Está colidindo se:– | C1 – C2 | < r1 + r2

Onde C1 e C2 são os centros das esferas 1 e 2 e r1 e r2 são os raios das esferas 1 e 2.

Page 429: Curso Professional

Interseção Esfera - Esfera

Page 430: Curso Professional

Interseção Elipsóide - Elipsóide

O que diabos é um elipsoíde? Elipsóide é como uma esfera que possui um

raio de tamanho diferente para cada eixo.

Page 431: Curso Professional

Interseção Elipsóide - Elipsóide

A interseção de elipsóides é muito parecida com a de esferas.

Dois elipsóides estão colidindo se:– | C1 – C2 | < | R1 | + | R2 |

Onde C1 e C2 são os centros dos elipsóides. R1 é o vetor que vai de C1 até a superfície da elipsóide 1 na direção de C2. R2 é similar porém indo na direção de C2 para C1.

Page 432: Curso Professional

Interseção Elipsóide - Elipsóide

O tamanho do raio de uma elipsóide varia dependendo da direção, logo como achar o tamanho de R1 e R2?

Page 433: Curso Professional

Interseção Elipsóide - Elipsóide

Ou seja, após achar a direção, normalizar e depois multiplicar pelos tamanhos dos raios nos eixos x, y e z.

Page 434: Curso Professional

Interseção Elipsóide - Elipsóide

Page 435: Curso Professional

Interseção AABB - AABB

AABB significa Axis Aligned Bounding Box, ou seja, representa uma caixa com os alinhada aos eixos x,y e z.

Page 436: Curso Professional

Interseção AABB - AABB

AABBs são representadas por um ponto mínimo e um ponto máximo.

Duas AABBs estão colidindo se em nenhum momento algum dos testes triviais de rejeição retornam sucesso.

Page 437: Curso Professional

Interseção AABB - AABB

Page 438: Curso Professional

Exercício

Implemente uma aplicação que renderiza dois cubos.

Coloque duas AABBs envolvendo cada um dos cubos.

Faça um dos cubos se moverem com o uso de setas.

Implemente a detecção de colisão entre os cubos e impeça que os cubos entrem um no outro.

Page 439: Curso Professional

Detecção de Colisão em cenário estático usando Elipsóides

Como podemos colidir elipsóides com triângulos?

Page 440: Curso Professional

Colisão com cenários estáticos

Para detectar colisão: Lance um raio do centro da elipsóide na

direção do triângulo usando a normal negativa do triângulo como direção.

Page 441: Curso Professional

Colisão com cenário estáticos

Calcule o tamanho do raio nessa direção usada.

Se o raio acerta o triângulo e sua distância para o plano é menor que o raio da elipsóide na direção usada, a elipsóide colide com o triângulo.

Page 442: Curso Professional

Colisão com cenários estáticos

Page 443: Curso Professional

Resposta à colisão

Após detectar a colisão temos que tratar a resposta à colisão.

Uma resposta normalmente dada é empurrar o objeto para fora da geometria em que ele colidiu.

Como vamos empurrar a elipsóide para fora do triângulo?

Page 444: Curso Professional

Resposta a colisão

Nós empurramos o centro da elipsóide para fora na direção da normal do plano.

A distância empurrada = Tamanho raio – Distância centro-plano.

Page 445: Curso Professional

Resposta à colisão

Page 446: Curso Professional

Exercício

Implemente uma aplicação onde no cenário há um triângulo.

Coloque um elipsóide como BV da câmera. Faça a câmera se mover e colidir com o

triângulo.

Page 447: Curso Professional

Picking

Algo bastante utilizado em games é a seleção de algum objeto 3d com o uso do mouse.

Para conseguirmos descobrir o objeto selecionado, precisamos lançar um raio no espaço de mundo.

Para descobrirmos esse raio precisamos saber onde no mundo se encontra a posição selecionada na tela.

Com essa informação podemos lançar o raio partindo da câmera e passando por essa posição 3D no mundo.

Page 448: Curso Professional

Picking

Para achar a posição no espaço 3D usaremos as informações para a criação do frustum de visão.

Para achar a metade da altura da tela em espaço de mundo você calcula(usando os valores da imagem como exemplo):

tg(15) = x / near tg(15) * near = x; Para achar a metade da largura basta fazer: half_width = x * aspect; aspect é a divisão da largura da tela pela altura. Na prática, o valor 15 da figura será FOVy / 2 (FOVy é o

mesmo valor passado na função de criação de matriz de perspectiva).

Page 449: Curso Professional

Picking

Page 450: Curso Professional

Binary Space Partition Trees

BSPs são árvores binárias muito parecidas com as árvores binárias de busca. (Na realidade, a árvore binária de busca pode ser vista como uma BSP de 1 dimensão).

BSPs são úteis para acelerar a detecção de colisão.

Page 451: Curso Professional

Binary Space Partition Trees

Uma BSP é uma árvore onde cada nó representa um plano. Esse plano corta o espaço em 2. Os planos dos filhos a direita e esquerda cortam os espaços resultantes da direita e da esquerda.

Page 452: Curso Professional

Binary Space Partition Trees

Para detectar a colisão de um objeto com outros:

Adicione todos os objetos à BSP. Os objetos terminam em listas nas folhas da árvore.

Detectar colisão de cada objeto com todos os outros objetos da mesma folha.

Page 453: Curso Professional

Exercício (Para Casa)

Implementar uma BSP. Adicionar objetos usando AABBs. Implemente a detecção de colisão de cada

objeto com os outros da mesma folha.

Page 454: Curso Professional

Dinâmica Linear

Como podemos mover objetos linearmente de maneira fisicamente realista?

Aplicamos a segunda lei de Newton: – F = M * A

Dessa forma: – F / M = A

Onde F é força, M é massa e A é aceleração. F e A são vetores, M é um escalar.

Page 455: Curso Professional

O tempo e a posição

Aceleração = variação de velocidade / variação de tempo

Velocidade = variação de posição / variação de tempo

Posição = área da função da velocidade em uma faixa de tempo

Velocidade = área da função da aceleração em uma faixa de tempo

Page 456: Curso Professional

Um problema complicado

Dada uma aceleração, temos que achar a variação da velocidade e depois a variação da posição.

O problema é que isso envolve uma integração de uma função (e nós não sabemos a função previamente ).

Page 457: Curso Professional

Método de Euler

Consiste no método mais simples para achar as áreas.

Nele você adquire o valor no início do intervalo e considera ele constante durante todo o intervalo.

Page 458: Curso Professional

Método de Euler

Para adquirir a posição:– Aceleração = força / massa– Posição = posição + velocidade * variação de

tempo– Velocidade = velocidade + aceleração * variação

de tempo

Page 459: Curso Professional

Implementando o método de Euler

Page 460: Curso Professional

Dinâmica Rotacional

Nós aprendemos a mexer linearmente um objeto. Mas e quanto a rotação?

Torque é o equivalente da força para o movimento rotacional.

Para achar o torque de um corpo rígido, ache o produto vetorial entre o vetor que vai do centro de massa do objeto até o local onde está sendo aplicada uma força e o vetor da força.

Page 461: Curso Professional

Descobrindo a rotação

Torque = Cross(R, F) Aceleração Angular = Torque / Inércia Rotação = Rotação + Velocidade Angular *

variação de tempo. Velocidade Angular = Velocidade Angular +

Aceleração Angular * variação de tempo.

Page 462: Curso Professional

Descobrindo a rotação

Page 463: Curso Professional

Exercício

Implemente um demo que renderiza uma caixa.

Implemente física linear aplicando uma força constante na caixa.

Implemente física rotacional causando a caixa rotacional dependendo do lugar onde se aplica a força.

Page 464: Curso Professional

Tópicos para Inteligência Artificial

Máquinas de Estados Embedding Lua na sua aplicação Path Finding

Page 465: Curso Professional

Máquinas de Estado

Máquinas de Estado são uma das principais técnicas de inteligência artificial usadas desde o primórdio dos tempos (~1980).

Máquinas de Estado são máquinas abstratas compostas por estados e eventos que geram transições nesses estados.

Elas são úteis pois permitem a criação de seres que possuem comportamento dependendo do estado e que variam esse comportamento dependendo de eventos que ocorrem no jogo.

Page 466: Curso Professional

Máquinas de Estado

Um soldado em um jogo pode ter a seguinte máquina de estado:

Page 467: Curso Professional

Maquinas de estado

Page 468: Curso Professional

Maquina de estado

Page 469: Curso Professional

Máquinas de Estado Paralelas

Quando uma determinada entidade exige um comportamento sofisticado sua máquina de estado tende a ficar complexa demais.

A solução pra isso é fazer uma mesma entidade usar múltiplas máquinas paralelas para resolver diferentes problemas.

Por exemplo: Digamos que aquele inimigo do exemplo anterior passe a usar uma metralhadora e 2 máquinas de estado, uma para movimentação e outra para atacar.

Page 470: Curso Professional

Maquina de estado de movimentação

Page 471: Curso Professional

Maquina de estado de combate

Page 472: Curso Professional

Máquinas de estado paralelas

Implemente da mesma forma que a máquina de estado normal, porém use 1 variável de estado por máquina e 1 switch por máquina.

Page 473: Curso Professional

Sincronizando máquinas de estado

É interessante às vezes fazer com que máquinas de estado façam interações.

Half-life fez isso com seus soldados que se coordenavam ao combater o player.

Para fazer essa comunicação basta usar variáveis compartilhadas como variáveis estáticas.

Page 474: Curso Professional

Sincronizando máquinas de estado

Digamos que nós queremos que um inimigo ao avistar o player avise aos outros inimigos da localização do player e todos os outros inimigos a seguir se movem para a região avisada.

Page 475: Curso Professional

Máquina de estado de movimentação

Page 476: Curso Professional

Exercício

Implemente um demo com 2 caixas. Uma caixa é o inimigo e se move pela tela seguindo por 4 posições pré-definidas. A outra é controlada pelo jogador.

Quando a caixa do jogador se aproxima à uma certa distância. O inimigo começa a se aproximar até que ele chega à uma distância e pára. Se o jogador se afastar depois do inimigo, o inimigo volta a caminhar no seu caminho pré-definido.

Implemente esse demo usando uma máquina de estados.

Page 477: Curso Professional

Embedding Lua na sua aplicação

Scripting é uma adição fundamental à qualquer engine.

Scripting fornece uma ambiente sandbox para programadores de gameplay e de inteligência artificial onde eles podem criar lógica e conteúdo sem se preocupar em quebrar nada interno da engine. Ou seja, Scripting fornece permite que um trabalho puramente criativo seja realizado.

Scripting também é necessário se você deseja que seus jogos sejam “modable”.

Page 478: Curso Professional

Embedding Lua

Page 479: Curso Professional

Embedding Lua

A primeira linha cria o objeto de estado lua que é usado em todas as funções.

A função dofile é quem executa scripts. No final lua_close deve ser chamado para

liberar recursos.

Page 480: Curso Professional

Escrevendo e lendo valores

Page 481: Curso Professional

Escrevendo e lendo valores

Script em lua:

Resultado: x = 7 e y = 9

Page 482: Curso Professional

Escrevendo e lendo valores

Lua utiliza de uma pilha para trocar valores com o código em C++.

A função setglobal define o nome de uma variável e a pushnumber seu valor.

A função getglobal coloca uma variável no topo da pilha que pode ser capturada com a função tonumber que recebe o estado lua e o índice que se deseja usar para pegar um valor.

Page 483: Curso Professional

Adicionando funções à Lua

Scripts são úteis para customização de comportamentos, implementação de lógica de jogo e AI.

Porém scripts são mais lentos que código compilado em C++, portanto para certas computações custosas é valido implementá-las em C++ e adicionar a função à Lua.

Page 484: Curso Professional

Adicionando funções a Lua

Page 485: Curso Professional

Adicionando funções a Lua

Page 486: Curso Professional

Adicionando funções a lua

A função register registra uma função em lua.

Dentro da função faz-se uso da pilha normalmente para acessar valores.

Para retornar valores usa-se push e o valor retornado define o numero de valores a serem retornados (É possível retornar mais de um valor).

Page 487: Curso Professional

Exercício

Reimplemente o exemplo anterior executando a máquina de estados em Lua ao invés de executá-la em C++.

Adicione à lua a função de distância implementada em C++.

Page 488: Curso Professional

Path Finding

Um problema muito comum em diversos jogos é a necessidade de calcular o caminho para se mover de um ponto a outro do mapa.

Para resolver esse problema nós usaremos o algoritmo A*.

Page 489: Curso Professional

A*

O algoritmo A* é um algoritmo que implementa uma busca heurística.

Uma busca heurística leva em consideração alguma informação antes de tomar uma decisão.

No nosso caso, o A* levará em consideração informações geométricas para tomar decisões.

Page 490: Curso Professional

Min-Heap

O algoritmo do A* precisa de uma estrutura de dados que implemente uma fila de prioridade.

Uma fila de prioridade implementa uma função para retornar o elemento mais prioritário de forma eficiente.

Uma forma de implementar uma fila de prioridade é usar a estrutura Min-Heap.

Page 491: Curso Professional

Min-Heap

Uma Min-Heap é semelhante à uma árvore binária que possui a seguinte regra:– Cada nó é menor que seus filhos.

A Min-Heap pode ser implementada em um vetor.

Page 492: Curso Professional

PriorityQueue

Page 493: Curso Professional

PriorityQueue

Page 494: Curso Professional

PriorityQueue

Page 495: Curso Professional

PriorityQueue

Page 496: Curso Professional

PriorityQueue

Page 497: Curso Professional

A*

A prioridade de um nó é calculada usando 2 informações.

– A distância percorrida até o nó = g.– A distância do nó atual até o nó destino = h.

A prioridade é então calculada:– f = g + h

Essas prioridades fazem o algoritmo selecionar os nós que se aproximam mais rapidamente do nó destino.

Page 498: Curso Professional

A*

Page 499: Curso Professional

A*

Page 500: Curso Professional

Exercício

Implemente um PathFinder usando A* que recebe uma matriz de inteiros onde 1 é lugar passável e 0 é parede, e a partir dessa matriz é criado uma estrutura de dados onde cada nó possui norte, sul, leste e oeste.

Faça o PathFinder calcular o caminho entre duas posições.

Imprima as posições numa console application.

Page 501: Curso Professional

Fundamentos de Programação de Jogos

Arquitetura de Tecnologias de Jogos

Page 502: Curso Professional

Arquitetura de Tecnologia de Jogos

Jogos 3D possuem a vantagem de poderem compartilhar muita tecnologia.

Isso aumenta a recompensa em implementar uma engine de jogos.

Engines de jogos podem possuir designs completamente diferentes, logo o design mostrado aqui não deve ser considerado o design supremo e fundamental de engines.

Page 503: Curso Professional

Implementando um Jogo

Uma forma interessante de dividir os diferentes momentos de um jogo é implementando-o como uma máquina de estados.

Cada estado é implementado em uma classe diferente.

Page 504: Curso Professional

Implementando um Jogo

Page 505: Curso Professional

Loop Principal

Uma forma, para jogos single player é a seguinte:– Renderiza a cena (Sem dar Present)– Adquire e Processa Input do Player– Processa AI– Processamento física, testa colisão e resposta– Processamentos extras, específicos do estado

atual– Present

Page 506: Curso Professional

Game Engine Todo List (Single Player)

1 Level Loader que carrega o arquivo com a configuração do level. Esse arquivo aponta para outros arquivos que deve ser carregados para a execução do level.

1 engine 3d para carregar e renderizar o cenário com efeitos especiais de maneira rápida.

1 engine de física/colisão com estruturas otimizadas para detecção de colisão. Esse engine move objetos e detecta colisão e repassa o tratamento da resposta para o game.

1 engine de input para aquisição do input. 1 engine de AI que carrega dados em um cenário específicos

para AI e processa as entidades AI do game. Todos são Singletons.

Page 507: Curso Professional

Level Loader

Tem como missão carregar o arquivo que representa o level.

Esse arquivo possui os nomes de todos os outros arquivos que serão usados no level. Ex: O arquivo da octree do cenário. O arquivo que armazena os waypoints do cenário. O arquivo que armazena a estrutura usada para processar a colisão. Os modelos, os scripts.

O level loader repassa todos esses nomes para as respectivas engines carregarem.

Page 508: Curso Professional

Engine 3D

Responsável pela parte gráfica do jogo. Carrega o cenário e os modelos 3D. Pode

carregar uma estrutura especial como uma Octree. Carrega também a parte gráfica dos elementos do cenário.

Renderiza o cenário 3D e os modelos usando técnicas de aceleração e efeitos especiais.

Page 509: Curso Professional

Engine 3D

Page 510: Curso Professional

Engine 3D (Extras)

É interessante criar plugins para 3DS Max para exportar cenário e modelos.

É importantíssimo implementar um level editor onde as fases são feitas a la wysiwyg onde você define locais onde ficam as entidades, triggers e scripts especiais. Você também configura características gráficas específicas da engine e vê em tempo real as alterações.

Page 511: Curso Professional

Engine de Física / Colisão

Carrega a estrutura de colisão e a parte física dos elementos da cena. Pode carregar por exemplo uma BSP.

Processa a física das entidades e usa técnicas de aceleração para os testes de colisão. Delega a resposta de colisão ao game. Isso pode ser feito com ponteiros para função ou funções virtuais.

Page 512: Curso Professional

Engine de Física / Colisão

Page 513: Curso Professional

Engine de Input

Wrapper de funções que fazem polling de dispositivos.

Page 514: Curso Professional

Engine de AI

Carrega a estrutura de dados necessária para executar a AI. Como exemplo, carregar os caminhos possíveis pela AI. Carrega a parte de AI das entidades da cena.

Processa movimentação e inteligência usando C++ e delegando para Lua partes do processamento.

Page 515: Curso Professional

Engine de AI

Page 516: Curso Professional

Problema

O AI Engine decide mover um NPC para alguma região. Ele então requisita a movimentação para o Engine de Física. O Engine de física o move normalmente. Como o engine gráfico recebe essa alteração?

Uma solução é fazer uso de IDs. Um elemento é identificado nas 3 engines através do uso de um mesmo ID. Logo se o engine de AI decidir mover um personagem, ele identifica o personagem através de seu ID. O engine gráfico antes da renderização requisita todos os elementos que se moveram para atualizar suas posições.

Page 517: Curso Professional

Elementos e IDs

Page 518: Curso Professional

Exercício Final

Implementar um Jogo 3D