在OpenGL ES 2.0中渲染任何几何图形到屏幕中,你必须创造叫着色器的两个小程序。
着色器是写用一种叫做GLSL的类C语言。不用担心在这个点学习这个参考,现在你只要看这个例子在这个教程中。
有两种类型的着色器:
attribute vec4 Position; // 1
attribute vec4 SourceColor; // 2
varying vec4 DestinationColor; // 3
void main(void) { // 4
DestinationColor = SourceColor; // 5
gl_Position = Position; // 6
}
这个 attribute 关键字定义这个着色器将传递进一个叫做Position的输入变量。后面,你将写一些代码传一些数据到输入变量。它将表明这个顶点的位置。注意这个顶点类型是vec4,意味着一个顶点有4个组件。
定义第二个输入变量,是顶点的颜色。
这个定义其他的变量,但是它没有attribute关键字,他是一个输出变量传递给片段着色器。它也有一个varying关键字,像是说“我将告诉你这个特定顶点的值,但是当你给出一个像素计算出这个值,指出这个平滑的值在顶点附近”。
哈?这个最后一点听起来有些迷惑,但是如果你看下面的图片实际上是很好理解的:
基本上,你能为每个像素指定不同的颜色,它将设置所有的值在两个渐变!你将看到一个例子不久。
4.每个着色器用一个main开始,就像C一样。
5.设置这个目的颜色为这个顶点给原颜色。让这个OpenGL修改这个值上面解释的。
6.这个构造输出变量你必须设置在顶点着色器叫gl_Position相等这个最终顶点位置。这里仅仅设置它为原始位置而不改变它最终。 好的,这个是简单的顶点着色器,下面让我们增加简单的片段着色器。 去File\New\New File…, 选择 iOS\Other\Empty,并且点击Next。新文件名字是SimpleFragment.glsl 打开SimpleFragment.glsl并且增加下面的代码:
varying lowp vec4 DestinationColor; // 1
void main(void) { // 2
gl_FragColor = DestinationColor; // 3
}
- (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType {
// 1
NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName
ofType:@"glsl"];
NSError* error;
NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath
encoding:NSUTF8StringEncoding error:&error];
if (!shaderString) {
NSLog(@"Error loading shader: %@", error.localizedDescription);
exit(1);
}
// 2
GLuint shaderHandle = glCreateShader(shaderType);
// 3
const char * shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = [shaderString length];
glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
// 4
glCompileShader(shaderHandle);
// 5
GLint compileSuccess;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@"%@", messageString);
exit(1);
}
return shaderHandle;
}
- (void)compileShaders {
// 1
GLuint vertexShader = [self compileShader:@"SimpleVertex"
withType:GL_VERTEX_SHADER];
GLuint fragmentShader = [self compileShader:@"SimpleFragment"
withType:GL_FRAGMENT_SHADER];
// 2
GLuint programHandle = glCreateProgram();
glAttachShader(programHandle, vertexShader);
glAttachShader(programHandle, fragmentShader);
glLinkProgram(programHandle);
// 3
GLint linkSuccess;
glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@"%@", messageString);
exit(1);
}
// 4
glUseProgram(programHandle);
// 5
_positionSlot = glGetAttribLocation(programHandle, "Position");
_colorSlot = glGetAttribLocation(programHandle, "SourceColor");
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
}
typedef struct {
float Position[3];
float Color[4];
} Vertex;
const Vertex Vertices[] = {
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, 1, 0}, {0, 1, 0, 1}},
{{-1, 1, 0}, {0, 0, 1, 1}},
{{-1, -1, 0}, {0, 0, 0, 1}}
};
const GLubyte Indices[] = {
0, 1, 2,
2, 3, 0
};
- (void)setupVBOs {
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}
- (void)render {
glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// 1
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
// 2
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE,
sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
// 3
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]),
GL_UNSIGNED_BYTE, 0);
[_context presentRenderbuffer:GL_RENDERBUFFER];
}