Draw a rounded rectangle using a single glDrawElement( triangle_strip…) call in OpenGL ES

笑着哭i 提交于 2019-12-23 15:36:30

问题


I want to draw a rounded rectangle in Opengl es, with a single glDraw call. I have also tried it. and shared it in the answer.

Hope it will be helpful.


回答1:


I have tried to draw a rounded rectangle in opengl es with single glDraw call.
Below is the code snippet:

// -0.3f,   -0.2f,  0.0f,   // 0
//  0.3f,  -0.2f,  0.0f,    // 1
// -0.3f,   0.2f,  0.0f,    // 2
//  0.3f,    0.2f,  0.0f,   // 3
//  0.6f,   0.2f,  0.0f,    // 4
//  0.6f,   -0.2f,  0.0f,   // 5
//  0.6f,  -0.5f,  0.0f,    // 6
//  0.3f,  -0.5f,  0.0f,    // 7
// -0.3f,   -0.5f,  0.0f,   // 8
// -0.6f,  -0.5f,  0.0f,    // 9
// -0.6f,  -0.2f,  0.0f,    // 10
// -0.6f,   0.2f,  0.0f,    // 11
// -0.6f,    0.5f,  0.0f,   // 12
// -0.3f,   0.5f,  0.0f,    // 13
//  0.3f,    0.5f,  0.0f,   // 14
//  0.6f,   0.5f,  0.0f // 15
//
//            8_______________________7
//            /|                      |\
//          9/ |                      | \6
//        10/  |                      |  \5
//         /___|______________________|___\
//       1 |   |2                    3|   |4
//         |   |                      |   |
//         |   |                      |   |
//      12 |___|______________________|___|19
//         \   |0                    1|   /
//        13\  |                      |  /18
//         14\ |                      | /17
//            \|______________________|/
//            15                      16
//

static GLfloat vertRndRect[N];
// first store the vertices 0,1,2,3,4 in vertRndRect array
// then calculate the value for vertices 5 and 6 using the below code
for (i = 30; i < 90; i = i + 30)  // change this line to create more vertices but 'indices' array will change
{
float X_cen = vert1[9]; 
float Y_cen = vert1[10];
    vertRndRect[iVertCnt++]  = X_cen + (cos(degreesToRadians(i)) * rad); 
    vertRndRect[iVertCnt++]  = Y_cen + (sin(degreesToRadians(i)) * rad); 
vertRndRect[iVertCnt++]  = 0.0f; // Z
}
// Then store  vertices 7 and 8 to vertRndRect array
// then calculate the value for vertices 9 and 10 using the below code
for (i =  120; i < 180; i = i + 30)
{
float X_cen = vert1[6];
float Y_cen = vert1[7];
    vertRndRect[iVertCnt++]  = X_cen + (cos(degreesToRadians(i)) * rad);
    vertRndRect[iVertCnt++]  = Y_cen + (sin(degreesToRadians(i)) * rad);
vertRndRect[iVertCnt++]  = 0.0f; // Z
}

// Then store  vertices 11 and 12 to vertRndRect array
// then calculate the value for vertices 13 and 14 using the below code
for (i = 210; i < 270;  i = i + 30)
{
float X_cen = vert1[0];
float Y_cen = vert1[1];
    vertRndRect[iVertCnt++]  = X_cen + (cos(degreesToRadians(i)) * rad);
    vertRndRect[iVertCnt++]  = Y_cen + (sin(degreesToRadians(i)) * rad);
vertRndRect[iVertCnt++]  = 0.0f; // Z
}

// Then store  vertices 15 and 16 to vertRndRect array
// then calculate the value for vertices 13 and 14 using the below code
for (i = 300; i < 360;  i = i + 30)
{
float X_cen = vert1[3];
float Y_cen = vert1[4];
    vertRndRect[iVertCnt++]  = X_cen + (cos(degreesToRadians(i)) * rad);
    vertRndRect[iVertCnt++]  = Y_cen + (sin(degreesToRadians(i)) * rad);
vertRndRect[iVertCnt++]  = 0.0f; // Z
}
// Then store  vertices 19
//////////////////////////
GLushort indices[] = {  0, 1, 2, 3, 3, 4, 
                            5, 5, 3, 6, 7, 7, 
                            3, 8, 2, 9, 10, 10, 
                            2, 11, 0, 12, 13, 13, 
                            0, 14, 15, 15, 0, 16, 
                            1, 17, 18, 18, 1, 19, 3, 4
                         };
