【问题标题】:Custom iOS interface orientation change animation with OpenGL使用 OpenGL 自定义 iOS 界面方向更改动画
【发布时间】:2013-02-28 00:31:54
【问题描述】:

我有一个 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 视图边界不匹配,则像素纵横比不正确,并且绘图看起来很糟糕。

任何帮助将不胜感激。

【问题讨论】:

  • 好的我想我理解了我的问题的部分答案,即我需要在方向更改期间继续呈现渲染缓冲区以覆盖默认情况下显示的内容。目前我只在需要根据 UI 更改更改视图内容时显示它。

标签: ios animation opengl-es interface-orientation


【解决方案1】:

我花了一些时间寻找正确执行此操作的合理方法,最终选择了最简单的方法,即清除 willRotateToInterfaceOrientation 上的屏幕,然后在 didRotateFromInterfaceOrientation 的正确位置呈现新内容.它只是看起来还不错,恕我直言,为了更好的东西而增加额外的复杂性是不值得的。

另外,虽然我没有采用这种解决方案,但我在不费力的情况下获得的最佳动画效果是这样的:

- (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 更改的影响。

【讨论】:

    【解决方案2】:

    您可以按如下方式在顶点着色器中旋转 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,这取决于视频的方向,然后是它的旋转。每个 matrix4 都会翻转视频窗口——而不是旋转它。对于旋转,您必须首先根据方向选择 matrix4,然后将 preferredRotation 变量替换为度数(以弧度为单位,还提供了公式)。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-31
      相关资源
      最近更新 更多