1 VertexShader
1 | attribute vec2 TexCoordIn; // New |
2 FragmentShader
1 | varying lowp vec4 DestinationColor; |
3 将图片资源转换成位图数据,绑定到对应纹理ID中
1 | + (GLuint)createTextureWithImage:(UIImage *)image{ |
4 绘制时使用纹理
1 | glActiveTexture(GL_TEXTURE0); |
5 关于纹理坐标
1 VertexShader
1 | attribute vec2 TexCoordIn; // New |
2 FragmentShader
1 | varying lowp vec4 DestinationColor; |
3 将图片资源转换成位图数据,绑定到对应纹理ID中
1 | + (GLuint)createTextureWithImage:(UIImage *)image{ |
4 绘制时使用纹理
1 | glActiveTexture(GL_TEXTURE0); |
5 关于纹理坐标
1 发射光(emission):物体本身发的光,如果物体不发光,一般无此属性
2 环境光(ambient):在环境中充分散射的光,光线在物体表面各个方向均匀泛射在openGL中,全局光强度为(0.2,0.2,0.2,1.0)
3 漫反射光(diffuse):关于来自某个方向,但是在物体表面向各个方向反射
4 镜面高光:光线来自某一个特定的方向,然后在物体表面,以一个特定方向反射出去,在OpenGL中,镜面反射的强度,可以通过光泽度(shiness)来调节
1 发射光计算:发射颜色=物体的发射材质颜色
2 环境光计算
环境颜色 = 光源的环境光颜色*物体的环境材质颜色
3 漫反射计算:
漫反射颜色=光源的漫反射光颜色 * 物体的漫反射材质颜色 * DiffuseFactor
其中DiffuseFactor = max(0,dot(N,L))
dot表示两个向量夹角的cos
4 镜面反射:
镜面反射颜色 = 光源的镜面光颜色 * 物体的镜面材质颜色 * SpecularFactor
SpecularFactor = power(max(0, dot(N,H)),shininess)
H = normalise(L+E)
主要是为了提高效率,减少在CPU向GPU中传输数据,直接在GPU上申请内存空间
两种target分别是GL_ARRAY_BUFFER和GL_ELEMENT_ARRAY_BUFFER
分别对应顶点数据和索引
使用glVertexAttribPointer和glDrawElements的流程和以前大致保持一致,区别在于,最后一个参数不是传指针了,而是传bindBuffer的偏移量
1 | //获取一个操作句柄 |
attribute,可以理解为顶点的属性,表示顶点的输入数据,只在顶点着色器中使用
uniform,可以简单理解为向着色器中传递matrix等数据,这个是在着色器中是只读的,并且在两个着色器中都可以使用
使用上的区别:
1 获取指针,分别使用glGetAttribLocation和glGetUniformLocation方法
2 设置值时,分别使用glVertexAttribPointer和glUniformMatrix4fv,注意使用glVertexAttribPointer和glEnableVertexAttribArray需要配合使用,而glUniformMatrix4fv无此限制
3 使用矩阵时,一般先LoadIdentity,然后进行平移,旋转和缩放,glDrawElements与顶点着色器可以理解为一一对应,也就是说,可以设置matrix1,传入shader的modelView中,然后glDrawElements,接下来可以再设置matrix2,再传入modelView中,再进行glDrawElements
1 EAGLView的layer为CAEAGLLayer,设置kEAGLDrawablePropertyRetainedBacking和kEAGLDrawablePropertyColorFormat属性
1 | - (void)setupLayer{ |
2 创建EAGLContext
1 | _context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2]; |
3 加载着着色器程序,获取到着色器变量的索引,此过程,大致可分为:
a获取着色器源文件,创建shader,编译
b创建program,attachShader,link,useProgram
c从program,通过名字获取着色器中变量的索引(后续可以向着色器中传递参数)
这里有一点需要注意,此过程的前提,一定是已经设置了EAGLContext的currentContext
4 每一帧绘制流程
在外面使用CADisplayLink来控制播放帧率,每一帧的绘制流程就是
1 | - (void)drawFrame{ |
5 关于frameBuffetObject的创建和释放
前提:context确保设置
流程大致是
1 | - (void)createBuffer{ |
6 关于绘制三角形
1 | - (void)draw{ |
frame描述的是在父layer上的坐标和尺寸
bounds是类似于View的bounds
anchor描述的是做动画时,比如旋转时的中心点,以某个点旋转,默认时(0.5,0.5)左上点是(0,0),右下点是(1,1)
position描述的是anchor的在父layer的坐标
举例来说,一个View的Frame是(40,40,100,100)
那么layer的frame是(40,40,100,100)
bound是(0,0,100,100)
position是:(140,140)
position计算:
pos.x = origin.x + anchor.x*size.with
pos.y = origin.y + anchor.y*size.height
如果想修改anchor,一定要同时修改position,才能保证位置不变,否则,单独修改position或者anchor,根据上面公式会导致layer位置发生变化
如果想修改anchor,而不影响layer移动,只需修改完成后,再设置一次layer的frame即可
CGRect oldFrame = _redView.frame;
_redView.layer.anchorPoint = CGPointMake(0.5, 1);
_redView.frame = oldFrame;
注意,position并不适用这一点