Question

I have created a simple test using Away3D 4.1 (2500 cubes) but performance is a lot lower than i expected - only 10 FPS.

I assume i am making a noob mistake (being a noob and all) so here are relevant pieces of code:

Lighting:

var light1:DirectionalLight = new DirectionalLight();
light1.position = new Vector3D(400, 300, -200);
light1.lookAt(new Vector3D());
light1.color = 0xFFFFFF;
light1.ambient = 0.25;
lightPicker = new StaticLightPicker([light1]);

Creating cubes:

var material:ColorMaterial = new ColorMaterial(0x999999);
material.lightPicker = lightPicker;
material.specular = 0;
var mesh:Mesh = new Mesh(new CubeGeometry(50, 50, 50), material);

for (var i:uint = 0; i < 50; i++)
{
    for (var j:uint = 0; j < 50; j++)
    {
        var cube:Mesh = Mesh(mesh.clone());
        cube.x = 100*(i-25);
        cube.y = 25;
        cube.z = 100*(j-25);
        scene.addChild(cube);
    }
}

And the camera:

camera = new Camera3D();
camera.position = new Vector3D(0, 1000, -5000);
camera.lookAt(new Vector3D(0, 0, 0));
camera.lens.far = 10000;

Stage3D output in Scout shows that there are many calls between each drawTriangles call and my basic understanding tells me that drawTriangle calls should be 'batched'.

I know that some other frameworks have batch methods but i havent been able to find anything related to Away3D.

Thanks in advance for any help.

Was it helpful?

Solution 2

Yeah, you should batch your draw calls. I don't have much experience with Away3D but after a quick look through their API reference it seems that away3d.tools.commands.Merge should help you to merge all those cubes into one large batched mesh.

OTHER TIPS

It looks like Merge (thanks to Varnius for spotting that) is the recommended way to do it with previous versions, but it doesn't work in 4.1 (see away3d forum thread).

However, user kurono posted a solution in the forum that works (at least for my scenario) so i reproduce it here in case anyone else has the same problem:

var material:ColorMaterial = new ColorMaterial(0x999999);
material.lightPicker = lightPicker;
material.specular = 0;
var mesh:Mesh = new Mesh(new CubeGeometry(50, 50, 50));
var meshes:Vector.<Mesh> = new Vector.<Mesh>();
for (var i:uint = 0; i < 50; i++)
{
    for (var j:uint = 0; j < 50; j++)
    {
        var cube:Mesh = Mesh(mesh.clone());
        cube.x = 100*(i-25);
        cube.y = 25;
        cube.z = 100*(j-25);
        meshes.push(cube);
    }
}
var bigMesh:Mesh = doMerge(meshes, material);
scene.add(bigMesh);

The magic is in the doMerge() method:

function doMerge(meshes:Vector.<Mesh>, material:MaterialBase):Mesh
{
    var isub:ISubGeometry;
    var rawVertsAll:Vector.<Number> = new Vector.<Number>();
    var rawIndicesAll:Vector.<uint> = new Vector.<uint>();
    var rawUVsAll:Vector.<Number> = new Vector.<Number>();
    var rawNormalsAll:Vector.<Number> = new Vector.<Number>();
    var rawTangentsAll:Vector.<Number> = new Vector.<Number>();
    var offset:uint = 0;
    var verts:Vector.<Number>;
    var normals:Vector.<Number>;
    var tangents:Vector.<Number>;
    var uvs:Vector.<Number>;
    var indices:Vector.<uint>;
    var i:uint;
    var j:uint;
    var k:uint;
    for (k = 0; k < meshes.length; k++)
    {
        var m:Mesh = meshes[k];
        isub = m.geometry.subGeometries[0].cloneWithSeperateBuffers();
        isub.applyTransformation(m.transform.clone());
        verts = new Vector.<Number>();
        normals = new Vector.<Number>();
        tangents = new Vector.<Number>();
        uvs = new Vector.<Number>();
        indices = isub.indexData;
        for (i = 0; i < isub.numVertices; i++)
        {
            verts.push(isub.vertexData[i * isub.vertexStride + isub.vertexOffset]);
            verts.push(isub.vertexData[i * isub.vertexStride + isub.vertexOffset + 1]);
            verts.push(isub.vertexData[i * isub.vertexStride + isub.vertexOffset + 2]);
            normals.push(isub.vertexNormalData[i * isub.vertexNormalStride + isub.vertexNormalOffset]);
            normals.push(isub.vertexNormalData[i * isub.vertexNormalStride + isub.vertexNormalOffset + 1]);
            normals.push(isub.vertexNormalData[i * isub.vertexNormalStride + isub.vertexNormalOffset + 2]);
            tangents.push(isub.vertexTangentData[i * isub.vertexTangentStride + isub.vertexTangentOffset]);
            tangents.push(isub.vertexTangentData[i * isub.vertexTangentStride + isub.vertexTangentOffset + 1]);
            tangents.push(isub.vertexTangentData[i * isub.vertexTangentStride + isub.vertexTangentOffset + 2]);
            uvs.push(isub.UVData[i * isub.UVStride + isub.UVOffset]);
            uvs.push(isub.UVData[i * isub.UVStride + isub.UVOffset + 1]);
        }
        for (j = 0; j < indices.length; j++)
        {
            indices[j] += offset;
        }
        offset += isub.numVertices;
        rawVertsAll = rawVertsAll.concat(verts);
        rawNormalsAll = rawNormalsAll.concat(normals);
        rawTangentsAll = rawTangentsAll.concat(tangents);
        rawUVsAll = rawUVsAll.concat(uvs);
        rawIndicesAll = rawIndicesAll.concat(indices);
    }
    var geometry:Geometry = new Geometry();
    var subGeometry:SubGeometry = new SubGeometry();
    subGeometry.updateVertexData(rawVertsAll);
    subGeometry.updateIndexData(rawIndicesAll);
    subGeometry.updateUVData(rawUVsAll);
    subGeometry.updateVertexNormalData(rawNormalsAll);
    subGeometry.updateVertexTangentData(rawTangentsAll);
    geometry.subGeometries.push(subGeometry);

    return new Mesh(geometry, material);
}

And voila! 10fps becomes 60fps

Are you getting 10 fps in the debug player or the release version?

I ran your code and get 20 fps in the debug player but 50+ fps in the release version.

I tried merging and didn't see any improvements. Plus, if you want to access the individual cubes, merging will make that quite complicated :)enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top