Minko Weekly Roundup #4

Features

  • The JointsDebugController makes it possible to display the joints and bones of a skinned mesh in order to check if everything works as expected.
  • The VertexPositionDebugController will display the position of each vertex of a mesh.
  • The VertexNormalDebugController will display the normal of each vertex. You can use it with the VertexNormalShader to display and debug the normals of a mesh.

Examples

Answers

Tutorials

Fixes

  • minko-collada will now load the vertex RGBA data when it’s available
  • min/max computation is always possible upon creation of a VertexStream regardless of its StreamUsage
  • frustum culling will now also test the center of the bounding box and not only the 8 corners

Minko Weekly Roundup #3

Projects

Wieliczka Salt Mine website and apps

Created by the Polish agency GoldenSubmarine, the Wieliczka Salt Mine web site offers an interative experience with HD 360° panoramas built with Minko. Thanks to Adobe AIR, the application is also available on mobile platforms such as the iPad, the iPhone and Android.

This awesome project was just rewarded with the “FWA Mobile of the Day” award! This is the very first FWA for a project built with Minko so we are very proud of course!

Videos

This video presents yet another example of a very cool shader built by developer Jeremy Sellam from the Les Chinois, a French digital agency based in Paris, France. It was built with the public beta of the ShaderLab of course!

Features

ByteArray streams

Geometry is now stored in ByteArray objects. It reduces the memory consumption and should provide a significant performances boost. Especially on mobile devices. You can read more about this feature on my previous blog post.

Parametric frustum culling

Minko now implements frustum culling in a very flexible fashion. You can chose on what planes and using what volume (sphere or box) frustum culling is computed. For example, to use the bounding sphere on all planes but the box only on the near/far planes, you can write:

Such flexibility should make it possible to optimize performances to every use case. It’s also nice to consider computations are kept to a minimum by storing world space versions of the bounding sphere/box. You can view the entire code for this feature in the VisibilityController.

Per-triangle ray casting

Geometry.cast() now makes it possible to get the triangle ID (the first indice of the triangle) that crosses the specified ray. Combined with Mesh.cast() and Group.cast(), it makes it very easy to perform ray-casting at any level, from the root of the scene to the geometry level.

Local/world gizmos in Minko Studio

Gizmos are the key to any WYSIWYG editor. We’ve enhanced Minko Studio’s gizmos not only by adding scale/rotation gizmos but also the possiblity to chose whether those gizmos should be used in local or world space.

Smooth shadows in Minko Studio

Shadows are a very important part of any real-time 3D immersive application. Thus, being able to control the quality of the shadows while keeping interactive framerates is very important. The minko-lighting plugin already introduced soft shadows a few weeks ago, and now the corresponding options are available right inside Minko Studio! It’s now easier than ever to fine tune the lighting engine in order to get the best performance/quality ratio.

Documentation

Minko now has a new, clean and fast growing wiki: the developers Hub. You will find a lots a old and new tutorials. But also lots a new examples and projects done with Minko!

Fixes

  • Geometry.fillNormalsData() and Geometry.fillTangentsData will reset the corresponding buffers to make sure normals/tangents are not incremented everytime they are supposed to be updated.
  • Picking has been completely refactored: all the known bugs have been fixed and we are now using a 1*1 BitmapData/scissor rectangle to get better performances.
  • The Collada loader will now inspect 3D transforms in order to handle negative scales properly. It will also invert the z axis at the vertex level in order to perform right to left handed coordinates conversion. It fixes problems occuring when loading animations build using symmetry.

Don’t forget to “watch” Minko’s github repository to get your daily dose of new features and fixes!

New Minko Feature: ByteArray Streams

I’ve just pushed on github my work for the past few weeks and it’s a major update. But most of you should not
have to change a single line of code in the best case. The two major changes are the activation of
frustum culling – who now works perfectly well – and the use of ByteArray objectst to store vertex/index
streams data.

Using ByteArray instead of Vector, why are we doing this?

As you might now, Number is the equivalent of the “double” data type and as such they are stored on
64bits. As 32bits is all a GPU can handle regarding vertex data it is a big waste of RAM. Using ByteArray
makes it possible to store floats as floats and avoid any memory waste
. The same goes with indices stored
in uint when they are actually shorts.

Another important optimization is the GPU upload. Using Number of uint requires the Flash player to
re-interpret every value before upload: each 64bits Number has to be turned into a 32bits float, each
32bit uint has to be turned into a 16bits short. This process is slow by itself, but it also prevent
the Flash player to simply memcopy the buffers into the GPU data. Thus, using ByteArray should really
speed up the upload of the streams data to the GPU
and make it as fast as possible. This difference should be even bigger on low-end and
mobile devices.

Finally, it also makes it a lot faster to load external assets because it is now possible to memcopy
chunk of binary files directly into vertex/index streams. It should also prove to be very very useful
for a few exclusive – and quite honestly truly incredible – features we will add in the next few months.

What does it change for you ?

If you’ve never been playing around with the vertex/index streams raw data, it should not change a single
thing in your code
. For example, iterators such as VertexIterator and TriangleIterator will keep working just the way
they did. A good example of this is the TerrainExample, who runs just fine without a single change.

If you are relying on VertexStream.lock() or IndexStream.lock(), you will find that those methods now
return a ByteArray instead of a Vector. You should update you code accordingly. If you want to see a good example of ByteArray manipulations for streams, you can read the code of the Geometry.fillNormalsData() and Geometry.fillTangentsData() methods.

What’s next?

This and some recent additions should make it much easier to keep streams data in the RAM without wasting too much memory and be able to restore it on context device loss. It’s not implemented yet but it’s a good first step on this complicated memory management path.

Another possible feature would be to store streams data in compressed ByteArray. As LZMA compression is now available, it could save a lot of memory. The only price to pay would be to have to uncompress the data before being able to read/write it.

Tutorial: Add pixel-perfect 3D mouse interactivity

In this tutorial we’re going to see how you can add pixel-perfect 3D mouse interactivity. I’ve already introduced a technique called “ray casting” in another article. But it works only with very basic static shapes. And sometimes, testing very complex shapes can be very painful performance wise. It’s even more expensive when you want it to be very precise.

In this article, we will see a technique called “pixel picking”. This technique uses hardware acceleration to provide pixel perfect mouse interactivity. It works very well for both static and animated models. The concept is very simple: we render the scene with one color per mesh. Then, we just have to get the pixel under the mouse cursor to know what mesh is “interactive”. Of course, things are much more complicated in the real life: this kind of stunts are pretty hard to push properly in a general purpose rendering pipeline.

But Minko provides everything required out of the box! Even better, the minko-picking extension features a simple controller – the PickingController – that provides all the mouse signals we might need! This tutorial will explain how to setup the PickingController and listen for the mouse signals.


Pixel picking test application (sources)

Create and setup the PickingController

The first step is to instanciate a new PickingController:

The constructor takes only one argument: the “picking rate” of the controller. This value will determine how many times per second the controller will try to execute the picking pass and the relevant mouse signals. The lower the picking rate, the better the performances. A picking rate of 30 should be more than enough for 99% of the applications. You can also set that value at any time using the PickingController.pickingRate property:

Setting the picking rate to the half of the frame rate will work just fine for most applications and should be completely painless performance wise. By default, the picking rate is fixed to 15.

Set the mouse events source

The job of the PickingController is to listen for the mouse events on one (or more) specific dispatcher(s) and re-dispatch them as mouse signals. The difference between the original events and the signals executed by the PickingController is that the signals are aware of the 3D scene. To setup the dispatcher to listen, you just have to call the PickingController.bindDefaultInputs() and provide the IDispatcher object to listen:

Setup the PickingController on the 3D scene

In most cases, you don’t want the whole 3D scene to be mouse interactive. Sometimes it’s just a Mesh or a Group. The PickingController can be added to any Mesh/Group so it’s easy to target precisely what is interactive and what is not. The basic use case is to add mouse interactivity on a single Mesh:

BUt you also might want to listen for the mouse signals trigerred by a whole sub-scene instead of a single mesh. For example, some skinned 3D assets have multiple meshes animated by a single skeleton. To do this, we can add the PickingController on Group:

In the code snippet above, the PickingController will execute mouse signals for all the Mesh descendants of the target group. You don’t have to worry about the descendants of the groups targeted by a PickingController: it will listen for the Group.descendantsAdded and Group.descendantsRemoved to start/stop tracking any descendant Mesh added to this part of the scene.

