OPENGL|ES第四天,Adding color and shade

来源:互联网 发布:有关小说的软件 编辑:程序博客网 时间:2024/06/05 10:36

Here’s our game plan for this chapter:

• First we’ll learn how to define a color at each point as a vertex attribute instead of using a single color for an entire object.

• We’ll then learn how to smoothly blend these colors between the differentvertices that make up an object.



4.1 Smooth Shading

how can we represent a complex scene with many different colors and shades?what if there was a way to blend different colors across the same triangle?

1.Smooth Shading Is Done Between Vertices

OpenGL gives us a way to smoothly blend the colors at each vertex across a line or across the surface of a triangle. We’ll use this type of shading to make our table appear

brighter in the middle and dimmer toward the edges.

How could we make this appear brighter in the middle?We’ll need to add a point in the middle so that we can blend colors between the middle of  the table and the edges.



4.2.Introducing Triangle Fans

With a new point in the middle of the table, we’ll end up with four triangles instead of two. Let's update the triangles as follows:

//AirHockey2/src/com/airhockey/android/AirHockeyRenderer.java// Triangle Fan0, 0,-0.5f, -0.5f,0.5f, -0.5f,0.5f, 0.5f,-0.5f, 0.5f,-0.5f, -0.5f,

Each edge vertex is used in two triangles,and the center vertex is used in all four triangles! We can do that by drawing these vertices as a triangle fan. A triangle fan looks

something like the following image:

A triangle fan begins with a center vertex, using the next two vertices to create the first triangle. Each subsequent vertex will create another triangle, fanning around the

original center point. To complete the fan, we just repeat the second point at the end. We’ll need to update our draw call so that OpenGL knows that this data represents

a triangle fan. In onDrawFrame(), update the call to the first glDrawArrays() as follows:

//AirHockey2/src/com/airhockey/android/AirHockeyRenderer.javaglDrawArrays(GL_TRIANGLE_FAN, 0, 6);

4.3.Adding a New Color Attribute

we can now add a color attribute to each point. Let’s update the entire array of data as follows:

//AirHockey2/src/com/airhockey/android/AirHockeyRenderer.javafloat[] tableVerticesWithTriangles = {// Order of coordinates: X, Y, R, G, B// Triangle Fan0f, 0f, 1f, 1f, 1f,-0.5f, -0.5f, 0.7f, 0.7f, 0.7f,0.5f, -0.5f, 0.7f, 0.7f, 0.7f,0.5f, 0.5f, 0.7f, 0.7f, 0.7f,-0.5f, 0.5f, 0.7f, 0.7f, 0.7f,-0.5f, -0.5f, 0.7f, 0.7f, 0.7f,// Line 1-0.5f, 0f, 1f, 0f, 0f,0.5f, 0f, 1f, 0f, 0f,// Mallets0f, -0.25f, 0f, 0f, 1f,0f, 0.25f, 1f, 0f, 0f};
we’ve added three additional numbers to each vertex. These numbers represent red, green, and blue, and together they will form the color for that particular vertex.

1.Adding the Color Attribute to the Shaders

The next step will be to remove the color uniform from the shader and replace it with an attribute. We’ll then update the Java code to reflect the new shader code.

Open simple_vertex_shader.glsl and update it as follows:

//AirHockey2/res/raw/simple_vertex_shader.glslattribute vec4 a_Position;attribute vec4 a_Color;varying vec4 v_Color;void main(){v_Color = a_Color;gl_Position = a_Position;gl_PointSize = 10.0;}

//AirHockey2/res/raw/simple_vertex_shader.glslattribute vec4 a_Position;attribute vec4 a_Color;varying vec4 v_Color;void main(){v_Color = a_Color;gl_Position = a_Position;gl_PointSize = 10.0;}

We added a new attribute, a_Color, and we also added a new varying called v_Color. What is a "varying"? We wanted our colors to vary across the surface of a triangle,

this is done by using a special variable type known as a varying.

A varying is a special type of variable that blends the values given to it and sends these values to the fragment shader. Using the line above as an example, if a_Color was

red at vertex 0 and green at vertex 1, then by assigning a_Color to v_Color, we’re telling OpenGL that we want each fragment to receive a blended color. Near vertex 0, the

blended color will be mostly red, and as the fragments get closer to vertex 1, the color will start to become green. Update the code as follows.

//AirHockey2/res/raw/simple_fragment_shader.glslprecision mediump float;varying vec4 v_Color;void main(){gl_FragColor = v_Color;}

We’ve replaced the uniform that was there before with our varying, v_Color.

2.How Does a Varying Get Blended at Each Fragment?

We can blend more than just colors; we can send any value to a varying, and OpenGL will take the two values belonging to a line, or the three belonging to a triangle, and 

smoothly blend these values across the primitive, with a different value for each fragment.

Let’s say that we had a line with a red vertex and a green vertex. At the left side of the line, the color of each fragment is mostly red. As we move toward the right, the 

fragments become less red, and in the middle, they are somewhere in between red and green. As we get closer to the green vertex, the fragments become more and

more green.We can see that each color scales linearly along the length of the line. The same thing happens with green.

The same with a triangle


4.4 Rendering with the New Color Attribute

Now that we’ve added a color attribute to our data and we’ve updated the vertex and fragment shaders to use this attribute, the next steps are to remove the old code that

passed in the color via a uniform and to tell OpenGL to read in colors as a vertex attribute. 

1.Updating Constants

//AirHockey2/src/com/airhockey/android/AirHockeyRenderer.javaprivate static final String A_COLOR = "a_Color";private static final int COLOR_COMPONENT_COUNT = 3;private static final int STRIDE =(POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT;private int aColorLocation;

We can now remove the old constants and variables associated with u_Color.

As we now have both a position and a color attribute in the same data array, OpenGL can no longer assume that the next position follows immediately after the previous

position. Once OpenGL has read the position for a vertex, it will have to skip over the color for the current vertex if it wants to read the position for the next vertex. We’ll use

the stride to tell OpenGL how many bytes are between each position so that it knows how far it has to skip.

2.Updating onSurfaceCreated()

Then next is to update onSurfaceCreated() to reflect the new colorattribute. We first need to get the location of our new attribute, so let’s remove the code associated with

u_Color and add the following code:

//AirHockey2/src/com/airhockey/android/AirHockeyRenderer.javaaColorLocation = glGetAttribLocation(program, A_COLOR);

We should also update the call to glVertexAttribPointer() to add in the stride:

//AirHockey2/src/com/airhockey/android/AirHockeyRenderer.javaglVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,false, STRIDE, vertexData);

Now we can add in the code to tell OpenGL to associate our vertex data with a_Color in the shader. Add the following code to the end of onSurfaceCreated():

//AirHockey2/src/com/airhockey/android/AirHockeyRenderer.javavertexData.position(POSITION_COMPONENT_COUNT);glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT,false, STRIDE, vertexData);glEnableVertexAttribArray(aColorLocation);

This is an important bit of code, so let’s take the time to understand each line carefully:

1). First we set the position of vertexData to POSITION_COMPONENT_COUNT, which is set to 2. Why do we do this? Well, when OpenGL starts reading in the color

attributes, we want it to start at the first color attribute, not the first position attribute. We need to skip over the first position ourselves by taking the position component size 

into account, so we set the position to POSITION_COMPONENT_ COUNT so that the buffer’s position is set to the position of the very first color attribute. Had we set the 

position to 0 instead, OpenGL would be reading in the position as the color. 

2). We then call glVertexAttribPointer() to associate our color data with a_Color in our shaders. The stride tells OpenGL how many bytes are between eachcolor, so that  

when it reads in the colors for all of the vertices, it knows how many bytes it needs to skip to read the color for the next vertex. It’s very important that the stride be specified 

in terms of bytes. Even though a color in OpenGL has four components (red, green, blue, and alpha), we don’t have to specify all of them. Unlike uniforms, OpenGLwill 

replace unspecified components in attributes with defaults: the first three components will be set to 0, and the last component set to 1.

3). Finally, we enable the vertex attribute for the color attribute, just like we did for the position attribute.

3.Updating onDrawFrame

We have just one more thing to do: update onDrawFrame(). All we have to do here is delete the calls to glUniform4f(), because we no longer need them.