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

📄 3ds.h

📁 粒子效果演示(附代码) 利用C++所提供的一些标准容器很容易实现粒子效果. 简单的说就是,将粒子数据写在一个类里面,有一个粒子源,不停地生成粒子,然后放入一个stl::list中(push
💻 H
📖 第 1 页 / 共 3 页
字号:
  int index = 0;

  // 读入一个字节的数据
  fread(pBuffer, 1, 1, m_FilePointer);

  // 直到结束
  while (*(pBuffer + index++) != 0) {

    // 读入一个字符直到NULL
    fread(pBuffer + index, 1, 1, m_FilePointer);
  }

  // 返回字符串的长度
  return strlen(pBuffer) + 1;
}

// 下面的函数读入RGB颜色
void CLoad3DS::ReadColorChunk(tMaterialInfo *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 CLoad3DS::ReadVertexIndices(t3DObject *pObject, tChunk *pPreviousChunk)
{
  unsigned short index = 0;          // 用于读入当前面的索引

  // 读入该对象中面的数目
  pPreviousChunk->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++)
    {
      // 读入当前面的第一个点 
      pPreviousChunk->bytesRead += fread(&index, 1, sizeof(index), m_FilePointer);

      if(j < 3)
      {
        // 将索引保存在面的结构中
        pObject->pFaces[i].vertIndex[j] = index;
      }
    }
  }
}

// 下面的函数读入对象的UV坐标
void CLoad3DS::ReadUVCoordinates(t3DObject *pObject, tChunk *pPreviousChunk)
{
  // 为了读入对象的UV坐标,首先需要读入UV坐标的数量,然后才读入具体的数据

  // 读入UV坐标的数量
  pPreviousChunk->bytesRead += fread(&pObject->numTexVertex, 1, 2, m_FilePointer);

  // 分配保存UV坐标的内存空间
  pObject->pTexVerts = new CVector2 [pObject->numTexVertex];

  // 读入纹理坐标
  pPreviousChunk->bytesRead += fread(pObject->pTexVerts, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
}

// 读入对象的顶点
void CLoad3DS::ReadVertices(t3DObject *pObject, tChunk *pPreviousChunk)
{
  // 在读入实际的顶点之前,首先必须确定需要读入多少个顶点。
  
  // 读入顶点的数目
  pPreviousChunk->bytesRead += fread(&(pObject->numOfVerts), 1, 2, m_FilePointer);

  // 分配顶点的存储空间,然后初始化结构体
  pObject->pVerts = new CVector3 [pObject->numOfVerts];
  memset(pObject->pVerts, 0, sizeof(CVector3) * pObject->numOfVerts);

  // 读入顶点序列
  pPreviousChunk->bytesRead += fread(pObject->pVerts, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);

  // 现在已经读入了所有的顶点。
  // 因为3D Studio Max的模型的Z轴是指向上的,因此需要将y轴和z轴翻转过来。
  // 具体的做法是将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 CLoad3DS::ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk)
{
  char strMaterial[255] = {0};      // 用来保存对象的材质名称
  int buffer[50000] = {0};        // 用来读入不需要的数据

  // 材质或者是颜色,或者是对象的纹理,也可能保存了象明亮度、发光度等信息。

  // 下面读入赋予当前对象的材质名称
  pPreviousChunk->bytesRead += GetString(strMaterial);

  // 遍历所有的纹理
  for(int i = 0; i < pModel->numOfMaterials; i++)
  {
    //如果读入的纹理与当前的纹理名称匹配
    if(strcmp(strMaterial, pModel->pMaterials[i].strName) == 0)
    {
      // 设置材质ID
      pObject->materialID = i;

      // 判断是否是纹理映射,如果strFile是一个长度大于1的字符串,则是纹理
      if(strlen(pModel->pMaterials[i].strFile) > 0) {
        //载入纹理
        BuildTexture(pModel->pMaterials[i].strFile, pModel->texture[pObject->materialID]);
		// 设置对象的纹理映射标志
        pObject->bHasTexture = true;
      }  
      break;
    }
    else
    {
      // 如果该对象没有材质,则设置ID为-1
      pObject->materialID = -1;
    }
  }

  pPreviousChunk->bytesRead += fread(buffer, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
}      

// 下面的这些函数主要用来计算顶点的法向量,顶点的法向量主要用来计算光照
// 下面的宏定义计算一个矢量的长度
#define Mag(Normal) (sqrt(Normal.x*Normal.x + Normal.y*Normal.y + Normal.z*Normal.z))

// 下面的函数求两点决定的矢量
CVector3 Vector(CVector3 vPoint1, CVector3 vPoint2)
{
  CVector3 vVector;              

  vVector.x = vPoint1.x - vPoint2.x;      
  vVector.y = vPoint1.y - vPoint2.y;      
  vVector.z = vPoint1.z - vPoint2.z;      

  return vVector;                
}

// 下面的函数两个矢量相加
CVector3 AddVector(CVector3 vVector1, CVector3 vVector2)
{
  CVector3 vResult;              
  
  vResult.x = vVector2.x + vVector1.x;    
  vResult.y = vVector2.y + vVector1.y;    
  vResult.z = vVector2.z + vVector1.z;    

  return vResult;                
}

// 下面的函数处理矢量的缩放
CVector3 DivideVectorByScaler(CVector3 vVector1, float Scaler)
{
  CVector3 vResult;              
  
  vResult.x = vVector1.x / Scaler;      
  vResult.y = vVector1.y / Scaler;      
  vResult.z = vVector1.z / Scaler;      

  return vResult;                
}

// 下面的函数返回两个矢量的叉积
CVector3 Cross(CVector3 vVector1, CVector3 vVector2)
{
  CVector3 vCross;                
                        
  vCross.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y));
                        
  vCross.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z));
                        
  vCross.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x));

  return vCross;                
}

