⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 3dsloader.cpp

📁 通过vc++编程实现3DS格式的模型载入
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		/** 关键帧 */
		case EDITKEYFRAME:
			
			/** 跳过关键帧块的读入 */
			m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		default: 
			
			/**  跳过所有忽略的块的内容的读入 */
			m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		}
		
		/** 增加从最后块读入的字节数 */
		pPreChunk->bytesRead += m_CurrentChunk->bytesRead;
	}
	
	/** 释放当前块的内存空间 */
	delete m_CurrentChunk;
	m_CurrentChunk = pPreChunk;

}
/** 处理所有的文件中对象的信息 */
void C3DSLoader::ReadNextObjChunk(t3DModel *pModel, t3DObject *pObject, tChunk *pPreChunk)
{	
	int buffer[50000] = {0};					/** 用于读入不需要的数据 */
	
	/** 对新的块分配存储空间 */
	m_CurrentChunk = new tChunk;
	
	/** 继续读入块的内容直至本子块结束 */
	while (pPreChunk->bytesRead < pPreChunk->length)
	{	
		/** 读入下一个块 */
		ReadChunk(m_CurrentChunk);
		
		/** 区别读入是哪种块 */
		switch (m_CurrentChunk->ID)
		{
		case OBJ_MESH:					/**< 正读入的是一个新块 */
			
			/** 使用递归函数调用,处理该新块 */
			ReadNextObjChunk(pModel, pObject, m_CurrentChunk);
			break;
		case OBJ_VERTICES:				/**< 读入是对象顶点 */
			ReadVertices(pObject, m_CurrentChunk);
			break;
		case OBJ_FACES:					/**< 读入的是对象的面 */
			ReadVertexIndices(pObject, m_CurrentChunk);
			break;
		case OBJ_MATERIAL:				/**< 读入的是对象的材质名称 */
			
			/** 读入对象的材质名称 */
			ReadObjMat(pModel, pObject, m_CurrentChunk);			
			break;
		case OBJ_UV:						/**< 读入对象的UV纹理坐标 */
			/** 读入对象的UV纹理坐标 */
			ReadUVCoordinates(pObject, m_CurrentChunk);
			break;
		default:  
			/** 略过不需要读入的块 */
			m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		}
		/** 添加从最后块中读入的字节数到前面的读入的字节中 */
		pPreChunk->bytesRead += m_CurrentChunk->bytesRead;
	}
	/** 释放当前块的内存空间,并把当前块设置为前面块 */
	delete m_CurrentChunk;
	m_CurrentChunk = pPreChunk;
}
/** 处理所有的材质信息 */
void C3DSLoader::ReadNextMatChunk(t3DModel *pModel, tChunk *pPreChunk)
{	
	int buffer[50000] = {0};					/**< 用于读入不需要的数据 */
	/** 给当前块分配存储空间 */
	m_CurrentChunk = new tChunk;
	/** 继续读入这些块 */
	while (pPreChunk->bytesRead < pPreChunk->length)
	{	
		/** 读入下一块 */
		ReadChunk(m_CurrentChunk);
		/** 判断读入的是什么块 */
		switch (m_CurrentChunk->ID)
		{
		case MATNAME:							/**< 材质的名称 */
			/** 读入材质的名称 */
			m_CurrentChunk->bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strName, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		case MATDIFFUSE:						/**< 对象的R G B颜色 */
			ReadColor(&(pModel->pMaterials[pModel->numOfMaterials - 1]), m_CurrentChunk);
			break;
		case MATMAP:							/**< 纹理信息的头部 */
			/** 下一个材质块信息 */
			ReadNextMatChunk(pModel, m_CurrentChunk);
			break;
		case MATMAPFILE:						/**< 材质文件的名称 */
			/** 读入材质的文件名称 */
			m_CurrentChunk->bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strFile, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		default:  
			/** 跳过不需要读入的块 */
			m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		}
		/** 添加从最后块中读入的字节数 */
		pPreChunk->bytesRead += m_CurrentChunk->bytesRead;
	}
	/** 删除当前块,并将当前块设置为前面的块 */
	delete m_CurrentChunk;
	m_CurrentChunk = pPreChunk;
}


/** 读入RGB颜色 */
void C3DSLoader::ReadColor(tMatInfo *pMaterial, tChunk *pChunk)
{	
	/** 读入颜色块信息 */
	ReadChunk(m_TempChunk);
	/** 读入RGB颜色 */
	m_TempChunk->bytesRead += fread(pMaterial->color, 1, m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer);
	/** 增加读入的字节数 */
	pChunk->bytesRead += m_TempChunk->bytesRead;
}
/** 读入顶点索引 */
void C3DSLoader::ReadVertexIndices(t3DObject *pObject, tChunk *pPreChunk)
{	
	unsigned short index = 0;					/**< 用于读入当前面的索引 */
	/** 读入该对象中面的数目 */
	pPreChunk->bytesRead += fread(&pObject->numOfFaces, 1, 2, m_FilePointer);
	/** 分配所有面的存储空间,并初始化结构 */
	pObject->pFaces = new tFace [pObject->numOfFaces];
	memset(pObject->pFaces, 0, sizeof(tFace) * pObject->numOfFaces);
	/** 遍历对象中所有的面 */
	for(int i = 0; i < pObject->numOfFaces; i++)
	{	for(int j = 0; j < 4; j++)
		{	
			/** 读入当前面的第一个点  */
			pPreChunk->bytesRead += fread(&index, 1, sizeof(index), m_FilePointer);
			if(j < 3)
			{	
				/** 将索引保存在面的结构中 */
				pObject->pFaces[i].vertIndex[j] = index;
			}
		}
	}
}

