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 de coordenadas cartesiano. A figura 6.9 ilustra a representação de um ponto em coordenadas cartesianas no espaço euclidiano de três dimensões (espaço 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} \]
Frames
Assim como no mundo físico não existe um ponto de referência absoluto (uma “origem” no universo), no espaço euclidiano qualquer ponto pode ser considerado como a origem. Desse modo, para definir unicamente vetores e pontos, precisamos de uma base e um ponto de referência. Um frame cumpre esse papel27.
Um frame de um espaço euclidiano de \(n\) dimensões é composto por:
- Um ponto de referência \(P_0\);
- Uma base composta por \(n\) vetores linearmente independentes \(\mathbf{v}_1, \dots, \mathbf{v}_n\).
Dado um frame \(\{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.\]
O ponto de referência \(P_0\) representa a origem do frame. No frame cartesiano padrão,
\[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\), a base é frequentemente 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} \]
O conceito de frame é importante em computação gráfica pois é comum que os modelos geométricos 3D sejam representados originalmente em um frame local no qual a origem é o centro ou a base do objeto. Esses modelos podem ser dispostos em uma cena virtual 3D que usa outro frame de referência. Além disso, durante o processamento geométrico do pipeline de renderização, os objetos da cena podem ser expressos em relação ao frame da câmera virtual, cuja origem é frequentemente o centro de projeção. Veremos futuramente como realizar essas mudanças de representação através 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 padrão \(\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 ilustra 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 externo 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). \]
Para memorizar mais facilmente, podemos expressar o produto vetorial como um 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} \]
Outras propriedades 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 é o vetor \(\mathbf{n}=(2x, 2y, 2z)\) (figura 6.17). 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 pontos, segmentos e triângulos. Se quisermos renderizar uma esfera, teremos de usar uma malha triangular que aproxime essa esfera. A figura 6.18 ilustra uma malha que aproxima uma esfera. Essa malha pode ser descrita unicamente por triângulos, pois 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.18 precisa ser calculada utilizando unicamente os triângulos que formam a malha.
Para calcular a normal de um triângulo \(\triangle ABC\), basta definir dois vetores sobre o plano do triângulo, e então calcular o produto vetorial desses vetores. Os dois vetores podem ser obtidos através da subtração dos vértices que formam quaisquer duas arestas do triângulo (figura 6.19):
\[ \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. Nesse caso, a normal será calculada como
\[ \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, isso evidencia um problema com o cálculo do vetor normal em vértices de uma malha que aproxima uma superfície suave. Observe na figura 6.20 o detalhe ampliado da esfera da figura 6.18. 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.21 ilustra, em um corte bidimensional, como a normal do vértice \(P\) aproxima a superfície suave mostrada no tracejado.
Podemos utilizar este método sempre que soubermos que a malha aproxime uma superfície suave. Veremos nas próximas seções que esse é o método ideal para ser utilizado com geometria indexada, que é a geometria em que os atributos de um vértice são compartilhados com todas as faces adjacentes. Entretanto, se a malha representar um objeto com quinas, tal como um cubo ou pirâmide, então cada face precisará ser renderizada 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.20, 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.
Nesse contexto, frame é um quadro de referência (frame of reference) de um sistema de coordenadas e não tem relação com o termo frame utilizado para descrever uma imagem renderizada.↩︎