// 下面的函数规范化矢量
CVector3 Normalize(CVector3 vNormal)
{
  double Magnitude;              

  Magnitude = Mag(vNormal);          // 获得矢量的长度

  vNormal.x /= (float)Magnitude;        
  vNormal.y /= (float)Magnitude;        
  vNormal.z /= (float)Magnitude;        

  return vNormal;                
}

// 下面的函数用于计算对象的法向量
void CLoad3DS::ComputeNormals(t3DModel *pModel)
{
  CVector3 vVector1, vVector2, vNormal, vPoly[3];

  // 如果模型中没有对象,则返回
  if(pModel->numOfObjects <= 0)
    return;

  // 遍历模型中所有的对象
  for(int index = 0; index < pModel->numOfObjects; index++)
  {
    // 获得当前的对象
    t3DObject *pObject = &(pModel->pObject[index]);

    // 分配需要的存储空间
    CVector3 *pNormals    = new CVector3 [pObject->numOfFaces];
    CVector3 *pTempNormals  = new CVector3 [pObject->numOfFaces];
    pObject->pNormals    = new CVector3 [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 = Vector(vPoly[0], vPoly[2]);    // 获得多边形的矢量
      vVector2 = Vector(vPoly[2], vPoly[1]);    // 获得多边形的第二个矢量

      vNormal = Cross(vVector1, vVector2);    // 获得两个矢量的叉积
      pTempNormals[i] = vNormal;          // 保存非规范化法向量
      vNormal = Normalize(vNormal);        // 规范化获得的叉积

      pNormals[i] = vNormal;            // 将法向量添加到法向量列表中
    }

    // 下面求顶点法向量
    CVector3 vSum = {0.0, 0.0, 0.0};
    CVector3 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 = AddVector(vSum, pTempNormals[j]);
          shared++;                
        }
      } 
      
      pObject->pNormals[i] = DivideVectorByScaler(vSum, float(-shared));

      // 规范化最后的顶点法向
      pObject->pNormals[i] = Normalize(pObject->pNormals[i]);  

      vSum = vZero;                
      shared = 0;                    
    }
  
    // 释放存储空间,开始下一个对象
    delete [] pTempNormals;
    delete [] pNormals;
  }
}

⌨️ 快捷键说明

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