模板测试

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

用C++从零复刻Wordle:手把手教你实现命令行猜词游戏(含完整源码解析)

本文详细介绍了如何使用C++从零开始实现一个命令行版本的Wordle猜词游戏,包含完整的源码解析和核心模块设计。通过游戏逻辑控制器、单词库管理器等模块的构建,开发者可以学习C++实战技巧和性能优化方法,适合提升编程能力和游戏开发兴趣。

weixin_26763955的博客 334

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

一、模板测试(Stencil Test)

s178435865的专栏 1069

Yolov26 在 Rk3588 上的 Rknn Onnx 部署实践(c++)

本文介绍了YOLOv26在RK3588平台的C++推理部署方案。重点包括:1)扩展Ultralytics导出格式,新增RKNN_ONNX专用导出选项;2)重构Detect Head结构,使其更适合RKNN推理;3)提供C++侧后处理实现建议。该方案保留了Ultralytics训练生态,通过优化模型结构输出,将解码等操作移至C++端,充分发挥Rockchip NPU性能。适用于RK3588/RK356x等平台,需配合rknn-toolkit2使用,为YOLOv26的嵌入式部署提供完整解决方案。

qq_64366203的博客 2178

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

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

清清!的博客 1079

Flink 作业报错——TaskManager连接不上

Flink 作业报错——TaskManager连接不上

lm223的博客 1901

大模型辅助意图识别,更懂你的客户洞察平台

通过大量的学习和训练,大模型不仅具备庞大的知识库,更掌握着丰富的语言模式和语义规则,能够精准地理解每一段对话的含义,为每一通对话进行全面、准确的标注。主要来自客户的行为信息,将客户与机构的重要时刻以时间轴的方式呈现出来,掌握客户生命周期的完整脉络,识别一些容易被忽略的重要营销MOT(Moment Of Truth,关键时刻研究)机会,提示理财经理跟进处理。将客户的历史交易数据和埋点系统采集的客户行为数据结合起来,辅以部分内容资讯的偏好探测,综合分析和预测客户在各个维度的喜好程度,实现千人千面的客户推送。

Dezhuzhineng的博客 2161

OpenGL 模板测试

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

w2064004678的博客 805

电赛经验分享——赛前准备

⏩ 大家好哇!我是小光,想要成为系统架构师的嵌入式爱好者。⏩在之前的电赛中取得了省一的成绩,本文对电赛比赛前需要准备什么做一个经验分享。加入小光嵌入式交流群(qq群号:737327353)免费获取博主所有资料哦!

qq_52608074的博客 7779

【Unity——模板测试Stencil】

简单的模板测试介绍

m0_62316271的博客 2274

老 Intel Mac mini 装 OpenClaw:低成本常年在线方案

老款Intel Mac mini部署OpenClaw方案摘要 本文详细介绍了如何利用老款Intel Mac mini低成本部署OpenClaw系统。方案推荐2011-2018款Mac mini,建议升级至16GB内存和SSD存储以提升性能。部署步骤包括:1)安装Ubuntu系统;2)配置Docker环境;3)通过docker-compose部署OpenClaw及其依赖组件(PostgreSQL和Redis);4)进行系统级和Docker层面的性能优化;5)设置开机自启动服务。该方案充分利用老款设备剩余价值,

一键难忘的博客 2477

[网络安全自学篇] 二.Chrome浏览器保留密码功能渗透解析及登录加密入门笔记

最近开始学习网络安全相关知识,接触了好多新术语,感觉自己要学习的东西太多,真是学无止境,也发现了好几个默默无闻写着博客、做着开源的大神。接下来系统分享一些网络安全的自学笔记,希望读者们喜欢。 上一篇文章分享了看雪Web安全总结知识和一个异或解密的示例,本篇文章着重讲解Chrome浏览器保留密码功能渗透解析及登录加密入门笔记,结合实际例子一步步实现浏览器漏洞的挖掘。非常基础的文章,希望对入门的博友们有帮助,大神请飘过,谢谢各位看官!

杨秀璋的专栏 2万+

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

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

OpenGL 技术 2万+

芒果YOLOv8改进16:检测头Head篇:即插即用|新颖轻量化非对称多级压缩LADH检测头,原创改进适配YOLOv8高效检测头,检测头新颖性改进,全网首发独一份

YOLOv8代码改进教程:即插即用|新颖轻量化非对称多级压缩LADH检测头🎈

包括YOLOv5、YOLOv7、YOLOv8等模型改进 5613

模板测试StencilTest

有趣的空间效果!

weixin_65539050的博客 1233

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

深度测试 & 模板测试

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

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

测试用例模板

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

shulei00的博客 4万+

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

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、付费专栏及课程。

余额充值