【问题标题】:OpenGL—ES 1.0 2d rounded rectangleOpenGL—ES 1.0 2d 圆角矩形
【发布时间】:2019-12-24 14:49:17
【问题描述】:

如何在 OpenGL 中制作圆角矩形,或任何带圆角的多边形?

【问题讨论】:

  • 你需要这个有什么目的?某些 UI 元素的圆角?您需要缩放吗?

标签: opengl-es rounded-corners


【解决方案1】:

使用多边形

如果绝对需要使用多边形,例如需要大量缩放或缩放具有舍入的对象,或者需要控制舍入量,则可以将矩形分成几个子对象。

至少有三个矩形部分和四个角。计算角坐标很容易。只需从圆圈中找到一个点并构建如上图所示的三角形。

 float anglerad = PI * angle / 180.0f;
 float x = sinf(anglerad) * radius; 
 float y = cosf(anglerad) * radius;

它仍然会有锋利的边缘,但更多的点会使角落更圆。小物体比大物体需要的积分少。

简单的方法是使用GL_TRIANGLE_FAN 进行弯道。然而,对于 OpenGL ES,尽量减少 OpenGL 调用的数量并使用更多顶点可能是明智的,因为可以将整个对象构建为 GL_TRIANGLE_STRIP。

这种方法可以用于任何形状。对于矩形,角的角度始终为 90 度,但对于其他形状,角度需要从边缘计算。

使用纹理

另一种方法称为9-slice scaling。矩形和纹理被分成 9 个切片。实际的舍入是在纹理的角落。想法是角落没有缩放,但保持其原始大小。这种方法是 UI 设计中广泛使用的模式,允许可变大小的 UI 元素(如按钮)。它的优点是一个矩形只需要这 9 个四边形来渲染。但是如果还需要缩放角落,尤其是纹理分辨率较低时,它看起来会很糟糕。

【讨论】:

  • 通过将第一个顶点放置在矩形的中心,您可以有效地使用 GL_TRIANGLE_FAN 和一次绘制调用。
  • 完全正确!如果需要一些纹理坐标,那可能有点棘手。
  • GL_TRIANGLE_STRIP 不足以进行这种渲染吗?
  • 这在内存资源上不是很贵吗?我尝试实现这一点,我有很多代码只是为了调用一次glDrawElements。即使我将slice count 设置为 90,边缘也不是那么平滑
  • 可以使用 GL_TRIANGLE_STRIP 来绘制整个东西。但是它的代码很容易变得复杂。就像@schellsan 建议的那样,一个 GL_TRIANGLE_FAN 更简单。但我认为这里的内存资源不是问题。限制绘图调用更为重要。确实,没有抗锯齿的边缘可能很粗糙,无论使用多少多边形。我个人现在更喜欢 9 切片缩放,因为它允许纹理边缘平滑。
【解决方案2】:

有点颠簸,但我今天遇到了同样的问题,这是我输出的,它是用 Desktop GL 创建的,但应该很容易转换为 GLES,一切都是一条条。它可能没有达到应有的优化水平,但如果有人想尝试一下,请成为我的客人;)

typedef struct
{
    float x;
    float y;

} Vector2f;


