美文网首页
OpenGL--纹理(上)

OpenGL--纹理(上)

作者: tp夕阳武士 | 来源:发表于2020-03-16 00:04 被阅读0次
原始图像数据

图像的存储空间 = 图像的高度 * 图像的宽度 * 每个像素点占用的字节数

我们在OpenGL中使用的纹理文件是:.tga后缀的文件:

image.png
图像的函数
6-1.png 6-2.png
/// 改变像素存储方式
void glPixelStorei(GLenum pname , GLint param);

/// 恢复像素存储方式
void glPixelStoref(GLenum pname , GLfloat param);

//举例:
//参数1:枚举类型 用来指定OpenGL用什么方式从缓存中解包图像数据
//参数2:为参数1指定的方式设置一个值
//GL_UNPACK_ALIGNMENT 指内存中每个像素⾏起点的排列列请求,
//允许设置为1 (byte排列列)、2(排列列为偶数byte的⾏行行)、4(字word排列列)、8(行从双字节 边界开始)
void  glPixelStorei(GL_UNPACK_ALIGNMENT,1);


/// 从颜色缓存区内容作为像素图直接读取
// 参数1:矩形左下角的窗口坐标;
// 参数2:矩形左下角的窗口坐标;
// 参数3:矩形的宽,以像素为单位
// 参数4: 矩形的高,以像素为单位
// 参数5:OpenGL的像素格式
// 参数6:解释参数7-> pixels指向的数据,告诉OpenGL使用缓存区中的什么类型数据来存储颜色分量,像素数据的数据类型,参考表6-2;
// 参数7: pixels 指向图形数据的指针
void  glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, Glenn format, GLenum type, GLvoid *pixels)

void  glReadBuffer(mode);  // 指定读取的内容
void  glWriteBuffer(mode); //指定写入的缓存 

