视景体方程与剔除

这次来讨论一下视景体剔除的一些技巧,视景体在3d程序中是个很重要的概念,我们可以把视景体看作是一台摄像机也就是肉眼能够看到的空间.视景体以外的东西是看不到的,可以利用这点来剔除多余的模型,于是不必要的顶点将不会进入管线,这能够提高不少fps.

首先来看一下视景体是个啥东西

就是这么个六面棱锥,这是经过视图变换的样子,那么接下来应该进行投影变换,那么视景体就会变成这样

是一个立方体,范围是-1到1.(NDC坐标系)

假设空间中一点P(x,y,z,1)经过这一系列变换变成P1(x1/w1,y1/w1,z1/w1,1) 并且假设ProjectMatrix左乘ModelViewMatrix得到的第一行是(a,b,c,d),那么有

a*x+b*y+c*z+d=x1

假设变换矩阵的最后一行(e,f,g,h),那么有

e*x+f*y+g*z+h=w1

因为P1在NDC坐标系,范围是-1到1,那么在视景体左面上的点都符合x1/w1=-1,式子可以变为x1+w1=0

代入之前的等式:

a*x+b*y+c*z+d+e*x+f*y+g*z+h=0

于是得到:

(a+e)*x+(b+f)*y+(c+g)*z+(d+h)=0

一般的平面方程是:

A*x+B*y+C*z+D=0 (A,B,C)是平面的法向量

于是左侧平面的方程就是

(a+e)*x+(b+f)*y+(c+g)*z+(d+h)=0 其中的x,y,z就是空间中的点坐标

那么对应的代码就是:

    mFrustum[1][0] = clip[ 3] + clip[ 0];
    mFrustum[1][1] = clip[ 7] + clip[ 4];
    mFrustum[1][2] = clip[11] + clip[ 8];
    mFrustum[1][3] = clip[15] + clip[12];

其中的clip就是变换矩阵ModelViewProjectMatrix

clips=projs*modls;

然后对平面方程进行发现归一化,这对于求点到面的距离有好处:

	t = GLfloat(sqrt( mFrustum[0][0] * mFrustum[0][0] + mFrustum[0][1] * mFrustum[0][1] + mFrustum[0][2] * mFrustum[0][2] ));
	mFrustum[0][0] /= t;
	mFrustum[0][1] /= t;
	mFrustum[0][2] /= t;
	mFrustum[0][3] /= t;

其它5个面也这样推导,最终的代码是这样的:

GLfloat mFrustum[6][4];

