三维模型转求顶和底视图

Thisarticledescribesanalgorithmtogeneratetopandbottomviewsofa3Dmodel,calculatingintersectionpointswithtrianglesforheightvalues.Thecomplexityiscubic(O(n^3)),andoptimizationslikeparallelprocessingandhardwareaccelerationarediscussed.Keycodeshowcasestheprocessofconvertingameshintoaheightmap.
摘要由CSDN通过智能技术生成

有一项需求: 求出模型的任意方向的视图

本文写一个求顶视图和底视图的方式,  任意方向的视图只是投影平面方程不同而已

测试模型:

顶视图

底视图

顶部高度图(灰度, 未取材质颜色, 懒没写)

底部高度图(灰度)

本算法原理分以下几部:

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值, 就是平面方程求z
				if (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再去三角形种内插颜色即可

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值