Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Hello.Android.3rd.Edition.pdf
Скачиваний:
39
Добавлен:
02.02.2015
Размер:
3.24 Mб
Скачать

BUILDING A MODEL 206

Version 1.what?

OpenGL ES 1.0 is based on full OpenGL version 1.3, and ES 1.1 is based on OpenGL 1.5. JSR 239 has two versions: the original 1.0 and a maintenance release version 1.0.1. There are also some OpenGL ES extensions that I won’t get into. All versions of Android implement JSR 239 1.0.1, with OpenGL ES 1.0 and some 1.1. For most programs, the JSR standard will suffice, so that’s what we use in this chapter.

Starting with Android 2.2, OpenGL ES 2.0 is supported via the android.opengl package. You can also call it from the Native Development Kit (NDK).OpenGL ES 2.0 is defined relative to the full OpenGL 2.0 specification and emphasizes shaders and programmable 3D pipelines. There is no JSR standard yet for OpenGL ES 2.0, and the programming interface is not backwards compatible with 1.0.

. http://d.android.com/reference/android/opengl/GLES20.html

†. http://d.android.com/sdk/ndk

strange results left over from the depth information for the previous frame. We also set the starting position for the rest of the drawing commands, which will be completed in the next section.

If you run the program now, you get Figure 10.2, on the previous page. If you’re thinking that it’s silly to draw the same black screen over and over again in a loop, you’re right. This will make more sense later when we talk about animation, so just bear with me for now.

Let’s move on and draw something a little more interesting. But first we need to define exactly what we’re drawing (the model).

10.5Building a Model

Depending on the complexity of the objects you want to draw, you will typically create them using a graphical design tool and import them into your program. For the purposes of this example, we’ll just define a simple model in code: a cube.

BUILDING A MODEL 207

 

Download OpenGL/src/org/example/opengl/GLCube.java

Line 1

package org.example.opengl;

-

 

-import java.nio.ByteBuffer;

-import java.nio.ByteOrder; 5 import java.nio.IntBuffer;

-

-import javax.microedition.khronos.opengles.GL10;

-

-import android.content.Context; 10 import android.graphics.Bitmap;

-import android.graphics.BitmapFactory;

-import android.opengl.GLUtils;

-

-class GLCube {

15 private final IntBuffer mVertexBuffer;

-public GLCube() {

-int one = 65536;

-int half = one / 2;

-int vertices[] = {

20

// FRONT

--half, -half, half, half, -half, half,

--half, half, half, half, half, half,

-// BACK

--half, -half, -half, -half, half, -half,

25

half, -half, -half, half, half, -half,

-// LEFT

--half, -half, half, -half, half, half,

--half, -half, -half, -half, half, -half,

-// RIGHT

30

half, -half, -half, half, half, -half,

-half, -half, half, half, half, half,

-// TOP

--half, half, half, half, half, half,

--half, half, -half, half, half, -half,

35

// BOTTOM

--half, -half, half, -half, -half, -half,

-half, -half, half, half, -half, -half, };

-

-// Buffers to be passed to gl*Pointer() functions must be 40 // direct, i.e., they must be placed on the native heap

-// where the garbage collector cannot move them.

-//

-// Buffers with multi-byte data types (e.g., short, int,

-// float) must have their byte order set to native order

45

ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);

 

-

vbb.order(ByteOrder.nativeOrder());

-

mVertexBuffer = vbb.asIntBuffer();

-

mVertexBuffer.put(vertices);

-

mVertexBuffer.position(0);

50

}

-

 

BUILDING A MODEL 208

-public void draw(GL10 gl) {

-gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer);

-

55 gl.glColor4f(1, 1, 1, 1);

-gl.glNormal3f(0, 0, 1);

-gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

-gl.glNormal3f(0, 0, -1);

-gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);

60

-gl.glColor4f(1, 1, 1, 1);

-gl.glNormal3f(-1, 0, 0);

-gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);

-gl.glNormal3f(1, 0, 0);

65 gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);

-

-gl.glColor4f(1, 1, 1, 1);

-gl.glNormal3f(0, 1, 0);

-gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4); 70 gl.glNormal3f(0, -1, 0);

-gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);

-}

-}

