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;
        }
    }

 希望对校准一直没有好的解决方案的同学有所帮助.欢迎大家提问题,一起学习.

秀才坤坤出品

posted @ 2012-09-02 19:45  秀才坤坤  阅读(766)  评论(2编辑  收藏  举报