OpenGL ES 颜色缓冲 深度测试 表面剔除

本文详细介绍了如何在OpenGL中启用颜色缓冲区,通过创建MyTriangleConeRenderer类来绘制带有颜色过渡效果的三角圆锥,包括清除颜色缓冲区、深度测试、表面剔除等关键步骤,最终实现美观且高效的图形渲染效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、修改MyAbstractRenderer.java 启用颜色缓冲区

 public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
        //设置清屏色(背景)
        gl.glClearColor(0, 0, 0, 1);
        //启用顶点缓冲区
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        //为了给每个点都有颜色 启用颜色缓冲区
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
    }

2、创建 MyTriangleConeRenderer 类

public class MyTriangleConeRenderer extends MyAbstractRenderer {

	protected void drawBefore(GL10 gl) {
		//清除颜色缓冲区 |深度缓冲区
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
		//启用深度测试 导致点计算
		gl.glEnable(GL10.GL_DEPTH_TEST);
		//启用表面剔除 //剔除 :如果看不见 就告诉openGL 不用绘制 (提高性能)
		gl.glEnable(GL10.GL_CULL_FACE);
		gl.glFrontFace(GL10.GL_CW);//顺时针  为正面
//		
		//绘制指定两点间其他点颜色的过渡模式
		gl.glShadeModel(GL10.GL_FLAT);  //单调模式 没有过度 
//		gl.glShadeModel(GL10.GL_SMOOTH); //默认平滑 过度
	}
	
	@Override
	protected void draw(GL10 gl) {
		float r =0.5f;
		float x =0f;
		float y =-1f;
		float z =0f;
		float alphaStep=(float) (Math.PI/8);
		//扇面点集合
		List<Float> fanList=new ArrayList<Float>();
		fanList.add(0f);
		fanList.add(1f);
		fanList.add(0f);
		//底面点集合
		List<Float> bottomList =new ArrayList<Float>();
		bottomList.add(0f);
		bottomList.add(y);
		bottomList.add(0f);
		
		//颜色集合
		List<Float> colorList =new ArrayList<Float>();
		colorList.add(1f);//r
		colorList.add(1f);//g
		colorList.add(0f);//b
		colorList.add(1f);//a
		
		boolean flag =false;
		boolean first =true;
		for(float alpha =0f;alpha<Math.PI*2+alphaStep;alpha+=alphaStep){
			x=(float) (r*Math.cos(alpha));
			z=(float) (r*Math.sin(alpha));
			//扇面点坐标
			fanList.add(x);
			fanList.add(y);
			fanList.add(z);
			//底面点坐标
			bottomList.add(x);
			bottomList.add(y);
			bottomList.add(z);
			//点色值
			if(flag =!flag){
				redColor(colorList);
			}else{
				if(first){
					first =false;
					whiteColor(colorList);
				}else{
					yellowColor(colorList);
				}
			}
		}
		if(flag =!flag){
			redColor(colorList);
		}else{
			yellowColor(colorList);
		}
		//扇面颜色
		ByteBuffer cFIbb =BufferUtil.list2ByteBuffer(colorList);
		gl.glColorPointer(4, GL10.GL_FLOAT, 0, cFIbb);	
		//由于 绘制扇面是顺时针 
		//设置了 gl.glFrontFace(GL10.GL_CW);顺时针 为正面 
		//要满足能看到扇面 则要剔除 背面
		gl.glCullFace(GL10.GL_BACK);//如果下面 没有再设值 则一直使用剔除背面
		//扇面点
		ByteBuffer fIbb=BufferUtil.list2ByteBuffer(fanList);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fIbb);
		gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, fanList.size()/3);
		//底面颜色
		ByteBuffer cBIbb =BufferUtil.list2ByteBuffer(colorList);
		cBIbb.position(4*4); //偏移一个点像素 使其底面颜色与扇面间隔开
		gl.glColorPointer(4, GL10.GL_FLOAT, 0, cBIbb);	
		//由于 绘制底面是逆时针 
		//设置了 gl.glFrontFace(GL10.GL_CW);顺时针 为正面 
		//要满足能看到底面 则要剔除 前面
		gl.glCullFace(GL10.GL_FRONT);
		//底面
		ByteBuffer bIbb=BufferUtil.list2ByteBuffer(bottomList);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, bIbb);
		gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, bottomList.size()/3);
	}
	private void redColor(List<Float> colorList){
		colorList.add(1f);//r
		colorList.add(0f);//g
		colorList.add(0f);//b
		colorList.add(1f);//a
	}
	private void yellowColor(List<Float> colorList){
		colorList.add(1f);//r
		colorList.add(1f);//g
		colorList.add(0f);//b
		colorList.add(1f);//a
	}
	private void whiteColor(List<Float> colorList){
		colorList.add(1f);//r
		colorList.add(1f);//g
		colorList.add(1f);//b
		colorList.add(1f);//a
	}
}

3、运行效果


### 关于 OpenGL ES 深度测试 #### 什么是深度测试深度测试是一种用于决定哪些片段应该被绘制到屏幕上,而哪些不应该的机制。它通过比较新片段的深度值与当前帧缓冲中的深度值来实现这一功能。如果新的片段更靠近观察者,则更新帧缓冲;否则丢弃该片段。 在 OpenGL ES 中,深度测试可以通过 `glEnable(GL_DEPTH_TEST)` 启用,并使用 `glDepthFunc` 设置具体的比较函数[^2]。常见的比较函数有: - **GL_NEVER**: 新片段永远不会通过测试。 - **GL_LESS**: 如果新片段的深度小于现有深度值则通过。 - **GL_EQUAL**: 如果两者相等则通过。 - **GL_LEQUAL**: 如果新片段的深度小于等于现有深度值则通过。 - **GL_GREATER**, **GL_NOTEQUAL**, **GL_GEQUAL**, 和 **GL_ALWAYS** 提供其他不同的比较逻辑。 默认情况下,深度测试是禁用的,因此需要显式调用上述命令以激活并配置其行为。 #### 如何初始化深度缓冲区? 为了使深度测试生效,必须确保存在有效的深度缓冲区。这通常涉及设置合适的上下文属性以及分配足够的资源给深度缓存区域。例如,在创建 EGL 上下文时可以指定所需的深度位数: ```c EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 16, // 请求至少具有 16 位精度的深度缓冲区 EGL_NONE }; ``` 接着验证所选配置确实支持请求的功能集: ```c if (config->depthSize >= 16) { /* 配置满足需求 */ } else { /* 错误处理 */} ``` 此外还需要清除每一帧开始前的深度缓冲状态以便获得正确的渲染效果: ```cpp glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ``` #### 常见问题及其解决方案 1. **为什么我的模型看起来像是穿模?** 这可能是由于未能正确开启或设定深度测试所致。确认已执行如下代码片段: ```cpp glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); // 或其他适合的选择 ``` 2. **即使启用了深度测试仍然看不到预期的结果怎么办?** 应当检查是否遗漏了清屏步骤或者错误设置了清除值。标准做法如下所示: ```cpp GLfloat clearDepthValue = 1.0f; glClearDepth(clearDepthValue); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ``` 3. **性能下降明显是什么原因引起的呢?** 当场景复杂度增加时可能会遇到这种情况。尝试优化几何结构减少不必要的绘图指令提交次数,同时考虑利用层级遮挡剔除技术(Hierarchical Z-culling)提高效率[^1]。 4. **如何调试深度相关的问题?** 利用工具如 RenderDoc 来捕获帧数据进而分析具体哪一部分出现了偏差可以帮助定位问题所在位置。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值