OpenGL学习之模板测试绘制模型的轮廓

1、本次试验是参考LearnOpenGL网站进行学习总结。有关模板测试的概念和原理请查看学习网站即可,这里就不做解释。
2、再啰嗦一下绘制轮廓的主要步骤:
(1).在绘制物体前,把模板方程设置为GL_ALWAYS,用1更新物体将被渲染的片段。
(2).渲染物体,写入模板缓冲。
(3).关闭模板写入和深度测试。
(4).每个物体放大一点点。
(5).使用一个不同的片段着色器用来输出一个纯颜色。
(6).再次绘制物体,但只是当它们的片段的模板值不为1时才进行。
(7).开启模板写入和深度测试。
上面是网站上的作者给定的创建步骤,在这里我再详细加一下注解,因为要绘制物体轮廓那么在场景中分别画了两遍模型,第一次是原始的模型,第二遍是带有模板写入并且是带有纯色模型。最后是对原物体关闭深度测试,不写入模板测试,而对第二遍绘制的模型对其缩放值,假设为scale。将其缩放值改为scale+0.1即可。
3、下面在用代码演示上面的整个过程。
头文件:

    GLuint  m_cubeVBO;
    GLuint  m_cubeVAO;
    CShader* m_cubeShader;
    CTexture* m_cubeTexture;

