OpenGL-ES 1.0 2d圆角矩形

mic*_*ael 10 opengl-es rounded-corners

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

Vir*_*rne 19

使用多边形

如果绝对需要使用多边形,例如,如果需要对具有舍入的对象进行缩放或缩放,或者需要控制舍入量,则可以将矩形拆分为多个子对象.

圆角

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

 float anglerad = PI * angle / 180.0f;
 float x = sinf(anglerad) * radius; 
 float y = cosf(anglerad) * radius;
Run Code Online (Sandbox Code Playgroud)

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

简单的路线是使用GL_TRIANGLE_FAN作为角落.但是对于OpenGL ES,最好尽量减少OpenGL调用量并使用更多顶点,因为可以将整个对象构建为GL_TRIANGLE_STRIP.

这个接近可以用于任何形状.对于矩形,角的角度始终为90度,但是对于其他形状,需要从边缘计算角度.

使用纹理

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

  • 通过将第一个顶点放在矩形的中心,可以有效地使用GL_TRIANGLE_FAN和一个绘制调用. (3认同)

McB*_*Bob 5

有点磕磕碰碰但是今天我遇到了同样的问题,这就是我输出的,它是用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 );
}
Run Code Online (Sandbox Code Playgroud)

要绘制圆角矩形,只需调用类似于正交视图的内容:

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