Skip to content

Commit 284910b

Browse files
android vr: better performance
1 parent aa8328e commit 284910b

File tree

4 files changed

+131
-66
lines changed

4 files changed

+131
-66
lines changed

cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxAccelerometer.java

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ public class Cocos2dxAccelerometer implements SensorEventListener {
5050
private final Sensor mCompass;
5151
private final int mNaturalOrientation;
5252
final float[] accelerometerValues = new float[3];
53-
final float[] magneticFieldValues = new float[3];
54-
final float[] rotationMatrix = new float[16];
53+
final float[] compassFieldValues = new float[3];
5554
static final float ALPHA = 0.25f; // if ALPHA = 1 OR 0, no filter applies.
5655

5756
// ===========================================================
@@ -73,12 +72,11 @@ public Cocos2dxAccelerometer(final Context context) {
7372
// Getter & Setter
7473
// ===========================================================
7574

76-
public void enableAll() {
77-
this.mSensorManager.registerListener(this, this.mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
75+
public void enableCompass() {
7876
this.mSensorManager.registerListener(this, this.mCompass, SensorManager.SENSOR_DELAY_GAME);
7977
}
8078

81-
public void enable() {
79+
public void enableAccel() {
8280
this.mSensorManager.registerListener(this, this.mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
8381
}
8482

@@ -99,26 +97,19 @@ public void disable() {
9997
// ===========================================================
10098
// Methods for/from SuperClass/Interfaces
10199
// ===========================================================
102-
103-
protected float[] lowPass( float[] input, float[] output ) {
104-
if ( output == null ) return input;
105-
106-
for ( int i=0; i<input.length; i++ ) {
107-
output[i] = output[i] + ALPHA * (input[i] - output[i]);
108-
}
109-
return output;
110-
}
111-
112100
@Override
113101
public void onSensorChanged(final SensorEvent sensorEvent) {
114102
if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
115103

116-
lowPass(sensorEvent.values, this.accelerometerValues);
117-
118104
float x = sensorEvent.values[0];
119105
float y = sensorEvent.values[1];
120106
final float z = sensorEvent.values[2];
121107

108+
// needed by VR code
109+
this.accelerometerValues[0] = x;
110+
this.accelerometerValues[1] = y;
111+
this.accelerometerValues[2] = z;
112+
122113
/*
123114
* Because the axes are not swapped when the device's screen orientation
124115
* changes. So we should swap it here. In tablets such as Motorola Xoom,
@@ -134,19 +125,22 @@ public void onSensorChanged(final SensorEvent sensorEvent) {
134125
final float tmp = x;
135126
x = y;
136127
y = -tmp;
137-
}
138-
128+
}
129+
130+
139131
Cocos2dxGLSurfaceView.queueAccelerometer(x,y,z,sensorEvent.timestamp);
140132

141-
142133
/*
143134
if(BuildConfig.DEBUG) {
144135
Log.d(TAG, "x = " + sensorEvent.values[0] + " y = " + sensorEvent.values[1] + " z = " + pSensorEvent.values[2]);
145136
}
146137
*/
147138
}
148139
else if (sensorEvent.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
149-
lowPass(sensorEvent.values, this.magneticFieldValues);
140+
// needed by VR code
141+
this.compassFieldValues[0] = sensorEvent.values[0];
142+
this.compassFieldValues[1] = sensorEvent.values[1];
143+
this.compassFieldValues[2] = sensorEvent.values[2];
150144
}
151145
}
152146

@@ -158,7 +152,7 @@ public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
158152
// Methods
159153
// Native method called from Cocos2dxGLSurfaceView (To be in the same thread)
160154
// ===========================================================
161-
155+
162156
public static native void onSensorChanged(final float x, final float y, final float z, final long timestamp);
163157

164158
// ===========================================================

cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxHelper.java

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public class Cocos2dxHelper {
6868
private static AssetManager sAssetManager;
6969
private static Cocos2dxAccelerometer sCocos2dxAccelerometer;
7070
private static boolean sAccelerometerEnabled;
71+
private static boolean sCompassEnabled;
7172
private static boolean sActivityVisible;
7273
private static String sPackageName;
7374
private static String sFileDirectory;
@@ -188,12 +189,12 @@ public static AssetManager getAssetManager() {
188189

189190
public static void enableAccelerometer() {
190191
Cocos2dxHelper.sAccelerometerEnabled = true;
191-
Cocos2dxHelper.sCocos2dxAccelerometer.enable();
192+
Cocos2dxHelper.sCocos2dxAccelerometer.enableAccel();
192193
}
193194

194-
public static void enableAccelAndCompass() {
195-
Cocos2dxHelper.sAccelerometerEnabled = true;
196-
Cocos2dxHelper.sCocos2dxAccelerometer.enableAll();
195+
public static void enableCompass() {
196+
Cocos2dxHelper.sCompassEnabled = true;
197+
Cocos2dxHelper.sCocos2dxAccelerometer.enableCompass();
197198
}
198199

199200
public static void setAccelerometerInterval(float interval) {
@@ -322,7 +323,10 @@ public static void end() {
322323
public static void onResume() {
323324
sActivityVisible = true;
324325
if (Cocos2dxHelper.sAccelerometerEnabled) {
325-
Cocos2dxHelper.sCocos2dxAccelerometer.enable();
326+
Cocos2dxHelper.sCocos2dxAccelerometer.enableAccel();
327+
}
328+
if (Cocos2dxHelper.sCompassEnabled) {
329+
Cocos2dxHelper.sCocos2dxAccelerometer.enableCompass();
326330
}
327331
}
328332

@@ -617,23 +621,13 @@ public static int setLowPowerMode(boolean enable) {
617621
return -1;
618622
}
619623
}
624+
620625
//Enhance API modification end
621-
public static float[] getSensorRotationMatrix() {
622-
if (!SensorManager.getRotationMatrix(
623-
Cocos2dxHelper.sCocos2dxAccelerometer.rotationMatrix,
624-
null,
625-
Cocos2dxHelper.sCocos2dxAccelerometer.accelerometerValues,
626-
Cocos2dxHelper.sCocos2dxAccelerometer.magneticFieldValues))
627-
{
628-
for (int i=0; i<16; i++) {
629-
Cocos2dxHelper.sCocos2dxAccelerometer.rotationMatrix[i] = 0;
630-
}
631-
// identity matrix if error
632-
Cocos2dxHelper.sCocos2dxAccelerometer.rotationMatrix[0] =
633-
Cocos2dxHelper.sCocos2dxAccelerometer.rotationMatrix[5] =
634-
Cocos2dxHelper.sCocos2dxAccelerometer.rotationMatrix[10] =
635-
Cocos2dxHelper.sCocos2dxAccelerometer.rotationMatrix[15] = 1;
636-
}
637-
return Cocos2dxHelper.sCocos2dxAccelerometer.rotationMatrix;
626+
public static float[] getAccelValue() {
627+
return Cocos2dxHelper.sCocos2dxAccelerometer.accelerometerValues;
628+
}
629+
630+
public static float[] getCompassValue() {
631+
return Cocos2dxHelper.sCocos2dxAccelerometer.compassFieldValues;
638632
}
639633
}

cocos/platform/android/jni/JniHelper.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ THE SOFTWARE.
3131
#include <unordered_map>
3232
#include <functional>
3333
#include "platform/CCPlatformMacros.h"
34+
#include "math/Vec3.h"
3435

3536
NS_CC_BEGIN
3637

@@ -157,6 +158,31 @@ class CC_DLL JniHelper
157158
return nullptr;
158159
}
159160

161+
template <typename... Ts>
162+
static Vec3 callStaticVec3Method(const std::string& className,
163+
const std::string& methodName,
164+
Ts... xs) {
165+
Vec3 ret;
166+
cocos2d::JniMethodInfo t;
167+
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")[F";
168+
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
169+
jfloatArray array = (jfloatArray) t.env->CallStaticObjectMethod(t.classID, t.methodID, convert(t, xs)...);
170+
jsize len = t.env->GetArrayLength(array);
171+
if (len == 3) {
172+
jfloat* elems = t.env->GetFloatArrayElements(array, 0);
173+
ret.x = elems[0];
174+
ret.y = elems[1];
175+
ret.z = elems[2];
176+
t.env->ReleaseFloatArrayElements(array, elems, 0);
177+
}
178+
t.env->DeleteLocalRef(t.classID);
179+
deleteLocalRefs(t.env);
180+
} else {
181+
reportError(className, methodName, signature);
182+
}
183+
return ret;
184+
}
185+
160186
template <typename... Ts>
161187
static double callStaticDoubleMethod(const std::string& className,
162188
const std::string& methodName,

cocos/vr/CCVRGenericHeadTracker.cpp

Lines changed: 73 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,65 @@ static Mat4 matrixFromRotationMatrix(const CMRotationMatrix& rotationMatrix)
6565
0.0f,
6666
1.0f);
6767
}
68-
#endif // (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
68+
69+
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
70+
71+
// getRotationMatrix taken from Android's SensorManager.java
72+
Mat4 getRotationMatrix(const Vec3& gravity, const Vec3& geomagnetic)
73+
{
74+
float Ax = gravity.x;
75+
float Ay = gravity.y;
76+
float Az = gravity.z;
77+
78+
const float normsqA = (Ax*Ax + Ay*Ay + Az*Az);
79+
const float g = 9.81f;
80+
const float freeFallGravitySquared = 0.01f * g * g;
81+
if (normsqA < freeFallGravitySquared) {
82+
// gravity less than 10% of normal value
83+
return Mat4::IDENTITY;
84+
}
85+
86+
const float Ex = geomagnetic.x;
87+
const float Ey = geomagnetic.y;
88+
const float Ez = geomagnetic.z;
89+
float Hx = Ey*Az - Ez*Ay;
90+
float Hy = Ez*Ax - Ex*Az;
91+
float Hz = Ex*Ay - Ey*Ax;
92+
const float normH = std::sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
93+
94+
if (normH < 0.1f) {
95+
// device is close to free fall (or in space?), or close to
96+
// magnetic north pole. Typical values are > 100.
97+
return Mat4::IDENTITY;
98+
}
99+
const float invH = 1.0f / normH;
100+
Hx *= invH;
101+
Hy *= invH;
102+
Hz *= invH;
103+
const float invA = 1.0f / std::sqrt(Ax*Ax + Ay*Ay + Az*Az);
104+
Ax *= invA;
105+
Ay *= invA;
106+
Az *= invA;
107+
const float Mx = Ay*Hz - Az*Hy;
108+
const float My = Az*Hx - Ax*Hz;
109+
const float Mz = Ax*Hy - Ay*Hx;
110+
111+
return Mat4( Hx, Mx, Ax, 0,
112+
Hy, My, Ay, 0,
113+
Hz, Mz, Az, 0,
114+
0, 0, 0, 1);
115+
}
116+
117+
Vec3 lowPass(const Vec3& input, const Vec3& prev)
118+
{
119+
// if ALPHA = 1 OR 0, no filter applies.
120+
static const float ALPHA = 0.12f;
121+
return Vec3(prev.x + ALPHA * (input.x - prev.x),
122+
prev.y + ALPHA * (input.y - prev.y),
123+
prev.z + ALPHA * (input.z - prev.z));
124+
}
125+
126+
#endif // (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
69127

70128
static Mat4 getRotateEulerMatrix(float x, float y, float z)
71129
{
@@ -147,7 +205,8 @@ void VRGenericHeadTracker::startTracking()
147205
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
148206
_deviceToDisplay = getRotateEulerMatrix(0.f, 0.f, -90.f);
149207
_worldToInertialReferenceFrame = getRotateEulerMatrix(-90.f, 0.f, 90.f);
150-
JniHelper::callStaticVoidMethod("org/cocos2dx/lib/Cocos2dxHelper", "enableAccelAndCompass");
208+
JniHelper::callStaticVoidMethod("org/cocos2dx/lib/Cocos2dxHelper", "enableAccelerometer");
209+
JniHelper::callStaticVoidMethod("org/cocos2dx/lib/Cocos2dxHelper", "enableCompass");
151210
#endif
152211
}
153212

@@ -178,26 +237,18 @@ Mat4 VRGenericHeadTracker::getLocalRotation()
178237
return _deviceToDisplay * worldToDevice;
179238

180239
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
181-
auto rotMatrix = JniHelper::callStaticFloatArrayMethod("org/cocos2dx/lib/Cocos2dxHelper", "getSensorRotationMatrix");
182-
//
183-
// char buf[512];
184-
// snprintf(buf, sizeof(buf)-1, "%f %f %f %f - %f %f %f %f - %f %f %f %f - %f %f %f %f", rotMatrix[0]
185-
// , rotMatrix[1]
186-
// , rotMatrix[2]
187-
// , rotMatrix[3]
188-
// , rotMatrix[4]
189-
// , rotMatrix[5]
190-
// , rotMatrix[6]
191-
// , rotMatrix[7]
192-
// , rotMatrix[8]
193-
// , rotMatrix[9]
194-
// , rotMatrix[10]
195-
// , rotMatrix[11]
196-
// , rotMatrix[12]
197-
// , rotMatrix[13]
198-
// , rotMatrix[14]
199-
// , rotMatrix[15]);
200-
// log("cocos matrix: %s", buf);
240+
static Vec3 prevAccel = Vec3(0,0,0);
241+
static Vec3 prevCompass = Vec3(0,0,0);
242+
243+
Vec3 accel = JniHelper::callStaticVec3Method("org/cocos2dx/lib/Cocos2dxHelper", "getAccelValue");
244+
Vec3 compass = JniHelper::callStaticVec3Method("org/cocos2dx/lib/Cocos2dxHelper", "getCompassValue");
245+
246+
// CCLOG("accel: %f, %f, %f.... compass: %f, %f, %f", accel.x, accel.y, accel.z, compass.x, compass.y, compass.z);
247+
prevAccel = lowPass(accel, prevAccel);
248+
prevCompass = lowPass(compass, prevCompass);
249+
// CCLOG("low pass accel: %f, %f, %f.... compass: %f, %f, %f", prevAccel.x, prevAccel.y, prevAccel.z, prevCompass.x, prevCompass.y, prevCompass.z);
250+
251+
Mat4 rotMatrix = getRotationMatrix(prevAccel, prevCompass);
201252

202253
Mat4 inertialReferenceFrameToDevice(rotMatrix);
203254
Mat4 worldToDevice = inertialReferenceFrameToDevice * _worldToInertialReferenceFrame;

0 commit comments

Comments
 (0)