纹理的基本概念
纹理是一个用来保存图像的颜色元素的OpenGL ES缓存。当用一个图像初始化一个纹理缓存之后,在这个图像中的每个像素变成纹理中的一个纹素。纹素存在于一个虚拟的纹理坐标系中。纹理坐标系有一个命名为S和T的2D轴,轴大小为0.0-1.0,如下图:

〜
对齐纹理和几何图形
当绘制纹理时,我们需要把纹理坐标系与顶点的3D坐标系关联起来,所以在给顶点数据时,除了X、Y、Z坐标,还需要U和V的坐标值,U对应纹理坐标S轴的值,V对应纹理坐标T轴的值。
上代码
首先初始化数据,其中positionCoords为顶点坐标,图形由两个3角形组成,0.8是为了占整个视图的80%大小。textureCoords为纹理坐标,这里设置的是左下角(-1,-1)右上角(2,2),这样的话,总共有9个纹理坐标大小,正中间的一块坐标为左下角(0,0)右上角(1,1),为显示纹理的地方,其余边缘8块会根据拉伸样式来处理。
// 数据结构体
typedef struct {
GLKVector3 positionCoords;
GLKVector2 textureCoords;
}
SceneVertex;
// 要用到顶点纹理坐标
static SceneVertex vertices[] =
{
{{-0.8f, -0.8f, 0.0f}, {-1.0f, -1.0f}},
{{ 0.8f, -0.8f, 0.0f}, {2.0f, -1.0f}},
{{-0.8f, 0.8f, 0.0f}, {-1.0f, 2.0f}},
{{ 0.8f, -0.8f, 0.0f}, {2.0f, -1.0f}},
{{-0.8f, 0.8f, 0.0f}, {-1.0f, 2.0f}},
{{0.8f, 0.8f, 0.0}, {2.0f, 2.0f}},
};
〜
然后是进行一些初始化操作。
- (void)viewDidLoad {
[super viewDidLoad];
// 设置刷新时间为1/60秒
self.preferredFramesPerSecond = 60;
GLKView *view = (GLKView *)self.view;
NSAssert([view isKindOfClass:[GLKView class]], @"View controller's view is not a GLKView");
view.context = [[AGLKContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[AGLKContext setCurrentContext:view.context];
self.baseEffect = [[GLKBaseEffect alloc] init];
self.baseEffect.useConstantColor = GL_TRUE;
self.baseEffect.constantColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f);
((AGLKContext *)view.context).clearColor = GLKVector4Make(0.2f, 0.2f, 0.2f, 1.0f);
// 设置顶点缓存1,2,3步,生成id,绑定id,设置缓存内容
self.vertexBuffer = [[AGLKVertexAttribArrayBuffer alloc] initWithAttribStride:sizeof(SceneVertex)
numberOfVertices:sizeof(vertices)/sizeof(SceneVertex)
bytes:vertices
usage:GL_DYNAMIC_DRAW];
CGImageRef imageRef = [[UIImage imageNamed:@"small32.png"] CGImage];
// 垂直翻转图像数据
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(YES), GLKTextureLoaderOriginBottomLeft, nil];
// GLKTextureInfo类的作用
// 跟据图片获取OpenGL ES能使用的大小2的幂,向上取值,如400会变成512,最大1024
// 生成纹理缓存标识符
// 绑定当前上下文
// 将图片像素的颜色数据复制到绑定的纹理缓存中
// 其属性保存数据
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:imageRef
options:options
error:NULL];
self.baseEffect.texture2d0.name = textureInfo.name;
self.baseEffect.texture2d0.target = textureInfo.target;
// 多层纹理
CGImageRef imageRef1 = [[UIImage imageNamed:@"beetle.png"] CGImage];
GLKTextureInfo *textureInfo1 = [GLKTextureLoader textureWithCGImage:imageRef1
options:options
error:NULL];
self.baseEffect.texture2d1.name = textureInfo1.name;
self.baseEffect.texture2d1.target = textureInfo1.target;
// GLKTextureEnvModeReplace, 输出颜色由从纹理获取的颜色.忽略输入的颜色
// GLKTextureEnvModeModulate, 输出颜色是通过将纹理颜色与输入颜色来计算所得
// GLKTextureEnvModeDecal, 输出颜色是通过使用纹理的alpha组件来混合纹理颜色和输入颜色来计算的。
// GLKTextureEnvModeDecal颜色混合公式:
// 1为上层纹理,2为下层纹理
// R = A1*R1 + (1.0-A1)*R2
// G = A1*G1 + (1.0-A1)*G2
// B = A1*B1 + (1.0-A1)*B2
// A = A1 + (1.0-A1)*A2
// iOS CoreGraphics的混合方式也是如此
self.baseEffect.texture2d1.envMode = GLKTextureEnvModeDecal;
}
〜
〜
设置纹理填充样式
GL_TEXTURE_WRAP_S:S轴上填充样式
GL_TEXTURE_WRAP_T:T轴上填充样式
GL_REPEAT: 超出纹理范围的坐标整数部分被忽略,形成重复效果。
GL_MIRRORED_REPEAT: 超出纹理范围的坐标整数部分被忽略,但当整数部分为奇数时进行取反,形成镜像效果。
GL_CLAMP_TO_EDGE:超出纹理范围的坐标被截取成0和1,形成纹理边缘延伸的效果。
GL_TEXTURE_MAG_FILTER:放大过滤(图片小于实际使用像素时)
GL_TEXTURE_MIN_FILTER:缩小过滤(图片大于实际使用像素时)
GL_NEAREST:最靠近像素中心的那个纹理单元将用于放大和缩小,这可能导致锯齿状的人工痕迹(会出现马赛克)
GL_LINEAR:会对靠近像素中心的一块2×2的纹理单元去加权平均值,用于放大和缩小(会模糊)
以下为不同填充过滤方式的效果图:

