本章主要講解內(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