/** 读入对象的UV坐标 */
void C3DSLoader::ReadUVCoordinates(t3DObject *pObject, tChunk *pPreChunk)
{	
	/** 读入UV坐标的数量 */
	pPreChunk->bytesRead += fread(&pObject->numTexVertex, 1, 2, m_FilePointer);
	
	/** 分配保存UV坐标的内存空间 */
	pObject->pTexVerts = new Vector2 [pObject->numTexVertex];
	
	/** 读入纹理坐标 */
	pPreChunk->bytesRead += fread(pObject->pTexVerts, 1, pPreChunk->length - pPreChunk->bytesRead, m_FilePointer);
}

/**  读入对象的顶点 */
void C3DSLoader::ReadVertices(t3DObject *pObject, tChunk *pPreChunk)
{	
	/** 读入顶点的数目 */
	pPreChunk->bytesRead += fread(&(pObject->numOfVerts), 1, 2, m_FilePointer);
	
	/** 分配顶点的存储空间,然后初始化结构体 */
	pObject->pVerts = new Vector3 [pObject->numOfVerts];
	memset(pObject->pVerts, 0, sizeof(Vector3) * pObject->numOfVerts);
	
	/** 读入顶点序列 */
	pPreChunk->bytesRead += fread(pObject->pVerts, 1, pPreChunk->length - pPreChunk->bytesRead, m_FilePointer);
	
	/** 遍历所有的顶点将Y轴和Z轴交换,然后将Z轴反向 */
	for(int i = 0; i < pObject->numOfVerts; i++)
	{	
		/** 保存Y轴的值 */
		float fTempY = pObject->pVerts[i].y;
		/** 设置Y轴的值等于Z轴的值 */
		pObject->pVerts[i].y = pObject->pVerts[i].z;
		/** 设置Z轴的值等于-Y轴的值  */
		pObject->pVerts[i].z = -fTempY;
	}
}

/** 读入对象的材质名称 */
void C3DSLoader::ReadObjMat(t3DModel *pModel, t3DObject *pObject, tChunk *pPreChunk)
{	
	char strMaterial[255] = {0};			/**< 用来保存对象的材质名称 */
	int buffer[50000] = {0};				/**< 用来读入不需要的数据 */
	
	/** 读入赋予当前对象的材质名称 */
	pPreChunk->bytesRead += GetString(strMaterial);
	
	/** 遍历所有的纹理 */
	for(int i = 0; i < pModel->numOfMaterials; i++)
	{	
		/** 如果读入的纹理与当前的纹理名称匹配 */
		if(strcmp(strMaterial, pModel->pMaterials[i].strName) == 0)
		{	
			/** 设置材质ID */
			pObject->materialID = i;
			
			/** 判断是否是纹理映射 */
			if(strlen(pModel->pMaterials[i].strFile) > 0) {
				
				/** 设置对象的纹理映射标志 */
				pObject->bHasTexture = true;
			}	
			break;
		}
		else
		{	
			/** 如果该对象没有材质,则设置ID为-1 */
			pObject->materialID = -1;
		}
	}
	pPreChunk->bytesRead += fread(buffer, 1, pPreChunk->length - pPreChunk->bytesRead, m_FilePointer);
}


/** 计算对象的法向量 */
void C3DSLoader::ComputeNormals(t3DModel *pModel)
{	
	Vector3 vVector1, vVector2, vNormal, vPoly[3];
	
	/** 如果模型中没有对象,则返回 */
	if(pModel->numOfObjects <= 0)
		return;
	
	/** 遍历模型中所有的对象 */
	for(int index = 0; index < pModel->numOfObjects; index++)
	{	
		/** 获得当前的对象 */
		t3DObject *pObject = &(pModel->pObject[index]);
		
		/** 分配需要的存储空间 */
		Vector3 *pNormals		= new Vector3 [pObject->numOfFaces];
		Vector3 *pTempNormals	= new Vector3 [pObject->numOfFaces];
		pObject->pNormals		= new Vector3 [pObject->numOfVerts];
		
		/** 遍历对象的所有面 */
		for(int i=0; i < pObject->numOfFaces; i++)
		{	vPoly[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]];
			vPoly[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]];
			vPoly[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]];
			
			/** 计算面的法向量 */
			vVector1 = vPoly[0] - vPoly[2];		        /**< 获得多边形的矢量 */
			vVector2 = vPoly[2] - vPoly[1];		        /**< 获得多边形的第二个矢量 */
			vNormal  = vVector1.crossProduct(vVector2);	/**< 计算两个矢量的叉积 */
			pTempNormals[i] = vNormal;					
			vNormal  = vNormal.normalize();				/**< 规一化叉积 */
			pNormals[i] = vNormal;						/**< 将法向量添加到法向量列表中 */
		}
		
		/** 计算顶点法向量 */
		Vector3 vSum(0.0,0.0,0.0);
		Vector3 vZero = vSum;
		int shared=0;
		
		/** 遍历所有的顶点 */
		for (i = 0; i < pObject->numOfVerts; i++)			
		{	for (int j = 0; j < pObject->numOfFaces; j++)	/**< 遍历所有的三角形面 */
			{												/**< 判断该点是否与其它的面共享 */
				if (pObject->pFaces[j].vertIndex[0] == i || 
					pObject->pFaces[j].vertIndex[1] == i || 
					pObject->pFaces[j].vertIndex[2] == i)
				{	
					vSum = vSum + pTempNormals[j];
					shared++;								
				}
			}      
			pObject->pNormals[i] = vSum / float(-shared);
			
			/** 规一化顶点法向 */
			pObject->pNormals[i] = pObject->pNormals[i].normalize();	
			vSum = vZero;								
			shared = 0;										
		}
		/** 释放存储空间,开始下一个对象 */
		delete [] pTempNormals;
		delete [] pNormals;
	}
}








⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -