iOS:将视图转换为圆柱形

时间:2014-02-21 15:33:33

标签: ios opengl-es core-graphics cgaffinetransform

使用Quartz 2D,我们可以在xyz轴上转换视图。

在某些情况下,我们甚至可以通过更改矩阵的值来使它们看起来像3D。

我想知道是否可以将视图转换为圆柱形状,如下图所示?

enter image description here

请忽略气缸的顶部。我更好奇地知道是否有可能像图像中那样扭曲UIView像圆柱体一样。

这可能只使用Quartz 2D,图层和转换(不是OpenGL)吗?如果没有,是否有可能至少在CGContext中绘制它以使视图看起来像这样?

4 个答案:

答案 0 :(得分:4)

你绝对不能通过变换做到这一点。您可以做的是在屏幕外创建UIView,获取视图的上下文,从中获取图像,然后使用非线性映射将图像映射到新图像。

所以:

  1. 使用UIGraphicsBeginImageContext()
  2. 创建图像上下文
  3. 使用view.layer.renderInContext()
  4. 在那里渲染视图
  5. 使用CGBitmapContextCreateImage()
  6. 获取结果的图像
  7. 编写一个映射函数,该函数采用x / y屏幕坐标并将它们映射到圆柱体上的坐标。
  8. 创建一个与屏幕视图大小相同的新图像,并调用映射 用于将像素从源复制到目标。
  9. 将目标位图绘制到屏幕上。
  10. 这些步骤都不是特别困难,您可能会想出各种简化方法。例如,如果没有进行透视变换,只需渲染原始视图的条带,根据圆的坐标偏移Y坐标。

    如果您希望视图实际上是交互式的,那么在处理触摸事件时您需要以相反的方向进行转换。

答案 1 :(得分:3)

不,您无法使用转换弯曲视图。

变换只能操纵视图的四个角,所以无论你做什么,它仍然是一个平面。

答案 2 :(得分:2)

我意识到这超出了Quartz2D ...您可以尝试添加SceneKit。

  • 通过UIGraphicsBeginImageContext(),view.layer.renderInContext(),CGBitmapContextCreateImage()获取视图的图像。
  • 创建一个SCNMaterial,其diffuse属性设置为您的视图图像
  • 创建一个SCNCylinder并将材料应用于它。
  • 将圆柱体添加到SCNScene。
  • 创建一个SCNView并设置其场景。
  • 将SCNView添加到视图层次结构中。

答案 3 :(得分:1)

参考:Using OpenGL ES 2.0 with iOS, how do I draw a cylinder between two points?

我也为我的一个项目使用了相同的代码:

检查提到它的地方以绘制cone shape;它已经过时了但是在适应算法后,它可以工作。

请参阅以下代码以获取解决方案。 Self表示网格,包含顶点,索引等。

- (instancetype)initWithOriginRadius:(CGFloat)originRadius
                   atOriginPoint:(GLKVector3)originPoint
                    andEndRadius:(CGFloat)endRadius
                      atEndPoint:(GLKVector3)endPoint
                   withPrecision:(NSInteger)precision
                        andColor:(GLKVector4)color
{
self = [super init];

if (self) {
    // normal pointing from origin point to end point
    GLKVector3 normal = GLKVector3Make(originPoint.x - endPoint.x,
                                       originPoint.y - endPoint.y,
                                       originPoint.z - endPoint.z);

    // create two perpendicular vectors - perp and q
    GLKVector3 perp = normal;
    if (normal.x == 0 && normal.z == 0) {
        perp.x += 1;
    } else {
        perp.y += 1;
    }

    // cross product
    GLKVector3 q = GLKVector3CrossProduct(perp, normal);
    perp = GLKVector3CrossProduct(normal, q);

    // normalize vectors
    perp = GLKVector3Normalize(perp);
    q = GLKVector3Normalize(q);

    // calculate vertices
    CGFloat twoPi = 2 * PI;        
    NSInteger index = 0;
    for (NSInteger i = 0; i < precision + 1; i++) {
        CGFloat theta = ((CGFloat) i) / precision * twoPi; // go around circle and get points

        // normals
        normal.x = cosf(theta) * perp.x + sinf(theta) * q.x;
        normal.y = cosf(theta) * perp.y + sinf(theta) * q.y;
        normal.z = cosf(theta) * perp.z + sinf(theta) * q.z;

        AGLKMeshVertex meshVertex;
        AGLKMeshVertexDynamic colorVertex;

        // top vertex
        meshVertex.position.x = endPoint.x + endRadius * normal.x;
        meshVertex.position.y = endPoint.y + endRadius * normal.y;
        meshVertex.position.z = endPoint.z + endRadius * normal.z;
        meshVertex.normal = normal;
        meshVertex.originalColor = color;

        // append vertex
        [self appendVertex:meshVertex];

        // append color vertex
        colorVertex.colors = color;
        [self appendColorVertex:colorVertex];

        // append index
        [self appendIndex:index++];

        // bottom vertex
        meshVertex.position.x = originPoint.x + originRadius * normal.x;
        meshVertex.position.y = originPoint.y + originRadius * normal.y;
        meshVertex.position.z = originPoint.z + originRadius * normal.z;
        meshVertex.normal = normal;
        meshVertex.originalColor = color;

        // append vertex
        [self appendVertex:meshVertex];

        // append color vertex
        [self appendColorVertex:colorVertex];

        // append index
        [self appendIndex:index++];
    }

    // draw command
    [self appendCommand:GL_TRIANGLE_STRIP firstIndex:0 numberOfIndices:self.numberOfIndices materialName:@""];
}

return self;
}