Hi all,
I’m trying to make a 2D perspective transform matrix that maps 4 source points to 4 destination points.
I think I’m doing something backward but I can’t pinpoint my error.
I’m using mathjs for solving the system. here is my situation: I have followed this topic to set up the equations math - Perspective projection, 4 points - Stack Overflow
and have come up with the following function.
export function getTransformMatrix(
s1: THREE.Vector2, s2: THREE.Vector2, s3: THREE.Vector2, s4: THREE.Vector2,
d1: THREE.Vector2, d2: THREE.Vector2, d3: THREE.Vector2, d4: THREE.Vector2,
) {
const A = [
[s1.x, s1.y, 1, 0, 0, 0, -d1.x * s1.x, -d1.x * s1.y],
[0, 0, 0, s1.x, s1.y, 1, -d1.y * s1.x, -d1.y * s1.y],
[s2.x, s2.y, 1, 0, 0, 0, -d2.x * s2.x, -d2.x * s2.y],
[0, 0, 0, s2.x, s2.y, 1, -d2.y * s2.x, -d2.y * s2.y],
[s3.x, s3.y, 1, 0, 0, 0, -d3.x * s3.x, -d3.x * s3.y],
[0, 0, 0, s3.x, s3.y, 1, -d3.y * s3.x, -d3.y * s3.y],
[s4.x, s4.y, 1, 0, 0, 0, -d4.x * s4.x, -d4.x * s4.y],
[0, 0, 0, s4.x, s4.y, 1, -d4.y * s4.x, -d4.y * s4.y],
];
const B = [
d1.x, d1.y,
d2.x, d2.y,
d3.x, d3.y,
d4.x, d4.y
];
const A_matrix = mathjs.matrix(A);
const B_matrix = mathjs.matrix(B);
// A = H * B
// H = A^-1 * B
const A_inv = (mathjs.inv(A_matrix));
const H_matrix = (mathjs.multiply(A_inv, B_matrix));
const H = H_matrix.valueOf().flat();
// Re-order the 3x3 matrix for Three.js
const res = new THREE.Matrix3();
res.set(
H[0], H[3], H[6],
H[1], H[4], H[7],
H[2], H[5], 0
);
return res;
}
the problem is that when I apply the transform, it is wrong.
function applyTransform1(matrix: THREE.Matrix3, vertices :THREE.Vector2[]) {
vertices.forEach(vertice => {
vertice.applyMatrix3(matrix);
})
}
So I tried to make my own version applyTransform2 to try and understand what is hapenning inside. Here it is :
function applyTransform2(matrix: THREE.Matrix3, vertices: THREE.Vector2) {
vertices.forEach(vertex => {
const x = vertex.x;
const y = vertex.y;
const w = matrix.elements[6] * x + matrix.elements[7] * y + 1; // Homogeneous coordinate
const newX = (matrix.elements[0] * x + matrix.elements[1] * y + matrix.elements[2]) / w;
const newY = (matrix.elements[3] * x + matrix.elements[4] * y + matrix.elements[5]) / w;
vertex.setX(newX)
vertex.setY(newY)
});
}
applyTransform2 makes the correct transform with the matrices out of getTransformMatrix but if I use it with some standard THREE js transform matrix such as new THREE.Matrix3().translate(...).matrix.scale(...)
it makes a wrong transform.
So in the end my functions work well together but obviously there is something wrong since vertice.applyMatrix3(M) doesn’t give the expected result.
Here is an example of result:
const s1 = new THREE.Vector2(0, 0);
const s2 = new THREE.Vector2(80, 0);
const s3 = new THREE.Vector2(0, 80);
const s4 = new THREE.Vector2(80, 80);
let d1 = new THREE.Vector2(-200, 100)
let d2 = new THREE.Vector2(0, 200)
let d3 = new THREE.Vector2(0, 0)
let d4 = new THREE.Vector2(30, 100)
expected result (made using applyTransform2): red source, blue destination
wrong result (using applyTransform1): red source, blue destination
I guess I am solving for a right hand multiplication instead of left hand multiplication or I am missing a transpose somewhere… I’ve been at it for a few days but I feel like I’m running in circles now.
Help and pointers welcome