iOS OpenGL 纹理坐标详解


//顶点着色器
//v.shader

//顶点着色器是一个可编程的处理单元,执行顶点变换、纹理坐标变换、光照、材质等顶点的相关操作,每顶点执行一次。替代了传统渲染管线中顶点变换、光照以及纹理坐标的处理,开发人员可以根据自己的需求自行开发,大大增加了程序的灵活性。
//顶点着色器主要是传入相应的Attribute变量、Uniforms变量、采样器以及临时变量,经过顶点着色器后生成Varying变量。

attribute vec4 position;// 应用程序传入顶点着色器的顶点位置

//vec2                包含了2个浮点数的向量
//vec3                包含了3个浮点数的向量
//vec4                包含了4个浮点数的向量

//(1)attribute变量(属性变量)只能用于顶点着色器中,不能用于片元着色器。一般用该变量来表示一些顶点数据,如:顶点坐标、纹理坐标、颜色等。
//(2)uniforms变量(一致变量)用来将数据值从应用程其序传递到顶点着色器或者片元着色器。该变量有点类似C语言中的常量(const),即该变量的值不能被shader程序修改。一般用该变量表示变换矩阵、光照参数、纹理采样器等。
//(3)varying变量(易变变量)是从顶点着色器传递到片元着色器的数据变量。顶点着色器可以使用易变变量来传递需要插值的颜色、法向量、纹理坐标等任意值。在顶点与片元shader程序间传递数据是很容易的,一般在顶点shader中修改varying变量值,然后片元shader中使用该值,当然,该变量在顶点及片元这两段shader程序中声明必须是一致的。例如:下面代码中应用程序中由顶点着色器传入片元着色器中的coord变量。
//(4)gl_Position为内建变量,表示变换后点的空间位置。顶点着色器从应用程序中获得原始的顶点位置数据,这些原始的顶点数据在顶点着色器中经过平移、旋转、缩放等数学变换后,生成新的顶点位置。新的顶点位置通过在顶点着色器中写入gl_Position传递到渲染管线的后继阶段继续处理。

attribute vec2 textCoord;// 应用程序传入顶点着色器的顶点纹理坐标

varying lowp vec2 coord;// 用于传递给片元着色器的顶点纹理数据


uniform mat4 modelViewProjectionMatrix;// 应用程序传入顶点着色器的矩阵坐标

void main(){
    
    coord = textCoord;
//    gl_Position = position;
    
    gl_Position = modelViewProjectionMatrix * position;
}

//片元着色器
// f.shader

//

varying lowp vec2 coord;// 接收从顶点着色器过来的纹理坐标 

uniform sampler2D colorMap;// 纹理采样器,代表一幅纹理


void main(){
//    gl_FragColor = vec4(0, 1, 0, 1);
    
//    片段的颜色改为由“texture2D”函数计算出来,实际上就是按纹理坐标从纹理像素中取样。
    gl_FragColor = texture2D(colorMap, coord.st);// 进行纹理采样
    
    
//    此片元着色器的主要功能为根据接收的记录片元纹理坐标的易变变量中的纹理坐标,调用texture2D内建函数从采样器中进行纹理采样,得到此片元的颜色值。最后,将采样到的颜色值传给gl_FragColor内建变量,完成片元的着色。
    
//    片元着色器是一个处理片元值及其相关联数据的可编程单元,片元着色器可执行纹理的访问、颜色的汇总、雾化等操作,每片元执行一次。片元着色器替代了纹理、颜色求和、雾以及Alpha测试,这一部分是需要开发者自己开发的。
//    
//    (1)varying指的是从顶点着色器传递到片元着色器的数据变量
//    (2)gl_FragColor为内置变量,用来保存片元着色器计算完成的片元颜色值,此颜色值将送入渲染管线的后继阶段进行处理。
    
    //varying在片元着色器里面表示从顶点着色器传过来的输入参数;
    //片元着色器不能直接传如参数,只能接收顶点着色器的输出;
    
}


//
//  ViewController.m
//  test_opengl_02
//
//  Created by jeffasd on 16/8/5.
//  Copyright © 2016年 jeffasd. All rights reserved.
//

