什么是裁剪测试?在Opengl中如何使用裁剪测试

什么是裁剪测试

剪裁测试用于限制绘制区域,在 OpenGL 中启用裁剪测试可以在屏幕或者帧缓冲上指定一个矩形区域,然后在该矩形区域内绘制,只有在该区域内的片元才有机会最终进入帧缓冲,不在该区域内的将会被丢弃, 裁剪测试的效果就相当于在屏幕上开辟一个矩形区域,在该区域内的内容才会处于可见状态。

裁剪测试的一个重要的作用就是提高渲染性能,用于在渲染绘制时只刷新屏幕上发生变化的部分区域。

需要注意的是裁剪测试只是在原来的视口标准的绘制区域内开辟一块矩形区域来控制显示的区域,而不是把内容放到裁剪的区域内来显示。

在Opengl中如何使用裁剪测试

Opengl中关于裁剪测试的几个API,它们分别是

  • 启用剪裁测试
glEnable(GL_SCISSOR_TEST);
  • 禁用剪裁测试
glDisable(GL_SCISSOR_TEST);
  • 指定剪裁窗口
glScissor(x,y,width,height); 

x 和 y 坐标所在的坐标系是以视口矩形区域的左下角为原点的,x 轴向右,y 轴向上的坐标系,对应到屏幕的坐标,就是以屏幕的左下角为坐标原点。

实战例子

在之前的系列入门教程中Opengl ES之纹理贴图 我们介绍了纹理贴图的相关知识点, 今天我们就在这个基础上使用裁剪测试绘制一个蓝色的方块。

我们先来看下完整的代码再做相关解析:

#include "ScissorTestOpengl.h"

#include "TextureMapOpengl.h"

#include "../utils/Log.h"

// 顶点着色器
static const char *ver = "#version 300 es\n"
                         "in vec4 aPosition;\n"
                         "in vec2 aTexCoord;\n"
                         "out vec2 TexCoord;\n"
                         "void main() {\n"
                         "  TexCoord = aTexCoord;\n"
                         "  gl_Position = aPosition;\n"
                         "}";

// 片元着色器
static const char *fragment = "#version 300 es\n"
                              "precision mediump float;\n"
                              "out vec4 FragColor;\n"
                              "in vec2 TexCoord;\n"
                              "uniform sampler2D ourTexture;\n"
                              "void main()\n"
                              "{\n"
                              "    FragColor = texture(ourTexture, TexCoord);\n"
                              "}";


// 使用绘制两个三角形组成一个矩形的形式(三角形带)
// 第一第二第三个点组成一个三角形,第二第三第四个点组成一个三角形
const static GLfloat VERTICES[] = {
        0.5f,-0.5f, // 右下
        0.5f,0.5f, // 右上
        -0.5f,-0.5f, // 左下
        -0.5f,0.5f // 左上
};

// 纹理坐标(原点在左下角,这样贴图看到的会是倒置的
//const static GLfloat TEXTURE_COORD[] = {
//        1.0f,0.0f, // 右下
//        1.0f,1.0f, // 右上
//        0.0f,0.0f, // 左下
//        0.0f,1.0f // 左上
//};

// 贴图纹理坐标(参考手机屏幕坐标系统,原点在左上角)
//由于对一个OpenGL纹理来说,它没有内在的方向性,因此我们可以使用不同的坐标把它定向到任何我们喜欢的方向上,然而大多数计算机图像都有一个默认的方向,它们通常被规定为y轴向下,X轴向右
const static GLfloat TEXTURE_COORD[] = {
        1.0f,1.0f, // 右下
        1.0f,0.0f, // 右上
        0.0f,1.0f, // 左下
        0.0f,0.0f // 左上
};

// 四分屏  GL_REPEAT环绕方式
//const static GLfloat TEXTURE_COORD[] = {
//        2.0f,2.0f, // 右下
//        2.0f,0.0f, // 右上
//        0.0f,2.0f, // 左下
//        0.0f,0.0f // 左上
//};