Thus, if your whole 3D scene is interactive, you can add the PickingController directly on the Scene node:

Listen for the mouse signals

To catch 3D mouse events, you just have to add callback(s) to any of the PickingController.mouse* signals. The available signals are:

  • mouseClick, mouseDown, mouseUp: executed when the left button is clicked, down or up
  • mouseRightClick, mouseRightDown, mouseRightUp: executed when the right button is clicked, down or up
  • mouseMiddleClick, mouseMiddleDown, mouseMiddleUp: executed when the right button is clicked, down or up
  • mouseDoubleClick: executed when the user makes a double click
  • mouseMove: executed when the mouse moves
  • mouseWheel: executed when the mouse wheel turns
  • mouseRollOver, mouseRollOut: executed when the mouse roll over/out a mesh

The following code sample will catch the left and the right click signals:

It would be too difficult to use the PickingController if the mouse signals where triggered only when an actual 3D object is under the cursor. For example, it would be pretty hard to select/unselect objects without listening to some actual 2D mouse events. The code would then quickly become very complicated to mix both 2D mouse events and 3D mouse signals.

Therefore, the mouse signals are triggered whenever the corresponding mouse event is dispatched (and when the picking rate allows it of course). As a direct consequence, the mesh : Mesh argument is null when there is no actual interactive 3D object under the mouse cursor.

Conclusion

You can find the complete source code of the picking example demo in the minko-examples repository on github. If you have questions/suggestions regarding this comment, you can ask them in the comments or on Aerys Answers, the official support forum for Minko.

Tutorial: your first mobile 3D application with Minko

As you already know I’m sure, you can build Android and iOS devices with the Flash platform. And Stage3D is also available on those devices! As a matter of fact, Stage3D was especially designed to work on mobiles. And so was Minko! We put a lot of efforts in building a robust and fast engine that will work on most mobile devices. This tutorial will start where the “Your first Minko application” tutorial stopped and explain what needs to be done to get it working on mobile.

Create your mobile project

The first thing to do is – of course – create a mobile project. With Flash Builder it is very simple: you just have to go into File > New > ActionScript Mobile Project. If you need a little reminder of how to bootstrap your project/development environment, you can read the “Getting started with Minko” tutorial. The only difference compared to creating a desktop/wepp application is to uncheck “BlackBerry Table OS” in the Mobile Settings panel: Stage3D is not yet available on BlackBerry devices. There is an issue opened on the BlackBerry tracker if you want to vote for it!

Configure the application

Now our project has been created we just have to make sure it can use the Stage3D API. It implies two little changes in the app.xml file (this file is named after your main class, most of the time it’s Main-app.xml):

  1. renderMode has to be set to “direct”
  2. depthAndStencil has to be set to “true”

Here is a basic example of a properly setup app.xml file for AIR 3.2:

Bootstrap the Main class

That’s the beauty of the Flash platform, Stage3D and Minko: the project boostrap aside, the code of the application is exactly the same whether you are working on a desktop, web or mobile application! Therefore, you can bootstrap your Main class by following the “Your first Minko application” tutorial!

Basically, you just have to copy/paste the MinkoApplication sample class…

… and make your Main class extend it:

Run your mobile application for the first time

If you use Flash Builder, it will display the Debug Configurations panel when you will try to run/debug your mobile application for the first time. This panel does not have anything special regarding Stage3D or Minko, but it’s still a good thing to see the basics! There are two important fields on the panel:

  1. The “Target platform” field will specify what device you want to target for this debug session.
  2. The “Launch method” field will specify whether you want to run the application in the desktop device emulator or directly on the device. Of course, the “On device” method is better if you want to have a preview of the actual performances.

Display your first 3D object

Now that our project is setup and that we can launch it on the device or in the emulator, we will display our first 3D object. You just have to follow the “Display your first 3D object” tutorial for your mobile project. Here is what you’ll get if you choose to run it on the desktop emulating the iPhone4 device:

You can also directly download the sources for this project!

If you have questions/suggestions regarding this tutorial, please post in the comments or on Aerys Answers, Minko’s official support forum.

Minko Weekly Roundup #1

Updates are committed every day. Demos are starting to pop from third party developers. And I clearly don’t have enough time to write an article about each of them! So I got the idea to write little summaries of what happened during the (past few) week(s). Here we go!

Demos

Smooth shadows

We’ve been working a lot to give the user more control on the shadow quality. One of the options now involves shadow smoothing. This features is available on all lights but the PointLight for now:

Click to view the live shadow smoothing demo

This new feature and the corresponding examples should be available in the public repository next week.

Points/particles rendering

minko-examples has been updated with a points/particles rendering example. The code includes both the geometry and the shader required to draw massive amounts of particles. It also demonstrates how one can built simple animations directly on the GPU:

Click on the picture to launch the PointsExample app.

Yellow Submarine

A little demo done by Jérémie Sellam (@chloridrik), developer at the “Les Chinois” interactive agency in Paris, France. The demo mixes my terrain generation example, texture splatting, points rendering and a custom displacement shader to simulate an underwater trip in control of a yellow submarine:

The submarine model was imported and customized using Minko Studio. In a few minutes, Jeremy was able import the original Collada asset, customize it with alpha blending and environment mapping and export an optimized compressed MK file.

Color Transition Shader

Another great work from Jérémie Sellam who implemented a very nice transition effect using nothing more but the public beta of the ShaderLab:

If you cannot run this demo, there is a video of this nice color transition shader on Youtube.

Answers

Tutorials

Features

  • Support for multiple shadows in Minko Studio.
  • New geometry primitives: ConeGeometry and TorusGeometry
  • Normals flipping: you can now flip (= multiply by -1) the normals (and tangents) of a geometry by calling Geometry.flipNormals(). We will soon add an IndexStream.invertWinding() method to be able to fully turn any shape inside out without bugging the shaders that might rely on the normals/tangents.
  • Merging geometries: you can now merge two Geometry objects. Used along with Geometry.applyTransform(), it makes it very easy to merge any static objects.
  • Disposing local geometry data: you can now dispose the entire geometry data (IndexStream + all VertexStreams) with a single call to Geometry.disposeLocalData().
  • New Matrix4x4 methods: Matrix4x4.setColumn(), Matrix4x4.getColumn(), Matrix4x4.getRow() and Matrix4x4.setRow().

Fixes

Tutorial: Display your first 3D object with Minko

Now that we’ve seen how to bootstrap an empty Minko application, it’s time to learn how to display a simple 3D primitive.

Step 1: The Camera

In order to display anything 3D, we will need a camera. In Minko, cameras are represented by the Camera scene node class. The following code snippet creates a Camera object and adds it to the scene:

By default, the camera is in (0, 0, 0) and looks toward the Z axis. We must remember this when we will add our 3D object in the scene: we must make sure it’s far enough on the Z axis to be visible!

Step 2: The Cube

A Mesh is a 3D object that can be rendered on the screen. It is somekind of 3D equivalent of the Shape class used by Flash for 2D vector graphics. But in 3D. As such, it is made of two main components:

  1. a Geometry object containing the triangles that will be rendered on the screen
  2. a Material object defining how that very geometry should be rendered

Creating a Mesh involves passing those two objects to the Mesh constructor:

There are many primitives available as pre-defined geometry classes in Minko: cube, sphere, cylinder, quad, torus… Those classes are in the aerys.minko.render.geometry.primitive package. You can easily swap the CubeGeometry with a SphereGeometry to create a sphere instead of cube for example.

The BasicMaterial is the material provided by default with Minko’s core framework. It’s a simple material that can render using a solid color or a texture. Here, we use it with a simple color. To do this, we simply set the BasicMaterial.diffuseColor property to the color we want to use with an RGBA format.

Remember: the camera is in (0, 0, 0) and – by default – so is our cube. Therefore, we have to slightly translate our cube on the Z axis to make sure it’s in the field of view of the camera:

We will introduce 3D transformations in details in the next tutorial.

Conclusion

To make it simple, our main class will extend the MinkoApplication class detailed at the end of the previous tutorial. We will simply override its initializeScene() method to create our cube, our camera and add both of them to the scene:

And here is what you should get:

If you have questions or suggestions, you can post in the comments or on Aerys Answers!