#import "ViewController.h"

//// 顶点坐标既法线和纹理
//GLfloat squareVertexData[48] = {
//    
//    0.5f, 0.5f, -0.9f,     0.0f, 0.0f, 1.0f,   1.0f, 1.0f,//0
//    -0.5f, 0.5f, -0.9f,     0.0f, 0.0f, 1.0f,   0.0f, 1.0f,//1
//    0.5f, -0.5f, -0.9f,     0.0f, 0.0f, 0.0f,   1.0f, 0.0f,//2
//    0.5f, -0.5f, -0.9f,     0.0f, 0.0f, 0.0f,   1.0f, 0.0f,//2
//    -0.5f, 0.5f, -0.9f,     0.0f, 0.0f, 1.0f,   0.0f, 1.0f,//1
//    -0.5f, -0.5f, -0.9f,     0.0f, 0.0f, 1.0f,   0.0f, 0.0f//3
//};

// 顶点坐标既法线和纹理
//GLfloat squareVertexData[48] = {
//    
//    0.5f, 0.5f, -0.9f,     0.0f, 0.0f, 1.0f,   1.0f, 1.0f,//0
//    -0.5f, 0.5f, -0.9f,     0.0f, 0.0f, 1.0f,   0.0f, 1.0f,//1
//    0.5f, -0.5f, -0.9f,     0.0f, 0.0f, 0.0f,   1.0f, 0.0f,//2
//    -0.5f, -0.5f, -0.9f,     0.0f, 0.0f, 1.0f,   0.0f, 0.0f,//3
//    0.5f, -0.5f, -0.9f,     0.0f, 0.0f, 0.0f,   1.0f, 0.0f,//2
//    -0.5f, 0.5f, -0.9f,     0.0f, 0.0f, 1.0f,   0.0f, 1.0f//1
//    
//};

typedef struct {
    GLfloat Positon[3];//位置
    GLfloat Normal[3];//法线
    GLfloat Color[4];//颜色-这里使用GLKBaseEffect做着色器 此值在此处没有用到
    GLfloat TexCoord[2];//纹理
} Vertex;

// 顶点坐标既法线和纹理
const Vertex squareVertexData[] = {
    
    //默认纹理取样坐标
//    {0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  1.0f, 1.0f},//0
//    {-0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  0.0f, 1.0f},//1
//    {0.5f, -0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f},//2
//    {-0.5f, -0.5f, -0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,  0.0f, 0.0f}//3
    
    //改变纹理取样坐标1
//    {0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  1.0f, 1.0f},//0
//    {-0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  0.0f, 1.0f},//1
//    {0.5f, -0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  1.0f, -1.0f},//2
//    {-0.5f, -0.5f, -0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,  0.0f, -1.0f}//3
    

    //改变纹理取样坐标 三角形取样
//    {0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  0.0f, 0.0f},//0
//    {-0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  0.25f, 1.0f},//1
//    {0.5f, -0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f},//2
//    {-0.5f, -0.5f, -0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,  0.0f, 0.0f}//3
    
    //改变纹理取样坐标 小矩形取样
    {0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  0.5f, 0.5f},//0
    {-0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  -0.5f, 0.5f},//1
    {0.5f, -0.5f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  0.5f, -0.5f},//2
    {-0.5f, -0.5f, -0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,  -0.5f, -0.5f}//3
    
    //改变顶点坐标
//    {0.5f, 0.2f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  1.0f, 1.0f},//0
//    {-0.5f, 0.2f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  0.0f, 1.0f},//1
//    {0.5f, -0.2f, -0.9f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f},//2
//    {-0.5f, -0.2f, -0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,  0.0f, 0.0f}//3
    
};


const GLubyte Indices[] = {
    0, 1, 2,
    2, 1, 3
};

