OpenGL学习笔记-2015.4.1——纹理加载与控制

在纹理贴图技术问世之前,虚拟3维世界只能通过几何模型去模拟现实,可想而知,现实世界的错综复杂,计算量之大并不能满足实时显示的需求。纹理映射带来了革命性的变换,简单的使得虚拟的3维世界得以无限接近于现实。纹理映射技术最早是由Catmull 在1947年率先提出的,Catmull首先找到了以(u,v)表示的双变量实数空间(纹理空间)和以参数(s,t)表示的三维曲面之间的对应关系(映射关系)。
    纹理由纹素组成,通常包括颜色值。但是在实际应用中,很多时候把纹理看作可以再着色器中查询的表(一个存储数据的地方),你可以用于任何目的,不仅仅局限于纹理贴图。
     基本纹理类型:
        OpenGL支持多类型的维数和布局可变的纹理对象,每个纹理对象表示组成完整纹理的一组图像,可以是1维,2维,3维数组。纹理可以使用用于2维和2维数组纹理的多重采样的纹理类型来表示多重采样颜色。多重采样是一个用于抗锯齿的术语,其中每个纹素被赋予多个独立的颜色,然后在渲染过程中合并这些颜色来生成最终的颜色。
        纹理通过纹理单元绑定到OpenGL中,纹理单元命名为GL_TEXTURE0到GL_TEXTUREi(i是OpenGL实现所支持的最大纹理数目减一)的绑定点。只要一个纹理绑定到环境中,则在着色器中可以使用采样器来访问,而采样器变量用匹配纹理的维数来声明,具体看下表:
目标GL_TEXTURE*
采样器类型
维度
1D
sampler1D
1D
1D_ARRAY
sampler1DArray
1D数组
2D
sampler2D
2D
2D_ARRAY
sampler2DArray
2D数组
2D_MULTISAMPLE
sampler2DMS
2D多重采样
2D_MULTISAMPLE_ARRAY
sampler2DMSArray
2D多重采样数组
3D
sampler3D
3D
CUBE
samplerCube
立方体纹理映射
ARRAY
samplerCubeArray
立方体映射数组
RECTANGLE
samplerRect
2D矩阵
BUFFER
samplerBuffer
1D缓存
ps:很多类型的纹理映射现在自己并没用用到对于一些概念还是比较模糊,在此mark~~什么时候了解了回来改改
一些特殊的纹理对象:1、矩形纹理对象(GL_TEXTURE_RECTANGLE),2维纹理的特例,表示一个简单的矩阵,没用mipmap(层次纹理)并且不能表示为纹理数组?!一些纹理模式(texture wrapping)不支持矩阵纹理。2、缓冲纹理(GL_TEXTURE_BUFFER),表示纹素的1维数组。同样没有mipmap,不能聚合数组。纹理缓冲是任意着色器阶段的数据访问(顶点数据,颜色。。。)而不需要把数据拷贝到纹理图像中。
     纹理映射四步曲:
 一、创建纹理对象
    1、void glGenTextures( GLsizei n, GLuint* textures ):返回n个用于纹理对象的当前没有使用的名称。
    2、void glBindTexture( GLenum target, GLuint texture ):改api完成三项工作:a、当第一次绑定texture并且texture不为0时,创建一个新的纹理对象并关联该名称,并激活。b、当绑定是先前已经创建的纹理对象,则直接激活该对象。c、当texture为0时,OpenGL将删除与激活纹理单元(GL_TEXTURE0...GL_TEXTUREi)特定目标关联的所有绑定。target参数可以为一下之一:GL_TEXTURE_1D, GL_TEXTURE_2D。。。。。见上表。
    3、void glActiveTexture( GLenum texture ):选择当前纹理函数改变的纹理单元,GL_TEXTURE0--GL_TEXTUREi.默认的应该是GL_TEXTURE0.
    4、void glIIsTexture( GLuint texture ):判断一个整形是否为纹理对象名称。
    5、void  glDeleteTextures( GLsizei n, const GLuint* textures ):删除纹理对象,这将删除所有与纹理关联的底层存储引用,并且在最后不被需要时释放。只要纹理对象呗glDeleteTextures删除,那么他的名称将再次变为没有使用,可以被glGenTextures()返回。
