xatlas源码解析(二)

在进行xatlas分析之前,先说说xatlas将模型加载到内存后的数据组织方式,代码如下:

typedef struct {
	uint32_t flags;				// flags代表网格索引数是否超过65535
	// uint32_t if OBJZ_FLAG_INDEX32 flag is set, otherwise uint16_t.
	// See: objz_setIndexFormat
	void *indices;				// 所有的面索引buffer
	uint32_t numIndices;		// 面索引数量
	objzMaterial *materials;	// 所有的材质buffer
	uint32_t numMaterials;		// 材质数量
	objzMesh *meshes;			// 所有的网格buffer
	uint32_t numMeshes;			// 网格数量
	objzObject *objects;		// 所有对象的buffer
	uint32_t numObjects;		// 对象数量
	void *vertices; // See: objz_setVertexFormat	// 所有的顶点buffer
	uint32_t numVertices;							// 顶点数量
} objzModel;

可以看到,xatlas将模型格式化成内部结构,比较简单,便于以后的查找和访问,需要注意一个mesh中不同的面可能使用了不同的材质,上面结构中的meshs是按照材质划分的mesh,object不是按照材质划分,而是按照mesh划分的。

网格内的数据填充完成后,s_atlas.thread = new std::thread(atlasGenerateThread);就开始在线程中处理这些数据,因为界面中有一个useUvMesh标记,是否使用mesh原有的uv,所以后续的处理过程分为两种情况对待,对于使用uv的将mesh添加到 xatlas::AddUvMesh,不使用uv的调用xatlas::AddMesh,代码如下:

// 构建图集线程
static void atlasGenerateThread()
{
	// 获取模型数据
	const objzModel *model = modelGetData();
	// 第一次构建【如果data==null】
	const bool firstRun = !s_atlas.data;
	// 开始时间
	const clock_t startTime = clock();

#if USE_MIMALLOC
	if (firstRun)
		xatlas::SetAlloc(mi_realloc);   // 设置内存申请函数
#endif

	// Create xatlas context and add meshes on first run only, unless uv mesh option has changed.
	// 第一次或者是否使用uv改变了
	if (firstRun || s_atlas.useUvMeshChanged) {

		//之前展开过,这一次使用uv选项改变了
		if (s_atlas.useUvMeshChanged && s_atlas.data) {
			// 销毁数据
			xatlas::Destroy(s_atlas.data);
			s_atlas.data = nullptr;
		}

		// 申请在uv展开的过程当中使用的内存,并初始化,同时创建了整个处理过程所使用的调度线程、任务队列
		s_atlas.data = xatlas::Create();
		// 设置处理进程回调
		xatlas::SetProgressCallback(s_atlas.data, atlasProgressCallback);

		// 需要忽略的面(忽略自发光、透明材质的面)
		std::vector<uint8_t> ignoreFaces;			 // Should be bool, workaround stupid C++ specialization.
		std::vector<uint32_t> faceMaterials;		// 面材质

		// 遍历模型【一个模型会有多个对象,每一个对象按照不同部分的材质会产生不同的mesh】
		for (uint32_t i = 0; i < model->numObjects; i++) {
			// 获取一个模型
			const objzObject &object = model->objects[i];
			// 【模型的顶点都存储在了model的一个大缓存中】,每一个对象只是存储了一个偏移量
			auto v = &((const ModelVertex *)model->vertices)[object.firstVertex];

			// Ignore faces with an emissive or transparent material.
			// 忽略自发光、透明材质的面
			// 设置ignoreFace的大小,填充0数据
			ignoreFaces.resize(object.numIndices / 3);
			memset(ignoreFaces.data(), 0, ignoreFaces.size() * sizeof(uint8_t));

			// 遍历mesh数量收集需要忽略的面【一个对象上有多个子材质】
			for (uint32_t j = 0; j < object.numMeshes; j++) {
				// 获取一个mesh
				const objzMesh &mesh = model->meshes[object.firstMesh + j];
				// 获取材质,有可能存在无材质的面
				const objzMaterial *mat = mesh.materialIndex == -1 ? nullptr : &model->materials[mesh.materialIndex];
				//材质使用了自发光
				if (mat && (mat->emission[0] > 0.0f || mat->emission[1] > 0.0f || mat->emission[2] > 0.0f || mat->opacity < 1.0f)) {
					for (uint32_t k = 0; k < mesh.numIndices / 3; k++)
						ignoreFaces[(mesh.firstIndex - object.firstIndex) / 3 + k] = true;  // 每一个mesh的面??【多余的遍历,直接设置面全部为true】
				}
			}

			// AddMesh时产生的各种错误
			xatlas::AddMeshError error;
			// 使用uvmesh【模型原来有uv坐标】
			if (s_atlas.useUvMesh)
			{
				// Set face materials so charts are detected correctly with overlapping UVs.
				// 收集每一个面的材质,以便使用重叠UV正确检测chart。
				faceMaterials.resize(object.numIndices / 3);   
				// 遍历mesh数量【一个对象上有多个材质】
				for (uint32_t j = 0; j < object.numMeshes; j++) {
					// 获取一个mesh
					const objzMesh &mesh = model->meshes[object.firstMesh + j];
					// 这些面共用了一个材质
					for (uint32_t k = 0; k < mesh.numIndices / 3; k++)
						faceMaterials[(mesh.firstIndex - object.firstIndex) / 3 + k] = (uint32_t)mesh.materialIndex;
				}

				// 按照原始数据的object组织成一个UvMeshDecl,添加到s_atlas.data中
				xatlas::UvMeshDecl meshDecl;
				meshDecl.faceMaterialData = faceMaterials.data();		// 某一个对象的面材质数据
				meshDecl.vertexCount = object.numVertices;				// 某一个对象的顶点数量
				meshDecl.vertexUvData = &v->texcoord;					// 某一个对象的纹理坐标buffer
				meshDecl.vertexStride = sizeof(ModelVertex);			// 顶点属性步长
				meshDecl.indexCount = object.numIndices;				// mesh索引数量
				meshDecl.indexData = &((uint32_t *)model->indices)[object.firstIndex];	//索引数据
				meshDecl.indexFormat = xatlas::IndexFormat::UInt32;		// 索引格式
				meshDecl.indexOffset = -(int32_t)obje
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值