Sobre
Objetivos
Pretende-se que os alunos dominem efetivamente os conceitos e técnicas fundamentais da computação gráfica 2D e 3D. Para os gráficos 2D são desenvolvidos temas como primitivas de desenho procedimental e gráficos vetoriais, transformações e técnicas de animação. Nos gráficos 3D são tratados os grafos de cena, pontos de vista, geometria e aspeto, transformações, iluminação e animação. Os conceitos e técnicas são transmitidos no contexto da web, usando as tecnologias mais recentes deste domínio. |
Programa
Capítulo | Sumário |
---|---|
Introdução |
Sobre a Computação Gráfica. |
Gráficos 2D |
Introdução 2D, Geometria, Transformações. |
Aspeto, Exemplos, Revisões. |
|
Gráficos 3D |
Introdução 3D, Geometria. |
Transformações, Aspeto. |
|
Exemplos 3D. |
|
Animação |
Animação por Tempo e por Passos. |
Exemplos & Aplicações |
Gerador SVG em javascript. |
Sistemas-L (C2D). |
|
Animação 2D (C2D + SVG). |
|
Geometria, Aspeto, Animação (X3D). |
Avaliação
-
A avaliação de Computação Gráfica tem uma componente teórica e uma componente prática.
-
A componente teórica pode ser realizada por exame, ou por três testes.
-
A componente prática consiste na realização de quatro trabalhos dentro do processo e condições indicadas a seguir.
-
Os exames correspondem apenas à componente teórica da avaliação.
-
Se reprovar no exame normal pode fazer o exame de recurso.
Em casos individuais que o docente ache necessário, pode haver uma prova oral. |
Veja as datas das provas nos anúncios do moodle. |
Componente Teórica
-
A componente teórica vale 60% da nota final (12 valores).
-
Cada teste vale 20% da nota final (4 valores).
-
Pode realizar os testes que desejar e também os exames (normal e de recurso).
-
A nota final desta componente é a combinação mais vantajosa que resulta dos testes e dos exames.
-
Exemplo 01. Testes: 03, 03, NA; Exame: 11; Nota final: 11.
-
Exemplo 02. Testes: 04, 03, 03; Exame: 08; Nota final: 10.
-
Exemplo 03. Testes: 04, NA, 04; Exame: NA; Nota final: 08.
Componente Prática
-
A componente prática vale 40% da nota final (8 valores).
-
Cada trabalho conta 10% da nota final (2 valores).
-
Cada trabalho corresponde a uma das tecnologias:
SVG
,C2D
,X3D
e3JS
. -
A componente prática não tem «recurso».
-
A classificação de cada trabalho é calculada segundo os Critérios de Avaliação dos Trabalhos Práticos apresentados mais abaixo.
Todos os trabalhos terão de ser entregues até à data do «Exame Normal». |
Critério | Descrição | Peso |
---|---|---|
formatação |
encoding, comportamento, etc. |
4% |
fidelidade |
em relação ao tema e à proposta. |
6% |
organização/separação |
ficheiros externos |
10% |
organização/abstrações |
aplicação de elementos comuns, eliminação de elementos repetidos. |
10% |
organização/grafo de cena |
hierarquia de objetos gráficos, espaços do objeto/mundo. |
10% |
modelação/geometria e aspeto básicos |
quadrados, caixas, círculos, esferas, etc. |
5% |
modelação/transformações |
translação, rotação, escala, composição |
10% |
modelação/geometria construída |
caminhos, segmentos, geometrias por faces, extrusões. |
15% |
modelação/aspeto construído |
gradientes, mosaicos, mapas de cores, mapas UV. |
15% |
modelação/animação |
tweens, por passos, eventos internos (por exemplo, colisões). |
15% |
Note bem o peso de cada componente da avaliação! |
Bibliografia
-
João Madeiras Pereira, João Brisson, António Coelho, Alfredo Ferreira, Mário Rui Gomes - Introdução à Computação Gráfica (2019).
-
Marschner, S., Shirley, P. - Fundamentals of Computer Graphics (2016).
-
Hughes J.F., et al. - Computer graphics. Principles and practice (2014).
-
Ammeraal, L., Zhang, K. - Computer Graphics for Java Programmers (2007).
Recursos
-
«Cábulas»
-
Tutoriais
-
Bibliotecas:
-
X3D
+3JS
+TweenJS
: Bibliotecas (versão para 2020).
-
-
X3D
: -
3JS
-
Tween.js
-
Repositório tween.js.
-
Em Design and UI/Animations @ Google Developers encontra uma exposição sobre a aplicação de easing nos interfaces gráficos.
-
As acelerações inicial e final de um tween podem ser calculadas de muitas formas diferentes. Um exemplo dessa variedade está nos exemplos do repositório do tween.js.
-
-
Outros Recursos e Ferramentas:
Introdução
Conceitos Fundamentais
Definição e Disciplinas Relacionadas.
- Computação Gráfica
-
É o estudo e aplicação das técnicas de modelação, processamento e construção de objetos gráficos em computadores.
- Visão Artificial
-
É o oposto da computação gráfica: procura reconstruir um modelo (virtual) a partir de imagens reais.
- Programação de Jogos
-
É uma aplicação da computação gráfica: usa um modelo (virtual) onde o utilizador interage.
- Processamento de Imagem
-
Tem técnicas para:
-
Melhoramento de imagem (equalização do histograma, etc).
-
Compressão de imagem.
-
Deteção de features: arestas, super-pixeis, etc..
-
Resolver crimes (CSI).
-
- Álgebra Linear
-
Proporciona as bases formais e numéricas para a CG.
Conceitos Principais da Computação Gráfica
- Modelador
-
Especifica o modelo gráfico.
- Construtor
-
Transforma o modelo gráfico numa imagem.
- Grafo de Cena
-
Estrutura de Dados que define e organiza o modelo gráfico.
Os Principais Espaços (ou Referenciais) da Computação Gráfica
A modelação consiste em especificar o modelo gráfico que define a imagem. |
Modelação
- Espaço do Modelo
-
É um espaço 2D ou 3D onde é definido o modelo, juntando e organizando vários objetos gráficos — nos espaços 3D os problemas são mais complexos e tratados de forma significativamente diferente dos espaços 2D.
- Objetos Gráficos
-
Entidades geométricas (linhas, superfícies) ou luzes, textos, imagens.
- Representações Matemáticas
-
Permitem definir e transformar os objetos gráficos.
- Vistas
-
Mostram um modelo numa perspetiva específica e enquadram o passo da construção — Os modelos 2D têm vistas relativamente simples. Para modelos 3D é necessário ter em inúmeras propriedades que envolvem a câmara, a projeção, a posição e orientação da vista ou o campo de profundidade.
Construção (ou Rendering) é o processo computacional que transforma um modelo gráfico numa imagem exibida num dispositivo físico. |
Construção
- Modo Retido
-
O modelo é definido e depois a imagem é construída.
- Modo Imediato
-
Os objetos são imediatamente desenhados.
O Grafo de Cena é a estrutura de dados que define o modelo gráfico. |
Além do «simples» desenho de objetos, interessa definir uma cena onde os objetos são colocados e geridos. O grafo de cena organiza os vários objetos gráficos numa única estrutura de dados que «alimenta» a rotina de rendering.
A programação gráfica consiste em:
|
Outros Aspetos
- Problemas
-
Oclusão, Posicionamento de objetos, Aspeto de materiais, etc.
- Hardware
-
Ecrãs, Impressoras, Plotters, Projetores holográficos, etc.
- Animação
-
Filmes, Jogos, Simulações, etc.
- Interação
-
Teclados e Ratos, Rede, Interfaces Gráficos, etc.
Aplicações
Filmes |
|
Jogos |
|
Visualização |
|
Simulação |
|
Estatística |
|
Medicina |
Computação Gráfica na Web
A Computação Gráfica na web proporciona:
-
Normas Abertas com ecossistema enorme:
-
Aplicações, Ferramentas.
-
Informação, Comunidade.
-
-
Paradigmas modernos de descrição de dados e de programação.
-
Suporte para gráficos 2D (contexto
2d
esvg
) e 3D (x3dom
e contextowebgl
).
Web 2D
Os elementos canvas
e svg
:
-
São elementos
HTML
para gráficos 2D (e 3D). -
Proporcionam ferramentas para modelar:
-
Figuras Geométricas, Texto, Imagens.
-
Transparências, Gradientes, Transformações, Glifos.
-
Web 3D
-
O elemento
x3d
é usado para integrar conteúdo 3D diretamente num documentohtml
, sem extensões. -
A biblioteca
threejs
usa o elementocanvas
com contextowebgl
permite o rendering de gráficos 2D e 3D, sem extensões.
Exemplos elementares
canvas
com contexto 2D (C2D
)<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Exemplo C2D</title>
<script>
function main() {
let gc = document
.getElementById("acanvas") (1)
.getContext("2d"); (2)
gc.fillStyle = "steelblue"; (3)
gc.fillRect(0,0,256,256); (4)
}
</script>
</head>
<body onload="main();"> (5)
<canvas id="acanvas" (6)
width="256"
height="256" />
</body>
</html>
1 | Variável javascript que representa o elemento HTML identificado ("acanvas" ). |
2 | O contexto gráfico é um objeto com atributos e métodos de desenho. |
3 | Definir a cor da tinta como «azul». |
4 | Pintar um retângulo. |
5 | "main();" é a função que corre quando o browser «carrega» o documento. |
6 | "<canvas>" é o tipo de elemento HTML que proporciona um contexto gráfico. |
SVG
<!DOCTYPE svg PUBLIC (1)
"-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg (2)
xmlns="http://www.w3.org/2000/svg" (3)
xmlns:xlink="http://www.w3.org/1999/xlink"
width="512" height="512">
<path (4)
stroke="black"
fill="none"
d=" M 0 50
Q 50 0 100 50
Q 50 100 0 50
M 25 40
L 75 60
L 75 40
L 25 60
L 25 40" />
</svg>
1 | Identificação do tipo de documento XML . Neste caso, SVG . |
2 | Um modelo/uma cena 2D |
3 | Validação de conteúdos SVG . |
4 | Desenhar um «caminho». |
X3D
<!doctype html>
<html>
<head>
<meta encoding="utf-8">
<title>Exemplo X3D</title>
<script src="x3dom-full.js"></script>
<link rel="stylesheet" href="x3dom.css">
</head>
<body>
<x3d width="512px" height="512px">
<scene> (1)
<shape> (2)
<appearance>
<material
diffuseColor="orange"> (3)
</material>
</appearance>
<box size="2 2 2"> (4)
</box>
</shape>
</scene>
</x3d>
</body>
</html>
1 | Uma cena 3D… |
2 | … com um «objeto gráfico» … |
3 | … «pintado» de laranja … |
4 | … e com a forma de uma caixa. |
threejs
(3JS
)<!doctype html>
<html>
<head>
<meta charset = "utf-8" />
<title>Exemplo Three.js</title>
<script src = "three.js"></script>
<script type = "text/javascript" >
function main() {
let renderer = new THREE.WebGLRenderer();
renderer.setSize(500,500);
document.body.appendChild(renderer.domElement);
let scene = new THREE.Scene(); (1)
let camera = new THREE.PerspectiveCamera( (2)
35, // abertura
500/500, // proporção largura/altura
0.1, // corte perto
10000 // corte longe
);
camera.position.set( -2.5, 0, 20 );
//camera.position.set( 0, 0, 0 );
camera.lookAt( scene.position );
let geometry = new THREE.BoxGeometry( 5, 5, 5 ); (3)
let material = new THREE.MeshLambertMaterial(
{color: 0x00FF00 } ); (4)
let mesh = new THREE.Mesh( geometry, material ); (5)
scene.add( mesh ); (6)
let light = new THREE.PointLight( 0xFFFF00 ); (7)
light.position.set( -15, 10, 10 );
scene.add( light ); (8)
renderer.render( scene, camera );
}
</script>
</head>
<body onload = "main();">
</body>
</html>
1 | Um modelo/cena 3D… |
2 | … visto da perspetiva desta câmara. |
3 | Uma caixa… |
4 | … pintada de verde |
5 | … é um «objeto gráfico». |
6 | … acrescentado ao modelo. |
7 | Uma fonte de luz… |
8 | … para iluminar o modelo. |
Exercícios
Programação
-
Funções geradoras
-
Escreva uma função
repete(x, n)
que devolve umarray
comn
cópias dex
. -
Escreva uma função
aleatorios(n)
que devolve umarray
comn
números aleatórios. -
Escreva uma função
intervalo(a, b)
que devolve umarray
com os números inteiros entrea
eb
incluindo ambos os extremos. Seb < a
o resultado deve ser a lista vazia[]
. -
Escreva uma função
linspace(a, b, n)
que enche umarray
comn
números reais (float
) entrea
eb
, igualmente espaçados. Por exemplo,linspace(0, 1, 3)
devolve[0.0, 0.5, 1.0]
.
-
-
Filtros
-
Escreva uma função
pares(x)
que tem como argumento umarray x
de números inteiros e que devolve umarray
apenas com os números pares. Por exemplopares([1, 2, 4, 5, 2, 3])
devolve[2, 4, 2]
. -
Escreva uma função
positivos(x)
que tem como argumento umarray x
de números reais e que devolve umarray
apenas com os números positivos. Por exemplopositivos([1, -2.5, 0.4, 0.0, -1.5, 2, 2.3])
devolve[1, 0.4, 2, 2.3]
. -
Escreva uma função
limite_sup(x, a)
que tem como argumentos umarray x
de números reais e um valora
e que devolve umarray
apenas com os números menores ou iguais que o valora
. Por exemplolimite_sup([1, -2.5, 0.4, 0.0, -1.5, 2, 2.3], 0.4)
devolve[-2.5, 0.4, 0.0, -1.5]
. -
Escreva uma função
filtro(f, x)
que tem como argumentos uma funçãof: float -> boolean
e umarray x
de números reais e que devolve umarray
apenas com os númerosxi
dex
tais quef(xi) === true
. Por exemplofiltro(x => x % 2 === 0, [1, 2, 4, 5, 2, 3])
devolve[2, 4, 2]
. Quais das alíneas acima consegue tornar a resolver usando esta função?
-
-
Mapas
-
Escreva uma função
dobro(x)
que tem como argumento umarray x
de números reais e que devolve umarray
com os dobros desses números. Por exemplodobro([1, 2.1, 4, 5, -2, 3])
devolve[2, 4.2, 8, 10, -4, 6]
. -
Escreva uma função
quadrado(x)
que tem como argumento umarray x
de números reais e que devolve umarray
com os quadrados desses números. Por exemploquadrado([1, -2.5, 0.4])
devolve[1, 6.25, 0.16]
. -
Escreva uma função
unicos(x)
que tem como argumento umarray x
de números reais e que devolve umarray
sem valores repetidos. Por exemploquadrado([1, -2.5, 1])
devolve[1, -2.5]
. -
Escreva uma função
crescente(x)
que tem como argumento umarray x
de números reais e que devolve umarray
com os valores por ordem crescente. Por exemplocrescente([1, -2.5, 1])
devolve[-2.5, 1, 1]
. -
Escreva uma função
estender(x, n)
que tem como argumento umarray x
de números reais e um valor inteiron
e que devolve umarray
exatamente de comprimenton
. Se o comprimento dex
for menor quen
devem ser acrescentados zeros suficientes. Se o comprimento dex
for maior quen
os valores a mais são descartados. Por exemploestender([1, -2.5], 4)
devolve[1, -2.5, 0, 0]
, eestender([1, 6.25, 0.16], 2)
devolve[1, 6.25]
. -
Escreva uma função
mapa(f, x)
que tem como argumentos uma funçãof: float -> float
e umarray x
de números reais e que devolve umarray
com númerosyi = f(xi)
em quex = [ ..., xi, ...] +`. Por exemplo `+mapa(x => 2 * x, [1, 2.1, 4, 5, -2, 3])
devolve[2, 4.2, 8, 10, -4, 6]
. Quais das alíneas acima consegue tornar a resolver usando esta função?
-
-
Misturas
-
Escreva uma função
inverte(x)
que tem como argumentos oarray x
de números reais e que devolve umarray
com os valores dex
por ordem inversa (do último para o primeiro). -
Assegure-se que
x = cadeia(cabeca(n, x), cauda(n, x))
para qualquerx
e qualquern
, em que:-
A função
cadeia(x, y)
tem como argumentos doisarray x, y
de números reais e devolve umarray
com os valores dex
seguidos pelos valores dey
. Por exemplocadeia([1, 2.1, 4], [5, -2, 3])
devolve[1, 2.1, 4, 5, -2, 3]
. -
A função
cabeca(n, x)
tem como argumentos oint n
e oarray x
de números reais e devolve oarray
dos primeirosn
valores dex
. -
A função
cauda(n, x)
tem como argumentos oint n
e oarray x
de números reais e devolve oarray
com os valores dex
a partir don
-ésimo elemento.
-
-
Escreva uma função
somar(x, y)
que tem como argumentos doisarray x, y
de números reais e que devolve umarray
com os valores dex
somados aos valores dey
pela mesma ordem. Se os argumentos tiverem comprimentos diferentes o resultado deve ser a lista vazia:[]
. Por exemplosomar([1, 2.1, 4], [5, -2, 3])
devolve[6, 0.1, 7]
esomar([1, 2], [3])
devolve[]
. -
Escreva uma função
emparelhar(x, y)
que tem como argumentos doisarray x, y
de números reais e que devolve umarray
com objetos{x: xi, y: yi}
ondexi, yi
estão nas mesmas posições dex, y
. Se os argumentos tiverem comprimentos diferentes o resultado deve ser a lista vazia:[]
. Por exemploemparelhar([1, 2.1, 4], [5, -2, 3])
devolve[{x: 1, y: 5}, {x: 2.1, y: -2}, {x: 4, y: 3}]
eemparelhar([1, 2], [3])
devolve[]
. Consegue usar a funçãomapa
do exercício anterior para resolver esta alínea?
-
-
Agrupamentos
-
Escreva uma função
conta(x)
que tem como argumento umarray x
de números reais e que devolve o comprimento doarray
. Por exemploconta([1, 2, 3, 4])
devolve4
. -
Escreva uma função
soma(x)
que tem como argumento umarray x
de números reais e que devolve a soma desses números. Por exemplosoma([1, 2, 3, 4])
devolve10
. -
Escreva uma função
media(x)
que tem como argumento umarray x
de números reais e que devolve a média desses números. Por exemplomedia([1, 2, 3, 4])
devolve2.5
. -
Escreva uma função
max(x)
que tem como argumento umarray x
de números reais e que devolve o maior desses números. Por exemplomax([1, 2, 3, 4])
devolve4
. -
Escreva uma função
min(x)
que tem como argumento umarray x
de números reais e que devolve o menor desses números. Por exemplomin([1, 2, 3, 4])
devolve1
. -
Escreva uma função
stats(x)
que tem como argumento umarray x
de números reais e que devolve um sumário estatístico desses valores: um objeto com atributoscount, mean, stdev, min, max
. O atributocount
é o comprimento dex
, os valores demean, min, max
resultam das alíneas anteriores estdev
(o desvio padrão) pode ser calculado pela fórmula \(\sqrt{\frac{1}{n - 1}\sum_{i=1}^{n} (x_i - m)^2}\) onde \(n\) é a dimensão do vetor e \(m\) a sua média. Por exemplostats([1, 2, 3, 4])
devolve{count: 4, mean: 2.5, stdev: 1.291, min: 1, max: 4}
. -
Escreva uma função
dot(x, y)
que tem como argumentos doisarray x, y
de números reais e que devolve o produto interno dos vetores \(x\) e \(y\). Se os argumentos tiverem comprimentos diferentes o resultado deve ser a lista vazia:[]
. Por exemplodot([1, 2, 3], [4, 5, 6])
devolve32
. Torne a resolver esta alínea usando as alíneas e exercícios anteriores. -
Escreva uma função
norma(x)
que tem como argumento umarray x
de números reais e que devolve a norma do vetor \(x\). Por exemplonorma([1, 1])
devolve1.4142135624
. Lembre-se que a norma de um vetor \(x = (x_1, \ldots, x_n)\) é \[\lVert x \rVert = \sqrt{\sum_{i=1}^{n} x_i^2} = \sqrt{x \cdot x}.\]
-
Geometria
-
Encontre as coordenadas dos vértices dos seguintes triângulos:
Aplicações
-
Indique três aplicações (programas) que usam Computação Gráfica 2D.
-
Indique (procurando online, se necessário) cinco filmes que aplicaram Computação Gráfica (procure incluir também filmes 2D!)
-
Identifique as áreas dos seguintes problemas/tarefas
-
Localizar pontos brilhantes numa mamografia
-
Construir um modelo 3D de um prédio a partir de fotografias
-
Mostrar uma simulação do sistema solar com o sol e os oito planetas em movimento
-
Reconhecer a região cerebral numa ressonância magnética e mostrar um modelo 3D do cérebro
-
Usar computadores para gerar a cena de uma colisão entre automóveis
-
Fazer a identificação automática de uma pessoa a partir de uma fotografia
-
Gráficos 2D
Conceitos Fundamentais 2D
.jpg)
Na computação gráfica 2D, tanto os espaços dos objetos (onde são definidos os objetos gráficos) como o espaço do modelo (onde é definido o modelo) são 2D (isto é, planos). |
Modelação
O processo de modelação é relativamente simples:
|
Modelação de Objetos Gráficos
Geometria (forma)
A geometria de um objeto gráfico (2D ou 3D) é geralmente obtida com:
|
Transformações
As transformações são usadas para
|
Aspeto (propriedades não geométricas)
Além da construção da geometria (isto é, da forma) também são usadas propriedades que dizem respeito ao aspeto:
|
Geometria 2D
A geometria dos objetos gráficos usa linhas e outros conjuntos de pontos, como polígonos ou elipses.
O problema que se coloca aqui é saber como representar essas linhas, conjuntos de pontos, etc.
A representação dos objetos gráficos assenta na aplicação da matemática, em particular da Álgebra Linear e da Geometria Analítica, que proporcionam as definições formais (como ponto, plano, etc) e propriedades relevantes. |
Neste capítulo vamos explorar a representação matemática das entidades geométricas:
-
Sistemas de coordenadas (ou Referenciais).
-
Equações para retas, circunferências e elipses.
-
Equações paramétricas.
-
Caminhos e formas «irregulares».
Referenciais
Um referencial é a ferramenta matemática que permite representar numericamente espaços geométricos. Uma vez escolhido um referencial, cada ponto do espaço fica identificado por uma lista de números: as coordenadas desse ponto. Num espaço 2D as coordenadas têm duas componentes, \((x, y)\) e no espaços 3D têm três componentes \((x, y, z)\). |
Podemos escolher diferentes referenciais para tratar problemas diferentes. Dois dos referenciais mais comuns são:
-
O referencial cartesiano, normalmente usado na aulas de matemática.
-
O referencial do ecrã, normalmente usado em dispositivos gráficos;
Geometrias Primitivas
Matematicamente, um objeto gráfico, como uma linha reta ou uma circunferência, é um conjunto de pontos. |
Ingenuamente, poderíamos pensar em usar (digamos) listas com esses pontos. O problema é que mesmo os objetos gráficos mais simples são formados por infinitos pontos (quantos pontos existem numa linha?).
A solução para representar objetos gráficos consistem em usar equações. |
Uma equação tem uma quantidade finita de informação que define um conjunto infinito de pontos.
Por exemplo \((x - 2)^2 + (y + 1)^2 = 9\) é um texto finito que define os infinitos pontos da circunferência de raio \(3\) centrada em \((2, -1)\).
Equações Comuns
|
Questões
|
As equações dadas anteriormente não são a forma mais prática de trabalhar com Objetos Gráficos para efeitos da Computação Gráfica. |
Como obter 100 pontos da circunferência \(x^2 + y^2 = 3\)? Com equações paramétricas, que indicam explicitamente as coordenadas \(x, y\) dos pontos do objeto. |
-
Para a reta:
\[X = P + \lambda v \Rightarrow (x,y) = (P_x, P_y) + t (v_x, v_y) \Rightarrow \left\lbrace \begin{aligned} x &= P_x + t v_x \\ y &= P_y + t v_y \end{aligned} \right.\] -
Para a circunferência:
\[x^2 + y^2 = R^2 \Rightarrow \left\lbrace \begin{aligned} x &= R \cos t \\ y &= R \sin t \end{aligned} \right.\] -
Para a elipse:
\[\left (\frac{x - x_0}{a}\right)^2 + \left(\frac{y - y_0}{b}\right)^2 = 1 \Rightarrow \left\lbrace \begin{aligned} x &= x_0 + a \cos t \\ y &= y_0 + b \sin t \end{aligned} \right.\]
Equações Paramétricas e Geometria
As equações paramétricas usam um parâmetro (nestes exemplos, a variável \(t\)) que imaginamos que está a percorrer um certo intervalo (digamos \(\left\lbrack 0, 2\pi\right\rbrack\)). Conforme \(t\) vai tomando diferentes valores nesse intervalo, vamos também obtendo diferentes valores das coordenadas \(x,y\) dos pontos que formam a geometria do objeto gráfico. |
A equação paramétrica da reta tem um problema: O que acontece se \(B = 0\)?
Caminhos
As equações permitem representar eficientemente formas «regulares», mas nem sempre existe uma forma «regular» adequada ao objeto que se pretende construir… |
Os caminhos permitem definir formas «irregulares» que podem ser tratadas como «Objetos Básicos». |
Pensamos num caminho como (o resultado d)as operações que fazemos com um lápis numa folha de papel:
-
«traçar» um contorno;
-
«pintar» o interior dum contorno;
Traçar um Contorno
Um contorno é formado por por vários segmentos. Cada segmento é traçado a partir do fim do segmento anterior, como um lápis numa folha de papel.
Há quatro tipos básicos de segmentos:
-
salto: o lápis salta para uma certa posição.
-
linha: o lápis desenha uma reta até uma certa posição.
-
curva quadrática: o lápis desenha uma curva, controlada por um ponto, até uma certa posição.
-
curva cúbica: o lápis desenha uma curva, controlada por dois pontos, até uma certa posição.
"Pintar" Caminhos
«Pintar» um caminho (isto é, encher a zona delimitada pelo caminho) é uma tarefa surpreendentemente difícil de «programar».
O problema pode ser formulado da seguinte forma:
Dada um retângulo com um caminho fechado lá dentro, como determinar se um dado ponto está dentro ou fora da região delimitada pelo caminho?
É usado um de dois algoritmos (regras) para encher um caminho:
-
A regra par-ímpar é mais simples e por isso menos «controlável».
-
A regra não-zero é mais complexa do que a regra par-ímpar mas permite tirar partido da orientação dos segmentos para definir o interior do caminho.
Ambas as regras funcionam com base no seguinte princípio:
-
O retângulo é «varrido de cima para baixo» por linhas que «andam» da esquerda para a direita.
-
Em cada uma dessas linhas são calculados os pontos que intersectam o caminho.
-
É aplicada uma das regras para determinar quais segmentos limitados por esses pontos são interiores e quais são exteriores ao caminho.
A regra par-ímpar | A regra não-zero |
---|---|
Os segmentos do caminho têm de ser orientados. |
|
Os pontos de interseção são numerados da esquerda para a direita (a começar em zero). |
Os pontos de interseção são:
|
Os segmentos interiores estão entre um ponto par (azul) e um ponto ímpar (vermelho). |
Os segmentos interiores estão entre pontos com total acumulado não zero (estritamente positivo ou negativo). |
Explore o código |
Aspeto 2D
A apresentação de um objeto gráfico, além da forma (definida pela geometria) também depende de outras propriedades visuais:
-
cores, traços e tintas;
-
textos e fontes;
Cores
A especificação numérica de uma cor depende de um espaço numérico. Conforme a aplicação do modelo gráfico, certos espaços são mais adequados que outros:
-
Para ecrãs, onde a cor é emitida, a escolha mais comum é um espaço RGB onde cada cor fica definida por três componentes
(r,g,b)
correspondentes a vermelho, verde e azul. -
Para impressão, onde a cor é refletida, usam-se espaços CMY (cião, magenta e amarelo) ou CMYK (cião, magenta, amarelo e preto). A adição do preto resulta da dificuldade de se produzir economicamente o preto com as restantes componentes.
-
Para certas aplicações a escolha de uma cor em termos de RGB ou CMY (definidos em função do hardware) pode iludir a perceção humana; Um espaço de cor definido em termos de perceção humana é o HSL (de hue=tom, saturation=saturação e luminosity=luminosidade).
No contexto da web o espaço de cor normal é o RGB; Há imensas formas de especificar concretamente uma cor mas a mais comum é da forma
#rrggbb
em que rr
, gg
e bb
são números entre 0 e 255 representados em notação hexadecimal. Por exemplo:
cor | código hexadecimal | exemplo |
---|---|---|
cião |
|
|
magenta |
|
|
amarelo |
|
|
Traços
Os traços (isto é, as propriedades visuais das linhas) são inesperadamente complexos.
Uma linha desenhada num dispositivo não é um objeto abstrato (como uma linha matemática, de espessura 0). Na prática as linhas têm formas específicas.
Os traços são definidos por
-
uma espessura;
-
um tracejado;
-
as formas das extremidades;
-
o estilo da junções com outros traços;
-
o controlo das junções;
Tintas
A tinta define como uma forma é pintada. Há várias formas de pintar uma geometria:
-
usando uma cor sólida;
-
usando um mosaico (uma imagem repetida);
-
usando um gradiente de cores (uma variação suave entre cores);
Uma tinta pode ser aplicada apenas ao contorno (stroke) ou encher (fill) o interior da geometria:
Mosaicos
O uso de mosaicos para traçar ou encher o contorno é semelhante à aplicação de uma cor sólida, com a particularidade de que a «cor» é um padrão repetido:
Gradientes de Cores
Os gradientes mais simples são lineares: uma cor inicial vai mudando suavemente ao longo de uma linha, até chegar a uma cor final. Também podemos definir versões um pouco mais complexas, com várias cores:
A forma de definir gradientes «multi-coloridos» consiste em associar cores a pontos de paragem. Um ponto de paragem fica definido por um certo offset
(deslocamento) do caminho entre o ponto mais à esquerda e o ponto mais à direita:
-
o ponto mais à esquerda tem
offset
0; -
o ponto mais à direita tem
offset
1; -
pontos intermédios têm
offset
entre 0 e 1. Por exemplo, um ponto exatamente a meio temoffset
0.5 e um ponto a um quarto «do caminho» temoffset
0.25;
Por exemplo, o gradiente acima está definido com:
-
um ponto de paragem com
offset
0.00 e corkhaki
: -
um ponto de paragem com
offset
0.20 e corsteelblue
: -
um ponto de paragem com
offset
0.75 e corcrimson
: -
um ponto de paragem com
offset
1.00 e cordarkseagreen
:
Outra propriedade que controla a aplicação dos gradientes é a repetição, que em geral tem três formas:
Finalmente, um gradiente também pode ser circular (em vez de linear):
Texto
Texto e Fonte
O uso de textos envolve selecionar uma fonte e desenhar o texto de acordo com essa fonte.
|
Letras, Dígitos, Glifos
Tecnicamente, glifo é o termo que designa, em conjunto:
|
As propriedades das fontes estão definidas na norma CSS Fonts Module Level 3 e incluem, entre outras:
atributo | variantes |
---|---|
família ( |
serif, sans-serif, monospace |
estilo ( |
normal, italic |
espessura ( |
normal, bold, bolder, lighter |
tamanho ( |
small, medium, large |
Transformações 2D
Como já vimos, o Processo da Computação Gráfica determina que cada cena deve ser construida seguindo os seguintes passos:
-
Construção de cada Objeto Gráfico nos respetivo Espaço do Objeto;
-
Construção do Modelo, no Espaço do Mundo, juntando os vários Objetos Gráficos do ponto anterior;
-
Construção (Rendering) final, no Espaço do Dispositivo, com base no Modelo do ponto anterior e das definições da Vista;
O último passo, do Rendering, assenta num conjunto de transformações e outras operações (por exemplo, no clipping) que, normalmente, são automaticamente tratadas pelo sistema gráfico em que se está a trabalhar.
Falta esclarecer:
-
Como é construído cada Objeto Gráfico no seu espaço;
-
Como esse objeto é «transportado» para o Espaço do Mundo;
As Transformações são as principais ferramentas nestes passos. Neste capítulo vamos ilustrar o papel que desempenham.
Transformações: Representação matricial e Casos Especiais
Uma transformação é uma função que aplica pontos em pontos:
\[(x_0,y_0) \stackrel{T}{\to} (x_1,y_1)\]
Para a computação gráfica interessam apenas alguns tipos de transformações. Os tipos principais de transformações são:
|
Adicionalmente ainda podem ser usadas reflexões (em relação a um certo eixo) e deslizamentos (numa certa direção).
A escolha destes tipos de transformações assenta nas seguintes razões:
-
são suficientemente expressivos para a maior parte das necessidades da computação gráfica;
-
são intuitivamente acessíveis;
-
são numericamente eficientes;
A eficiência numérica assenta na forma como os cálculos são efetuados: as coordenadas transformadas \((x_1,y_1)\) resultam de multiplicar as coordenadas originais \((x_0,y_0)\)por uma matriz de transformação:
Os valores concretos dos parâmetros \(a,b,c,d,e,f\) dependem da transformação concreta que se pretende aplicar às coordenadas originais.
Nas páginas seguintes vamos ver como esses valores também dependem do tipo de transformação.
Translações
Uma translação consiste em mover as coordenadas originais \((x_0, y_0)\) segundo um certo vetor \((dx, dy)\).
Isto é, as coordenadas transformadas são obtidas por \( (x_1, y_1) = (x_0, y_0) + (dx, dy) \)
A matriz de translação é
e temos
Rotações
Uma rotação consiste em rodar as coordenadas originais \((x_0, y_0)\) segundo um certo ângulo \(\alpha\) em torno da origem \((0,0)\).
A matriz de rotação é
e temos
Escalas
Uma escala consiste em encolher ou esticar as coordenadas originais \((x_0, y_0)\) segundo um certo fator \((sx, sy)\).
A matriz de escala é
e temos
Composição
Nem sempre as transformações básicas são suficientes para construir os objetos gráficos pretendidos.
Nesse caso é necessário compor as transformações básicas de forma a obter-se o efeito pretendido.
Motivação da composição ilustrada acima
Supondo que se pretende escalar e rodar um certo objeto gráfico, sem o deslocar da posição em que está. O problema está na rotação, quo o feita em torno da origem do referencial, e não em torno do «centro do objeto». A solução consiste em compor várias transformações de forma a obter-se o efeito pretendido. Geometricamente:
|
Explore o código |
Exercícios 2D
Reveja a matéria de Álgebra Linear e de Geometria Analítica. |
Geometria 2D
-
Considere a equação paramétrica da reta, \(X = P + \lambda v\). Suponha que são dados dois pontos, \(A = (a_x, a_y)\) e \(B=(b_x, b_y)\). Determine os valores dos parâmetros \(P, v\) da reta que passa em \(A, B\) e tais que \(A = P + \lambda v\) quando \(\lambda = 0\) e \(B = P + \lambda v\) quando \(\lambda = 1\).
-
Escreva uma expressão matemática para definir:
-
Os segmentos de reta \((0,0) - (0,1)\), \((0,0) - (1,0)\) e \((0,0) - (1,1)\).
-
O triângulo de vértices \((0,0) - (0,1) - (1,0)\).
-
O quadrado \((0,0) - (1,0) - (1,1) - (0,1)\).
-
O interior do quadrado e triângulo anteriores.
-
-
Encontre os valores dos parâmetros da equação paramétrica:
-
Da reta:
-
Que passa nos pontos \((0,0)\) e \((0,1)\).
-
Que passa nos pontos \((0,0)\) e \((1,0)\).
-
Que passa nos pontos \((0,0)\) e \((1,1)\).
-
-
Da reta com equação algébrica:
-
\(2x + 3y - 4 = 0\).
-
\(3x - 2y - 4 = 0\).
-
\(4x + 6y - 8 = 0\).
-
-
Da circunferência:
-
Centrada em \((0,1)\) e de raio \(2\).
-
Centrada em \((1,0)\) e de raio \(2\).
-
Centrada em \((1,1)\) e de raio \(2\).
-
Centrada em \((0,1)\) e que passa no ponto \((0,0)\).
-
Centrada em \((1,0)\) e que passa no ponto \((0,0)\).
-
Centrada em \((1,1)\) e que passa no ponto \((0,0)\).
-
-
Programação 2D
-
Calcule os parâmetros
A, B, C
da equação algébrica da reta (\(Ax + By + C = 0\)), dadas as coordenadas(x1, y1), (x2, y2)
de dois pontos:-
Implemente a função
eqna_s(x1, y1, x2, y2)
que devolve um objeto com atributos{A, B, C}
. -
Em que casos é que as entradas
x1, y1, x2, y2
não definem uma reta?No seu código detete esse caso e devolva
null
. -
Em que casos é que
A1, B1, C1
define a mesma reta queA2, B2, C2
?Implemente uma função
equala_ss(A1, B1, C1, A2, B2, C2)
que devolvetrue
se os parâmetros definem a mesma reta efalse
caso contrário.
-
-
Calcule os parâmetros
P, v
da equação paramétrica da reta (\(X = P + \lambda v\)), dadas as coordenadas(x1, y1), (x2, y2)
de dois pontos:-
Implemente a função
eqnp_s(x1, y1, x2, y2)
que devolve um objeto com atributos{P, v}
. -
Em que casos é que as entradas
x1, y1, x2, y2
não definem uma reta?No seu código detete esse caso e devolva
null
. -
Em que casos é que
P1, v1
define a mesma reta queP2, v2
?Implemente uma função
equalp_ss(P1, v1, P2, v2)
que devolvetrue
se os parâmetros definem a mesma reta efalse
caso contrário.
-
-
Implemente uma função
dot(x1, y1, x2, y2)
para calcular o produto interno e use-a para implementar funções para calcular:-
A distância entre dois pontos,
dist_pp
. -
A distância de um ponto a uma reta,
dist_ps
. -
O «reflexo» de um ponto por uma reta,
mirror_ps
. -
O «reflexo» de uma reta por outra reta,
mirror_ss
. -
Se duas retas são perpendiculares,
are_perp
.
-
-
Pode gerar pontos de uma circunferência usando uma equação paramétrica.
-
Implemente a função
points_c(x1, y1, r, n)
que gera uma lista comn
pontos equidistantes da circunferência de centrox1, y1
e raior
. -
Use a função
points_c
para estimar a distância de uma circunferência a:-
Um ponto:
edist_cp
. -
Uma reta:
edist_cl
. -
Outra circunferência:
edist_cc
.
-
-
-
Pode gerar pontos de um segmento de reta usando os dois extremos do segmento e uma equação paramétrica.
-
Implemente a função
points_s(x1, y1, x2, y2, n)
que gera uma lista comn
pontos equidistantes do segmento limitado pelos pontos(x1, y1)
e(x2, y2)
. Sugestão: Use a equação vetorial da reta:\[(x, y) = \lambda ( x_2 - x_1, y_2 - y_1 ) + (x_1, y_1)\] -
Estime a distância de um segmento de reta a:
-
Um ponto:
edist_sp
. -
Outro segmento de reta:
edist_ss
. -
Uma circunferência:
edist_sc
. Suponha que a circunferência:-
está definida por centro e raio.
-
está aproximada por um conjunto de pontos.
-
-
-
-
A forma de representar as coordenadas dos pontos usada acima é muito «trapalhona». Em vez de usar
x1, y1
(ou outros indíces) use listas,P1 = [x1, y1]
, para representar pontos. Atualize todas as funções anteriores. Por exemplo,x = dot(P, Q)
. -
Pode obter formas simples usando apenas conjuntos de pontos para definir o contorno do objeto gráfico. Implemente:
-
A função
join(A, B)
em queA
eB
são listas de pontos e que devolve a lista que resulta de acrescentar os pontos deB
a seguir aos pontos deA
. -
A função
frame(A)
que calcula os cantos superior esquerdo e inferior direito dos pontos emA
, isto ém a moldura para os pontos deA
. -
A função
min_circ(A)
que calcula a menor circunferência que contém todos os pontos deA
. Resolva em duas versões: uma que devolve o centro e o raio da circunferência e outra que devolve uma aproximação comn
pontos.
-
-
Pode transformar pontos usando as operações da álgebra linear.
-
Implemente a função
[x1, y1, z1] = dot_mv(a,b,c,d,e,f,g,h,i,x0,y0,z0)
que calcula\[\begin{bmatrix} x_1 \\ y_1 \\ z_Y \end{bmatrix} = \begin{bmatrix} a & b & c \\ d & e & f \\ g & h & i \end{bmatrix} \begin{bmatrix} x_0 \\ y_0 \\ z_0 \end{bmatrix}.\] -
A forma de representar matrizes e vetores na alínea anterior é muito «trapalhona». Represente os vetores por listas
v = [x, y, z]
e as matrizes por listas de listas:A = [[a, b, c], [d, e, f], [g, h, i]]
Note que
A[0]
é a primeira linha deA
. -
Implemente funções para gerar matrizes e calcular operações comuns:
-
A matriz
zeros(n,m)
temn
linhas,m
colunas e todas as entradas são0
. -
Na matriz
ones(n, m)
temn
linhas,m
colunas e todas as entradas são1
. -
A matriz
eye(n)
é a matriz identidade de ordemn
. -
A função
t(A)
é a matriz transposta deA
. -
A função
sum_mm(A, B)
soma as matrizesA
eB
. Se as dimensões forem incompatíveis, devolvenull
. -
A função
dot_mm(A, B)
multiplica as matrizesA
eB
. Se as dimensões forem incompatíveis, devolvenull
. -
A função
translate(dx, dy)
devolve a matriz da translação por(dx, dy)
. -
A função
rotate(alpha)
devolve a matriz da rotação poralpha
radianos. -
A função
scale(sx, sy)
devolve a matriz da escala por(sx, sy)
.
-
-
-
Use a biblioteca de funções que definiu acima para construir e transformar (aproximações) de circunferências e de segmentos. Visualize as formas originais (a verde) e transformadas (a vermelho) nos sistemas
C2D
eSVG
. -
Implemente a regra par-ímpar de enchimento de formas. Suponha que
F
é um conjunto de pontos que aproxima uma figura 2D:-
Defina a função
sort_h(F)
que devolve os pontos deF
ordenados da esquerda para a direita (isto é, primeiro os pontos com menor coordenadax
). -
Defina a função
strip_h(F, y0, e)
que devolve os pontos deF
que estão numa faixa horizontal, isto é os pontos deF
cuja coordenaday
é tal que \(\left| y - y_0 \right| \leq e\). Se não existirem pontos assim emF
, devolve a lista vazia. -
Defina a função
first_left(F)
que devolve o ponto mais à esquerda deF
. SeF
for uma lista vazia devolvenull
. -
Defina a função
next_right(F, x0)
que devolve o ponto deF
que, de todos os pontos deF
com coordenadax
maior quex0
, é o que tem menor coordenadax
. Se não existir tal ponto devolvenull
. -
Use as funções
sort_h, strip_h, first_left
enext_right
para definir a funçãofill_evenodd(F, …)
, que implementa a regra par-ímpar por faixas horizontais.O resultado deve ser uma lista com os segmentos horizontais interiores, sendo cada segmento definido por dois pontos.
Considere ainda que argumentos são úteis e/ou necessário e como detetar e assinalar potenciais erros.
-
-
Visualize o preenchimento de formas pela regra par-ímpar usando vermelho para a forma e verde para o interior. Resolva esta alínea para os sistemas
C2D
eSVG
. -
Visualize o interior da forma usando os sistemas
C2D
eSVG
com:-
Um gradiente horizontal com várias cores (pelo menos 3).
-
Um gradiente vertical com várias cores (pelo menos 3).
-
Um padrão xadrez.
-
Modelação 2D
-
Escreva um programa que use o
C2D
para desenhar um caminho entre os pontos de coordenadas (0,0) e (64,64) que tenha um arco de raio 16. -
Escreva um programa
javascript
para oC2D
que desenhe um círculo amarelo no meio de um retângulo 100x100 azul. Defina a mesma imagem com um documentoSVG
. -
Procure na internet: Qual é o intervalo dos comprimentos de onda das cores visíveis?
-
Marque os seguintes pontos num referencial cartesiano e num referencial de ecrã (desenhados numa folha de papel):
(1, 3), (-2, 1.5), (0, -2), (0, 0), (2, 1), (-1.5, 1.5), (3, -0.5)
-
Escreva um programa
javascript
para oC2D
, e um documentoSVG
para desenhar:-
Uma meia lua:
-
Um quadrado centrado e rodado 45º.
-
Um tabuleiro de xadrez.
-
Um tabuleiro tri-colorido. Generalize para uma função que desenhe um tabuleiro n-colorido.
-
O símbolo oriental Yin-Yang:
-
Um retângulo pintado com um gradiente radial acíclico.
-
Um retângulo pintado com um gradiente radial cíclico.
-
Um octógono. Generalize para um n-ágono.
-
Uma estrela de cinco pontas. Generalize para n pontas.
-
Desenhe a bandeira da união europeia.
-
-
Implemente uma função
javascript
para ajudar a desenhar o gráfico de uma função:grafico(f, n, a, b)
devolven
pontos(xi, f(xi))
do gráfico da funçãof : float → float
, com osxi
igualmente espaçados no intervalo[a, b]
. Implemente funções para adaptar as listas produzidas porgrafico(…)
a caminhosC2D
eSVG
. -
Implemente uma pequena biblioteca gráfica 2D.
-
Suponha que cada objeto gráfico é definido por:
-
Um caminho, isto é uma lista de pontos
x, y
. -
Uma transformação com uma translação, uma rotação e uma escala.
-
Propriedades de aspeto (
stroke
efill
). -
Descendentes: uma lista de objetos gráficos.
-
-
Implemente uma função para desenhar estes objetos gráficos num
C2D
e para produzir um elementoSVG
.
-
Gráficos 3D
Conceitos Fundamentais 3D

A Computação Gráfica 3D trata o problema da visualização a 2D de modelos 3D.
Um modelo 3D é composto por objetos gráficos, fontes de luz e câmaras
Um sistema gráfico 3D tem de resolver os muitos problemas derivados da representação dos objetos, das transformações, da organização e do rendering da cena.
Funções de um sistema gráfico 3D
|
Geometria 3D
Tipos de Geometrias
Técnicas para definir geometrias 3D.
Para aproximar a geometria de um objeto gráfico ideal podem usar-se:
|
Além destas formas de construção de geometrias «estáticas» também são usadas técnicas que deformam a geometria inicial e que envolvem «esqueletos» e/ou «morphing». Estes técnicas não constam do programa deste curso. |
Geometria Construída
Exemplo X3D |
Exemplo 3JS |
---|---|
Além das formas básicas, em geral estão disponíveis outras métodos para definir a geometria dos objetos gráficos.
Os métodos principais para construir geometrias são:
-
As geometrias parametrizadas; em particular, extrusões.
-
Os conjuntos de faces.
Exemplo/Aplicação da construção de geometrias.
Vamos ilustrar estes dois métodos construindo um objeto que usa ambos. O casco de um barco tem três partes:
|
Extrusões
A secção… | …transportada ao longo da espinha… | …gera uma geometria 3D. |
---|---|---|
Exemplos de extrusões.
|
Parâmetros das extrusões.
Uma extrusão é definida por:
Estes parâmetros definem uma geometria de acordo com o seguinte processo:
|
Versão X3D |
Versão 3JS |
||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
||||||||||||||||
No |
No |
Conjuntos de Faces
A versão final da proa, um conjunto de faces. | A proa em wireframe, com faces poligonais. | A proa em wireframe, com faces triangulares. |
---|---|---|
O |
No |
Formas pouco regulares (por exemplo, um rosto ou um terreno) têm de ser construídas definido individualmente as coordenadas dos vértices e ligando esses vértices para formar faces (triângulos ou quadriláteros). |
Parâmetros dos conjuntos de faces.
Um conjunto de faces é definido por:
|
Versão X3D |
Versão 3JS |
||||||||
---|---|---|---|---|---|---|---|---|---|
|
|
Listas de vértices, índices e faces.
Nos exemplos acima as faces são listas de índices. Mais concretamente, em ambos os exemplos:
|
Aspeto 3D
A luz é refletida segundo um certo ângulo tangente à superfície do objeto no ponto onde incide.
|
O aspeto percecionado de um objeto depende:
-
Da textura desse objeto.
-
Da iluminação da cena.
Parâmetros das texturas.
As texturas (ou materiais) são propriedades do objeto que contribuem para a sua perceção. Definem como o objeto é «pintado» e como transforma a luz.
|
Tipos de iluminação.
A iluminação resulta de um conjunto de propriedades do modelo (da cena) que contribuem para a perceção dos vários objetos nesse modelo.
|
Texturas
Vejamos o efeito que cada caraterística das texturas tem na perceção (e realismo) do objeto seguindo um exemplo: o planeta terra.
A geometria da terra é (aproximadamente) uma esfera, e vamos supor que na cena há um ponto de luz razoavelmente afastado, de forma a simular o sol.
- Mapas de Cores (difusão: diffuse)
-
São as cores «próprias» do objeto:
luz refletida = cor do objeto + luz incidente
Para pintar «num passo» todas as cores da superfície da esfera usa-se uma textura para a difusão das cores. |
Mapa de Difusão | Efeito do Mapa |
---|---|
A esfera fica pintada com as cores pretendidas mas falta realismo à imagem. Por exemplo, as superfícies líquidas devem refletir muito mais luz do que as massa de terra. |
- Mapas de Reflexos (specular)
-
Determinam a quantidade de luz refletida:
luz refletida = reflexo * luz incidente
Para definir «num passo» os reflexos na superfície da esfera usa-se uma textura para a reflexão das cores. Nestas texturas branco significa «reflete 100%», preto significa «reflete 0%» e tons intermédios refletem percentagens intermédias.
|
A principal avanço em relação aos mapas de difusão «simples» nota-se nas zonas que devem brilhar.
Por exemplo, nas zonas com água (rios, lagos, mares, oceanos) pode ver-se o reflexo do «sol» enquanto que nas zonas «de terra» não há grandes diferenças.
Mapa de Reflexos | Efeito do Mapa |
---|---|
Sem Mapa de Reflexos | Efeito do Mapa |
---|---|
As superfícies planas, como os rios, lagos, mares, estão mais reais do que antes. Mas ainda falta realçar o efeito do relevo nas sombras. |
- Mapas de Normais (normals)
-
Determinam a direção da luz refletida:
ângulo da luz refletida = normal + ângulo da luz incidente
Para definir «num passo» as normais à superfície da esfera usa-se uma textura para as normais. |
Representação das normais por uma imagem.
Uma normal é um vetor no espaço 3D e, como tal, tem três componentes Uma cor também tem três componentes, |
Sem Mapa de Normais | Efeito do Mapa de Normais |
---|---|
A principal diferença em relação ao resultado anterior está nas zonas rugosas. Por exemplo, nas zonas montanhosas podem ver-se as sombras como o efeito do relevo. |
Pode ver o resultado final, com difusão, reflexos e normais aqui. |
Mapas UV
Textura de Difusão | Geometria | Efeito «Ingénuo» |
---|---|---|
Temos uma textura de difusão… |
…e uma geometria. |
O que pode correr mal? |
Controlo de aplicação das texturas
As texturas definidas por imagens são uma forma conveniente de refinar o aspeto de um objeto gráfico. Para funcionar corretamente, é preciso controlar como cada sector da textura é associado a cada face da geometria do objeto. |
Termos e processo dos mapas UV
Resumidamente, o processo para aplicar uma textura a uma geometria consiste em:
Especificamente:
|
A aplicação de mapas UV é adequado a geometrias definidas por conjunto de faces onde os vértices e as faces estão explicitamente indicados. |
UV
do «dado»O processo para ilustrar a aplicação dos mapas UV
é o seguinte:
-
Definir os vértices e as faces da geometria 3D.
-
Definir os pontos e os setores da textura 2D.
Por convenção, o primeiro setor é aplicado à primeira face, etc. |
Coordenadas dos Vértices XYZ do Cubo | Faces do Cubo |
---|---|
|
|
A «marcação» dos pontos na textura consiste apenas em indicar as coordenadas Porém, dado que |
Pontos UV na Textura de Difusão | Coordenadas dos Pontos UV |
---|---|
|
7 8 3 2 // setor #0 para a face #0
11 6 5 10 // setor #1 para a face #1
2 3 1 0 // setor #2 para a face #2
3 8 9 4 // setor #3 para a face #3
8 7 12 13 // setor #4 para a face #4
5 4 9 10 // setor #5 para a face #5
Regra da mão direita
Na definição dos setores, Tem de usar a regra da mão direita para se determinar o lado da face como uma página numa folha de papel. |
Transformações 3D
As transformações colocam os objetos gráficos no espaço e alteram a sua forma, tamanho e posição.
Além disso também são usadas pelos sistemas gráficos para produzir a vista 2D do modelo 3D.
Tipos de transformações
Normalmente são usados dois tipos de transformações nos sistemas gráficos 3D:
|
Vistas, câmaras e parâmetros
Uma vista de uma cena é obtida fazendo uma certa projeção do modelo, precisamente da mesma forma que uma câmara fotográfica produz uma imagem 2D de um ambiente 3D. A projeção que define a vista é normalmente designada câmara e depende de um conjunto de parâmetros. Os mais comuns são:
|
Exercícios 3D
Geometria 3D
-
Vetor Perpendicular 1. Dados dois vetores 3D \(u = (u_x, u_y, u_z), v = (v_x, v_y, v_z)\), como é que encontra um terceiro vetor \(w=(w_x, w_y, w_z)\) que é perpendicular a ambos?
-
Vetor Perpendicular 2. Como é que adapta a resolução do exercício anterior para o caso em que, em vez de dois vetores, são dados três pontos 3D, \(A=(A_x, A_y, A_z), B=(B_x, B_y, B_z), C=(C_x, C_y, C_z)\)?
Programação 3D
-
Distância. Implemente uma função
dist(p, q)
que calcula a distância entre dois pontos. Suponha que os pontos são definidos por objetos{x, y, z}
. -
Produto Externo. Implemente a função
outer(u, v)
que calcula o produto externo entre dois vetores. Supondo que \(w = u \otimes v\), então as componentes de \(w\) podem ser calculadas por\[w_x \mathbf{x} + w_y \mathbf{y} + w_z \mathbf{z} = \begin{vmatrix} \mathbf{x} & \mathbf{y} & \mathbf{z} \cr u_x & u_y & u_z \cr v_x & v_y & v_z \end{vmatrix}\]
Conjuntos de Pontos
-
Centro. Implemente uma função
center(points)
que calcula o centro de umarray
de pontos. -
Próximo. Implemente a função
nearest(target, points)
em quetarget
é um ponto 3D epoints
é umarray
de pontos 3D e que encontra o elemento depoints
que está mais próximo detarget
. A sua função deve devolver um objeto com atributos{d, p}
em qued
é a distância ep
o ponto mais próximo. -
Afastado. Implemente a função
farthest(target, points)
em quetarget
é um ponto 3D epoints
é umarray
de pontos 3D e que encontra o elemento depoints
que está mais afastado detarget
. Resolva de forma semelhante à alínea anterior. -
«Mais Isolado». Implemente a função
loneliest(points)
em quepoints
é umarray
de pontos 3D e que encontra o ponto «mais isolado» de um conjunto de pontos. O ponto «mais isolado» é o que está mais distante do centro. -
«Mais Central». Implemente a função
centralest(points)
em quepoints
é umarray
de pontos 3D e que encontra o ponto «mais central» de um conjunto de pontos. O ponto «mais central» é o que está mais perto do centro. -
Canto Superior Direito Anterior. Implemente a função
corner_trf(points)
(trf
: top right front) em quepoints
é umarray
de pontos 3D e que encontra o «canto superior direito anterior» (SDA) de um conjunto de pontos. As coordenadas do SDA são os valores máximos nos eixos x, y e z. Por exemplo:
let points = [
{x: -1, y: 2, z: 0},
{x: 20, y: 1, z: 3}
];
{x: 20, y: 2, z: 3} === corner_trf(points);
O SDA não tem de ser um dos pontos dados. |
-
Canto Inferior Esquerdo Posterior. Implemente a função
corner_llb(points)
(llb
: lower left back) nos mesmos moldes do exercício anterior, substituindo o máximo pelo mínimo. -
Pontos Mais Afastados. Implemente a função
most_apart(points)
em quepoints
é umarray
de pontos 3D e que encontra os dois elementos depoints
que estão mais afastados um do outro. Isto é, sep, q
forem esses pontos então, dados quaisquer dois pontosa
eb
empoints
,dist(a,b) <= dist(p,q)
. -
Pontos Menos Afastados. Implemente a função
least_apart(points)
em quepoints
é umarray
de pontos 3D e que encontra os dois elementos distintos depoints
que estão menos afastados um do outro. Isto é, sep, q
forem esses pontos então, dados quaisquer dois pontosa
eb
empoints
,dist(a,b) >= dist(p,q)
.
Processamento de Extrusões
Na construção de uma extrusão a secção percorre a espinha. Suponha que:
-
A secção é definida por um
array
de pontos 2D{x, z}
(note que é usadoz
e nãoy
). -
A espinha é definida por um array de vetores 3D
{x, y, z}
.
Estes dois parâmetros definem os vértices da geometria obtida por extrusão. Mais concretamente, cada ponto p:{x, z}
da secção e cada vetor v:{x, y, z}
da espinha definem o vértice q = {x: p.x + v.x, y: v.y, z: p.z + v.z}
da extrusão.
Por exemplo, dados
let seccao = [
{x: 0.0, z: 0.0},
{x: 1.0, z: 0.0},
{x: 0.0, z: 1.0} ];
let espinha = [
{x: 0.0, y: 0.0, z: 0.0},
{x: 0.0, y: 1.0, z: 0.0},
{x: 1.0, y: 2.0, z: -1.0} ];
o ponto seccao[2] === {x: 0.0, z: 1.0}
e o vetor espinha[1] === {x: 0.0, y: 1.0, z: 0.0}
definem o vértice {x: 0.0, y: 1.0, z: 1.0}
.
-
Escreva a função
vertex(i, j, section, spine)
que devolve as coordenadasxyz
do vértice definido peloi
-ésimo ponto da secção e peloj
-ésimo passo da espinha.Por exemplo, usando as variáveis acima,
vertex(1, 2, seccao, espinha)
é o ponto 3D{x: 2.0, y: 2.0, z: -1.0}
, que resulta do ponto{x: 1.0, z: 0.0}
e do vetor{x: 1.0, y: 2.0, z: -1.0}
.Assegure-se que
i
ej
são índices válidos. Se não o forem a função deve devolvernull
.
Outros Casos
-
Grelha de elevação em 3JS. A biblioteca
3JS
não tem um construtor «direto» equivalente àElevationGrid
doX3D
. Estude este elemento, determine três parâmetros que mais contribuem para esta geometria e faça uma implementação para o3JS
.
Modelação 3D
-
Desenhar um referencial. Faça um documento
X3D
e um programa3JS
que desenhem um referencialXYZ
. Assegure-se que os eixos estão corretamente orientados e use o seguinte esquema de cores:X:red; Y:green; Z:blue
. -
Desenhar uma pirâmide. Faça um documento
X3D
e um programa3JS
que desenhem uma pirâmide em wireframe. -
Desenhar um frustum. Um frustum (veja também o artigo na wikipédia) é um poliedro (isto é, um sólido com todas as faces planas) com duas das faces quadradas paralelas (o topo e a base). Faça um documento
X3D
e um programa3JS
que desenhem um frustum em wireframe em que a base é um quadrado de lado 2, o topo um quadrado de lado 1 e com altura 1. -
Desenhar um octaedro.
Um octaedro é um dos cinco sólido platónicos (veja o artigo na wikipédia); tem oito faces triangulares e seis vértices:
\[(0,0,-1), (-1,0,0), (0,-1,0), (1,0,0), (0,1,0), (0,0,1)\]Faça um documento
X3D
e um programa3JS
que desenhem um octaedro em wireframe. -
Desenhar um icosaedro.
Um icosaedro é um dos cinco sólido platónicos (veja o artigo na wikipédia) e tem os vértices seguintes:
\[\begin{aligned} && (0,\phi,1) && (0,\phi,-1) \cr && (-\phi,1,0) && (\phi,1,0) \cr (1,0,\phi) && (1,0,-\phi) && (-1,0,-\phi) && (-1,0,\phi) \cr && (-\phi,-1,0) && (\phi,-1,0) \cr && (0,-\phi,-1) && (0,-\phi,1) \end{aligned}\]onde \(\phi = \frac{\sqrt{5} + 1}{2}\). Faça um documento
X3D
e um programa3JS
que desenhem um icosaedro em wireframe. -
Pintar uma pirâmide. Faça um documento
X3D
e um programa3JS
que desenhem uma pirâmide com as texturas de difusão, brilho e normais obtidas de imagens feitas ou encontradas por si. Seja realista. -
Pintar uma tenda. Os vértices de uma tenda estão dados abaixo
\[\begin{aligned} (0.0, 1.5, 0.0)\cr (-.7, 1.0, 0.7) && (0.7, 1.0, 0.7)\cr (0.7, 1.0, -.7) && (-.7, 1.0, -.7)\cr (-1., 0.0, 1.0) && (1.0, 0.0, 1.0)\cr (1.0, 0.0, -1.) && (-1., 0.0, -1.) \end{aligned}\]Faça um documento
X3D
e um programa3JS
que desenhem uma tenda pintada com texturas feitas (ou encontradas) por si. Seja realista.
Animação
Conceitos Fundamentais da Animação

Com animação uma cena estática ganha vida e torna-se mais informativa e interessante. Isto é:
Animação = Imagem x Tempo
Historicamente, a animação computacional descende do cinema e dos desenhos animados, onde uma sequência de imagens estáticas (fotogramas, em inglês frames) é apresentada em rápida sucessão.
Animação por Fotogramas
Uma animação por fotogramas define um conjunto fixo de imagens (os fotogramas) que são «projetadas» em sequência, com uma certa frequência («fotogramas por segundo», FPS). |
O limiar humano de perceção anda perto dos 24FPS. |
Se os fotogramas forem substituídas a um ritmo de 24 por segundo, a maioria das pessoas não distingue a passagem de um fotograma para o seguinte e interpreta «o que está a ver» como um movimento fluído.
Na realidade, 24 fotogramas por segundo está demasiado perto do limiar de perceção e a esta frequência muitas pessoas apercebem-se da substituição dos fotogramas.
Os primeiros filmes foram filmados e projetados entre 16FPS e 24FPS. A frequência «padrão» 24FPS foi adotado no início da computação gráfica. Atualmente as placas gráficas facilmente proporcionam 60+FPS. |
Limitações da Animação por Fotogramas
Uma animação por fotogramas é feita para uma certa frequência e não resulta bem a frequências diferentes. Além disso, dispositivos diferentes, bem como «cargas» diferentes, proporcionam frequências diferentes. A animação por tempo resolve o problema das diferenças de frequências na animação por fotogramas. |
Animação por Tempo
Deste ponto em diante a matéria de Computação Gráfica muda substancialmente. O foco deixa os sistemas gráficos específicos e passa para a representação e para o processamento de modelos gráficos. Certifique-se que está confortável a programar. |
Chaves | Valores Interpolados |
---|---|
|
|
As chaves definem os pontos «vermelhos» |
A interpolação calcula os pontos «verdes» |
A animação por tempo resolve o problema das diferenças de frequências que a animação por fotogramas coloca.
Processo da Animação por Tempo
|
Tweens
Os tweens (contração do inglês «in-between») assentam uma técnica simples mas flexível e eficiente para calcular os valores intermédios entre um valor inicial \(x_0\) e um valor final \(x_1\) durante um certo intervalo de tempo \([t_0, t_1\)]. |
Um tween atualiza, ao longo de um certo tempo \(d\), um valor \(x(t)\) que varia entre \(x_0\) e \(x_1\). |
Os parâmetros fundamentais de um tween são:
- Valor Inicial
-
Em que valor começa a variação.
- Valor Final
-
Em que valor termina a variação.
- Duração
-
Quanto tempo demora a variação do valor inicial para o final.
Os tweens são usados para fazer uma animação com um modelo parametrizado. |
A forma mais simples de tween é linear:
Para animações com «objetos naturais» este tween não funciona bem porque produz movimentos uniformes, com velocidade constante.
O resultado é semelhante ao movimento dos robots nos filmes antigos, ou de segunda categoria e também de alguns estilos de dança.
Os movimentos naturais não são uniformes. Alguns aceleram no início e travam no fim. Outros têm uma fase de «ganhar balanço». As variantes são muitas. |
Easing
A aceleração de um tween é designada por easing e, em geral, tem as algumas variantes bem definidas. |
As variantes mais comuns de easing são:
- ease-in
-
Início gradual.
- ease-out
-
Fim gradual.
- ease-in-out
-
Início e fim graduais.
Definir Tweens com a Biblioteca
Tween.js Os tween da biblioteca |
Os tweens desta biblioteca:
-
São construídos com um valor inicial, um valor final e uma duração.
-
Aceitam uma grande variedade de easings.
-
Podem ser operados de várias formas:
-
yoyo: depois de atingir o valor final, o tween volta ao inicial.
-
repetir: o tween é repetido um certo número de vezes.
-
encadear: aplicar um segundo tween após a conclusão do primeiro.
-
etc.
-
Os ciclos de animação e de uso dos tweens têm essencialmente a mesma estrutura e podem ser facilmente unificados.
Ciclo de Animação | Ciclo dos Tweens |
---|---|
|
|
Programação Web e Ciclos Infinitos
No contexto da programação na |
function step(model) {
model.parameter_1 = tween.parameter_1; (1)
...
draw(model); (2)
TWEEN.update(); (3)
requestAnimationFrame(function() { (4)
step(model);
});
}
let model = init_model(); (5)
let tween = new TWEEN.Tween( ... ) ...; (6)
tween.start(); (7)
step(model); (8)
1 | Atualiza os parâmetros do modelo com valores no tween. |
2 | Constrói o modelo atualizado. |
3 | Atualiza o sistema de tweens. |
4 | Próximo passo no ciclo de animação. |
5 | Inicialização do modelo. |
6 | Configuração do tween. |
7 | Início do tween. |
8 | Início do ciclo de animação. |
function draw(context, model) {
context.fillStyle = "darkblue";
context.fillRect(0, 0, 250, 60);
context.fillStyle = "crimson";
context.fillRect(model.x, 10, 40, 40);
}
function update(context, model) {
draw(context, model);
requestAnimationFrame(function() {
update(context, model);
});
TWEEN.update();
}
function show_tween() {
let context = document
.getElementById("AnimCanvas")
.getContext("2d");
let model = {x: 10};
let tween = new TWEEN.Tween(model)
.to({ x: 200 }, 2000)
.easing(TWEEN.Easing.Cubic.InOut)
.yoyo(true)
.repeat(Infinity);
tween.start();
requestAnimationFrame(function() {
update(context, model);
});
}
Animação por Passos
Embora flexíveis, nos tweens todos os valores estão determinados antes da animação começar. Uma vez iniciado, o tween vai seguir um «percurso» fixo, previsível. |
Quando a animação dum objeto depende doutros objetos ou eventos, é necessário ir além dos tweens. |
Por exemplo:
-
Com movimentos baseados na física é preciso tratar da aceleração, colisões com outros objetos, etc.
-
Os comportamentos reativos («seguir X», «olhar para Y», etc) dependem dos valores de outros objetos.
-
Os objetos controlados por interação (do teclado, rato, etc) dependem de valores externos ao próprio modelo.
A estrutura básica da animação por tempo, com modelos parametrizados e o ciclo
m = initial_model() # INICIALIZAÇÃO DO MODELO
while True: # CICLO DE ANIMAÇÃO
m.update() # ATUALIZAR OS PARÂMETROS
m.render() # CONSTRUIR/DESENHAR A IMAGEM
é válida em geral: a animação resulta da variação dos parâmetros calculada na atualização, quer esta variação resulte de tweens ou de outros cálculos.
Quando o tempo decorrido entre dois fotogramas não é constante, a atualização dos parâmetros do modelo tem de adaptar-se a essa variação. |
Os tweens fazem automaticamente esta adaptação: O «valor» do tween é atualizado «internamente». |
Para animações gerais, é necessário proporcionar, ao ciclo de animação, informação sobre o tempo: A forma universal e prática para lidar com a variação do tempo no ciclo da animação consiste em passar informação temporal para guiar a atualização dos parâmetros do modelo.
Revisitar os Ciclos de Animação
A função indicada como argumento ( Quando o |
Elemento animado: <span id="counter"></span>
function draw_model(canvas, model) { (1)
canvas.innerHTML = `Count: ${model.count}; ` +
`Time: ${Math.round(model.time * 0.001)}s; ` +
`Elapsed: ${Math.round(model.elapsed)}ms; ` +
`FPS: ${Math.round(1000 * model.count \ model.time)}.`; // \ == divisão :(
}
//
let canvas = document.getElementById("counter");
let model = { count: 0, time: 0, elapsed: 0 }; (2)
let start = performance.now(); (3)
let previous = performance.now(); (4)
animation_step = function (timestamp) {
let progress = timestamp - start; (5)
let elapsed = timestamp - previous; (6)
previous = timestamp; (7)
model.count += 1; (8)
model.time = progress;
model.elapsed = elapsed;
draw_model(canvas, model); (9)
requestAnimationFrame(animation_step); (10)
}
//
// START THE ANIMATION CYCLE
requestAnimationFrame(animation_step); (11)
//
1 | Função para desenhar o modelo tendo em conta os valores dos parâmetros. |
2 | Inicialização do modelo. |
3 | Registo do momento início da animação. |
4 | Registo do momento passo anterior. |
5 | Cálculo da duração desde o início da animação. |
6 | Cálculo da duração desde o passo anterior. |
7 | Atualização do momento passo anterior. |
8 | Cálculo dos parâmetros do modelo. |
9 | Desenho do modelo. |
10 | Próximo passo da animação. |
11 | Início da animação. |
Para ilustrar uma aplicação da animação geral usamos uma (simples) simulação física do movimento uniformemente acelerado.
As leis do movimento (de Newton) definem o estado de uma partícula em termos de posição \(p\), velocidade \(v\) e aceleração \(a\) e como variam a posição e a velocidade em função da posição, velocidade, aceleração e do tempo decorrido \(\delta_t\):
let model = { (1)
x: 64, y: 64, // POSITION
vx: 0, vy: 0, // VELOCITY
ax: 0, ay: 0, // ACCELERATION
r: 16, // RADIUS
min_x: 0, max_x: 256, // BOUNDS: X
min_y: 0, max_y: 256, // BOUNDS: Y
G: 0.25E-3, K: 0.8 // PHYSICS CONSTANTS
};
// Record time of the animation start
let start = performance.now();
// Record time of the previous step
let previous = performance.now();
physdemo_step = function (timestamp) { (2)
let dt = timestamp - previous; (3)
previous = timestamp;
if (timestamp - start < 1000.0) { (4)
model.ax = 2.0 * model.G;
} else {
model.ax = 0.0;
}
model.ay = model.G;
model.vx = model.vx + model.ax * dt; (5)
model.vy = model.vy + model.ay * dt;
model.x = model.x + model.vx * dt; (6)
model.y = model.y + model.vy * dt;
if (model.x - model.r < model.min_x) { (7)
model.vx = -model.K * model.vx;
model.x = model.min_x + model.r; }
if (model.x + model.r > model.max_x) {
model.vx = -model.K * model.vx;
model.x = model.max_x - model.r; }
if (model.y - model.r < model.min_y) {
model.vy = -model.K * model.vy;
model.y = model.min_y + model.r; }
if (model.y + model.r > model.max_y) {
model.vy = -model.K * model.vy;
model.y = model.max_y - model.r; }
draw_physmodel(context, model); (8)
requestAnimationFrame(physdemo_step); (9)
}
1 | Um modelo simples com leis da física. |
2 | Passo do modelo. |
3 | Tempo decorrido desde o passo anterior. |
4 | Atualização da aceleração. |
5 | Atualização da velocidade. |
6 | Atualização da posição. |
7 | Tratamento das colisões. |
8 | Desenhar o modelo. |
9 | Passo seguinte. |
Exercícios Animação
Exceto quando indicado o contrário, cada exercício é para ser resolvido em |
-
Percursos Lineares Uniformes. Desenhe uma forma simples (por exemplo, uma bola ou uma esfera azul) e desloque-a:
-
200 pixeis para a direita.
-
Num retângulo com 200 pixeis de largura e 100 de altura.
-
Num caminho poligonal com \(n\) pontos.
-
-
Percursos Curvos. Como é que representa percursos «curvos»? Por exemplo, percursos circulares ou em onda. Leve a forma do anterior a percorrer um percurso em forma de:
-
Círculo.
-
Seno (ondas).
-
Curva \(x^3\).
-
Um caminho poligonal com \(n\) pontos, definido por uma equação paramétrica.
-
-
Percursos Compostos. Como é que representa percursos definidos por várias «partes"? Por exemplo, um percurso como ilustrado na figura seguinte:
-
Percursos Acelerados. Repita o exercício dos percursos compostos, mas a forma:
-
Acelera no início de cada segmento e trava no fim.
-
Acelera no início do percurso e trava no fim.
-
Exemplos
2D
JavaScript
3D
X3D
3JS
Iluminação
Animação
Comportamento: Seguidor

Exemplo de Animação: Comportamento «Seguidor»
Neste exemplo vai ver:
|
Neste modelo criamos um líder (leader
) que percorre os quatro cantos da imagem num ciclo infinito e um seguidor (follower
) que «tenta» chegar à posição do líder. Veja o resultado aqui.
Como a animação do líder depende apenas do tempo, pode ser implementada com um tween. Já a animação do seguidor é sensível à posição do líder, pelo que tem de ser implementada por passos. |
-
A imagem é um quadrado de lado
1.0
, com o canto superior esquerdo na origem do referencial (de ecrã). -
O líder (vermelho) e o seguidor (azul) são quadrados de lado
0.1
e a «âncora» desses objetos é o centro do quadrado. -
O líder percorre o seguinte «circuito», com cada «troço» a durar `1.5`segundos:
-
(0.2, 0.2)
, perto do CSE. -
(0.2, 0.8)
, perto do CIE. -
(0.8, 0.8)
, perto do CID. -
(0.8, 0.2)
, perto do CSD.
-
-
Para tornar a animação um pouco mais «natural», o easing do movimento do líder é elástico no início e no fim.
O modelo é um objeto javascript
com a seguinte estrutura:
let model = {
background: {
color: "khaki",
},
leader: {
x: 0.2,
y: 0.2,
color: "crimson",
},
follower: {
x: 0.8,
y: 0.2,
speed: 0.005,
color: "steelblue",
},
last_timestamp: performance.now(),
frame_count: 0,
}
function render(model) {
this.enter(0, 0, (1)
this.canvas.width, this.canvas.height, 0); (3)
this.message(`FRAME COUNT: ${model.frame_count}`); (2)
this.fillStyle = model.background.color; (4)
this.fillRect(0, 0, 1, 1); (4)
this.fillStyle = model.leader.color;
this.fillRect(
model.leader.x - 0.05, model.leader.y - 0.05,
0.1, 0.1);
this.fillStyle = model.follower.color;
this.fillRect(
model.follower.x - 0.05, model.follower.y - 0.05,
0.1, 0.1);
this.leave(); (3)
}
1 | this refere-se ao contexto gráfico 2D de um elemento canvas do documento. |
2 | O método message limita-se a escrever um texto num elemento do documento html (exercício). |
3 | Os métodos enter e leave já foram previamente explicados, comas Transformações. |
4 | Os restantes métodos são standard do C2D . |
De seguida vai ser analisada a função dos atributos e como são atualizados. |
- Animação do Líder
-
O líder percorre os quatro cantos da imagem num ciclo infinito.
Esta animação é «independente» do estado do restante modelo. Portanto pode ser implementada por um tween.
let down = new TWEEN.Tween(model.leader) (1)
.to({y: 0.8}, 1500)
.easing(TWEEN.Easing.Elastic.InOut);
let right = new TWEEN.Tween(model.leader) (1)
.to({x: 0.8}, 1500)
.easing(TWEEN.Easing.Elastic.InOut);
let up = new TWEEN.Tween(model.leader) (1)
.to({y: 0.2}, 1500)
.easing(TWEEN.Easing.Elastic.InOut);
let left = new TWEEN.Tween(model.leader) (2)
.to({x: 0.2}, 1500)
.easing(TWEEN.Easing.Elastic.InOut);
//
down.chain(right); (2)
right.chain(up);
up.chain(left);
left.chain(down);
//
... (3)
//
down.start(); (4)
requestAnimationFrame(animation_step) (4)
1 | Definir cada troço do percurso. |
2 | Encadear os troços. |
3 | Tratar de outros assuntos anted de começar o ciclo de animação. |
4 | Inicial o tween e o ciclo de animação. |
Durante o ciclo de animação os parâmetros controlados pelo interpolador têm de ser atualizados. Para esse efeito, basta uma única instrução TWEEN.update() na função de atualização do modelo.
|
function update(model) {
// SOME TIME MANAGEMENT STUFF
// ...
TWEEN.update(); // UPDATE TWEEN'ED PARAMETERS
// UPDATE OTHER PARAMETERS
// ...
return model;
}
- Animação do Seguidor
-
O seguidor aproxima-se gradualmente da posição do líder, a partir da posição em que está.
Como atualizar a posição do seguidor?
Geometricamente, seja \(P\) a posição \((x, y)\) do seguidor e \(Q\) a posição \((x, y)\) do líder. Então \(d = Q - P\) é o vetor que «transporta» \(P\) para \(Q\). Estas operações podem ser facilmente implementadas na função de atualização do modelo. |
function update(model) {
// ...
let dx = model.leader.x - model.follower.x;
let dy = model.leader.y - model.follower.y;
//
model.follower.x += dx;
model.follower.y += dy;
// ...
return model;
}
-
Não se adapta à duração dos passos
-
O seguidor salta imediatamente para a posição do líder, sem se observar o efeito pretendido, de «aproximação gradual».
Portanto a atualização dos parâmetros da posição do seguidor tem de ser mais sofisticada. Para esse efeito o atributo
leader.speed
serve para atenuar o movimento do seguidor:
function update(model) {
//
// UPDATE TIME STUFF
//
let timestamp = performance.now();
let dt = timestamp - model.last_timestamp;
model.last_timestamp = timestamp;
// ...
let dx = model.follower.speed * (model.leader.x - model.follower.x);
let dy = model.follower.speed * (model.leader.y - model.follower.y);
//
model.follower.x += dx * dt;
model.follower.y += dy * dt;
// ...
return model;
}
Falta iniciar a animação e detalhar o passo de animação.
function init_model() {} (1)
function render(model) {} (2)
function enter(x, y, sx, sy, a) {} (3)
function leave() {} (3)
function update(model) { (4)
let timestamp = performance.now(); (5)
let dt = timestamp - model.last_timestamp;
model.last_timestamp = timestamp;
//
model.frame_count += 1; (6)
//
... (7)
... (8)
return model;
}
//
function animate(gc) { (9)
let model = init_model();
function animation_step(timestep) {
model = update(model);
gc.render(model);
requestAnimationFrame(animation_step);
};
down.start();
requestAnimationFrame(animation_step);
}
function main() { (10)
console.log("I'm alive!");
let gc = document.getElementById("canvas").getContext("2d");
gc.render = render;
gc.enter = enter;
gc.leave = leave;
let message = document.getElementById("message")
gc.message = (text) => { message.innerHTML = text; }
let width = 256;
let height = 256;
gc.canvas.width = width;
gc.canvas.height = height;
//
animate(gc);
}
1 | Inicialização do modelo |
2 | Desenhar/Construir o modelo |
3 | Transformações |
4 | Atualização por passos do modelo |
5 | Registos do tempo |
6 | Contador de ciclos |
7 | Atualizar parâmetros dos tweens (posição do líder) |
8 | Atualizar parâmetros por passos (posição do seguidor) |
9 | Ciclo de animação |
10 | Ligação ao dom , extensão do context, início da animação |
-
Torne o movimento do seguidor mais natural usando equações da física e controlando o movimento com acelerações.
-
Faça o mesmo para o movimento do líder. Deve continuar a usar tweens, mas controlar a aceleração em vez da posição. O movimento deve continuar a seguir os quatro cantos da imagem.
-
Defina um atributo para controlar a «sensibilidade» do seguidor. Um seguidor mais «sensível» reage com maior intensidade do que outro menos «sensível».
-
Crie um modelo com
n
seguidores, em posições e com sensibilidades aleatórias. Experimente vários valores do atributon
. -
Detete colisões:
-
Se dois seguidores colidirem (por exemplo, a distância entre eles é inferior a
c = 0.05
) simule um efeito de «ricochete». Experimente outros valores do atributoc
. -
Adicionalmente, da colisão resulta um terceiro (novo) seguidor de cor aleatória (procriação de seguidores).
-
-
Continue o exercício anterior mas, adicionalmente, cada seguidor «morre» se não se aproximar do líder menos de
d = 0.1
durantek = 100
passos consecutivos. Experimente outros valores para os atributosd
ek
. -
Continue o exercício anterior mas, adicionalmente, anime a cor de cada seguidor, aproximando-a de cinzento neutro
#C0C0C0
conforme envelhece mas, se ficar perto do líder, rejuvenesce.
Gerador SVG

svg
em JavaScript
Podemos ultrapassar algumas limitações do sistema svg
, principalmente no que diz respeito a objetos gráficos com repetições (por exemplo, um tabuleiro de xadrez) e aos aspetos dinâmicos (por exemplo, a animação), usando as funções do dom
do html
e JavaScript
.
O objetivo deste exemplo é mostrar como criar um objeto |
-
Um documento
html
com um elemento identificado. -
Um modelo da cena.
-
Uma função
JavaScript
que compile o modelo parasvg
.
HTML
<!DOCTYPE html>
<html lang="pt">
<head>
<meta charset="utf8">
<script src="script/svg-generator.js"> (1)
</script>
</head>
<body onload='main();'> (2)
<div id = "svg-container"></div> (3)
</body>
</html>
1 | O ficheiro/biblioteca JavaScript com funções para aceder ao dom e compilar o modelo da cena para svg . |
2 | Inicia o programa. |
3 | Elemento no dom do documento html onde vai ser construído o svg . |
Um documento svg
é uma árvore em que os nós têm um tipo (tag
), atributos (attributes
) e filhos (children
). O tipo é apenas uma string
, os atributos são um mapa (e.g. um objeto JavaScript
) e os filhos são uma lista de nós.
JavaScript
(e.g. JSON
)let model = {
tag: 'svg', (1)
attributes: { (2)
width: 256,
height: 256 },
children: [
{ tag: 'rect', (3)
attributes: {
x: 0,
y: 0,
width: 256,
height: 256,
fill: 'crimson' } }, (4)
{
tag: 'circle',
attributes: {
cx: 128,
cy: 128,
r: 68,
style: 'fill:darkolivegreen;' (5)
} } ] };
1 | A raíz do modelo é um elemento de tipo svg . |
2 | Ainda na raíz, especificam-se os atributos que definem o tamanho da cena. |
3 | Os filhos do nó raíz são os objetos gráficos que formam a cena. |
4 | Uma forma de definir a cor do interior deste objeto. |
5 | Uma forma diferente de definir a cor do interior. |
svg
:<svg (1)
width= "256" (2)
height="256">
<rect (3)
x="0"
y="0"
width="256"
height="256"
fill="crimson"></rect>
<circle
cx="128"
cy="128"
r="68"
style="fill:darkolivegreen;"></circle>
</svg>
1 | Este é o valor de model.tag . |
2 | Resulta de model.attributes.width . |
3 | Resulta de model.children[0].tag . |
svg
É necessário compilar (i.e. transformar) um modelo como o exemplo acima para um elemento adequado para injetar no dom
do documento html
.
/**
* Creates an svg element.
*
* The element is defined by an object with attributes:
*
* - tag: The element's tag (eg 'rect', 'svg', 'path').
* - attributes (optional): The element's attributes (e.g 'x', 'fill').
* - children (optional): list of sub-elements specifications.
*
* @param {object} spec - the specification of the svg element.
*/
function svg(spec) {
let element = document.createElementNS(
'http://www.w3.org/2000/svg',
spec.tag); (1)
if (spec.hasOwnProperty('attributes')) { (2)
for (let attr in spec.attributes) {
element.setAttributeNS(null,
attr, spec.attributes[attr]); (3)
}
}
if (spec.hasOwnProperty('children')) { (4)
for (let child_spec of spec.children) {
let child = svg(child_spec); (5)
element.appendChild(child); (6)
}
}
return element; (7)
}
1 | Sintaxe para criar corretamente um elemento svg . Consulte a documentação sobre createElementNS em mdn. |
2 | Aplicação dos atributos deste elemento. |
3 | Sintaxe para aplicar atributos. Consulte a documentação sobre setAttributeNS em mdn. |
4 | Construção dos filhos deste elemento. |
5 | Um filho é, ainda, um elemento svg . Portanto este passo é recursivo. |
6 | Acrescentar o nó filho. Consulte a documentação sobre appendChild em mdn. |
7 | That’s all, folks. |
dom
do documento html
Esta parte consiste essencialmente em ligar as várias partes ilustradas acima
let svg_container = document.getElementById('svg-container'); (1)
let svg_element = svg(model); (2)
svg_container.appendChild(svg_element); (3)
1 | Obter o elemento svg-container do dom do documento html . |
2 | Compilar o modelo para um elemento svg . |
3 | Injetar o elemento svg no dom do documento html . |
-
Neste exemplo não foi mostrada a totalidade do ficheiro/biblioteca
svg-generator.js
porque é um exercício. -
Use esta base para criar um elemento
svg
um pouco mais sofisticado. Por exemplo, um tabuleiro de xadrez. -
Continue a tornar o elemento
svg
mais rico, fazendo animações. Anime não só parâmetros de posição/tamanho/rotação mas também parâmetros de aspeto. Faça uma geometria deformável, por exemplo um triângulo que evolui para um quadrado, depois para um pentágono, etc.
C2D com SVG
Objetivo
Animação de um Camião |
---|
C2D |
SVG |
Grafo de Cena
scene(x,a): ground: rect, saddlebrown truck(x, a): weel_1: circle, black weel_2: circle, black weel_3: circle, black base: rect, olive cabin_box: path, darkorange cabin_glass: path, skyblue cargo(a): 0: circle, steelblue 1: rect, steelblue
C2D
Levantamento do Problema
Desenhar Figuras
- shape
-
Definir Formas.
- aspect
-
Traçar o Contorno e Pintar o Interior.
- transform
-
Aplicar Translações, Escalas e Rotações.
- children
-
Construir Figuras Complexas com outras mais simples.
let figure = { shape, aspect, transform, children };
Animar Figuras
Pretendemos uma representação das figuras (e da cena) que seja simultâneamente simples, intuitiva, flexível e eficiente.
let figure = { shape: unit_circle(32), aspect: { fill: 'orange', stroke: 'blue' }, transform: { x: 50, y: 50, sx: 15, sy: 15, a: 0.0 }, children: [ { transform: { x: 2, y: 0, sx: 0.25, sy: 0.25, a: 0.0 }, shape: unit_circle(32), aspect: { fill: 'crimson', stroke: 'green' } } ] }
Definir Formas
Já temos instruções para desenhar caminhos arbitrários:
.beginPath(), .closePath(), .moveTo(), .lineTo(), .quadraticCurveTo(), .bezierCurveTo()
.
Para desenhar diretamente com estas instruções, o caminho «é» um fragmento de código, pouco flexível.
Podemos representar o contorno de uma figura por um conjunto de segmentos de reta, ou seja, uma lista de pontos (x,y) no plano.
let quadrado = [ {x: 1, y:1}, {x: 1, y:-1}, {x: -1, y:-1}, {x: -1, y:1} ];
Contornos mais complexos usam mais segmentos e contornos curvos podem ser aproximadas por muitos segmentos. A lista de pontos pode ser gerada por uma função. Por exemplo unit_circle(n), nagon(n), star(n,r)
Agora precisamos de uma função que leia a lista de pontos e desenhe o contorno, com as instruções beginPath, closePath, moveTo, lineTo
.
function draw_shape(points) { this.beginPath(); let p0 = points[0]; this.moveTo(p0.x, p0.y); for (let p of points) { this.lineTo(p.x, p.y); } this.lineTo(p0.x, p0.y); this.closePath(); }
Aos passarmos de caminhos definidas por funções para caminhos definidas por dados as figuras passam a ser estruturas de dados que podem ser processadas.
Por exemplo, uma figura pode ficar «deformada» por uma «colisão».
Traçar e Pintar
A representação de traços e de tintas é baseada em dados
(.fillStyle, .strokeStyle
) e em instruções (.fill(), .stroke()
).
Nem sempre pretendemos aplicar o traço ou encher o interior.
Os «objetos» do |
Usamos esse método para fazer uma aplicação adaptativa do aspeto da figura.
let a = figure.aspect; // «Smart» Fill if (a.hasOwnProperty('fill')) { this.fillStyle = a.fill; this.fill(); } // «Smart» Stroke if (a.hasOwnProperty('stroke')) { this.strokeStyle = a.stroke; this.stroke(); }
Transformar
As transformações mais comuns são as translações, escalas e rotações. Aplicadas sequencialmente resolvem os problemas de orientação, tamanho e posição das figuras.
Como vimos, a aplicação de transformações não é comutativa: rodar primeiro e depois deslocar não produz o mesmo resultado que deslocar primeiro e depois rodar. |
Uma das sequências de transformações mais comum é
Translate, Scale, Rotate
, usada para «entrar» no espaço da figura ascendente.
function enter(x, y, sx, sy, a) { this.save(); this.translate(x, y); this.scale(sx, sy); this.rotate(a); } function leave() { this.restore(); }
O uso das instruções |
Compor
Precisamos de representar figuras complexas, compostas por sub-figuras.
Em particular, queremos que as figuras «filhas» sejam transformadas juntamente com a figura «mãe».
Um forma de representar as figuras «filhas» consiste em definir uma lista de figuras:
let figure = { ... children: [ child_1, child_2, ... ] }
Juntar Tudo
// function draw(figure) { // // TRANSFORM let t = figure.transform; // // HACK to side-track scale on lineWidth; let save_lineWidth = this.lineWidth; let scale_lw = 0.5 * (t.sx + t.sy); this.lineWidth = this.lineWidth / scale_lw; // // Apply TRANSFORM this.enter(t.x, t.y, t.sx, t.sy, t.a); // // Recursively, DRAW CHILDREN if (figure.hasOwnProperty('children')) { for (let child of figure.children) { this.draw(child); } } // DRAW SHAPE if (figure.hasOwnProperty('shape')) { this.draw_shape(figure.shape); } // Reset TRANSFORM this.leave(); // Reset lineWidth HACK this.lineWidth = save_lineWidth; // // ASPECT if (figure.hasOwnProperty('aspect')) { let a = figure.aspect; // ================ Smart Fill if (a.hasOwnProperty('fill')) { this.fillStyle = a.fill; this.fill(); } // ================ Smart Stroke if (a.hasOwnProperty('stroke')) { this.strokeStyle = a.stroke; this.stroke(); } } } //
Animação
Pretendemos usar a biblioteca tween.js
para tratar as animações.
O processo para definir uma animação consiste em dois passos:
-
Definir um modelo parametrizado.
-
Associar o tempo decorrido a valores dos parâmetros.
No grafo de cena, focamo-nos apenas no camião (truck
).
let lo_circle = unit_circle(25); let rect = unit_rect(); // let weel_1 = { shape: lo_circle, aspect: {fill: 'black'}, transform: {x: 0.75, y: 0.5, sx: 0.2, sy: 0.2, a: 0}, } let weel_2 = { shape: lo_circle, aspect: {fill: 'black'}, transform: {x: -0.7, y: 0.5, sx: 0.2, sy: 0.2, a: 0}, } let weel_3 = { shape: lo_circle, aspect: {fill: 'black'}, transform: {x: -0.25, y: 0.5, sx: 0.2, sy: 0.2, a: 0}, } let base = { shape: rect, aspect: {fill: 'olive'}, transform: {x: 0, y:0.3, sx: 1.0, sy: 0.075, a: 0}, } let cabin_box = { shape: [ {x: 0.0, y: 0.0}, {x: 1.0, y: 0.0}, {x: 1.0, y: 1.0}, {x: -1.0, y: 1.0}, {x: -1.0, y:-1.0}, {x: 0.0, y:-1.0} ], aspect: {fill: 'darkorange'}, transform: {x: 0.5, y: -0.17, sx: 0.4, sy: 0.4, a: 0}, } let cabin_glass_pts = unit_sector(16, -0.5 * Math.PI); cabin_glass_pts.push({x:0.0, y: 0.0}); let cabin_glass = { shape: cabin_glass_pts, aspect: { fill: 'skyblue', stroke: 'black'}, transform: { x: 0.5, y: -0.17, sx: 0.4, sy: 0.4, a: 0.0}, } let cargo = { transform: {x: -0.9, y: 0.1, sx: 1.0, sy: 1.0, a: 0.0}, children: [ { shape: lo_circle, aspect: {fill: 'steelblue', stroke: 'black'}, transform: {x: 0, y: 0, sx: 0.1, sy: 0.1, a: 0}, }, { shape: rect, aspect: {fill: 'steelblue'}, transform: { x: 0.2, y: -0.25, sx: 0.75, sy: 0.25, a: 0.0}, }], } let truck = { transform: { x: 100.0, y: 70.0, sx: 70.0, sy: 70.0, a: 0.0}, children: [ base, cabin_box, cabin_glass, weel_1, weel_2, weel_3, cargo], cargo: cargo, }
A animação tem duas partes:
-
O camião desloca-se para a direita.
-
A caixa do contentor roda para a esquerda e volta à posição inicial.
Definimos cada fase isoladamente e formamos uma cadeia com ambas.
let truck_anim = { from: { x: truck.transform.x, }, target: { x: 400, }, duration: 2000, easing: TWEEN.Easing.Quadratic.InOut, update_func: function (step) { gc.clear(); truck.transform.x = step.x; gc.draw(ground); gc.draw(truck); }, } let cargo_anim = { from: { a: truck.cargo.transform.a, }, target: { a: -0.25 * Math.PI, }, duration: 500, easing: TWEEN.Easing.Quadratic.InOut, update_func: function (step) { gc.clear(); truck.cargo.transform.a = step.a; gc.draw(ground); gc.draw(truck); }, } let truck_tween = make_tween(truck_anim); let cargo_tween = make_tween(cargo_anim) .yoyo(true) .repeat(1); truck_tween.chain(cargo_tween).start();
SVG
Levantamento do Problema
Desenhar Figuras
- shape
-
Definir Formas.
- aspect
-
Traçar o Contorno e Pintar o Interior.
- transform
-
Aplicar Translações, Escalas e Rotações.
- children
-
Construir Figuras Complexas com outras mais simples.
Todas estas caraterísticas são «nativas» do SVG
.
Animar Figuras
-
Definir o Modelo Parametrizado.
-
Associar Tempo e Parâmetros.
Definir o Modelo Parametrizado
O SVG
define modelos essencialmente estáticos, com animações «nativas» muito simples.
Cada documento Este acesso é concretizado, por exemplo, pelo método
|
A afirmação acima aplica-se quer a sub-elementos SVG
quer a documentos externos importados via object
e proporciona uma forma para «parametrizar» modelos SVG
.
Documento HTML
<canvas id="C2DAnim" width="512" height="136"></canvas> <object id="SVGAnim" data="anim.svg" type="image/svg+xml"></object>
Instruções javascript
SVG
.let elem = document .getElementById("SVGModel") .contentDocument; let truck = elem .getElementById("truck"); truck.setAttribute( "transform", "translate(10, 10)");
Para parametrizar documentos
|
Transformações
Para ler e definir programaticamente transformações de elementos SVG o processo é um pouco mais complicado do que devia.
|
.transform
(incompleto!)function get_transform(elem) { let item = elem.transform.baseVal.getItem(0) let m = item.matrix; return { x: m.e, y: m.f, sx: m.a, sy: m.d, a: item.angle } }
.transform
function set_transform(elem, t) { let item = elem.transform.baseVal.getItem(0); let m = item.matrix; if (t.hasOwnProperty('x')) m.e = t.x; if (t.hasOwnProperty('y')) m.f = t.y; if (t.hasOwnProperty('sx')) m.a = t.sx; if (t.hasOwnProperty('sy')) m.d = t.sy; }
Para definirmos a rotação, que funciona em relação a um centro não evidente, é necessária uma técnica um pouco diferente e ad-hoc:
element.setAttribute('transform', `translate(DX,DY)rotate(ANGLE)`);
Animação
A animação para o exemplo SVG
tem a mesma estrutura que foi usada para o exemplo CanvasRenderingContext2D
.
Basta, portanto, alterar a parte que diz respeito à atualização do modelo.
Com estas funções podemos associar o tempo e os parâmetros de forma muito semelhante ao que fizemos no caso do CanvasRenderingContext2D
.
let truck_anim = { from: { x: get_transform(truck).x, }, target: { x: 400, }, duration: 2000, easing: TWEEN.Easing.Quadratic.InOut, update_func: function (step) { set_transform(truck, {x: step.x}); }, } let cargo_t0 = get_transform(cargo); let cargo_anim = { from: { a: cargo_t0.a, }, target: { a: -0.25 * 180, }, duration: 500, easing: TWEEN.Easing.Quadratic.InOut, update_func: function (step) { cargo.setAttribute( 'transform', `translate(-0.9,0.1)rotate(${step.a})`); }, } let truck_tween = make_tween(truck_anim); let cargo_tween = make_tween(cargo_anim) .yoyo(true) .repeat(1); truck_tween.chain(cargo_tween).start();
Cenário 2D Animado
O Problema da Animação ficou dividido em duas partes:
-
Desenhar Figuras.
-
Animar Figuras.
Para Desenhar o Modelo (e as figuras que o formam) de forma parametrizada usamos atributos para definir:
-
Formas (
shape
). -
Aspeto (
aspect
). -
Transformações (
transform
). -
Descendentes (
children
).
Sistemas Gráficos diferentes permitem concretizar estes atributos de formas diferentes.
Nestes exemplos, um modelo foi definido usando
CanvasRenderingContext2D
e outro por um documento «standalone"
SVG
, incluído num documento HTML
.
Para Animar o Modelo (isto é, as figuras que o formam) definimos:
-
Os Parâmetros do Modelo.
-
A Associação do Tempo e dos Parâmetros.
Nestes exemplos, a Associação entre o Tempo e os Parâmetros foi feita por Tweens.
Desafios
-
Implemente a função
make_tween
. -
Melhorar a construção de figuras. Em
shape
permitir segmentos quadráticos e cúbicos. -
Usar um único modelo para criar e animar SVG e C2D.
-
Difícil. Fazer uma animação com física e colisões. Fazer com que o camião derrube uma parede.
-
Faça um modelo simples (por exemplo, uma bola a saltitar no chão) e visualize animações desse modelo nos quatro sistemas gráficos: C2D, SVG, X3D e 3JS.
Anexos
Documento SVG
anim.svg
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="136" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <rect id="urect" x = "-1" y = "-1" width = "2" height = "2"></rect> <circle id="ucirc" cx = "0" cy = "0" r = "1"></circle> </defs> <g id="ground" transform="translate(0,124)scale(512,10)"> <use xlink:href="#urect" transform="translate(0,0)scale(1,1)" fill="saddlebrown" /> </g> <g id="truck" transform="translate(100,70)scale(70,70)"> <use xlink:href="#urect" id = "t_base" transform="translate(0,0.3)scale(1,0.075)" fill="olive" /> <path id="t_cabin_box" transform="translate(0.5, -0.17)scale(0.4,0.4)" fill="darkorange" d=" M 0 0 L 1 0 L 1 1 L -1 1 L -1 -1 L 0 -1 Z " /> <path id="t_cabin_glass" fill = "skyblue" stroke="black" stroke-width="0.05" transform="translate(0.5,-0.17)scale(0.4,0.4)" d=" M 0 0 L 1 0 A 1 1 0 0 0 0 -1 L 0 0 " /> <use id="t_weel_1" fill="black" transform="translate(0.75, 0.5)scale(0.2,0.2)" xlink:href="#ucirc" /> <use id="t_weel_2" fill="black" transform="translate(-0.7, 0.5)scale(0.2,0.2)" xlink:href="#ucirc" /> <use id="t_weel_3" fill="black" transform="translate(-0.25, 0.5)scale(0.2,0.2)" xlink:href="#ucirc" /> <g id="cargo" transform="translate(-0.9,0.1)scale(1,1)"> <use xlink:href="#ucirc" transform="scale(0.1,0.1)" stroke-width="0.25" fill="steelblue" stroke="black" /> <use id="t_cargo" xlink:href="#urect" transform="translate(0.2,-0.25)scale(0.75,0.25)" fill="steelblue" /> </g> </g> </svg>