根据Android 传感器控制3D模型方向
2016-03-14 17:34
555 查看
目标
根据传感器信息, 平滑的控制3D模型方向.实现
1. 注册传感器@Override protected void onResume() { super.onResume(); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); // 初始化加速度传感器 mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // 初始化地磁场传感器 mMagnetic = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); if (mSensorManager != null) { mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, mMagnetic, SensorManager.SENSOR_DELAY_GAME); } }
2. 反注册
protected void onPause() { super.onPause(); mSensorManager.unregisterListener(this); }
3. 采样,计算旋转矩阵,再转换为四元数。
<span style="white-space:pre"> </span>float[] accelerometerValues = new float[3]; float[] magneticFieldValues = new float[3]; float getMat3(float[] m, int x, int y){ return m[x + y * 3]; } void matToQuat(float[]mat, float[]q) { float trace; float s; float t; int i; int j; int k; int next[] = { 1, 2, 0 }; trace = mat[0] + mat[4] + mat[8]; if ( trace > 0.0f ) { t = trace + 1.0f; s = 0.5f / (float)Math.sqrt(t); q[3] = s * t; q[0] = ( getMat3(mat, 2 , 1 ) - getMat3(mat, 1 , 2 ) ) * s; q[1] = ( getMat3(mat, 0 , 2 ) - getMat3(mat, 2 , 0 ) ) * s; q[2] = ( getMat3(mat, 1 , 0 ) - getMat3(mat, 0 , 1 ) ) * s; } else { i = 0; if ( getMat3(mat, 1 , 1 ) > getMat3(mat, 0 , 0 ) ) { i = 1; } if ( getMat3(mat, 2 , 2 )> getMat3(mat, i , i ) ) { i = 2; } j = next[ i ]; k = next[ j ]; t = ( getMat3(mat, i, i ) - ( getMat3(mat, j , j ) + getMat3(mat, k , k ) ) ) + 1.0f; s = 0.5f / (float)Math.sqrt(t); q[i] = s * t; q[3] = ( getMat3(mat, k , j ) - getMat3(mat, j ,k ) ) * s; q[j] = ( getMat3(mat, j , i ) + getMat3(mat, i , j ) ) * s; q[k] = ( getMat3(mat, k , i ) + getMat3(mat, i , k ) ) * s; } } float rotMat[] = new float[9]; float quat[] = new float[4]; @Override public void onSensorChanged(SensorEvent event) { // TODO Auto-generated method stub boolean needComputer = false; if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { //Log.e("ACCELEROMETER","onSensorChanged:TYPE_ACCELEROMETER " + String.format("%f %f %f", event.values[0],event.values[1],event.values[2])); if(true) { accelerometerValues[0] = -event.values[1]; accelerometerValues[1] = event.values[0]; accelerometerValues[2] = event.values[2]; needComputer = true; } } if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { if(true) { magneticFieldValues[0] = -event.values[1]; magneticFieldValues[1] = event.values[0]; magneticFieldValues[2] = event.values[2]; needComputer = true; } } if(needComputer == true){ SensorManager.getRotationMatrix(rotMat, null, accelerometerValues, magneticFieldValues); matToQuat(rotMat, mQuat); } }
4. 计算将几何模型坐标变换到手机世界坐标矩阵, 将上一部得到的四元数与当前四元数插值再转换为矩阵,计算视点变换矩阵
void normalizeQuat(float[] q){ float temp=(float)Math.sqrt(q[0]*q[0]+q[1]*q[1]+q[2]*q[2]+q[3]*q[3]); temp=(float)1.0/temp; q[0]*=temp; q[1]*=temp; q[2]*=temp; q[3]*=temp; } void quatSlerp(float[] q, float[]q0,float[] q1,float t) { float k0,k1,cosomega = q0[0] * q1[0] + q0[1] * q1[1] + q0[2] * q1[2] + q0[3] * q1[3]; if(cosomega < 0.0) { cosomega = -cosomega; q[0] = -q1[0]; q[1] = -q1[1]; q[2] = -q1[2]; q[3] = -q1[3]; } else { q[0] = q1[0]; q[1] = q1[1]; q[2] = q1[2]; q[3] = q1[3]; } if(1.0 - cosomega > 1e-6) { float omega = (float)Math.acos(cosomega); float sinomega = (float)Math.sin(omega); k0 = (float)Math.sin((1.0f - t) * omega) / sinomega; k1 = (float)Math.sin(t * omega) / sinomega; } else { k0 = 1.0f - t; k1 = t; } q[0] = q0[0] * k0 + q[0] * k1; q[1] = q0[1] * k0 + q[1] * k1; q[2] = q0[2] * k0 + q[2] * k1; q[3] = q0[3] * k0 + q[3] * k1; normalizeQuat(q); } void quatToMat(float[] ret, float[]q) { float x = q[0]; float y = q[1]; float z = q[2]; float w = q[3]; float x2 = x + x; float y2 = y + y; float z2 = z + z; float xx = x * x2; float yy = y * y2; float zz = z * z2; float xy = x * y2; float yz = y * z2; float xz = z * x2; float wx = w * x2; float wy = w * y2; float wz = w * z2; ret[0] = 1.0f - (yy + zz); ret[4] = xy - wz; ret[8] = xz + wy; ret[12]=0.0f; ret[1] = xy + wz; ret[5] = 1.0f - (xx + zz); ret[9] = yz - wx; ret[13]=0.0f; ret[2] = xz - wy; ret[6] = yz + wx; ret[10]= 1.0f - (xx + yy); ret[14]=0.0f; ret[3] = 0.0f; ret[7]= 0.0f; ret[11]= 0.0f; ret[15]=1.0f; } float[] mCurQuat = new float[4]; float[] mPreQuat = {0f, 0, 0, 1}; float[] mRotMat = new float[16]; public void draw() { ................................... temp[0] = 1.f; temp[4] = 0.f; temp[8] = 0.f; temp[12] = 0.f; temp[1] = 0.f; temp[5] = 0.f; temp[9] = -1.f; temp[13] = 0.f; temp[2] = 0.f; temp[6] = 1.f; temp[10] = 0.f; temp[14] = 0.f; temp[3] = 0.f; temp[7] = 0.f; temp[11] = 0.f; temp[15] = 1.f; quatSlerp(mCurQuat, mPreQuat, rotMat, rotMat[4]); mPreQuat[0] = mCurQuat[0]; mPreQuat[1] = mCurQuat[1]; mPreQuat[2] = mCurQuat[2]; mPreQuat[3] = mCurQuat[3]; quatToMat(mRotMat, mCurQuat); Matrix.multiplyMM(mWorld, 0, mRotMat, 0, temp, 0); .............................................. }
相关文章推荐
- Android Studio 插件 —— GsonFormat
- Android设计模式系列(12)--SDK源码之生成器模式(建造者模式)
- Android Fresco 图片框架加载图片解决不能warp_content得问题
- 采用MQTT协议实现Android消息推送
- 用Kotlin写响应式编程RxAndroid
- Android系统Intent中的Uri使用
- Android中糟糕的AsyncTask
- Android设计模式系列(11)--SDK源码之策略模式
- android:layout_weight的真实含义
- Android开发者入门必知了解谷歌官方Android开发文档
- Android 之Hierarchy Tool Window
- 在Android系统外部和内部读取Android应用的签名
- Android设计模式系列(10)--SDK源码之原型模式
- android4.4短信拦截怎么实现,abortBroadcast()不能实现啊
- android GridLayout。。。
- Activity的跳转
- android中MeasureSpec的使用
- Android AutoLayout全新的适配方式 堪称适配终结者
- Android设计模式系列(9)--SDK源码之适配器模式
- Android 编程下获得应用程序的签名