模板测试

模板测试(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

西门子TM PosInput1模块SSI编码器配置与速度测量实战

本文详细介绍了西门子TM PosInput1模块配置SSI绝对值编码器的实战步骤,涵盖硬件组态、工艺对象配置、编程实现与速度测量优化。重点解析了高分辨率编码器的数值处理技巧和常见调试问题,帮助工程师快速实现高精度位置与速度检测,提升自动化项目效率。

emacs5lisp的博客 340

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

一、模板测试(Stencil Test)

s178435865的专栏 1069

好书分享:Control and Estimation with MATLAB(5th Edition)pdf

基于MATLAB的控制与估计》(第5版)由八章组成,包括控制算法和设计。主要内容包括状态估计和数据平滑、RLS和卡尔曼滤波器状态估计、控制系统设计、自适应控制和PID。书中的概念已经使用MATLAB和Simulink实现。提供了可下载的MATLAB和Simulink文件。适合人群:大学生、研究生、控制类工程研究人员。需要电子版pdf,回复索取。

jixianhu的博客 1510

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

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

清清!的博客 1079

51单片机入门指南-基于STC89C52(持续更新)

一、环境介绍 编程IDE: keil5 单片机型号: STC89C51/52 开发板: 普中科技的开发板 完整PDF资源下载地址:https://download.youkuaiyun.com/download/xiaolong1126626497/19785856 二、51单片机开发手册介绍 2.1 前言 51单片机是对所有兼容Intel 8031指令系统的单片机的统称。 该系列单片机的始祖是Intel的8004单片机,后来随着Flash rom技术的发展,8004单片机取得了长足的进展,成为应用最.

8799

【ESP32使用MAX98357播放音频】

在物联网和智能家居领域,音频播放功能越来越受到重视。ESP32作为一款功能强大的微控制器,结合MAX98357音频放大器模块,可以实现高品质的音频播放。本文将详细介绍如何使用ESP32的I2S接口通过MAX98357进行音频播放。

vor234的博客 7529

OpenGL 模板测试

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

w2064004678的博客 805

含分布式电源的配电网三段式电流保护影响仿真研究

文章摘要 本文研究了分布式电源(DG)接入对配电网三段式电流保护的影响。通过在Matlab/Simulink平台搭建含同步发电机型DG的10kV配电网模型,设计了基于傅里叶算法的三段式电流保护模块(I段瞬时速断、II段限时速断、III段定时限过流)。研究分析了不同DG接入位置、容量及故障点对保护系统的影响机理。仿真结果表明,DG接入会改变故障电流特性,可能导致三种典型问题:保护范围扩大引起误动、保护灵敏度下降导致拒动,以及保护选择性丧失。该研究为含DG配电网的保护配置与整定提供了理论依据和仿真参考,对保障分

huanghm88的专栏 269

【Unity——模板测试Stencil】

简单的模板测试介绍

m0_62316271的博客 2274

思博伦仪表打流测试使用总结

下图红框中的checkbox为选中状态时,表示该流会携带测试仪做一些分析,包括时延和乱序等信息时需要的一些字节,当改选项选中时,如配置IPv4的TCP流,最小字节长度必须为78字节;如果需要64字节的TCP流,改选项必须不选中;

陌上花开缓缓归以的博客 1466

13、核心网络模块:VyOS 设备配置实战

本文详细介绍了如何使用 Ansible 核心网络模块对 VyOS 虚拟设备进行自动化配置,涵盖环境搭建、变量设置、任务编写、playbook 运行及配置验证全过程。通过实际案例展示了 Ansible 在网络设备管理中的强大功能,包括多设备支持、模板化配置、备份回滚等优势,并提供了最佳实践建议与未来发展趋势分析,帮助读者提升网络运维效率。

linux6sysadmin的博客 114

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

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

OpenGL 技术 2万+

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

模板测试StencilTest

有趣的空间效果!

weixin_65539050的博客 1233

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

深度测试 & 模板测试

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万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

测试用例模板

测试用例模板 文章目录前言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、付费专栏及课程。

余额充值