Visual LabINTERACTIVE LEARNING
OpenGL 与 3D第 1 / 4 章

数学基础:相机坐标基

推导 lookAt 矩阵和方向向量变换,为控制器建立数学底座。

OrbitControls相机交互
专题预计 52 分钟查看源文 ↗

参考xeokit实现的控制器

math

import { Matrix4, Vector3 } from 'three';

const lookAtMat = new Matrix4()
const _vec3 = new Vector3()

export function lookAtMat4v(pos, target, up, dest = lookAtMat) {

  const posx = pos.x;
  const posy = pos.y;
  const posz = pos.z;
  const upx = up.x;
  const upy = up.y;
  const upz = up.z;
  const targetx = target.x;
  const targety = target.y;
  const targetz = target.z;

  if (posx === targetx && posy === targety && posz === targetz) {
      return new Matrix4();
  }

  let z0;
  let z1;
  let z2;
  let x0;
  let x1;
  let x2;
  let y0;
  let y1;
  let y2;
  let len;

  //vec3.direction(eye, center, z);
  z0 = posx - targetx;
  z1 = posy - targety;
  z2 = posz - targetz;

  // normalize (no check needed for 0 because of early return)
  len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
  z0 *= len;
  z1 *= len;
  z2 *= len;

  //vec3.normalize(vec3.cross(up, z, x));
  x0 = upy * z2 - upz * z1;
  x1 = upz * z0 - upx * z2;
  x2 = upx * z1 - upy * z0;
  len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
  if (!len) {
      x0 = 0;
      x1 = 0;
      x2 = 0;
  } else {
      len = 1 / len;
      x0 *= len;
      x1 *= len;
      x2 *= len;
  }

  y0 = z1 * x2 - z2 * x1;
  y1 = z2 * x0 - z0 * x2;
  y2 = z0 * x1 - z1 * x0;

  len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
  if (!len) {
      y0 = 0;
      y1 = 0;
      y2 = 0;
  } else {
      len = 1 / len;
      y0 *= len;
      y1 *= len;
      y2 *= len;
  }

  const e = dest.elements;
  e[0] = x0;
  e[1] = y0;
  e[2] = z0;
  e[3] = 0;
  e[4] = x1;
  e[5] = y1;
  e[6] = z1;
  e[7] = 0;
  e[8] = x2;
  e[9] = y2;
  e[10] = z2;
  e[11] = 0;
  e[12] = -(x0 * posx + x1 * posy + x2 * posz);
  e[13] = -(y0 * posx + y1 * posy + y2 * posz);
  e[14] = -(z0 * posx + z1 * posy + z2 * posz);
  e[15] = 1;

  return dest;
}

export function transformVec3(m, v, dest = _vec3) {
  const v0 = v.x;
  const v1 = v.y;
  const v2 = v.z;
  const e = m.elements;
  dest.x = (e[0] * v0) + (e[4] * v1) + (e[8] * v2);
  dest.y = (e[1] * v0) + (e[5] * v1) + (e[9] * v2);
  dest.z = (e[2] * v0) + (e[6] * v1) + (e[10] * v2);
  return dest;
}