7-OpenGLES模板缓冲区

public class MyActivity extends Activity {
	private MyRenderer render;
	private MyGLSurfaceView view;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		view = new MyGLSurfaceView(this);
		render = new MyRenderer();
		view.setEGLConfigChooser(5, 6, 5, 0, 16, 4);
		view.setRenderer(render);
		view.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);// 脏渲染,命令渲染
		setContentView(view);
	}

	class MyGLSurfaceView extends GLSurfaceView {
		public MyGLSurfaceView(Context context) {
			super(context);
		}

		public MyGLSurfaceView(Context context, AttributeSet attrs) {
			super(context, attrs);
		}
	}

	class MyRenderer implements GLSurfaceView.Renderer {
		List<Float> vertexList;
		float ratio = 0;
		float left = -ratio, top = 1f, width = 0.3f;
		boolean xadd = false;
		boolean yadd = false;

		@Override
		public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
			gl.glClearColor(0f, 0f, 0f, 1.0f);// clearColor
			gl.glClearStencil(0);// 模板清除值,用0表示清除模板

			gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// vertex array
			gl.glEnable(GL10.GL_DEPTH_TEST);// depth test
			gl.glEnable(GL10.GL_STENCIL_TEST);// 启用模板测试
		}

		@Override
		public void onSurfaceChanged(GL10 gl, int w, int h) {// 设置视口
			gl.glViewport(0, 0, w, h);
			ratio = (float) w / h;
			left = -ratio;
			gl.glMatrixMode(GL10.GL_PROJECTION);
			gl.glLoadIdentity();
			gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
		}

		@Override
		public void onDrawFrame(GL10 gl) {
			// 清除颜色,深度,模板缓冲区
			gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT | GL10.GL_STENCIL_BUFFER_BIT);
			gl.glMatrixMode(GL10.GL_MODELVIEW);
			gl.glLoadIdentity();
			GLU.gluLookAt(gl, 0, 0, 5, 0, 0, 0, 0, 1, 0);
			/****************************** 绘制白色螺旋线 **********************************/
			// 单调着色
			gl.glShadeModel(GL10.GL_FLAT);

			vertexList = new ArrayList<Float>();
			float x = 0, y = .8f, z = 0, ystep = 0.005f, r = 0.7f;
			for (float angle = 0f; angle < (Math.PI * 2 * 3); angle += (Math.PI / 40)) {
				x = (float) (r * Math.cos(angle));
				z = -(float) (r * Math.sin(angle));
				y = y - ystep;
				vertexList.add(x);
				vertexList.add(y);
				vertexList.add(z);
			}
			ByteBuffer vbb = ByteBuffer.allocateDirect(vertexList.size() * 4);
			vbb.order(ByteOrder.nativeOrder());
			FloatBuffer fvb = vbb.asFloatBuffer();
			for (Float f : vertexList) {
				fvb.put(f);
			}
			fvb.position(0);

			// 所有无法通过模板测试的绘图命令并不进行绘制,而只是增加模板缓冲区内的值
			gl.glStencilFunc(GL10.GL_NEVER, 0x0, 0x0);
			gl.glStencilOp(GL10.GL_INCR, GL10.GL_INCR, GL10.GL_INCR);

			// 绘制白色螺旋线
			gl.glColor4f(1f, 1f, 1f, 1f);// 白线
			gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fvb);
			gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, vertexList.size() / 3);
			/****************************** 绘制红色方块 **********************************/
			if (xadd) {
				left = left + 0.01f;
			} else {
				left = left - 0.01f;
			}
			if (left <= (-ratio)) {
				xadd = true;
			}
			if (left >= (ratio - width)) {
				xadd = false;
			}

			if (yadd) {
				top = top + 0.01f;
			} else {
				top = top - 0.01f;
			}
			if (top >= 1) {
				yadd = false;
			}
			if (top <= (-1 + width)) {
				yadd = true;
			}
			float[] rectVertex = { left, top - width, 2f, 
					       left, top, 2f, 
					       left + width, top - width, 2f, 
					       left + width, top, 2f };
			vbb = ByteBuffer.allocateDirect(3 * 4 * 4);
			vbb.order(ByteOrder.nativeOrder());
			FloatBuffer rectfb = vbb.asFloatBuffer();
			rectfb.put(rectVertex);
			rectfb.position(0);

			// 现在,允许进行绘图,只包括那些模板模型是1的地方,并且不会对模板缓冲区进行修改
			gl.glStencilFunc(GL10.GL_NOTEQUAL, 0x1, 0x1);
			gl.glStencilOp(GL10.GL_KEEP, GL10.GL_KEEP, GL10.GL_KEEP);
			// 绘制红色方块
			gl.glColor4f(1f, 0f, 0f, 1f);
			gl.glVertexPointer(3, GL10.GL_FLOAT, 0, rectfb);
			gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
		}
	}
}