void RoundRect( int x,
            int y,
            int width,
            int height,
            int radius,
            int resolution )
{
float step = ( 2.0f * M_PI ) / resolution,
      angle = 0.0f,
      x_offset,
      y_offset;

int i = 0;

unsigned int index = 0,
             segment_count = ( int )( resolution / 4 );

Vector2f *top_left             = ( Vector2f * ) malloc( segment_count * sizeof( Vector2f ) ), 
         *bottom_left         = ( Vector2f * ) malloc( segment_count * sizeof( Vector2f ) ),
         *top_right             = ( Vector2f * ) malloc( segment_count * sizeof( Vector2f ) ),
         *bottom_right         = ( Vector2f * ) malloc( segment_count * sizeof( Vector2f ) ),
          bottom_left_corner = { x + radius,
                                 y - height + radius }; 

while( i != segment_count )
{
    x_offset = cosf( angle );
    y_offset = sinf( angle );


    top_left[ index ].x = bottom_left_corner.x - 
                          ( x_offset * radius );
    top_left[ index ].y = ( height - ( radius * 2.0f ) ) + 
                            bottom_left_corner.y - 
                          ( y_offset * radius );


    top_right[ index ].x = ( width - ( radius * 2.0f ) ) + 
                             bottom_left_corner.x + 
                           ( x_offset * radius );
    top_right[ index ].y = ( height - ( radius * 2.0f ) ) + 
                             bottom_left_corner.y -
                           ( y_offset * radius );


    bottom_right[ index ].x = ( width - ( radius * 2.0f ) ) +
                                bottom_left_corner.x + 
                              ( x_offset * radius );
    bottom_right[ index ].y = bottom_left_corner.y + 
                              ( y_offset * radius );


    bottom_left[ index ].x = bottom_left_corner.x - 
                             ( x_offset * radius );
    bottom_left[ index ].y = bottom_left_corner.y +
                             ( y_offset * radius );


    top_left[ index ].x = roundf( top_left[ index ].x );
    top_left[ index ].y = roundf( top_left[ index ].y );


    top_right[ index ].x = roundf( top_right[ index ].x );
    top_right[ index ].y = roundf( top_right[ index ].y );


    bottom_right[ index ].x = roundf( bottom_right[ index ].x );
    bottom_right[ index ].y = roundf( bottom_right[ index ].y );


    bottom_left[ index ].x = roundf( bottom_left[ index ].x );
    bottom_left[ index ].y = roundf( bottom_left[ index ].y );

    angle -= step;

    ++index;

    ++i;
}


glBegin( GL_TRIANGLE_STRIP );
{
    // Top
    {
        i = 0;
        while( i != segment_count )
        {
            //glColor4f( 1.0f, 0.0f, 0.0f, 1.0f );
            glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
            glVertex2i( top_left[ i ].x,
                        top_left[ i ].y );

            //glColor4f( 0.0f, 1.0f, 0.0f, 1.0f );
            glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
            glVertex2i( top_right[ i ].x,
                        top_right[ i ].y );

            ++i;
        }
    }


    // In order to stop and restart the strip.
    glColor4f( 0.0f, 1.0f, 0.0f,  1.5f );
    glVertex2i( top_right[ 0 ].x,
                top_right[ 0 ].y );

    glColor4f( 0.0f, 1.0f, 0.0f,  1.5f );
    glVertex2i( top_right[ 0 ].x,
                top_right[ 0 ].y );


    // Center
    {
        //glColor4f( 0.0f, 1.0f, 0.0f,  1.0f );
        glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
        glVertex2i( top_right[ 0 ].x,
                    top_right[ 0 ].y );


        //glColor4f( 1.0f, 0.0f, 0.0f,  1.0f );
        glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
        glVertex2i( top_left[ 0 ].x,
                    top_left[ 0 ].y );


        //glColor4f( 0.0f, 0.0f, 1.0f,  1.0f );
        glColor4f( 0.5f, 0.5f, 0.5f,  1.0f );
        glVertex2i( bottom_right[ 0 ].x,
                    bottom_right[ 0 ].y );


        //glColor4f( 1.0f, 1.0f, 0.0f,  1.0f );
        glColor4f( 0.5f, 0.5f, 0.5f,  1.0f );
        glVertex2i( bottom_left[ 0 ].x,
                    bottom_left[ 0 ].y );
    }


    // Bottom
    i = 0;
    while( i != segment_count )
    {
        //glColor4f( 0.0f, 0.0f, 1.0f,  1.0f );
        glColor4f( 0.5f, 0.5f, 0.5f,  1.0f );
        glVertex2i( bottom_right[ i ].x,
                    bottom_right[ i ].y );    

        //glColor4f( 1.0f, 1.0f, 0.0f,  1.0f );
        glColor4f( 0.5f, 0.5f, 0.5f,  1.0f );
        glVertex2i( bottom_left[ i ].x,
                    bottom_left[ i ].y );                                    

        ++i;
    }    
}
glEnd();



glBegin( GL_LINE_STRIP );

//glColor4f( 0.0f, 1.0f, 1.0f, 1.0f );
glColor4f( 1.0f, 0.5f, 0.0f, 1.0f );

// Border
{
    i = ( segment_count - 1 );
    while( i > -1 )
    {    
        glVertex2i( top_left[ i ].x,
                    top_left[ i ].y );

        --i;
    }


    i = 0;
    while( i != segment_count )
    {    
        glVertex2i( bottom_left[ i ].x,
                    bottom_left[ i ].y );

        ++i;
    }


    i = ( segment_count - 1 );
    while( i > -1 )
    {    
        glVertex2i( bottom_right[ i ].x,
                    bottom_right[ i ].y );

        --i;
    }


    i = 0;
    while( i != segment_count )
    {    
        glVertex2i( top_right[ i ].x,
                    top_right[ i ].y );

        ++i;
    }


    // Close the border.
    glVertex2i( top_left[ ( segment_count - 1 ) ].x,
                top_left[ ( segment_count - 1 ) ].y );
}
glEnd();




glBegin( GL_LINES );

//glColor4f( 0.0f, 1.0f, 1.0f, 1.0f );
glColor4f( 0.0f, 0.5f, 1.0f, 1.0f );

// Separator
{
    // Top bar
    glVertex2i( top_right[ 0 ].x,
                top_right[ 0 ].y );

    glVertex2i( top_left[ 0 ].x,
                top_left[ 0 ].y );    


    // Bottom bar
    glVertex2i( bottom_left[ 0 ].x,
                bottom_left[ 0 ].y );    

    glVertex2i( bottom_right[ 0 ].x,
                bottom_right[ 0 ].y );    
}
glEnd();



free( top_left );
free( bottom_left );
free( top_right );
free( bottom_right );
}

