重新自學(xué)學(xué)習(xí)openGL 之高級(jí)數(shù)據(jù)和高級(jí)glsl

本章主要講解內(nèi)容如下

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

數(shù)據(jù)填充的三種方式

正常填充

到目前為止瘤运,我們一直是調(diào)用glBufferData函數(shù)來填充緩沖對(duì)象所管理的內(nèi)存,這個(gè)函數(shù)會(huì)分配一塊內(nèi)存澡绩,并將數(shù)據(jù)添加到這塊內(nèi)存中。
我們一般這樣用

 glGenBuffers(1, &_vertexBuffers);
  glBindBuffer(GL_ARRAY_BUFFER,
                 self.vertexBuffers);
    glBufferData( GL_ARRAY_BUFFER,
                 self.getAllocSpaceByteNum,
                 self.vertex,       ///buffer中已經(jīng)存在數(shù)據(jù)了
                 usage);

這是我們經(jīng)常使用的填充方式,一次性填充好

關(guān)鍵測(cè)試代碼

我們用正常填充的關(guān)鍵測(cè)試代碼如下

#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

結(jié)果如下


分批填充

除了使用一次函數(shù)調(diào)用填充整個(gè)緩沖之外贴浙,我們也可以使用glBufferSubData杆逗,填充緩沖的特定區(qū)域。這個(gè)函數(shù)需要一個(gè)緩沖目標(biāo)珠插、一個(gè)偏移量食店、數(shù)據(jù)的大小和數(shù)據(jù)本身作為它的參數(shù)渣淤。這個(gè)函數(shù)不同的地方在于,我們可以提供一個(gè)偏移量吉嫩,指定從何處開始填充這個(gè)緩沖价认。這能夠讓我們插入或者更新緩沖內(nèi)存的某一部分。要注意的是自娩,緩沖需要有足夠的已分配內(nèi)存用踩,所以對(duì)一個(gè)緩沖調(diào)用glBufferSubData之前必須要先調(diào)用glBufferData。

GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
參數(shù)介紹
target 需要填充的緩沖區(qū)域
offset 緩沖區(qū)的偏移量
size 需要填充緩沖區(qū)的大小 填充在緩沖區(qū)位置是是 offset+size
data 需要填充的數(shù)據(jù)

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

因?yàn)榭梢苑峙鷮懭?因?yàn)閷?duì)填充數(shù)據(jù)具有更高的靈活性.
其實(shí)一次填充也可以完成上述操作的.只不過需要提前把需要填充的數(shù)據(jù)組織好

使用該方案,一般是需要分批填充頂點(diǎn)屬性使用的

分批頂點(diǎn)屬性

通過使用glVertexAttribPointer忙迁,我們能夠指定頂點(diǎn)數(shù)組緩沖內(nèi)容的屬性布局脐彩。在頂點(diǎn)數(shù)組緩沖中,我們對(duì)屬性進(jìn)行了交錯(cuò)(Interleave)處理姊扔,也就是說惠奸,我們將每一個(gè)頂點(diǎn)的位置、發(fā)現(xiàn)和/或紋理坐標(biāo)緊密放置在一起恰梢。既然我們現(xiàn)在已經(jīng)對(duì)緩沖有了更多的了解佛南,我們可以采取另一種方式梗掰。

我們可以做的是,將每一種屬性類型的向量數(shù)據(jù)打包(Batch)為一個(gè)大的區(qū)塊嗅回,而不是對(duì)它們進(jìn)行交錯(cuò)儲(chǔ)存及穗。與交錯(cuò)布局123123123123不同,我們將采用分批(Batched)的方式111122223333妈拌。
當(dāng)從文件中加載頂點(diǎn)數(shù)據(jù)的時(shí)候拥坛,你通常獲取到的是一個(gè)位置數(shù)組蓬蝶、一個(gè)法線數(shù)組和/或一個(gè)紋理坐標(biāo)數(shù)組尘分。我們需要花點(diǎn)力氣才能將這些數(shù)組轉(zhuǎn)化為一個(gè)大的交錯(cuò)數(shù)據(jù)數(shù)組。使用分批的方式會(huì)是更簡(jiǎn)單的解決方案丸氛,我們可以很容易使用glBufferSubData函數(shù)實(shí)現(xiàn):

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);

