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 clone(ViewMatrix src)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 toStr(double d)93 private static String toStr(double d) { 94 String s = " " + df.format(d); 95 return s.substring(s.length() - 9); 96 } 97 toStr(double[] d)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 print()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 ViewMatrix()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 setScreenDim(int x, int y)125 public void setScreenDim(int x, int y) { 126 mScreenDim = new int[]{x, y}; 127 } 128 getLookPoint()129 public double[] getLookPoint() { 130 return mLookPoint; 131 } 132 setLookPoint(double[] mLookPoint)133 public void setLookPoint(double[] mLookPoint) { 134 this.mLookPoint = mLookPoint; 135 } 136 getEyePoint()137 public double[] getEyePoint() { 138 return mEyePoint; 139 } 140 setEyePoint(double[] mEyePoint)141 public void setEyePoint(double[] mEyePoint) { 142 this.mEyePoint = mEyePoint; 143 } 144 getUpVector()145 public double[] getUpVector() { 146 return mUpVector; 147 } 148 setUpVector(double[] mUpVector)149 public void setUpVector(double[] mUpVector) { 150 this.mUpVector = mUpVector; 151 } 152 getScreenWidth()153 public double getScreenWidth() { 154 return mScreenWidth; 155 } 156 setScreenWidth(double screenWidth)157 public void setScreenWidth(double screenWidth) { 158 this.mScreenWidth = screenWidth; 159 } 160 makeUnit()161 public void makeUnit() { 162 163 } 164 calcMatrix()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 calcRight(double[] a, double[] b, double[] out)207 static void calcRight(double[] a, double[] b, double[] out) { 208 VectorUtil.cross(a, b, out); 209 } 210 main(String[] args)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 calcLook(TriData tri, float[] voxelDim, int w, int h)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 calcLook(TriData triW, int w, int h)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 look(char dir, TriData tri, float[] voxelDim, int w, int h)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 lookAt(TriData tri, float[] voxelDim, int w, int h)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 trackBallUP(float x, float y)312 public void trackBallUP(float x, float y) { 313 314 } 315 trackBallDown(float x, float y)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 trackBallMove(float x, float y)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 ballToVec(float x, float y, double[] v)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