Quaternion translation and rotation in iOS OpenGL ES

I'm struggling with some quaternion code in iOS. I have an open cube, which i've rotated into an isometric view. i am able to rotate the cube with touch and rotate about its axis and also zoom in/out. I also have labels associated with the cube - which also need to rotate with the cube. Again, i've managed to do this.

However, i'm now trying to implement being able to drag the label (ie. translate it) from one position, to another. If we look at the image below, what i've tried to illustrate is that i want to be able to translate the label from "label from" to the position "label to". Then, when i come to rotating the cube, the label should stay in its new position and rotate with the cube. However, i'm making a cock-up of this translation and when i try rotating the cube, the label jumps to a new position since i've not set the label coordinates properly.

开放式立方体

I have the quaternion associated with the cube.

With the following code, i have been able to translate the label properly when the quaternion is set to [0, 0, 0, 1] (so that the cube is front-on - looks like a square from this position).

- (void) rotateWithAngle:(float) radians andVector:(GLKVector3) axis andScale:(float) scale
{
    if (radians != self.lastRadians
        || (axis.v[0] != self.lastAxis.v[0] || axis.v[1] != self.lastAxis.v[1] || axis.v[2] != self.lastAxis.v[2])
        || scale != self.lastScale)
    {
        GLKMatrix4 m = GLKMatrix4MakeTranslation(self.normX, self.normY, self.normZ);

        if (radians != 0)
            m = GLKMatrix4Rotate(m, radians, axis.x, -axis.y, axis.z);

        m = GLKMatrix4Scale(m, scale, scale, scale);

        float x = (m.m00 * m.m30) + (m.m01 * m.m31) + (m.m02 * m.m32) + (m.m03 * m.m33);
        float y = (m.m10 * m.m30) + (m.m11 * m.m31) + (m.m12 * m.m32) + (m.m13 * m.m33);
        float z = (m.m20 * m.m30) + (m.m21 * m.m31) + (m.m22 * m.m32) + (m.m23 * m.m33);

        x /= m.m33;
        y /= m.m33;
        z /= m.m33;

        float w = (((x+self.winSz) / (self.winSz * 2.0)) * self.parentFrame.size.width) + self.parentFrame.origin.x;
        float h = (((y+self.winSz) / (self.winSz * 2.0)) * self.parentFrame.size.height) + self.parentFrame.origin.y;

        self.lastRadians = radians;
        self.lastAxis = axis;
        self.lastScale = scale;

        [self setCenter:CGPointMake(w,h)];
    }
}

- (void) translateFromTouch:(UIPanGestureRecognizer *) pan
{
    CGPoint translation = [pan translationInView:self];
    CGPoint imageViewPosition = self.center;

    GLKVector3 axis = GLKQuaternionAxis(*_quaternion);
    float rot = GLKQuaternionAngle(*_quaternion);

    CGFloat h = self.parentFrame.size.height;
    CGFloat w = self.parentFrame.size.width;

    imageViewPosition.x += translation.x;
    imageViewPosition.y += translation.y;

    self.center = imageViewPosition;

    // recalculate the norm position
    float x = ((2.0 * self.winSz * (imageViewPosition.x - self.parentFrame.origin.x)) / w) - self.winSz;
    float y = ((2.0 * self.winSz * (imageViewPosition.y - self.parentFrame.origin.y)) / h) - self.winSz;

    self.normX = x;
    self.normY = y;

    [pan setTranslation:CGPointZero inView:self];
}

These methods are hit if a label (based on a UILabel) is either dragged or the cube (or the opengl scene) is rotated.

This works when we are looking front-on, so that the x,y values can easily be converted from pixel coords into normal or world coords. However, when the axis is not front-on, i'm struggling to figure it out. For instance, we we have the quaternion set at (0, sqrt(2)/2, 0, sqrt(2)/2) then all x translations correspond to z world coords. So how do i make this connection/calculation? I'm sure it's fairly easy but i've hit a wall with this.

(winSz i have set to 1.5. model coords very between -1 and 1)

链接地址: http://www.djcxy.com/p/14352.html

上一篇: opengl围绕固定轴旋转对象

下一篇: 四元数在iOS OpenGL ES中的翻译和旋转