El producto vectorial de dos vectores tridimensionales produce un nuevo vector perpendicular a ambos. Su dirección sigue la regla de la mano derecha y su magnitud mide un área.
El producto escalar produce un número que mide alineación. El producto vectorial, también llamado producto cruz, produce un vector con una propiedad diferente: es perpendicular a los dos vectores originales.
Esta operación es fundamental para calcular normales, orientaciones, áreas y efectos de rotación en gráficos, física y geometría computacional.
El producto vectorial usual estudiado en este curso toma dos vectores de ℝ3 y devuelve otro vector de ℝ3:
Su resultado queda determinado por tres elementos:
Sean u = (ux, uy, uz) y v = (vx, vy, vz):
function productoVectorial(u, v) {
return [
u[1] * v[2] - u[2] * v[1],
u[2] * v[0] - u[0] * v[2],
u[0] * v[1] - u[1] * v[0]
];
}
console.log(productoVectorial([1, 2, 3], [4, 5, 6])); // [-3, 6, -3]
La fórmula puede recordarse mediante un determinante formal:
Al expandir por la primera fila se obtiene:
El signo negativo del término asociado a j es una fuente frecuente de errores.
La orientación positiva de los ejes cumple:
Invertir el orden cambia el signo:
const cruz = (u, v) => [
u[1] * v[2] - u[2] * v[1],
u[2] * v[0] - u[0] * v[2],
u[0] * v[1] - u[1] * v[0]
];
const i = [1, 0, 0];
const j = [0, 1, 0];
console.log(cruz(i, j)); // [0, 0, 1]
console.log(cruz(j, i)); // [0, 0, -1]
Para determinar el sentido de u × v, se orientan los dedos de la mano derecha desde u hacia v por el giro más corto. El pulgar extendido señala la dirección del producto.
El orden es esencial. Al intercambiar los operandos, el sentido se invierte:
const u = [1, 2, 3];
const v = [4, 5, 6];
const cruz = (a, b) => [
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
a[0] * b[1] - a[1] * b[0]
];
console.log(cruz(u, v)); // [-3, 6, -3]
console.log(cruz(v, u)); // [3, -6, 3]
Sean u = (1, 2, 3) y v = (4, 5, 6):
El resultado no depende de un dibujo: se obtiene directamente de las componentes.
Si w = u × v, entonces sus productos escalares con u y v son cero:
const u = [1, 2, 3];
const v = [4, 5, 6];
const w = [-3, 6, -3];
const dot = (a, b) => a.reduce((suma, valor, i) => suma + valor * b[i], 0);
console.log(dot(u, w)); // 0
console.log(dot(v, w)); // 0
Si θ es el ángulo entre u y v:
La magnitud es máxima cuando los vectores son perpendiculares y cero cuando son paralelos o alguno es nulo.
const cruz = (u, v) => [
u[1] * v[2] - u[2] * v[1],
u[2] * v[0] - u[0] * v[2],
u[0] * v[1] - u[1] * v[0]
];
const resultado = cruz([3, 0, 0], [0, 4, 0]);
console.log(resultado); // [0, 0, 12]
console.log(Math.hypot(...resultado)); // 12
La magnitud ||u × v|| es el área del paralelogramo construido sobre u y v. La mitad corresponde al triángulo formado por esos lados.
function areaTriangulo(A, B, C) {
const u = B.map((valor, i) => valor - A[i]);
const v = C.map((valor, i) => valor - A[i]);
const cruz = [
u[1] * v[2] - u[2] * v[1],
u[2] * v[0] - u[0] * v[2],
u[0] * v[1] - u[1] * v[0]
];
return Math.hypot(...cruz) / 2;
}
console.log(areaTriangulo([0, 0, 0], [4, 0, 0], [0, 3, 0])); // 6
Dos vectores no nulos son paralelos cuando su producto vectorial es el vector cero. Del mismo modo, tres puntos A, B y C son colineales si (B − A) × (C − A) es cero.
function sonParalelos(u, v, tolerancia = 1e-10) {
const cruz = [
u[1] * v[2] - u[2] * v[1],
u[2] * v[0] - u[0] * v[2],
u[0] * v[1] - u[1] * v[0]
];
return Math.hypot(...cruz) <= tolerancia;
}
console.log(sonParalelos([1, 2, 3], [2, 4, 6])); // true
En código numérico conviene usar una tolerancia relativa a las magnitudes de los vectores.
| Propiedad | Expresión |
|---|---|
| Anticonmutativa | u × v = −(v × u) |
| Distributiva | u × (v + w) = u × v + u × w |
| Compatibilidad escalar | (ku) × v = k(u × v) |
| Producto consigo mismo | u × u = 0 |
| No asociativa | En general, (u × v) × w ≠ u × (v × w) |
El producto vectorial no es conmutativo ni asociativo; el orden y los paréntesis importan.
Dados los vértices A, B y C, una normal de la superficie se obtiene con (B − A) × (C − A). Al normalizarla se conserva únicamente su dirección.
function normalTriangulo(A, B, C, tolerancia = 1e-12) {
const u = B.map((valor, i) => valor - A[i]);
const v = C.map((valor, i) => valor - A[i]);
const n = [
u[1] * v[2] - u[2] * v[1],
u[2] * v[0] - u[0] * v[2],
u[0] * v[1] - u[1] * v[0]
];
const longitud = Math.hypot(...n);
return longitud <= tolerancia ? null : n.map(valor => valor / longitud);
}
console.log(normalTriangulo([0, 0, 0], [1, 0, 0], [0, 1, 0]));
// [0, 0, 1]
Si los puntos son colineales, el triángulo es degenerado y no posee una normal definida.
Intercambiar B y C invierte la normal. Por eso el orden de los vértices de una malla determina qué lado se considera frontal.
const cruz = (u, v) => [
u[1] * v[2] - u[2] * v[1],
u[2] * v[0] - u[0] * v[2],
u[0] * v[1] - u[1] * v[0]
];
const AB = [1, 0, 0];
const AC = [0, 1, 0];
console.log(cruz(AB, AC)); // [0, 0, 1]
console.log(cruz(AC, AB)); // [0, 0, -1]
En geometría plana se utiliza con frecuencia el componente z que resultaría al considerar los vectores como tridimensionales con z = 0:
El resultado es un escalar con signo: positivo indica un giro antihorario y negativo, horario, usando la convención cartesiana habitual.
function orientacion(A, B, C, tolerancia = 1e-10) {
const AB = [B[0] - A[0], B[1] - A[1]];
const AC = [C[0] - A[0], C[1] - A[1]];
const z = AB[0] * AC[1] - AB[1] * AC[0];
if (Math.abs(z) <= tolerancia) return "colineales";
return z > 0 ? "antihoraria" : "horaria";
}
console.log(orientacion([0, 0], [1, 0], [0, 1])); // antihoraria
En mecánica, el torque producido por una fuerza F aplicada a una distancia vectorial r respecto del eje es:
Su dirección indica el eje de giro y su magnitud mide la capacidad de producir rotación.
const r = [2, 0, 0];
const fuerza = [0, 5, 0];
const torque = [
r[1] * fuerza[2] - r[2] * fuerza[1],
r[2] * fuerza[0] - r[0] * fuerza[2],
r[0] * fuerza[1] - r[1] * fuerza[0]
];
console.log(torque); // [0, 0, 10]
A partir de una dirección frontal y una referencia vertical pueden construirse ejes perpendiculares para una cámara.
const cruz = (u, v) => [
u[1] * v[2] - u[2] * v[1],
u[2] * v[0] - u[0] * v[2],
u[0] * v[1] - u[1] * v[0]
];
const frente = [0, 0, -1];
const verticalAproximada = [0, 1, 0];
const derecha = cruz(frente, verticalAproximada);
const arriba = cruz(derecha, frente);
console.log({ derecha, arriba }); // [1,0,0] y [0,1,0]
Si la dirección frontal y la vertical aproximada son paralelas, el producto es cero y debe elegirse otra referencia.
Una implementación debe comprobar que ambos argumentos tengan exactamente tres componentes finitas. Para detectar paralelismo o triángulos degenerados se utiliza una tolerancia adaptada a la escala.
function cruzValidado(u, v) {
const validos = [u, v].every(vector =>
Array.isArray(vector) && vector.length === 3 && vector.every(Number.isFinite)
);
if (!validos) throw new Error("Se requieren dos vectores 3D válidos");
return [
u[1] * v[2] - u[2] * v[1],
u[2] * v[0] - u[0] * v[2],
u[0] * v[1] - u[1] * v[0]
];
}
console.log(cruzValidado([1, 0, 0], [0, 1, 0]));
Errores frecuentes son alterar el orden, equivocarse en el signo de la segunda componente, esperar un escalar, usar vectores 2D directamente, normalizar un resultado cero y confundir producto escalar con vectorial.
El producto vectorial convierte dos direcciones tridimensionales en una perpendicular orientada. Su magnitud y sentido codifican información geométrica esencial para superficies, áreas y rotaciones.
En el próximo tema estudiaremos la proyección de un vector sobre otro, que permite separar la parte alineada con una dirección determinada.