How To Create Dynamic Textures with CCRenderTexture in Cocos2D 2.X

Learn how to create dynamic textures similar to the hills in Tiny Wings using CCRenderTexture in this Cocos2D 2.X Tutorial. By Ali Hafizji.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Creating Noise For the Texture

As you’ve probably noticed in Tiny Wings, the textures aren’t just flat colors – they’re decorated with a bit of noise to make them look like they have shadows and highlights.

You can always write some code to make dynamic noise, but it’s often easier (and more performant) to just ship your app with some premade noise – and that’s what you’re going to do in this tutorial.

One easy way to make random noise is through a free image editing program called Gimp. The rest of this section will show you how to make this texture for yourself, but if you’re like this guy:

"F that!" guy

Then you can just download the Noise2 I already made. Extract the contents of the file and add them to your project, you can then skip to the next section :]

If you want to follow along, download Gimp if you haven’t already, and start it up.

After Gimp starts up, go to File\New, and create a new Image of size 512×512. Then go to Filter\Render\Clouds\Solid Noise, tweak the parameters if you want, and click OK. You should then have something that looks like this:

Creating random noise with Gimp

You’re going to use this image to multiply the texture’s colors. So wherever the image is white, the original color will show through, and wherever it’s black, the original color will be darkened.

As it currently stands, there’s too much black in the image for the subtle effect we’re looking for. So to reduce the amount of black, go to Colors\Levels, and drag the leftmost slider in the “Output Levels” section to the right.

You will see the image begin to lighten up as shown below:

Modifying levels with Gimp

Click OK when you’re done. Then there’s one last step – the noise texture needs to be made seamless, so that if you repeat the texture everything lines up OK.

Gimp makes this extremely easy. Just go to Filters\Map\Make Seamless – and you’re done!

Use File\Export to and export your image as Noise.png somewhere on your hard drive.

Then repeat the above process to generate two more textures, one of size 1024×1024 for retina device and the other of size 2048×1024 for the iphone 5 4″screen. Make sure you name the first one Noise-hd.png and the other Noise-iphone5hd.png.

Then find the files in Finder and drag them into your TinySeals project. Verify that “Copy items into destination group’s folder” is selected, and click Finish.

Congrats, now you have the noise textures you can use to make your dynamic textures look more cool and realistic!

And now that you know how to create this basic texture, you can play around with it using Gimp’s filters to get different effects!

Applying Noise to Texture

Now that you have an image with some noise, you are going apply it to the texture you created with CCRenderTexture.

Inside spriteWithColor:textureWidth:textureHeight:, add the following code right after the comment for step 3:

CCSprite *noise = [CCSprite spriteWithFile:@"Noise.png"];
[noise setBlendFunc:(ccBlendFunc){GL_DST_COLOR, GL_ZERO}];
noise.position = ccp(textureWidth/2, textureHeight/2);
[noise visit];

This creates a CCSprite with the noise texture, centers it within the render texture, and calls visit. The visit routine is what executes all of the OpenGL ES commands required to draw the texture.

There’s only one tricky bit – it’s this setBlendFunc method. What in the heck does that do?!

Well, the first constant passed in (GL_DST_COLOR) specifies how to multiply the incoming/source color (which is the noise texture), and the second constant passed in (GL_ZERO) specifies how to multiply the existing/destination color (which is the colored texture).

So effectively:

  • The existing color is multiplied by GL_ZERO, which means the existing color is cleared out.
  • The noise texture colors are multiplied by GL_DST_COLOR. GL_DST_COLOR means the existing colors, so the noise texture colors are multiplied by the existing color. So the more “white” in the noise, the more of the existing color appears, but the more “black” in the noise the darker the existing color is.
  • The above two colors are added together, and since the first is zero all that really matters in this case is the second result.

By the way, I found (and still sort-of find) these blend constants confusing, but luckily there’s a great online tool that you can use to visualize the effects of these blend constants.

Anyway, that’s all you need! Compile and run your code, you will now see a subtle shadow effect on your texture.

Note that it often doesn’t look good on the simulator, you might need to try it on an actual device.

A dynamic background with noise applied for shadows and lighting

Adding a Gradient to the Texture

To make the texture look even better, let’s add a gradient from top to bottom, where the texture will get darker and darker going down.

You could do this by modifying the noise image with Gimp, but you can also do it in code, which makes things more dynamic and easily modifiable.

The basic idea is that you will draw a black rectangle on top of the texture, but it will be completely transparent up top, and opaque at the bottom. This will keep the top untouched, but gradually darken the image going down.

To do this, you need to use some OpenGL commands. If you are new to OpenGL, don’t worry – I will show you the code you need and explain how it works at a high level, which will get you through this tutorial. At the end of the tutorial, I’ll give you a reference for more information.

Inside spriteWithColor:textureWidth:textureHeight:, add the following code right before creating the noise sprite:

self.shaderProgram = [[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionColor];

CC_NODE_DRAW_SETUP();

// 3: Draw into the texture
float gradientAlpha = 0.7f;
CGPoint vertices[4];
ccColor4F colors[4];
int nVertices = 0;

vertices[nVertices] = CGPointMake(0, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0 };
vertices[nVertices] = CGPointMake(textureWidth, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
vertices[nVertices] = CGPointMake(0, textureHeight);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
vertices[nVertices] = CGPointMake(textureWidth, textureHeight);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};

ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position  | kCCVertexAttribFlag_Color);

glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_FLOAT, GL_FALSE, 0, colors);
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)nVertices);

One weird thing about drawing textures is that the upper left is 0,0 – rather than the lower left like you’re used to in Cocos2D.

So the above code first defines the four vertices for the texture in the order
top left, top right, bottom left, bottom right – and the colors at each point.

You might wonder why the vertices were drawn in this order. That is because you’re going to draw two triangles to make up this rectangle:

Drawing texture with an OpenGL triangle strip

You’re going to draw these triangle using GL_TRIANGLE_STRIP, which means the first triangle is the first three vertices in the array, and the rest of the triangles take the previous two vertices and the next vertex.

So the first triangle is V0, V1, V2, and the second triangle is V1, V2, V3.

After defining the array of vertices and colors, you pass them to the OpenGL ES pipeline with glVertexAttribPointer specifying kCCVertexAttrib_Position as the constant. Next you need to pass the colors array, this is done using the same method but this time you pass kCCVertexAttrib_Color as the constant.

Compile and run your code, and you should see a neat gradient texture!

Dynamic background with noise and gradient

Note: If you’d like to learn more about OpenGL in order to better understand what these commands are doing, check out our OpenGL tutorial series.

Note: If you’d like to learn more about OpenGL in order to better understand what these commands are doing, check out our OpenGL tutorial series.

Ali Hafizji

Contributors

Ali Hafizji

Author

Over 300 content creators. Join our team.