6.3 Espaço euclidiano
O espaço euclidiano é um espaço afim que inclui a operação de produto escalar, também chamada de produto interno.
O produto escalar produz um escalar a partir de dois vetores. Com isso é possível definir conceitos como distância e ângulo.
O espaço euclidiano inclui o espaço vetorial de números reais \(\mathbb{R}^n\). Seus elementos são \(n\)-tuplas de números reais \((a_1, a_2, \dots, a_n)\) que denotam coordenadas do sistema cartesiano.
A figura 6.9 ilustra a representação de um ponto em coordenadas cartesianas no espaço euclidiano de três dimensões (3D).
As operações do espaço vetorial são definidas como:
\[ \begin{align} \mathbf{u}+\mathbf{v}&=(u_1 + v_1, u_2 + v_2, \dots, u_n + v_n),\\ a \mathbf{v}&=(av_1, av_2, \dots, av_n). \end{align} \]
As operações afins são definidas como:
\[ \begin{align} P-Q &= (p_1 - q_1, p_2 - q_2, \dots, p_n - q_n),\\ P+\mathbf{u} &= (p_1 + u_1, p_2 + u_2, \dots, p_n + u_n). \end{align} \]
Quadro de referência
Em aplicações de computação gráfica, é comum desejarmos representar pontos e vetores em relação a diferentes quadros de referência. Por exemplo, em uma cena tridimensional que representa uma sala de aula, a geometria da sala pode ser definida em relação a uma base com eixos ortogonais nas direções da largura, comprimento e altura da sala, além de um ponto de referência (origem) localizado no centro da sala. Entretanto, cada mesa e cada cadeira podem ter seu próprio referencial local, com origem e eixos diferentes do quadro global. Esse uso de diferentes quadros de referência é conveniente para posicionarmos e orientarmos os objetos da cena de forma intuitiva em relação a outros objetos e diferentes pontos de vista.
Um quadro de referência de um espaço euclidiano de \(n\) dimensões é composto por:
- Um ponto \(P_0\) que representa a origem do quadro;
- Uma base composta por \(n\) vetores linearmente independentes \(\mathbf{v}_1, \dots, \mathbf{v}_n\).
O quadro padrão é o quadro composto por
\[P_0=(0, \dots, 0),\]
e a base formada pelo conjunto de tuplas
\[ \begin{align} \mathbf{e}_1 &= (1, 0, 0, \dots, 0),\\ \mathbf{e}_2 &= (0, 1, 0, \dots, 0),\\ &\;\;\vdots\\ \mathbf{e}_n &= (0, 0, 0, \dots, 1),\\ \end{align} \] No \(\mathbb{R}^3\), essa base é denotada por vetores \(\hat{\mathbf{i}}\), \(\hat{\mathbf{j}}\), \(\hat{\mathbf{k}}\):
\[ \begin{align} \hat{\mathbf{i}} &= (1, 0, 0),\\ \hat{\mathbf{j}} &= (0, 1, 0),\\ \hat{\mathbf{k}} &= (0, 0, 1). \end{align} \]
Dado um quadro \(\{P_0, \mathbf{v}_1, \dots, \mathbf{v}_n\}\), um vetor
\[\mathbf{u}=(u_1, \dots, u_n)\]
pode ser escrito unicamente como
\[\mathbf{u}=u_1 \mathbf{v}_1 + u_2 \mathbf{v}_2 + \cdots + u_n \mathbf{v}_n.\]
Um ponto
\[P=(p_1, \dots, p_n)\]
pode ser escrito unicamente como
\[P=P_0 + p_1\mathbf{v}_1 + p_2\mathbf{v}_2 + \cdots + p_n\mathbf{v}_n.\]
Veremos futuramente como realizar mudança de coordenadas entre diferentes quadros através da composição de matrizes de transformação.
Produto escalar
Sejam \(\mathbf{u}=(u_1, \dots, u_n)\) e \(\mathbf{v}=(v_1, \dots, v_n)\) dois vetores do \(\mathbb{R}^n\). O produto escalar, denotado por \(\mathbf{u} \cdot \mathbf{v}\), é a soma da multiplicação componente a componente das tuplas. O resultado é, portanto, um escalar:
\[\mathbf{u} \cdot \mathbf{v} = \sum_{i=1}^n u_i v_i = u_1 v_1 + u_2 v_2 + \cdots + u_n v_n.\]
As seguintes propriedades se aplicam:
- \(\mathbf{u} \cdot \mathbf{v}= \mathbf{v} \cdot \mathbf{u}\).
- \((a \mathbf{u} + b \mathbf{v}) \cdot \mathbf{w} = a \mathbf{u} \cdot \mathbf{w} + b \mathbf{v} \cdot \mathbf{w}\).
- \(\mathbf{v} \cdot \mathbf{v} \geq 0\), e \(\mathbf{v} \cdot \mathbf{v} = 0\) se e somente se \(\mathbf{v}=\mathbf{0}\).
- \(\mathbf{0} \cdot \mathbf{0} = 0\).
Ortogonalidade
Se \(\mathbf{u} \cdot \mathbf{v} = 0\), então \(\mathbf{u}\) e \(\mathbf{v}\) são ortogonais, isto é, os vetores são perpendiculares entre si.
Quando todos os vetores de uma base são ortogonais, temos uma base ortogonal.
A base \(\mathbf{e}_1, \dots, \mathbf{e}_n\) de \(\mathbb{R}^n\) é um exemplo de base ortogonal, pois \(\mathbf{e}_i \cdot \mathbf{e}_j = 0\) para \(i \neq j\).
Comprimento e distância
No espaço euclidiano, a magnitude ou comprimento de um vetor \(\mathbf{u}=(u_1, u_2, \dots, u_n)\) é definida pela norma euclidiana:
\[ \begin{align} |\mathbf{u}| &= \sqrt{\mathbf{u} \cdot \mathbf{u}}\\ & = \sqrt{u_1^2 + u_2^2 + \cdots + u_n^2}. \end{align} \]
A norma euclidiana permite calcular a distância entre pontos. Como \(P - Q\) é um vetor de deslocamento de \(Q=(q_1, \dots, q_n)\) para \(P=(p_1, \dots, p_n)\), a distância entre os dois pontos pode ser calculada como
\[ \begin{align} |P - Q| &= \sqrt{(P-Q) \cdot (P-Q)}\\ &= \sqrt{\sum_{i=1}^n (q_i - p_i)^2}. \end{align} \]
A figura 6.10 mostra a distância euclidiana entre dois pontos \(P=(p_x, p_y)\) e \(Q=(q_x, q_y)\). Observe sua relação com o teorema de Pitágoras.
Normalização
Se \(|\mathbf{v}|=1\), dizemos que \(\mathbf{v}\) é um vetor unitário. Podemos transformar qualquer vetor \(\mathbf{v}\) não nulo em um vetor unitário na mesma direção, denotado por \(\hat{\mathbf{v}}\), se dividirmos todos os elementos de \(\mathbf{v}\) por seu comprimento: \[\hat{\mathbf{v}}=\frac{\mathbf{v}}{|\mathbf{v}|}.\] A figura 6.11 ilustra o resultado da normalização de vetores no \(\mathbb{R}^2\). Observe que os vetores normalizados desenhados a partir da origem ficam inscritos em um círculo unitário.
Sempre que possível trabalharemos com vetores unitários. O uso de vetores unitários simplifica o cálculo do sombreamento e iluminação de superfícies.
Quando dois vetores unitários são ortogonais, dizemos que os vetores são ortonormais. A base padrão \(\mathbf{e}_1, \dots, \mathbf{e}_n\) do \(\mathbb{R}^n\) é uma base ortonormal pois possui vetores de base unitários (isto é, \(|\mathbf{e}_i|=1\)) e ortogonais entre si.
Ângulo entre vetores
O produto escalar entre dois vetores \(\mathbf{u}\) e \(\mathbf{v}\) não nulos é proporcional ao cosseno do ângulo \(\theta\) formado entre esses vetores:
\[\mathbf{u} \cdot \mathbf{v} = |\mathbf{u}||\mathbf{v}|\cos \theta.\] Logo,
\[\cos \theta = \frac{\mathbf{u} \cdot \mathbf{v}}{|\mathbf{u}||\mathbf{v}|}.\]
Se os vetores são ortogonais, \(\cos \theta = 0\). Se os vetores são paralelos e na mesma direção, \(\cos \theta = 1\).
O menor ângulo não negativo entre dois vetores (\(\theta \in [0, \pi]\)) pode ser calculado como:
\[\theta = \cos^{-1} \left( \frac{\mathbf{u} \cdot \mathbf{v}}{|\mathbf{u}||\mathbf{v}|} \right).\] Note que, para vetores unitários, a expressão é mais simples:
\[\cos \theta = \mathbf{u} \cdot \mathbf{v}\] e
\[\theta = \cos^{-1}(\mathbf{u} \cdot \mathbf{v}).\] A relação entre \(\theta\) e \(\mathbf{u} \cdot \mathbf{v}\) é como segue:
\[ \begin{align} \nonumber \textbf{u} \cdot \textbf{v} \begin{cases} >0, \quad \text{para }0 \leq \theta < \frac{\pi}{2} \\[4pt] =0, \quad \text{para }\theta = \frac{\pi}{2} \\[4pt] <0, \quad \text{para } \frac{\pi}{2} < \theta \leq \pi \end{cases} \end{align} \] A figura 6.12 mostra exemplos dos diferentes valores do produto escalar usando vetores no plano.
Projeção ortogonal
Dado um vetor \(\mathbf{w}\) e um vetor \(\mathbf{v}\) não nulo, podemos decompor \(\mathbf{w}\) como uma soma de dois vetores, sendo um paralelo a \(\mathbf{v}\) e outro ortogonal a \(\mathbf{v}\) (figura 6.13):
\[\mathbf{w} = a\mathbf{v} + \mathbf{u},\]
\(a \mathbf{v}\) é o vetor paralelo, chamado de projeção de \(\mathbf{w}\) sobre \(\mathbf{v}\), sendo que
\[a = \frac{\mathbf{w} \cdot \mathbf{v}}{\mathbf{v} \cdot \mathbf{v}}.\]
\(\mathbf{u}\) é o vetor ortogonal a \(\mathbf{v}\) (isto é, \(\mathbf{u} \cdot \mathbf{v}=0\)) e
\[\mathbf{u}=\mathbf{w}-a \mathbf{v}.\]
Note que, se \(\mathbf{v}\) é um vetor unitário,
\[a=\mathbf{w} \cdot \hat{\mathbf{v}}=|\mathbf{w}|\cos \theta,\]
onde \(\theta\) é o ângulo entre \(\mathbf{w}\) e \(\hat{\mathbf{v}}\).
Produto vetorial
Sejam \(\mathbf{u}\) e \(\mathbf{v}\) dois vetores do \(\mathbb{R}^3\). O produto vetorial ou produto cruzado de \(\mathbf{u}\) e \(\mathbf{v}\) é definido como
\[\mathbf{u} \times \mathbf{v} = |\mathbf{u}| |\mathbf{v}| \sin(\theta) \hat{\mathbf{n}},\]
onde \(\hat{\mathbf{n}}\) é um vetor unitário ortogonal a \(\mathbf{u}\) e \(\mathbf{v}\), e \(\theta\) é o ângulo entre \(\mathbf{u}\) e \(\mathbf{v}\). Assim, \(\mathbf{u} \times \mathbf{v}\) é um vetor ortogonal aos dois vetores, com magnitude \(|\mathbf{u} \times \mathbf{v}| = |\mathbf{u}| |\mathbf{v}| |\sin \theta|\) como mostra a figura 6.14.
A direção do vetor ortogonal é dada pela regra da mão direita: usando a mão direita, se o indicador apontar na direção de \(\mathbf{u}\) e o dedo médio apontar na direção de \(\mathbf{v}\), o vetor ortogonal \(\mathbf{u} \times \mathbf{v}\) apontará na direção do dedão (figura 6.15).
O produto vetorial é anticomutativo, isto é,
\[\mathbf{u} \times \mathbf{v} = -(\mathbf{v} \times \mathbf{u}).\]
Assim, se a ordem dos operandos for invertida, o vetor ortogonal apontará para a direção oposta, como mostra a figura 6.16 (pela regra da mão direita, o dedão apontará para baixo).
O produto vetorial é calculado como
\[ \mathbf{u} \times \mathbf{v} = (u_y v_z - u_z v_y, u_z v_x - u_x v_z, u_x v_y - u_y v_x). \]
Essa operação corresponde ao determinante de ordem 3:
\[ \mathbf{u} \times \mathbf{v} = \begin{vmatrix} \hat{\mathbf{i}} & \hat{\mathbf{j}} & \hat{\mathbf{k}} \\ u_x & u_y & u_z \\ v_x & v_y & v_z \end{vmatrix}. \] Usando expansão de cofatores:
\[ \begin{align} \mathbf{u} \times \mathbf{v} &= \begin{vmatrix} u_y & u_z \\ v_y & v_z \end{vmatrix}\hat{\mathbf{i}} - \begin{vmatrix} u_x & u_z \\ v_x & v_z \end{vmatrix}\hat{\mathbf{j}} + \begin{vmatrix} u_x & u_y \\ v_x & v_y \end{vmatrix}\hat{\mathbf{k}}\\ &= (u_y v_z - u_z v_y)\hat{\mathbf{i}}-(u_x v_z - u_z v_x)\hat{\mathbf{j}}+(u_x v_y - u_y v_x)\hat{\mathbf{k}}\\ &= (u_y v_z - u_z v_y, u_z v_x - u_x v_z, u_x v_y - u_y v_x). \end{align} \] Uma vez que o vetor ortogonal tem tamanho proporcional ao seno do ângulo entre os vetores, o produto vetorial de dois vetores paralelos é o vetor nulo:
\[ \begin{align} \mathbf{u} \times \mathbf{u} &= \mathbf{0},\\ -\mathbf{u} \times \mathbf{u} &= \mathbf{0}. \end{align} \]
A magnitude do produto vetorial corresponde à área do paralelogramo formado pelos vetores, como mostra a figura 6.17.
Como resultado, a área do triângulo com lados definidos pelos vetores corresponde à metade da magnitude do produto vetorial (figura 6.18).
Então, para calcular a área de um triângulo \(\triangle P_1 P_2 P_3\), podemos formar dois vetores a partir de um ponto em comum (por exemplo, \(P_1\)):
\[ \mathbf{u}=P_3-P_1,\\ \mathbf{v}=P_2-P_1, \]
e obter a área com
\[ |\mathbf{u} \times \mathbf{v}|/2=|(P_3-P_1)\times(P_2-P_1)|/2. \] Uma generalização do produto vetorial – o chamado produto externo – é particularmente útil para o cálculo de coordenadas baricêntricas. Seja \(\triangle P_1 P_2 P_3\) um triângulo com pontos \(P_1\), \(P_2\) e \(P_3\) no \(\mathbb{R}^2\). Se \(\mathbf{u}=P_3-P_1\), \(\mathbf{v}=P_2-P_1\), a área do paralelogramo formado por \(\mathbf{u}\) e \(\mathbf{v}\) é o produto externo \(\mathbf{u}\wedge\mathbf{v}\). Essa operação corresponde ao determinante
\[ \begin{align} \mathbf{u}\wedge\mathbf{v} &= \begin{vmatrix} u_x & u_y \\ v_x & v_y \end{vmatrix}\\ &= u_x v_y - u_y v_x. \end{align} \] O uso do determinante tem a vantagem de produzir uma “área com sinal”. Se \(\mathbf{u}\) e \(\mathbf{v}\) estão orientados no sentido anti-horário, a área será positiva. Caso contrário, será negativa. Isso pode ser utilizado para verificar se um dado ponto \(P\) está dentro do triângulo. Em particular, \(P\) está dentro do triângulo \(\triangle P_1 P_2 P_3\) com pontos orientados no sentido anti-horário se e somente se \(w_1 \geq 0\), \(w_2 \geq 0\) e \(w_3 \geq 0\), onde
\[ w_1 = (P-P_2)\wedge(P_3-P_2) = 2 \times \textrm{área}(\triangle P_2 P_3 P),\\ w_2 = (P-P_3)\wedge(P_1-P_3) = 2 \times \textrm{área}(\triangle P_3 P_1 P),\\ w_3 = (P-P_1)\wedge(P_2-P_1) = 2 \times \textrm{área}(\triangle P_1 P_2 P). \] As coordenadas baricêntricas de \(P\) são os pesos \(w_1\), \(w_2\), \(w_3\) divididos pela área total do paralelogramo28:
\[ \alpha = w_1 / (2 \times \textrm{área}(\triangle P_1 P_2 P_3)),\\ \beta = w_2 / (2 \times \textrm{área}(\triangle P_1 P_2 P_3)),\\ \gamma = w_3 / (2 \times \textrm{área}(\triangle P_1 P_2 P_3)).\\ \] Outras propriedades do produto vetorial são dadas a seguir:
- \(\mathbf{u} \times (\mathbf{v} + \mathbf{w}) = (\mathbf{u}\times\mathbf{v})+(\mathbf{u}\times\mathbf{w})\).
- \((a\mathbf{u}) \times \mathbf{v} = \mathbf{u} \times (a \mathbf{v}) = a (\mathbf{u} \times \mathbf{v})\).
- \(\mathbf{u} \cdot (\mathbf{v} \times \mathbf{w}) = (\mathbf{u} \times \mathbf{v}) \cdot \mathbf{w}\).
- \(\mathbf{u} \times (\mathbf{v} \times \mathbf{w})=(\mathbf{u} \cdot \mathbf{w})\mathbf{v} - (\mathbf{u} \cdot \mathbf{v})\mathbf{w}\).
Além disso,
\[ \begin{align} \hat{\mathbf{i}} \times \hat{\mathbf{j}} = \hat{\mathbf{k}},\\ \hat{\mathbf{j}} \times \hat{\mathbf{k}} = \hat{\mathbf{i}},\\ \hat{\mathbf{k}} \times \hat{\mathbf{i}} = \hat{\mathbf{j}}. \end{align} \]
Vetor normal
Um vetor normal, ou simplesmente normal, é um vetor perpendicular ao plano que tangencia uma superfície em um dado ponto. Em computação gráfica, vetores normais são essenciais para o cálculo correto do sombreamento e iluminação de superfícies.
Se considerarmos a superfície de uma esfera de raio \(r>0\) dada pela equação
\[x^2+y^2+z^2=r^2,\] a normal de um ponto \(P=(x,y,z)\) sobre essa esfera é, por exemplo, o vetor \(\mathbf{n}=(2x, 2y, 2z)\) (figura 6.19). O vetor no sentido oposto, \(-\mathbf{n}\), também é um vetor normal. Entretanto, em superfícies fechadas como a esfera, geralmente estamos interessados nas normais que apontam para fora da superfície.
O cálculo do vetor normal em superfícies suaves frequentemente exige o uso de ferramentas de geometria diferencial. Por exemplo, em uma superfície definida implicitamente como uma função level set \(f(x,y,z)=c\), o vetor normal é calculado através do gradiente
\[ \begin{align} \mathbf{n} = \nabla f(x,y,z) = \frac{\partial f}{\partial x}\hat{\mathbf{i}} + \frac{\partial f}{\partial y}\hat{\mathbf{j}} + \frac{\partial f}{\partial z}\hat{\mathbf{k}}. \end{align} \] De fato, para a esfera centralizada na origem,
\[f(x,y,z)=x^2+y^2+z^2\]
e
\[ \begin{align} \mathbf{n} = \nabla f(x,y,z) &= 2x\,\hat{\mathbf{i}} + 2y\,\hat{\mathbf{j}} + 2z\,\hat{\mathbf{k}}\\ &= (2x, 2y, 2z). \end{align} \]
Entretanto, neste curso não trabalharemos com superfícies implícitas. Utilizaremos apenas superfícies formadas por malhas de triângulos, uma vez que o pipeline gráfico do OpenGL trabalha apenas com triângulos. Se quisermos renderizar uma esfera, teremos de usar uma malha triangular que aproxime essa esfera. A figura 6.20 ilustra esse caso. Cada faceta da malha é visualizada como um quadrilátero, mas essa malha pode ser descrita unicamente por triângulos, uma vez que cada quadrilátero pode ser formado por dois triângulos.
Em geral, dada uma malha de triângulos, não temos acesso à representação implícita ou paramétrica da superfície que a malha tenta aproximar. Assim, no caso geral, a normal \(n\) mostrada na figura 6.20 precisa ser calculada utilizando unicamente os triângulos.
Para calcular a normal de um triângulo \(\triangle ABC\), basta definirmos dois vetores sobre o plano do triângulo, e então calcularmos o produto vetorial entre eles. Os vetores podem ser obtidos através da subtração dos vértices que formam quaisquer duas arestas (figura 6.21):
\[ \begin{align} \mathbf{u}&=A-C,\\ \mathbf{v}&=B-C,\\ \mathbf{n}&=\mathbf{u} \times \mathbf{v}.\\ \end{align} \] Em geral, desejaremos trabalhar com normais unitárias:
\[ \begin{align} \hat{\mathbf{n}}&=\frac{\mathbf{u} \times \mathbf{v}}{|\mathbf{u} \times \mathbf{v}|}.\\ \end{align} \] Como o triângulo é uma superfície planar, o vetor normal é o mesmo para todos os pontos do triângulo. Entretanto, sob arestas e vértices compartilhados por diferentes triângulos, podemos ter mais de um vetor normal. Observe na figura 6.22 o detalhe ampliado da esfera da figura 6.20. Cada face, formada por dois triângulos (mostrados pelo tracejado), é uma superfície planar. Portanto, cada face tem o mesmo vetor normal para todos os pontos. Por outro lado, o ponto \(P\) é compartilhado por quatro faces (seis triângulos). Qual das normais (\(\mathbf{n}_1\), \(\mathbf{n}_2\), \(\mathbf{n}_3\), \(\mathbf{n}_4\)) deve ser utilizada em \(\mathbf{n}_p\)?
Como a malha de triângulos aproxima uma superfície suave, podemos calcular um vetor normal em \(P\) como uma média dos vetores normais de todos os \(n\) triângulos que usam \(P\). Uma forma simples de fazer isso é através da normalização da soma dessas normais
\[ \begin{align} \hat{\mathbf{n}}_p&=\frac{\sum_{i=1}^n \mathbf{n}_i}{|\sum_{i=1}^n \mathbf{n}_i|},\\ \end{align} \] onde \(\mathbf{n}_i\) é o vetor normal do \(n\)-ésimo triângulo que usa \(P\). O resultado é um vetor normalizado chamado de normal de vértice. A figura 6.23 ilustra, em um corte bidimensional, como a normal de vértice \(P\) aproxima a superfície suave mostrada no tracejado.
Podemos utilizar este método sempre que soubermos que a malha aproxima uma superfície suave. Esse método é ideal para ser utilizado com geometria indexada, pois os vértices compartilhados têm em comum tanto a posição como a normal de vértice. Entretanto, se a malha representar um objeto com quinas, tal como um cubo ou pirâmide, então cada face precisará ser desenhada com vértices não compartilhados, pois queremos evidenciar a descontinuidade da superfície. Se esse fosse o caso da geometria ilustrada na figura 6.22, quatro vértices teriam de ser utilizados em \(P\): um para cada face (quadrilátero formado por dois triângulos). Os vértices teriam a mesma posição de \(P\), mas cada um usaria a normal da face correspondente.
Poderíamos calcular os pesos e o fator de normalização usando a área do triângulo ao invés da área do paralelogramo, mas o que importa aqui é a razão entre as áreas, que é a mesma.↩︎