Skip to content

Commit d266486

Browse files
committed
Add inverseTransform; Rename transpose to avoid confusion
1 parent 5c7f9f7 commit d266486

27 files changed

+94
-45
lines changed

assembly/__tests__/array.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,12 @@ describe('array', () => {
192192
}
193193
});
194194

195-
test('tr(a)', () => {
195+
test('transpose(a)', () => {
196196
const actuals: Vec[] = [
197-
array.tr(1, [1], [0]),
198-
mat2.tr([1, 2, 3, 4]),
199-
mat3.tr([1, 2, 3, 4, 5, 6, 7, 8, 9]),
200-
mat4.tr([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
197+
array.transpose(1, [1], [0]),
198+
mat2.transpose([1, 2, 3, 4]),
199+
mat3.transpose([1, 2, 3, 4, 5, 6, 7, 8, 9]),
200+
mat4.transpose([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
201201
];
202202

203203
const expecteds: Vec[] = [

assembly/__tests__/transform.spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
Float, Mat4, ortho, perspective, Quat, ReadonlyMat4, rotate, rotateX, rotateY, rotateZ, rotateAxis, rotationOf,
33
scale, scaleOf, transform, translate, translationOf, Vec3, direction, vec3
44
} from '../index';
5-
import { lookAt, targetTo } from '../transform';
5+
import { inverseTransform, lookAt, targetTo } from '../transform';
66
import { expectVecEqual } from './test-utils';
77

88
const PI_OVER_3 = Math.PI as Float / 3;
@@ -81,6 +81,13 @@ describe('transfrom', () => {
8181
expectVecEqual(actual, expected);
8282
});
8383

84+
test('inverseTransform(m)', () => {
85+
const m: ReadonlyMat4 = [2, 2, -1, 0, -2, 4, 4, 0, 6, -3, 6, 0, 1, 2, 3, 1];
86+
const expected: ReadonlyMat4 = [2/9, -1/18, 2/27, 0, 2/9, 1/9, -1/27, 0, -1/9, 1/9, 2/27, 0, -1/3, -1/2, -2/9, 1];
87+
const actual = inverseTransform(m);
88+
expectVecEqual(actual, expected);
89+
});
90+
8491
test('translationOf(m)', () => {
8592
expectVecEqual(translationOf([2, 2, -1, 0, -2, 4, 4, 0, 6, -3, 6, 0, 1, 2, 3, 1]), [1, 2, 3] as Vec3);
8693
});

assembly/array.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export function dot(a: ReadonlyVec, b: ReadonlyVec): Float {
116116
* @param out the output matrix
117117
* @returns out = [M]T
118118
*/
119-
export function tr(n: Int, m: ReadonlyVec, out: Vec): Vec {
119+
export function transpose(n: Int, m: ReadonlyVec, out: Vec): Vec {
120120
let f: Float = 0;
121121
for (let i = 0; i < n; ++i) {
122122
for (let j = i; j < n; ++j) {

assembly/mat2.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ export function scale(m: ReadonlyMat2, s: Float, out: Mat2 = create()): Mat2 {
7070
* Transpose a {@link Mat2}.
7171
* @returns [M]T
7272
*/
73-
export function tr(m: ReadonlyMat2, out: Mat2 = create()): Mat2 {
74-
return array.tr(2, m, out) as Mat2;
73+
export function transpose(m: ReadonlyMat2, out: Mat2 = create()): Mat2 {
74+
return array.transpose(2, m, out) as Mat2;
7575
}
7676

7777
/**

assembly/mat3.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ export function scale(m: ReadonlyMat3, s: Float, out: Mat3 = create()): Mat3 {
5959
* Transpose a {@link Mat3}.
6060
* @returns [M]T
6161
*/
62-
export function tr(m: ReadonlyMat3, out: Mat3 = create()): Mat3 {
63-
return array.tr(3, m, out) as Mat3;
62+
export function transpose(m: ReadonlyMat3, out: Mat3 = create()): Mat3 {
63+
return array.transpose(3, m, out) as Mat3;
6464
}
6565

6666
/**
@@ -118,5 +118,5 @@ export function nmat(a: ReadonlyMat3, out: Mat3 = create()): Mat3 | null {
118118
if (!invert(a, out)) {
119119
return null;
120120
}
121-
return tr(out, out);
121+
return transpose(out, out);
122122
}

assembly/mat4.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ export function scale(m: ReadonlyMat4, s: Float, out: Mat4 = create()): Mat4 {
9393
* Transpose a {@link Mat4}.
9494
* @returns [M]T
9595
*/
96-
export function tr(m: ReadonlyMat4, out: Mat4 = create()): Mat4 {
97-
return array.tr(4, m, out) as Mat4;
96+
export function transpose(m: ReadonlyMat4, out: Mat4 = create()): Mat4 {
97+
return array.transpose(4, m, out) as Mat4;
9898
}
9999

100100
/**

assembly/transform.ts

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export function rotate(q: ReadonlyQuat, out: Mat4 = mat4.create()): Mat4 {
3939

4040
/**
4141
* Returns a {@link Mat4} for a 3D rotation about the x-axis in couterclockwise direction.
42-
* see: https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
42+
* @see https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
4343
*/
4444
export function rotateX(theta: Float, out: Mat4 = mat4.create()): Mat4 {
4545
mat4.id(out);
@@ -51,7 +51,7 @@ export function rotateX(theta: Float, out: Mat4 = mat4.create()): Mat4 {
5151

5252
/**
5353
* Returns a {@link Mat4} for a 3D rotation about the y-axis in couterclockwise direction.
54-
* see: https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
54+
* @see https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
5555
*/
5656
export function rotateY(theta: Float, out: Mat4 = mat4.create()): Mat4 {
5757
mat4.id(out);
@@ -63,7 +63,7 @@ export function rotateY(theta: Float, out: Mat4 = mat4.create()): Mat4 {
6363

6464
/**
6565
* Returns a {@link Mat4} for a 3D rotation about the z-axis in couterclockwise direction.
66-
* see: https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
66+
* @see https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
6767
*/
6868
export function rotateZ(theta: Float, out: Mat4 = mat4.create()): Mat4 {
6969
mat4.id(out);
@@ -75,7 +75,7 @@ export function rotateZ(theta: Float, out: Mat4 = mat4.create()): Mat4 {
7575

7676
/**
7777
* Returns a {@link Mat4} for a 3D rotation about a given unit axis in couterclockwise direction.
78-
* see: https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
78+
* @see https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
7979
*/
8080
export function rotateAxis(axis: ReadonlyVec3, theta: Float, out: Mat4 = mat4.create()): Mat4 {
8181
const
@@ -121,6 +121,42 @@ export function transform(translation: ReadonlyVec3, rotation: ReadonlyQuat, sca
121121
return out;
122122
}
123123

124+
/**
125+
* Returns the inverse of a {@link ReadonlyMat4} that represents a valid transformation in TRS order (= translation * rotation * scale).
126+
* This function is more efficient than {@link mat4.invert} by using the properties of a TRS matrix.
127+
* @returns out = M^-1
128+
*/
129+
export function inverseTransform(m: ReadonlyMat4, out: Mat4 = mat4.create()): Mat4 {
130+
// Assume M is a TRS matrix:
131+
// M = T * R * S = [RS t]
132+
// [0 1]
133+
// Then the inverse of M is:
134+
// M^-1 = [(RS)^-1 (RS)^-1 * -t]
135+
// [ 0 1 ]
136+
// Where: (RS)^-1 = S^-1 * R^-1 = S^-1 * RT = S^-1 * ((RS)(S^-1))T = S^-1 * (S^-1)T * (RS)T = S^-1 * S^-1 * (RS)T
137+
138+
// Calculate output = (RS)T
139+
mat4.transpose(m, out);
140+
unchecked(out[3] = out[7] = out[11] = 0);
141+
142+
// Extract S and premultiply S^-2 = 1/(S*S) to output
143+
scaleOf(m, v1);
144+
for (let i = 0; i < 3; ++i) {
145+
for (let j = 0; j < 3; ++j) {
146+
unchecked(out[4 * i + j] *= 1 / (v1[j] * v1[j]));
147+
}
148+
}
149+
150+
// With output = (RS)^-1, apply translation = (output * -t) to output
151+
array.copy(
152+
vec3.mmul4(out, vec3.scale(array.copy(m, v0, 12, 0, 3) as Vec3, -1)),
153+
out,
154+
0, 12, 3
155+
);
156+
157+
return out;
158+
}
159+
124160
// -- Transformation matrix decomposition --
125161

126162
/**
@@ -131,7 +167,7 @@ export function translationOf(m: ReadonlyMat4, out: Vec3 = vec3.create()): Vec3
131167
}
132168

133169
/**
134-
* Extract the {@link Vec3} scaling components from an affine transformation matrix.
170+
* Extract the {@link Vec3} scaling components from a transformation matrix in TRS order (= translation * rotation * scale).
135171
*/
136172
export function scaleOf(m: ReadonlyMat4, out: Vec3 = vec3.create()): Vec3 {
137173
for (let i = 0; i < 3; ++i) {
@@ -144,7 +180,7 @@ export function scaleOf(m: ReadonlyMat4, out: Vec3 = vec3.create()): Vec3 {
144180
}
145181

146182
/**
147-
* Extract the {@link Quat} rotation components from an affine transformation matrix.
183+
* Extract the {@link Quat} rotation components from a transformation matrix in TRS order (= translation * rotation * scale).
148184
* @see https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion
149185
*/
150186
export function rotationOf(m: ReadonlyMat4, out: Quat = quat.create()): Quat {

dist/array.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export declare function dot(a: ReadonlyVec, b: ReadonlyVec): Float;
5151
* @param out the output matrix
5252
* @returns out = [M]T
5353
*/
54-
export declare function tr(n: Int, m: ReadonlyVec, out: Vec): Vec;
54+
export declare function transpose(n: Int, m: ReadonlyVec, out: Vec): Vec;
5555
/**
5656
* Calculate matrix multiplication of a * b, where size of a is (rr * n), and b is (n * rc).
5757
* @param n matrix order

dist/array.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/array.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)