3

I am struggling to apply a projective transformation based on the 4 corners of my display, as followed :

enter image description here

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...

enter image description here

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 !

Community
  • 1
  • 1
Julien Mazars
  • 1,032
  • 11
  • 24
  • 1
    "*apply a projective transformation based on the 4 corners of my display*" What does that mean, exactly? Your diagrams likewise don't make it clear what you're trying to do. – Nicol Bolas Aug 02 '16 at 19:30
  • I just added a picture to make it more clear. – Julien Mazars Aug 02 '16 at 19:44
  • My result looks more like an "affine transformation" instead of a "projective transformation", but I don't understand why... (cf http://www.graphicsmill.com/docs/gm/affine-and-projective-transformations.htm) – Julien Mazars Aug 02 '16 at 19:52
  • Looking at what you expect, I'd say you want just to render to a texture and map that texture on that polygon – elect Aug 03 '16 at 08:44

0 Answers0