因为各个变换都是通过 matrix3d 来实现, 故在实现过程中需要进行矩阵的相乘以及求逆矩阵的运算. CSS3Wrapper 中通过第三方库 mathjs 库来完成矩阵运算.
矩阵相乘
- # 在旋转才 camera 过程中
- # 每个子组件为了保持法向量始终朝向屏幕, 旋转矩阵应该等于 rotateY(-b) 对应的旋转矩阵乘以 rotateX(-a) 对应的旋转矩阵.
- # 为了保持之前的位移, 子组件最终的变换矩阵应该等于旋转矩阵乘以平移矩阵
- const matrix = card.matrix3d;
- card.matrix3d = math.chain(reverseRotateYMatrix).multiply(reverseRotateXMatrix)
- .multiply([[1,0,0,0], [0,1,0,0], [0,0,1,0], matrix.slice(12, 16)]).valueOf().reduce((a, b) => a.concat(b), []);
需要注意的是再通过矩阵运算计算 matrix3d 时, 比如 matrix3d = A * B * C 那么在组件实际的变换过程中是先执行矩阵 C 的变换, 再执行矩阵 B 的变换, 最后执行矩阵 A 的变换. 故上面代码中, 平移矩阵虽然是最后乘的, 但是子组件先执行的平移
求逆矩阵
- # 被点击选中的子组件的最终变换矩阵为固定的 focusMatrix3d.
- # 因为 focusMatrix3d = cardMatrix3d * cameraMatrix3d
- # 故被点击选中子组件的变换矩阵 cardMatrix3d = focusMatrix3d * cameraReverseMatrix3
- let matrix3d = math.chain([focusMatrix3d.slice(0, 4),
- focusMatrix3d.slice(4, 8),
- focusMatrix3d.slice(8, 12),
- focusMatrix3d.slice(12, 16)])
- .multiply(math.divide(math.eye(4), math.matrix(camMat)).valueOf())
- .valueOf().reduce((a, b) => a.concat(b));
上面代码中 camMat 为 camera 当前的变换矩阵.
来源: https://juejin.im/post/5ace288d518825555d479fff