Преглед изворни кода

Added Accelerometer only fallback for devices without gyro/compass/magnet
Added lerp method to omath (using it later)
Implemented by Koen Mertens from Thorworks

Joey Ferwerda пре 10 година
родитељ
комит
edfd332262
3 измењених фајлова са 118 додато и 10 уклоњено
  1. 56 4
      src/drv_android/android.c
  2. 6 6
      src/drv_android/android.h
  3. 56 0
      src/omath.c

+ 56 - 4
src/drv_android/android.c

@@ -19,6 +19,57 @@ static void update_device(ohmd_device* device)
 {
 }
 
+static void nofusion_update(fusion* me, float dt, const vec3f* accel)
+{	
+	//avg raw accel data to smooth jitter, and normalise
+	ofq_add(&me->accel_fq, accel);
+	vec3f accel_mean;
+	ofq_get_mean(&me->accel_fq, &accel_mean);
+	vec3f acc_n = accel_mean;
+	ovec3f_normalize_me(&acc_n);
+	
+	
+	//reference vectors for axis-angle
+	vec3f xyzv[3] = { 
+		{1,0,0},
+		{0,1,0},
+		{0,0,1}
+	};
+	quatf roll, pitch;
+	
+	//pitch is rot around x, based on gravity in z and y axes
+	oquatf_init_axis(&pitch, xyzv+0, atan2f(-acc_n.z, -acc_n.y)); 
+	
+	//roll is rot around z, based on gravity in x and y axes
+	//note we need to invert the values when the device is upside down (y < 0) for proper results
+	oquatf_init_axis(&roll, xyzv+2, acc_n.y < 0 ? atan2f(-acc_n.x, -acc_n.y) : atan2f(acc_n.x, acc_n.y)); 
+	
+			
+	
+	quatf or = {0,0,0,1};
+	//order of applying is yaw-pitch-roll
+	//yaw is not possible using only accel
+	oquatf_mult_me(&or, &pitch); 
+	oquatf_mult_me(&or, &roll);
+
+	me->orient = or;
+}
+
+//shorter buffers for frame smoothing
+void nofusion_init(fusion* me)
+{
+	memset(me, 0, sizeof(fusion));
+	me->orient.w = 1.0f;
+
+	ofq_init(&me->mag_fq, 10);
+	ofq_init(&me->accel_fq, 10);
+	ofq_init(&me->ang_vel_fq, 10);
+
+	me->flags = FF_USE_GRAVITY;
+	me->grav_gain = 0.05f;
+}
+
+
 static int getf(ohmd_device* device, ohmd_float_value type, float* out)
 {
 	android_priv* priv = (android_priv*)device;
@@ -53,7 +104,8 @@ static int setf(ohmd_device* device, ohmd_float_value type, float* in)
 
 	switch(type){
 		case OHMD_EXTERNAL_SENSOR_FUSION: {
-				ofusion_update(&priv->sensor_fusion, *in, (vec3f*)(in + 1), (vec3f*)(in + 4), (vec3f*)(in + 7));
+				//ofusion_update(&priv->sensor_fusion, *in, (vec3f*)(in + 1), (vec3f*)(in + 4), (vec3f*)(in + 7));
+				nofusion_update(&priv->sensor_fusion, *in, (vec3f*)(in + 4));
 			}
 			break;
 
@@ -101,8 +153,8 @@ static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
 	priv->base.close = close_device;
 	priv->base.getf = getf;
 	priv->base.setf = setf;
-
-	ofusion_init(&priv->sensor_fusion);
+	
+	nofusion_init(&priv->sensor_fusion);
 
 	return (ohmd_device*)priv;
 }
@@ -142,7 +194,7 @@ ohmd_driver* ohmd_create_android_drv(ohmd_context* ctx)
 }
 
 /* Android specific functions */