這樣子我們就能直接將屬性數(shù)組作為一個(gè)整體傳遞給緩沖培愁,而不需要事先處理它們了。我們?nèi)钥梢詫⑺鼈兒喜橐粋€(gè)大的數(shù)組缓窜,再使用glBufferData來填充緩沖定续,但對(duì)于這種工作,使用glBufferSubData會(huì)更合適一點(diǎn)禾锤。

我們還需要更新頂點(diǎn)屬性指針來反映這些改變:

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參數(shù)等于頂點(diǎn)屬性的大小私股,因?yàn)橄乱粋€(gè)頂點(diǎn)屬性向量能在3個(gè)(或2個(gè))分量之后找到。

這給了我們?cè)O(shè)置頂點(diǎn)屬性的另一種方法恩掷。使用哪種方法都不會(huì)對(duì)OpenGL有什么立刻的好處倡鲸,它只是設(shè)置頂點(diǎn)屬性的一種更整潔的方式。具體使用的方法將完全取決于你的喜好與程序類型黄娘。

測(cè)試代碼
#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

結(jié)果如下


獲取buffer指針賦值法

將數(shù)據(jù)導(dǎo)入緩沖的另外一種方法是峭状,請(qǐng)求緩沖內(nèi)存的指針,直接將數(shù)據(jù)復(fù)制到緩沖當(dāng)中逼争。通過調(diào)用glMapBuffer函數(shù)优床,OpenGL會(huì)返回當(dāng)前綁定緩沖的內(nèi)存指針,供我們操作:

  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);

當(dāng)我們使用glUnmapBuffer函數(shù)誓焦,告訴OpenGL我們已經(jīng)完成指針操作之后胆敞,OpenGL就會(huì)知道你已經(jīng)完成了。在解除映射(Unmapping)之后杂伟,指針將會(huì)不再可用移层,并且如果OpenGL能夠成功將您的數(shù)據(jù)映射到緩沖中,這個(gè)函數(shù)將會(huì)返回GL_TRUE稿壁。

如果要直接映射數(shù)據(jù)到緩沖幽钢,而不事先將其存儲(chǔ)到臨時(shí)內(nèi)存中,glMapBuffer這個(gè)函數(shù)會(huì)很有用傅是。比如說匪燕,你可以從文件中讀取數(shù)據(jù)蕾羊,并直接將它們復(fù)制到緩沖內(nèi)存中。

關(guān)鍵代碼
#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

結(jié)果如下


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(@"頂點(diǎn)沒有空間");
    }
}

-(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);
    
}

///通過指針設(shè)置buffer數(shù)據(jù)
-(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的函數(shù)使用

gl_PointSize

我們已經(jīng)見過gl_Position了帽驯,它是頂點(diǎn)著色器的裁剪空間輸出位置向量龟再。如果你想在屏幕上顯示任何東西,在頂點(diǎn)著色器中設(shè)置gl_Position是必須的步驟尼变。這已經(jīng)是它的全部功能了利凑。

但是有時(shí)候我們需要繪制一個(gè)點(diǎn).即我們能夠選用的其中一個(gè)圖元是GL_POINTS,如果使用它的話嫌术,每一個(gè)頂點(diǎn)都是一個(gè)圖元哀澈,都會(huì)被渲染為一個(gè)點(diǎn)《绕可是單純一個(gè)點(diǎn)在屏幕上是沒啥意義了,只有賦予了大小才可見.因此我們可以通過OpenGL的glPointSize函數(shù)來設(shè)置渲染出來的點(diǎn)的大小割按,但我們也可以在頂點(diǎn)著色器中修改這個(gè)值。

GLSL定義了一個(gè)叫做gl_PointSize輸出變量磷籍,它是一個(gè)float變量适荣,你可以使用它來設(shè)置點(diǎn)的寬高(像素)。在頂點(diǎn)著色器中修改點(diǎn)的大小的話院领,你就能對(duì)每個(gè)頂點(diǎn)設(shè)置不同的值了弛矛。

一個(gè)簡(jiǎn)單的例子就是將點(diǎn)的大小設(shè)置為裁剪空間位置的z值,也就是頂點(diǎn)距觀察者的距離比然。點(diǎn)的大小會(huì)隨著觀察者距頂點(diǎn)距離變遠(yuǎn)而增大丈氓。

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

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

}