void updateFrustum() {
	MATRIX4X4 clips;
	MATRIX4X4 projs;
	MATRIX4X4 modls;
	GLfloat   t;

	glGetFloatv( GL_PROJECTION_MATRIX, projs );
	glGetFloatv( GL_MODELVIEW_MATRIX, modls );

	clips=projs*modls;

	GLfloat   clip[16];
	for(int i=0;i<16;i++)
		clip[i]=clips.entries[i];

	/* Extract the numbers for the RIGHT plane */
	mFrustum[0][0] = clip[ 3] - clip[ 0];
	mFrustum[0][1] = clip[ 7] - clip[ 4];
	mFrustum[0][2] = clip[11] - clip[ 8];
	mFrustum[0][3] = clip[15] - clip[12];

	/* Normalize the result */
	t = GLfloat(sqrt( mFrustum[0][0] * mFrustum[0][0] + mFrustum[0][1] * mFrustum[0][1] + mFrustum[0][2] * mFrustum[0][2] ));
	mFrustum[0][0] /= t;
	mFrustum[0][1] /= t;
	mFrustum[0][2] /= t;
	mFrustum[0][3] /= t;

    /* Extract the numbers for the LEFT plane */
    mFrustum[1][0] = clip[ 3] + clip[ 0];
    mFrustum[1][1] = clip[ 7] + clip[ 4];
    mFrustum[1][2] = clip[11] + clip[ 8];
    mFrustum[1][3] = clip[15] + clip[12];

    /* Normalize the result */
    t = GLfloat(sqrt( mFrustum[1][0] * mFrustum[1][0] + mFrustum[1][1] * mFrustum[1][1] + mFrustum[1][2] * mFrustum[1][2] ));
    mFrustum[1][0] /= t;
    mFrustum[1][1] /= t;
    mFrustum[1][2] /= t;
    mFrustum[1][3] /= t;

	/* Extract the BOTTOM plane */
    mFrustum[2][0] = clip[ 3] + clip[ 1];
    mFrustum[2][1] = clip[ 7] + clip[ 5];
    mFrustum[2][2] = clip[11] + clip[ 9];
    mFrustum[2][3] = clip[15] + clip[13];

    /* Normalize the result */
    t = GLfloat(sqrt( mFrustum[2][0] * mFrustum[2][0] + mFrustum[2][1] * mFrustum[2][1] + mFrustum[2][2] * mFrustum[2][2] ));
    mFrustum[2][0] /= t;
    mFrustum[2][1] /= t;
    mFrustum[2][2] /= t;
    mFrustum[2][3] /= t;

    /* Extract the TOP plane */
    mFrustum[3][0] = clip[ 3] - clip[ 1];
    mFrustum[3][1] = clip[ 7] - clip[ 5];
    mFrustum[3][2] = clip[11] - clip[ 9];
    mFrustum[3][3] = clip[15] - clip[13];

    /* Normalize the result */
    t = GLfloat(sqrt( mFrustum[3][0] * mFrustum[3][0] + mFrustum[3][1] * mFrustum[3][1] + mFrustum[3][2] * mFrustum[3][2] ));
    mFrustum[3][0] /= t;
    mFrustum[3][1] /= t;
    mFrustum[3][2] /= t;
    mFrustum[3][3] /= t;

    /* Extract the FAR plane */
    mFrustum[4][0] = clip[ 3] - clip[ 2];
    mFrustum[4][1] = clip[ 7] - clip[ 6];
    mFrustum[4][2] = clip[11] - clip[10];
    mFrustum[4][3] = clip[15] - clip[14];

    /* Normalize the result */
    t = GLfloat(sqrt( mFrustum[4][0] * mFrustum[4][0] + mFrustum[4][1] * mFrustum[4][1] + mFrustum[4][2] * mFrustum[4][2] ));
    mFrustum[4][0] /= t;
    mFrustum[4][1] /= t;
    mFrustum[4][2] /= t;
    mFrustum[4][3] /= t;

    /* Extract the NEAR plane */
    mFrustum[5][0] = clip[ 3] + clip[ 2];
    mFrustum[5][1] = clip[ 7] + clip[ 6];
    mFrustum[5][2] = clip[11] + clip[10];
    mFrustum[5][3] = clip[15] + clip[14];

    /* Normalize the result */
    t = GLfloat(sqrt( mFrustum[5][0] * mFrustum[5][0] + mFrustum[5][1] * mFrustum[5][1] + mFrustum[5][2] * mFrustum[5][2] ));
    mFrustum[5][0] /= t;
    mFrustum[5][1] /= t;
    mFrustum[5][2] /= t;
    mFrustum[5][3] /= t;
}

然后判断球体在视景体内部还是外部,根据点到平面的距离公式计算

D=a*x+b*y+c*z-(a*xp+b*yp+c*zp) (xp,yp,zp)是面上的点,且平面方程是经过法线规范化处理的.

a*xp+b*yp+c*zp=-d

那么公式变为

D=a*x+b*y+c*z+d

D是有正负的,正距离是与法向量同向,负距离与法向量反向.

那么判断是否在视景体内部的代码如下:

bool sphereInFrustum(float x,float y,float z,float radius) {
	for(int i = 0; i < 6; i++) {
		if(mFrustum[i][0] * x + mFrustum[i][1] * y + mFrustum[i][2] * z + mFrustum[i][3] <= -radius)
			return false;
	}

	return true;
}

在每一帧都调用updateFrustum()就能够更新视景体平面,然后把模型的中心,大致半径作为变量调用sphereInFrustum即可判断模型是否能够看得见.

赶紧构造视景体,尽情地剔除看不见的东西吧!

参考:

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/

http://www.cnblogs.com/summericeyl/archive/2011/09/30/2196284.html

http://songho.ca/math/plane/plane.html

时间: 2024-10-13 20:18:09

视景体方程与剔除的相关文章

WorldWind源码剖析系列:视景体类

PluginSDK中的视景体类Frustum是三维计算机图形学中的概念,主要用来描述透视投影的过程.三维计算机图形学中关于三维物体的渲染,Direct3D和OpenGL都是先通过对现实世界中的场景先进行世界变换,再通过设置观察矩阵以在场景中安置一个虚拟相机,构建一个视景体来裁剪场景的可见区域,然后在通过投影变换(平行投影或透视投影),获取三维场景的“像”,最后再通过视口变换,将场景的“像”光栅化输出到二维显示屏幕上.如下图所示. 其中投影变换主要有透视投影和平行投影两类.视景体类Frustum正

OSG视景器四种线程模型(摘自Array《最长的一帧》)

