• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google LLC All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.skar;
18 
19 import android.graphics.Matrix;
20 
21 /**
22  * Provides static methods for matrix manipulation needed to draw in ARCore with Canvas.
23  * Input matrices are assumed to be 4x4 android.opengl.Matrix types (16-float arrays in column-major
24  * order).
25  * Output matrices are 3x3 android.graphics.Matrix types.
26  */
27 
28 public class CanvasMatrixUtil {
29 
30     /******************* PUBLIC FUNCTIONS ***********************/
31 
32     /**
33      * Returns an android.graphics.Matrix that can be used on a Canvas to draw a 2D object in
34      * perspective. Object will be rotated towards the XZ plane and will appear to stick on Planes.
35      * Undefined behavior when any of the matrices are not of size 16, or are null.
36      *
37      * @param model          4x4 model matrix of the object to be drawn (global/world)
38      * @param view           4x4 camera view matrix (brings objects to camera origin and
39      *                       orientation)
40      * @param projection     4x4 projection matrix
41      * @param viewPortWidth  width of viewport of GLSurfaceView
42      * @param viewPortHeight height of viewport of GLSurfaceView
43      * @return 3x3 matrix that puts a 2D objects in perspective on a Canvas
44      */
45 
createPerspectiveMatrix(float[] model, float[] view, float[] projection, float viewPortWidth, float viewPortHeight)46     public static Matrix createPerspectiveMatrix(float[] model, float[] view, float[] projection,
47                                                  float viewPortWidth, float viewPortHeight) {
48         float[] viewPort = createViewportMatrix(viewPortWidth, viewPortHeight);
49         float[] planeStickRotation = createXYtoXZRotationMatrix();
50         float[][] matrices = {planeStickRotation, model, view, projection, viewPort};
51         return createMatrixFrom4x4Array(matrices);
52     }
53 
54     /**
55      * Returns a 16-float matrix in column-major order that represents a viewport matrix given
56      * the width and height of the viewport.
57      *
58      * @param width  width of viewport
59      * @param height height of viewport
60      */
61 
createViewportMatrix(float width, float height)62     public static float[] createViewportMatrix(float width, float height) {
63         float[] viewPort = new float[16];
64         android.opengl.Matrix.setIdentityM(viewPort, 0);
65         android.opengl.Matrix.translateM(viewPort, 0, width / 2, height / 2, 0);
66         android.opengl.Matrix.scaleM(viewPort, 0, width / 2, -height / 2, 0);
67         return viewPort;
68     }
69 
70     /**
71      * Returns a 16-float matrix in column-major order that is used to rotate objects from the
72      * XY plane to the XZ plane. This is useful given that objects drawn on the Canvas are on the
73      * XY plane.
74      * In order to get objects to appear as if they are sticking on planes/ceilings/walls, we need
75      * to rotate them from the XY plane to the XZ plane.
76      */
77 
createXYtoXZRotationMatrix()78     public static float[] createXYtoXZRotationMatrix() {
79         float[] rotation = new float[16];
80         android.opengl.Matrix.setIdentityM(rotation, 0);
81         android.opengl.Matrix.rotateM(rotation, 0, 90, 1, 0, 0);
82         return rotation;
83     }
84 
85 
86     /**
87      * Returns an android.graphics.Matrix resulting from a 16-float matrix array in column-major
88      * order.
89      * Undefined behavior when the array is not of size 16 or is null.
90      *
91      * @param m4 16-float matrix in column-major order
92      */
93 
createMatrixFrom4x4(float[] m4)94     public static Matrix createMatrixFrom4x4(float[] m4) {
95         float[] m3 = matrix4x4ToMatrix3x3(m4);
96         return createMatrixFrom3x3(m3);
97     }
98 
99     /**
100      * Returns an android.graphics.Matrix resulting from the concatenation of 16-float matrices
101      * in column-major order from left to right.
102      * e.g: m4Array = {m1, m2, m3} --> returns m = m3 * m2 * m1
103      * Undefined behavior when the array is empty, null, or contains arrays not of size 9 (or null)
104      *
105      * @param m4Array array of 16-float matrices in column-major order
106      */
107 
createMatrixFrom4x4Array(float[][] m4Array)108     public static Matrix createMatrixFrom4x4Array(float[][] m4Array) {
109         float[] result = multiplyMatrices4x4(m4Array);
110         return createMatrixFrom4x4(result);
111     }
112 
113     /**
114      * Returns 4-float array resulting from the multiplication of a Vector of 4 floats
115      * with a 4x4 float Matrix. The return is essentially m4 * v4, with perspective-divide applied
116      * if perspectiveDivide is true
117      * @param m4                16-float matrix in column-major order
118      * @param v4                4-float vector
119      * @param perspectiveDivide if true, divide return value by the w-coordinate
120      * @return                  4-float array resulting from the multiplication
121      */
122 
multiplyMatrixVector(float[] m4, float[] v4, boolean perspectiveDivide)123     public static float[] multiplyMatrixVector(float[] m4, float[] v4, boolean perspectiveDivide) {
124         float[] result = new float[4];
125         android.opengl.Matrix.multiplyMV(result, 0, m4, 0, v4, 0);
126         if (perspectiveDivide) {
127             return new float[] {result[0] / result[3], result[1] / result[3],
128                                 result[2] / result[3], 1};
129         }
130 
131         return new float[] {result[0], result[1], result[2], result[3]};
132     }
133 
134     /**
135      * Returns a 16-float matrix in column-major order resulting from the multiplication of matrices
136      * e.g: m4Array = {m1, m2, m3} --> returns m = m3 * m2 * m1
137      * Undefined behavior when the array is empty, null, or contains arrays not of size 9 (or null)
138      *
139      * @param m4Array array of 16-float matrices in column-major order
140      */
141 
multiplyMatrices4x4(float[][] m4Array)142     public static float[] multiplyMatrices4x4(float[][] m4Array) {
143         float[] result = new float[16];
144         android.opengl.Matrix.setIdentityM(result, 0);
145         float[] rhs = result;
146         for (int i = 0; i < m4Array.length; i++) {
147             float[] lhs = m4Array[i];
148             android.opengl.Matrix.multiplyMM(result, 0, lhs, 0, rhs, 0);
149             rhs = result;
150         }
151         return result;
152     }
153 
154     /******************* PRIVATE FUNCTIONS ***********************/
155 
156     /**
157      * Returns an android.graphics.Matrix resulting from a 9-float matrix array in row-major order.
158      * Undefined behavior when the array is not of size 9 or is null.
159      *
160      * @param m3 9-float matrix array in row-major order
161      */
162 
createMatrixFrom3x3(float[] m3)163     private static Matrix createMatrixFrom3x3(float[] m3) {
164         Matrix m = new Matrix();
165         m.setValues(m3);
166         return m;
167     }
168 
169     /**
170      * Returns a 9-float matrix in row-major order given a 16-float matrix in column-major order.
171      * This will drop the Z column and row.
172      * Undefined behavior when the array is not of size 9 or is null.
173      *
174      * @param m4 16-float matrix in column-major order
175      */
176 
matrix4x4ToMatrix3x3(float[] m4)177     private static float[] matrix4x4ToMatrix3x3(float[] m4) {
178         float[] m3 = new float[9];
179 
180         int j = 0;
181         for (int i = 0; i < 7; i = i + 3) {
182             if (j == 2) {
183                 j++; //skip row #3
184             }
185             m3[i] = m4[j];
186             m3[i + 1] = m4[j + 4];
187             m3[i + 2] = m4[j + 12];
188             j++;
189         }
190         return m3;
191     }
192 }
193