NDK OpenGL ES 3.0 开发(二):纹理映射

简介: 现实生活中,纹理(Texture)最通常的作用是装饰 3D 物体,它就像是贴纸一样贴在物体表面,丰富物体的表面和细节。 在 OpenGLES 开发中,纹理除了用于装饰物体表面,还可以用来作为存储数据的容器。

作者:字节流动

来源:https://blog.csdn.net/Kennethdroid/article/details/96887637


什么是纹理

现实生活中,纹理(Texture)最通常的作用是装饰 3D 物体,它就像是贴纸一样贴在物体表面,丰富物体的表面和细节。 在 OpenGLES 开发中,纹理除了用于装饰物体表面,还可以用来作为存储数据的容器。

那么在 OpenGL 中,纹理实际上是一个可以被采样的复杂数据集合,是 GPU 使用的图像数据结构,纹理分为 2D 纹理、 立方图纹理和 3D 纹理。

2D 纹理是 OpenGLES 中最常用和最常见的纹理形式,是一个图像数据的二维数组。纹理中的一个单独数据元素称为纹素或纹理像素。

立方图纹理是一个由 6 个单独的纹理面组成的纹理。立方图纹理像素的读取通过使用一个三维坐标(s,t,r)作为纹理坐标。

3D 纹理可以看作 2D 纹理作为切面的一个数组,类似于立方图纹理,使用三维坐标对其进行访问。

什么是纹理映射

在 OpenGLES 中,纹理映射就是通过为图元的顶点坐标指定恰当的纹理坐标,通过纹理坐标在纹理图中选定特定的纹理区域,最后通过纹理坐标与顶点的映射关系,将选定的纹理区域映射到指定图元上

纹理映射也称为纹理贴图,简单地说就是将纹理坐标(纹理坐标系)所指定的纹理区域,映射到顶点坐标(渲染坐标系或OpenGLES 坐标系)对应的区域。

纹理坐标系

image.png

渲染坐标系或OpenGLES 坐标系:

image.png

4 个纹理坐标分别为

T0(0,0),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 度的纹理贴图。所以调整纹理坐标和顶点坐标的对应关系可以实现纹理图简单的旋转。

纹理映射的简单实现

纹理映射的一般步骤:

  • 生成纹理,编译链接着色器程序
  • 确定纹理坐标及对应的顶点坐标
  • 加载图像数据到纹理,加载纹理坐标和顶点坐标到着色器程序
  • 绘制

生成纹理并加载图像数据到纹理

//生成一个纹理,将纹理 id 赋值给 m_TextureId
glGenTextures(1, &m_TextureId); 
//将纹理 m_TextureId 绑定到类型 GL_TEXTURE_2D 纹理
glBindTexture(GL_TEXTURE_2D, m_TextureId);
//设置纹理 S 轴(横轴)的拉伸方式为截取
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
//设置纹理 T 轴(纵轴)的拉伸方式为截取
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);
//加载 RGBA 格式的图像数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_RenderImage.width, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);

对纹理采样的片元着色器脚本

#version 300 es                                     
precision mediump float;                            
in vec2 v_texCoord;                                 
layout(location = 0) out vec4 outColor;             
uniform sampler2D s_TextureMap; //声明采用器                     
void main()                                         
{
  // texture() 为内置的采样函数,v_texCoord 为顶点着色器传进来的纹理坐标
  // 根据纹理坐标对纹理进行采样,输出采样的 rgba 值(4维向量)                                                  
  outColor = texture(s_TextureMap, v_texCoord);      
}                                                   

简单实现代码

// 生成纹理,编译链接着色器程序
void TextureMapSample::Init()
{
  //create RGBA texture
  glGenTextures(1, &m_TextureId);
  glBindTexture(GL_TEXTURE_2D, m_TextureId);
  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);
  glBindTexture(GL_TEXTURE_2D, GL_NONE);
  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_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");
  }
}
// 加载图像数据、纹理坐标和顶点坐标数据,绘制实现纹理映射
void TextureMapSample::Draw(int screenW, int screenH)
{
  LOGCATE("TextureMapSample::Draw()");
  if(m_ProgramObj == GL_NONE || m_TextureId == GL_NONE) return;
  GLfloat verticesCoords[] = {
      -1.0f,  0.5f, 0.0f,  // Position 0
      -1.0f, -0.5f, 0.0f,  // Position 1
      1.0f, -0.5f, 0.0f,  // Position 2
      1.0f,  0.5f, 0.0f,  // Position 3
  };
  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 };
  //upload RGBA image data
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, m_TextureId);
  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);
  // 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);
}

结果图

image.png

联系与交流

技术交流、获取源码可以扫码添加我的微信:Byte-Flow ,领取视频教程


「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

阿里云社区.png

相关文章
|
6月前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
150 1
Android开发之使用OpenGL实现翻书动画
|
6月前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
75 1
Android开发之OpenGL的画笔工具GL10
|
6月前
|
前端开发 API vr&ar
Android开发之OpenGL绘制三维图形的流程
即将连载的系列文章将探索Android上的OpenGL开发,这是一种用于创建3D图形和动画的技术。OpenGL是跨平台的图形库,Android已集成其API。文章以2D绘图为例,解释了OpenGL的3个核心元素:GLSurfaceView(对应View)、GLSurfaceView.Renderer(类似Canvas)和GL10(类似Paint)。通过将这些结合,Android能实现3D图形渲染。文章介绍了Renderer接口的三个方法,分别对应2D绘图的构造、测量布局和绘制过程。示例代码展示了如何在布局中添加GLSurfaceView并注册渲染器。
197 1
Android开发之OpenGL绘制三维图形的流程
|
6月前
|
XML Java Android开发
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
79 1
|
6月前
|
XML 小程序 Java
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
124 0
|
存储 编解码 算法
Opengl ES之LUT滤镜(上)
Opengl ES之连载系列
458 0
|
数据安全/隐私保护 开发者
OpenGL ES 多目标渲染(MRT)
Opengl ES连载系列
319 0
|
数据安全/隐私保护 索引
Opengl ES之纹理数组
Opengl ES连载系列
257 0
|
缓存 C++
Opengl ES之FBO
Opengl ES连载系列
151 0
|
数据安全/隐私保护
Opengl ES之水印贴图
Opengl ES之连载系列
150 0