实现文件:下面代码时创建立方体盒子,并设置纹理,加了两张贴图进行融合,并且用颜色再次融合。

          glGenVertexArrays(1, &m_cubeVAO);
          glBindVertexArray(m_cubeVAO);

          glGenBuffers(1, &m_cubeVBO);
          glBindBuffer(GL_ARRAY_BUFFER, m_cubeVBO);

           //Make a cube out of triangles (two triangles per side)
          GLfloat vertexData[] = {
              //  X     Y     Z       U     V   R    G    B
              // bottom
              -1.0f,-1.0f,-1.0f,   0.0f, 0.0f,  1.0, 0.0, 0.0,
              1.0f,-1.0f,-1.0f,   1.0f, 0.0f,   0.0, 1.0, 0.0,
              -1.0f,-1.0f, 1.0f,   0.0f, 1.0f,  0.0, 0.0, 1.0,
              1.0f,-1.0f,-1.0f,   1.0f, 0.0f,   1.0, 1.0, 0.0,
              1.0f,-1.0f, 1.0f,   1.0f, 1.0f,   0.0, 1.0, 1.0,
              -1.0f,-1.0f, 1.0f,   0.0f, 1.0f,  1.0, 0.0, 1.0,

              // top
              -1.0f, 1.0f,-1.0f,   0.0f, 0.0f,  1.0, 0.0, 0.0,
              -1.0f, 1.0f, 1.0f,   0.0f, 1.0f,  0.0, 1.0, 0.0,
              1.0f, 1.0f,-1.0f,   1.0f, 0.0f,   0.0, 0.0, 1.0,
              1.0f, 1.0f,-1.0f,   1.0f, 0.0f,   1.0, 1.0, 0.0,
              -1.0f, 1.0f, 1.0f,   0.0f, 1.0f,  0.0, 1.0, 1.0,
              1.0f, 1.0f, 1.0f,   1.0f, 1.0f,   1.0, 0.0, 1.0,

              // front
              -1.0f,-1.0f, 1.0f,   1.0f, 0.0f,  1.0, 0.0, 0.0,
              1.0f,-1.0f, 1.0f,   0.0f, 0.0f,   0.0, 1.0, 0.0,
              -1.0f, 1.0f, 1.0f,   1.0f, 1.0f,  0.0, 0.0, 1.0,
              1.0f,-1.0f, 1.0f,   0.0f, 0.0f,   1.0, 1.0, 0.0,
              1.0f, 1.0f, 1.0f,   0.0f, 1.0f,   0.0, 1.0, 1.0,
              -1.0f, 1.0f, 1.0f,   1.0f, 1.0f,  1.0, 0.0, 1.0,

              // back
              -1.0f,-1.0f,-1.0f,   0.0f, 0.0f,  1.0, 0.0, 0.0,
              -1.0f, 1.0f,-1.0f,   0.0f, 1.0f,  0.0, 1.0, 0.0,
              1.0f,-1.0f,-1.0f,   1.0f, 0.0f,   0.0, 0.0, 1.0,
              1.0f,-1.0f,-1.0f,   1.0f, 0.0f,   1.0, 1.0, 0.0,
              -1.0f, 1.0f,-1.0f,   0.0f, 1.0f,  0.0, 1.0, 1.0,
              1.0f, 1.0f,-1.0f,   1.0f, 1.0f,   1.0, 0.0, 1.0,

              // left
              -1.0f,-1.0f, 1.0f,   0.0f, 1.0f,  1.0, 0.0, 0.0,
              -1.0f, 1.0f,-1.0f,   1.0f, 0.0f,  0.0, 1.0, 0.0,
              -1.0f,-1.0f,-1.0f,   0.0f, 0.0f,  0.0, 0.0, 1.0,
              -1.0f,-1.0f, 1.0f,   0.0f, 1.0f,  1.0, 1.0, 0.0,
              -1.0f, 1.0f, 1.0f,   1.0f, 1.0f,  0.0, 1.0, 1.0,
              -1.0f, 1.0f,-1.0f,   1.0f, 0.0f,  1.0, 0.0, 1.0,

              // right
              1.0f,-1.0f, 1.0f,   1.0f, 1.0f,   1.0, 0.0, 0.0,
              1.0f,-1.0f,-1.0f,   1.0f, 0.0f,   0.0, 1.0, 0.0,
              1.0f, 1.0f,-1.0f,   0.0f, 0.0f,   0.0, 0.0, 1.0,
              1.0f,-1.0f, 1.0f,   1.0f, 1.0f,   1.0, 1.0, 0.0,
              1.0f, 1.0f,-1.0f,   0.0f, 0.0f,   0.0, 1.0, 1.0,
              1.0f, 1.0f, 1.0f,   0.0f, 1.0f,    1.0, 0.0, 1.0
          };
          m_cubeShader->loadShader("../res/shader/cube.vs", "../res/shader/cube.ps");
          GLint attrib = glGetAttribLocation(m_cubeShader->getProgram(), "position");
          std::cout << "Position Location: " << attrib << std::endl;
          GLint arribTex = glGetAttribLocation(m_cubeShader->getProgram(), "texCoords");
          std::cout << "TexCoords Location: " << attrib << std::endl;
          GLint arribcolor = glGetAttribLocation(m_cubeShader->getProgram(), "outColor");
          std::cout << "arribcolor Location: " << arribcolor << std::endl;
          m_uniformBlockCube = glGetUniformBlockIndex(m_cubeShader->getProgram(), "Matrices");

          glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
          
          // 启用顶点属性数组,并设置顶点的属性指针
          glEnableVertexAttribArray(attrib);
          glVertexAttribPointer(attrib, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);

          // 启用UV属性数组,并设置UV属性指针
           glEnableVertexAttribArray(arribTex);
           glVertexAttribPointer(arribTex, 2, GL_FLOAT, GL_TRUE, 8 * sizeof(GLfloat), (const GLvoid*)(3 * sizeof(GLfloat)));

           //启用颜色属性数组,并设置颜色属性指针
           glEnableVertexAttribArray(arribcolor);
           glVertexAttribPointer(arribcolor, 3, GL_FLOAT, GL_TRUE, 8 * sizeof(GLfloat), (const GLvoid*)(5 * sizeof(GLfloat)));
          // 解绑 VAO
          glBindVertexArray(0);

          //Load Texture1
          m_cubeTexture->loadTexture("../res/image/wooden-crate.jpg");
          //Load Texture2
          m_cubeTexture->loadTexture("../res/image/awesomeface.png");

创建完之后记得开启模板测试及深度测试,模板测试函数,深度测试函数

    glEnable(GL_DEPTH_TEST);      //启用深度测试
    glDepthFunc(GL_LESS);
    glEnable(GL_STENCIL_TEST);    //开启模板测试
    glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

好了下面准备着色器代码,首先是为立方体盒子提供的着色器代码
cube.vs代码:

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;
layout (location = 3) in vec3 outColor;


out VS_OUT
{
	vec2 TexCoords;
	vec3 OutColor;
}vs_out;