// 设置纹理填充样式(重复加马赛克方式)
- (void)update {
[self.baseEffect.texture2d0 aglkSetParameter:GL_TEXTURE_WRAP_S
value:GL_REPEAT];
[self.baseEffect.texture2d0 aglkSetParameter:GL_TEXTURE_WRAP_T
value:GL_REPEAT];
[self.baseEffect.texture2d0 aglkSetParameter:GL_TEXTURE_MAG_FILTER
value:GL_NEAREST];
}
〜
〜
绘制视图
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
[self.baseEffect prepareToDraw];
[(AGLKContext *)view.context clear:GL_COLOR_BUFFER_BIT];
// 顶点4.5步,启用缓存,传达缓存格式
[self.vertexBuffer prepareToDrawWithAttrib:GLKVertexAttribPosition
numberOfCoordinates:3
attribOffset:offsetof(SceneVertex, positionCoords)
shouldEnable:YES];
// 猫纹理4.5步,启用缓存,传达缓存格式
[self.vertexBuffer prepareToDrawWithAttrib:GLKVertexAttribTexCoord0
numberOfCoordinates:2
attribOffset:offsetof(SceneVertex, textureCoords)
shouldEnable:YES];
// 虫子纹理4.5步,启用缓存,传达缓存格式
[self.vertexBuffer prepareToDrawWithAttrib:GLKVertexAttribTexCoord1
numberOfCoordinates:2
attribOffset:offsetof(SceneVertex, textureCoords)
shouldEnable:YES];
[self.vertexBuffer drawArrayWithMode:GL_TRIANGLES
startVertexIndex:0
numberOfVertices:6];
}
释放资源
-(void)dealloc {
GLKView *view = (GLKView *)self.view;
[AGLKContext setCurrentContext:view.context];
self.vertexBuffer = nil;
((GLKView *)self.view).context = nil;
[EAGLContext setCurrentContext:nil];
}
网友评论