闲着没事,把之前做CASCADE SHADOWMAP时弄的一个视锥类放上来,若有更闲者点评点评,感激。——ZwqXin.com
这个类其实作用更在于把场景中的真实视锥在渲染窗口里画出来。这样在调试一些与摄象机相关的效果时挺有用的。譬如shadowmap中,光源视觉下“光源所看到的世界”,通过画出其视锥就一清二楚了。
- #include "Vector3.h"
- #define PI 3.1415926
- class CFrustum
- {
- public:
- CFrustum();
- CFrustum(GLfloat _fov, GLfloat _ratio, GLfloat d_near, GLfloat d_far);
- ~CFrustum();
- inline void ReshapeFov(GLfloat _fov){fov = _fov;};
- inline void ReshapeRatio(GLfloat _ratio){ratio = _ratio;};
- inline void ResightNear(GLfloat d_near){distance_near = d_near;};
- inline void ResightFar(GLfloat d_far){distance_far = d_far;};
- void UpdateFrustum(CVector3 &viewpos, CVector3 &viewdir, CVector3 &viewupvec);
- void DrawFrustum(bool linemode, Color col, CVector3 &viewpos, bool nearPlane = false, bool farPlane = false);
- inline GLfloat GetFov() {return fov; };
- inline GLfloat GetRatio(){return ratio; };
- inline GLfloat GetNear(){return distance_near; };
- inline GLfloat GetFar() {return distance_far; };
- CVector3 GetPoint(GLuint index);
- private:
- GLfloat distance_near;
- GLfloat distance_far;
- GLfloat fov;
- GLfloat ratio;
- CVector3 point[8];
- };
成员变量除了point[8]指示作图相关的8个点外,都是gluPerspective的参数一致的。在初始化实例的时候指定。成员函数基本都是自解释的,UpdateFrustum用于在每帧末尾更新视锥,DrawFrustum则是把视锥画出来。
- void CFrustum::UpdateFrustum(CVector3 &viewpos, CVector3 &viewdir, CVector3 &viewupvec)
- {
- CVector3 rightvector = viewdir.CrossProd(viewupvec);
- rightvector = rightvector.normalize();
- CVector3 new_upvector = rightvector.CrossProd(viewdir);
- new_upvector = new_upvector.normalize();
- GLfloat radian_fov = GLfloat(fov * PI/180.0f) ;
- GLfloat Half_near_height = distance_near * (GLfloat)tan(radian_fov/2.0f);
- GLfloat Half_near_width = Half_near_height * ratio;
- GLfloat Half_far_height = distance_far * (GLfloat)tan(radian_fov/2.0f);
- GLfloat Half_far_width = Half_far_height * ratio;
- CVector3 near_clip_center = viewpos + viewdir * distance_near;
- CVector3 far_clip_center = viewpos + viewdir * distance_far;
- point[0] = near_clip_center - new_upvector*Half_near_height - rightvector*Half_near_width;
- point[1] = near_clip_center - new_upvector*Half_near_height + rightvector*Half_near_width;
- point[2] = near_clip_center + new_upvector*Half_near_height + rightvector*Half_near_width;
- point[3] = near_clip_center + new_upvector*Half_near_height - rightvector*Half_near_width;
- point[4] = far_clip_center - new_upvector*Half_far_height - rightvector*Half_far_width;
- point[5] = far_clip_center - new_upvector*Half_far_height + rightvector*Half_far_width;
- point[6] = far_clip_center + new_upvector*Half_far_height + rightvector*Half_far_width;
- point[7] = far_clip_center + new_upvector*Half_far_height - rightvector*Half_far_width;
- }
UpdateFrustum的输入参数也就是相机的那几个参数了——如果更新相机,则视锥也应该要更新。输出的是用于作图的几个关键点位置。
- void CFrustum::DrawFrustum(bool linemode, Color col, CVector3 &viewpos, bool nearPlane, bool farPlane)
- {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_LIGHTING);
- if(linemode)glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glPushMatrix();
- glColor4f(col.r, col.g, col.b, 0.3f);
- glLineWidth(1.0);
- glPointSize(10);
- if(nearPlane)
- {
- glBegin(GL_QUADS);
- for(int j=0; j<4; j++)
- glVertex3d(point[j].x, point[j].y, point[j].z);
- glEnd();
- }
- if(farPlane)
- {
- glBegin(GL_QUADS);
- for(int i=4; i<8; i++)
- glVertex3d(point[i].x, point[i].y, point[i].z);
- glEnd();
- }
- for(int k=0; k<3; k++)
- {
- glBegin(GL_QUADS);
- glVertex3d(point[k].x, point[k].y, point[k].z);
- glVertex3d(point[k+4].x, point[k+4].y, point[k+4].z);
- glVertex3d(point[k+5].x, point[k+5].y, point[k+5].z);
- glVertex3d(point[k+1].x, point[k+1].y, point[k+1].z);
- glEnd();
- }
- glBegin(GL_QUADS);
- glVertex3d(point[3].x, point[3].y, point[3].z);
- glVertex3d(point[7].x, point[7].y, point[7].z);
- glVertex3d(point[4].x, point[4].y, point[4].z);
- glVertex3d(point[0].x, point[0].y, point[0].z);
- glEnd();
- for(int l=0; l<4; l++)
- {
- glBegin(GL_LINES);
- glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
- glVertex3d(viewpos.x, viewpos.y, viewpos.z);
- glVertex3d(point[l+4].x, point[l+4].y, point[l+4].z);
- glEnd();
- }
- glPopMatrix();
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glDisable(GL_BLEND);
- }
画出来的视锥会有一定透明度,是否画线框,颜色,是否画近/远平面(一般不需要了吧这个)是可调的,另外输入“相机”位置是为了通过画图指示相机所在,这个还是必须的吧......
本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
原文地址:http://www.zwqxin.cn/archives/opengl/my-frustum-class.html