code sample fixes reviewed separately, see Change-Id: I1d760b75d1f2bfe1ec90c71471867577bd146241 fixing bugs: b/10798358 b/10796990 b/10603728 b/7962328 Change-Id: I1e0f6668ec8d2b103b88c385f1f067d30ecc7178
195 lines
7.2 KiB
Plaintext
195 lines
7.2 KiB
Plaintext
page.title=Drawing Shapes
|
||
parent.title=Displaying Graphics with OpenGL ES
|
||
parent.link=index.html
|
||
|
||
trainingnavtop=true
|
||
previous.title=Defining Shapes
|
||
previous.link=environment.html
|
||
next.title=Applying Projection and Camera Views
|
||
next.link=projection.html
|
||
|
||
@jd:body
|
||
|
||
<div id="tb-wrapper">
|
||
<div id="tb">
|
||
|
||
<h2>This lesson teaches you to</h2>
|
||
<ol>
|
||
<li><a href="#initialize">Initialize Shapes</a></li>
|
||
<li><a href="#draw">Draw a Shape</a></li>
|
||
</ol>
|
||
|
||
<h2>You should also read</h2>
|
||
<ul>
|
||
<li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a></li>
|
||
</ul>
|
||
|
||
<div class="download-box">
|
||
<a href="{@docRoot}shareables/training/OpenGLES.zip"
|
||
class="button">Download the sample</a>
|
||
<p class="filename">OpenGLES.zip</p>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<p>After you define shapes to be drawn with OpenGL, you probably want to draw them. Drawing shapes
|
||
with the OpenGL ES 2.0 takes a bit more code than you might imagine, because the API provides a
|
||
great deal of control over the graphics rendering pipeline.</p>
|
||
|
||
<p>This lesson explains how to draw the shapes you defined in the previous lesson using the OpenGL
|
||
ES 2.0 API.</p>
|
||
|
||
|
||
<h2 id="initialize">Initialize Shapes</h2>
|
||
|
||
<p>Before you do any drawing, you must initialize and load the shapes you plan to draw. Unless the
|
||
structure (the original coordinates) of the shapes you use in your program change during the course
|
||
of execution, you should initialize them in the {@link
|
||
android.opengl.GLSurfaceView.Renderer#onSurfaceCreated onSurfaceCreated()} method of your renderer
|
||
for memory and processing efficiency.</p>
|
||
|
||
<pre>
|
||
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
|
||
...
|
||
|
||
// initialize a triangle
|
||
mTriangle = new Triangle();
|
||
// initialize a square
|
||
mSquare = new Square();
|
||
}
|
||
</pre>
|
||
|
||
|
||
<h2 id="draw">Draw a Shape</h2>
|
||
|
||
<p>Drawing a defined shape using OpenGL ES 2.0 requires a significant amount of code, because you
|
||
must provide a lot of details to the graphics rendering pipeline. Specifically, you must define the
|
||
following:</p>
|
||
|
||
<ul>
|
||
<li><em>Vertex Shader</em> - OpenGL ES graphics code for rendering the vertices of a shape.</li>
|
||
<li><em>Fragment Shader</em> - OpenGL ES code for rendering the face of a shape with colors or
|
||
textures.</li>
|
||
<li><em>Program</em> - An OpenGL ES object that contains the shaders you want to use for drawing
|
||
one or more shapes.</li>
|
||
</ul>
|
||
|
||
<p>You need at least one vertex shader to draw a shape and one fragment shader to color that shape.
|
||
These shaders must be complied and then added to an OpenGL ES program, which is then used to draw
|
||
the shape. Here is an example of how to define basic shaders you can use to draw a shape:</p>
|
||
|
||
<pre>
|
||
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;" +
|
||
"}";
|
||
</pre>
|
||
|
||
<p>Shaders contain OpenGL Shading Language (GLSL) code that must be compiled prior to using it in
|
||
the OpenGL ES environment. To compile this code, create a utility method in your renderer class:</p>
|
||
|
||
<pre>
|
||
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;
|
||
}
|
||
</pre>
|
||
|
||
<p>In order to draw your shape, you must compile the shader code, add them to a OpenGL ES program
|
||
object and then link the program. Do this in your drawn object’s constructor, so it is only done
|
||
once.</p>
|
||
|
||
<p class="note"><strong>Note:</strong> Compiling OpenGL ES shaders and linking programs is expensive
|
||
in terms of CPU cycles and processing time, so you should avoid doing this more than once. If you do
|
||
not know the content of your shaders at runtime, you should build your code such that they only
|
||
get created once and then cached for later use.</p>
|
||
|
||
<pre>
|
||
public class Triangle() {
|
||
...
|
||
|
||
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
|
||
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
|
||
|
||
mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
|
||
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
|
||
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
|
||
GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables
|
||
}
|
||
</pre>
|
||
|
||
<p>At this point, you are ready to add the actual calls that draw your shape. Drawing shapes with
|
||
OpenGL ES requires that you specify several parameters to tell the rendering pipeline what you want
|
||
to draw and how to draw it. Since drawing options can vary by shape, it's a good idea to have your
|
||
shape classes contain their own drawing logic.</p>
|
||
|
||
<p>Create a {@code draw()} method for drawing the shape. This code sets the position and
|
||
color values to the shape’s vertex shader and fragment shader, and then executes the drawing
|
||
function.</p>
|
||
|
||
<pre>
|
||
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);
|
||
}
|
||
</pre>
|
||
|
||
<p>Once you have all this code in place, drawing this object just requires a call to the
|
||
{@code draw()} method from within your renderer’s {@link
|
||
android.opengl.GLSurfaceView.Renderer#onDrawFrame onDrawFrame()} method. When you run the
|
||
application, it should look something like this:</p>
|
||
|
||
<img src="{@docRoot}images/opengl/ogl-triangle.png">
|
||
<p class="img-caption">
|
||
<strong>Figure 1.</strong> Triangle drawn without a projection or camera view.</p>
|
||
|
||
<p>There are a few problems with this code example. First of all, it is not going to impress your
|
||
friends. Secondly, the triangle is a bit squashed and changes shape when you change the screen
|
||
orientation of the device. The reason the shape is skewed is due to the fact that the object’s
|
||
vertices have not been corrected for the proportions of the screen area where the {@link
|
||
android.opengl.GLSurfaceView} is displayed. You can fix that problem using a projection and camera
|
||
view in the next lesson.</p>
|
||
|
||
<p>Lastly, the triangle is stationary, which is a bit boring. In the <a href="motion.html">Adding
|
||
Motion</a> lesson, you make this shape rotate and make more interesting use of the OpenGL ES
|
||
graphics pipeline.</p> |