//每行顶点数据的排列含义是:
//
//顶点X、顶点Y,顶点Z、法线X、法线Y、法线Z、纹理S、纹理T。
//
//在后面解析此数组时,将参考此规则。
//
//顶点位置用于确定在什么地方显示,法线用于光照模型计算,纹理则用在贴图中。
//
//一般约定为“顶点以逆时针次序出现在屏幕上的面”为“正面”。
//
//世界坐标是OpenGL中用来描述场景的坐标,Z+轴垂直屏幕向外,X+从左到右,Y+轴从下到上,是右手笛卡尔坐标系统。我们用这个坐标系来描述物体及光源的位置。

@interface ViewController (){
    
    GLuint _program;
    
    GLfloat _rotation;
}

@property (nonatomic, strong) EAGLContext *context;
@property (nonatomic, strong) GLKBaseEffect *effect;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
//    self.view.backgroundColor = [UIColor whiteColor];
    
    
    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    
    if (!_context) {
        NSLog(@"faile to init context");
    }
    
    GLKView *glkView = (GLKView *)self.view;
    glkView.context = self.context;
    
//    drawableColorFormat
//    你的OpenGL上下文有一个缓冲区,它用以存储将在屏幕中显示的颜色。你可以使用其属性来设置缓冲区中每个像素的颜色格式。
//    缺省值是GLKViewDrawableColorFormatRGBA8888,即缓冲区的每个像素的最小组成部分(-个像素有四个元素组成 RGBA)使用8个bit(如R使用8个bit)(所以每个像素4个字节 既 4*8 个bit)。这非常好,因为它给了你提供了最广泛的颜色范围,让你的app看起来更好。
//    但是如果你的app允许更小范围的颜色,你可以设置为GLKViewDrawableColorFormatRGB565,从而使你的app消耗更少的资源(内存和处理时间)。
    glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    
    
//    drawableDepthFormat
//    你的OpenGL上下文还可以(可选地)有另一个缓冲区,称为深度缓冲区。这帮助我们确保更接近观察者的对象显示在远一些的对象的前面(意思就是离观察者近一些的对象会挡住在它后面的对象)。
//    其缺省的工作方式是:OpenGL把接近观察者的对象的所有像素存储到深度缓冲区,当开始绘制一个像素时,它(OpenGL)首先检查深度缓冲区,看是否已经绘制了更接近观察者的什么东西,如果是则忽略它(要绘制的像素,就是说,在绘制一个像素之前,看看前面有没有挡着它的东西,如果有那就不用绘制了)。否则,把它增加到深度缓冲区和颜色缓冲区。
//    你可以设置这个属性,以选择深度缓冲区的格式。缺省值是GLKViewDrawableDepthFormatNone,意味着完全没有深度缓冲区。
//    但是如果你要使用这个属性(一般用于3D游戏),你应该选择GLKViewDrawableDepthFormat16或GLKViewDrawableDepthFormat24。这里的差别是使用GLKViewDrawableDepthFormat16将消耗更少的资源,但是当对象非常接近彼此时,你可能存在渲染问题()。
    glkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    
//    将此“EAGLContext”实例设置为OpenGL的“当前激活”的“Context”。这样,以后所有“GL”的指令均作用在这个“Context”上。随后,发送第一个“GL”指令:激活“深度检测”。
    [EAGLContext setCurrentContext:_context];
    glEnable(GL_DEPTH_TEST);//发送第一个“GL”指令:激活“深度检测”。
    
//    创建一个GLK内置的“着色效果”,并给它提供一个光源,光的颜色为绿色。
    
//    iOS的OpenGL中里有2个着色器,
//    一个是GLKBaseEffect,为了方便OpenGL ES 1.0转移到2.0的通用着色器。
//    一个是OpenGL ES 2.0新添加的可编程着色器,使用跨平台的着色语言
    //    //实例化基础效果实例,如果没有GLKit与GLKBaseEffect类,就需要为这个简单的例子编写一个小的GPU程序,使用2.0的Shading Language,而GLKBaseEffect会在需要的时候自动的构建GPU程序。
    
    self.effect = [[GLKBaseEffect alloc] init];
    self.effect.light0.enabled = GL_TRUE;
//    self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 0.4f, 0.4f, 1.0f);
//    self.effect.light0.diffuseColor = GLKVector4Make(0.0f, 1.0f, 0.0f, 1.0f);
    self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f);
    
//    //实例化基础效果实例,如果没有GLKit与GLKBaseEffect类,就需要为这个简单的例子编写一个小的GPU程序,使用2.0的Shading Language,而GLKBaseEffect会在需要的时候自动的构建GPU程序。
//    self.baseEffect = [[GLKBaseEffect alloc] init];
//    self.baseEffect.useConstantColor = GL_TRUE;
//    
//    //控制渲染像素颜色的方式有多种。这个应用的GLKBaseEffect实例使用一个恒定不变的白色来渲染三角形。
//    //下面代码中使用的再GLKit中定义的用于保存4个颜色元素值的C数据结构体GLKVector4来设置这个恒定值。
//    self.baseEffect.constantColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f);
    
    
//    将顶点数据写入通用的顶点属性存储区
//
    //1.写入过程
//    首先将数据保存进GUP的一个缓冲区中,然后再按一定规则,将数据取出,复制到各个通用顶点属性中。
//    注:如果顶点数据只有一种类型(如单纯的位置坐标),换言之,在读数据时,不需要确定第一个数据的内存位置(总是从0开始),则不必事先保存进缓冲区。
//    
//    2.顶点数组保存进缓冲区
    //Vertex Data
    GLuint buffer;
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(squareVertexData), squareVertexData, GL_STATIC_DRAW);
    //    这几行代码表示的含义是:声明一个缓冲区的标识(GLuint类型)à让OpenGL自动分配一个缓冲区并且返回这个标识的值à绑定这个缓冲区到当前“Context”à最后,将我们前面预先定义的顶点数据“squareVertexData”复制进这个缓冲区中。
    
//    注:参数“GL_STATIC_DRAW”,它表示此缓冲区内容只能被修改一次,但可以无限次读取。
    
    GLuint elementBuffer;
    glGenBuffers(1, &elementBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
    
    
//    3、将缓冲区的数据复制进通用顶点属性中
    glEnableVertexAttribArray(GLKVertexAttribPosition);
//    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 4*8, 0);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
//    首先,激活顶点属性(默认它的关闭的)。“GLKVertexAttribPosition”是顶点属性集中“位置Position”属性的索引。
//    
//    顶点属性集中包含五种属性:位置、法线、颜色、纹理0,纹理1。
//    
//    它们的索引值是0到4。
//    
//    激活后,接下来使用“glVertexAttribPointer”方法填充数据。
//    
//    参数含义分别为:
//    
//    顶点属性索引(这里是位置)、3个分量的矢量、类型是浮点(GL_FLOAT)、填充时不需要单位化(GL_FALSE)、在数据数组中每行的跨度是32个字节(4*8=32。从预定义的数组中可看出,每行有8个GL_FLOAT浮点值,而GL_FLOAT占4个字节,因此每一行的跨度是4*8)。
//    
//    最后一个参数是一个偏移量的指针,用来确定“第一个数据”将从内存数据块的什么地方开始。
    
    
//    在前面预定义的顶点数据数组中,还包含了法线和纹理坐标,所以参照上面的方法,将剩余的数据分别复制进通用顶点属性中。
    glEnableVertexAttribArray(GLKVertexAttribNormal);
    
//    glVertexAttribPointer 指定了渲染时索引值为 index 的顶点属性数组的数据格式和位置
    
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid *) (sizeof(GLfloat) * 3));
//    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 4*8, (char *) + 12);
    
    
//    GLKVertexAttribColor
    
    glEnableVertexAttribArray(GLKVertexAttribColor);
    //glVertexAttribPointer 指定了渲染时索引值为 GLKVertexAttribColor 的顶点属性数组的数据格式和位置
    glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid *) (sizeof(GLfloat) * 6));
    
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
//    glVertexAttribPointer(GLKVertexAttribTexCoord0, 3, GL_FLOAT, GL_FALSE, 4*8, (char *) + 24);
    //glVertexAttribPointer 指定了渲染时索引值为 GLKVertexAttribTexCoord0 的顶点属性数组的数据格式和位置
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid *) (sizeof(GLfloat) * 10));
    
    //texture
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"beauty" ofType:@"png"];
//    默认,此图片加载进TEXTURE0,如果需要加载进其他单元,需要先用指令“glActiveTexure(GL_TEXTUREn)”。——n为1-(CL_COMBINED_TEXTURE_IMAGE_UNITS-1)中的一个数值。
//    
//    加载成功后,该纹理的信息都保存在“textureInfo”中,以后,直接使用此变量的相关属性,就可以在OpenGL中应用这个纹理了。
    //这样加载纹理图像会上下颠倒 图像颠倒是因为纹理的坐标原点不在左下角。
//    将纹理坐标原点改为左下角
//    
//    GLKit加载纹理,默认都是把坐标设置在“左上角”。然而,OpenGL的纹理贴图坐标却是在左下角,这样刚好颠倒。
//    
//    在加载纹理之前,添加一个“options”:
//    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:nil error:nil];
    
    
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], GLKTextureLoaderOriginBottomLeft, nil];
    
//    iOS GLKTextureInfo 纹理坐标默认值
//    Default Texture Parameters
//    
//    - The following values will be set as the default for the OpenGL filter and wrap texture parameters:
//        
//        GL_TEXTURE_MIN_FILTER: GL_LINEAR_MIPMAP_LINEAR if textures are mipmapped, GL_LINEAR otherwise
//            
//            GL_TEXTURE_MAG_FILTER: GL_LINEAR
//            
//            GL_TEXTURE_WRAP_S / GL_TEXTURE_WRAP_T: GL_CLAMP_TO_EDGE
//            
//            Any texture parameter not specified above will be set to OpenGL's default value.
    
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
    
    _effect.texture2d0.enabled = GL_TRUE;
    self.effect.texture2d0.name = textureInfo.name;
    
    
    NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"v" ofType:@"glsl"];
    NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"f" ofType:@"glsl"];
    _program = [self loadShaders:vertFile frag:fragFile];
    
    
//    此部分是绑定“position”属性到通用的的顶点属性索引“0”上,绑定“texCoord”到通用的顶点属性索引“3”上。(索引1是法线,2是顶点颜色)。
    glBindAttribLocation(_program, 0, "position");
    glBindAttribLocation(_program, 3, "textCoord");
//    绑定后,必须调用“glLinkProgram”方法才能生效。
    glLinkProgram(_program);
    
    
//    第二部分,绑定“统一的纹理sampler2D”变量,到纹理0号单元——在使用“GLKTextureLoader”加载纹理时,默认是激活了“0”号单元。当然,如果是激活其他单元(例如8),则这里就相应的改为8。
//    
//    绑定之前,必须调用“glUseProgram”才起作用。
    glUseProgram(_program);
    GLint colorMap = glGetUniformLocation(_program, "colorMap");
    glUniform1i(colorMap, 0);
    
}

- (GLint)loadShaders:(NSString *)vert frag:(NSString *)frag{
    GLuint vertShader, fragShader;
    GLuint program = glCreateProgram();
    
    [self compileShader:&vertShader type:GL_VERTEX_SHADER file:vert];
    [self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:frag];
    
    glAttachShader(program, vertShader);
    glAttachShader(program, fragShader);
    
//    最后,将“program”链接到当前“Context”,这样才能在OpenGL中发挥作用
    glLinkProgram(program);
    
    int params = 0;
    glGetProgramiv(program, GL_LINK_STATUS, ¶ms);
    if (params == 1) {
        NSLog(@"program is success");
    }
    
    return program;
}

-(void)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file{
    NSString *content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
    const GLchar *source = (GLchar *)[content UTF8String];
    
    *shader = glCreateShader(type);
    glShaderSource(*shader, 1, &source, NULL);
    glCompileShader(*shader);
}

//这两个方法每帧都执行一次(循环执行),一般执行频率与屏幕刷新率相同(但也可以更改)。
//
//第一次循环时,先调用“glkView”再调用“update”。
//
//一般,将场景数据变化放在“update”中,而渲染代码则放在“glkView”中。

