重新自学学习openGL 之高级数据和高级glsl

本章主要讲解内容如下

  • glBufferSubData的用法
  • glMapBuffer 的用法
  • gl_PointSize 的使用
  • gl_FragCoord 的使用

数据填充的三种方式

正常填充

到目前为止,我们一直是调用glBufferData函数来填充缓冲对象所管理的内存,这个函数会分配一块内存,并将数据添加到这块内存中。
我们一般这样用

 glGenBuffers(1, &_vertexBuffers);
  glBindBuffer(GL_ARRAY_BUFFER,
                 self.vertexBuffers);
    glBufferData( GL_ARRAY_BUFFER,
                 self.getAllocSpaceByteNum,
                 self.vertex,       ///buffer中已经存在数据了
                 usage);

这是我们经常使用的填充方式,一次性填充好

关键测试代码

我们用正常填充的关键测试代码如下

#import "DefaultViewController.h"
#import "DefaultBindObject.h"
#import "SphereManager.h"
@interface DefaultViewController ()

@end

@implementation DefaultViewController

-(void)initSubObject{
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    self.bindObject = [DefaultBindObject new];
}


-(void)loadVertex{
    self.vertexPostion= [Vertex new];
    int vertexNum =[SphereManager getVertexNum];
    [self.vertexPostion allocVertexNum:vertexNum andEachVertexNum:3];
    for (int i=0; i<vertexNum; i++) {
        float onevertex[3];
        for (int j=0; j<3; j++) {
            onevertex[j]=[SphereManager getSphereVerts][i*3+j];
        }
        [self.vertexPostion setVertex:onevertex index:i];
    }
    [self.vertexPostion bindBufferWithUsage:GL_STATIC_DRAW];
    [self.vertexPostion enableVertexInVertexAttrib:DF_aPos numberOfCoordinates:3 attribOffset:0];
    
    self.vertexTexture = [Vertex new];
    [self.vertexTexture allocVertexNum:vertexNum andEachVertexNum:2];
    
    for (int i=0; i<vertexNum; i++) {
        float onevertex[2];
        for (int j=0; j<2; j++) {
            onevertex[j]=[SphereManager getSphereTexCoords][i*2+j];
        }
        [self.vertexTexture setVertex:onevertex index:i];
    }
    [self.vertexTexture bindBufferWithUsage:GL_STATIC_DRAW];
    [self.vertexTexture enableVertexInVertexAttrib:DF_aTexCoords numberOfCoordinates:2 attribOffset:0];
}


-(void)createTextureUnit{
    UIImage *  image = [UIImage imageNamed:@"Earth512x256.jpg"];
    self.textureUnit0 = [TextureUnit new];
    [self.textureUnit0 setImage:image IntoTextureUnit:GL_TEXTURE0 andConfigTextureUnit:nil];
}



-(GLKMatrix4)getMVP{
    GLfloat aspectRatio= CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds);
    GLKMatrix4 projectionMatrix =
    GLKMatrix4MakePerspective(
                              GLKMathDegreesToRadians(85.0f),
                              aspectRatio,
                              0.1f,
                              20.0f);
    GLKMatrix4 modelviewMatrix =
    GLKMatrix4MakeLookAt(
                         0.0, 0.0, 2.0,   // Eye position
                         0.0, 0.0, 0.0,   // Look-at position
                         0.0, 1.0, 0.0);  // Up direction
    return GLKMatrix4Multiply(projectionMatrix,modelviewMatrix);
}


-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glClearColor(1, 1, 1, 1);
    GLKMatrix4  mvp= [self getMVP];
    static GLfloat angle=0;
    angle++;
    GLKMatrix4 mode =GLKMatrix4MakeRotation(angle*M_PI/180, 0, 1, 0);
    GLKMatrix4 result=  GLKMatrix4Multiply(mvp,mode);
    glUniformMatrix4fv(self.bindObject->uniforms[DF_uniform_MVPMatrix], 1, 0,result.m);
    GLKVector4 ambientLight = GLKVector4Make(1.0, 1, 1, 1.0);
    glUniform4fv(self.bindObject->uniforms[DF_uniform_AmbientLight], 1,ambientLight.v);
    [self.textureUnit0 bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DF_uniform_Samplers2D]];

    [self.vertexPostion drawVertexWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:[SphereManager getVertexNum]];
}