結(jié)果如圖

測(cè)試代碼如下


#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

在討論深度測(cè)試的時(shí)候,我們已經(jīng)見過gl_FragCoord很多次了谈秫,因?yàn)間l_FragCoord的z分量等于對(duì)應(yīng)片段的深度值扒寄。然而,我們也能使用它的x和y分量來實(shí)現(xiàn)一些有趣的效果拟烫。

gl_FragCoord的x和y分量是片段的窗口空間(Window-space)坐標(biāo)该编,其原點(diǎn)為窗口的左下角。x y 的取值是與我們?cè)O(shè)定屏幕像素的大小.在ios中默認(rèn)是全屏

通過利用片段著色器硕淑,我們可以根據(jù)片段的窗口坐標(biāo)课竣,計(jì)算出不同的顏色。gl_FragCoord的一個(gè)常見用處是用于對(duì)比不同片段計(jì)算的視覺輸出效果置媳,這在技術(shù)演示中可以經(jīng)秤谡粒看到。比如說拇囊,我們能夠?qū)⑵聊环殖蓛刹糠钟厍诖翱诘淖髠?cè)渲染一種輸出,在窗口的右側(cè)渲染另一種輸出寥袭。下面這個(gè)例子片段著色器會(huì)根據(jù)窗口坐標(biāo)輸出不同的顏色:

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);
}

這里我們繪制了一個(gè)旋轉(zhuǎn)的正方體

測(cè)試代碼如下

#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{
    
    /// 模板測(cè)試雖然開啟了. 但是不起作用.
    
    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


本章主要就是講究幾個(gè)函數(shù)的使用.這里簡(jiǎn)單的貼下代碼.代碼不全,讀者可以下載demo 觀看



參考地址2
參考地址1
OpenGLZeroStudyDemo(15)-高級(jí)Opengl-高級(jí)數(shù)據(jù)和高級(jí)glsl

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末路捧,一起剝皮案震驚了整個(gè)濱河市关霸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杰扫,老刑警劉巖队寇,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異章姓,居然都是意外死亡佳遣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門凡伊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來零渐,“玉大人,你說我怎么就攤上這事窗声∠嗍眩” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵笨觅,是天一觀的道長。 經(jīng)常有香客問我耕腾,道長见剩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任扫俺,我火速辦了婚禮苍苞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狼纬。我一直安慰自己羹呵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布疗琉。 她就那樣靜靜地躺著冈欢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盈简。 梳的紋絲不亂的頭發(fā)上凑耻,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音柠贤,去河邊找鬼香浩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛臼勉,可吹牛的內(nèi)容都是我干的邻吭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼宴霸,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼囱晴!你這毒婦竟也來了岸裙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤速缆,失蹤者是張志新(化名)和其女友劉穎降允,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艺糜,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡剧董,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了破停。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翅楼。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖真慢,靈堂內(nèi)的尸體忽然破棺而出毅臊,到底是詐尸還是另有隱情,我是刑警寧澤黑界,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布管嬉,位于F島的核電站,受9級(jí)特大地震影響朗鸠,放射性物質(zhì)發(fā)生泄漏蚯撩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一烛占、第九天 我趴在偏房一處隱蔽的房頂上張望胎挎。 院中可真熱鬧,春花似錦忆家、人聲如沸犹菇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揭芍。三九已至,卻和暖如春蹬竖,著一層夾襖步出監(jiān)牢的瞬間沼沈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國打工币厕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留列另,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓旦装,卻偏偏與公主長得像页衙,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容