二、设置加载数据。
    1、OpenGL有两个系列的API去对纹理对象设置存储和数据:glTexStorage*()系列和glTexImage*()
        glTexStorage*():创建的是固定存储,使用这些函数分配之后,不能再重新定义存储,这被认为是OpenGL的最好实现,OpenGL假设纹理对象的格式和大小在他生命周期内不会改变,因此可以停止跟踪纹理对象的某些方面,ps:这只是存储属性不可变!纹理的内容可以使用glTexSubImage*()函数来修改。
        glTexImage*():与glTexStorage*()相对,允许重新定义纹理对象(例如,缩放或者改变格式)
        并且,两个系列的都有单采样和多重采样的重载函数,以下是函数的详细声明:
        void glTexStorage1D( GLenum target, GLsizei levels, GLenum internalFormat, GLsize width )
        void glTexStorage2D( GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height )
        void glTexStorage3D( GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth )
        void glTexStorage2DMultisample( GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations )
        void glTexStorage3DMultisample( GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLbollean fixedsamplelocations )
        PS:target是GL_TEXTURE_1D, GL_TEXTURE_2D。。。。。也可以见上表,当然里不同的函数有不同的target参数,glTexStorage1D的target必须是GL_TEXTURE_1D。glTexStorage2D()可以是GL_TEXTURE_1D_ARRAY或GL_TEXTURE_2D。glTexStorage3()可以为GL_TEXTURE_2D_ARRAY或GL_TEXTURE_3D。glTexStorage2DMultisample()则必须是GL_TEXTURE_2D_MULTISAMPLE。  glTexStorage3DMultisample()为GL_TEXTURE_3D_MULTISAMPLE。
                levels表示mipmap的层数。interFormat表示内存格式,太多了,例如GL_RGBA8....就不一一列举。width,height, depth分别为纹理的宽,高和深度。samples设置了纹理采样数目。fixedsamplelocations  如果为GL_TRUE, OpenGL为纹理中每个纹理的相同样本使用相同的子纹素位置,否则OpenGL为每个纹素给定的样本选择空间变化的位置(这话读起来这么绕。。)。

        void glTexImage1D( GLenum target , GLint level, GLint interalFormat, GLsizei width, GLsizei border, GLenum format, GLenum type, const void* data )
        void glTexImage2D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLborder, GLenum format, GLenum type, const void* data )    
        void glTexImage3D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height,  GLsizei depth, GLborder, GLenum format, GLenum type, const void* data )    
          void glTexImage2DMultisample( GLenum target, GLenum samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations )
        void glTexImage3DMultisample( GLenum target, GLenum samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations )
        PS:border表示边框宽度必须是0,format 与type定义了 data中的数据格式和存储格式。
                特别注意:对于data参数有两种解释,a:如果将一个缓冲绑定到了GL_PIXEL_UNPACK_BUFFER绑定点,那么他表示偏移地址,b.如果没有缓存绑定到GL_PIXEL_UNPACK_BUFFER那么表示纹理数据内容,如果为NULl空指针则将是未定义的。

        API : void glTexSubImage*()系列函数显示的设置纹理数据:
            void glTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* data )
            void glTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLsizei width,  GLsizei height, GLenum format, GLenum type, const void* data )
            void glTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLsizei width, ,  GLsizei height,  ,  GLsizei depth, GLenum format, GLenum type, const void* data )
            参数的意义已经够明了了。函数最终的结果是替换纹理数据的一个区域。

       纹理数据的数据源可以是程序生成,可以是帧缓存中拷贝,可以冲图像文件中加载。
        glCopyTexImage*()提供了在帧缓存中拷贝数据的途径。而从图像文件中加载则显得比较复杂,因为图像文件格式多种多样,需要对应每种格式的文件编写对应的解析代码。幸福的是这些工作大部分前人都帮我们做了,如freeImage一个开源的图像加载库。而本书自身编写了vglLoadImage()的封装函数加载dds格式的纹理。

 三、纹理的使用
        1、采样器对象
        在非固定流水线中,OpengGL通过关联一个采样器变量和一个纹理单元,并且使用GLSL的内置函数从纹理图像中提取纹素,这样在着色中可以任意是用纹理数据。
           void glGenSamplers( GLsizei count, GLuint* samplers ):返回count个未使用的sampler名称。0是保留至,永远不会被返回。
           void glBindSampler( GLuint uint, GLuint sampler ): unit 是基于0的无符号整数,允许OpenGL实现支持任意数目的采样器单元而不用OpenGL保留标志。 可以理解为任意的无符号整数,0,1,2.......并不表示纹理单元。那问题来了,该如何关联起来让着色器通过sampler查询纹理数据呢?1、需要在着色器中定义内置采样器类型:samplerBuffer,sample2D.... 修饰的整形变量。texture unit 的值就对应于这个变量的值,这个值需要在应用程序c++代码中通过glUniformi()赋值,着色器中根据这个值具体类型采用不同类型的内置函数查询纹理数据,并在采样过程中应用比较模式,缩放过滤模式之类的,而对于同一纹理数据源,使用不同设置的sampler可以达到不同的采样结果,这也许是非默认sampler的好处之一。
            GLboolean gllsSampler( GLenum id ):判断id是否是一个采样器名称。返回GL_TRUE or GL_FALSE.
        2、设置采样器参数
         每个采样器对象拥有控制如何从纹理中采集纹素的一些参数,使用glSamplerParameter*()函数进行设置。
         void glSamplerParameter{fi}( GLuint sampler, GLenum paname, Type param )
         void glSamplerParameter{fi}v( GLuint sampler, GLenum paname, const Type* param  ):  
         void glSamplerParameterl{I,ui}v( GLuint sampler, GLenum pname, const Type* param )  
        给sampler名称的采样器对象设置,pname参数,值为 param。三个版本对应于不同数据类型的param。对于pname主要包括,纹理缩放过滤方式,对于当纹理坐标不在0.0--1.0范围内是的处理方式。其中对应关系如下:
pname
param
GL_TEXTURE_MAG_FILTER
GL_NEAREST、GL_LINEAR
GL_TEXTURE_MIN_FILTER
GL_NEAREST、GL_LINEAR、GL_NEAREST_MIPMAP_NEAREST、GL_NEAREST_MIPMAP_LINEAR、GL_LINEAR_MIPMAP_NEAREST、GL_LINEAR_MIPMAP_LINEAR
GL_TEXTURE_WRAP_S、GL_TEXTURE_WRAP_T
GL_REPEAT、GL_CLAMP_TO_EDGE、GL_MIRRORED_REPEAT
具体意义课查阅openGL文档: https://www.opengl.org/sdk/docs/man4/  ctrl+f函数名称即可。有详细的解释。
        当没有采样器对象绑定到对应的采样器单元时,每个用来从纹理中读取数据的纹理对象都有默认的采样器对象。为了修改这些参数,可以使用glTexParameter*()函数。
        void glTexParameter{fi}( GLenum target, GLenum pname, Type param )
        void glTexParameter{fi}v( GLenum target, GLenum pname, Type, param )
        void glTexParameterl{fi}v( GLenum target, GLenum pname, Type param )
        target参数表示绑定到当前激活纹理单元的纹理对象,pname ,与 param大致与glSamplerParameter*()相同,不过glTexParameter*()有更多不同的参数,控制不同方面的内容,如当 还有对于外部的数据源,并不能保证其纹理数据的保存顺序均为RGBA分分量顺序。所以OpenGL提供了在读取时纹理数据的保存顺序设置。man手册万能:https://www.opengl.org/sdk/docs/man4/  
        最后你是删除sampler对象的接口:glDeleteSamplers( GLsizei count, const GLuint* samplers )
        GLSL在着色器阶段可以使用内置函数来读取纹理信息。texture()的几个重载版本。
        Gvec4 texture( gsampler1D tex, float P[, float bias] )
        Gvec4 texture( gsampler2D tex, float P[, float bias] );
        Gvec4 texture( gsampler3D tex, float P[, float bias] );
        Gvec4 texture( gsamplerCube tex, float P[, float bias] );
        Gvec4 texture( gsampler1DArray tex, float P[, float bias] );
        Gvec4 texture( gsampler2DArray tex, float P[, float bias] );
        Gvec4 texture( gsampler2DRect tex, float P[, float bias] );
        Gvec4 texture( gsamplerCubeArray tex, float P[, float bias] );
        tex表示纹理采样器类型,前面加g相当于一个占位符,如gsampler2D可以表示sampler2D, isampler2D,或则usampler2D.Gvec4也是可以表示vec4 ivec4 uvec4.。p表示纹理的纹理坐标,bias表示如果启动了mipmapping,用来偏移确定mipmap的细节层次计算。
      4、几个简单的例子,代码中对于使用到的一些接口参数会有详细的解释。
            先来看一下LoadTexture的内容。
    
GLuint vglLoadTexture(const char* filename,
                      GLuint texture,
                      vglImageData* image)
{
    vglImageData local_image;
    int level;

    if (image == 0)
        image = &local_image;

    vglLoadImage(filename, image);

    if (texture == 0)
    {
        glGenTextures(1, &texture);
    }

    glBindTexture(image->target, texture);

    GLubyte * ptr = (GLubyte *)image->mip[0].data;

    switch (image->target)
    {
        case GL_TEXTURE_1D:
            glTexStorage1D(image->target,
                           image->mipLevels,
                           image->internalFormat,
                           image->mip[0].width); //根据从dds中读取到的纹理数据,分配纹理内存,设置纹理格式。
            for (level = 0; level < image->mipLevels; ++level)
            {
                glTexSubImage1D(GL_TEXTURE_1D,
                                level,
                                0,
                                image->mip[level].width,
                                image->format, image->type,
                                image->mip[level].data);//设置数据,minmap
            }
            break;
        case GL_TEXTURE_1D_ARRAY:
            glTexStorage2D(image->target,
                           image->mipLevels,
                           image->internalFormat,
                           image->mip[0].width,
                           image->slices);
            for (level = 0; level < image->mipLevels; ++level)
            {
                glTexSubImage2D(GL_TEXTURE_1D,
                                level,
                                0, 0,
                                image->mip[level].width, image->slices,
                                image->format, image->type,
                                image->mip[level].data);
            }
            break;
        case GL_TEXTURE_2D:
            glTexStorage2D(image->target,
                           image->mipLevels,
                           image->internalFormat,
                           image->mip[0].width,
                           image->mip[0].height);
            for (level = 0; level < image->mipLevels; ++level)
            {
                glTexSubImage2D(GL_TEXTURE_2D,
                                level,
                                0, 0,
                                image->mip[level].width, image->mip[level].height,
                                image->format, image->type,
                                image->mip[level].data);
            }
            break;
        case GL_TEXTURE_CUBE_MAP:
            for (level = 0; level < image->mipLevels; ++level)
            {
                ptr = (GLubyte *)image->mip[level].data;
                for (int face = 0; face < 6; face++)
                {
                    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
                                 level,
                                 image->internalFormat,
                                 image->mip[level].width, image->mip[level].height,
                                 0,
                                 image->format, image->type,
                                 ptr + image->sliceStride * face);
                }
            }
            break;
        case GL_TEXTURE_2D_ARRAY:
            glTexStorage3D(image->target,
                           image->mipLevels,
                           image->internalFormat,
                           image->mip[0].width,
                           image->mip[0].height,
                           image->slices);
            for (level = 0; level < image->mipLevels; ++level)
            {
                glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
                                level,
                                0, 0, 0,
                                image->mip[level].width, image->mip[level].height, image->slices,
                                image->format, image->type,
                                image->mip[level].data);
            }
            break;
        case GL_TEXTURE_CUBE_MAP_ARRAY:
            glTexStorage3D(image->target,
                           image->mipLevels,
                           image->internalFormat,
                           image->mip[0].width,
                           image->mip[0].height,
                           image->slices);
            break;
        case GL_TEXTURE_3D:
            glTexStorage3D(image->target,
                           image->mipLevels,
                           image->internalFormat,
                           image->mip[0].width,
                           image->mip[0].height,
                           image->mip[0].depth);
            for (level = 0; level < image->mipLevels; ++level)
            {
                glTexSubImage3D(GL_TEXTURE_3D,
                                level,
                                0, 0, 0,
                                image->mip[level].width, image->mip[level].height, image->mip[level].depth,
                                image->format, image->type,
                                image->mip[level].data);
            }
            break;
        default:
            break;
    }

    glTexParameteriv(image->target, GL_TEXTURE_SWIZZLE_RGBA, reinterpret_cast(image->swizzle));

    if (image == &local_image)
    {
        vglUnloadImage(image);
    }

    return texture;
}
a、简单纹理加载
#include "vermilion.h"
#include "loadTexture.h"
#include "vbm.h"
#include "vmath.h"
#include "vutils.h"

namespace loadTexture
{
	float aspect = 800.0f/600.0f;
	GLuint base_prog;
	GLuint vao;

	GLuint quad_vbo;

	GLuint tex;
};

using namespace loadTexture;

void loadTextureInit()
{
	base_prog = glCreateProgram();

	static const char quad_shader_vs[] =
		"#version 330 core\n"
		"\n"
		"layout (location = 0) in vec2 in_position;\n"
		"layout (location = 1) in vec2 in_tex_coord;\n"
		"\n"
		"out vec2 tex_coord;\n"
		"\n"
		"void main(void)\n"
		"{\n"
		"    gl_Position = vec4(in_position, 0.5, 1.0);\n"
		"    tex_coord = in_tex_coord;\n"//把纹理坐标传递给下一阶段。 
		"}\n"
		;

	static const char quad_shader_fs[] =
		"#version 330 core\n"
		"\n"
		"in vec2 tex_coord;\n"
		"\n"
		"layout (location = 0) out vec4 color;\n"
		"\n"
		"uniform sampler2D tex;\n"
		"\n"
		"void main(void)\n"
		"{\n"
		"    color = texture(tex, tex_coord);\n"//texture 根据纹理坐标采集纹素。
		"}\n"
		;
		
	vglAttachShaderSource( base_prog, GL_VERTEX_SHADER, quad_shader_vs );
	vglAttachShaderSource( base_prog, GL_FRAGMENT_SHADER, quad_shader_fs );

	glGenBuffers( 1, &quad_vbo );
	glBindBuffer( GL_ARRAY_BUFFER, quad_vbo );

	static const GLfloat quad_data[] =
	{
		0.5f, -0.5f,
		-1.0f, -1.0f,
		-1.0f, 1.0f,
		1.0f, 1.0f,

		0.0f, 0.0f,
		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f
	};

	glBufferData( GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW );

	glGenVertexArrays( 1, &vao );
	glBindVertexArray( vao );

	glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) ); //设置顶点着色器的输出,顶点坐标
	glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET( 8 * sizeof(float) ) );//顶点数据,纹理坐标

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	glLinkProgram( base_prog );

	//char buf[1024];
	//glGetProgramInfoLog( base_prog, 1024, NULL, buf );

	vglImageData image;

	tex = vglLoadTexture("../8edlib/media/test.dds", 0, &image ); //内部实现了纹理加载操作glGenTexture(),glBindTexture(),glStorage*(),glTexSubImage*()

	glTexParameteri( image.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); //纹理缩小过滤模式
	vglUnloadImage(&image);//纹理信息已经保存在纹理对象当中,释放内存
}

void loadTextureDisplay()
{
	float t = float(GetTickCount() & 0x3FFF) / float(0x3FFF);
	static const vmath::vec3 X(1.0f, 0.0f, 0.0f);
	static const vmath::vec3 Y(0.0f, 1.0f, 0.0f);
	static const vmath::vec3 Z(0.0f, 0.0f, 1.0f);

	glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
	glClearDepth( 1.0f );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glDisable( GL_CULL_FACE );//禁用剔除操作
	glUseProgram( base_prog );

	glBindVertexArray( vao );
	glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );//扇形三角形绘制

}

void loadTextureUpdate(float delta)
{

}
运行结果:
OpenGL学习笔记-2015.4.1——纹理加载与控制_第1张图片
b、纹理坐标越界控制
#include "commonHead.h"
#include "vbm.h"
#include "vutils.h"

namespace textureWrap
{
	float aspect = 800.0f/600.0f;
    GLuint base_prog;
    GLuint vao;

    GLuint quad_vbo;

    GLuint tex;
};

using namespace textureWrap;

void textureWrapInit()
{
	base_prog = glCreateProgram();

	static const char quad_shader_vs[] =
		"#version 330 core\n"
		"\n"
		"layout (location = 0) in vec2 in_position;\n"
		"layout (location = 1) in vec2 in_tex_coord;\n"
		"\n"
		"out vec2 tex_coord;\n"
		"\n"
		"void main(void)\n"
		"{\n"
		"    gl_Position = vec4(in_position, 0.5, 1.0);\n"
		"    tex_coord = in_tex_coord;\n"
		"}\n"
		;

	static const char quad_shader_fs[] =
		"#version 330 core\n"
		"\n"
		"in vec2 tex_coord;\n"
		"\n"
		"layout (location = 0) out vec4 color;\n"
		"\n"
		"uniform sampler2D tex;\n"
		"\n"
		"void main(void)\n"
		"{\n"
		"    color = texture(tex, tex_coord);\n"
		"}\n"
		;

	vglAttachShaderSource( base_prog, GL_VERTEX_SHADER, quad_shader_vs );
	vglAttachShaderSource( base_prog, GL_FRAGMENT_SHADER, quad_shader_fs );

	glGenBuffers( 1, &quad_vbo );
	glBindBuffer( GL_ARRAY_BUFFER, quad_vbo );

	static const GLfloat quad_data[] = 
	{
		-0.75f, -0.75f,
		0.75f, -0.75f,
		0.75f, 0.75f,
		-0.75f, 0.75f,

		0.0f, 0.0f,
		4.0f, 0.0f, 
		4.0f, 4.0f,
		0.0f, 4.0f
	};

	glBufferData( GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW );

	glGenVertexArrays( 1, &vao );
	glBindVertexArray( vao );

	glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
	glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET( 8 * sizeof(float) ) );

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	glLinkProgram( base_prog );

	glGenTextures( 1, &tex );
	glBindTexture( GL_TEXTURE_2D, tex );
	glTexStorage2D( GL_TEXTURE_2D, 4, GL_RGBA8, 8, 8 ); //分配内存,不可改变

	static const unsigned char texture_data[] =
	{
		0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
		0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
		0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
		0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
		0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
		0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
		0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
		0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF
	};

	glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RED, GL_UNSIGNED_BYTE, texture_data );//数据初始化

	static const GLint swizzles[] = { GL_RED, GL_RED, GL_RED, GL_ONE };//只使用纹理的红色通道
	glTexParameteriv( GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzles );

	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 );//超出-1.0~1.0f的纹理坐标处理方式设置s方向
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );//t方向

	glGenerateMipmap( GL_TEXTURE_2D );//产生层级纹理。

}

void textureWrapUpdate(float)
{

}

void textureWrapDisplay()
{
	unsigned int ticks = GetTickCount();
	float t = float(ticks & 0x3FFF) / float(0x3FFF);
	static const vmath::vec3 X(1.0f, 0.0f, 0.0f);
	static const vmath::vec3 Y(0.0f, 1.0f, 0.0f);
	static const vmath::vec3 Z(0.0f, 0.0f, 1.0f);

	glClearColor( 0.3f, 0.3f, 0.3f, 1.0f );
	glClearDepth( 1.0f );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glDisable( GL_CULL_FACE );
	glUseProgram( base_prog );

	static const GLenum wrap_modes[] = { GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, GL_REPEAT, GL_MIRRORED_REPEAT };
	//GL_CLAMP_TO_EDGE : 当纹理坐标超出0.0—1.0时,使用纹理边缘的纹素返回。
	//GL_CLAMP_TO_BORDER : 读取纹理范围之外的卓彪将生成用来形成最总的纹理常数边界颜色。可以通过glTexParameterfv()以GL_TEXTURE_BORDER_COLOR为参数设置边界颜色值。
	//GL_REPEAT : 包裹纹理,无限重复,只有纹理坐标的小数部分用来生成纹理坐标,整数部分被抛弃。
	//GL_MIRRORED_REPEAT : 是一个特殊的模式,纹理可以以镜像模式重复。整数部分是偶数的纹理坐标只考虑小数部分,整数部分是奇数的纹理坐标是1.0减去其小数部分来形成最终坐标。
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_modes[3] );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_modes[3] );

	glBindVertexArray( vao );
	glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );

}
运行结果:
OpenGL学习笔记-2015.4.1——纹理加载与控制_第2张图片
GL_CLAMP_TO_EDGE模式
OpenGL学习笔记-2015.4.1——纹理加载与控制_第3张图片
GL_CLAMP_TO_BORDER模式
OpenGL学习笔记-2015.4.1——纹理加载与控制_第4张图片
GL_REPEAT模式
OpenGL学习笔记-2015.4.1——纹理加载与控制_第5张图片
GL_MIRROED_REPEAT模式。

c、使用多重纹理。
#include "multiTexture\multiTexture.h"
#include "vbm.h"
#include "vutils.h"
#include  "vermilion.h"

namespace multiTexture
{
	float aspect = 800.0f/600.0f;
	GLuint base_prog;
	GLuint vao;

	GLuint quad_vbo;

	GLuint tex1;
	GLuint tex2;

	GLint  time_loc;
};

using namespace multiTexture;

void multiTextureInit()
{
	base_prog = glCreateProgram();

	static const char quad_shader_vs[] =
		"#version 330 core\n"
		"\n"
		"layout (location = 0) in vec2 in_position;\n"
		"layout (location = 1) in vec2 in_tex_coord;\n"
		"\n"
		"out vec2 tex_coord0;\n"
		"out vec2 tex_coord1;\n"
		"\n"
		"uniform float time;\n"
		"\n"
		"void main(void)\n"
		"{\n"
		"    mat2 m = mat2( vec2(cos(time), sin(time)),\n" //书中源码这里定义的是const mat2是会产生连接时错误,因为m是根据时间而改变的,不可以为const
		"                         vec2(-sin(time), cos(time)) );\n"
		"    gl_Position = vec4(in_position, 0.5, 1.0);\n"
		"    tex_coord0 = in_tex_coord * m;\n"
		"    tex_coord1 = in_tex_coord * transpose(m);\n"//构造的是一个旋转矩阵,
		"}\n"
		;

	static const char quad_shader_fs[] =
		"#version 330 core\n"
		"\n"
		"in vec2 tex_coord0;\n"
		"in vec2 tex_coord1;\n"
		"\n"
		"layout (location = 0) out vec4 color;\n"
		"\n"
		"uniform sampler2D tex1;\n" //sampler1
		"uniform sampler2D tex2;\n" //sampler2
		"\n"
		"void main(void)\n"
		"{\n"
		"    color = texture(tex1, tex_coord0) + texture(tex2, tex_coord1);\n" //对两个纹理采样进行混合,add
		"}\n"
		;
	vglAttachShaderSource( base_prog, GL_VERTEX_SHADER, quad_shader_vs );
	vglAttachShaderSource(base_prog, GL_FRAGMENT_SHADER, quad_shader_fs);

	glGenBuffers( 1, &quad_vbo );
	glBindBuffer( GL_ARRAY_BUFFER, quad_vbo );

	static const GLfloat quad_data[] =
	{
		1.0f, -1.0f,
		-1.0f, -1.0f,
		-1.0f, 1.0f,
		1.0f, 1.0f,

		0.0f, 0.0f,
		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f
	};

	glBufferData( GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW );

	glGenVertexArrays( 1, &vao );
	glBindVertexArray( vao );

	glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
	glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET( sizeof(float) * 8 ) );

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	
	glLinkProgram( base_prog );
	char buf[1024];
	glGetProgramInfoLog(base_prog, 1024, NULL, buf);
	glUseProgram(base_prog);
	time_loc = glGetUniformLocation( base_prog, "time" );
	glUniform1i(glGetUniformLocation(base_prog, "tex1"), 0);
	glUniform1i( glGetUniformLocation(base_prog, "tex2"), 1);
	
	vglImageData image;

	tex1 = vglLoadTexture("../8edlib/media/test.dds", 0, &image );
	
	glBindTexture( image.target, tex1 );
	glTexParameteri( image.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
	
	vglUnloadImage( &image );

	tex2 = vglLoadTexture("../8edlib/media/test3.dds", 0, &image);
	vglUnloadImage( &image );


}

void multiTextureDisplay()
{
	float t = float(GetTickCount() & 0x3FFF) / float(0x3FFF);
	static const vmath::vec3 X(1.0f, 0.0f, 0.0f);
	static const vmath::vec3 Y(0.0f, 1.0f, 0.0f);
	static const vmath::vec3 Z(0.0f, 0.0f, 1.0f);

	glClearColor( 0.0f, 1.0f, 0.0f, 1.0f );
	glClearDepth( 1.0f );
	
	glDisable( GL_CULL_FACE );
	glUseProgram( base_prog );
	glUniform1f( time_loc, t );
	
	glBindVertexArray( vao );
	glActiveTexture( GL_TEXTURE0 ); //启用纹理单元0
	glBindTexture( GL_TEXTURE_2D, tex1 );
	glActiveTexture( GL_TEXTURE1 ); //启用纹理单元1
	glBindTexture(GL_TEXTURE_2D, tex2 );

	glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
	GLenum errcode = glGetError();
	const char* buf1 = (const char*)glewGetErrorString(errcode);
}

void multiTextureUpdate(float delta)
{

}
运行结果
OpenGL学习笔记-2015.4.1——纹理加载与控制_第6张图片

T he End~~
希望坚持和努力会迎来好的结果。

你可能感兴趣的:(——OpenGL,读书笔记/Reading,Notes,——OpenGL,Program,Guide编程指南8ed)