有一项需求: 求出模型的任意方向的视图
本文写一个求顶视图和底视图的方式, 任意方向的视图只是投影平面方程不同而已
测试模型:
顶视图
底视图
顶部高度图(灰度, 未取材质颜色, 懒没写)
底部高度图(灰度)
本算法原理分以下几部:
1: 求模型外包围盒box, 根据顶视图输出大小计算输出分辨率resx,resy
2: 遍历图像宽高范围内的所有像素, 求每点与模型每个三角面片的交点 z值
3: 一个点可能与多个三角形在Z方向上交, 按照最大最小值记录, 最小值底视图, 最大值顶视图
4: 得到的高度数组根据高度范围拉伸到0-255, 保存为图片
初步估算算法复杂度为n的3次方, 优化空间不大, 除了求接点与三角形外包可用box加速, 目前就剩开omp硬件加速,或者simd加速等非软件方法了.
可以看出求底部的时候中间有一个高度不正常, 检查模型发现是模型有个洞, 所以是正常现象. 关键算法代码如下:
关键代码如下:
void Mesh2HeightMap(Mesh & mesh, int w, int h, ByteBuffer * bufferhm, double hmin, double hmax)
{Help ctb;auto box = mesh.pTriMesh->GetBox();float Width = box[3] - box[0];float Height = box[4] - box[1];double resx = Width / w;double resy = Height / h;if (bufferhm)bufferhm->AllocateT<float>(w*h);float* Head = (float*)bufferhm->BufferHead();
#pragma omp parallel for for (int i = 0; i < h; i++)for (int j = 0; j < w; j++){double x = box[0] + i * resx + 0.25 * resx;double y = box[4] - j * resy - 0.25 * resy;Point3D pOut(x, y, 0.);double maxvalue = -DBL_MAX;double minvalue = DBL_MAX;for (unsigned int k = 0; k < mesh.pTriMesh->triangles.size(); k++){int nindep1 = mesh.pTriMesh->triangles[k][0];int nindep2 = mesh.pTriMesh->triangles[k][1];int nindep3 = mesh.pTriMesh->triangles[k][2];size_t pointssize = mesh.pTriMesh->points.size();if (nindep1 >= pointssize || nindep1 < 0)continue;if (nindep2 >= pointssize || nindep2 < 0)continue;if (nindep3 >= pointssize || nindep3 < 0)continue;Vec3F p1 = mesh.pTriMesh->points[nindep1];Vec3F p2 = mesh.pTriMesh->points[nindep2];Vec3F p3 = mesh.pTriMesh->points[nindep3];Point3D pt1(p1.X(), p1.Y(), p1.Z());Point3D pt2(p2.X(), p2.Y(), p2.Z());oint3D pt3(p3.X(), p3.Y(), p3.Z());double xmin = std::min(std::min(pt1.X, pt2.X), std::min(pt3.X, pt2.X));double ymin = std::min(std::min(pt1.Y, pt2.Y), std::min(pt3.Y, pt2.Y));double xmax = std::max(std::max(pt1.X, pt2.X), std::max(pt3.X, pt2.X));double ymax = std::max(std::max(pt1.Y, pt2.Y), std::max(pt3.Y, pt2.Y));if (pOut.X < xmin || pOut.Y < ymin || pOut.X > xmax || pOut.Y >ymax)continue;//点在三角形上z值, 就是平面方程求zif (ctb.Point2Ttiangle(pt1, pt2, pt3, pOut)){maxvalue = maxvalue < pOut.Z ? pOut.Z : maxvalue;minvalue = minvalue > pOut.Z ? pOut.Z : minvalue;}}//Head[w * i + j] = maxvalue;Head[w * i + j] = minvalue;}
}
//保存高度数组为图像
void SaveHeight( int w,int h, ByteBuffer*bufferhm)
{ByteBuffer bufftttt;bufftttt.AllocateT<unsigned int>(w*h);unsigned int* buffhead = (unsigned int*)bufftttt.BufferHead();float* f = (float*)bufferhm->BufferHead();double min = DBL_MAX, max = -DBL_MIN;for (int i = 0; i < bufferhm->BufferSizeT<float>(); i++){ if (std::isinf(f[i]))continue;min = min > f[i] ? f[i]: min ;max = max < f[i] ? f[i]: max ;}BitmapPtr ptrIMG = new Bitmap(w, h);for (int i = 0; i < bufferhm->BufferSizeT<float>(); i++){unsigned char* g = (unsigned char*)&buffhead[i];if (std::isinf(f[i])){g[0] = 0;g[1] = 0;g[2] = 0;g[3] = 0;continue;}unsigned char RGB = 255 * (fabs(f[i] / (max - min)));g[0] = RGB;g[1] = RGB;g[2] = RGB;g[3] = 255;}ptrIMG->FillImageData(bufftttt.BufferHead(), bufftttt.BufferSize(), ptrIMG->RGBAType());char file[512];sprintf(&file[0], "D:\\testdata\\%d_%d_%d.png", 0, 0, 0);ptrIMG->SavePNG(file);
}
以上代码vs2015 测过( 高度图赋值颜色就是求z再去三角形种内插颜色即可