OSG 的视景器包括四种线程模型,可以使用setThreadingModel 进行设置,不同的线程 模型在仿真循环运行时将表现出不同的渲染效率和线程控制特性.通常而言,这四种线程的 特性如下: SingleThreaded:单线程模型.OSG 不会创建任何新线程来完成场景的筛选和渲染,因 而也不会对渲染效率的提高有任何助益.它适合任何配置下使用. CullDrawThreadPerContext:OSG 将为每一个图形设备上下文(GraphicsContext)创建 一个图形线程,以实现并行的渲

GL-Studio GL Studiov3.0.2 1CD(视景仿真完整好用 +Y圆方橱柜

Paradigm Sysdrill v2009 1CD\Parasoft.C.Plus.Plus.Test.Professional.v6.7.4.0.Incl.Patch.and.Keymaker-ZWT\PDMS.v12.0.SP6-ISO 1DVD\VPstudio v10.03C8 1CD(包括中文版)\膜结构设计软件Easy 8.2\ 187\MSC.MD.NASTRAN.V2010\MSC.MD.Nastran.v2010.1.3-ISO 1DVD\MSC.Patran.v2010-

OSG 3.0 三维视景仿真技术开发详解

第一章 OSG三维渲染引擎概述 OSG的主要功能包括以下几个方面: 1. 可以实时高效地绘制和控制使用建模软件所建立的3D模型, 如3DMAX.MAYA.Creator等制作的3D模型, 该功能是场景渲染的基本功能. 2. 支持多种外设, 如操作杆.游戏柄.轨迹球.方向盘.键盘鼠标等. 3. 除了传统的二维屏幕上进行三维展示外, OSG还可以完成红绿偏移的立体投影, 实现真正的立体展示. 4. 支持骨骼动画.关键帧动画.颜色动画等各种流行的动画. OSG的相关扩展: OSG的相关扩展,OSG针对

OpenGL管线(用经典管线代说着色器内部)

图形管线(graphics pipeline)向来以复杂为特点,这归结为图形任务的复杂性和挑战性.OpenGL作为图形硬件标准,是最通用的图形管线版本.本文用自顶向下的思路来简单总结OpenGL图形管线,即从最高层开始,然后逐步细化到管线图中的每个框,再进一步细化到OpenGL具体函数.注意,这里用经典管线代说着色器内部,也就是OpenGL固定管线功能(Fixed-Function,相对于programmable也即可编程着色器),也会涉及着色器,但差不多仅限于“这些固定管线功能对应xx着色器”

OpenGL投影矩阵(Projection Matrix)构造方法

(翻译,图片也来自原文) 一.概述 绝大部分计算机的显示器是二维的(a 2D surface).在OpenGL中一个3D场景需要被投影到屏幕上成为一个2D图像(image).这称为投影变换(参见这或这),需要用到投影矩阵(projection matrix). 首先,投影矩阵会把所有顶点坐标从eye coordinates(观察空间,eye space或view space)变换到裁剪坐标(clip coordinated,属于裁剪空间,clip space).然后,这些裁剪坐标被变换到标准化设

浙江大学软件学院三维动画与交互技术考试概念整理

第一讲 1.    增强现实技术AR: --融合了三维动画.立体视觉和图像处理: --建模.渲染.位置标定.图像融合: 2.    OpenGL是一种用于创建实时3D图像的编程接口. 3.    三维这个术语表示一个正在描述或显示的物体具有三维维度:宽度.高度.深度: --计算机3D图形实质上也是平面的: --在计算机屏幕上显示的二维图像,提供深度(或第三维)的错觉: 2D+透视 = 3D 透视使人产生深度的错觉. 4.    真正的3D是通过人的两只眼睛观察同一个物体,在视网膜上生成具有视差的

计算机图形学名词解释

转自 http://blog.csdn.net/lwfcgz/article/details/39254743 3D三维(three dimension).客观世界中静止的物体都是三维的,在计算机图形学中常在一定的坐标系中用(x,y,z)坐标系列表示物体. 3D modeling3D建模.用三维坐标来描述物体的形状.在各种计算机图形应用领域中有不同的三维建模方法,用不同的算法来描述这些领域中的物体和对象. 3D transformation3D变换.在三维空间中把物体的三维坐标从一个位置变换至另

NeHe OpenGL教程 第四十四课:3D光晕

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十四课:3D光晕 3D 光晕 当镜头对准太阳的时候就会出现这种效果,模拟它非常的简单,一点数学和纹理贴图就够了.好好看看吧. 大家好,欢迎来到新的一课,在这一课中我们将扩展glCamera类,来实现镜头光晕的效果.在日常生活中,