您的位置:首页 > 运维架构

Displaying Graphics with OpenGL ES(三)——Drawing Shapes

2016-04-15 18:33 411 查看

Drawing Shapes

在用OpenGl定义shapes后,就要画出他们了。画出形状需要大量的代码,因为API提供了强大的图形渲染通道。

1.初始化 Shapes

在你画之前,必须初始化和加载shape。除非执行程序期间改变shapes的构造( 原始坐标),你应该初始化他们在onSurfaceCreate()方法里为了渲染消耗内存和执行效率。

public class MyGLRenderer implements GLSurfaceView.Renderer {

...
private Triangle mTriangle;
private Square   mSquare;

public void onSurfaceCreated(GL10 unused, EGLConfig config) {
...

// initialize a triangle
mTriangle = new Triangle();
// initialize a square
mSquare = new Square();
}
...
}


2.Draw a Shape

通过绘制OpenGL ES 2.0的定义shape需要的代码量较大,因为你必须提供很多细节的图形渲染通道。具体而言,您必须定义如下:

~Vertex Shader:为渲染图形顶点的OpenGL ES图形代码。

~Fragment Shader:渲染shape正面的颜色和纹理的OpenGL ES 代码。

~Program:一个OpenGL ES对象,其中包含要用于绘制一个或多个shapes的着色器。

至少需要一个vertex shader 和 一个fragment shader。这些shaders必须被编译和添加到OpenGL ES program。下面是一个最基本的三角形shaders,你可以在Triangle.class里定义:

public class Triangle {

private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
"  gl_Position = vPosition;" +
"}";

private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
"  gl_FragColor = vColor;" +
"}";

...
}


包含着色器,必须先在OpenGL ES的环境中使用该编译OpenGL着色语言(GLSL)代码。编译这段代码,在你的渲染器类创建一个实用方法:

public static int loadShader(int type, String shaderCode){

// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);

// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);

return shader;
}


为了绘制shape,您必须编译shader代码,将其添加到OpenGL ES的程序对象,然后链接程序。这是绘制的对象的构造函数,所以只进行一次。

Note: 编译的OpenGL ES着色器和链接程序在CPU周期和处理时间方面的代价较大,所以你应该避免做更多的操作在这里。如果你不知道你的着色器在运行时的内容,你应该建立你的代码,他们只获得创建一次,然后缓存以备后用。

public class Triangle() {
...

private final int mProgram;

public Triangle() {
...

int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);

// create empty OpenGL ES Program
mProgram = GLES20.glCreateProgram();

// add the vertex shader to program
GLES20.glAttachShader(mProgram, vertexShader);

// add the fragment shader to program
GLES20.glAttachShader(mProgram, fragmentShader);

// creates OpenGL ES program executables
GLES20.glLinkProgram(mProgram);
}
}


下面,你就可以添加绘制shape的实际调用。绘制形状与OpenGL ES需要您指定几个参数来告诉画什么渲染通道以及如何绘制它。由于绘图选项可以通过形状有所不同,所以在你的形状类包含自己的绘画逻辑是个好想法。

创建绘制形状的draw()方法。此代码设置形状的顶点着色器颜色值和fragment着色器的位置,然后执行绘图功能。

private int mPositionHandle;
private int mColorHandle;

private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

public void draw() {
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);

// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);

// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);

// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);

// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}


一但你有了所有到位的代码,绘制这个对象只需要调用draw()方法从渲染的onDrawFrame()方法里:

public void onDrawFrame(GL10 unused) {
...

mTriangle.draw();
}


然后运行程序,可以看到:



Figure 1. Triangle绘制没有用到Projection或Camera View。

此代码示例的一些问题。首先,它不会打动你的朋友。其次,三角形是有点压扁,并改变形状,当您更改设备的屏幕方向。形状歪斜的原因是由于对象的顶点未针对其中显示GLSurfaceView屏幕区域的比例校正。可以使用在下一章的投影和相机视图解决这个问题。

最后,三角形是固定的,这是一个有点无聊。在Add Motion 章节里,可以使这种形状旋转,做更多有趣的使用的OpenGL ES图形通道。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: