简单的顶点合并方式

一个简单mesh顶点合并方式

主要思路

给每个顶点计算一个key,同key的顶点直接去掉,用之前已经存在的顶点的索引替换即可,下面上代码

std::vector<float> inVerties; //处理前的顶点
std::vector<float> inNormals; //处理前的法向
std::vector<unsigned int> inIndices; //处理前的索引
std::vector<float> outVerties; //处理后的顶点
std::vector<float> outNormals; //处理后的法向
std::vector<unsigned int> outIndices; //处理后的索引
	if (inVerties.size() <3 || inIndices.size() < 3 || inVerties.size() != inNormals.size() )
	{
		return;
	}
	//一次性给输出的vector分配内存
	outVerties.reserve(inVerties.size());
	outIndices.reserve(inIndices.size());
	outNormals.reserve(inNormals.size());
	struct Info
	{
		size_t index;
		float normal[3];
	};
	//用map开存放顶点的key 
	//我这里key算的比较简单 直接用顶点的xyz值放大取整拼接成字符串,也可以直接用位运算直接算一个long值
	//同key 的顶点存储在value内
	std::unordered_map<std::string, std::vector<Info>> remap;
	for (size_t i = 0; i < inIndices.size(); i++)
	{
		unsigned int index = inIndices[i];
		unsigned int pIndex = index * 3;
		char buffer[256];
		//计算key
		sprintf(buffer, "%d|%d|%d", (int)(inVerties[pIndex] * 10e6 + 0.5), (int)(inVerties[pIndex + 1] * 10e6 + 0.5), (int)(inVerties[pIndex + 2] * 10e6 + 0.5));
		std::string key = buffer;
		//找不到对应的key 添加顶点 法向 索引到输出数组
		if (remap.find(buffer) == remap.end()) 
		{
			remap[key] = std::vector<Info>();
			remap[key].emplace_back(Info{ outVerties.size() / 3, inNormals[pIndex],inNormals[pIndex + 1],inNormals[pIndex + 2] });
			outIndices.push_back(outVerties.size() / 3);

			outVerties.push_back(inVerties[pIndex]);
			outVerties.push_back(inVerties[pIndex + 1]);
			outVerties.push_back(inVerties[pIndex + 2]);

			outNormals.push_back(inNormals[pIndex]);
			outNormals.push_back(inNormals[pIndex + 1]);
			outNormals.push_back(inNormals[pIndex + 2]);
			continue;
		}
		//这里找到key时候分两种情况 
		//一直是可以合并的,判断条件可以根据直接业务来,我这里是当前顶点的法向和之前对比顶点的法向成锐角切小于60度时候合并,因为这种情况下,这两个顶点构成的三角面是钝角,一般是平面或者比较圆滑一些的面
		//如果这两个顶点构成的三角面是锐角或者角度很小的的情况下,直接合并,比如对应一个正方体,有些引擎渲染的时候会渲染的很圆润,但是实际上正方体是需要棱角的;
		bool isFind = false;
		for (Info& info : remap[key])
		{
			float* normal = &inNormals[pIndex];
			float* n = info.normal;
			if (Angle(normal, n) < _PI * 0.3)
			{
				outIndices.push_back(info.index);

				outNormals[info.index * 3] =     (outNormals[info.index*3]     + inNormals[pIndex]) *0.5;
				outNormals[info.index * 3 + 1] = (outNormals[info.index*3 + 1] + inNormals[pIndex + 1]) * 0.5;
				outNormals[info.index * 3 + 2] = (outNormals[info.index*3 + 2] + inNormals[pIndex + 2]) * 0.5;
				isFind = true;
				break;
			}
		}
		//找不到合适合并的顶点直接输出
		if (!isFind)
		{
			remap[key].emplace_back(Info{ outVerties.size() / 3, inNormals[pIndex],inNormals[pIndex + 1],inNormals[pIndex + 2] });

			outIndices.push_back(outVerties.size() / 3);


			outVerties.push_back(inVerties[pIndex]);
			outVerties.push_back(inVerties[pIndex + 1]);
			outVerties.push_back(inVerties[pIndex + 2]);

			outNormals.push_back(inNormals[pIndex]);
			outNormals.push_back(inNormals[pIndex + 1]);
			outNormals.push_back(inNormals[pIndex + 2]);
		}
	}
	//由于前面的的法向都是直接加进去的,所以这里把法向取成单位向量即可
	size_t size = outNormals.size();
	for (size_t i = 0; i < size-2; i+=3)
	{
		Normalized(&outNormals[i]);
	}

最后不保证这代码没有bug

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值