openGL之深度测试、表面剔除、剪裁---openGL学习笔记(五)
来源:互联网 发布:服装厂出货软件 编辑:程序博客网 时间:2024/05/18 02:23
深度测试:
上次用画三角形扇面的方法绘制的棱锥,发现一个问题,就是无论将棱锥如何旋转,底面总是可见的。
这与实际不符,实际中,当我们从棱锥的顶点向下看的时候是看不见底面的,出现这种情况的原因是因为,我们先画的棱锥锥面,后画的棱锥底面,在openGL中后画出来的部分,会一直可见。
那么为了解决这个问题,我们就需要用到openGL中的深度测试。
深度测试简单来说就是,让应该被挡住的物体不显示。
深度测试的原理是:启用一个z值(深度Z轴),在绘制的时候会拿这个z值对比,从而确定是否显示。
一般的,我们在onDrawFram()方法中启用深度测试:
//启用深度测试gl.glEnable(GL10.GL_DEPTH_TEST);而要启用深度测试就要先清除深度缓存:
//清除深度缓冲区gl.glClear(GL10.GL_DEPTH_BUFFER_BIT);这样,就可以让应该被挡住的物体不显示了。
表面剔除:
一张纸有两面,即正面和反面,那么同样的,我们绘制的棱锥的锥面和锥底都有两面,外面和里面,外面就是我们可见的部分,里面就是在棱锥闭合空间内的部分,这部分我们是看不见的,那么既然看不见,我们就可以告诉openGL,里面的部分不要绘制出来,这样既不影响图像,又能提升性能,这个让不可见的部分不绘制的过程,叫做表面剔除。
表面剔除和深度测试一样,是一个状态机,与所有状态机的开启方式一样的:
//启用表面剔除gl.glEnable(GL10.GL_CULL_FACE);启用了表面剔除之后,我们还需指定,顺时针方向为正面还是逆时针方向为正面,需要剔除正面还是背面。
根据我们的需求,我们的圆锥是逆时针绘制的,那么圆锥内部就是顺时针绘制的,我们要剔除的是圆锥内部,那么就设置逆时针方向为正面,剔除背面:
gl.glFrontFace(GL10.GL_CW);//设定前面 ccw:counter clock wise--->逆时针(cw:顺时针)gl.glCullFace(GL10.GL_BACK);//剔除背面这样绘制完了会发现,棱锥的底面不见了,这是因为,底面也是逆时针绘制的,因为指定了逆时针方向为正面,而我们可见底面的部分刚好为背面,所以就将底面我们可见的部分剔除了,而我们不可见的部分还在。
所以,这就需要在我们绘制底面的时候再次手动指定:剔除正面。
gl.glCullFace( GL10.GL_FRONT ); //剔除正面这样就将棱锥内部不可见的部分剔除了。
裁剪:
scissor:剪刀
有的时候,我们只想让画面局部更新,其他地方保持原样,那么这就要用到裁剪。
在屏幕上,我们实际可见的部分是视口决定的,而设置视口的方法在onSurfaceChanged()方法中:
//设置视口gl.glViewport(0,0,width,height);那么我们就要在这个方法中将视口的width,和height赋给定义的成员变量。
这样就可以设置我们想要的剪裁后的区域了。
首先裁剪也是状态机,先要启用剪裁:
//启用剪裁gl.glEnable( GL10.GL_SCISSOR_TEST );启用了剪裁之后,还需要设置剪裁区:
gl.glScissor();
如上图所示,假如每次缩进20px,那么蓝色区域的宽和高就都会比白色区域小40px,因为上下左右都需要缩进。同样的绿色区域也比蓝色区域小40px。
gl.glScissor();方法一共四个参数,前两个参数x,y即是缩进后的矩形左下角的坐标。那么如定义缩进量为20的话,(x,y)就是(20,20)。
第三个第四个参数为缩进后的矩形的宽高,那么此时应该是(width-20*2,heihgt-20*2)。
为不同颜色显示,我们设置一个二维数组:
float [] [] colors = { {1f,0f,0f,1f}, {0f,1f,0f,1f}, {0f,0f,1f,1f}, {1f,1f,0f,1f}, {0f,1f,1f,1f}, {1f,0f,1f,1f},};顶点坐标为:
float [] coords = { -ratio,1f,2f, -ratio,-1f,2f, ratio,-1f,2f, ratio,1f,2f,};假定缩进量为100px,那么该如下设置:
int step = 100;for( int i = 0;i < 6;i++ ){ //设置剪裁区 gl.glScissor(i*step,i*step,with - (i*step*2),height - (i*step*2)); gl.glColor4f( colors[i][0],colors[i][1],colors[i][2],colors[i][3] ); gl.glVertexPointer( 3,GL10.GL_FLOAT,0,BufferUtils.array2ByteBuffer(coords) ); gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0,4);}这样就完成了剪裁。
附剪裁源码:
public class MyScissorRenderer extends AbstractRenderer { private int with; private int height; @Override public void onSurfaceChanged(GL10 gl, int width, int height) { this.with = width; this.height = height; //设置视口 gl.glViewport(0,0,width,height); //计算视口比例 ratio = (float)width / (float)height; //设置矩阵模式 gl.glMatrixMode(GL10.GL_PROJECTION); //加载单位矩阵 gl.glLoadIdentity(); //设置平截头体 gl.glFrustumf(ratio,-ratio,-1f,1f,3f,7f);//ratio为with/height,所以高度为,宽度为ratio } public void onDrawFrame(GL10 gl) { //清除颜色缓冲区 gl.glClear(GL10.GL_COLOR_BUFFER_BIT); //设置绘图颜色 gl.glColor4f(1f, 1f, 1f, 1f); //设置模型视图矩阵 gl.glMatrixMode(GL10.GL_MODELVIEW); //载入单位矩阵 gl.glLoadIdentity(); //放置眼球位置 GLU.gluLookAt(gl, 0f, 0f, 5f, 0f, 0f, 0f, 0f, 1f, 0f); //启用剪裁 gl.glEnable( GL10.GL_SCISSOR_TEST ); //旋转角度,以便更直观查看 gl.glRotatef(xRotate,1,0,0);// 绕x轴旋转 (openGL规定,顺时针旋转为负值) gl.glRotatef(yRotate,1,0,0);// 绕y轴旋转 float [] coords = { -ratio,1f,2f, -ratio,-1f,2f, ratio,-1f,2f, ratio,1f,2f, }; float [] [] colors = { {1f,0f,0f,1f}, {0f,1f,0f,1f}, {0f,0f,1f,1f}, {1f,1f,0f,1f}, {0f,1f,1f,1f}, {1f,0f,1f,1f}, }; int step = 100; for( int i = 0;i < 6;i++ ){ //设置剪裁区 gl.glScissor(i*step,i*step,with - (i*step*2),height - (i*step*2)); gl.glColor4f( colors[i][0],colors[i][1],colors[i][2],colors[i][3] ); gl.glVertexPointer( 3,GL10.GL_FLOAT,0,BufferUtils.array2ByteBuffer(coords) ); gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0,4); } }}附深度测试、表面剔除源码:(画棱锥为例)
/** * 概念: * cone:圆锥 * 顶点的着色模式: * 1.平滑 smooth(渐变模式):默认 * 2.单调 flat(单调模式)也是就和最后一个点的颜色相同 * * 深度测试:被挡住的部分不显示 * 原理为启用一个z值(深度轴z轴),被遮挡的物体看不见,但是还是会绘制。 * * 表面剔除:如果看不见的部分,就告诉openGL不要绘制该部分,这样可以提高性能。 * 例如在画一个椎面,该锥面为逆时针绘制,相应的锥面内部就是顺时针绘制, * 那么指定逆时针方向为正面后,可以剔除背面,那么背面部分就会不绘制。 */public class MyTriangleConeRenderer extends AbstractRenderer{ @Override public void onSurfaceChanged(GL10 gl, int width, int height) { super.onSurfaceChanged(gl, width, height); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); } public void onDrawFrame(GL10 gl) { //清除颜色缓冲区 gl.glClear(GL10.GL_COLOR_BUFFER_BIT); //清除深度缓冲区 gl.glClear(GL10.GL_DEPTH_BUFFER_BIT); //设置绘图颜色 gl.glColor4f(1f, 1f, 1f, 1f); //启用深度测试 gl.glEnable(GL10.GL_DEPTH_TEST); //启用深度测试前要清除深度缓冲区 //启用表面剔除 gl.glEnable(GL10.GL_CULL_FACE); gl.glFrontFace(GL10.GL_CW);//设定前面 ccw:counter clock wise--->逆时针(cw:顺时针) gl.glCullFace(GL10.GL_BACK);//剔除背面 //设置着色模式 gl.glShadeModel(GL10.GL_FLAT); //单调模式 //设置模型视图矩阵 gl.glMatrixMode(GL10.GL_MODELVIEW); //载入单位矩阵 gl.glLoadIdentity(); //放置眼球位置 GLU.gluLookAt(gl, 0f, 0f, 5f, 0f, 0f, 0f, 0f, 1f, 0f); //旋转角度,以便更直观查看 gl.glRotatef(xRotate, 1, 0, 0);// 绕x轴旋转 (openGL规定,顺时针旋转为负值) gl.glRotatef(yRotate,1,0,0);// 绕y轴旋转 /** * 计算点的坐标 * @param r 半径 * @param coordsList 坐标集合 * @param x,y,z 每个点的坐标 * @param alpha 角度 * */ float r = 0.5f;//半径 float x = 0f,y = 0f,z = -0.5f;//点的坐标 /******************** 锥面 **********************/ List<Float> coordsList = new ArrayList<Float>(); //添加锥顶点 coordsList.add(0f); coordsList.add(0f); coordsList.add(0.5f); //顶点颜色集合 List<Float> colorList = new ArrayList<Float>(); colorList.add(1f);//r colorList.add(0f);//g colorList.add(0f);//b colorList.add(1f);//a /******************** 锥底 **********************/ List<Float> coordsConeBottomList = new ArrayList<Float>(); coordsConeBottomList.add(0f); coordsConeBottomList.add(0f); coordsConeBottomList.add(-0.5f); boolean flag = false; //底面 for( float alpha = 0f; alpha < Math.PI * 6;alpha = (float) (alpha+Math.PI / 8 )){ x = (float) (Math.cos(alpha) * r); y = (float) (Math.sin(alpha) * r); //锥面坐标 coordsList.add(x); coordsList.add(y); coordsList.add(z); //锥底坐标 coordsConeBottomList.add(x); coordsConeBottomList.add(y); coordsConeBottomList.add(z); //点颜色值 if( flag = !flag ){ //黄色 colorList.add(1f); colorList.add(1f); colorList.add(0f); colorList.add(1f); }else { //红色 colorList.add(1f); colorList.add(0f); colorList.add(0f); colorList.add(1f); } /*****使锥底颜色与锥面颜色错位*****/ if( flag = !flag ){ //黄色 colorList.add(1f); colorList.add(1f); colorList.add(0f); colorList.add(1f); }else { //红色 colorList.add(1f); colorList.add(0f); colorList.add(0f); colorList.add(1f); } } /****************绘制锥面*********************/ ByteBuffer colorBuffer = BufferUtils.list2ByteBuffer(colorList); gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer );//顶点颜色指针 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, BufferUtils.list2ByteBuffer(coordsList));//指定顶点坐标指针 gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, coordsList.size() / 3);//绘制锥面 /****************绘制锥底*********************/ colorBuffer.position(4); //四个数为一个颜色,从五个颜色开始就会从第二个颜色开始绘制 gl.glCullFace( GL10.GL_FRONT ); //剔除正面 gl.glColorPointer(4, GL10.GL_FLOAT, 0,colorBuffer );//顶点颜色指针 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, BufferUtils.list2ByteBuffer(coordsConeBottomList));//指定顶点坐标指针 gl.glDrawArrays( GL10.GL_TRIANGLE_FAN,0,coordsConeBottomList.size() / 3 );//绘制锥底 }}
- openGL之深度测试、表面剔除、剪裁---openGL学习笔记(五)
- OpenGL ES 颜色缓冲 深度测试 表面剔除
- OPENGL学习笔记之五
- Opengl笔记---深度测试
- OPENGL学习笔记(五)
- OpenGL学习笔记(五)
- OpenGL学习笔记(五)
- 现代OpenGL+Qt学习笔记之五:OpenGL矩阵变换
- 《高效学习OpenGL》 之 隐藏表面消除
- OpenGL ES学习笔记之五
- OpenGL学习笔记:测试
- OpenGL核心技术之深度测试
- Win32 OpenGL编程(13) 隐藏表面消除(深度测试)及雾效果
- OpenGL核心技术之面剔除
- openGL之圆环---openGL学习笔记(七)
- openGL之光照1---openGL学习笔记(九)
- openGL之混合、抗锯齿---openGL学习笔记(十一)
- openGL之雾效果---openGL学习笔记(十二)
- 58.The PART_CODE column in the SPARES table contains the following list of values:
- 网卡接口相关定义
- Leetcode:237. Delete Node in a Linked List(JAVA)
- 用户管理系统——添加用户
- 《Android开发精要》读书笔记——Android的系统架构
- openGL之深度测试、表面剔除、剪裁---openGL学习笔记(五)
- EXP/IMP迁移数据库的时候注释乱码解决方法
- Ajax 整体结构
- 转换人民币大写
- OpenCV仿射变换+投射变换+单应性矩阵
- LeetCode 33 - Search in Rotated Sorted Array
- 网址URL中特殊字符转义编码
- 数据库知识汇总
- 苹果手机safairi不支持position:fixed