@end

结果如下


分批填充

除了使用一次函数调用填充整个缓冲之外,我们也可以使用glBufferSubData,填充缓冲的特定区域。这个函数需要一个缓冲目标、一个偏移量、数据的大小和数据本身作为它的参数。这个函数不同的地方在于,我们可以提供一个偏移量,指定从何处开始填充这个缓冲。这能够让我们插入或者更新缓冲内存的某一部分。要注意的是,缓冲需要有足够的已分配内存,所以对一个缓冲调用glBufferSubData之前必须要先调用glBufferData。

GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
参数介绍
target 需要填充的缓冲区域
offset 缓冲区的偏移量
size 需要填充缓冲区的大小 填充在缓冲区位置是是 offset+size
data 需要填充的数据

    glBindBuffer(GL_ARRAY_BUFFER,
                 self.vertexBuffers);
    glBufferSubData(GL_ARRAY_BUFFER, offset, size, ptr);

因为可以分批写入,因为对填充数据具有更高的灵活性.
其实一次填充也可以完成上述操作的.只不过需要提前把需要填充的数据组织好

使用该方案,一般是需要分批填充顶点属性使用的

分批顶点属性

通过使用glVertexAttribPointer,我们能够指定顶点数组缓冲内容的属性布局。在顶点数组缓冲中,我们对属性进行了交错(Interleave)处理,也就是说,我们将每一个顶点的位置、发现和/或纹理坐标紧密放置在一起。既然我们现在已经对缓冲有了更多的了解,我们可以采取另一种方式。

我们可以做的是,将每一种属性类型的向量数据打包(Batch)为一个大的区块,而不是对它们进行交错储存。与交错布局123123123123不同,我们将采用分批(Batched)的方式111122223333。
当从文件中加载顶点数据的时候,你通常获取到的是一个位置数组、一个法线数组和/或一个纹理坐标数组。我们需要花点力气才能将这些数组转化为一个大的交错数据数组。使用分批的方式会是更简单的解决方案,我们可以很容易使用glBufferSubData函数实现:

float positions[] = { ... };
float normals[] = { ... };
float tex[] = { ... };
// 填充缓冲
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), &positions);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(normals), &normals);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals), sizeof(tex), &tex);

这样子我们就能直接将属性数组作为一个整体传递给缓冲,而不需要事先处理它们了。我们仍可以将它们合并为一个大的数组,再使用glBufferData来填充缓冲,但对于这种工作,使用glBufferSubData会更合适一点。

我们还需要更新顶点属性指针来反映这些改变:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);  
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(sizeof(positions)));  
glVertexAttribPointer(
  2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(sizeof(positions) + sizeof(normals)));

注意stride参数等于顶点属性的大小,因为下一个顶点属性向量能在3个(或2个)分量之后找到。

这给了我们设置顶点属性的另一种方法。使用哪种方法都不会对OpenGL有什么立刻的好处,它只是设置顶点属性的一种更整洁的方式。具体使用的方法将完全取决于你的喜好与程序类型。

测试代码
#import "HeightDataSubViewController.h"
#import "SphereManager.h"
#import "DefaultBindObject.h"
@interface HeightDataSubViewController ()
@property (nonatomic ,strong) Vertex * heightVertex ;
@end

@implementation HeightDataSubViewController

-(void)loadVertex{
    self.heightVertex = [Vertex new];
    int vertexNum =[SphereManager getVertexNum];
    [self.heightVertex allocVertexNum:vertexNum andEachVertexNum:5];
    [self.heightVertex bindBufferWithUsage:GL_STATIC_DRAW];
    [self.heightVertex writeBufferInOffset:0 dataSize:sizeof(GL_FLOAT)* 3*vertexNum Data:[SphereManager getSphereVerts]];
    [self.heightVertex writeBufferInOffset:sizeof(GL_FLOAT)*3*vertexNum dataSize:sizeof(GL_FLOAT)*2*vertexNum Data:[SphereManager getSphereTexCoords]];
    [self.heightVertex enableVertexInVertexAttrib:DF_aPos numberOfCoordinates:3 attribOffset:0 vertexWidth:3*sizeof(GL_FLOAT)];
    [self.heightVertex enableVertexInVertexAttrib:DF_aTexCoords numberOfCoordinates:2 attribOffset:sizeof(GL_FLOAT)*3*vertexNum vertexWidth:2*sizeof(GLfloat)];
}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glClearColor(1, 1, 1, 1);
    GLKMatrix4  mvp= [self getMVP];
    static GLfloat angle=0;
    angle++;
    GLKMatrix4 mode =GLKMatrix4MakeRotation(angle*M_PI/180, 0, 1, 0);
    GLKMatrix4 result=  GLKMatrix4Multiply(mvp,mode);
    glUniformMatrix4fv(self.bindObject->uniforms[DF_uniform_MVPMatrix], 1, 0,result.m);
    GLKVector4 ambientLight = GLKVector4Make(1.0, 1, 1, 1.0);
    glUniform4fv(self.bindObject->uniforms[DF_uniform_AmbientLight], 1,ambientLight.v);
    [self.textureUnit0 bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DF_uniform_Samplers2D]];
    
    [self.heightVertex drawVertexWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:[SphereManager getVertexNum]];

@end

结果如下


获取buffer指针赋值法

将数据导入缓冲的另外一种方法是,请求缓冲内存的指针,直接将数据复制到缓冲当中。通过调用glMapBuffer函数,OpenGL会返回当前绑定缓冲的内存指针,供我们操作:

  glBindBuffer(GL_ARRAY_BUFFER,
                 self.vertexBuffers);
   glBindBuffer(GL_ARRAY_BUFFER,
                     self.vertexBuffers);
        void *ptr = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
        memcpy(ptr, self.vertex, self.getAllocSpaceByteNum);
        glUnmapBufferOES(GL_ARRAY_BUFFER);

当我们使用glUnmapBuffer函数,告诉OpenGL我们已经完成指针操作之后,OpenGL就会知道你已经完成了。在解除映射(Unmapping)之后,指针将会不再可用,并且如果OpenGL能够成功将您的数据映射到缓冲中,这个函数将会返回GL_TRUE。

如果要直接映射数据到缓冲,而不事先将其存储到临时内存中,glMapBuffer这个函数会很有用。比如说,你可以从文件中读取数据,并直接将它们复制到缓冲内存中。

关键代码
#import "HeightDataViewController.h"
#import "SphereManager.h"
#import "DefaultBindObject.h"

@interface HeightDataViewController ()

@end

@implementation HeightDataViewController

-(void)loadVertex{

    self.vertexPostion= [Vertex new];
    int vertexNum =[SphereManager getVertexNum];
    [self.vertexPostion allocVertexNum:vertexNum andEachVertexNum:3];
    [self.vertexPostion bindBufferWithUsage:GL_STATIC_DRAW];

    for (int i=0; i<vertexNum; i++) {
        float onevertex[3];
        for (int j=0; j<3; j++) {
            onevertex[j]=[SphereManager getSphereVerts][i*3+j];
        }
        [self.vertexPostion setVertex:onevertex index:i];
    }
    [self.vertexPostion writeBufferData];
    [self.vertexPostion enableVertexInVertexAttrib:DF_aPos numberOfCoordinates:3 attribOffset:0];
    
    self.vertexTexture = [Vertex new];
    [self.vertexTexture allocVertexNum:vertexNum andEachVertexNum:2];
    [self.vertexTexture bindBufferWithUsage:GL_STATIC_DRAW];
    for (int i=0; i<vertexNum; i++) {
        float onevertex[2];
        for (int j=0; j<2; j++) {
            onevertex[j]=[SphereManager getSphereTexCoords][i*2+j];
        }
        [self.vertexTexture setVertex:onevertex index:i];
    }
    [self.vertexTexture writeBufferData];
    [self.vertexTexture enableVertexInVertexAttrib:DF_aTexCoords numberOfCoordinates:2 attribOffset:0];
}

@end

结果如下


vertex核心代码如下

#import "Vertex.h"

@interface Vertex()

@property (nonatomic ,assign)   GLfloat  *vertex; ;
@property (nonatomic ,assign) GLsizei vertexNum ;
@property (nonatomic ,assign) GLsizei eachVertexNum ;
@property (nonatomic, assign) GLuint vertexBuffers;
@property (nonatomic ,assign) GLenum usage ;
@end

@implementation Vertex

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self _customInit];
    }
    return self;
}

-(void)_customInit{
     glGenBuffers(1, &_vertexBuffers);
}

-(NSInteger)getAllocSpaceByteNum{
    return self.getVertexWidth*self.vertexNum;
}
-(GLsizei)getVertexWidth{
    return sizeof(GLfloat) * self.eachVertexNum;
}

-(void)allocVertexNum:(GLsizei)vertexNum andEachVertexNum:(GLsizei)eachVertexNum{
    [self releaseVertex];
    self.vertexNum = vertexNum;
    self.eachVertexNum = eachVertexNum;
     self.vertex =(GLfloat*)malloc(self.getAllocSpaceByteNum);
    memset( self.vertex, 0,  self.getAllocSpaceByteNum);
}

-(void)setVertex:(GLfloat *)vertex index:(NSInteger)index{
    if (self.vertex) {
        NSInteger offset = index * self.eachVertexNum;
        for (NSInteger i = 0; i<self.eachVertexNum; i++) {
             self.vertex[offset+i] = vertex[I];
        }
    }else{
        NSLog(@"顶点没有空间");
    }
}

-(void)releaseVertex{
    if (self.vertex) {
        free( self.vertex);
         self.vertex = NULL;
    }
}

-(void)bindBufferWithUsage: (GLenum) usage{
    if (!self.vertexBuffers) {
        [self _customInit];
    }
    glBindBuffer(GL_ARRAY_BUFFER,
                 self.vertexBuffers);
    glBufferData( GL_ARRAY_BUFFER,
                 self.getAllocSpaceByteNum,
                 self.vertex,
                 usage);
    
}

///通过指针设置buffer数据
-(void)writeBufferData{
    glBindBuffer(GL_ARRAY_BUFFER,
                 self.vertexBuffers);
        glBindBuffer(GL_ARRAY_BUFFER,
                     self.vertexBuffers);
        void *ptr = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
        memcpy(ptr, self.vertex, self.getAllocSpaceByteNum);
        glUnmapBufferOES(GL_ARRAY_BUFFER);

}

-(void)writeBufferInOffset:(int)offset dataSize:(float)size Data:(void*)ptr{
    glBindBuffer(GL_ARRAY_BUFFER,
                 self.vertexBuffers);
    glBufferSubData(GL_ARRAY_BUFFER, offset, size, ptr);
}

-(void)enableVertexInVertexAttrib:(GLuint)index  numberOfCoordinates:(GLint)count attribOffset:(GLsizeiptr)offset vertexWidth:(GLsizei)width{
    glBindBuffer(GL_ARRAY_BUFFER,
                 self.vertexBuffers);
    glEnableVertexAttribArray(index);
    glVertexAttribPointer(index,               // Identifies the attribute to use
                          count,               // number of coordinates for attribute
                          GL_FLOAT,            // data is floating point
                          GL_FALSE,            // no fixed point scaling
                          width ,         // total num bytes stored per vertex
                          NULL + offset);
#ifdef DEBUG
    {  // Report any errors
        GLenum error = glGetError();
        if(GL_NO_ERROR != error)
        {
            NSLog(@"[GL Error]: enableVertex  0x%x", error);
        }
    }
    //    GL_INVALID_OPERATION  operation;
    //    GL_INVALID_VALUE
#endif
}

-(void)enableVertexInVertexAttrib:(GLuint)index  numberOfCoordinates:(GLint)count attribOffset:(GLsizeiptr)offset{
    [self enableVertexInVertexAttrib:index numberOfCoordinates:count attribOffset:offset vertexWidth:[self getVertexWidth]];
}


-(void)drawVertexWithMode:(GLenum)mode  startVertexIndex:(GLint)first
         numberOfVertices:(GLsizei)count {
    NSAssert([self getAllocSpaceByteNum] >=
             ((first + count) *sizeof(GLfloat) * self.eachVertexNum),
             @"Attempt to draw more vertex data than available.");
    glBindBuffer(GL_ARRAY_BUFFER,
                 self.vertexBuffers);
     glDrawArrays(mode, first, count);
}

