In addition to voxel-maps you can now also use height-maps to generate a terrain in YAOGL. Here is an example:

    YATerrain* terrain = [[YATerrain alloc] init];
    [terrain generate];
    [world createHeightmapTexture:terrain withName:@"terrainHeightMap"];

    NSString* terrainIngredientName = @"terrain";
    __block YAIngredient* terrainIngredient = [world createIngredient:terrainIngredientName];
    [terrainIngredient setFlavour:Terrain];
    [terrainIngredient setTexture:@"terrainHeightMap"];

    YATriangleGrid* grid = [[YATriangleGrid alloc] initWithDim:32];
    [terrainIngredient createModelfromGrid:[grid triangles]];

    int terrainImpId = [world createImpersonator:terrainIngredientName];
    YAImpersonator* terrainImp = [world getImpersonator:terrainImpId];

The major new feature in Blender 2.63 is BMesh. BMesh is the new data structure to handle your model data. If you have written you own export script to avoid the use of extensive xml or text based exchange languages like collada or wavefront it is now necessary to update it. The use of binary (BSON) exports is one reason why YAOgl only needs milliseconds for the startup process.

Your script will most likely look like this(I assume that you split these commands in different methods):

for obj in bpy.data.objects:
    ...
    faces = obj.data.faces
    vertices = obj.data.vertices
    facesMaterials = obj.data.materials
...

With these commands you collect the faces, vertices and materials of your model. In Blender 2.63 the faces attribute will be replaced with tessfaces. The “tesselated faces” attribute contains the list of all triangulated ngons. You can now update your script like this:

for obj in bpy.data.objects:
    ...
    obj.data.calc_tessface()
    faces = obj.data.tessfaces
    vertices = obj.data.vertices
    facesMaterials = obj.data.materials
...

The method calc_tessface() is used to calculate and update the list of tessellated faces.

Example of an exported model.
Example of an exported model.

UV Maps

If you are using uv maps for textures, normals or ambient occlusion you also have to take the new data structure into account. For example:

facesuvs = o.data.uv_textures.active.data

shoud be changed to:

facesuvs = o.data.tessface_uv_textures.active.data

I checked these modifications against several unit-tests without any noticeable problems.

Here are the first results for:

Sorting 50.000.000 (50 Million) random elements.

Java 7Objective C (Heap)Scala 2.9 (Concurrent)OpenCL (Bitonic)
sec.55,68712,2383,6810,372

For OpenCL the “copy to memory” time was included and for Java and Scala the launch time was excluded from the result.

OpenCL programming is in several ways restricted. The local memory of a kernel is bounded to 32MB. OpenCL isn‘t available on all devices(hosts) and the driver quality differs between different vendors.

Therefore I will initially limit the availability of my library to OsX systems.

Also I abandoned the idea to embed OpenCL inside a guest language. I worked with frameworks for embedded DDL/SQL, Javascript, XML and many more. These solutions always tend to be too extensive and during the “translation process” often performance is lost.

However, If you are interested in embedded solutions take a look at:

As a consequence my library will consist of OpenCL include files. Programs have to be written in the „OpenCL Programming Language“. OpenCL commands like context creation, program compilation etc. are managed by the framework.

What are the base functions?

With OpenGL and scientific applications in mind I started with:

  • Sorting
  • Searching
  • Scheduling
  • Packing
  • LS solving

and

  • N-trees

This library will complete my toolset for developing modern desktop and tablet applications.

Since most modern algorithms and data structures for cg are designed for fast parallel processing I began to play with OpenCL.
Examples therefor are algorithms for physically correct lighting or spatial data structures.

For an easy start I took a simple algorithm and ported it to a kernel:

A perfect number is a positive integer that is equal to the sum of its proper positive divisors. (Wikipedia)

To evaluate a number for perfection, it is necessary to factorize it. A very simple way to do this is a for loop:

__kernel void perfectNumber(__global int * Number, __global int *FACSum)
{
    int i = get_global_id(0);

    int testNumber = Number[i];
    int result = 0;

    for(int f = 0; f <= testNumber / 2; f++) {
        result += testNumber % f == 0 ? f : 0;
    }

    FACSum[i] = result;
}

The program (kernel) is uploaded to the GPU. The remaining task for the CPU is to feed the GPU with new values.

To ensure that only the GPU is used, it is necessary to filter the desired device-type:

clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, &ret_num_devices);

In my demo, I stopped the calculation after the fifth result:

An atlantic manta (modeled with Sculptris) and its little blue offspring (modeled and rigged with Blender)

I’m using this scene to check my exporter-scripts against the latest application updates.

It is now possible to use HI Devices like gamepads, joysticks for object or camera movement.

Here is a short demonstration of this feature:

    YAHIDAnimator* gamepad = [world createHIDAnimator];
    [gamepad addListener:[voxelCubeImp rotation] factor:90];

    YABasicAnimator* rotZ = [world createBasicAnimator];
    [rotZ setProgress:harmonic];
    [rotZ setInterval:0.5f];
    [rotZ addListener:[voxelCubeImp rotation] factor:5];
    [rotZ setInfluence:z];

This new animation class can be combined with any other animation method:

The iso-surface of a voxel map is now simultaneously updated with the change of voxel-densities. In this demo following code was used to produce a growing cube effect:

        const char growth = 120 / 10; 

        for(int i = 0; i <= 25; i++) {
            int xP = 10 + (rand() % (33 - 20));
            int zP = 10 + (rand() % (33 - 20));

            if( (xP > 12 && xP < 20) && (zP > 12 && zP < 20) )
                continue;

            int yP = 1;
            while(yP < 31 && [voxelMap getVoxel:xP :yP :zP] > 1 )
                yP++;

            if(yP < 15) {
                char d = [voxelMap getVoxel:xP :yP - 1 :zP];

                if(d < 120)
                    [voxelMap setVoxel:d + growth x:xP y:yP -1 z:zP];
                else
                    [voxelMap setVoxel:growth x:xP y:yP z:zP];
            }
        }

        if(voxelMap.hasChanged) {
            [voxelMap updateIso];
            [voxelMapIngredient updateTriangles:[voxelMap vbo]];
        }

For each frame about 25 voxels are changed. The method updateIso is used to recalculate the mesh data. The voxel algorithm is fast enough to run exclusively on the CPU.