Here are some interesting links I’ve come across recently:
Cross-platform
Giveaways
OpenGL
- History of the Modern GPU Series
- How to write portable WebGL
- OpenGL ES Particle System Tutorial: Part 1/3
NDK
SDKs
Learn how to develop mobile graphics using OpenGL ES 2
Here are some interesting links I’ve come across recently:
Cross-platform
Giveaways
OpenGL
NDK
SDKs
Let’s say you’ve decided to develop the next viral game for Android. You now have a choice: Do you go with a pre-packaged solution, flawed and rough around the edges though it may be, or do you decide to DIY (Do It Yourself) which has the disadvantage of reinventing the wheel and spending more time writing boiler-plate code? You also need to decide if you are going to go with a commercial solution or with one of the open-source libraries available.
Here are two of the more well-known open-source libraries that won’t cost you a dime to use:
libgdx is an open-source framework which abstracts away the job of developing graphics for Android, and it also allows you to build for the desktop with only a few lines of code. It also appears to have support for OpenGL 2 on the desktop, though using standard OpenGL 2 instead of OpenGL ES 2.
forplay is a cross-platform library for developing games to target to the desktop, HTML5, Android, and Flash. It seems to be geared toward making 2d platformers rather than more intensive 3D games. Examples of forplay in action and more information can be seen at the Google IO 2011 session titled “Kick-ass Game Programming with Google Web Toolkit“.
The pros
You can focus on the implementation of your app or game and save development time by not having to reinvent the wheel and rewrite boiler-plate code; being able to build for different platforms with only a few lines of code is a neat thing. Rovio reportedly used forplay in the development of the WebGL version of Angry Birds.
The cons
By using a framework, you won’t learn about the finer details of OpenGL ES and other aspects of game development, and ultimately, you’ll want to learn and understand these finer details if you also want to understand the broader picture. You’ll also have to live with the design decisions and implementation details of the various frameworks, as well as any rough edges. If you’re targeting Android and the Android Market, it’s better to test on and develop for the phone rather than on the desktop — it’s better to do well on one platform than mediocre on a few.
With the wide availability of code snippets and open-source libraries, there’s no need to go either-or. You can go with an existing framework if that’s most convenient for you, or you can start building from scratch, while taking code and math from the vast array of resources available on the Internet. Be sure to check the licenses before using code from other libraries — some open-source libraries are GPL licensed, which requires you to make your source code available for others should you incorporate it into your own code.
As always, don’t hesitate to leave your comments and feedback. 🙂
Previously, if you wanted to do real-time 3D graphics on the web, your only real option was to use a plugin such as Java or Flash. However, there is currently a push to bring hardware-accelerated graphics to the web called WebGL. WebGL is based on OpenGL ES 2, which means that we’ll need to use shaders. Since WebGL runs inside a web browser, we’ll also need to use JavaScript to control it.
You’ll need a browser that supports WebGL, and you should also have the most recent drivers installed for your video card. You can visit Get WebGL to see if your browser supports WebGL and if not, it will tell you where you can get a browser that supports it.
The latest stable releases of Chrome and Firefox support WebGL, so you can always start there.
This lesson uses the following third-party libraries:
The reader should be familiar with programming and 3D concepts on a basic level. The Khronos WebGL Public Wiki is a good place to start out.
As I write this, I am also learning WebGL, so we’ll be learning together! We’ll look at how to get a context and start drawing stuff to the screen, and we’ll more or less follow lesson one for Android as this lesson is based on it. For those of you who followed the Android lesson, you may remember that getting an OpenGL context consisted of creating an activity and setting the content view to a GLSurfaceView object. We also provided a class which overrode GLSurfaceView.Renderer and provided methods which were called by the system.
With WebGL, it is just as easy to get things setup and running. The webgl-utils.js script provides us with two functions to get things going:
function setupWebGL(canvas, opt_attribs); function window.requestAnimFrame(callback, element);
The setupWebGL() function takes care of initializing WebGL for us, as well as pointing the user to a browser that supports WebGL or further troubleshooting if there were errors initializing WebGL. More info on the optional parameters can be found at the WebGL Specification page, section 5.2.1.
The second function provides a cross-browser way of setting up a render callback. The browser will call the function provided in the callback parameter at a regular interval. The element parameter lets the browser know for which element the callback is firing.
In our script we have a function main() which is our main entry point, and is called once at the end of the script. In this function, we initialize WebGL with the following calls:
// Try to get a WebGL context canvas = document.getElementById("canvas"); // We don't need a depth buffer. // See https://www.khronos.org/registry/webgl/specs/1.0/ Section 5.2 // for more info on parameters and defaults. gl = WebGLUtils.setupWebGL(canvas, { depth: false });
If the calls were successful, then we go on to initialize our model data and set up our rendering callback.
Like in lesson one for Android, we need to define our model data as an array of floating point numbers. These numbers can represent vertex positions, colors, or anything else that we need. Unlike OpenGL ES 2 on Android, WebGL does not support client-side buffers. This means that we need to load all of the data into WebGL using vertex buffer objects (VBOs). Thankfully, this is a pretty trivial step and it will be explained in more detail further below.
Before we transfer the data into WebGL, we’ll define it in client memory first using the Float32Array datatype. These typed arrays are an attempt to increase the performance of Javascript by adding typing information.
// Define points for equilateral triangles. trianglePositions = new Float32Array([ // X, Y, Z, -0.5, -0.25, 0.0, 0.5, -0.25, 0.0, 0.0, 0.559016994, 0.0]); // This triangle is red, green, and blue. triangle1Colors = new Float32Array([ // R, G, B, A 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0]); ...
All of the triangles can share the same position data, but we’ll define a different set of colors for each triangle.
After defining basic model data, our main function calls startRendering(), which takes care of setting up the viewport, building the shaders, and starting the rendering loop.
First, we configure the viewport to be the same size as the canvas viewport. Note that this assumes a canvas that doesn’t change size, since we’re only doing this once.
// Set the OpenGL viewport to the same size as the canvas. gl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight);
Then we setup the projection matrix. Please see “Understanding matrices” for more information.
// Create a new perspective projection matrix. The height will stay the same // while the width will vary as per aspect ratio. var ratio = canvas.clientWidth / canvas.clientHeight; var left = -ratio; var right = ratio; var bottom = -1.0; var top = 1.0; var near = 1.0; var far = 10.0; mat4.frustum(left, right, bottom, top, near, far, projectionMatrix);
Setting up the viewport and configuring the projection matrix is something we should do whenever the canvas has changed size. The next step is to set the default clear color as well as the view matrix.
// Set the background clear color to gray. gl.clearColor(0.5, 0.5, 0.5, 1.0); /* Configure camera */ // Position the eye behind the origin. var eyeX = 0.0; var eyeY = 0.0; var eyeZ = 1.5; // We are looking toward the distance var lookX = 0.0; var lookY = 0.0; var lookZ = -5.0; // Set our up vector. This is where our head would be pointing were we holding the camera. var upX = 0.0; var upY = 1.0; var upZ = 0.0; // Set the view matrix. This matrix can be said to represent the camera position. var eye = vec3.create(); eye[0] = eyeX; eye[1] = eyeY; eye[2] = eyeZ; var center = vec3.create(); center[0] = lookX; center[1] = lookY; center[2] = lookZ; var up = vec3.create(); up[0] = upX; up[1] = upY; up[2] = upZ; mat4.lookAt(eye, center, up, viewMatrix);
Finally, we load in our shaders and compile them. The code for this is essentially identical to Android; please see “Defining vertex and fragment shaders” and “Loading shaders into OpenGL” for more information.
In WebGL we can embed shaders in a few ways: we can embed them as a JavaScript string, we can embed them into the HTML of the page that contains the script, or we can put them in a separate file and link to that file from our script. In this lesson, we take the second approach:
<script id="vertex_shader" type="x-shader/x-vertex">
uniform mat4 u_MVPMatrix;
...
</script>
<script id="vertex_shader" type="x-shader/x-vertex">
precision mediump float;
...
</script>
We can then read in these scripts using the following code snippit:
// Read the embedded shader from the document. var shaderSource = document.getElementById(sourceScriptId); if (!shaderSource) { throw("Error: shader script '" + sourceScriptId + "' not found"); } // Pass in the shader source. gl.shaderSource(shaderHandle, shaderSource.text);
I mentioned a bit earlier that WebGL doesn’t support client-side buffers, so we need to upload our data into WebGL itself using buffer objects. This is actually pretty straightforward:
// Create buffers in OpenGL's working memory. trianglePositionBufferObject = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, trianglePositionBufferObject); gl.bufferData(gl.ARRAY_BUFFER, trianglePositions, gl.STATIC_DRAW); triangleColorBufferObject1 = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, triangleColorBufferObject1); gl.bufferData(gl.ARRAY_BUFFER, triangle1Colors, gl.STATIC_DRAW); ...
First we create a buffer object using createBuffer(), then we bind the buffer. Then we pass in the data using gl.bufferData() and tell OpenGL that this buffer will be used for static drawing; this hints to OpenGL that we will not be updating this buffer often.
You may have noticed that the WebGL API is a bit different than the base OpenGL ES 2 API: functions and variable names have had their “gl” or “GL_” prefixes removed. This actually makes the API a bit cleaner to use and read. At the same time, some functions have been modified a bit to mesh better with the JavaScript environment.
We finally kick off the rendering loop by calling window.requestAnimFrame():
// Tell the browser we want render() to be called whenever it's time to draw another frame. window.requestAnimFrame(render, canvas);
The code to render to the screen is pretty much a transpose of the lesson one code for Android. One main difference is that we call window.requestAnimFrame() at the end to request another animation frame.
// Request another frame window.requestAnimFrame(render, canvas);
If everything went well, you should end up with an animated canvas like the one just below:
If you would like more explanations behind the shaders or other aspects of the program, please be sure to check out lesson one for Android.
Debugging in JavaScript in the browser is a little more difficult than within an integrated environment such as Eclipse, but it can be done using tools such as Chrome’s inspector. You can also use the WebGL Inspector, which is a plugin that lets you delve into WebGL’s internals and get a better idea of what’s going on.
WebGL can easily be embedded into your posts and pages! You need a canvas, script includes for any third-party libraries, and a script body for your main script (this can also be an include).
Example of a canvas:
<pre><canvas id="canvas" width="550" height="375">Your browser does not support the canvas tag. This is a static example of what would be seen.</canvas></pre>
…
Example of a script include:
<pre><script type="text/javascript" src="http://www.learnopengles.com/wordpress/wp-content/uploads/2011/06/webgl-utils.js"></script></pre>
Example of an embedded script:
<pre><script type="text/javascript">
/**
* Lesson_one.js
*/
...
</script></pre>
The <pre> tag is important; otherwise WordPress will mangle your scripts and insert random paragraph tags and other stuff inside. Also, once you’ve inserted this code, you have to stick to using the HTML editor, as the visual editor will also mangle or delete your scripts.
Try changing the animation speed, vertex points, or colors, and see what happens!
The full source code for this lesson can be downloaded from the project site on GitHub.
Don’t hesitate to ask any questions or offer feedback, and thanks for stopping by!