模板测试

模板测试(Stencil Test)的基础知识 本文分享模板测试(Stencil Test)的基础知识 在渲染管线中, 模板测试发生在片元着色器处理和透明度测试之后, 深度测试之前. 模板测试最常见的应用就是各种遮罩, 特别是有形状的遮罩, 如Unity中的Mask组件, 这些遮罩的特点就是可以按照某种形状(可以是非矩形的)来渲染片元. 比如我们在游戏中经常看到的各种形状的头像 ,而Rect Mask 2D组件使用的是裁剪测试(Scissor Test), 可以指定绘制一块矩形区域内的片元. 模板测试的圆形遮罩如图所示. 模板测试基础 和深度测试类 阅读详情

当片段着色器处理完片段之后,模板测试(Stencil Test) 就开始执行了,和深度测试一样,它能丢弃一些片段。仍然保留下来的片段进入深度测试阶段,深度测试可能丢弃更多。模板测试基于模板缓冲(Stencil Buffer)。

模板缓冲中的模板值(Stencil Value)通常是8位的,因此每个片段/像素共有256种不同的模板值(译注:8位就是1字节大小,因此和char的容量一样是256个不同值)。这样我们就能将这些模板值设置为我们链接的,然后在模板测试时根据这个模板值,我们就可以决定丢弃或保留它了。

下面是一个模板缓冲的简单例子:

image description

模板缓冲先清空模板缓冲设置所有片段的模板值为0,然后开启矩形片段用1填充。场景中的模板值为1的那些片段才会被渲染(其他的都被丢弃)。

无论我们在渲染哪里的片段,模板缓冲操作都允许我们把模板缓冲设置为一个特定值。改变模板缓冲的内容实际上就是对模板缓冲进行写入。在同一次(或接下来的)渲染迭代我们可以读取这些值来决定丢弃还是保留这些片段。当使用模板缓冲的时候,你可以随心所欲,但是需要遵守下面的原则:

  • 开启模板缓冲写入。
  • 渲染物体,更新模板缓冲。
  • 关闭模板缓冲写入。
  • 渲染(其他)物体,这次基于模板缓冲内容丢弃特定片段。

使用模板缓冲我们可以基于场景中已经绘制的片段,来决定是否丢弃特定的片段。

物体轮廓

要理解模板测试是如何工作的,我们会展示一个用模板测试实现的一个特别的和有用的功能,叫做物体轮廓(Object Outlining)。

物体轮廓就像它的名字所描述的那样,它能够给每个(或一个)物体创建一个有颜色的边。在策略游戏中当你打算选择一个单位的时候它特别有用。给物体加上轮廓的步骤如下:

  1. 在绘制物体前,把模板方程设置为GL_ALWAYS,用1更新物体将被渲染的片段。
  2. 渲染物体,写入模板缓冲。
  3. 关闭模板写入和深度测试。
  4. 每个物体放大一点点。
  5. 使用一个不同的片段着色器用来输出一个纯颜色。
  6. 再次绘制物体,但只是当它们的片段的模板值不为1时才进行。
  7. 开启模板写入和深度测试。

这个过程将每个物体的片段模板缓冲设置为1,当我们绘制边框的时候,我们基本上绘制的是放大版本的物体能通过测试的地方,放大的版本绘制后物体就会有一个边。我们基本会使用模板缓冲丢弃所有的不是原来物体的片段的放大的版本内容。


(一)、我们先来创建一个非常基本的片段着色器,它输出一个边框颜色:singlecolor.fsh,

void main()
{
    outColor = vec4(0.04, 0.28, 0.26, 1.0);
}
我们只打算给两个箱子加上边框,所以我们不会对地面做什么。这样我们要先绘制地面,然后再绘制两个箱子(同时写入模板缓冲),接着我们绘制放大的箱子(同时丢弃前面已经绘制的箱子的那部分片段)。