要绘制圆角矩形,只需在正交视图中调用类似的东西:

RoundRect( 200, /* x */
           400, /* y */
           400, /* width */
           300, /* height */
           25,  /* Corner radius, at least less than 140? */
           64  /* need to be "dividable" by 4 */ );

【讨论】:

    【解决方案3】:

    我需要绘制类似的矩形,但透明 - 上面的代码绘制了一些重叠的三角形。修复了这个问题,也删除了 malloc,只是为了简化解决方案。这是我的版本:

    typedef struct
    {
        float x;
        float y;
    } Vector2f;
    
    //
    //  Draws rounded rectangle.
    //
    //  Slightly tuned version of http://stackoverflow.com/questions/5369507/opengles-1-0-2d-rounded-rectangle
    //
    #define ROUNDING_POINT_COUNT 8      // Larger values makes circle smoother.
    void DrawRoundRect( float x, float y, float width, float height, float* color = 0, float radius = 0.0 )
    {
        Vector2f top_left[ROUNDING_POINT_COUNT];
        Vector2f bottom_left[ROUNDING_POINT_COUNT];
        Vector2f top_right[ROUNDING_POINT_COUNT];
        Vector2f bottom_right[ROUNDING_POINT_COUNT];
    
        if( radius == 0.0 )
        {
            radius = min(width, height);
            radius *= 0.10; // 10%
        }
    
        int i = 0;
        float x_offset, y_offset;
        float step = ( 2.0f * pi ) / (ROUNDING_POINT_COUNT * 4),
              angle = 0.0f;
    
        unsigned int index = 0, segment_count = ROUNDING_POINT_COUNT;
        Vector2f bottom_left_corner = { x + radius, y - height + radius }; 
    
    
        while( i != segment_count )
        {
            x_offset = cosf( angle );
            y_offset = sinf( angle );
    
    
            top_left[ index ].x = bottom_left_corner.x - 
                                  ( x_offset * radius );
            top_left[ index ].y = ( height - ( radius * 2.0f ) ) + 
                                    bottom_left_corner.y - 
                                  ( y_offset * radius );
    
    
            top_right[ index ].x = ( width - ( radius * 2.0f ) ) + 
                                     bottom_left_corner.x + 
                                   ( x_offset * radius );
            top_right[ index ].y = ( height - ( radius * 2.0f ) ) + 
                                     bottom_left_corner.y -
                                   ( y_offset * radius );
    
    
            bottom_right[ index ].x = ( width - ( radius * 2.0f ) ) +
                                        bottom_left_corner.x + 
                                      ( x_offset * radius );
            bottom_right[ index ].y = bottom_left_corner.y + 
                                      ( y_offset * radius );
    
    
            bottom_left[ index ].x = bottom_left_corner.x - 
                                     ( x_offset * radius );
            bottom_left[ index ].y = bottom_left_corner.y +
                                     ( y_offset * radius );
    
    
            top_left[ index ].x = top_left[ index ].x;
            top_left[ index ].y = top_left[ index ].y;
    
    
            top_right[ index ].x = top_right[ index ].x;
            top_right[ index ].y = top_right[ index ].y;
    
    
            bottom_right[ index ].x = bottom_right[ index ].x ;
            bottom_right[ index ].y = bottom_right[ index ].y;
    
    
            bottom_left[ index ].x =  bottom_left[ index ].x ;
            bottom_left[ index ].y =  bottom_left[ index ].y ;
    
            angle -= step;
    
            ++index;
    
            ++i;
        }
    
        static GLubyte clr[] = { 156, 207, 255, 128 };   // Light blue, 50% transparent.
    
        if( color )
            glColor4fv(color);
        else
            glColor4ubv(clr);
    
        glBegin( GL_TRIANGLE_STRIP );
        {
            // Top
            for( i = segment_count - 1 ; i >= 0 ; i--)
            {
                glVertex2f( top_left[ i ].x, top_left[ i ].y );
                glVertex2f( top_right[ i ].x, top_right[ i ].y );
            }
    
            // In order to stop and restart the strip.
            glVertex2f( top_right[ 0 ].x, top_right[ 0 ].y );
            glVertex2f( top_right[ 0 ].x, top_right[ 0 ].y );
    
            // Center
            glVertex2f( top_right[ 0 ].x, top_right[ 0 ].y );
            glVertex2f( top_left[ 0 ].x, top_left[ 0 ].y );
            glVertex2f( bottom_right[ 0 ].x, bottom_right[ 0 ].y );
            glVertex2f( bottom_left[ 0 ].x, bottom_left[ 0 ].y );
    
            // Bottom
            for( i = 0; i != segment_count ; i++ )
            {
                glVertex2f( bottom_right[ i ].x, bottom_right[ i ].y );    
                glVertex2f( bottom_left[ i ].x, bottom_left[ i ].y );                                    
            }    
        }
        glEnd();
    } //DrawRoundRect
    

    【讨论】:

    • top_left[索引].x = top_left[索引].x; ——你不觉得有点多余吗?
    【解决方案4】:

    以下代码是从我自己的项目中应对的,我在代码中添加了一些cmets来解释。 如果将绘制一个没有边框的渐变圆角矩形。

    #define GLW_SMALL_ROUNDED_CORNER_SLICES 5  // How many vertexes you want of each corner
    
    #define glwR(rgb) ((float)(((rgb) >> 16) & 0xff) / 255)
    #define glwG(rgb) ((float)(((rgb) >> 8) & 0xff) / 255)
    #define glwB(rgb) ((float)(((rgb)) & 0xff) / 255)
    
    
    typedef struct glwVec2 {
      float x;
      float y;
    } glwVec2;
    
    static glwVec2 glwRoundedCorners[GLW_SMALL_ROUNDED_CORNER_SLICES] = {{0}}; // This array keep the generated vertexes of one corner
    
    static void createRoundedCorners(glwVec2 *arr, int num) {
      // Generate the corner vertexes
      float slice = M_PI / 2 / num;
      int i;
      float a = 0;
      for (i = 0; i < num; a += slice, ++i) {
        arr[i].x = cosf(a);
        arr[i].y = sinf(a);
      }
    }
    
    createRoundedCorners(glwRoundedCorners, GLW_SMALL_ROUNDED_CORNER_SLICES);
    
    void glwDrawRoundedRectGradientFill(float x, float y, float width, float height,
        float radius, unsigned int topColor, unsigned int bottomColor) {
      float left = x;
      float top = y;
      float bottom = y + height - 1;
      float right = x + width - 1;
      int i;
      glDisable(GL_TEXTURE_2D);
      glBegin(GL_QUAD_STRIP);
        // Draw left rounded side.
        for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
          glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
          glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
            bottom - radius + radius * glwRoundedCorners[i].y);
          glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
          glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
            top + radius - radius * glwRoundedCorners[i].y);
        }
        // Draw right rounded side.
        for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
          glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
          glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
            bottom - radius + radius * glwRoundedCorners[i].y);
          glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
          glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
            top + radius - radius * glwRoundedCorners[i].y);
        }
      glEnd();
    }
    

    如果你想画边框,这里是代码。

    static void glwDrawRightTopVertexs(float left, float top, float right,
        float bottom, float radius) {
      int i;
      for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
        glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
          top + radius - radius * glwRoundedCorners[i].y);
      }
    }
    
    static void glwDrawRightBottomVertexs(float left, float top, float right,
        float bottom, float radius) {
      int i;
      for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
        glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
          bottom - radius + radius * glwRoundedCorners[i].y);
      }
    }
    
    static void glwDrawLeftBottomVertexs(float left, float top, float right,
        float bottom, float radius) {
      int i;
      for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
        glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
          bottom - radius + radius * glwRoundedCorners[i].y);
      }
    }
    
    static void glwDrawLeftTopVertexs(float left, float top, float right,
        float bottom, float radius) {
      int i;
      for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
        glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
          top + radius - radius * glwRoundedCorners[i].y);
      }
    }
    
    void glwDrawRoundedRectBorder(float x, float y, float width, float height,
        float radius, unsigned int color) {
      float left = x;
      float top = y;
      float bottom = y + height - 1;
      float right = x + width - 1;
      glDisable(GL_TEXTURE_2D);
      glColor3f(glwR(color), glwG(color), glwB(color));
      glBegin(GL_LINE_LOOP);
        glVertex2f(left, top + radius);
        glwDrawLeftTopVertexs(left, top, right, bottom, radius);
        glVertex2f(left + radius, top);
    
        glVertex2f(right - radius, top);
        glwDrawRightTopVertexs(left, top, right, bottom, radius);
        glVertex2f(right, top + radius);
    
        glVertex2f(right, bottom - radius);
        glwDrawRightBottomVertexs(left, top, right, bottom, radius);
        glVertex2f(right - radius, bottom);
    
        glVertex2f(left + radius, bottom);
        glwDrawLeftBottomVertexs(left, top, right, bottom, radius);
        glVertex2f(left, bottom - radius);
      glEnd();
    }
    

    【讨论】:

    • 请补充说明
    【解决方案5】:
    #define PI_2   1.57079632679490f
    
    #define SIN(x) SDL_sinf (x)
    #define COS(x) SDL_cosf (x)
    
    typedef struct _g2d_vertex_t g2d_vertex_t;
    
    struct _g2d_vertex_t {
    
        float x, y;
    };
    
    // pVertices - destination buffer
    // nVertices - buffer size
    // dx - width
    // dy - height
    // r - radius
    // returnes the number of used vertices
    int
    __cdecl buildRoundedRect (g2d_vertex_t * pVertices, int nVertices, float dx, float dy, float r) {
    
        float a, da;
        int i1, i2, i3, i4, n;
    
        if (nVertices < 4) { return 0; }
    
        if (nVertices == 4) {
    
            pVertices [0].x = 0.f; pVertices [0].y = 0.f;
            pVertices [1].x = dx;  pVertices [1].y = 0.f;
            pVertices [2].x = dx;  pVertices [2].y = dy;
            pVertices [3].x = 0.f; pVertices [3].y = dy;
    
            return nVertices;
        }
    
        n = nVertices >> 2;
    
        if (r > dx / 2.f) { r = dx / 2.f; }
        if (r > dy / 2.f) { r = dy / 2.f; }
    
        a = 0.f;
        da = PI_2 / (float) (n - 1);
    
        for (i1 = 0, i2 = (n << 1) - 1, i3 = n << 1, i4 = (n << 2) - 1; i1 < n; i1++, i2--, i3++, i4--, a += da) {
    
            float cosA = COS (a), sinA = SIN (a);
    
            pVertices [i1].x = (dx - r) + r * cosA; pVertices [i1].y = (dy - r) + r * sinA;
            pVertices [i2].x =     r    - r * cosA; pVertices [i2].y = (dy - r) + r * sinA;
            pVertices [i3].x =     r    - r * cosA; pVertices [i3].y =     r    - r * sinA;
            pVertices [i4].x = (dx - r) + r * cosA; pVertices [i4].y =     r    - r * sinA;
        }
    
        return n << 2;
    }
    
    void drawRoundedRect () {
    
        g2d_vertex_t vertices [50];
    
        glColor3f (0.3f, 0.5f, 0.2f);
    
        glVertexPointer (2, GL_FLOAT, 0, vertices);
        glEnableClientState (GL_VERTEX_ARRAY);
    
        glDrawArrays (GL_LINE_LOOP, 0, buildRoundedRect (vertices, 50 /* max count of vertices to use: 4 - 50 */, 150.f, 80.f, 20.f));
    }
    

    【讨论】:

    • 一个小修复:当你限制半径时使用:r = min( r, 0.499999 * min( dx, dy ) ); 否则当r 正好是矩形宽度或高度的一半时会产生重复点。
    【解决方案6】:

    我在一些开源软件中遇到了这个修复崩溃的问题 - 非 GL 版本运行良好,但基本上目的是实现一个圆角矩形,但开发人员对此太懒了,决定改为强制崩溃: -(

    虽然我认为@vime 的回答简洁而完整,但我见过很多类似的例子,但没有一个让我有信心,而且我认为这些例子并不明显,所以这里是我的记录......调用函数 实现 4 角(代码 sn-p)...

    glBegin(GL_POLYGON);
    
    // top-left corner
    DrawGLRoundedCorner(x, y + radius, 3 * PI / 2, PI / 2, radius);
    
    // top-right
    DrawGLRoundedCorner(x + size_x - radius, y, 0.0, PI / 2, radius);
    
    // bottom-right
    DrawGLRoundedCorner(x + size_x, y + size_y - radius, PI / 2, PI / 2, radius);
    
    // bottom-left
    DrawGLRoundedCorner(x + radius, y + size_y, PI, PI / 2, radius);
    
    glEnd();
    

    ... 和弧形截面函数 DrawGLRoundedCorner()。请注意,这假定 glBegin() 已经被调用并绘制了弧的起点和终点——这就是为什么您不需要在边的末端显式添加顶点的原因。

    void DrawGLRoundedCorner(int x, int y, double sa, double arc, float r) {
        // centre of the arc, for clockwise sense
        float cent_x = x + r * cos(sa + PI / 2);
        float cent_y = y + r * sin(sa + PI / 2);
    
        // build up piecemeal including end of the arc
        int n = ceil(N_ROUNDING_PIECES * arc / PI * 2);
        for (int i = 0; i <= n; i++) {
            double ang = sa + arc * (double)i  / (double)n;
    
            // compute the next point
            float next_x = cent_x + r * sin(ang);
            float next_y = cent_y - r * cos(ang);
            glVertex2f(next_x, next_y);
        }
    }
    

    通过使用不同的 glBegin,例如 GL_LINE_LOOP,我认为您最终会得到一个未填充的圆角矩形。对于较大的圆角半径,可能需要使用各种抗锯齿提示或类似方法使其看起来更漂亮,但还有其他关于此的帖子。

    希望对某人有所帮助。

    【讨论】:

    • 我以为OpenGL ES不支持glBegin()/glEnd()对?!
    【解决方案7】:

    您还可以制作三角形而不是矩形来斜切边缘。

    【讨论】:

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