opengles3.0 纹理(七):
纹理对象和纹理加载:
纹理有2D纹理,2D纹理数组,3D纹理,立方图纹理。
2D纹理是一个图像数据的二维数组。用2D纹理渲染时,纹理坐标用做纹理图像中的索引。每个顶点都有一个纹理坐标。
纹理图像的左下角由st坐标(0.0,0.0),右上角(1.0,1.0)
glGenTextures(GLsizei n, GLuint *texture) //生成纹理ID
glBindTexture(GLenum target, GLuint texture)
target 将纹理对象绑定到GL_TEXTURE_2D,GL_TEXTURE_3D,GL_TEXTURE_2D_ARRAY,GL_TEXTURE_CUBE_MAP
glTexImage2D 加载2D和立方体纹理,纹理比较大的时候加载纹理会比较慢,因为它需要把数据传给GPU的自己的BUFFER.
texture:要绑定的纹理对象的句柄。
在纹理缩小模式中,只有GL_NEAREST和GL_LINEAR不需要为纹理指定完整的mip贴图链。
纹理坐标的包装:
纹理包装模式用于指定纹理坐标超出【0.0,1.0】范围时所有发生的行为,用glTexParameter设置,这些模式可以为s,t,r坐标单独设置。
GL_TEXTURE_WRAP_S (s)
GL_TEXTURE_WRAP_T (t)
GL_TEXTURE_WRAP_R (r)
GL_REPEAT 重复纹理
GL_CLAMP_TO_EDGE 限定读取纹理边缘
GL_MIRRORED_REPEAT 重复纹理和镜像
opengles3.0 支持的纹理格式:规范化的纹理格式、浮点纹理、整数纹理、共享指数纹理、sRGB纹理和深度纹理。
规范化格式的每个纹素可以用1-4个分量指定(R,RG,RGB或者RGBA),opengles3.0还引入了GL_RGB10_A2,允许纹理数据的规范对于每个(R,G,B)
值上有10bit,对于每个alpha值有2位。
// Initialize the shader and program object
//
int Init ( ESContext *esContext )
{
UserData *userData = esContext->userData;
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 a_position; \n"
"layout(location = 1) in vec2 a_texCoord; \n"
"out vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" v_texCoord = a_texCoord; \n" #纹理坐标
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"in vec2 v_texCoord; \n"
"layout(location = 0) out vec4 outColor; \n"
"uniform sampler2D s_texture; \n"
"void main() \n"
"{ \n"
" outColor = texture( s_texture, v_texCoord ); \n" //s_texture纹理贴图,接口外面传进来,v_texCoord纹理坐标
"} \n";
// Load the shaders and get a linked program object
userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
// Get the sampler location
userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
// Load the texture
userData->textureId = CreateSimpleTexture2D ();
glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
return TRUE;
}
void Draw ( ESContext *esContext )
{
UserData *userData = esContext->userData;
GLfloat vVertices[] = { -0.5f, 0.5f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-0.5f, -0.5f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
0.5f, -0.5f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
0.5f, 0.5f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; //顶点的画的顺序
// Set the viewport
glViewport ( 0, 0, esContext->width, esContext->height );
// Clear the color buffer
glClear ( GL_COLOR_BUFFER_BIT );
// Use the program object
glUseProgram ( userData->programObject );
// Load the vertex position
glVertexAttribPointer ( 0, 3, GL_FLOAT,
GL_FALSE, 5 * sizeof ( GLfloat ), vVertices );
// Load the texture coordinate
glVertexAttribPointer ( 1, 2, GL_FLOAT,
GL_FALSE, 5 * sizeof ( GLfloat ), &vVertices[3] );
glEnableVertexAttribArray ( 0 );
glEnableVertexAttribArray ( 1 );
// Bind the texture
glActiveTexture ( GL_TEXTURE0 );
glBindTexture ( GL_TEXTURE_2D, userData->textureId );
// Set the sampler texture unit to 0
glUniform1i ( userData->samplerLoc, 0 );
glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
}
顶点着色器以一个二分量纹理坐标作为顶点输入,并将其作为输出传递给片段着色器。片段着色器消费该纹理坐标
并将其用于纹理读取。片段着色器声明一个类型位sampler2D的统一变量s_texture.
采样器是用于从纹理贴图中读取的特殊统一变量。采样器统一变量将加载一个指定纹理绑定的纹理单元的数值。
例如,用数值0指定采样器表示从单元GL_TEXTURE0读取。
在shader中使用内建texture从纹理贴图中读取数据。
压缩纹理:
opengles3.0还支持压缩纹理,glCompressedTexImage2D,加载压缩纹理
一旦加载了压缩纹理,他就可以和五压缩纹理一样用于纹理处理。要所问题ETC压缩工具。
纹理子图像规范:
用glTexImage2D上传纹理图像之后,可以更新图像之后,可以更新图像的各个部分,如果你只希望更新图像的一个子区域
这种能力就很实用。加载2D纹理图像一部分的函数是glTexsubImage2D.
glTexSubImage2D函数
提供修改图像函数,因为修改一个纹理比重新创建一个纹理开销小得多,对于一些视频捕捉程序可以先将视频图像存储在更大的初始图像中(该图像大小要求是2的次方,OGL 2.0后没有这个限制),创建一个渲染用的纹理,然后反复调用glTexSubImage2D(修改的图像区域不用是2的次方)函数从图像视频图像区域读取数据到渲染纹理图像中。渲染用的纹理图像只需要创建一次即可。
函数原型:
glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
target参数必须是glCopyTexImage2D中的对应的target可使用的值。
level 是mipmap等级。
xoffset,yoffset是要修改的图像的左下角偏移。width,height是要修改的图像宽高像素。修改的范围在原图之外并不受到影响。
format,type描述了图像数据的格式和类型,和glTexImage2D中的format, type一致。
pixels 是子图像的纹理数据,替换为的值。
子图像也受到glPixelStore*()和glPixelTransfer*()以及其它像素传输操作所设置模式的影响。
实例:
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_2D, texName);
int offsetX = 0;// 12;
int offsetY = 0;// 44;
glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, subImageWidth,
subImageHeight, GL_RGBA,
GL_UNSIGNED_BYTE, subImage);
从颜色缓冲区复制纹理数据:
opengles3.0 中支持另一个纹理功能是从颜色缓冲区复制数据到一个纹理。如果你希望实用渲染的结果作为纹理中的数据,这一功能很实用。
作为复制图像数据来源的颜色换成哦过去可以用glReadBuffer函数设置。如果应用程序渲染到一个双缓冲区EGL的可显示表面。则glReadBuffer必须
设置为GL_BACK.
glCopyTexSubImage2D函数
glCopyTexSubImage2D函数
从帧缓存区GL_READ_BUFFER读取一块像素矩形,并替换一个现有的纹理数组的一部分或全部,相当于调用了glCopyTexImage2D和glTexSubImage2D函数。
原型:
glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
glCopyTexSubImage2D — copy a two-dimensional texture subimage
target
Specifies the target texture. Must be GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z.
像素是从当前的GL_READ_BUFFER读取的,它处理的过程像调用了glCopyPixels,但像素数据并不是放在帧缓存区中,而是放入纹理内存中。glPixelTransfer*和其它像素传输操作的设置也会对它产生作用。在OGL 3.0及以后的版本,应该可以使用帧缓存区对象直接渲染到纹理内存,从而高效的执行和glCopyTexSubImage2D相同的操作。
glGenTextures(1, &_iTexDepth);
glBindTexture(GL_TEXTURE_2D, _iTexDepth);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE
);
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE
);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _w, _h, 0,
GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
and prefare to render:
glViewport(0, 0, _w, _h);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(camera_proj);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(camera_modelview);
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_PIXEL_MODE_BIT);
glDrawBuffer(GL_BACK);
glReadBuffer(GL_BACK);
glClearColor(0, 0, 0, 1);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
and render something, and copy to texture :
glBindTexture(GL_TEXTURE_2D, _iTexDepth);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, _w, _h);
glBindTexture(GL_TEXTURE_2D, 0);