//一般,将场景数据变化放在“update”中,而渲染代码则放在“glkView”中。
//本函数放场景变化代码
- (void)update{
    
    CGSize size = self.view.bounds.size;
    float aspect = fabs(size.width / size.height);
    
#if 0
    GLKMatrix4 projectionMatrix = GLKMatrix4Identity;
    projectionMatrix = GLKMatrix4Scale(projectionMatrix, 1.0f, aspect, 1.0f);
    self.effect.transform.projectionMatrix = projectionMatrix;
    
    GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 1.0f, 1.0f, -1.0f);
    
    self.effect.transform.modelviewMatrix = modelViewMatrix;
    
    GLint mat = glGetUniformLocation(_program, "modelViewProjectionMatrix");
    GLKMatrix4 modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
    glUniformMatrix4fv(mat, 1, GL_FALSE, modelViewProjectionMatrix.m);
#endif
    
//    查询到“modelViewProjectionMatrix”变量à计算合并矩阵à传给着色器。
//    
//    传入着色器的值是modelViewProjectionMatrix.m,注意后面的“m”,它表示是一维数组形式的矩阵。
    
//    glVertexAttribPointer
    
    
#if 1
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0), aspect, 0.1f, 10.0f);
    self.effect.transform.projectionMatrix = projectionMatrix;
    GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -1.0f);
    self.effect.transform.modelviewMatrix = modelViewMatrix;
    
    GLint mat = glGetUniformLocation(_program, "modelViewProjectionMatrix");
    
//    modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 0.0f, 0.0f, 1.0f);
    
    modelViewMatrix = GLKMatrix4Translate(modelViewMatrix, 0.0f, 1.0f, -1.0f);
    
//    modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 0.0f, 0.0f, 1.0f);
    
    GLKMatrix4 modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
    
//    查询到“modelViewProjectionMatrix”变量à计算合并矩阵à传给着色器。
//    传入着色器的值是modelViewProjectionMatrix.m,注意后面的“m”,它表示是一维数组形式的矩阵。
    glUniformMatrix4fv(mat, 1, GL_FALSE, modelViewProjectionMatrix.m);
    
    _rotation += self.timeSinceLastUpdate * 2.5f;
    
#endif
    
}

//渲染场景
//一般,将场景数据变化放在“update”中,而渲染代码则放在“glkView”中。
//本函数一般放渲染代码
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    
//    glClearColor(0.0, 1.0, 0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //    iOS的OpenGL中里有2个着色器,
    //    一个是GLKBaseEffect,为了方便OpenGL ES 1.0转移到2.0的通用着色器。
    //    一个是OpenGL ES 2.0新添加的可编程着色器,使用跨平台的着色语言
    //    //实例化基础效果实例,如果没有GLKit与GLKBaseEffect类,就需要为这个简单的例子编写一个小的GPU程序,使用2.0的Shading Language,而GLKBaseEffect会在需要的时候自动的构建GPU程序。
    
//    [self.effect prepareToDraw];

//    这里使用GLKBaseEffect来做着色器
    
    
//    triangle 三角形
//    glDrawArrays(GL_TRIANGLES, 0, 6);//GL_ARRAY_BUFFER
    
    int count = sizeof(Indices) / sizeof(Indices[0]);
    
    glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, 0);
    
//    前两行为渲染前的“清除”操作,清除颜色缓冲区和深度缓冲区中的内容,并且填充淡蓝色背景(默认背景是黑色)。
//    
//    “prepareToDraw”方法,是让“效果Effect”针对当前“Context”的状态进行一些配置,它始终把“GL_TEXTURE_PROGRAM”状态定位到“Effect”对象的着色器上。此外,如果Effect使用了纹理,它也会修改“GL_TEXTURE_BINDING_2D”。
//    
//    
//    
//    接下来,用“glDrawArrays”指令,让OpenGL“画出”两个三角形(拼合为一个正方形)。OpenGL会自动从通用顶点属性中取出这些数据、组装、再用“Effect”内置的着色器渲染。
    
    glUseProgram(_program);
//    glDrawArrays(GL_TRIANGLES, 0, 6);
    glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, 0);
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end


你可能感兴趣的:(iOS OpenGL 纹理坐标详解)