(注意要加上view.setEGLConfigChooser(5, 6, 5, 0, 16, 4);

void android.opengl.GLSurfaceView.setEGLConfigChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize)
Install a config chooser which will choose a config with at least the specified depthSize and stencilSize, and exactly the specified redSize, greenSize, blueSize and alphaSize.
If this method is called, it must be called before setRenderer(Renderer) is called.
If no setEGLConfigChooser method is called, then by default the view will choose an RGB_888 surface with a depth buffer depth of at least 16 bits.

模板和深度缓存测试一样,允许或禁止在以单个像素为基础上绘制。模板平面将最先通过GL绘制基元进行绘制,然后是几何体和图像在通过使用模板平面指定的屏幕部分上进行渲染。模板是一种典型的使用多通道渲染算法来达到特殊效果的方法,比如贴花,绘制轮廓和创造性的几何体渲染等。
模板测试有条件的剔除像素,剔除方法基于ref值和模板缓存中值的比较结果。要允许或禁止该测试的话,使用glEnable(GL_STENCIL_TEST)或glDisable(GL_STENCIL_TEST). 

void glStencilFunc(int func, int ref, int mask);
模板函数func可以取下面任意一个值: GL_NEVER、GL_ALWAYS、GL_LESS、GL_LEQUAL、GL_EQUAL、GL_GEQUAL、GL_GREATER和GL_NOTEQUAL。这些值告诉了OpenGL如何把已经存储在模板缓冲区中的值ref参数所指定的值进行比较。假设参考值为A,存储在模板缓冲区中的值为B,则上面这些值分别代表“从不通过”、“总是通过”、“当A小于B时通过”、“当 A小于等于B
时通过”、“当A等于B时通过”、“当A大于等于B时通过”、“当A大于B时通过”和“当A不等于B时通过”。另外,我们可以指定一个掩码,在进行比较之前,将这个掩码与参考值和模板缓冲区中的值进行位AND操作。

void g1StencilOp(int fail, int zfail, int zpass);
这些值告诉OpenGL,如果模板测试失败,它应该如何修改模板缓冲区的值。而且,即使模板测试通过,也可以根据深度测试是失败(zfail)还是通过(zpass)来修改模板缓冲区的值。这些参数的合法值包括GL_KEEP、GL_ZERO、GL_REPLACE、GL_INCR、GL_DECR、GL_INVERT 、GL_INCR_WRAP和GL_DECR_WRAP。这些值分别对应于“保持当前值"、“把它设置为0”、“用参
考值(取自glStencilFunc)代替"、“增加或减少这个值”、“反转这个值”以及“循环增加或减少这个值"。GL_INCR和GL_DECR增加或减少模板值,但是它的值限制在最小值和最大值的范围之内。最大/最小值是由模板缓冲区中每个特定位的深度决定的。GL_INCR_WRAP和GL_DECR_WRAP在值小于一个特定位的最小值或大于这个特定位的最大值时简单地对它进行循环增减。


现在,我们已经知道了如何执行模板测试,但一开始值是如何放进模板缓冲区的呢?在开始绘图操作之前,我们必须确保模板缓冲区已被清除。这与使用glClear函数清除颜色和深度缓冲区的方法是一样的, 只不过使用的位掩码是GL_STENCIL_BUFFER_BIT。例如,下面这行代码同时清除了颜色、深度和模板缓冲区。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
在清除操作中所使用的值是在之前调用下面这个函数时设置的。
glClearStencil(int s);
在启用了模板测试之后,渲染命令就使用我们刚刚讨论的glStencilFunc函数的参数与存储在模板缓冲区中的值进行测试。根据模板测试的结果,值片段(颜色缓冲区中的颜色值)被写入或丢弃。在测试过程中,模板缓冲区本身也会被修改,进入模板缓冲区的值取决于glStencilOp函数是如何被调用的。
在示例程序中,我们在模板缓冲区而不是颜色缓冲区中创建了一个螺旋线模型。我们使用了反弹方块,但现在使用了模板测试,以使在模板缓冲区中未含1值的地方绘制这个方块。

glStencilFunc(GL_NEVER, 0x0, 0x0);
glStencilOp(GL_INCR,GL_INCR, GL_INCR);
但是,glStencilOp函数的参数导致了模板缓冲区中的值被写入(实际上是增加),而不管屏幕上是否能看到什么东西。下面这几行代码绘制了一条白色螺旋线,线的颜色是白色的,使我们可以在黑色背景中看到它,它也不会在颜色缓冲区中绘制,因为它总是无法通过模板测试(GL_NEVER)。事实上,我们只能够渲染到模板缓冲区!
接下来,我们使用下面这两行代码修改模板操作。
glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
现在,绘图将在所有模板缓冲区中不等于1(GL_NOTEQUAL)的地方进行,也就是屏幕上未绘制螺旋线的地方,因为画的白色线,颜色值(1,1,1,1) = ref。而反弹方块颜色值都不等于1。在这个例子中,接下来对glStencilOp的调用是可选的,但它可以告诉OpenGL保留模板缓冲区,用于以后所有的绘图操作。运行效果图显示了一幅图像,其中反弹红色方块看上去像是被“模板镂空”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itzyjr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值