简体   繁体   English

在iOS上使用OpenGL ES 2.0,如何在两点之间绘制圆柱?

[英]Using OpenGL ES 2.0 with iOS, how do I draw a cylinder between two points?

I am given two GLKVector3 's representing the start and end points of the cylinder. 我得到了两个GLKVector3 ,分别代表圆柱体的起点和终点。 Using these points and the radius, I need to build and render a cylinder. 使用这些点和半径,我需要构建和渲染圆柱体。 I can build a cylinder with the correct distance between the points but in a fixed direction (currently always in the y (0, 1, 0) up direction). 我可以建立一个在点之间具有正确距离但沿固定方向的圆柱体(当前始终沿y(0,1,0)向上方向)。 I am not sure what kind of calculations I need to make to get the cylinder on the correct plane between the two points so that a line would run through the two end points. 我不确定我需要进行哪种计算才能将圆柱体放置在两点之间的正确平面上,以便一条直线穿过两个端点。 I am thinking there is some sort of calculations I can apply as I create my vertex data with the direction vector, or angle, that will create the cylinder pointing the correct direction. 我在考虑使用方向矢量或角度创建顶点数据时可以应用某种计算,这些计算将创建指向正确方向的圆柱。 Does anyone have an algorithm, or know of one, that will help? 有没有人有一种算法,或者知道一种算法会有所帮助?

Check this awesome article ; 查看这篇很棒的文章 ; it's dated but after adapting the algorithm, it works like a charm. 它已经过时,但是在修改算法后,它就像一个魅力。 One tip, OpenGL ES 2.0 only supports triangles so instead of using GL_QUAD_STRIP as the method does, use GL_TRIANGLE_STRIP instead and the result is identical. 提示OpenGL ES 2.0仅支持三角形,因此不像方法那样使用GL_QUAD_STRIP,而是使用GL_TRIANGLE_STRIP,结果是相同的。 The site also contains a bunch of other useful information regarding OpenGL geometries. 站点还包含有关OpenGL几何形状的许多其他有用信息。

See code below for solution. 请参阅下面的代码以获取解决方案。 Self represents the mesh and contains the vertices, indices, and such. 自体表示网格,并包含顶点,索引等。

- (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;
}

Are you drawing more than one of these cylinders? 您要绘制多个这些圆柱体吗? Or ever drawing it in a different position? 还是曾经将其绘制在其他位置? If so, using the algorithm from the awesome article is a not-so-awesome idea. 如果是这样,那么使用很棒的文章中的算法是一个不太好的想法。 Every time you upload geometry data to the GPU, you incur a performance cost. 每次将几何数据上传到GPU时,都会产生性能损失。

A better approach is to calculate the geometry for a single basic cylinder once — say, one with unit radius and height — and stuff that vertex data into a VBO . 更好的方法是一次计算单个基本圆柱的几何形状(例如,一个具有单位半径和高度的几何形状),然后将顶点数据填充到VBO中 Then, when you draw, use a model-to-world transformation matrix to scale (independently in radius and length if needed) and rotate the cylinder into place. 然后,在绘制时,请使用模型到世界的转换矩阵进行缩放(如果需要,可以独立地使用半径和长度),然后将圆柱体旋转到位。 This way, the only new data that gets sent to the GPU with each draw call is a 4x4 matrix instead of all the vertex data for whatever polycount of cylinder you're drawing. 这样,每次绘制调用都会发送到GPU的唯一新数据是4x4矩阵,而不是您绘制的任何圆柱数的所有顶点数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM