Adding a New Color Attribute 63

Một phần của tài liệu 1937785343 {CCD27CA4} OpenGL ES 2 for android a quick start guide brothaler 2013 07 06 (Trang 77 - 85)

Part I A Simple Game of Air Hockey 2. Defining Vertices and Shaders

4. Adding Color and Shade

4.3 Adding a New Color Attribute 63

Now that we’ve updated our table structure by adding an additional point in the center of the table, 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.java float[] tableVerticesWithTriangles = {

// Order of coordinates: X, Y, R, G, B // Triangle Fan

0f, 0f, 1f, 1f, 1f,

Adding a New Color Attribute • 63

-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, // Mallets

0f, -0.25f, 0f, 0f, 1f, 0f, 0.25f, 1f, 0f, 0f };

As you can see, 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.

Converting Colors Using Android’s Color Class

When we use floating-point attributes, we need to specify each color component in a range from 0 to 1, with 1 being the maximum value for that color component. Figuring out the right numbers for a certain color might not be obvious, but by using Android’s Color class, we can easily come up with the right values. For example, here’s what we do to get the OpenGL color values for green:

float red = Color.red(Color.GREEN) / 255f;

float green =Color.green(Color.GREEN) / 255f;

float blue = Color.blue(Color.GREEN) / 255f;

We can also do this with web colors:

int parsedColor = Color.parseColor("#0099CC");

float red = Color.red(parsedColor) / 255f;

float green =Color.green(parsedColor) / 255f;

float blue = Color.blue(parsedColor) / 255f;

The values returned by Color.red(), Color.green(), and Color.blue() range from 0 to 255, so to convert these into OpenGL colors, we just divide each component by 255.

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:

Chapter 4. Adding Color and Shade • 64

AirHockey2/res/raw/simple_vertex_shader.glsl attribute 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 on earth is a varying?” you might ask. Remember that we said we wanted our colors to vary across the surface of a triangle? Well, this is done by using a special variable type known as a varying. To better understand what a varying does, let’s go back and review how OpenGL combines vertices together to create objects, as seen in Figure 11, Rasterization: generating fragments, on page 33.

As we learned in Section 2.5, Introducing the OpenGL Pipeline, on page 28, when OpenGL builds a line, it takes the two vertices that make up that line and generates fragments for it. When OpenGL builds a triangle, it does the same thing by using three vertices to build a triangle. The fragment shader will then be run for every fragment generated.

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.

Before we go into more detail on how this blending is done, let’s add the varying to the fragment shader as well. Open simple_fragment_shader.glsl and update it as follows:

AirHockey2/res/raw/simple_fragment_shader.glsl precision mediump float;

varying vec4 v_Color;

void main() {

gl_FragColor = v_Color;

}

Adding a New Color Attribute • 65

We’ve replaced the uniform that was there before with our varying, v_Color. If the fragment belongs to a line, then OpenGL will use the two vertices that make up that line to calculate the blended color. If the fragment belongs to a triangle, then OpenGL will use the three vertices that make up that triangle to calculate the blended color.

Now that we’ve updated our shaders, we’ll also need to update our Java code so that we pass in the new color attribute to a_Color in the vertex shader. Before we do that, let’s take some time to learn more about how OpenGL can smoothly blend colors from one point to another.

How Does a Varying Get Blended at Each Fragment?

We just learned that we can use a varying to produce a blended color at each fragment of a line or triangle. 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. This blending is done using linear interpolation. To learn how this works, let’s first start with the example of a line.

Linear Interpolation Along a Line

Let’s say that we had a line with a red vertex and a green vertex, and we wanted to blend the colors from one to the other. The blended colors would look something like this:

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. Since the left vertex of the line is red and the right vertex is green, the left end of the line should be 100 percent red, the middle should be 50 percent red, and the right should be 0 percent red:

Chapter 4. Adding Color and Shade • 66

The same thing happens with green. Since the left vertex is red and the right vertex is green, the left end of the line will be 0 percent green, the middle will be 50 percent green, and the right will be 100 percent green:

Once we add the two together, we end up with a blended line:

This is linear interpolation in a nutshell. The strength of each color depends on the distance of each fragment from the vertex containing that color.

To calculate this, we can take the value at vertex 0 and the value at vertex 1, and then we calculate the distance ratio for the current fragment. The distance ratio is simply a ratio between 0 and 100 percent, with 0 percent being the left vertex and 100 percent being the right vertex. As we move from left to right, the distance ratio will increase linearly from 0 to 100 percent. Here’s an example of a few distance ratios:

Adding a New Color Attribute • 67

To calculate the actual blended value using linear interpolation, we can then use the following formula:

blended_value = (vertex_0_value * (100% – distance_ratio)) + (vertex_1_value * distance_ratio) This calculation is done for each component, so if we’re dealing with color values, this calculation will be done for the red, green, blue, and alpha com- ponents separately, with the results combined into a new color value.

Let’s try this out with our line example. Let the vertex_0_value equal red, with an RGB value of (1, 0, 0), and the vertex_1_value equal green, with an RGB value of (0, 1, 0). Let’s calculate the final color for a few positions on the line:

Equation Distance

ratio Position

(vertex_0_value * (1 - distance_ratio)) + (vertex_1_value * distance_ratio) =

0%

Far left

((1, 0, 0) * (100% – 0%)) + ((0, 1, 0) * 0%) = ((1, 0, 0) * 100%) =

(1, 0, 0) (red)

(vertex_0_value * (1 – distance_ratio)) + (vertex_1_value * distance_ratio) =

25%

One-quarter along the line

((1, 0, 0) * (100% – 25%)) + ((0, 1, 0) * 25%) = ((1, 0, 0) * 75%) + ((0, 1, 0) * 25%) =

(0.75, 0, 0) + (0, 0.25, 0) = (0.75, 0.25, 0) (mostly red)

(vertex_0_value * (1 – distance_ratio)) + (vertex_1_value * distance_ratio) =

50%

Middle of the line

((1, 0, 0) * (100% – 50%)) + ((0, 1, 0) * 50%) = ((1, 0, 0) * 50%) + ((0, 1, 0) * 50%) =

(0.5, 0, 0) + (0, 0.5, 0) =

(0.5, 0.5, 0) (half red, half green)

(vertex_0_value * (1 – distance_ratio)) + (vertex_1_value * distance_ratio) =

75%

Three-quarters along the line

((1, 0, 0) * (100% – 75%)) + ((0, 1, 0) * 75%) =

Chapter 4. Adding Color and Shade • 68

Equation Distance

ratio Position

((1, 0, 0) * 25%) + ((0, 1, 0) * 75%) = (0.25, 0, 0) + (0, 0.75, 0) =

(0.25, 0.75, 0) (mostly green)

(vertex_0_value * (1 – distance_ratio)) + (vertex_1_value * distance_ratio) =

100%

Far right

((1, 0, 0) * (100% – 100%)) + ((0, 1, 0) * 100%) = ((1, 0, 0) * 0%) + ((0, 1, 0) * 100%) =

(0, 1, 0) (green) Table 2—Linear interpolation equation examples

Notice that at all times the weights of both colors add up to 100 percent. If red is at 100 percent, green is at 0 percent. If red is 50 percent, green is 50 percent.

Using a varying, we can blend any two colors together. We’re also not limited to colors: we can interpolate other attributes as well.

Now that we know how linear interpolation works with a line, let’s read on to see how this works with a triangle.

Blending Across the Surface of a Triangle

Figuring out how linear interpolation works wasn’t so bad when we were dealing with just two points; we learned that each color scales from 100 per- cent to 0 percent from that color’s vertex to the other vertex on the line, and that both scaled colors are added together to give the final color.

Linear interpolation across a triangle works with the same idea, but there are now three points and three colors to deal with. Let’s look at a visual example:

Adding a New Color Attribute • 69

This triangle has three colors associated with it: the top vertex is cyan, the left vertex is magenta, and the right is yellow. Let’s break the triangle down into the colors derived from each vertex:

Just like with the line, each color is strongest near its vertex and fades away toward the other vertices. We also use ratios to determine the relative weights of each color, except this time we use ratios of areas instead of lengths:

At any given point inside the triangle, three inner triangles can be created by drawing a line from that point to each vertex. The ratios of the areas of these inner triangles determine the weight of each color at that point. For example, the strength of yellow at that point is determined by the area of the inner Chapter 4. Adding Color and Shade • 70

triangle that is opposite of the yellow vertex. The closer the point gets to the yellow vertex, the larger that triangle gets, and the more yellow the fragment at that point will be.

Just like with the line, these weights always equal 100 percent. We can use the following formula to calculate the color at any point inside the triangle:

blended_value = (vertex_0_value * vertex_0_weight) + (vertex_1_value * vertex_1_weight) + (ver- tex_2_value * (100% – vertex_0_weight – vertex_1_weight))

Given that we understand how this works with a line, we don’t need to go into specific examples here. The idea is the same, but we have three points instead of two.

Một phần của tài liệu 1937785343 {CCD27CA4} OpenGL ES 2 for android a quick start guide brothaler 2013 07 06 (Trang 77 - 85)

Tải bản đầy đủ (PDF)

(330 trang)