layout (std140) uniform Matrices
{
	mat4 projection;
	mat4 view;
};

uniform mat4 model ;


void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
    vs_out.TexCoords = vec2(texCoords.x , 1-texCoords.y);
	vs_out.OutColor = outColor;
}

cube.ps代码:

#version 330 core
in VS_OUT
{
	vec2 TexCoords;
	vec3 OutColor;

}fs_in;

out vec4 color;

uniform sampler2D texture_diffuse1;
uniform sampler2D texture_diffuse2;

void main()
{    
	//color = vec4(texture(texture_diffuse1,TexCoords)) * vec4(outcolor,1.0f);
	color = mix(texture(texture_diffuse1,fs_in.TexCoords),texture(texture_diffuse2,fs_in.TexCoords),0.5) * vec4(fs_in.OutColor,1.0);
}

下面再准备模板写入的着色器代码:
stencil.vs

#version 330 core
layout (location = 0) in vec3 position;


uniform mat4 model;
layout (std140) uniform Matrices
{
	mat4 projection;
	mat4 view;
};

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
}

stencil.ps

#version 330 core

out vec4 color;


void main()
{             
    color = vec4(1.0, 1.0, 0.0, 1.0);
}

好了,着色器代码准备完毕之后下面就看如何设置让物体显示轮廓了。
首先设置相机的投影和视图矩阵给着色器,代码如下:
这种写法,可以一次设置避免可多次传入数据的作用,你可以参考高级GLSL

    glm::mat4 projection = m_pCamera->getCameraProjectMatrix();
    glm::mat4 view = m_pCamera->getCameraViewMatrix();
    glBindBuffer(GL_UNIFORM_BUFFER, m_uboMatrices);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(projection));
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glBindBuffer(GL_UNIFORM_BUFFER, m_uboMatrices);
    glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view));
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

加载着色器:

          m_cubeShader->loadShader("../res/shader/cube.vs", "../res/shader/cube.ps");
          m_modelStencilShader->loadShader("../res/shader/stencil.vs", "../res/shader/stencil.ps");

好了下面是模板写入代码:

    //模板测试
    glStencilFunc(GL_ALWAYS, 1, 0xFF);
    glStencilMask(0xFF);
    m_modelStencilShader->ProgramUse();
    glm::mat4 cubeScale = glm::scale(glm::vec3(1.1,1.1,1.1));//记得要修改缩放值
    m_modelStencilShader->setShaderUniform(m_cubeShader->getProgram(), "model", cubeScale, GL_FALSE);


    // bind the VAO (the triangle)
    glBindVertexArray(m_cubeVAO);
    // draw the VAO
    glDrawArrays(GL_TRIANGLES, 0, 36);
    // unbind the VAO, the program and the texture
    glBindVertexArray(0);

    m_modelStencilShader->stopProgrameUse();

关闭模板写入,关闭深度测试 再次绘制模型开启深度测试。

    //启用着色器
      m_cubeShader->ProgramUse();
     glm::mat4 model;
     model = glm::scale(glm::vec3(1.0,1.0, 1.0));
     //给模型设置缩放值大小
     m_cubeShader->setShaderUniform(m_cubeShader->getProgram(), "model", model, GL_FALSE);
     //绑定材质
     m_cubeTexture->bindTexture();
     //给片段设置纹理采样值
     m_cubeShader->setShaderUniform(m_cubeShader->getProgram(), "texture_diffuse1",(GLuint) 0);
     m_cubeShader->setShaderUniform(m_cubeShader->getProgram(), "texture_diffuse2", (GLuint)1);
     glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
     glStencilMask(0x00);
     //关闭深度测试
     glDisable(GL_DEPTH_TEST);
     //绑定VAO
     glBindVertexArray(m_cubeVAO);
     //绘制VAO
      glDrawArrays(GL_TRIANGLES, 0,  36);
     //解绑VAO
     glBindVertexArray(0);
     //开启深度测试
     glEnable(GL_DEPTH_TEST);
     //关闭着色器
     m_cubeShader->stopProgrameUse();

运行程序如下图所示:
OpenGL学习之模板测试绘制模型的轮廓_第1张图片

你可能感兴趣的:(OpenGL)