[jimmyzhouj 翻译] Nehe iOS OpenGL ES 2.0教程
使用OpenGL将几何图形(geometry)绘制到屏幕上需要完成几个步骤。首先我们需要告诉OpenGL绘制什么几何图形。通常是一系列的三角形,每个三角形用三个顶点来指定。OpenGL为每个顶点调用顶点着色器(vertex shader),它可以通过旋转和移动来执行几何变换,或者是简单的光照(lighting)。得到的平面被光栅化(rasterized),意思是OpenGL会计算出被各平面覆盖的所有像素点。对每一个被覆盖的像素点,OpenGL会调用片段着色器(fragment shader,如果我们使用多重抽样,每个像素会运行不止一次,所以总的来说这是片段而不是像素)。片段着色器的任务是根据颜色,光照来决定片段的颜色,或者是将图像映射到几何图形上。
几何图形可以被指定为几种几何图元:GL_POINT, GL_LINES或者GL_TRIANGLES,其中直线和三角形都有一些变体,可以绘制chain的或者strip的。所有这些几何图元都是由一组顶点组成的。一个顶点是三维空间的一个点,参照坐标系是x轴指向正右方,y轴指向正上方,z轴垂直于屏幕指向读者。
- //create a triangle
- std::vector<float> geometryData;
- //4 floats define one vertex (x, y, z and w), first one is lower left
- geometryData.push_back(-0.5); geometryData.push_back(-0.5); geometryData.push_back(0.0); geometryData.push_back(1.0);
- //we go counter clockwise, so lower right vertex next
- geometryData.push_back( 0.5); geometryData.push_back(-0.5); geometryData.push_back(0.0); geometryData.push_back(1.0);
- //top vertex is last
- geometryData.push_back( 0.0); geometryData.push_back( 0.5); geometryData.push_back(0.0); geometryData.push_back(1.0);
- //generate an ID for our geometry buffer in the video memory and make it the active one
- glGenBuffers(1, &m_geometryBuffer);
- glBindBuffer(GL_ARRAY_BUFFER, m_geometryBuffer);
- //send the data to the video memory
- glBufferData(GL_ARRAY_BUFFER, geometryData.size() * sizeof(float), &geometryData[0], GL_STATIC_DRAW);
- //create a color buffer, to make our triangle look pretty
- std::vector<float> colorData;
- //3 floats define one color value (red, green and blue) with 0 no intensity and 1 full intensity
- //each color triplet is assigned to the vertex at the same position in the buffer, so first color -> first vertex
- //first vertex is red
- colorData.push_back(1.0); colorData.push_back(0.0); colorData.push_back(0.0);
- //lower right vertex is green
- colorData.push_back(0.0); colorData.push_back(1.0); colorData.push_back(0.0);
- //top vertex is blue
- colorData.push_back(0.0); colorData.push_back(0.0); colorData.push_back(1.0);
- //generate an ID for the color buffer in the video memory and make it the active one
- glGenBuffers(1, &m_colorBuffer);
- glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
- //send the data to the video memory
- glBufferData(GL_ARRAY_BUFFER, colorData.size() * sizeof(float), &colorData[0], GL_STATIC_DRAW);
- //load our shader
- m_shader = new Shader("shader.vert", "shader.frag");
- if(!m_shader->compileAndLink())
- {
- NSLog(@"Encountered problems when loading shader, application will crash...");
- }
- //tell OpenGL to use this shader for all coming rendering
- glUseProgram(m_shader->getProgram());
- //get the attachment points for the attributes position and color
- m_positionLocation = glGetAttribLocation(m_shader->getProgram(), "position");
- m_colorLocation = glGetAttribLocation(m_shader->getProgram(), "color");
- //check that the locations are valid, negative value means invalid
- if(m_positionLocation < 0 || m_colorLocation < 0)
- {
- NSLog(@"Could not query attribute locations");
- }
- //enable these attributes
- glEnableVertexAttribArray(m_positionLocation);
- glEnableVertexAttribArray(m_colorLocation);
- //bind the geometry VBO
- glBindBuffer(GL_ARRAY_BUFFER, m_geometryBuffer);
- //point the position attribute to this buffer, being tuples of 4 floats for each vertex
- glVertexAttribPointer(m_positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
- //bint the color VBO
- glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
- //this attribute is only 3 floats per vertex
- glVertexAttribPointer(m_colorLocation, 3, GL_FLOAT, GL_FALSE, 0, NULL);
- //initiate the drawing process, we want a triangle, start at index 0 and draw 3 vertices
- glDrawArrays(GL_TRIANGLES, 0, 3);
函数glDrawArrays需要三个参数:我们要画的图元(可以是GL_POINTS,GL_LINE_STRIP,GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES之一),离缓冲区首个元素的偏移量,和需要画多少个顶点。
OpenGL Shading Language
- //the incoming vertex' position
- attribute vec4 position;
- //and its color
- attribute vec3 color;
- //the varying statement tells the shader pipeline that this variable
- //has to be passed on to the next stage (so the fragment shader)
- varying lowp vec3 colorVarying;
- //the shader entry point is the main method
- void main()
- {
- colorVarying = color; //save the color for the fragment shader
- gl_Position = position; //copy the position
- }
- //incoming values from the vertex shader stage.
- //if the vertices of a primitive have different values, they are interpolated!
- varying lowp vec3 colorVarying;
- void main()
- {
- //create a vec4 from the vec3 by padding a 1.0 for alpha
- //and assign that color to be this fragment's color
- gl_FragColor = vec4(colorVarying, 1.0);
- }