问题
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