No Three.js, transformar objetos como malhas envolve operações matriciais subjacentes. Métodos como translateX, rotateY e propriedades como scale são ipmlementados usando matrizes de modelo que combinam translação, rotação e escala. A essência é a multiplicação de matrizes: cada transformação é representada por uma matriz específica, e a matriz de modelo final é o produto dessas matrizes aplicadas sequencialmente.
Translação: Deslocamento via Matrizes
A translação move um objeto ao longo dos eixos. Matematicamente, é experssa por uma matriz 4x4 onde os elementos da quarta coluna representam os deslocamentos em x, y e z. Por exemplo, deslocar um ponto (x, y, z, 1) por (tx, ty, tz) corresponde a multiplicar por uma matriz de translação.
// Exemplo em GLSL para translação
attribute vec4 vertexPos;
mat4 translateMatrix = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.5, 0.3, 0.2, 1.0 // Deslocamento em x, y, z
);
void main() {
gl_Position = translateMatrix * vertexPos;
}
No Three.js, o método translate internamente constrói uma matriz de translação e a aplica à geometria. Vejamos um trecho simplificado da fonte:
// Fonte: Three.js BufferGeometry.js (simplificado)
const tempMatrix = new THREE.Matrix4();
function applyTranslation(geo, dx, dy, dz) {
tempMatrix.makeTranslation(dx, dy, dz);
applyMatrixToGeometry(geo, tempMatrix);
}
function applyMatrixToGeometry(geo, matrix) {
const posAttr = geo.attributes.position;
if (posAttr) {
posAttr.applyMatrix4(matrix);
posAttr.needsUpdate = true;
}
}
A chave está em makeTranslation, que configura a matriz com os valores de deslocamento na quarta coluna, alinhando-se ao princípio matemático.
Rotação: Transformação Angular com Matrizes
A rotação gira um objeto ao redor de um eixo, utilizando uma matriz onde os elementos da submatriz 3x3 superior esquerda contêm senos e cosesnos do ângulo. Por exemplo, rotação ao redor do eixo Z por θ radianos usa uma matriz específica.
// Exemplo em GLSL para rotação no eixo Z
attribute vec4 vertexPos;
float theta = radians(45.0);
float cosTheta = cos(theta);
float sinTheta = sin(theta);
mat4 rotateZMatrix = mat4(
cosTheta, -sinTheta, 0.0, 0.0,
sinTheta, cosTheta, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
void main() {
gl_Position = rotateZMatrix * vertexPos;
}
No Three.js, o método rotateZ segue um processo similar, criando uma matriz de rotação e combinando-a com a matriz de modelo existente. Código adaptado:
// Fonte: Three.js Matrix4.js (simplificado)
THREE.Matrix4.prototype.setRotationZ = function(angle) {
const c = Math.cos(angle), s = Math.sin(angle);
this.set(
c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
return this;
};
// Em BufferGeometry.js (simplificado)
function rotateGeometryAroundZ(geo, angle) {
tempMatrix.setRotationZ(angle);
applyMatrixToGeometry(geo, tempMatrix);
}
Observe que no Three.js as matrizes são armazenadas em ordem colunar, o que difere da convensão usual em álgebra linear, onde as linhas e colunas podem ser transpostas na interpretação.
Escala: Redimensionamento via Diagonal Matricial
A escala altera o tamanho de um objeto ao multiplicar as coordenadas por fatores em cada eixo. Isso é representado por uma matriz diagonal, onde os elementos diagonais contêm os fatores de escala.
// Exemplo em GLSL para escala
attribute vec4 vertexPos;
mat4 scaleMatrix = mat4(
1.5, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 0.8, 0.0,
0.0, 0.0, 0.0, 1.0 // Fatores de escala em x, y, z
);
void main() {
gl_Position = scaleMatrix * vertexPos;
}
No Three.js, a propriedade scale é atualizada internamente usando uma matriz de escala. Um exemplo simplificado:
// Fonte: Three.js Matrix4.js (simplificado)
THREE.Matrix4.prototype.makeScale = function(sx, sy, sz) {
this.set(
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
0, 0, 0, 1
);
return this;
};
// Em Object3D.js (simplificado)
function updateScale(obj, fx, fy, fz) {
tempMatrix.makeScale(fx, fy, fz);
applyMatrixToGeometry(obj.geometry, tempMatrix);
}
A aplicação combinada de translação, rotação e escala é eficiente através da composição matricial: multiplica-se as matrizes individuais em uma única matriz de modelo, que é então aplicada aos vértices. Isso permite transformações complexas em uma operação unificada.