/// 载入纹理
void  glTexImage1D(<#GLenum target#>, <#GLint level#>, <#GLint internalformat#>, <#GLsizei width#>, <#GLint border#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)

void  glTexImage2D(<#GLenum target#>, <#GLint level#>, <#GLint internalformat#>, <#GLsizei width#>, <#GLsizei height#>, <#GLint border#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)

//参数解释:
//target: 枚举 -> `GL_TEXTURE_1D`、`GL_TEXTURE_2D`、`GL_TEXTURE_3D`
//level: 指定所夹在的mip贴图层次,通常设置为0;
//internalformat: 每个纹理单元中存储多少颜色成分
//width / height : 宽 / 高  这些值必须是2的整数次方(旧版本OpenGL的要求,新版本已经支持非2的整数次方)
//border: 允许纹理贴图指定一个边界宽度;
//format: 与glReadPixels(...);方法中一样
//type:与glReadPixels(...);方法中一样
//pixels:与glReadPixels(...);方法中一样

//更新纹理:
void  glTexSubImage1D(<#GLenum target#>, <#GLint level#>, <#GLint xoffset#>, <#GLsizei width#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)
void  glTexSubImage2D(<#GLenum target#>, <#GLint level#>, <#GLint xoffset#>, <#GLint yoffset#>, <#GLsizei width#>, <#GLsizei height#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)


//插入替换纹理
void  glCopyTexSubImage1D(<#GLenum target#>, <#GLint level#>, <#GLint xoffset#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>)
void  glCopyTexSubImage2D(<#GLenum target#>, <#GLint level#>, <#GLint xoffset#>, <#GLint yoffset#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>, <#GLsizei height#>)

// 使用颜色缓存区加载数据,形成新的纹理使⽤
void  glCopyTexImage1D(<#GLenum target#>, <#GLint level#>, <#GLenum internalFormat#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>, <#GLint border#>)
void  glCopyTexImage2D(<#GLenum target#>, <#GLint level#>, <#GLenum internalFormat#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>, <#GLsizei height#>, <#GLint border#>)

//纹理对象
//指定纹理对象的个数和直指针
void glGenTextures(<#GLsizei n#>, <#GLuint *textures#>)

/// 绑定纹理对象
// target : GL_TEXTURE_1D , GL_TEXTURE_2D , GL_TEXTURE_3D; 
// texture : 需要绑定的纹理对象 
void glBindTexture(<#GLenum target#>, <#GLuint texture#>)

/// 删除绑定纹理对象 , 离开界面的时候删除纹理或者是不需要在使用的时候删除
void glDeletTexture(<#GLsizei n#> , <#GLuint texture#>);

/// 测试纹理对象是否有效
// texture : 被测试的纹理对象
void glIsTexture(<#GLuint texture#>)
  • 纹理对象三步走


    纹理对象三步走.png
设置纹理参数 - 过滤方式
///设置纹理参数
void glTexParameterf(<#GLenum target#>, <#GLenum pname#>, <#GLfloat param#>)
void glTexParameteri(<#GLenum target#>, <#GLenum pname#>, <#GLint param#>)
void glTexParameterfv(<#GLenum target#>, <#GLenum pname#>, <#const GLfloat *params#>)
void glTexParameteriv(<#GLenum target#>, <#GLenum pname#>, <#const GLint *params#>)
//参数解释:
//target : 指定纹理模式 : GL_TEXTURE_1/2/3D
//panme : 需要设置的纹理参数GL_TEXTURE_MIN_FILTER(放大) / GL_TEXTURE_MAG_FILTER(缩小)
//param : 参数的值 GL_NEAREST(临近过滤 ) / GL_LINEAR(线性过滤)

//遗留问题: 四个方法的区别???????

//举例:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

  • 临近过滤与线性过滤的图形效果


    图片取自逻辑教育_CC老师课件
设置纹理参数 - 环绕方式
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_T,GL_CLAMP_TO_EDGE);
//参数1: GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
//参数2: GL_TEXTURE_WRAP_S、GL_TEXTURE_T、GL_TEXTURE_R
//参数3: GL_REPEAT:OpenGL/GL_CLAMP/GL_CLAMP_TO_EDGE/GL_CLAMP_TO_BORDER
环绕方式参数解释与效果
纹理坐标

纹理坐标命名为s/ t/r/q 类似顶点坐标x/y/z/w
q坐标对于几何图形坐标w,作为缩放因子,作用于其他纹理坐标。也就是说,实际上所使用的纹理坐标是s/qt/qr/q。在默认情况下,q设置为1.0

image.png
2D纹理坐标

xy轴上,范围为0~1之间。使用纹理坐标获取纹理颜色叫做采用(Sampling)。
假定纹理坐标的起点为(0,0),那么一张图片的纹理坐标应如下图:

纹理坐标.png

如果此时我们需要绘制一个三角形:


image.png

上图中三角形的三个顶点的纹理坐标应该分别是:(0,0),(1,0),(0.5,1)

纹理的映射关系

在使用一张图片时,我们可以随意旋转,但是无法做到交叉


image.png
金字塔案例
image.png
void SetupRC()
{
    //1.
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
    shaderManager.InitializeStockShaders();
    
    //2.开启深度测试
    glEnable(GL_DEPTH_TEST);
    
    //3.
    //分配纹理对象 参数1:纹理对象个数,参数2:纹理对象指针
    glGenTextures(1, &textureID);
    //绑定纹理状态 参数1:纹理状态2D 参数2:纹理对象
    glBindTexture(GL_TEXTURE_2D, textureID);
    //将TGA文件加载为2D纹理。
    //参数1:纹理文件名称
    //参数2&参数3:需要缩小&放大的过滤器
    //参数4:纹理坐标环绕模式
    LoadTGATexture("stone.tga", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, GL_CLAMP_TO_EDGE);
    
    //4.创造金字塔pyramidBatch
    MakePyramid(pyramidBatch);
    
    //5.
    /**相机frame MoveForward(平移)
    参数1:Z,深度(屏幕到图形的Z轴距离)
     */
    cameraFrame.MoveForward(-10);
}
// 将TGA文件加载为2D纹理。
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
    GLbyte *pBits;
    int nWidth, nHeight, nComponents;
    GLenum eFormat;
    
    //1、读纹理位,读取像素
    //参数1:纹理文件名称
    //参数2:文件宽度地址
    //参数3:文件高度地址
    //参数4:文件组件地址
    //参数5:文件格式地址
    //返回值:pBits,指向图像数据的指针
    
    pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
    if(pBits == NULL)
        return false;
    
    //2、设置纹理参数
    //参数1:纹理维度
    //参数2:为S/T坐标设置模式
    //参数3:wrapMode,环绕模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
    
    //参数1:纹理维度
    //参数2:线性过滤
    //参数3:wrapMode,环绕模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
    

    //3.载入纹理
    //参数1:纹理维度
    //参数2:mip贴图层次
    //参数3:纹理单元存储的颜色成分(从读取像素图是获得)
    //参数4:加载纹理宽
    //参数5:加载纹理高
    //参数6:加载纹理的深度
    //参数7:像素数据的数据类型(GL_UNSIGNED_BYTE,每个颜色分量都是一个8位无符号整数)
    //参数8:指向纹理图像数据的指针
    
    glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
                 eFormat, GL_UNSIGNED_BYTE, pBits);
    
    //使用完毕释放pBits
    free(pBits);
    
    
    //4.加载Mip,纹理生成所有的Mip层
    //参数:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
    glGenerateMipmap(GL_TEXTURE_2D);
 
    return true;
}
绘制金字塔纹理
//绘制金字塔

void MakePyramid(GLBatch& pyramidBatch)
{
    /*1、通过pyramidBatch组建三角形批次
      参数1:类型
      参数2:顶点数
      参数3:这个批次中将会应用1个纹理
      注意:如果不写这个参数,默认为0。
     */
    pyramidBatch.Begin(GL_TRIANGLES, 18, 1);
    
     
     1)设置法线
     void Normal3f(GLfloat x, GLfloat y, GLfloat z);
     Normal3f:添加一个表面法线(法线坐标 与 Vertex顶点坐标中的Y轴一致)
     表面法线是有方向的向量,代表表面或者顶点面对的方向(相反的方向)。在多数的关照模式下是必须使用。后面的课程会详细来讲法线的应用
     
     pyramidBatch.Normal3f(X,Y,Z);
     
     2)设置纹理坐标
     void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
     参数1:texture,纹理层次,对于使用存储着色器来进行渲染,设置为0
     参数2:s:对应顶点坐标中的x坐标
     参数3:t:对应顶点坐标中的y
     (s,t,r,q对应顶点坐标的x,y,z,w)
     
     pyramidBatch.MultiTexCoord2f(0,s,t);
     
     3)void Vertex3f(GLfloat x, GLfloat y, GLfloat z);
      void Vertex3fv(M3DVector3f vVertex);
     向三角形批次类添加顶点数据(x,y,z);
      pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
     
     
     4)获取从三点找到一个法线坐标(三点确定一个面)
     void m3dFindNormal(result,point1, point2,point3);
    
    //塔顶
    M3DVector3f vApex = { 0.0f, 1.0f, 0.0f };
    M3DVector3f vFrontLeft = { -1.0f, -1.0f, 1.0f };
    M3DVector3f vFrontRight = { 1.0f, -1.0f, 1.0f };
    M3DVector3f vBackLeft = { -1.0f,  -1.0f, -1.0f };
    M3DVector3f vBackRight = { 1.0f,  -1.0f, -1.0f };
    M3DVector3f n; // 此处的n就是用来存储法线的
    
    //金字塔底部
    //底部的四边形 = 三角形X + 三角形Y
    //三角形X = (vBackLeft,vBackRight,vFrontRight)
    
    //1.找到三角形X 法线
    m3dFindNormal(n, vBackLeft, vBackRight, vFrontRight);
   
    //vBackLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //vBackRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    //vFrontRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    
    //三角形Y =(vFrontLeft,vBackLeft,vFrontRight)
   
    //1.找到三角形y 法线
    m3dFindNormal(n, vFrontLeft, vBackLeft, vFrontRight);
    
    //vFrontLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);
    
    //vBackLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //vFrontRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    pyramidBatch.Vertex3fv(vFrontRight);

    
    // 金字塔前面
    //三角形:(Apex,vFrontLeft,vFrontRight)
    m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);
   
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    //金字塔左边
    //三角形:(vApex, vBackLeft, vFrontLeft)
    m3dFindNormal(n, vApex, vBackLeft, vFrontLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);
    
    //金字塔右边
    //三角形:(vApex, vFrontRight, vBackRight)
    m3dFindNormal(n, vApex, vFrontRight, vBackRight);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    //金字塔后边
    //三角形:(vApex, vBackRight, vBackLeft)
    m3dFindNormal(n, vApex, vBackRight, vBackLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //结束批次设置
    pyramidBatch.End();
}

金字塔的坐标解析

image.png

顶点坐标
vApex(0.0, 1.0, 0.0)
vBackLeft(-1.0, -1.0, -1.0)
vBackRight(1.0. -1.0, -1.0)
vFrontRight(1.0, -1.0, 1.0)
vFrontLeft(-1.0, -1.0, 1.0)

对应的纹理坐标 (注意,此处第一位0是表示level = 0 , 后两位数才是纹理上的坐标) ;
vApex(0,0.5,1)
vFrontLeft(0.0, 0.0, 1.0)
vBackLeft(0.0, 0.0, 0.0)
vFrontRight(0.0, 1.0, 1.0)

回顾一下上面的代码注释中:2)设置纹理坐标

     void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
     参数1:texture,纹理层次,
对于使用存储着色器来进行渲染,设置为0
     参数2:s->对应顶点坐标中的x坐标
     参数3:t->对应顶点坐标中的y`
     (s,t,r,q对应顶点坐标的x,y,z,w)

下面这张图很好的诠释了金字塔底部的纹理坐标取值原理:


image.png

本文参考了简书作者:[佐_笾]的<<OpenGL/OpenGL ES入门: 纹理应用 - 纹理坐标及案例解析(金字塔)>>

相关文章

  • OpenGL--纹理(上)

    原始图像数据 图像的存储空间 = 图像的高度 * 图像的宽度 * 每个像素点占用的字节数 我们在OpenGL中使用...

  • OpenGL-- 纹理加载

    前言 这一篇文章的主要内容是用OpenGL去加载纹理,也就是将图片加载到屏幕上。之前几篇文章已经讲解了OpenGL...

  • OpenGL-纹理应用

    纹理坐标 加载纹理只是在几何图形上应用纹理的第一步。最低限度我们必须同时提供纹理坐标,并设置纹理坐标环绕模式和纹理...

  • Android万能视频播放器10-OpenGL ESMediaC

    1、OpenGL生成纹理 2、纹理绑定到SurfaceTexture上 3、用SurfaceTexture做参数创...

  • OpenGL(七)-纹理(上)

    设定金字塔坐标 注意纹理坐标的设置方式://设置顶点对应的纹理坐标// s , t 相当于 x , y// Mul...

  • OpenGL纹理详解(上)

    写在前面的话 现实生活中,纹理最通常的作用是装饰我们的物体模型,它就像是贴纸一样贴在物体表面,使得物体表面拥有图案...

  • 6.纹理(上)

    1.图像存储空间计算?图像存储空间=图片width图片height每个像素的字节数RGB需要一个字节即8位。2.宽...

  • 透视纹理映射

    伪3D中的贴图纹理的透视矫正深入探索透视纹理映射(上)深入探索透视纹理映射(下)Perspective Textu...

  • OpenGL--投影

    我们日常缩看到的屏幕显示设备,都是属于二维的显示设备,尽管有时候我们看到手机上,电视上显示的内容很有立体感,但是事...

  • OpenGL ES纹理

    1,纹理【1】什么是纹理:定义:在计算机图形学中,纹理既包括通常意义上物体表面的纹理。也就是我们土话所讲的使物体表...

网友评论

      本文标题:OpenGL--纹理(上)

      本文链接:https://www.haomeiwen.com/subject/rgkudhtx.html