Homogeneous coordinates in 3D

Here is an animation of a house. It’s special because it’s drawn using my very own ✨homogeneous coordinates✨ library.

In my previous post, I showed homogeneous coordinates in 2D. I can geometrically visualize homogeneous coordinates for 2D space - the hard part being the projection matrix that warps a 3D space of homogeneous coordinates to create a 1D projection of a 2D space. But my brain melts when trying to visualize how a 4D projection matrix warps 4D space to create a 2D projection of a 3D space. Therefore, for this 3D animation, I reasoned entirely by analogy with my 2D implementation. That said, the conversion from 2D to 3D was clean and mechanical.

Here are the matrices I derived for rotation, scaling, translation and projection. They are in column-major format, which is the only sensible format, and the one used by my 5-line matrix library.

const rotateZHom3d = a => [
  [ Math.cos(a), Math.sin(a), 0, 0], // x
  [-Math.sin(a), Math.cos(a), 0, 0], // y
  [0,            0,           1, 0], // z is unchanged
  [0,            0,           0, 1], // w is unchanged
];
const rotateXHom3d = a => [
  [1,            0,           0, 0], // x is unchanged
  [0,  Math.cos(a), Math.sin(a), 0], // y
  [0, -Math.sin(a), Math.cos(a), 0], // z
  [0,            0,           0, 1], // w is unchanged
];
const rotateYHom3d = a => [
  [ Math.cos(a), 0, Math.sin(a), 0],
  [0,            1, 0,           0],  // y is unchanged
  [-Math.sin(a), 0, Math.cos(a), 0],
  [0,            0, 0,           1],  // w is unchanged
];
const scaleSepHom3d = (s) => [ 
  [s[0],     0,    0, 0],  // x 
  [0,    s[1],     0, 0],  // y
  [0,        0, s[2], 0],  // z
  [0,        0,    0, 1],  // w
];
const scaleHom3d = s => scaleSepHom3d([s,s,s]);
const translateHom3d = v => [
  [   1,    0,    0, 0],  // x
  [   0,    1,    0, 0],  // y
  [   0,    0,    1, 0],  // z
  [v[0], v[1], v[2], 1],  // w
];

// Projects onto the z=1 plane from the origin
const projectHom3d = [
  [1,0,0,0], // x is unchanged
  [0,1,0,0], // y is unchanged
  // Points scaled down in proportion with their distance from the projection plane
  [0,0,1,1], 
  // A point's w-factor is IGNORED. For projection, we're only interested in _direction_ from the origin
  [0,0,0,0],
];
Tagged #mathematics, #programming, #js, #graphics.

Similar posts

More by Jim

Want to build a fantastic product using LLMs? I work at Granola where we're building the future IDE for knowledge work. Come and work with us! Read more or get in touch!

This page copyright James Fisher 2020. Content is not associated with my employer. Found an error? Edit this page.