unity自动校准
关于unity中校准的问题,在论坛里查过很多资料.最后好友推荐了一篇老外写的博客.关于校准给了一个很好的实现.
问题是老外用objective-c写的.后来自己翻译成unity中的c#脚本与自己的一点改进.很好的实现了unity平台的校准功能.
具体博文地址如下:http://www.paradeofrain.com/2010/07/lessons-learned-in-tilt-controls/
我对该博文做了一下翻译,自己翻译能力有限,刚过六级,大家觉得有翻得不好的地方,欢迎提出来.我改进.
翻译链接http://www.cnblogs.com/xckk/archive/2012/09/02/2667838.html
老外的具体实现如下
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { /* while not ideal, most of the relevant code is stuffed in this method for clarity. A lot can be computed once and saved in instance variables, preferences, etc instead of re-calculating each frame */ // hard coding our 'neutral' orientation. By default this is the orientation of // having the device tilted slightly towards your face. // if you wanted strictly a 'top down' orientation then a (0,0,-1) vector would be put here. // to create a new 'neutral' position you can sample the UIAcceleration parameter for a single // frame and set that to be the new nx,ny,nz for the remainder of the app (aka calibrating). const float nx = -0.63f; const float ny = 0; const float nz = -0.92f; // this quaternion represents an orientation (I like to think of it as a 3D vector with 0 rotation in this case) // that points straight out from the device's back away from the user's face. Quaternion neutral(0,nx, ny, nz); // take a straight up vector and rotate it by our 'neutral' orientation // to give us a vector that points straight out from the device's screen (at the user's face) Quaternion neutralPosition = neutral * Quaternion(0,0,0,1); /* now with our 'neutral' quaternion setup we: 1. take the incoming accelerometer data 2. convert it to a 2D velocity projected onto the plane of the device's screen 3. and rotate it by 90 degrees (since we are landscape oriented) and feed it to our player's velocity directly. */ // convert our accel data to a Quaternion Quaternion accelQuat(0, acceleration.x, acceleration.y, acceleration.z); // now rotate our accel data BY the neutral orientation. effectively transforming it // into our local space. Vec3 accelVector = (accelQuat * neutralPosition).v; // we only want the 3D vector at this point // now with our accel vector we wish to transform it into our standard (1,1,1) coordinate space Vec3 planeXAxis(1,0,0); Vec3 planeYAxis(0,1,0); Vec3 normal(0,0,1); // the normal of the plane we wish to transform our data into. //project this movement onto our X/Y plane by removing // the accel part that is along our normal // note: Vec3 * Vec3 = dot product of the 2 vectors. Vec3 projection = accelVector - normal *(accelVector * normal); // now decompose that projection along our X and Y axis that represents our 2D plane Vec2 accel2D(0,0); accel2D.x = planeXAxis * projection; accel2D.y = planeYAxis * projection; const float xSensitivity = 2.8f; const float ySensitivity = 2.8f; // yay magic numbers! const float tiltAmplifier = 8; // w0ot more magic numbers // now apply it to our player's velocity data. // we also rotate the 2D vector by 90 degrees by switching the components and negating one // since we are in a landscape orientation. vx += (-accel2D.y) * tiltAmplifier * xSensitivity; vy -= accel2D.x * tiltAmplifier * ySensitivity; // we do a (-) here because the accel y axis is inverted. }
这是老外写的原始方法,该方法后面有改进.但是我认为这个方法比较容易理解.
后面是改进的方法,代码更少了,但是理解起来有点困难
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { // A much more concise version courtesy of Mikko Mononen http://digestingduck.blogspot.com/ Vec2 accel2D(0,0); Vec3 ax(1, 0, 0); Vec3 ay(-.63f, 0,-.92f); Vec3 az(Vec3::Cross(ay,ax).normalize()); ax = Vec3::Cross(az,ay).normalize(); accel2D.x = -Vec3::Dot(Vec3(acceleration.x, acceleration.y, acceleration.z), ax); accel2D.y = -Vec3::Dot(Vec3(acceleration.x, acceleration.y, acceleration.z), az); const float xSensitivity = 2.8f; const float ySensitivity = 2.8f; // yay magic numbers! const float tiltAmplifier = 8; // w0ot more magic numbers // since we are in a landscape orientation. // now apply it to our player's velocity data. // we also rotate the 2D vector by 90 degrees by switching the components and negating one vx += -(accel2D.y) * tiltAmplifier * xSensitivity; vy += accel2D.x * tiltAmplifier * ySensitivity; }
我将两种方法分别翻译成了unity的C#脚本.这里先只贴出第二种方法的,第一种方法的暂时不知道到哪去了.
public static Vector3 getAccelerator2() { Vector3 accelerator = Input.acceleration; Vector3 accel2D = Vector3.zero; Vector3 ax = new Vector3(1, 0, 0); Vector3 ay = neutralVector3; Vector3 az = Vector3.Cross(ay, ax).normalized; ax = Vector3.Cross(az, ay).normalized; accel2D.x = -Vector3.Dot(accelerator, ax); accel2D.y = -Vector3.Dot(accelerator, az); float t = accel2D.x; accel2D.x = -accel2D.y; accel2D.y = t; accel2D.y = -accel2D.y; if(!isRightDirection) { accel2D.y = -accel2D.y; accel2D.x = -accel2D.x; } return accel2D; }
方法中neutralVector3就是你校准平衡位置的加速度值,即Input.acceleration.校准方法如下:
每次需要校准时,调用下面方法即可:
注意,当iphone4设备向上抬超过90度时,加速度计的值会反转.因此做了一下判断
本文做的是landscape left方向.其它的方向可以依此类推
public static void setNeutralVector() { neutralVector3 = Input.acceleration; if(neutralVector3.z < 0) { isRightDirection = true; }else { isRightDirection = false; } }
希望对校准一直没有好的解决方案的同学有所帮助.欢迎大家提问题,一起学习.
秀才坤坤出品