1.概念:
什么是纹理
现实生活中,纹理(Texture)最通常的作用是装饰 3D 物体,它就像是贴纸一样贴在物体表面,丰富物体的表面和细节。 在 OpenGLES 开发中,纹理除了用于装饰物体表面,还可以用来作为存储数据的容器。
那么在 OpenGL 中,纹理实际上是一个可以被采样的复杂数据集合,是 GPU 使用的图像数据结构,纹理分为 2D 纹理、 立方图纹理和 3D 纹理。
2D 纹理是 OpenGLES 中最常用和最常见的纹理形式,是一个图像数据的二维数组。纹理中的一个单独数据元素称为纹素或纹理像素。
立方图纹理是一个由 6 个单独的纹理面组成的纹理。立方图纹理像素的读取通过使用一个三维坐标(s,t,r)作为纹理坐标。
3D 纹理可以看作 2D 纹理作为切面的一个数组,类似于立方图纹理,使用三维坐标对其进行访问。
什么是纹理映射
在 OpenGLES 中,纹理映射就是通过为图元的顶点坐标指定恰当的纹理坐标,通过纹理坐标在纹理图中选定特定的纹理区域,最后通过纹理坐标与顶点的映射关系,将选定的纹理区域映射到指定图元上。
纹理映射也称为纹理贴图,简单地说就是将纹理坐标(纹理坐标系)所指定的纹理区域,映射到顶点坐标(渲染坐标系或OpenGLES 坐标系)对应的区域。
纹理坐标系
渲染坐标系或OpenGLES 坐标系
坐标值为正数。
渲染坐标系或OpenGLES 坐标系:
,T1(0,1),T2(1,1),T3(1,0)。
4 个纹理坐标对于的顶点坐标分别为
V0(-1,0.5),V1(-1, -0.5),V2(1,-0.5),V3(1,0.5)
由于 OpenGLES 绘制是以三角形为单位的,设置绘制的 2 个三角形为 V0V1V2 和 V0V2V3 。
当我们调整纹理坐标的顺序顶点坐标顺序不变,如 T0T1T2T3 -> T1T2T3T0 ,绘制后将得到一个顺时针旋转 90 度的纹理贴图。所以调整纹理坐标和顶点坐标的对应关系可以实现纹理图简单的旋转
纹理映射的简单实现
2.纹理映射的一般步骤:
生成纹理,编译链接着色器程序
确定纹理坐标及对应的顶点坐标
加载图像数据到纹理,加载纹理坐标和顶点坐标到着色器程序
绘制
3.代码实现:
从本地drawable中load一张图片
Bitmap bitmap;
private void loadRGBImage() {
@SuppressLint("ResourceType") InputStream inputStream = this.getResources().openRawResource(R.drawable.tmap);
bitmap = BitmapFactory.decodeStream(inputStream);
if (bitmap != null) {
int bytes = bitmap.getByteCount();
ByteBuffer buf = ByteBuffer.allocate(bytes);
bitmap.copyPixelsToBuffer(buf);
byte[] byteArray = buf.array();
mSurfaceView.getNativeRender().native_SetImageData(IMAGE_FORMAT_RGBA, bitmap.getWidth(), bitmap.getHeight(), byteArray);
}
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
c++中loadImage方法
void TextureMapSample::LoadImage(NativeImage *pImage)
{
LOGCATE("TextureMapSample::LoadImage pImage = %p", pImage->ppPlane[0]);
if (pImage)
{
m_RenderImage.width = pImage->width;
m_RenderImage.height = pImage->height;
m_RenderImage.format = pImage->format;
NativeImageUtil::CopyNativeImage(pImage, &m_RenderImage);
}
}
创建纹理单元
void TextureMapSample::CreateTexture()
{
//create RGBA texture 设置激活的纹理单元(texture unit)
glActiveTexture(GL_TEXTURE0);
// 绑定纹理目标(一个或多个)到纹理单元
glGenTextures(1, &m_TextureId);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
//设置纹理 S 轴(横轴)的拉伸方式为截取
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//设置纹理采样方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
生成纹理链接编译着色器程序
void TextureMapSample::Init()
{
CreateTexture();
//eeeeee 顶点着色器绘制图形.
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";
//光栅化是将图元转化为一组二维片段的过程,这些片段由片段着色器处理.
//eeeeee 创建片段着色器.给二维片段着色.
// texture() 为内置的采样函数,v_texCoord 为顶点着色器传进来的纹理坐标
// 根据纹理坐标对纹理进行采样,输出采样的 rgba 值(4维向量)
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_TextureMap; \n"
"void main() \n"
"{ \n"
" outColor = texture(s_TextureMap, v_texCoord); \n"
"} \n";
//创建项目在项目上运行 顶点着色器和片段着色器.
m_ProgramObj = GLUtils::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);
if (m_ProgramObj)
{
m_SamplerLoc = glGetUniformLocation(m_ProgramObj, "s_TextureMap");
}
else
{
LOGCATE("TextureMapSample::Init create program fail");
}
}
调用OpenGL进行绘制
void TextureMapSample::Draw()
{
// LOGCATE("eeeeeeee TextureMapSample::Draw()");
if(m_ProgramObj == GL_NONE || m_TextureId == GL_NONE) return;
//设置激活的纹理单元
glActiveTexture(GL_TEXTURE0);
//将纹理 m_TextureId 绑定到类型 GL_TEXTURE_2D 纹理
glBindTexture(GL_TEXTURE_2D, m_TextureId);
//加载 RGBA 格式的图像数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_RenderImage.width, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);
glBindTexture(GL_TEXTURE_2D, GL_NONE);
//glViewport(0, 0, m_RenderImage.width, m_RenderImage.height);
//eeeeeee 4个纹理贴图对应的坐标系
GLfloat verticesCoords[] = {
-1.0f, 0.7f, 0.0f, // Position 0
-1.0f, -0.7f, 0.0f, // Position 1
1.0f, -0.7f, 0.0f, // Position 2
1.0f, 0.7f, 0.0f, // Position 3
};
// 4 个纹理坐标分别为
GLfloat textureCoords[] = {
0.0f, 0.0f, // TexCoord 0
0.0f, 1.0f, // TexCoord 1
1.0f, 1.0f, // TexCoord 2
1.0f, 0.0f // TexCoord 3
};
GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
// Use the program object
glUseProgram (m_ProgramObj);
// Load the vertex position 加载顶点的位置
glVertexAttribPointer (0, 3, GL_FLOAT,
GL_FALSE, 3 * sizeof (GLfloat), verticesCoords);
// Load the texture coordinate 加载纹理坐标
glVertexAttribPointer (1, 2, GL_FLOAT,
GL_FALSE, 2 * sizeof (GLfloat), textureCoords);
glEnableVertexAttribArray (0);
glEnableVertexAttribArray (1);
// Bind the RGBA map
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
// Set the RGBA map sampler to texture unit to 0
glUniform1i(m_SamplerLoc, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}
4.demo下载地址: https://gitee.com/wanshi33/open-gl_-texture-map-sample.git
更多资源链接:https://github.com/githubhaohao/NDK_OpenGLES_3_0