游戏开发论坛

 找回密码
 立即注册
搜索
查看: 11090|回复: 23

自己研究的一个场景物体剔除方法

[复制链接]

14

主题

283

帖子

293

积分

中级会员

Rank: 3Rank: 3

积分
293
QQ
发表于 2005-4-16 23:38:00 | 显示全部楼层 |阅读模式
场景剔除方法
首先将场景划分成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<p2.x)
        {
                StartX=p1.x;
                EndX=p2.x;
                if(StartX>p3.x)
                {
                        StartX=p3.x;
                }
                else
                {
                        if(EndX<p3.x)
                        {
                                EndX=p3.x;
                        }
                }
        }
        else
        {
                StartX=p2.x;
                EndX=p1.x;
                if(StartX>p3.x)
                {
                        StartX=p3.x;
                }
                else
                {
                        if(EndX<p3.x)
                        {
                                EndX=p3.x;
                        }
                }
        }
        if(p1.y<p2.y)
        {
                StartZ=p1.y;
                EndZ=p2.y;
                if(StartZ>p3.y)
                {
                        StartZ=p3.y;
                }
                else
                {
                        if(EndZ<p3.y)
                        {
                                EndZ=p3.y;
                        }
                }
        }
        else
        {
                StartZ=p2.y;
                EndZ=p1.y;
                if(StartZ>p3.y)
                {
                        StartZ=p3.y;
                }
                else
                {
                        if(EndZ<p3.y)
                        {
                                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<EndZ;i++)
        {
                for(int j=StartX;j<EndX;j++)
                {
                        if(Area[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[j];//这个数组就是保存区域链表的数组Area[0

][0]就保存的第0,0区域的链表
                                                pNode=m_pCulledObject;
                                        }
                                        else
                                        {
                                                pNode->m_pNext=new

PObjectList();
                                                pNode=pNode->m_pNext;
                                                pNode->m_pObjectList=Area[j];
                                        }
                                }
                        }
                       
                }
        }
}
sf_2005416233830.jpg

14

主题

283

帖子

293

积分

中级会员

Rank: 3Rank: 3

积分
293
QQ
 楼主| 发表于 2005-4-16 23:49:00 | 显示全部楼层

Re:自己研究的一个场景物体剔除方法

忘了说了,AtoR()是自定义的将角度转成弧度的函数

190

主题

1801

帖子

2096

积分

金牌会员

Rank: 6Rank: 6

积分
2096
QQ
发表于 2005-4-17 00:51:00 | 显示全部楼层

Re:自己研究的一个场景物体剔除方法

我也用类似的方法
不过要查所有的方块也不是件很轻松的事
我又分了cell和portal

14

主题

283

帖子

293

积分

中级会员

Rank: 3Rank: 3

积分
293
QQ
 楼主| 发表于 2005-4-17 01:40:00 | 显示全部楼层

Re:自己研究的一个场景物体剔除方法

不需要查所有方块的啊,按照摄象机三角形,可以算出一个大致范围,然后在这个小范围内判断方快是否在三角形内,计算量还是不大的
而且这个方块是合适大小的,也就是说,不会分的很多,大概也就是在平视的时候有20-30个方块可视,这样,真的要判断的方块也就在60-80个左右了.一次判断80个点是否在一个三角形内,还是很快的

132

主题

1341

帖子

1341

积分

金牌会员

Rank: 6Rank: 6

积分
1341
发表于 2005-4-17 11:27:00 | 显示全部楼层

Re:自己研究的一个场景物体剔除方法

请问为什么要自己做剔除,图形引擎没有这个功能吗?

14

主题

131

帖子

136

积分

注册会员

Rank: 2

积分
136
发表于 2005-4-17 11:46:00 | 显示全部楼层

Re:自己研究的一个场景物体剔除方法

我觉得应该使用树性结构,效率高

14

主题

283

帖子

293

积分

中级会员

Rank: 3Rank: 3

积分
293
QQ
 楼主| 发表于 2005-4-17 11:54:00 | 显示全部楼层

Re:自己研究的一个场景物体剔除方法

树性结构不没这个快,他得一层一层的往下查询,而且处理两个树接点之间物体的移动比较麻烦

14

主题

283

帖子

293

积分

中级会员

Rank: 3Rank: 3

积分
293
QQ
 楼主| 发表于 2005-4-17 11:56:00 | 显示全部楼层

Re:自己研究的一个场景物体剔除方法

5楼说的对,引擎基本都提供这个功能
单我的目标是自己做引擎~呵呵,自己设计更好的算法更好的引擎

132

主题

1341

帖子

1341

积分

金牌会员

Rank: 6Rank: 6

积分
1341
发表于 2005-4-17 12:14:00 | 显示全部楼层

Re:自己研究的一个场景物体剔除方法

是基于DirectX或OpenGL的引擎,还是完全自己做?

2

主题

70

帖子

70

积分

注册会员

Rank: 2

积分
70
发表于 2005-4-17 12:23:00 | 显示全部楼层

Re:自己研究的一个场景物体剔除方法

这样一来,就没法剔除不同高度的对象了。

八叉数仍然是3D空间对象剔除的普遍算法。这种算法也是很多专家推荐的,在户内,户外都能很好的工作。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-27 17:02

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表