Home | History | Annotate | Download | only in engine
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      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.example.android.rs.vr.engine;
     18 
     19 import android.util.Log;
     20 
     21 import java.text.DecimalFormat;
     22 import java.util.Arrays;
     23 
     24 public class ViewMatrix extends Matrix {
     25     private static final String LOGTAG = "ViewMatrix";
     26     private double[] mLookPoint;
     27     private double[] mEyePoint;
     28     private double[] mUpVector;
     29     private double mScreenWidth;
     30     private int[] mScreenDim;
     31 
     32     private Matrix mStartMatrix;
     33     private double[] mStartV = new double[3];
     34     private double[] mMoveToV = new double[3];
     35     private double[] mStartEyePoint;
     36     private double[] mStartUpVector;
     37     private Quaternion mQ = new Quaternion(0, 0, 0, 0);
     38 
     39     public final static char UP_AT = 0x001;
     40     public final static char DOWN_AT = 0x002;
     41     public final static char RIGHT_AT = 0x010;
     42     public final static char LEFT_AT = 0x020;
     43     public final static char FORWARD_AT = 0x100;
     44     public final static char BEHIND_AT = 0x200;
     45 
     46     public void clone(ViewMatrix src) {
     47         if (src.mLookPoint != null) {
     48             System.arraycopy(src.mLookPoint, 0, mLookPoint, 0, mLookPoint.length);
     49         }
     50         if (src.mEyePoint != null) {
     51             System.arraycopy(src.mEyePoint, 0, mEyePoint, 0, mEyePoint.length);
     52         }
     53         if (src.mUpVector != null) {
     54             System.arraycopy(src.mUpVector, 0, mUpVector, 0, mUpVector.length);
     55         }
     56         mScreenWidth = src.mScreenWidth;
     57 
     58         if (src.mScreenDim != null) {
     59             System.arraycopy(src.mScreenDim, 0, mScreenDim, 0, mScreenDim.length);
     60         }
     61         if (src.mStartV != null) {
     62             System.arraycopy(src.mStartV, 0, mStartV, 0, mStartV.length);
     63         }
     64         if (src.mMoveToV != null) {
     65             System.arraycopy(src.mMoveToV, 0, mMoveToV, 0, mMoveToV.length);
     66         }
     67 
     68 
     69         if (src.mStartEyePoint != null) {
     70             if (mStartEyePoint == null) {
     71                 mStartEyePoint = Arrays.copyOf(src.mStartEyePoint,src.mStartEyePoint.length);
     72             } else {
     73                 System.arraycopy(src.mStartEyePoint, 0, mStartEyePoint, 0, mStartEyePoint.length);
     74             }
     75         }
     76         if (src.mStartUpVector != null) {
     77             if (mStartUpVector == null) {
     78                 mStartUpVector = Arrays.copyOf(src.mStartUpVector,src.mStartUpVector.length);
     79             } else {
     80                 System.arraycopy(src.mStartUpVector, 0, mStartUpVector, 0, mStartUpVector.length);
     81             }
     82         }
     83         if (src.mStartMatrix != null) {
     84             if (mStartMatrix == null) {
     85                 mStartMatrix = new Matrix();
     86             }
     87             mStartMatrix.clone(src.mStartMatrix);
     88         }
     89         mQ.clone(src.mQ);
     90         super.clone(src);
     91     }
     92 
     93     private static String toStr(double d) {
     94         String s = "         " + df.format(d);
     95         return s.substring(s.length() - 9);
     96     }
     97 
     98     private static String toStr(double[] d) {
     99         String s = "[";
    100         for (int i = 0; i < d.length; i++) {
    101             s += toStr(d[i]);
    102         }
    103 
    104         return s + "]";
    105     }
    106 
    107     private static DecimalFormat df = new DecimalFormat("##0.000");
    108 
    109     @Override
    110     public void print() {
    111         Log.v(LOGTAG, "mLookPoint  :" + toStr(mLookPoint));
    112         Log.v(LOGTAG, "mEyePoint   :" + toStr(mEyePoint));
    113         Log.v(LOGTAG, "mUpVector   :" + toStr(mUpVector));
    114         Log.v(LOGTAG, "mScreenWidth: " + toStr(mScreenWidth));
    115         Log.v(LOGTAG, "mScreenDim  :[" + mScreenDim[0] + ", " + mScreenDim[1] + "]");
    116     }
    117 
    118     public ViewMatrix() {
    119         mLookPoint = new double[3];
    120         mEyePoint = new double[3];
    121         mUpVector = new double[3];
    122         mScreenDim = new int[2];
    123     }
    124 
    125     public void setScreenDim(int x, int y) {
    126         mScreenDim = new int[]{x, y};
    127     }
    128 
    129     public double[] getLookPoint() {
    130         return mLookPoint;
    131     }
    132 
    133     public void setLookPoint(double[] mLookPoint) {
    134         this.mLookPoint = mLookPoint;
    135     }
    136 
    137     public double[] getEyePoint() {
    138         return mEyePoint;
    139     }
    140 
    141     public void setEyePoint(double[] mEyePoint) {
    142         this.mEyePoint = mEyePoint;
    143     }
    144 
    145     public double[] getUpVector() {
    146         return mUpVector;
    147     }
    148 
    149     public void setUpVector(double[] mUpVector) {
    150         this.mUpVector = mUpVector;
    151     }
    152 
    153     public double getScreenWidth() {
    154         return mScreenWidth;
    155     }
    156 
    157     public void setScreenWidth(double screenWidth) {
    158         this.mScreenWidth = screenWidth;
    159     }
    160 
    161     public void makeUnit() {
    162 
    163     }
    164 
    165     public void calcMatrix() {
    166         if (mScreenDim == null) {
    167             return;
    168         }
    169         double scale = mScreenWidth / mScreenDim[0];
    170         double[] zv = {
    171                 mLookPoint[0] - mEyePoint[0],
    172                 mLookPoint[1] - mEyePoint[1],
    173                 mLookPoint[2] - mEyePoint[2]
    174         };
    175         VectorUtil.normalize(zv);
    176 
    177 
    178         double[] m = new double[16];
    179         m[2] = zv[0];
    180         m[6] = zv[1];
    181         m[10] = zv[2];
    182         m[14] = 0;
    183 
    184         calcRight(zv, mUpVector, zv);
    185         double[] right = zv;
    186 
    187         m[0] = right[0] * scale;
    188         m[4] = right[1] * scale;
    189         m[8] = right[2] * scale;
    190         m[12] = 0;
    191 
    192         m[1] = -mUpVector[0] * scale;
    193         m[5] = -mUpVector[1] * scale;
    194         m[9] = -mUpVector[2] * scale;
    195         m[13] = 0;
    196         double sw = mScreenDim[0] / 2 - 0.5;
    197         double sh = mScreenDim[1] / 2 - 0.5;
    198         double sz = -0.5;
    199         m[3] = mEyePoint[0] - (m[0] * sw + m[1] * sh + m[2] * sz);
    200         m[7] = mEyePoint[1] - (m[4] * sw + m[5] * sh + m[6] * sz);
    201         m[11] = mEyePoint[2] - (m[8] * sw + m[9] * sh + m[10] * sz);
    202 
    203         m[15] = 1;
    204         this.m = m;
    205     }
    206 
    207     static void calcRight(double[] a, double[] b, double[] out) {
    208         VectorUtil.cross(a, b, out);
    209     }
    210 
    211     public static void main(String[] args) {
    212         double[] up = {0, 0, 1};
    213         double[] look = {0, 0, 0};
    214         double[] eye = {-10, 0, 0};
    215         ViewMatrix v = new ViewMatrix();
    216         v.setEyePoint(eye);
    217         v.setLookPoint(look);
    218         v.setUpVector(up);
    219         v.setScreenWidth(10);
    220         v.setScreenDim(512, 512);
    221         v.calcMatrix();
    222     }
    223 
    224     private void calcLook(TriData tri, float[] voxelDim, int w, int h) {
    225         float minx = Float.MAX_VALUE, miny = Float.MAX_VALUE, minz = Float.MAX_VALUE;
    226         float maxx = -Float.MAX_VALUE, maxy = -Float.MAX_VALUE, maxz = -Float.MAX_VALUE;
    227 
    228         for (int i = 0; i < tri.mVert.length; i += 3) {
    229             maxx = Math.max(tri.mVert[i], maxx);
    230             minx = Math.min(tri.mVert[i], minx);
    231             maxy = Math.max(tri.mVert[i + 1], maxy);
    232             miny = Math.min(tri.mVert[i + 1], miny);
    233             maxz = Math.max(tri.mVert[i + 2], maxz);
    234             minz = Math.min(tri.mVert[i + 2], minz);
    235         }
    236         mLookPoint = new double[]{voxelDim[0] * (maxx + minx) / 2,
    237                 voxelDim[1] * (maxy + miny) / 2,
    238                 voxelDim[2] * (maxz + minz) / 2};
    239         mScreenWidth = Math.max(voxelDim[0] * (maxx - minx),
    240                 Math.max(voxelDim[1] * (maxy - miny),
    241                         voxelDim[2] * (maxz - minz))) * 2;
    242     }
    243 
    244     private void calcLook(TriData triW, int w, int h) {
    245         float minx = Float.MAX_VALUE, miny = Float.MAX_VALUE, minz = Float.MAX_VALUE;
    246         float maxx = -Float.MAX_VALUE, maxy = -Float.MAX_VALUE, maxz = -Float.MAX_VALUE;
    247 
    248         for (int i = 0; i < triW.mVert.length; i += 3) {
    249             maxx = Math.max(triW.mVert[i], maxx);
    250             minx = Math.min(triW.mVert[i], minx);
    251             maxy = Math.max(triW.mVert[i + 1], maxy);
    252             miny = Math.min(triW.mVert[i + 1], miny);
    253             maxz = Math.max(triW.mVert[i + 2], maxz);
    254             minz = Math.min(triW.mVert[i + 2], minz);
    255         }
    256         mLookPoint = new double[]{(maxx + minx) / 2, (maxy + miny) / 2, (maxz + minz) / 2};
    257 
    258         mScreenWidth = 2 * Math.max((maxx - minx), Math.max((maxy - miny), (maxz - minz)));
    259     }
    260 
    261     public void look(char dir, TriData tri, float[] voxelDim, int w, int h) {
    262         calcLook(tri, w, h);
    263         int dx = ((dir >> 4) & 0xF);
    264         int dy = ((dir >> 8) & 0xF);
    265         int dz = ((dir >> 0) & 0xF);
    266         if (dx > 1) {
    267             dx = -1;
    268         }
    269         if (dy > 1) {
    270             dy = -1;
    271         }
    272         if (dz > 1) {
    273             dz = -1;
    274         }
    275         mEyePoint = new double[]{mLookPoint[0] + 2 * mScreenWidth * dx,
    276                 mLookPoint[1] + 2 * mScreenWidth * dy,
    277                 mLookPoint[2] + 2 * mScreenWidth * dz};
    278         double[] zv = new double[]{-dx, -dy, -dz};
    279         double[] rv = new double[]{(dx == 0) ? 1 : 0, (dx == 0) ? 0 : 1, 0};
    280         double[] up = new double[3];
    281         VectorUtil.norm(zv);
    282         VectorUtil.norm(rv);
    283 
    284         VectorUtil.cross(zv, rv, up);
    285         VectorUtil.cross(zv, up, rv);
    286         VectorUtil.cross(zv, rv, up);
    287         mUpVector = up;
    288         mScreenDim = new int[]{w, h};
    289         calcMatrix();
    290     }
    291 
    292     public void lookAt(TriData tri, float[] voxelDim, int w, int h) {
    293         calcLook(tri, voxelDim, w, h);
    294 
    295         mEyePoint = new double[]{mLookPoint[0] + mScreenWidth,
    296                 mLookPoint[1] + mScreenWidth,
    297                 mLookPoint[2] + mScreenWidth};
    298         double[] zv = new double[]{-1, -1, -1};
    299         double[] rv = new double[]{1, 1, 0};
    300         double[] up = new double[3];
    301         VectorUtil.norm(zv);
    302         VectorUtil.norm(rv);
    303 
    304         VectorUtil.cross(zv, rv, up);
    305         VectorUtil.cross(zv, up, rv);
    306         VectorUtil.cross(zv, rv, up);
    307         mUpVector = up;
    308         mScreenDim = new int[]{w, h};
    309         calcMatrix();
    310     }
    311 
    312     public void trackBallUP(float x, float y) {
    313 
    314     }
    315 
    316     public void trackBallDown(float x, float y) {
    317 
    318         ballToVec(x, y, mStartV);
    319         mStartEyePoint = Arrays.copyOf(mEyePoint, m.length);
    320         mStartUpVector = Arrays.copyOf(mUpVector, m.length);
    321         mStartMatrix = new Matrix(this);
    322         mStartMatrix.makeRotation();
    323     }
    324 
    325     public void trackBallMove(float x, float y) {
    326         ballToVec(x, y, mMoveToV);
    327 
    328         double angle = Quaternion.calcAngle(mStartV, mMoveToV);
    329         if (angle < 0.0001) {
    330             calcMatrix();
    331             return;
    332         }
    333         double[] axis = Quaternion.calcAxis(mStartV, mMoveToV);
    334 
    335 
    336         axis = mStartMatrix.vecmult(axis);
    337 
    338         mQ.set(angle, axis);
    339 
    340         VectorUtil.sub(mLookPoint, mStartEyePoint, mEyePoint);
    341 
    342         mEyePoint = mQ.rotateVec(mEyePoint);
    343         mUpVector = mQ.rotateVec(mStartUpVector);
    344 
    345         VectorUtil.sub(mLookPoint, mEyePoint, mEyePoint);
    346         calcMatrix();
    347     }
    348 
    349     void ballToVec(float x, float y, double[] v) {
    350         float ballRadius = Math.min(mScreenDim[0], mScreenDim[1]) * .4f;
    351         double cx = mScreenDim[0] / 2.;
    352         double cy = mScreenDim[1] / 2.;
    353 
    354         double dx = (cx - x) / ballRadius;
    355         double dy = (cy - y) / ballRadius;
    356         double scale = dx * dx + dy * dy;
    357         if (scale > 1) {
    358             scale = Math.sqrt(scale);
    359             dx = dx / scale;
    360             dy = dy / scale;
    361         }
    362 
    363         double dz = Math.sqrt(Math.abs(1 - (dx * dx + dy * dy)));
    364         v[0] = dx;
    365         v[1] = dy;
    366         v[2] = dz;
    367         VectorUtil.normalize(v);
    368     }
    369 }
    370