(二)、开启模板测试,设置模板、深度测试通过或失败时才采取动作:

    //开启模板测试
    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
    //sfail: 如果模板测试失败将采取的动作。
    //dpfail: 如果模板测试通过,但是深度测试失败时采取的动作。
    //dppass: 如果深度测试和模板测试都通过,将采取的动作。
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

有两种函数可供我们使用去配置模板测试:glStencilFunc和glStencilOp。

void glStencilFunc(GLenum func, GLint ref, GLuint mask)函数有三个参数:

  • func:设置模板测试操作。这个测试操作应用到已经储存的模板值和glStencilFunc的ref值上,可用的选项是:GL_NEVER、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL、GL_ALWAYS。它们的语义和深度缓冲的相似。
  • ref:指定模板测试的引用值。模板缓冲的内容会与这个值对比。
  • mask:指定一个遮罩,在模板测试对比引用值和储存的模板值前,对它们进行按位与(and)操作,初始设置为1。因为模板缓冲中的模板值(Stencil Value)通常是8位, 0xFF相当于二进制的11111111。
glStencilFunc(GL_EQUAL, 1, 0xFF)它会告诉OpenGL,无论何时,一个片段模板值等于(GL_EQUAL)引用值1,片段就能通过测试被绘制了,否则就会被丢弃。

glStencilOp 描述我们如何更新缓冲。

glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)函数包含三个选项,我们可以指定每个选项的动作:

  • sfail: 如果模板测试失败将采取的动作。
  • dpfail: 如果模板测试通过,但是深度测试失败时采取的动作。
  • dppass: 如果深度测试和模板测试都通过,将采取的动作。

每个选项都可以使用下列任何一个动作。

操作 描述
GL_KEEP 保持现有的模板值
GL_ZERO 将模板值置为0
GL_REPLACE 将模板值设置为用glStencilFunc函数设置的ref值
GL_INCR 如果模板值不是最大值就将模板值+1
GL_INCR_WRAP 与GL_INCR一样将模板值+1,如果模板值已经是最大值则设为0
GL_DECR 如果模板值不是最小值就将模板值-1
GL_DECR_WRAP 与GL_DECR一样将模板值-1,如果模板值已经是最小值则设为最大值
GL_INVERT Bitwise inverts the current stencil buffer value.

glStencilOp函数默认设置为 (GL_KEEP, GL_KEEP, GL_KEEP) ,所以任何测试的任何结果,模板缓冲都会保留它的值。默认行为不会更新模板缓冲,所以如果你想写入模板缓冲的话,你必须像任意选项指定至少一个不同的动作。

使用glStencilFunc和glStencilOp,我们就可以指定在什么时候以及我们打算怎么样去更新模板缓冲了,我们也可以指定何时让测试通过或不通过。什么时候片段会被抛弃。


(三)、清空模板缓冲为0,为箱子的所有绘制的片段的模板缓冲更新为1:

glStencilFunc(GL_ALWAYS, 1, 0xFF); //所有片段都要写入模板缓冲
glStencilMask(0xFF); // 设置模板缓冲为可写状态
normalShader.Use();
DrawTwoContainers();
使用GL_ALWAYS模板测试函数,我们确保箱子的每个片段用模板值1更新模板缓冲。因为片段总会通过模板测试,在我们绘制它们的地方,模板缓冲用引用值更新。


(四)、绘制放大的箱子,但是这次关闭模板缓冲的写入:

glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00); // 禁止修改模板缓冲
glDisable(GL_DEPTH_TEST);
shaderSingleColor.Use();
DrawTwoScaledUpContainers();

模板方程设置为GL_NOTEQUAL,它保证我们只绘制箱子上不等于1的部分,这样只绘制前面绘制的箱子外围的那部分。注意,我们也要关闭深度测试,这样放大的的箱子也就是边框才不会被地面覆盖。做完之后还要保证再次开启深度缓冲。

场景中的物体边框的绘制方法最后看起来像这样:

glEnable(GL_DEPTH_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);  

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