The vertices array on line 19 defines the corners of the cube in fixedpoint model coordinates (see the “Fixed vs. Floating Point” sidebar). Each face of a cube is a square, which consists of two triangles. We use a common OpenGL drawing mode called triangle strips. In this mode, we specify two starting points, and then after that every subsequent point defines a triangle with the previous two points. It’s a quick way to get a lot of geometry pumped out to the graphics hardware in a hurry.

Note that each point has three coordinates (x, y, and z). The x- and y-axes point to the right and up, respectively, and the z-axis points out of the screen toward the eye point.

In the draw method (line 52), we use the vertex buffer created in the constructor and draw six different runs of triangles (for the six sides of the cube). In a real program, you would want to combine the calls into one or two strips, because the fewer number of OpenGL calls you make, the faster your program will go.

Now let’s use our new class in GLRenderer:

Download OpenGL/src/org/example/opengl/GLRenderer.java

private final GLCube cube = new GLCube(); public void onDrawFrame(GL10 gl) {

//...

//Draw the model cube.draw(gl);

}

LIGHTS, CAMERA, ... 209

Fixed vs. Floating Point

OpenGL ES provides fixed-point (integer) and floating-point interfaces for all its methods. The fixed-point methods end with the letter x, and the floating-point ones end with the letter f. For example, you can use either glColor4x( ) and glColor4f( ) to set the four components of a color.

A fixed-point number is scaled by 2^16, or 65,536. So, 32,768 in fixed point is equivalent to 0.5f. Put another way, the integral part uses the most significant two bytes of a four-byte int, while the fractional part uses the least significant two bytes. This is quite different from the way the native Android 2D library uses integers, so be careful.

In a simple example like this one, it doesn’t matter whether you use fixed-point or floating-point arithmetic, so I use them interchangeably as convenient. Keep in mind, though, that some Android devices will not have floating-point hardware, so fixed point might be faster. On the other hand, some developers report it’s actually slower than emulated floating point for them. Your mileage may vary.

My advice is to code it first using floating point, because it’s easier to program. Then optimize the slow parts using fixed point later if necessary.

Now if you run the program, you’ll see the exciting image in Figure 10.3, on the following page. Well, it’s more exciting than black.

10.6Lights, Camera, ...

In real life you have light sources such as the sun, headlights, torches, or glowing lava pools. OpenGL lets you define up to eight light sources in your scene. There are two parts to lighting—a light and something to shine it on. Let’s start with the light.

All 3D graphics libraries support three types of lighting:

Ambient: A general glow that the light contributes to the entire scene, even to objects facing away from the light. It’s important to have a little ambient light so you can pick out details even in the shadows.

Diffuse: Soft directional lighting, as you might get from a fluorescent panel. Most of the light contributed to your scene will typically come from diffuse sources.

LIGHTS, CAMERA, ... 210

Figure 10.3: Drawing an unshaded cube

Specular: Shiny light, usually from bright point sources. Combined with shiny materials, this gives you highlights (glints) that add realism.

A single light source can contribute all three types of light. These values go into a lighting equation that determines the color and brightness of each pixel on the screen.

The lighting is defined in the GLRenderer.onSurfaceCreated( ) method:

Download OpenGL/src/org/example/opengl/GLRenderer.java

float lightAmbient[] = new float[] { 0.2f, 0.2f, 0.2f, 1 }; float lightDiffuse[] = new float[] { 1, 1, 1, 1 };

float[] lightPos = new float[] { 1, 1, 1, 1 }; gl.glEnable(GL10.GL_LIGHTING); gl.glEnable(GL10.GL_LIGHT0);

gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient, 0); gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse, 0); gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0);

LIGHTS, CAMERA, ... 211

Figure 10.4: Lighting the scene

In our code we define one light source at position (1, 1, 1). It’s a white omnidirectional light that has a bright diffuse component and a dim ambient component. In this example, we’re not using specular lighting.

Next, we need to tell OpenGL about the materials our cube is made of. Light reflects differently off different materials, such as metal, plastic, or paper. To simulate this in OpenGL, add this code in onSurfaceCreated( ) to define how the material reacts with the three types of light: ambient, diffuse, and specular:

Download OpenGL/src/org/example/opengl/GLRenderer.java

float matAmbient[] = new float[] { 1, 1, 1, 1 }; float matDiffuse[] = new float[] { 1, 1, 1, 1 };

gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, matAmbient, 0);

gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, matDiffuse, 0);

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]