- (void)dealloc
{
    [self releaseVertex];
}

@end

glsl的函数使用

gl_PointSize

我们已经见过gl_Position了,它是顶点着色器的裁剪空间输出位置向量。如果你想在屏幕上显示任何东西,在顶点着色器中设置gl_Position是必须的步骤。这已经是它的全部功能了。

但是有时候我们需要绘制一个点.即我们能够选用的其中一个图元是GL_POINTS,如果使用它的话,每一个顶点都是一个图元,都会被渲染为一个点。可是单纯一个点在屏幕上是没啥意义了,只有赋予了大小才可见.因此我们可以通过OpenGL的glPointSize函数来设置渲染出来的点的大小,但我们也可以在顶点着色器中修改这个值。

GLSL定义了一个叫做gl_PointSize输出变量,它是一个float变量,你可以使用它来设置点的宽高(像素)。在顶点着色器中修改点的大小的话,你就能对每个顶点设置不同的值了。

一个简单的例子就是将点的大小设置为裁剪空间位置的z值,也就是顶点距观察者的距离。点的大小会随着观察者距顶点距离变远而增大。

attribute vec3 beginPostion; ///开始位置
uniform mat4 u_mvpMatrix;

void main(){
    gl_Position =u_mvpMatrix * vec4(beginPostion, 1.0);
    gl_PointSize =300.0/gl_Position.z;

}

结果如图

测试代码如下


#import "GLPointViewController.h"
#import "GLPointBindObject.h"
@interface GLPointViewController ()
@property (nonatomic ,strong) Vertex * vertex ;

@end

@implementation GLPointViewController

-(void)initSubObject{
    self.bindObject = [GLPointBindObject new];
}


-(void)loadVertex{
    self.vertex= [Vertex new];
    int vertexNum =1;
    [self.vertex allocVertexNum:vertexNum andEachVertexNum:3];
    float onevertex[3];
    for (int i=0; i<3; i++) {
        onevertex[i]=0;
    }
    [self.vertex setVertex:onevertex index:0];
    [self.vertex bindBufferWithUsage:GL_STATIC_DRAW];
    [self.vertex enableVertexInVertexAttrib:PT_aPos numberOfCoordinates:3 attribOffset:0];
}

-(GLKMatrix4)getMVP{
    GLfloat aspectRatio= CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds);
    GLKMatrix4 projectionMatrix =
    GLKMatrix4MakePerspective(
                              GLKMathDegreesToRadians(85.0f),
                              aspectRatio,
                              0.1f,
                              20.0f);
    GLKMatrix4 modelviewMatrix =
    GLKMatrix4MakeLookAt(
                         0.0, 0.0, 3.0,   // Eye position
                         0.0, 0.0, 0.0,   // Look-at position
                         0.0, 1.0, 0.0);  // Up direction
    return GLKMatrix4Multiply(projectionMatrix,modelviewMatrix);
}


-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(1, 1, 1, 1);
    GLKMatrix4  mvp= [self getMVP];
    static GLfloat width = 2;
    static GLfloat angle=0;
    angle+=0.1;
    GLfloat z = width* sin(angle);
    GLKMatrix4 mode =GLKMatrix4Translate(mvp, 0, 0, z);
    GLKMatrix4 result=  GLKMatrix4Multiply(mvp,mode);
    glUniformMatrix4fv(self.bindObject->uniforms[PT_uniform_MVPMatrix], 1, 0,result.m);
    [self.vertex drawVertexWithMode:GL_POINTS startVertexIndex:0 numberOfVertices:1];
}
@end

gl_FragCoord

在讨论深度测试的时候,我们已经见过gl_FragCoord很多次了,因为gl_FragCoord的z分量等于对应片段的深度值。然而,我们也能使用它的x和y分量来实现一些有趣的效果。

gl_FragCoord的x和y分量是片段的窗口空间(Window-space)坐标,其原点为窗口的左下角。x y 的取值是与我们设定屏幕像素的大小.在ios中默认是全屏

