OpenGL学习笔记(十五)模板测试

在这里插入图片描述
正如上图可以看到,模板测试就是给设置一个区域,让其显示出来,其他的则不会显示出来。
模板测试和深度测试真的很相似。
下面是打开模板测试和是否开启掩码的代码。

glEnable(GL_STENCIL_TEST);//开启模板测试
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);//清理缓冲区
glStencilMask(0xFF); // 每一位写入模板缓冲时都保持原样
glStencilMask(0x00); // 每一位在写入模板缓冲时都会变成0(禁用写入)

鼓励你们测试一下,因为我各种姿势都试过了,发现加不加这些代码,我的肉眼都没办法分辨出差别。可能要后面的来控制吧!
接下来就是两个函数了:
glStencilFunc(GLenum func, GLint ref, GLuint mask)一共包含三个参数:

func:设置模板测试函数(Stencil Test Function)。这个测试函数将会应用到已储存的模板值上和glStencilFunc函数的ref值上。可用的选项有:GL_NEVER、GL_LESS、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL和GL_ALWAYS。它们的语义和深度缓冲的函数类似。
ref:设置了模板测试的参考值(Reference Value)。模板缓冲的内容将会与这个值进行比较。
mask:设置一个掩码,它将会与参考值和储存的模板值在测试比较它们之前进行与(AND)运算。初始情况下所有位都为1。

glStencilFunc(GL_EQUAL, 0, 0xFF);//对,你没有看错,这里就是等于0,不是等于1,它不是应该等于1吗?
//可是我让他等于1时,通过模板测试,给我的就只是一个背景板,而且不等于,小于返回的也是背景板,
//剩下的我就不尝试了,如果有兴趣的话,你可以自己尝试一下。

但是glStencilFunc仅仅描述了OpenGL应该对模板缓冲内容做什么,而不是我们应该如何更新缓冲。这就需要glStencilOp这个函数了。

glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)一共包含三个选项,我们能够设定每个选项应该采取的行为:

sfail:模板测试失败时采取的行为。
dpfail:模板测试通过,但深度测试失败时采取的行为。
dppass:模板测试和深度测试都通过时采取的行为。

在这里插入图片描述
这里我只记录一些我自己尝试的组合
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
没有设置glStencilFunc(GL_LESS, 1, 0xFF)时:

    	glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);//1号图
	    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);//1
		glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);//1
		glStencilOp(GL_INCR, GL_INCR, GL_INCR);//1
		glStencilOp(GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP);//1
		glStencilOp(GL_DECR, GL_DECR, GL_DECR);//1
		glStencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP);//1
    	glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);//1

下面是glStencilFunc(GL_LESS, 1, 0xFF);

	glStencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP);//2
	    	glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);//2

下面是glStencilFunc(GL_LESS, 0, 0xFF);

	glStencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP);//2
	    	glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);//2

下面是glStencilFunc(GL_EQUAL, 0, 0xFF);

    	glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);//3

其余的如果你感兴趣的,可以自己去测试。我就懒得测试了。
然后我们通过模板测试,开始完成策略游戏中的物体描边
新开一个LightFrag.Frag

#version 330 core			
out vec4 FragColor;	
void main()				
{
FragColor=vec4(1.0f,0.0f,0.0f,1.0f);
}

然后实例化两个不同的着色器

    Shader* myShader = new Shader("vertexSource.vert", "fragmentSource.frag");
	Shader* lightShader = new Shader("vertexSource.vert", "LightFrag.Frag");

加载两张贴图

	unsigned int texbufferA;//贴图缓冲区ID
	texbufferA=LoadImageToGpu("container2.png",GL_RGBA,GL_RGBA, Shader::DIFFUSE);
	unsigned int texbufferB;//贴图缓冲区ID
	texbufferB = LoadImageToGpu("container2_specular.png", GL_RGBA, GL_RGBA, 2);

开启模板测试

	glEnable(GL_STENCIL_TEST);

然后是循环中

while (!glfwWindowShouldClose(window))
	{	// 检查事件,调用相应的回调函数,如下文的glfwInput函数
		//Process Input
		ProcessInput(window);
        //Clear screen
		glClearColor(0.3f, 0.3f, 0.3f, 1.0f);//渲染颜色到后台缓冲
		
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);//清除前台缓冲

		viewMat = myCamera->GetViewMatrix();//刷新视角
        for (size_t i = 1; i <= 10; i++)
		{
			glm::mat4 modelMat;//模型矩阵
			modelMat = glm::translate(modelMat, cubePositions[i]);
			modelMat = glm::rotate(modelMat, glm::radians(i*10.0f), glm::vec3(0, 1.0f, 0));
		
			glEnable(GL_DEPTH_TEST);//开启深度测试
			glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);//只有模板与深度有一个失败,就保持,都成功了,就换成ref值
			
			glStencilMask(0xFF);//设置模板可以写入
			glStencilFunc(GL_ALWAYS, 1, 0xFF);//模板测试总是通过,并将深度测试通过的模板值改为1
			//绘制中间的
			myShader->Use();
			
			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, texbufferA);
			
			glActiveTexture(GL_TEXTURE1);
			glBindTexture(GL_TEXTURE_2D, texbufferB);
			
			glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "modelMat"), 1, GL_FALSE, glm::value_ptr(modelMat));
			glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "viewMat"), 1, GL_FALSE, glm::value_ptr(viewMat));
			glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "projMat"), 1, GL_FALSE, glm::value_ptr(projMat));
			
			glUniform3f(glGetUniformLocation(myShader->ID, "objColor"), 1.0f, 1.0f, 1.0f);
			glUniform3f(glGetUniformLocation(myShader->ID, "ambientColor"), 0.1f, 0.1f, 0.1f);
			glUniform3f(glGetUniformLocation(myShader->ID, "CameraPos"), myCamera->Position.x, myCamera->Position.y, myCamera->Position.z);
	
			myShader->SetUniform1i("material.diffuse", Shader::DIFFUSE);
		    myShader->SetUniform1i("material.specular", Shader::SPECULAR);
			myShader->SetUniform1f("material.shininess", 32);
			mesh.DrawVertexArray(myShader);

//绘制边框
			glStencilFunc(GL_NOTEQUAL,1, 0xFF);//不等于1的模板值可以通过,
			glStencilMask(0x00);//不支持写入,似乎可以注释掉,不知道注释之后有什么坏处
			glDisable(GL_DEPTH_TEST);//关掉深度测试
			lightShader->Use();
			modelMat = glm::scale(modelMat, glm::vec3(1.1f, 1.1f, 1.1f));//设置模型为原来代码块的1.1倍
			glUniformMatrix4fv(glGetUniformLocation(lightShader->ID, "modelMat"), 1, GL_FALSE, glm::value_ptr(modelMat));
			glUniformMatrix4fv(glGetUniformLocation(lightShader->ID, "viewMat"), 1, GL_FALSE, glm::value_ptr(viewMat));
			glUniformMatrix4fv(glGetUniformLocation(lightShader->ID, "projMat"), 1, GL_FALSE, glm::value_ptr(projMat));
			mesh.DrawVertexArray(lightShader);//绘画
			glStencilMask(0xFF);//如果上面的0x00注释掉了,这个也可以注释掉,效果好像没什么区别
			glEnable(GL_DEPTH_TEST);


			//model.Draw(myShader);
			glBindVertexArray(0);
		
		}
		

其中的DrawVertexArray函数,是我将Mesh中的测试画正方体的部分封装了出来。
效果图:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值