//////////////////////////
glDrawElements(GL_TRIANGLE_STRIP, 38, GL_UNSIGNED_SHORT,indices); // 38 is size of 'indices' array

Here, I calculated only 2 vertices for each rounded corner.
But can increase it to get more smoothness.
But corresponding changes has to be done in 'indices' array

Lot of optimizations can be done in this code.




回答2:


I modified the code to get the inputs ( TopLeft Corner Position, width and height) and dynamically generating 10 vertices for each rounded corners and its texture coordinates.

     // Vertices and Texture Coordinates Generation.
    Input: Width and Height, Sx, Sy,Sz (Top Left Vertex Position)
    // To get smooth rounded rectangle, 10 vertices are generated for each rounded corner 

    float Sx = 0.0;
    float Sy = 0.0;
    float verCz = Sz = 0.0;

    float rad;

    if (fWidth > fHeight)
    {
        rad = 0.3f * (fHeight/fWidth);
    }
    else 
    {
        rad = 0.3f * (fWidth/fHeight);
    }

    float invWidth    = 1.0/fWidth ;
    float invHeight   = 1.0/fHeight;
    float radbywidth  = rad * invWidth;
    float radbyheight = rad * invHeight;

    float texCx   = (Sx + fWidth - rad) * invWidth;
    float texCy   = (Sy - rad)          * invHeight; 

    //0 to 9 vertices
    for (i = 0; i <= 90; i = i + 10)
    {
        vertices[iVertCnt++]  = (Sx + fWidth - rad) + (cos(degreesToRadians(i)) * rad); //centre point-X + r*cos
        vertices[iVertCnt++]  = (Sy - rad)          + (sin(degreesToRadians(i)) * rad); //centre point-Y + r*sin
        vertices[iVertCnt++]  = verCz;

        texcoord_RndRect [tex++]  = texCx + (cos(degreesToRadians(i)) * radbywidth); 
        texcoord_RndRect [tex++]  = texCy + (sin(degreesToRadians(i)) * radbyheight); 
    }

    GLfloat vert1[] =
    {
        (Sx + rad),   Sy       , 0.0f,  // 10
        (Sx + rad),   (Sy -rad), 0.0f,  // 11 
    };

    for (i = 0; i < 6; i = i+3)
    {
        vertices[iVertCnt++]        =  vert1[i];
        vertices[iVertCnt++]        =  vert1[i+1];
        vertices[iVertCnt++]        =  vert1[i+2];
        texcoord_RndRect [tex++]    =  vert1[i]   * invWidth;
        texcoord_RndRect [tex++]    =  vert1[i+1] * invHeight;
    }

    texCx   =  (Sx + rad) * invWidth;
    texCy   =  (Sy - rad) * invHeight; 
    ////12 to 21 vertices
    for (i = 90; i <= 180; i = i + 10)   
    {
        vertices[iVertCnt++]  = (Sx + rad) + (cos(degreesToRadians(i)) * rad); //centre point-X + r*cos
        vertices[iVertCnt++]  = (Sy - rad) + (sin(degreesToRadians(i)) * rad); //centre point-Y + r*sin
        vertices[iVertCnt++]  = verCz;

        texcoord_RndRect [tex++]  = texCx +(cos(degreesToRadians(i)) * radbywidth);  // texture will be from 0 to 1 only
        texcoord_RndRect [tex++]  = texCy +(sin(degreesToRadians(i)) * radbyheight); 
    }

    GLfloat vert2[] =
    {
        (Sx)        , (Sy - fHeight + rad),  0.0f,  // 22 
        (Sx + rad ),  (Sy - fHeight + rad),  0.0f,  // 23 
    };

    for (i = 0; i < 6; i = i+3)
    {
        vertices[iVertCnt++]        =  vert2[i];
        vertices[iVertCnt++]        =  vert2[i+1];
        vertices[iVertCnt++]        =  vert2[i+2];
        texcoord_RndRect [tex++]    =  vert2[i]   * invWidth;
        texcoord_RndRect [tex++]    =  vert2[i+1] * invHeight;
    }


    texCx   = (Sx + rad )          * invWidth;
    texCy   = (Sy - fHeight + rad)  * invHeight;
    ////24 to 33 vertices
    for (i = 180; i <= 270; i = i + 10) 
    {
        vertices[iVertCnt++]  = (Sx + rad )         + (cos(degreesToRadians(i)) * rad); //centre point-X + r*cos
        vertices[iVertCnt++]  = (Sy - fHeight + rad) + (sin(degreesToRadians(i)) * rad); //centre point-Y + r*sin
        vertices[iVertCnt++]  = verCz;

        texcoord_RndRect [tex++]  = texCx +(cos(degreesToRadians(i)) * radbywidth);  
        texcoord_RndRect [tex++]  = texCy +(sin(degreesToRadians(i)) * radbyheight); 
    }

    GLfloat vert3[] =
    {
        (Sx + fWidth - rad),   (Sy - fHeight)       ,  0.0f,    // 34
        (Sx + fWidth - rad),   (Sy - fHeight + rad) ,  0.0f,    // 35
    };

    for (i = 0; i < 6; i = i+3)
    {
        vertices[iVertCnt++]        =  vert3[i];
        vertices[iVertCnt++]        =  vert3[i+1];
        vertices[iVertCnt++]        =  vert3[i+2];
        texcoord_RndRect [tex++]    =  vert3[i]   * invWidth;
        texcoord_RndRect [tex++]    =  vert3[i+1] * invHeight;
    }

    //36th vertices
    vertices[iVertCnt++]  = (Sx + fWidth - rad);
    vertices[iVertCnt++]  = (Sy - fHeight + rad);
    vertices[iVertCnt++]  = 0.0f;

    texcoord_RndRect [tex++]  = (Sx + fWidth - rad) * invWidth;  // 11
    texcoord_RndRect [tex++]  = (Sy - fHeight + rad)* invHeight;

    texCx   = (Sx + fWidth - rad) * invWidth;
    texCy   = (Sy - fHeight + rad) *invHeight ; 

    ////37 to 46 to  vertices
    for (i = 270; i <= 360; i = i + 10) 
    {
        vertices[iVertCnt++]  = (Sx + fWidth - rad)  + (cos(degreesToRadians(i)) * rad); //centre point-X + r*cos
        vertices[iVertCnt++]  = (Sy - fHeight + rad) + (sin(degreesToRadians(i)) * rad); //centre point-Y + r*sin
        vertices[iVertCnt++]  = 0.0f;

        texcoord_RndRect [tex++]  = texCx +(cos(degreesToRadians(i))  * radbywidth);  
        texcoord_RndRect [tex++]  = texCy +(sin(degreesToRadians(i))  * radbyheight); 
    }

    GLfloat vert4[] =
    {
        (Sx + fWidth )      ,    (Sy - rad),  0.0f, // 47 
        (Sx + fWidth - rad) ,    (Sy -rad ),  0.0f, // 48 

    };

    for (i = 0; i < 6; i = i+3)
    {
        vertices[iVertCnt++]        =  vert4[i];
        vertices[iVertCnt++]        =  vert4[i+1];
        vertices[iVertCnt++]        =  vert4[i+2];
        texcoord_RndRect [tex++]    =  vert4[i]   * invWidth;
        texcoord_RndRect [tex++]    =  vert4[i+1] * invHeight;
    }

            // Display
    ///////////////////////////////////////
    GLushort indices_topright[] = 
    {   
        0,1,2,3,4,5,6,7,8,9,10,11
    };

    GLushort indices_topleft[] = 
    {   
        12,13,14,15,16,17,18,19,20,21,22,23
    };

    GLushort indices_bottomleft[] = 
    {   
        24,25,26,27,28,29,30,31,32,33,34,35
    };

    GLushort indices_bottomright[] = 
    {   
        36,37,38,39,40,41,42,43,44,45,46,47,48,11,23
    };
    glDrawElements(GL_TRIANGLE_FAN, (sizeof(indices_topright)/sizeof(indices_topright[0])), GL_UNSIGNED_SHORT, indices_topright);
    glDrawElements(GL_TRIANGLE_FAN, (sizeof(indices_topleft)/sizeof(indices_topleft[0])), GL_UNSIGNED_SHORT, indices_topleft);
    glDrawElements(GL_TRIANGLE_FAN, (sizeof(indices_bottomleft)/sizeof(indices_bottomleft[0])), GL_UNSIGNED_SHORT, indices_bottomleft);
    glDrawElements(GL_TRIANGLE_FAN, (sizeof(indices_bottomright)/sizeof(indices_bottomright[0])), GL_UNSIGNED_SHORT, indices_bottomright);
    ////////////////////////

This code works for me.



来源:https://stackoverflow.com/questions/19560575/draw-a-rounded-rectangle-using-a-single-gldrawelement-triangle-strip-call-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!