通过利用片段着色器,我们可以根据片段的窗口坐标,计算出不同的颜色。gl_FragCoord的一个常见用处是用于对比不同片段计算的视觉输出效果,这在技术演示中可以经常看到。比如说,我们能够将屏幕分成两部分,在窗口的左侧渲染一种输出,在窗口的右侧渲染另一种输出。下面这个例子片段着色器会根据窗口坐标输出不同的颜色:

precision mediump float;
uniform float screenWidth;

void main()
{
    if(gl_FragCoord.x < screenWidth/2.0)
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    else
        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}

这里我们绘制了一个旋转的正方体

测试代码如下

#import "GLFragCoordViewController.h"
#import "GLFragCoordBindObject.h"
#import "CubeManager.h"

@interface GLFragCoordViewController ()
@property (nonatomic ,strong) Vertex * vertex;

@end

@implementation GLFragCoordViewController
-(void)initSubObject{
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    self.bindObject = [GLFragCoordBindObject new];
}


-(void)loadVertex{
    self.vertex= [Vertex new];
    int vertexNum =[CubeManager getTextureNormalVertexNum];
    [self.vertex allocVertexNum:vertexNum andEachVertexNum:3];
    for (int i=0; i<vertexNum; i++) {
        float onevertex[3];
        for (int j=0; j<3; j++) {
            onevertex[j]=[CubeManager getTextureNormalVertexs][i*8+j];
        }
        [self.vertex setVertex:onevertex index:i];
    }
    [self.vertex bindBufferWithUsage:GL_STATIC_DRAW];
}

-(void)_bindViewMatrix4:(GLBaseBindObject*)bindObject{
    GLKMatrix4 viewMatrix =
    GLKMatrix4MakeLookAt(
                         0.0, 0.0, 3.0,   // Eye position
                         0.0, 0.0, 0.0,   // Look-at position
                         0.0, 1.0, 0.0);  // Up direction
    glUniformMatrix4fv(bindObject->uniforms[FC_uniform_view], 1, 0,viewMatrix.m);
}
-(void)_bindProjectionMatrix4:(GLBaseBindObject*)bindObject{
    GLfloat aspectRatio= CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds);
    GLKMatrix4 projectionMatrix =
    GLKMatrix4MakePerspective(
                              GLKMathDegreesToRadians(100.0f),
                              aspectRatio,
                              0.1f,
                              100.0f);
    glUniformMatrix4fv(bindObject->uniforms[FC_uniform_projection], 1, 0,projectionMatrix.m);
}


-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    
    /// 模板测试虽然开启了. 但是不起作用.
    
    glClearStencil(0);
    glClearColor(1,1, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    GLKMatrix4 cubeMode1 =[self _getModeMatrix4Location:GLKVector3Make(0.0f, 0.0f, 1.0f)];
    static CGFloat angle = 0;
    angle++;
    cubeMode1 = GLKMatrix4Rotate(cubeMode1, angle*M_PI/180.0, 0, 1, 0);
    [self.shader use];
    [self _bindViewMatrix4:self.bindObject];
    [self _bindProjectionMatrix4:self.bindObject];

    [self _drawCubeMode:cubeMode1 bindObject:self.bindObject];
    
}

-(GLKMatrix4)_getModeMatrix4Location:(GLKVector3)location{
    GLKMatrix4  mode = GLKMatrix4Identity;
    mode =  GLKMatrix4TranslateWithVector3(mode, location);
    //    mode = GLKMatrix4Rotate(mode, 30*M_PI/180.0, 0, 1, 0);
    return mode;
}

-(void)_drawCubeMode:(GLKMatrix4)mode bindObject:(GLBaseBindObject*)bindObject{
    
    glUniformMatrix4fv(bindObject->uniforms[FC_uniform_model], 1, 0,mode.m);
    glUniform1f(bindObject->uniforms[FC_uniform_screenWidth], UIScreen.mainScreen.bounds.size.width*UIScreen.mainScreen.scale);
    [self.vertex enableVertexInVertexAttrib:FC_aPos numberOfCoordinates:3 attribOffset:0];
    [self.vertex drawVertexWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:[CubeManager getTextureNormalVertexNum]];
}

@end


本章主要就是讲究几个函数的使用.这里简单的贴下代码.代码不全,读者可以下载demo 观看



参考地址2
参考地址1
OpenGLZeroStudyDemo(15)-高级Opengl-高级数据和高级glsl

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容