您现在的位置: 中国IT实验室 >> 游戏开发 >> 开发文档 >> 文章正文
自己研究的一个场景物体剔除方法
来源:ChinaITLab 收集整理 作者: 时间:2005-4-22


  场景剔除方法
  
  首先将场景划分成N*M个等大的矩形区域,推荐正方形,每个区域有一个链表保存这个区域上的所有物体,然后用一个N*M的二维数组保存这些指针。进行视锥剔除的时候,首先根据摄象机的参数得到一个近似的三角形(三角形指的是可视区域在XZ平面上的投影区域),算出三角形三个顶点的坐标,然后利用三个顶点坐标可以算出在这个三角形内的,刚才划分的区域,然后将这些区域的链表拼接就得到了所有可见物体。
  
  基于这个方法,区域之间有物体跨越的话,可以很方便的对这两个区域链表处理,保证剔除不出错。
  
  原理简单,下面是代码实现
  
  bool IsInTriangle2D(D3DXVECTOR2 p1,D3DXVECTOR2 p2,D3DXVECTOR2 p3,D3DXVECTOR2 p,float Precision)//判断点p是否在点p1,p2,p3的三角形内,Precision是允许的误差范围,值越大,表示允许超出三角形的距离越大
  {
  double a=p2.x-p1.x,b=p3.x-p1.x,c=p2.y-p1.y,d=p3.y-p1.y;
  double u=(a*(p.y-p1.y)/c+p1.x-p.x)/(a*d/c-b);
  double v=(b*(p.y-p1.y)/d+p1.x-p.x)/(b*c/d-a);
  if(u>=-Precision&&v>=-Precision&&u+v<=1+2*Precision)return true;
  else
  return false;
  }
  
  void CCuller::ViewCull()
  {
  if(!m_isCull)return;//是否打开剔除
  PObjectList* pNode=m_pCulledObject;//保存剔除后的物体
  if(pNode!=NULL)//每次剔除的时候先删除上次剔除保留的链表
  {
  while(pNode->m_pNext!=NULL)
  {
  pNode=pNode->m_pNext;
  delete m_pCulledObject;
  m_pCulledObject=pNode;
  }
  delete m_pCulledObject;
  m_pCulledObject=NULL;
  }
  float Distance=m_pCamera->GetDistance();//获得摄象机的观察距离,求近似三角形
  float Angle=m_pCamera->GetAngleH()-90;//这个不用管,只是我自己游戏中的一个角度转换问题
  static D3DXVECTOR2 p1,p2,p3;
  int StartX,StartZ,EndX,EndZ;
  
  //根据摄象机算出可视范围近似三角形的三个顶点
  p1.x=m_pCamera->GetPosition().x/CULL_RECT_WIDTH;//除以区域长宽的目的是将一个区域作为一个点来看
  p1.y=m_pCamera->GetPosition().z/CULL_RECT_LONG;//可以理解我们划分的区域为一个像素,
  p2.x=cos(AtoR(Angle+22.5))*Distance/CULL_RECT_WIDTH+p1.x;//观察范围的三角形也就是以这些像素表示的三角形了
  p2.y=sin(AtoR(Angle+22.5))*Distance/CULL_RECT_LONG+p1.y;//这个不理解也不要紧,这些不是关键
  p3.x=cos(AtoR(Angle-22.5))*Distance/CULL_RECT_WIDTH+p1.x;
  p3.y=sin(AtoR(Angle-22.5))*Distance/CULL_RECT_LONG+p1.y;
  //根据p1,p2,p3算出区域数组下标的范围
  if(p1.x  {
  StartX=p1.x;
  EndX=p2.x;
  if(StartX>p3.x)
  {
  StartX=p3.x;
  }
  else
  {
  if(EndX  {
  EndX=p3.x;
  }
  }
  }
  else
  {
  StartX=p2.x;
  EndX=p1.x;
  if(StartX>p3.x)
  {
  StartX=p3.x;
  }
  else
  {
  if(EndX  {
  EndX=p3.x;
  }
  }
  }
  if(p1.y  {
  StartZ=p1.y;
  EndZ=p2.y;
  if(StartZ>p3.y)
  {
  StartZ=p3.y;
  }
  else
  {
  if(EndZ  {
  EndZ=p3.y;
  }
  }
  }
  else
  {
  StartZ=p2.y;
  EndZ=p1.y;
  if(StartZ>p3.y)
  {
  StartZ=p3.y;
  }
  else
  {
  if(EndZ  {
  EndZ=p3.y;
  }
  }
  }
  
  //确保范围没超出地图,确保观察范围超出地图范围不出错
  if(StartX<0)
  {
  StartX=0;
  }
  if(EndX>CULL_SIZE_WIDTH)
  {
  EndX=CULL_SIZE_WIDTH;
  }
  
  if(StartZ<0)
  {
  StartZ=0;
  }
  if(EndZ>CULL_SIZE_LONG)
  {
  EndZ=CULL_SIZE_LONG;
  }
  for(int i=StartZ;i  {
  for(int j=StartX;j  {
  if(Area[i][j]->m_pObject!=NULL)
  {
  D3DXVECTOR2 p,pp1,pp2,pp3;
  p.x=j;
  p.y=i;
  pp1=p-p1;
  pp2=p-p2;
  pp3=p-p3;
  if(IsInTriangle2D(p1,p2,p3,p,0.038))////判断该点是否在三角形中,小于0为在三角形中,大于0外不在三角形中
  {
  if(m_pCulledObject==NULL)
  {
  m_pCulledObject=new PObjectList();
  
  m_pCulledObject->m_pObjectList=Area[i][j];//这个数组就是保存区域链表的数组Area[0][0]就保存的第0,0区域的链表
  pNode=m_pCulledObject;
  }
  else
  {
  pNode->m_pNext=new PObjectList();
  pNode=pNode->m_pNext;
  pNode->m_pObjectList=Area[i][j];
  }
  }
  }
  
  }
  }
  }
  
  
收藏本文 责编:admin 


相关文章
游戏开发新手入门之Windows编程
教你实现卡通渲染的另类勾边方法
Lua的function、closure和upvalue
Visual C#编写 3D游戏框架示例
真正的 Java 学习从入门到精通
推荐文章


 精彩友情推荐
·神州数码交换机
·神州数码交换机价格
·神州数码网络交换机
·netgear交换机
·网件交换机
·IDC资讯大全
·机房品质万里行
·IDC托管必备知识
·全国IDC报价
·网站推广优化
 基础入门  开发文档
 最新推荐
  多数的Windows程序都需要Windows.h和Windowsx.h这两个头文件,要确保使用它们。当然,你还需要其它......
游戏引擎演化史
在Windows上安装OGRE的方法
关于滤镜遮罩概念,Sobel 遮罩
游戏开发新手入门之Windows编程
游戏开发新手入门之位图化图形
教你实现卡通渲染的另类勾边方法
游戏设计大师谈如何成为一名游戏设
Visual C#编写 3D游戏框架示例
真正的 Java 学习从入门到精通
游戏开发经验——游戏开发的基本常
  针对于移动新出台的政策,需要尽快地把我们公司的游戏对应到不同的手机平台,这是针对市场策略的有利调整............
Quake-III代码里神奇的浮点开方函数
基于Dialogue的MFC程序调用DirectX
关于Kjava手机平台移植可行性报告
网络游戏的数据传输处理和防火墙穿
浅谈网游的数据传输处理和防火墙穿
向量几何在游戏编程中的使用(六)
向量几何在游戏编程中的使用(五)
向量几何在游戏编程中的使用(四)
向量几何在游戏编程中的使用(三)
向量几何在游戏编程中的使用(二)
  培训中心