6

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

任何帮助,将不胜感激。

4

2 回答 2

3

我花了一些时间寻找正确执行此操作的合理方法,最终选择了最简单的方法,即清除屏幕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 未来更改的影响。

于 2013-02-28T21:52:53.677 回答
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,这取决于视频的方向,然后是它的旋转。每个 matrix4 都会翻转视频窗口——而不是旋转它。对于旋转,您必须首先根据方向选择 matrix4,然后将 preferredRotation 变量替换为度数(以弧度为单位,还提供了公式)。

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

于 2016-03-30T17:11:50.137 回答