Games101 中介绍了多边形的绘制方式,其核心就是通过向量的叉乘以判别一个点是否在多边形内,最终实现多边形的绘制。绘制结果通过OpenCV展示出来,所以需要一点点OpenCV的入门知识和环境,如果你用其他方式展示图片,下面的代码稍加修改也可以直接使用。闲话不多说,核心代码如下
// 定义背景颜色
unsigned char bkColor[4] = {0, 148, 212, 255};
// 定义画布,并填上背景颜色
_mainMatImg = cv::Mat(500, 1000, CV_8UC3);
for (int y = 0; y < _mainMatImg.rows; ++y)
{
for (int x = 0; x < _mainMatImg.cols; ++x)
{
_mainMatImg.data[y * _mainMatImg.step + x * _mainMatImg.channels() + 0] = bkColor[0];
_mainMatImg.data[y * _mainMatImg.step + x * _mainMatImg.channels() + 1] = bkColor[1];
_mainMatImg.data[y * _mainMatImg.step + x * _mainMatImg.channels() + 2] = bkColor[2];
}
}
// 定义多边形的数据
const int polyEdgeNum = 3;
int triAngPt[polyEdgeNum][2] =
{
{309, 68},
{334, 276},
{36, 414},
//{67, 228},
//{131, 80},
//{222, 20},
};
// 先画不抗锯齿的多边形
double v1[2], v2[2];
double vxvRst;
bool ifNegative;
int i;
// 遍历图片中的每个点,判别是否在多边形中
for (int y = 0; y < _mainMatImg.rows; ++y)
{
for (int x = 0; x < _mainMatImg.cols / 2; ++x)
{
// 【核心代码】遍历多边形每一条边,判断该像素点在每条边的哪一侧
for (i = 0; i < polyEdgeNum; ++i)
{
// 求多边形边向量
v1[0] = triAngPt[(i + 1) % polyEdgeNum][0] - triAngPt[i][0];
v1[1] = triAngPt[(i + 1) % polyEdgeNum][1] - triAngPt[i][1];
// 求当前点和多边形当前边起始点的向量
v2[0] = x - triAngPt[i][0];
v2[1] = y - triAngPt[i][1];
// 将上述两个向量叉乘以求方向
vxvRst = v1[0] * v2[1] - v1[1] * v2[0];
//
if (i == 0)
{
ifNegative = (vxvRst > 0 ? false : true);
}
else
{
if (ifNegative == true && vxvRst > 0
|| ifNegative == false && vxvRst < 0)
{
break;
}
}
}
//
if (i >= polyEdgeNum)
{
_mainMatImg.data[y * _mainMatImg.step + x * 3 + 0] = 0;
_mainMatImg.data[y * _mainMatImg.step + x * 3 + 1] = 0;
_mainMatImg.data[y * _mainMatImg.step + x * 3 + 2] = 255;
}
}
}
上述代码绘制了一个三角形,结果如下
可以对代码进行简单修改,绘制更多边的图形,例如下面绘制6变形
后记:
(1)仔细看的话,会发现绘制的多边形锯齿感比较明显,下一步就对其进行抗锯齿处理;
(2)该方式有其局限性,其不适用于凹多边形的绘制,可对其进行改进,使其更为通用,具体可转这里
(3)多边形的绘制只是一项基础的图形学功能 ,可应用于多个方面,例如3D物体的渲染
最后,感谢闫令琪和Games101