xatlas源码解析(三)

这一章讲解当模型不参考本身的uv的情况:继续上一章AddMesh过程的讲解,AddMesh中将模型的数据组织为atlas内部的数据,并且是原始数据的拷贝,而不是引用,并将mesh交给了子线程处理。

// atlas中添加mesh【顶点、法线、uv】
AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint)
{
	......

	// 获取一个任务组句柄
	if (ctx->addMeshTaskGroup.value == UINT32_MAX)  
		ctx->addMeshTaskGroup = ctx->taskScheduler->createTaskGroup(ctx);

	// 创建一个任务,并将任务与任务处理函数绑定,方便后续线程处理
	internal::Task task;
	task.userData = mesh;
	task.func = runAddMeshTask;

	// 将任务添加到这个任务组中
	ctx->taskScheduler->run(ctx->addMeshTaskGroup, task);
	// 添加成功
	return AddMeshError::Success;
}

上面的过程中将 task.userData = mesh; 将mesh给了一个子任务,并且调度run了一下:

// 运行任务
	void run(TaskGroupHandle handle, const Task &task)
	{
		XA_DEBUG_ASSERT(handle.value != UINT32_MAX);
		// 获取任务,锁定处理,
		TaskGroup &group = m_groups[handle.value];
		group.queueLock.lock();
		group.queue.push_back(task);   // 任务队列
		group.queueLock.unlock();
		group.ref++;    // 任务数量递增

		// Wake up a worker to run this task.  唤醒所有的任务处理线程
		for (uint32_t i = 0; i < m_workers.size(); i++) {
			// 设置唤醒标志
			m_workers[i].wakeup = true;
			// 通知线程运行
			m_workers[i].cv.notify_one();   
		}
	}

上面的过程就是将任务放到任务队列当中,同时将线程在阻塞状态变为运行状态,线程运行后会执行,任务绑定的处理函数runAddMeshTask,

// 线程函数
	static void workerThread(TaskScheduler *scheduler, Worker *worker, uint32_t threadIndex)
	{
		// 当前形成索引
		m_threadIndex = threadIndex;
		// 锁定
		std::unique_lock<std::mutex> lock(worker->mutex);
		// 处理过程
		for (;;) {
			// 等待通知信号,检测wakeup是否为true,如果为true就等通知了,通知了就下运行
			worker->cv.wait(lock, [=]{ return worker->wakeup.load(); });
			// 设置为false,下一次循环会变为阻塞
			worker->wakeup = false;

			for (;;) {
				if (scheduler->m_shutdown)  // 线程停止了
					return;

				// Look for a task in any of the groups and run it.
				// 查找任务并执行
				TaskGroup *group = nullptr;
				Task *task = nullptr;
				for (uint32_t i = 0; i < scheduler->m_maxGroups; i++) {
					// 获取一个任务组
					group = &scheduler->m_groups[i];
					if (group->free || group->ref == 0)  // 没有任务
						continue;

					// 锁定队列
					group->queueLock.lock();
					// 遍历任务队列
					if (group->queueHead < group->queue.size()) {
						// 拿出一个任务
						task = &group->queue[group->queueHead++];
						// 解锁队列
						group->queueLock.unlock();
						break;
					}
					// 解锁队列
					group->queueLock.unlock();
				}
				// 如果任务不存在
				if (!task)
					break;
				// 处理任务【组数据,用户数据】
				task->func(group->userData, task->userData);
				// 处理完成后递减
				group->ref--;
			}
		}
	}
};

runAddMeshTask的处理如下:

//addmesh后的的处理,查询三角面有公共顶点的过程,有功能顶点就将他们串联起来
	void createColocals()
	{
		if (m_epsilon <= FLT_EPSILON)
			createColocalsHash();
		else
			createColocalsBVH();  
	}
// 使用hash的方式串联重复的索引
	void createColocalsHash()
	{
		// 顶点数量
		const uint32_t vertexCount = m_positions.size();
		// 顶点哈希
		HashMap<Vector3> positionToVertexMap(MemTag::Default, vertexCount);
		// 每一个顶点对应一个<顶点,哈希值>,相同哈希值,相同的点处理??
		for (uint32_t i = 0; i < vertexCount; i++)
			positionToVertexMap.add(m_positions[i]);

		// 临时存储查重数据
		Array<uint32_t> colocals(MemTag::MeshColocals);
		// 将相同的顶点按照升序的方式串联起来
		m_nextColocalVertex.resize(vertexCount);
		m_nextColocalVertex.fillBytes(0xff);   // 填充无效数据

		m_firstColocalVertex.resize(vertexCount);
		m_firstColocalVertex.fillBytes(0xff);  // 填充无效数据

		for (uint32_t i = 0; i < vertexCount; i++) {

			if (m_nextColocalVertex[i] != UINT32_MAX)
				continue; // Already linked.  已经连接了

			// Find other vertices colocal to this one.
			// 找到与此顶点共轴的其他顶点
			colocals.clear();
			colocals.push_back(i); // Always add this vertex.  已经添加了这个顶点

			// otherVertex是m_positions[i]在positionToVertexMap中keys、next的位置
			uint32_t otherVertex = positionToVertexMap.get(m_positions[i]);
			while (otherVertex != UINT32_MAX) {  // 有重复的坐标
				if (otherVertex != i && equal(m_positions[i], m_positions[otherVertex], m_epsilon) && m_nextColocalVertex[otherVertex] == UINT32_MAX)
					colocals.push_back(otherVertex);   // 添加一个索引
				// 获取下一个相同的哈希值的坐标的位置
				otherVertex = positionToVertexMap.getNext(m_positions[i], otherVertex);
			}

			if (colocals.size() == 1) {   // 只有一个相同的值
				// No colocals for this vertex.  第一个和下一个都指向一个
				m_nextColocalVertex[i] = i;
				m_firstColocalVertex[i] = i;
				continue;
			}

			// Link in ascending order.   相同的顶点值按照其在内存中的位置索引升序排序
			insertionSort(colocals.data(), colocals.size());

			for (uint32_t j = 0; j < colocals.size(); j++) {
				// 将相同的顶点索引位置,按照升序串联起来
				m_nextColocalVertex[colocals[j]] = colocals[(j + 1) % colocals.size()];
				m_firstColocalVertex[colocals[j]] = colocals[0];    // 
			}
			XA_DEBUG_ASSERT(m_nextColocalVertex[i] != UINT32_MAX);
		}
	}

以以上是AddMesh的过程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值