本文正在参加「金石计划」
什么是裁剪测试
剪裁测试用于限制绘制区域,在 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 ES系列入门介绍
Opengl ES之EGL环境搭建
Opengl ES之着色器
Opengl ES之三角形绘制
Opengl ES之四边形绘制
Opengl ES之纹理贴图
Opengl ES之VBO和VAO
Opengl ES之EBO
Opengl ES之FBO
Opengl ES之PBO
Opengl ES之YUV数据渲染
YUV转RGB的一些理论知识
Opengl ES之RGB转NV21
Opengl ES之踩坑记
Opengl ES之矩阵变换(上)
Opengl ES之矩阵变换(下)
Opengl ES之水印贴图
Opengl ES之纹理数组
OpenGL ES之多目标渲染(MRT
Opengl ES之LUT滤镜(上)
Opengl ES之LUT滤镜(下)-3DLUT
OpenglES之分屏滤镜
Opengl中GL_LUMINANCE被移除的兼容性问题
关注我,一起进步,人生不止coding!!!