Saltar al contenido

OpenGL: rectángulo redondeado 2d de ES 1.0

Hola, descubrimos la respuesta a tu pregunta, desplázate y la verás aquí.

Solución:

Usando polígonos

Si el uso de polígonos es absolutamente necesario, por ejemplo, si los objetos con redondeo deben ampliarse o ampliarse mucho o si es necesario controlar la cantidad de redondeo, es posible dividir el rectángulo en varios subobjetos.

Esquinas redondeadas

Hay al menos tres partes rectangulares y cuatro esquinas. Calcular las coordenadas de las esquinas es fácil. Solo encuentra un punto del círculo y construye triángulos como en la imagen de arriba.

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

Todavía tendrá bordes afilados, pero más puntos hacen que las esquinas sean más redondas. Los objetos pequeños necesitan menos puntos que los objetos grandes.

La ruta fácil es usar GL_TRIANGLE_FAN para las esquinas. Sin embargo, con OpenGL ES, sería aconsejable minimizar la cantidad de llamadas OpenGL y simplemente usar más vértices, ya que es posible construir un objeto completo como GL_TRIANGLE_STRIP.

Este enfoque se puede utilizar con cualquier forma. Con un rectángulo, el ángulo de la esquina es siempre de 90 grados, pero con otras formas, el ángulo debe calcularse a partir de los bordes.

Usando texturas

Otro enfoque se llama escala de 9 cortes. El rectángulo y la textura se dividen en 9 rodajas. El redondeo real está en la esquina de una textura. La idea es que las esquinas no se escalen, pero mantengan su tamaño original. Este enfoque es un patrón ampliamente utilizado en el diseño de la interfaz de usuario que permite elementos de la interfaz de usuario de tamaño variable, como botones. Su ventaja es que un rectángulo solo necesita estos 9 quads para renderizarse. Pero se verá mal si también es necesario escalar las esquinas y especialmente si la textura es de baja resolución.

Un poco complicado, pero hoy me quedé atrapado en el mismo problema, esto es lo que produzco, se creó con Desktop GL, pero debería ser muy fácil de convertir a GLES, todo es una tira. Probablemente no esté tan optimizado como debería ser, pero si alguien quiere probarlo, por favor sea mi invitado;)

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 );

Para dibujar el rectángulo redondeado, simplemente llame a algo como dentro de una vista ortográfica:

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

Necesitaba dibujar un rectángulo similar, pero transparente, y el código anterior dibuja algunos de los triángulos superpuestos. Se corrigió eso, también se eliminó malloc, solo para simplificar la solución. Aquí está mi versión:

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

Comentarios y puntuaciones del tutorial

Recuerda compartir este enunciado si te valió la pena.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *