您的位置:首页 > 运维架构

OpenGL超级宝典笔记三 - 基础纹理1

2015-05-07 15:56 489 查看
纹理对象的使用:纹理图像数据的类型,图像数据的导入导出方式,纹理的使用过程:图像数据的加载,纹理参数的设置,纹理的绑定。

一、图像数据的分类:位图图像和像素图像

二、像素图像数据的包装:

在OpenGL中:使用4字节的行对齐方式,每一行补全到4的倍数,使用glPixelStorei(pname,param)可以改变或者恢复像素的存储方式

介绍常用的两组:内存<->缓冲区的压缩和解包

glPixcelStorei(GL_UNPACK_ALIGNMENT) ----图像数据从内存到缓冲区的解包设置

glPixcelStorei(GL_PACK_ALIGNMENT) ---- 图像数据从缓冲区到内存的封包设置

三、像素图的存储过程(从颜色缓冲区中获取图像保存为图片)

1、从颜色缓冲区读取像素数据到内存中:glReadPixcels(x,y,width,height,format,type,*pixcels)

pixcels:必须有足够的存储空间

format:指定颜色布局,类似GL_RGB,GL_RBGA之类

type:颜色分量的数据类型,类似GL_UNSIGHED_BYTE,GL_BYTE之类

2、从内存到硬盘的图像文件保存

四、像素图数据的获取过程(从硬盘到内存)

gltReadTGABits(szFileName,iWidth,iHeight,iComponents,eFormat)

获取:图片位图数据,宽高,iComponents:颜色成分的存储大小和压缩状况,eFormat:颜色布局

这些数据是位图数据从内存加载到缓冲区的时候,OpenGL需要的数据

五、纹理载入方式一(图像数据从内存到纹理缓冲区):

glTexImage1D/glTexImage2D/glTexImage3D

glTexImage2D(target,level,internalformat,width,height,border,format,type,*data)

target:GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D

level:指定mip贴图的层次

internalformat:就是上述获取到的iComponents的数据

border:为纹理贴图指定一个边界宽度

format,type,data:和用于把图像数据放入颜色缓冲区的glDrawPixcels函数对应的参数一致

六、纹理载入方式二(图像数据从颜色缓冲区读取到纹理缓冲区):

glCopyTexImage2D(target,level,internalformat,x,y,width,height,border)

源缓冲区是通过glReadBuffer(mode)函数设置的。 mode为GL_FRONT,GL_LEFT 等参数

七、纹理更新操纵:更新替换原纹理的一部分数据

glTexSubImage2D(target,level,xOffset,yOffset,width,height,format,type,*data)

从颜色缓冲区中提取纹理作为数据去更新:

glCopyTexSubImage2D(target,level,xOffset,yOffset,width,height)

八、纹理对象的使用:由于使用glTexImage和glTexSubImage这样的函数加载和更新纹理太耗费内存,所以引用纹理对象

特点:纹理对象是允许我们一次加载一个以上的纹理状态(包括纹理图像)以及可以在它们之间快速切换的。

纹理对象的创建:glGenTextures(GLsizei n,GLuint* textures)

n:纹理对象数量

textures:不同纹理状态的句柄数组

纹理状态的绑定:glBindTexture(GLenum target,Gluint texture)

target:GL_TEXTURE_2D.....

texture:需要绑定的特定纹理状态

纹理对象的销毁:glDeleteTextures(n,textures)

纹理状态的确认:glIsTexure(GLuint texture)

九、纹理应用:

1、加载纹理数据

2、提供纹理坐标

s,t,r相当于x,y,z

3、设置纹理坐标的环绕模式(相对每个纹理坐标轴的)

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT)

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT)

环绕模式:

GL_REPEAT:超出1.0的对纹理进行重复

GL_CLAMP:使用纹理边界或者既定设置的边界颜色

GL_CLAMP_EDGE:使用纹理单元的最后一行或者一列数据

GL_CLAMP_BORDER:使用边界纹理单元

4、设置纹理的过滤(相对于拉伸和缩小的)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

过滤模式:

GL_NEAREST:最邻近过滤,快速,但是如果纹理被拉伸过大会出现大片的斑驳像素

GL_LINEAR:线性过滤,开销大,但是效果比较好

十、综合运用的例子:可以旋转带光照纹理的金字塔

// Pyramid.cpp
// OpenGL SuperBible, Chapter 5
// Demonstrates Texture mapping a pyramid
// Program by Richard S. Wright Jr.

#include <GLTools.h>	// OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLGeometryTransform.h>

#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

/////////////////////////////////////////////////////////////////////////////////
// An assortment of needed classes
GLShaderManager		shaderManager;
GLMatrixStack		modelViewMatrix;
GLMatrixStack		projectionMatrix;
GLFrame				cameraFrame;
GLFrame             objectFrame;
GLFrustum			viewFrustum;

GLBatch             pyramidBatch;

GLuint              textureID;

GLGeometryTransform	transformPipeline;
M3DMatrix44f		shadowMatrix;

void MakePyramid(GLBatch& pyramidBatch)
{
pyramidBatch.Begin(GL_TRIANGLES, 18, 1);
<span style="white-space:pre">	</span>//手动设置金字塔的顶点数据,包括位置,纹理坐标和光照法线向量
// Bottom of pyramid
pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);

pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3f(1.0f, -1.0f, -1.0f);

pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f);

pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
pyramidBatch.Vertex3f(-1.0f, -1.0f, 1.0f);

pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);

pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f);

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;

// 根据三个点计算法线向量
m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
pyramidBatch.Vertex3fv(vApex);		// Apex

pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontLeft);		// Front left corner

pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontRight);		// Front right corner

m3dFindNormal(n, vApex, vBackLeft, vFrontLeft);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
pyramidBatch.Vertex3fv(vApex);		// Apex

pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackLeft);		// Back left corner

pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontLeft);		// Front left corner

m3dFindNormal(n, vApex, vFrontRight, vBackRight);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
pyramidBatch.Vertex3fv(vApex);				// Apex

pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontRight);		// Front right corner

pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackRight);			// Back right cornder

m3dFindNormal(n, vApex, vBackRight, vBackLeft);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
pyramidBatch.Vertex3fv(vApex);		// Apex

pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackRight);		// Back right cornder

pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackLeft);		// Back left corner

pyramidBatch.End();
}
//获取纹理图像数据,并且设置纹理参数并得到一个纹理状态放入纹理对象中
bool loadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
GLbyte *pBits;
int nWidth,nHeight,nComponents;
GLenum eFormat;

pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if(pBits == NULL)
return false;
<span style="white-space:pre">	</span>//S,T轴上的纹理环绕模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
<span style="white-space:pre">	</span>//放大和缩小的过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,minFilter);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,magFilter);

glPixelStorei(GL_UNPACK_ALIGNMENT,1);		//图像数据解包,从内存区到缓存区
glTexImage2D(GL_TEXTURE_2D,0,nComponents,nWidth,nHeight,0,eFormat,GL_UNSIGNED_BYTE,pBits);

free(pBits);

if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
glGenerateMipmap(GL_TEXTURE_2D);

return true;
}

void SetupRC(){
glClearColor(0.7f,0.7f,0.7f,1.0f);

shaderManager.InitializeStockShaders();

glEnable(GL_DEPTH_TEST);

glGenTextures(1,&textureID);
glBindTexture(GL_TEXTURE_2D,textureID);
loadTGATexture("stone.tga",GL_LINEAR,GL_LINEAR,GL_CLAMP_TO_EDGE);

MakePyramid(pyramidBatch);
<span style="white-space:pre">	</span>//场景的照相机
cameraFrame.MoveForward(-7.0f);

}

void ShutdownRC(){
glDeleteTextures(1,&textureID);
}

void RenderScene(){
static GLfloat vLightPos[] = {1.0f,1.0f,0.0f};
static GLfloat vWhite[] = {1.0f,1.0f,1.0f,1.0f};

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.MultMatrix(mCamera);

M3DMatrix44f mObjectFrame;
objectFrame.GetCameraMatrix(mObjectFrame);
modelViewMatrix.MultMatrix(mObjectFrame);
<span style="white-space:pre">	</span>//在提交批绘制的时候,绑定我们需要使用的纹理
glBindTexture(GL_TEXTURE_2D,textureID);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(),vLightPos,vWhite,0);

pyramidBatch.Draw();

modelViewMatrix.PopMatrix();

glutSwapBuffers();
}

void SpecialKeys(int key,int x,int y){
if(key == GLUT_KEY_UP)
objectFrame.RotateWorld(m3dDegToRad(-5.0f),1.0f,0.0f,0.0f);
if(key == GLUT_KEY_DOWN)
objectFrame.RotateWorld(m3dDegToRad(5.0f),1.0f,0.0f,0.0f);
if(key == GLUT_KEY_LEFT)
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);

if(key == GLUT_KEY_RIGHT)
objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);

glutPostRedisplay();
}

void ChangeSize(int w,int h){
glViewport(0,0,w,h);
viewFrustum.SetPerspective(35.0f,float(w)/float(h),1.0f,500.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix,projectionMatrix);
}

int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("Pyramid");
glutReshapeFunc(ChangeSize);
glutSpecialFunc(SpecialKeys);
glutDisplayFunc(RenderScene);

GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}

SetupRC();

glutMainLoop();

ShutdownRC();

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: