2
votes

This is something I've been trying to work out for a while - I'm trying to go from a 2D x,y,w homogeneous transform matrix (eg. Android's graphics.matrix) and turn it into a 3D x,y,z,w transform matrix (eg. Android's opengl.matrix)

Convert an android.graphics.Matrix to a GL mat4? seems to be a similar question but the answer only applies to affine transformations while I need to handle perspective transformations in x and y. This also seems like something more general than a Android specific implementation.

I've tried making a system of equations to solve for what the 3D matrix values need to be such that for five points, the results for X and Y equal their value after the 2D transformation is applied and Z always equals one, but if the Z value is always left the same (what I want to happen) then the matrix is not invertible.

import numpy as np

# arbitrary points to sample
# need 5 points to have 5 * 3d = 15 equations to solve for 15 matrix coefficents

x0 = -1
y0 = 1
z0 = 1
u0 = -1
v0 = 1
w0 = 1

x1 = 1
y1 = 1
z1 = 1
u1 = 1
v1 = 1
w1 = 1

x2 = 1
y2 = -1
z2 = 1
u2 = 1
v2 = -1
w2 = 1

x3 = -1
y3 = -1
z3 = 1
u3 = -1
v3 = -1
w3 = 1

x4 = 0
y4 = 0
z4 = 1
u4 = 0
v4 = 0
w4 = 1

# The following numbers seem to allow the calculation to finish but are not what i want
# x4 = 21
# y4 = 15
# z4 = 36
# u4 = 12
# v4 = 21
# w4 = 31

# matrix made by extending https://stackoverflow.com/a/57280136 into 3d

A = np.matrix([
    [x0, y0, z0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -x0*u0, -y0*u0, -z0*u0],
    [x1, y1, z1, 1, 0, 0, 0, 0, 0, 0, 0, 0, -x1*u1, -y1*u1, -z1*u1],
    [x2, y2, z2, 1, 0, 0, 0, 0, 0, 0, 0, 0, -x2*u2, -y2*u2, -z2*u2],
    [x3, y3, z3, 1, 0, 0, 0, 0, 0, 0, 0, 0, -x3*u3, -y3*u3, -z3*u3],
    [x4, y4, z4, 1, 0, 0, 0, 0, 0, 0, 0, 0, -x4*u4, -y4*u4, -z4*u4],
    [0, 0, 0, 0, x0, y0, z0, 1, 0, 0, 0, 0, -x0*v0, -y0*v0, -z0*v0],
    [0, 0, 0, 0, x1, y1, z1, 1, 0, 0, 0, 0, -x1*v1, -y1*v1, -z1*v1],
    [0, 0, 0, 0, x2, y2, z2, 1, 0, 0, 0, 0, -x2*v2, -y2*v2, -z2*v2],
    [0, 0, 0, 0, x3, y3, z3, 1, 0, 0, 0, 0, -x3*v3, -y3*v3, -z3*v3],
    [0, 0, 0, 0, x4, y4, z4, 1, 0, 0, 0, 0, -x4*v4, -y4*v4, -z4*v4],
    [0, 0, 0, 0, 0, 0, 0, 0, x0, y0, z0, 1, -x0*w0, -y0*w0, -z0*w0],
    [0, 0, 0, 0, 0, 0, 0, 0, x1, y1, z1, 1, -x1*w1, -y1*w1, -z1*w1],
    [0, 0, 0, 0, 0, 0, 0, 0, x2, y2, z2, 1, -x2*w2, -y2*w2, -z2*w2],
    [0, 0, 0, 0, 0, 0, 0, 0, x3, y3, z3, 1, -x3*w3, -y3*w3, -z3*w3],
    [0, 0, 0, 0, 0, 0, 0, 0, x4, y4, z4, 1, -x4*w4, -y4*w4, -z4*w4]
])

print(A)
print(np.linalg.det(A)) # zero

b = np.array([u0, u1, u2, u3, u4, v0, v1, v2, v3, v4, w0, w1, w2, w3, w4])

c = np.linalg.solve(A, b) # crashes here

mat3d = np.matrix([
    [c[0], c[1], c[2], c[3]],
    [c[4], c[5], c[6], c[7]],
    [c[8], c[9], c[10], c[11]],
    [c[12], c[13], c[14], 1]
])

print(mat3d)

Is there a way to reliably extend a 2D homogeneous coordinates matrix to a 3D one?

Thanks!

1
I find this question still unclear: "Is there a way to reliably extend a 2D homogeneous coordinates matrix to a 3D one?" There are many ways, but it is unclear which properties are needed here. There is only a limited set of transformation properties which can be achieved by matrix multiplication in a homogeneous coordinate space.derhass
"The results for X and Y equal their value after the 2D transformation is applied and Z always equals one, but if the Z value is always left the same (what I want to happen) then the matrix is not invertible" If you want z to be mapped to a constant, then of course it is not invertible. But why do would you need it invertible then? As by your own specification, the inverse cannot exist. The 2D part of the mapping still can be inverted, though.derhass
"s there a way to find the proper 4D matrix values given the inverse of the 3D matrix?" What are you trying to achieve here? Since there is only a single w you have to divide all dimensions by, the prespective effect will always apply to x, y and z. If you wanted some linear function in the z dimension (regarding the full transform of matrix-vector product follwed by perspecitve divide), you would in the general case need a non-linear mapping in z (before the divide), which simply can't be represented by a matrix-vector product.derhass
But the question is: do you need it to by representable by a single matrix-vector product? Nothing is preventing you from for example setting gl_Position.z = input.z * gl_Position.w. However, you just need to be aware that then, the default interpolation for z will have the effect of bending your primitive in the z direction (will the corner points at the vertices stay correct), which might screw up the depth test and result in incorrect visibility if other primitves are close. But that effect can be fixed in the fragment shader (at the cost of losing early-z test, though).derhass
But if just drawing a 2D texture distorted to a trapezoid, you're better off by using homogeneous space for the texture coordinates, and simply have your primitives form the correct 2D trapezoid shape in your 3D world.derhass

1 Answers

0
votes

If I understand your question, have a 3x3 matrix M1 and you want a 4x4 matrix M2, such that:

Wherever M1[x1,y1,w1] = [x2,y2,w2]...

You want M2[x1,y1,0,w1] = [x3,y3,z3,w3]...

Such that x2/w2 = x3/w3, y2/w2 = y3/w3, z3/w3 = 1

The easiest way is just to extend the matrix so that x3 = x2, y3 = y2, z3 = w2, w3 = w2. To do that you just add a z column that is the same as the w column, and a z row that is all zeros