I am struggling to apply a projective transformation based on the 4 corners of my display, as followed :
My insight is to tune up a bit the projection matrix, by first computing the perspective transformation, and multiplying the matrix by the projective transformation.
Thanks to this nice answer, I was able to find the projective transformation matrix, but the results I obtain are not the one I expect...
Here is some code I have :
public void reshape(final GLAutoDrawable drawable, final int arg1, final int arg2, final int width,
final int height) {
// Get the OpenGL graphics context
if (width <= 0 || height <= 0) {
return;
}
final GL2 gl = drawable.getContext().getGL().getGL2();
// Set the viewport (display area) to cover the entire window
gl.glViewport(0, 0, width, height);
// Enable the model view - any new transformations will affect the
// model-view matrix
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
gl.glLoadIdentity(); // reset
// perspective view
gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
gl.glLoadIdentity();
// Only if zoomFit... camera.resetCamera(data.getEnvWidth(),
// data.getEnvHeight(), data.isOutput3D());
updatePerspective(gl);
}
public final void updatePerspective(final GL2 gl) {
final int height = getDrawable().getSurfaceHeight();
final double aspect = (double) getDrawable().getSurfaceWidth() / (double) (height == 0 ? 1 : height);
final double maxDim = getMaxEnvDim();
if (!data.isOrtho()) {
try {
final double zNear = maxDim / 1000;
double fW, fH;
// final double fovY = 45.0d;
final double fovY = this.data.getCameralens();
if (aspect > 1.0) {
fH = FastMath.tan(fovY / 360 * Math.PI) * zNear;
fW = fH * aspect;
} else {
fW = FastMath.tan(fovY / 360 * Math.PI) * zNear;
fH = fW / aspect;
}
gl.glFrustum(-fW, fW, -fH, fH, zNear, maxDim * 10);
} catch (final BufferOverflowException e) {
System.out.println("Buffer overflow exception");
}
} else {
if (aspect >= 1.0) {
((GL2ES1) gl).glOrtho(-maxDim * aspect, maxDim * aspect, -maxDim, maxDim, maxDim * 10, -maxDim * 10);
} else {
((GL2ES1) gl).glOrtho(-maxDim, maxDim, -maxDim / aspect, maxDim / aspect, maxDim, -maxDim);
}
gl.glTranslated(0d, 0d, maxDim * 0.05);
}
// keystoning
double[][] srcPoints = {
{0,0,0},
{1,0,0},
{1,1,0},
{0,1,0}
};
double[][] dstPoints = {
{X1,Y1,0},
{X2,Y2,0},
{X3,Y3,0},
{X4,Y4,0}
};
double[] keystoneMatrix = getDoubleArray(getHomography(srcPoints, dstPoints));
gl.glMultMatrixd(keystoneMatrix,0);
camera.animate();
}
public static Matrix4d getHomography(double[][] srcPoints, double[][] dstPoints) {
double sx1 = srcPoints[0][0];
double sy1 = srcPoints[0][1];
double sx2 = srcPoints[1][0];
double sy2 = srcPoints[1][1];
double sx3 = srcPoints[2][0];
double sy3 = srcPoints[2][1];
double sx4 = srcPoints[3][0];
double sy4 = srcPoints[3][1];
double dx1 = dstPoints[0][0];
double dy1 = dstPoints[0][1];
double dx2 = dstPoints[1][0];
double dy2 = dstPoints[1][1];
double dx3 = dstPoints[2][0];
double dy3 = dstPoints[2][1];
double dx4 = dstPoints[3][0];
double dy4 = dstPoints[3][1];
// 1) resolve the following equation for src and dst :
// | x1 x2 x3 | | lamda | | x4 |
// | y1 y2 y3 | . | mu | = | y4 |
// | 1 1 1 | | to | | 1 |
// for src :
double src_to = ( (sx4 - sx1)*(sy2 - sy1) - (sy4 - sy1)*(sx2 - sx1) ) /
( (sx3 - sx1)*(sy2 - sy1) - (sy3 - sy1)*(sx2 - sx1) );
double src_mu = (sx4 - sx1 - src_to*(sx3 - sx1)) / (sx2 - sx1);
double src_lamda = 1 - src_mu - src_to;
// for dst :
double dst_to = ( (dx4 - dx1)*(dy2 - dy1) - (dy4 - dy1)*(dx2 - dx1) ) /
( (dx3 - dx1)*(dy2 - dy1) - (dy3 - dy1)*(dx2 - dx1) );
double dst_mu = (dx4 - dx1 - dst_to*(dx3 - dx1)) / (dx2 - dx1);
double dst_lamda = 1 - dst_mu - dst_to;
// 2) scale the columns by the coefficients just computed :
// | lamda*x1 mu*x2 to*x3 |
// | lamda*y1 mu*y2 to*y3 |
// | lamda mu to |
Matrix3d A = new Matrix3d();
A.m00 = src_lamda * sx1;
A.m01 = src_mu * sx2;
A.m02 = src_to * sx3;
A.m10 = src_lamda * sy1;
A.m11 = src_mu * sy2;
A.m12 = src_to * sy3;
A.m20 = src_lamda;
A.m21 = src_mu;
A.m22 = src_to;
Matrix3d B = new Matrix3d();
B.m00 = dst_lamda * dx1;
B.m01 = dst_mu * dx2;
B.m02 = dst_to * dx3;
B.m10 = dst_lamda * dy1;
B.m11 = dst_mu * dy2;
B.m12 = dst_to * dy3;
B.m20 = dst_lamda;
B.m21 = dst_mu;
B.m22 = dst_to;
// 3) compute Ainvert
Matrix3d Ainv = (Matrix3d) A.clone();
Ainv.invert();
// 4) compute C = B . Ainvert
Matrix3d C = (Matrix3d) B.clone();
C.mul(Ainv);
// 5) compute the final matrix
Matrix4d Result = new Matrix4d();
Result.m00 = C.m00;
Result.m01 = C.m01;
Result.m02 = 0;
Result.m03 = C.m02;
Result.m10 = C.m10;
Result.m11 = C.m11;
Result.m12 = 0;
Result.m13 = C.m12;
Result.m20 = 0;
Result.m21 = 0;
Result.m22 = 1;
Result.m23 = 0;
Result.m30 = C.m20;
Result.m31 = C.m21;
Result.m32 = 0;
Result.m33 = C.m22;
return Result;
}
I must have missed something, but I don't know what... Thank you in advance for your help !