使用OpenGL自定义iOS界面方向更改动画

时间:2013-02-28 00:31:54

标签: ios animation opengl-es interface-orientation

我有一个iPad应用程序,并使用openGL绘制主视图,我想在旋转设备时动画我自己的更改。

请注意,此应用仅偶尔绘制,而不是经常动画。我的场景也是(非常复杂的)2D绘图,而不是3D。我只是希望它在设备方向改变期间简单地围绕显示中心旋转,保持正确的宽高比。

目前我只有以下代码:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    // nothing yet
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    IMMainView *mv = (IMMainView *)self.view;
    [mv createRenderbuffer];
    [mv drawView];
}

一旦旋转完成,我只需重新创建OpenGL渲染缓冲区以匹配新的宽度和高度。

默认的iOS行为似乎会旋转视图,但随着宽高比的变化,它也会奇怪地延伸。

我可以为我的绘图参数设置动画,以便在过渡期间更好地显示,但我不明白(1)如何停止iOS动画我的图层和(2)如何从这些方法调用设置动画循环匹配iOS动画。

例如,在动画期间,实际视图的宽度和高度是否会逐渐变化?

同样可能的问题是何时重新创建渲染缓冲区,因为如果OpenGL缓冲区与iOS视图边界不匹配,则像素纵横比不正确,图形看起来很糟糕。

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:3)

我花了一些时间寻找合理的方法来正确地执行此操作并最终走上最简单的路线,这只是为了清除willRotateToInterfaceOrientation上的屏幕,然后在didRotateFromInterfaceOrientation中的正确位置呈现新内容{1}}。它只是看起来不那么糟糕,更好的东西的额外复杂性是不值得的恕我直言。

或者,虽然我没有采用这种解决方案,但是我在没有太多工作的情况下获得的最佳动画结果是这样的:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    IMMainView *mv = (IMMainView *)self.view;
    [mv drawBlankScreen];

    m_oldviewsize = self.view.bounds.size;
}

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
    IMMainView *mv = (IMMainView *)self.view;

    CGPoint neworigin = mv.origin;

    neworigin.x += 0.5f*(self.view.bounds.size.width - m_oldviewsize.width);
    neworigin.y += 0.5f*(self.view.bounds.size.height - m_oldviewsize.height);

    mv.origin = neworigin;

    [mv createRenderbuffer];
    [mv drawView];
}

原点的更改旨在将旋转后的绘图重新定位在旋转前的相同位置。

我发现在计算新视图边界后调用willAnimateToInterfaceOrientation一次。因此,我在那时设置了新的渲染缓冲区,因为与方面变化相关的失真并不像我原来那样明显。我还必须清除willRotateToInterfaceOrientation中的屏幕,因为有一段延迟,在此期间原始绘图的扭曲版本清晰可见。

这方面的缺点是屏幕的清除会在动画开始时引起轻微的闪光,并且拉伸失真仍然存在,但是会聚焦在正确的外观上,而不是偏离旧的外观,然后是跳到新的外观,所以它看起来不那么糟糕。我怀疑任何尝试实际跟踪视图的动画宽高比变化,并使用我的绘图功能进行更新以持续保持正确的外观将会非常复杂,并且很可能在将来很容易受到Apple改变。

答案 1 :(得分:0)

您可以按如下方式在顶点着色器中旋转OpenGL输出:

#version 300 es


in vec4 position;
in mediump vec4 texturecoordinate;

in vec4 color;

uniform float preferredRotation;

out mediump vec2 coordinate;

void main()
{
    //const float pi = 4.0 * atan(1.0);
    //float radians  = (( -90.0 ) / 180.0 * pi );

    // Preferred rotation of video acquired, for example, by:
    // AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
    // CGAffineTransform preferredTransform = [videoTrack preferredTransform];
    // self.glKitView.preferredRotation = -1 * atan2(preferredTransform.b, preferredTransform.a);

    // Preferred rotation for both portrait and landscape           
    mat4 rotationMatrix = mat4( cos(preferredRotation), -sin(preferredRotation), 0.0, 0.0,
                                sin(preferredRotation),  cos(preferredRotation), 0.0, 0.0,
                                0.0,                     0.0,                    1.0, 0.0,
                                0.0,                     0.0,                    0.0, 1.0);

    // Mirror vertical (portrait only)
    mat4 rotationMatrix = mat4( cos(preferredRotation),  sin(preferredRotation), 0.0, 0.0,
                               -sin(preferredRotation),  cos(preferredRotation), 0.0, 0.0,
                                0.0,           0.0,          1.0, 0.0,
                                0.0,           0.0,          0.0, 1.0);

    // Mirror horizontal (landscape only)
    mat4 rotationMatrix = mat4( 1.0, 0.0,                     0.0,                    0.0,
                                0.0, cos(preferredRotation), -sin(preferredRotation), 0.0,
                                0.0, sin(preferredRotation),  cos(preferredRotation), 0.0,
                                0.0, 0.0,                     0.0,                    1.0);

    // Mirror vertical (landscape only)
    mat4 rotationMatrix = mat4( cos(preferredRotation), 0.0, sin(preferredRotation), 0.0,
                                0.0,                    1.0, 0.0,                    0.0,
                               -sin(preferredRotation), 0.0, cos(preferredRotation), 0.0,
                                0.0,                    0.0, 0.0,                    1.0);

    gl_Position = position * rotationMatrix;
    coordinate = texturecoordinate.xy;
}

使用每个vSync,您可以为preferredRotation传递一个新值,该值将在不拉伸的情况下旋转视图。

显然,您只选择一个矩阵4,具体取决于视频的方向,然后是旋转。每个矩阵4翻转视频窗口 - 不旋转它。对于旋转,您必须首先根据方向选择matrix4,然后将preferredRotation变量替换为度数(以弧度表示,也提供其公式)。

有很多方法可以旋转视图,图层,对象等;但是,如果你是通过OpenGL渲染图像,那么你应该选择这种方法,而只选择这种方法。