-static void set_android_properties(ohmd_driver* driver, ohmd_device_properties* props)
+static void set_android_properties(ohmd_device* device, ohmd_device_properties* props)
 {
     android_priv* priv = (android_priv*)device;
 

+ 6 - 6
src/drv_android/android.h

@@ -14,13 +14,13 @@
 #include "../openhmdi.h"
 
 typedef enum {
-    DROID_DUROVIS_OPEN_DIVE   = 1;
-    DROID_DUROVIS_DIVE_5      = 2;
-    DROID_DUROVIS_DIVE_7      = 3;
-    DROID_CARL_ZEISS_VRONE    = 4;
-    DROID_GOOGLE_CARDBOARD    = 5;
+    DROID_DUROVIS_OPEN_DIVE   = 1,
+    DROID_DUROVIS_DIVE_5      = 2,
+    DROID_DUROVIS_DIVE_7      = 3,
+    DROID_CARL_ZEISS_VRONE    = 4,
+    DROID_GOOGLE_CARDBOARD    = 5,
 
-    DROID_NONE                = 0;
+    DROID_NONE                = 0,
 } android_hmd_profile;
 
 #endif // ANDROID_H

+ 56 - 0
src/omath.c

@@ -122,6 +122,62 @@ void oquatf_diff(const quatf* me, const quatf* q, quatf* out_q)
 	oquatf_mult(&inv, q, out_q);
 }
 
+void oquatf_slerp (float fT, const quatf* rkP, const quatf* rkQ, bool shortestPath, quatf* out_q)
+{
+	float fCos =  oquatf_get_dot(rkP, rkQ);
+	quatf rkT;
+
+	// Do we need to invert rotation?
+	if (fCos < 0.0f && shortestPath)
+	{
+		fCos = -fCos;
+		rkT = *rkQ;
+		oquatf_inverse(&rkT);
+	}
+	else
+	{
+		rkT = *rkQ;
+	}
+
+	if (fabsf(fCos) < 1 - 0.001f)
+	{
+		// Standard case (slerp)
+		float fSin = sqrtf(1 - (fCos*fCos));
+		float fAngle = atan2f(fSin, fCos); 
+		float fInvSin = 1.0f / fSin;
+		float fCoeff0 = sin((1.0f - fT) * fAngle) * fInvSin;
+		float fCoeff1 = sin(fT * fAngle) * fInvSin;
+		
+		out_q->x = fCoeff0 * rkP->x + fCoeff1 * rkT.x;
+		out_q->y = fCoeff0 * rkP->y + fCoeff1 * rkT.y;
+		out_q->z = fCoeff0 * rkP->z + fCoeff1 * rkT.z;
+		out_q->w = fCoeff0 * rkP->w + fCoeff1 * rkT.w;
+			
+		//return fCoeff0 * rkP + fCoeff1 * rkT;
+	}
+	else
+	{
+		// There are two situations:
+		// 1. "rkP" and "rkQ" are very close (fCos ~= +1), so we can do a linear
+		//    interpolation safely.
+		// 2. "rkP" and "rkQ" are almost inverse of each other (fCos ~= -1), there
+		//    are an infinite number of possibilities interpolation. but we haven't
+		//    have method to fix this case, so just use linear interpolation here.
+		//Quaternion t = (1.0f - fT) * rkP + fT * rkT;
+		
+		out_q->x = (1.0f - fT) * rkP->x + fT * rkT.x;
+		out_q->y = (1.0f - fT) * rkP->y + fT * rkT.y;
+		out_q->z = (1.0f - fT) * rkP->z + fT * rkT.z;
+		out_q->w = (1.0f - fT) * rkP->w + fT * rkT.w;
+			
+		oquatf_normalize_me(out_q);
+		
+		// taking the complement requires renormalisation
+		//t.normalise();
+		//return t;
+	}
+}
+
 void oquatf_get_mat4x4(const quatf* me, const vec3f* point, float mat[4][4])
 {
 	mat[0][0] = 1 - 2 * me->y * me->y - 2 * me->z * me->z;