// 九分屏 GL_REPEAT环绕方式
//const static GLfloat TEXTURE_COORD[] = {
//        3.0f,3.0f, // 右下
//        3.0f,0.0f, // 右上
//        0.0f,3.0f, // 左下
//        0.0f,0.0f // 左上
//};


ScissorTestOpengl::ScissorTestOpengl():BaseOpengl() {
    initGlProgram(ver,fragment);
    positionHandle = glGetAttribLocation(program,"aPosition");
    textureHandle = glGetAttribLocation(program,"aTexCoord");
    textureSampler = glGetUniformLocation(program,"ourTexture");
    LOGD("program:%d",program);
    LOGD("positionHandle:%d",positionHandle);
    LOGD("textureHandle:%d",textureHandle);
    LOGD("textureSample:%d",textureSampler);
}

void ScissorTestOpengl::setPixel(void *data, int width, int height, int length) {
    LOGD("texture setPixel");
    glGenTextures(1, &textureId);

    // 激活纹理,注意以下这个两句是搭配的,glActiveTexture激活的是那个纹理,就设置的sampler2D是那个
    // 默认是0,如果不是0的话,需要在onDraw的时候重新激活一下?
//    glActiveTexture(GL_TEXTURE0);
//    glUniform1i(textureSampler, 0);

// 例如,一样的
    glActiveTexture(GL_TEXTURE2);
    glUniform1i(textureSampler, 2);

    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, textureId);
    // 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    // 生成mip贴图
    glGenerateMipmap(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, textureId);

    // 解绑定
    glBindTexture(GL_TEXTURE_2D, 0);
}

void ScissorTestOpengl::onDraw() {
    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(program);

    // 激活纹理
    glActiveTexture(GL_TEXTURE2);
    glUniform1i(textureSampler, 2);

    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, textureId);

    /**
     * size 几个数字表示一个点,显示是两个数字表示一个点
     * normalized 是否需要归一化,不用,这里已经归一化了
     * stride 步长,连续顶点之间的间隔,如果顶点直接是连续的,也可填0
     */
    // 启用顶点数据
    glEnableVertexAttribArray(positionHandle);
    glVertexAttribPointer(positionHandle,2,GL_FLOAT,GL_FALSE,0,VERTICES);

    // 纹理坐标
    glEnableVertexAttribArray(textureHandle);
    glVertexAttribPointer(textureHandle,2,GL_FLOAT,GL_FALSE,0,TEXTURE_COORD);

    // 4个顶点绘制两个三角形组成矩形
    glDrawArrays(GL_TRIANGLE_STRIP,0,4);

    glUseProgram(0);

    // 禁用顶点
    glDisableVertexAttribArray(positionHandle);

    // 蓝色
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    // 开启裁剪测试
    glEnable(GL_SCISSOR_TEST);
    // 设置裁剪区域,也就是后面绘制的内容在那个部分可见
    glScissor(eglHelper->viewWidth/2, eglHelper->viewHeight/2, 200,200);
    glClear(GL_COLOR_BUFFER_BIT);

    if(nullptr != eglHelper){
        eglHelper->swapBuffers();
    }

    glBindTexture(GL_TEXTURE_2D, 0);
    // 禁用裁剪测试
    glDisable(GL_SCISSOR_TEST);
}

ScissorTestOpengl::~ScissorTestOpengl() {
    LOGD("TextureMapOpengl析构函数");
}

其实代码都是和Opengl ES之纹理贴图 中的一样的,只是添加了147-153行的相关内容,绘制了一个蓝色的清屏。

倘若将150或152行注释掉,你得到的是一个蓝屏,没有任何纹理,因为纹理图片被蓝屏覆盖掉了。而152行glScissor(eglHelper->viewWidth/2, eglHelper->viewHeight/2, 200,200);正是设定了 裁剪窗口区域,不在这个区域内的将变得不可见,因此这个区域之外的地步纹理就变得可见了,因为没有被蓝屏覆盖。

什么是裁剪测试?在Opengl中如何使用裁剪测试
裁剪测试运行结果

推荐阅读:

Opengl ES之转场动画

关注我,一起进步,人生不止coding!!!

思想觉悟

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/28218.html

(0)

相关推荐

发表回复

登录后才能评论