glStencilMask(0x00); // 绘制地板时确保关闭模板缓冲的写入
normalShader.Use();
DrawFloor()  

glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(0xFF);
DrawTwoContainers();

glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00);
glDisable(GL_DEPTH_TEST);
shaderSingleColor.Use();
DrawTwoScaledUpContainers();
glStencilMask(0xFF);
glEnable(GL_DEPTH_TEST);

全部代码如下:

//
//  OpenGLStencilTest.cpp
//  shaderTest
//
//  Created by MacSBL on 2017/1/23.
//
//

#include "OpenGLStencilTest.h"


bool OpenGLStencilTest::init()
{
    if (!Layer::init()) {
        return false;
    }
    origin = Director::getInstance()->getVisibleOrigin();
    vsize = Director::getInstance()->getVisibleSize();
    
    GLfloat cubeVertices[] = {
        // Positions          // Texture Coords
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
        0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
        
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
    };
    GLfloat planeVertices[] = {
        // Positions            // Texture Coords (note we set these higher than 1 that together with GL_REPEAT as texture wrapping mode will cause the floor texture to repeat)
        5.0f,  -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f,  5.0f,  0.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
        
        5.0f,  -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
        5.0f,  -0.5f, -5.0f,  2.0f, 2.0f
    };
    
    auto gprogram = GLProgram::createWithFilenames("box.vsh", "box.fsh");
    this->setGLProgram(gprogram);
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // box vao;
    glGenVertexArrays(1, &boxvao);
    glBindVertexArray(boxvao);
    
    GLuint boxvbo;
    glGenBuffers(1, &boxvbo);
    glBindBuffer(GL_ARRAY_BUFFER, boxvbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW);
    
    //给vertex shader 的属性传值
    GLuint posloc = glGetAttribLocation(gprogram->getProgram(), "a_position");
    glEnableVertexAttribArray(posloc);
    glVertexAttribPointer(posloc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    
    
    GLuint texloc = glGetAttribLocation(gprogram->getProgram(), "a_texcoord");
    glEnableVertexAttribArray(texloc);
    glVertexAttribPointer(texloc, 2, GL_FLOAT, GL_FALSE, 5* sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    boxoutline_program = new GLProgram();
    boxoutline_program->initWithFilenames("box.vsh", "singlecolor.fsh");
    boxoutline_program->link();
    
    //给vertex shader 的属性传值
    GLuint ploc = glGetAttribLocation(boxoutline_program->getProgram(), "a_position");
    glEnableVertexAttribArray(ploc);
    glVertexAttribPointer(ploc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    
    GLuint tloc = glGetAttribLocation(boxoutline_program->getProgram(), "a_texcoord");
    glEnableVertexAttribArray(tloc);
    glVertexAttribPointer(tloc, 2, GL_FLOAT, GL_FALSE, 5* sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    
    glBindVertexArray(0);
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //floor vao;
    glGenVertexArrays(1, &floorvao);
    glBindVertexArray(floorvao);
    
    GLuint floorvbo;
    glGenBuffers(1, &floorvbo);
    glBindBuffer(GL_ARRAY_BUFFER, floorvbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW);
    
     //给vertex shader 的属性传值
    GLuint posloc2 = glGetAttribLocation(gprogram->getProgram(), "a_position");
    glVertexAttribPointer(posloc2, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(posloc2);
    
    GLuint texloc2 = glGetAttribLocation(gprogram->getProgram(), "a_texcoord");
    glVertexAttribPointer(texloc2, 2, GL_FLOAT, GL_FALSE, 5* sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(texloc2);
    
    glBindVertexArray(0);

    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 开启深度测试
    Director::getInstance()->setDepthTest(true);
//    glDepthFunc(GL_ALWAYS);
    
    //开启模板测试
    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
    //sfail: 如果模板测试失败将采取的动作。
    //dpfail: 如果模板测试通过,但是深度测试失败时采取的动作。
    //dppass: 如果深度测试和模板测试都通过,将采取的动作。
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    
    //加载纹理
    auto sprite = Sprite::create("container2.png");
    boxTexture = sprite->getTexture()->getName();
    
    auto floorimg = Sprite::create("wall.jpg");
    floorTexture = floorimg->getTexture()->getName();
    
    cam = new MyCamera(Vec3(0, 0, 3));
    
    //touch事件
    auto elistener = EventListenerTouchOneByOne::create();
    elistener->onTouchBegan = CC_CALLBACK_2(OpenGLStencilTest::onTouchBegan, this);
    elistener->onTouchMoved = CC_CALLBACK_2(OpenGLStencilTest::onTouchMoved, this);
    elistener->onTouchEnded = CC_CALLBACK_2(OpenGLStencilTest::onTouchEnded, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(elistener, this);
    
    return true;
}

void OpenGLStencilTest::visit(cocos2d::Renderer *render, const cocos2d::Mat4 &parentTransform, uint32_t parentflag)
{
    Layer::visit(render, parentTransform, parentflag);
    _command.init(_globalZOrder);
    _command.func = CC_CALLBACK_0(OpenGLStencilTest::onDraw, this);
    Director::getInstance()->getRenderer()->addCommand(&_command);
}

void OpenGLStencilTest::onDraw()
{
    
    //清空模板缓冲为0,为箱子的所有绘制的片段的模板缓冲更新为1:
    glStencilFunc(GL_ALWAYS, 1, 0xFF); //所有片段都要写入模板缓冲
    glStencilMask(0xFF); //设置模板缓冲为可写状态
    
    
    auto program = this->getGLProgram();
    program->use();
    
    
    auto view = cam->GetViewMatrix();
    auto projection = new Mat4;
    Mat4::createPerspective(cam->Zoom, vsize.width/vsize.height, 0.1, 1000.0f, projection);
    
    //给vertex shader 的uniform 传值
    glUniformMatrix4fv(glGetUniformLocation(program->getProgram(), "view"), 1, GL_FALSE,view->m);
    glUniformMatrix4fv(program->getUniformLocation("projection"), 1, GL_FALSE, projection->m);
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //box
    glBindVertexArray(boxvao);
    GL::bindTexture2DN(0, boxTexture);
    glUniform1i(program->getUniformLocation("u_tex"), 0);
    auto model = new Mat4();
    model->translate(-1, 0, -1);
    glUniformMatrix4fv(glGetUniformLocation(program->getProgram(), "model"), 1, GL_FALSE, model->m);
    glDrawArrays(GL_TRIANGLES, 0, 36);

    auto model2 = new Mat4;
    model2->translate(1, 0, 0);
    glUniformMatrix4fv(program->getUniformLocation("model"), 1, GL_FALSE, model2->m);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    glStencilMask(0x00); // 绘制地板时确保关闭模板缓冲的写入
    //floor
    glBindVertexArray(floorvao);
    GL::bindTexture2D(floorTexture);
    auto fmodel = new Mat4;
    glUniformMatrix4fv(program->getUniformLocation("model"), 1, GL_FALSE, fmodel->m);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    
    glBindVertexArray(0);
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //箱子的外框, 是绘制放大的箱子
    glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
    glStencilMask(0x00); //// 禁止修改模板缓冲
    Director::getInstance()->setDepthTest(false);
    
    boxoutline_program->use();
    //给vertex shader 的uniform 传值
    glUniformMatrix4fv(glGetUniformLocation(boxoutline_program->getProgram(), "view"), 1, GL_FALSE,view->m);
    glUniformMatrix4fv(boxoutline_program->getUniformLocation("projection"), 1, GL_FALSE, projection->m);
    
    
    glBindVertexArray(boxvao);
//    GL::bindTexture2DN(0, boxTexture);
    
    GLfloat fscale = 1.1;
    model = new Mat4();
    model->translate(-1, 0, -1);
    model->scale(fscale);
    glUniformMatrix4fv(glGetUniformLocation(boxoutline_program->getProgram(), "model"), 1, GL_FALSE, model->m);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    
    model2 = new Mat4;
    model2->translate(1, 0, 0);
    model2->scale(fscale);
    glUniformMatrix4fv(boxoutline_program->getUniformLocation("model"), 1, GL_FALSE, model2->m);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    
    glStencilMask(0xFF);
    Director::getInstance()->setDepthTest(true);
 
}
#pragma mark touch

bool OpenGLStencilTest::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *evt)
{
    return true;
}

void OpenGLStencilTest::onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *evt)
{
    Vec2 curpos = touch->getLocationInView();
    Vec2 prepos = touch->getPreviousLocationInView();
    GLfloat dx = curpos.x - prepos.x;
    GLfloat dy = curpos.y - prepos.y;
    
    //移动摄像机
    GLfloat camspeed = 0.05f;
    if (curpos.y - prepos.y > 0) { //w
        cam->ProcessKeyboard(Cam_Move::FORWARD, camspeed);
    }else if (curpos.y - prepos.y < 0){ //s
        cam->ProcessKeyboard(Cam_Move::BACKWARD, camspeed);
    }
    else if (curpos.x - prepos.x < 0){ //a
        cam->ProcessKeyboard(Cam_Move::LEFT, camspeed);
    }else if (curpos.x - prepos.x > 0){ //d
        cam->ProcessKeyboard(Cam_Move::RIGHT, camspeed);
    }
    //(3)旋转摄像机
    
    //    cam->ProcessMouseMovement(dx, dy);
    //(4)缩放
    //    if(fov >= 1 && fov <= 45){
    //        fov -= dx * camspeed;
    //    }
    //    if(fov <= 1){
    //        fov = 1;
    //    }
    //    if(fov >= 45){
    //        fov = 45;
    //    }
}

void OpenGLStencilTest::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *evt)
{
    
}


测试总结模板 项目                 项目名称 XXXX 总结部门 测试部 测试                测试周期 X月X日~X月X日 总结人 XXX 项目 测试                项目测试概述... 阅读详情

相关推荐

【Unity Shader】 模板测试

介绍 模板测试stencil test是3d渲染管线中介于透明测试alpha test和深度测试depth test之间的测试,目的是根据条件来比较设置的参考值referenceValue和模板缓冲区stencil buff中对应的值stencilBuffValue的大小,如果条件满足就让片段fragment(候选的像素)进入下一测试,即深度测试,条件不满足就过滤掉片段,不把对应材质的片段输出到...

赞美月亮的专栏 2971

Unity3D Shader系列之模板测试

1 引言 前面3篇文章详细总结了深度纹理相关的知识,可以文中可以看出,在Unity中使用深度纹理及其简单。但是我们为什么仍然在这3篇文章中花了大量的篇幅去说明深度纹理的底层知识呢?因为只有知道了底层的数学和原理,才能举一反三,才能心里有底。在学习建立在该原理上的新技术的时候,才能一点也不吃力。不论是计算机图形学还是CPU端的性能优化,本质的东西都是几十年不变的。只有夯实了基础,才有建高楼的可能。只有知道了本质,我们才知道如何去优化我们的代码,让其运行得更加地高效。才能写出自己真正感到满意、感到欣赏的代码。

老王的博客 4834

opengl深度测试、模板测试

深度测试 深度缓冲就像颜色缓冲(Color Buffer)(储存所有的片段颜色:视觉输出)一样,在每个片段中储存了信息,并且(通常)和颜色缓冲有着一样的宽度和高度。深度缓冲是由窗口系统自动创建的,它会以16、24或32位float的形式储存它的深度值。在大部分的系统中,深度缓冲的精度都是24位的。 当深度测试(Depth Testing)被启用的时候,OpenGL会将一个片段的深度值与深度缓冲的内容进行对比。OpenGL会执行一个深度测试,如果这个测试通过了的话,深度缓冲将会更新为新的深度值。如果深度测试失

LIEY 754

OpenGL之模板测试

默认情况下设置的位掩码所有位都为1,不影响输出,但如果我们将它设置为0x00,写入缓冲的所有模板值最后都会变成0.这与深度测试中的glDepthMask(GL_FALSE)是等价的。模板测试是根据又一个缓冲来进行的,它叫做模板缓冲(Stencil Buffer),我们可以在渲染的时候更新它来获得一些很有意思的效果。场景中的片段将会只在片段的模板值为1的时候会被渲染(其它的都被丢弃了)。1.在绘制(需要添加轮廓的)物体之前,将模板函数设置为GL_ALWAYS,每当物体的片段被渲染时,将模板缓冲更新为1。

一个小菜鸡的学习之路 987

深入了解OpenGL——模板测试

我们在用OpenGL绘图时往往想制作一些复合图形以及凹凸多边形,像五角星、大的矩形里再画一个小的矩形;另外有时还想做些镂空图或类似的效果。 这时我们可以开启模板测试功能来完成这些需求。 由于OpenGL的一个绘制流水线特征以及GPU着色特征,像对于大矩形里画小矩形这种不能通过先绘制大矩形,然后再在其中绘制小矩形的方式进行绘制,否则当此复合图形在做一些旋转时,我们会发现小矩形部分会有非常严重的抖

蚂蚁的坚持 1378

【实战指南】Jaspersoft Studio + JasperReports:从零构建企业级PDF报表

本文详细介绍了如何使用Jaspersoft Studio和JasperReports从零构建企业级PDF报表。通过可视化设计、数据连接、模板设计到最终输出的全链路支持,这套组合方案显著降低了报表开发的维护成本。文章还提供了开发环境搭建、中文乱码解决方案、Java集成代码及性能优化技巧,适合需要高效生成复杂PDF报表的开发者。

weixin_42666036的博客 247

3.1 模板测试与深度测试(Stencil Test & Z Test)

一、模板测试(Stencil Test)

s178435865的专栏 1069

STM32L433使用DSP库配置过程

STM32L433中有FPU,在使用中为了使用其中的部分函数,需要对其进行配置。     配置成功后做些总结,留待后续复习备忘,同时也希望有朋友像我一样使用DSP库配置时少走弯路,留作交流。

在在在的博客 4550

LearnOpenGL学习笔记—高级OpenGL 02:模板测试

LearnOpenGL学习笔记—高级OpenGL:模板测试 本节对应官网学习内容:模板测试

清清!的博客 1079

陀螺仪及四元数解算

陀螺仪 四元数

zb313982521的博客 2005

国密证书实战:在CentOS 7上构建GmSSL私有CA与完整证书链

本文详细介绍了在CentOS 7操作系统上,使用GmSSL工具构建私有国密证书颁发机构(CA)与完整证书链的实战指南。内容涵盖从部署GmSSL、创建国密根CA、签发服务器与客户端证书,到生产环境安全加固与最佳实践的全流程,旨在帮助系统管理员和安全工程师建立统一、可控的内部国密安全通信体系。

jenkins8butler的博客 496

OpenGL 模板测试

模板测试是一个强大的、可编程的遮罩系统。你通过设置规则和更新操作,来控制哪些像素可以被绘制,并动态地标记区域,用于后续的绘制 passes。它的功能是逻辑性的深度测试是一个高效的、硬件加速的遮挡系统。它自动处理物体的前后关系,是3D图形渲染的基石。它的功能是物理性的(模拟视觉遮挡)

w2064004678的博客 805

SRAM故障排查实战:如何用Nano Prober定位6T存储单元的异常点

本文详细介绍了在SRAM故障排查中,如何运用Nano Prober(纳米探针)技术精准定位6T存储单元的内部异常。面对传统方法难以发现的电性参数漂移(如晶体管阈值电压偏移)或微小物理缺陷,Nano Prober能直接对单个6T单元内的晶体管进行I-V特性测量,结合失效模式分析,有效解决读写错误等疑难问题,是芯片失效分析的关键工具。

v5w6x的博客 668

【Unity——模板测试Stencil】

简单的模板测试介绍

m0_62316271的博客 2274

【从零开始入门unity游戏开发之——C#篇37】进程、线程、C# 中实现多线程有多种方案和async/await异步编程

进程、线程、C# 中实现多线程有多种方案和async/await异步编程

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 1470

从0到1:用Claude 3.7十日拿下教育部课题申报书(附可修改LaTeX模板)

🟣"作为教育部人文社科项目评审专家,请根据近三年立项数据分析,为[您的学科方向]领域推荐5个具有创新性且符合'十四五'规划的重点选题,要求选题体现交叉学科特征,并标注潜在理论突破点"🟣"根据前期研究基础,创建包含4个研究模块、12个关键节点的三维技术路线图,要求体现实验仿真-实证研究-理论建模的螺旋递进关系,并标注每个节点的预期成果形态"🟣"现在切换至教育部学科评审组组长模式,从选题价值、创新程度、研究可行性三个维度对本申报书进行盲审,生成包含9个扣分风险点的诊断报告及修改优先级排序"

智能AI让学术科研更容易 545

OpenGL中的Alpha测试,深度测试,模板测试,裁减测试

大家好。现在因为参加工作的关系,又是长时间没有更新。趁着国庆的空闲,总算是又写出了一课。我感觉入门的知识已经快要介绍完毕,这课之后再有一课,就可以告一段落了。以后我可能会写一些自己在这方面的体会,做一份进阶课程。现在即将放出的是第十二课的内容。首先还是以前课程的连接:第一课,编写第一个OpenGL程序第二课,绘制几何图形第三课,绘制几何图形的一些细节问题第四课,颜色的选择第五课,三维的空间变换第六

OpenGL 技术 2万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

模板测试StencilTest

有趣的空间效果!

weixin_65539050的博客 1233

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

深度测试 & 模板测试

1. 深度测试 Depth testing 1.1 深度测试函数 Depth test function 1.2 深度值精度 Depth value precision 1.3 深度缓冲的可视化 1.4 深度冲突 1.4.1 防止深度冲突 2. 模板测试 Stencil testing 2.1 模板函数 Stencil function 2.1.1 函数 glStencilFunc...

u014767384的博客 1万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

测试用例模板

测试用例模板 文章目录前言1.测试用例模板2上线回归测试参考关键词链接 前言 这个是模仿别人的模板来进行补充的。有些是不需要的,但是我看到了,就纪录了下来,以备后来之需 这个最好是利用 excel 思维导图来做,我文字打在这里是引文方便更新,页面限制,也放不了多大的表格 1.测试用例模板 表头编写 用例编写者 (此列下面是文档地址) 评审时间 2020/3/27 需求文档 ...

shulei00的博客 4万+

8.模板测试

图形,渲染,OpenGl

x13262608581的博客 791

Opengl之模板测试

当之后,,和深度测试一样,它也可能会丢弃片段。接下来,被保留的片段会进入深度测试,它可能会丢弃更多的片段。模板测试是根据又一个缓冲来进行的,它叫做我们可以在渲染的时候更新它来获得一些很有意思的效果。一个模板缓冲中,(通常)的。所以每个像素/片段一共能有256种不同的模板值。我们可以将这些模板值设置为我们想要的值,然后当某一个片段有某一个模板值的时候,我们就可以选择丢弃或是保留这个片段了。,之后在模板缓冲中使用1填充了一个空心矩形。场景中的片段将会只在片段的模板值为1的时候会被渲染(其它的都被丢弃了)。

qq_44632658的博客 371
上一篇: 几种光源
下一篇: 混合
「已注销」
博客等级 码龄17年 6粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值