|
FeffersHat, Newbie
Posted: 01 May 2012 01:34 PM Total Posts: 21
I’m creating a game were there is randomly generated cubes on a floor. About 370 cubes are being generated. Of course, with so many cubes being created and rendered on the same screen, the application would lag. So how would I go about optimising this? The cubes are static so they don’t move, but the camera does. I was thinking about putting them in a 3d object container and then maybe it would only render the container instead of all 370 cubes? But that did not work. I really don’t know how to go about optimising this so some help would be really great. (:
By the way, away3D is great!
|
Matse, Sr. Member
Posted: 01 May 2012 01:48 PM Total Posts: 149
[ # 1 ]
Hi FeffersHat,
You can get enormous performance boost by merging meshes that share the same material using the Merge class. I recently did this with stunning results. I had quite a few troubles to get it to work at first, and was thinking about sharing some generic function or class for handling this… I’ll try to get some time to do this today.
Keep in mind that merging meshes will turn them into a single mesh, so if your game level or 3D world is big you might want to use a mix of partitionning and merging. For example merging all the trees in a given area makes sense, merging all the trees in your world/level does not
Let me know if you’re interested in my merging code, that might just give me the motivation to get it and post it ^^
|
FeffersHat, Newbie
Posted: 01 May 2012 02:27 PM Total Posts: 21
[ # 2 ]
Yeah, I’m definitely interested!
Thanks for posting.
|
FeffersHat, Newbie
Posted: 01 May 2012 03:13 PM Total Posts: 21
[ # 3 ]
I found a website that helped me share mesh’s between each other. Apparently it’s a lot faster, however when I try myself with my code it lags just as much. Am I doing something wrong or does it not really matter and is your Merge class more important?
|
Matse, Sr. Member
Posted: 01 May 2012 03:29 PM Total Posts: 149
[ # 4 ]
Sharing Geometry and Materials whenever possible is a good starting point, everyone should do it. Not sure how you create your cubes for example, typically you should only create one and then clone it to get as many as you need (or create new meshes using the first cube’s Geometry).
This definetely helps, but there’s a lot more to gain by using clever merging.
I have to stress out the Merge class is not mine : it comes with Away3D
I just wrote some code to make it easy to use. That code is not generic yet as it was written to fit my current game project, still it should be usable as is or easy to adapt to other situations.
Here you go :
package { import away3d.containers.ObjectContainer3D; import away3d.entities.Mesh; import away3d.tools.commands.Merge; import away3d.tools.helpers.MeshHelper; /** * ... * @author Matse */ public class MergeHelper { private static var _mergeTool:Merge = new Merge(); public static function mergeContainer($container:ObjectContainer3D):void { var lib:Object = { }; var mesh:Mesh; var srcMesh:Mesh; var meshList:Vector.<Mesh>; var i:int; var count:int = $container.numChildren; // browse meshes in container and store them // by their material name for (i = 0; i < count; i++) { mesh = $container.getChildAt(i) as Mesh; if (mesh == null) continue; if (lib[mesh.material.name] == null) { lib[mesh.material.name] = new Vector.<Mesh>(); } lib[mesh.material.name].push(mesh); } // now merge meshes per material for each (meshList in lib) { srcMesh = meshList.shift(); if (meshList.length > 0) { mesh = new Mesh(srcMesh.geometry.clone(), srcMesh.material); mesh.castsShadows = srcMesh.castsShadows; $container.addChild(mesh); mesh.rotationX = srcMesh.rotationX; mesh.rotationY = srcMesh.rotationY; mesh.rotationZ = srcMesh.rotationZ; mesh.x = srcMesh.x; mesh.y = srcMesh.y; mesh.z = srcMesh.z; MeshHelper.applyRotations(mesh); MeshHelper.applyScales(mesh, srcMesh.scaleX, srcMesh.scaleY, srcMesh.scaleZ); MeshHelper.applyPosition(mesh, srcMesh.x, srcMesh.y, srcMesh.z); _mergeTool.applyToMeshes(mesh, meshList); for each (mesh in meshList) { $container.removeChild(mesh); mesh.dispose(); } $container.removeChild(srcMesh); srcMesh.dispose(); } } } }
}
The function expects an ObjectContainer3D that contains all meshes you want to merge together.
It will then “analyze” meshes, sort them per material, and merge all meshes that share the same material.
Once this is done, all initial meshes that were merged are disposed and removed from the container. The container will only contain merged meshes and meshes that didn’t share a material with others.
Caution : the code expects the materials to be named, I’d have to change that, not sure what will happen with unnamed materials.
File Attachments
|
FeffersHat, Newbie
Posted: 01 May 2012 03:50 PM Total Posts: 21
[ # 5 ]
Thanks a lot for that!! :D
To be honest, I’m quite new to 3D so I don’t really understand this class that well. I understand most of it, just not exactly sure how it works.
Anyway, I’m getting some errors when I test it. Here are the errors.
I also had to change the imports to the correct ones because for some reason yours was located in a different place. :/
Here is my class that is practically just copied from you. I will change it around once I get all these errors out, though.
Anyway, so, I’m not really sure why these errors are here. For example, you used “_mergeTool.applyToMeshes” but there is no variable named mergeTool defined.
|
Matse, Sr. Member
Posted: 01 May 2012 04:06 PM Total Posts: 149
[ # 6 ]
Looks like you are using an old version of Away3D, while I’m using Away3D Beta 4, which is the current “official” version. This is why you had to change the imports.
I recommend that you get the Beta version from GitHub :
https://github.com/away3d/away3d-core-fp11
Obviously you will have to change a few things in your code, but shouldn’t be much trouble.
If you look at my code I have a static var named “_mergeTool”, you renamed it to “mergeTool” in your class
Also your first link doesn’t show errors but the code you use to create your walls. Not sure what you’re asking for here ?
|
FeffersHat, Newbie
Posted: 01 May 2012 04:26 PM Total Posts: 21
[ # 7 ]
Ah, thought I already had the newest version.
Anyway, thanks for everything, I’m going to sleep now but I’ll try everything tomorrow and report back.
Thanks again (:
|
John Brookes, Moderator
Posted: 01 May 2012 06:09 PM Total Posts: 732
[ # 8 ]
matse
Merge already has an applyToContainer method.
|
Matse, Sr. Member
Posted: 01 May 2012 07:36 PM Total Posts: 149
[ # 9 ]
Thanks John, I tried all methods from Merge class before I wrote this up.
That was about a week ago and I’ve been crunching non stop since then so I don’t remember the details exactly : if the default methods from Merge suits your needs that’s fine, but I know the only way that worked for me was this one.
If I remember correctly it will produce weird results when the first model, which becomes the “merge all meshes in that one” is offsetted and / or rotated, scaled…
Also again if I’m correct, it won’t work with a null mesh whereas it seems it should.
The 3 lines that really solved my issues with the Merge class are :
MeshHelper.applyRotations(mesh); MeshHelper.applyScales(mesh, srcMesh.scaleX, srcMesh.scaleY, srcMesh.scaleZ); MeshHelper.applyPosition(mesh, srcMesh.x, srcMesh.y, srcMesh.z);
Without that, it would always produce weird results with either all models correct except the first one or the opposite. Except if the first model was not rotated, not scaled, and at 0,0,0 position.
I guess the mergeContainer method from the Merge class will work fine when testing with simple cases, my little function works perfectly fine on a full game level (with *lots* of meshes, most of which are rotated and/or scaled and/or not at 0,0,0 position)
But again if the methods from Merge work for you then all good : don’t fix what isn’t broken
edit : oh and that line is pretty important too
mesh = new Mesh(srcMesh.geometry.clone(), srcMesh.material);
Here is a screen from a test that I did without that line :
http://tof.canardpc.com/view/e587ffa4-5396-478b-a57a-78cb4f266d19.jpg
See all those barrels ? I have a single barrel Geometry, used for all barrels, and I have barrel piles. If I merged a container containing a pile of barrels, that’s the kind of results I would get as the Geometry for all barrels gets modified during merge.
So it starts with the first barrel, takes the second one, merges it in… all barrels are now made of 2 barrels. Add more and more, and you will see barrels everywhere as they all share the Geometry that gets affeccted by the merging.
|
FeffersHat, Newbie
Posted: 02 May 2012 02:59 AM Total Posts: 21
[ # 10 ]
Worked perfectly, Matse, thanks a lot! :D
Also, Matse, that’s a LOT of Barrels. O.o
Edit: I have a feeling this is something to do with the new away3D, but when I try and do a collision test…
if (Collisions.test(Char.character, wallArray[j])) {
public static function test(model1:Mesh, model2:Mesh):Boolean { //intersecting function that calculates whether 2 models collide with each other // Use up to 6 separating planes if ( model1.maxX + model1.x < model2.minX + model2.x ) return false; ... ect, ect
I get the error:
TypeError: Error #1009: Cannot access a property or method of a null object reference. at away3d.bounds::BoundingVolumeBase/fromGeometry()[C:\Users\Rich\Desktop\New Game\Project\src\away3d\bounds\BoundingVolumeBase.as:122]
All my character is, is a mesh. My wall array is just an array of the wall mesh created and pushed in the array. I then push the wall inside my wall container and after all that has done, I merge the wall container.
Am I doing something wrong?
|
Matse, Sr. Member
Posted: 02 May 2012 09:54 AM Total Posts: 149
[ # 11 ]
Also, Matse, that’s a LOT of Barrels. O.o
Yeah, I was pretty much amazed that I still had 10 fps on my laptop with 10 Millions triangles on screen (not sure how many meshes that was), and that it didn’t exceed the 15 seconds timeout :D
I can’t say much about collisions in away3d as that’s an area I haven’t looked into yet. Still I think what happens here is that the wall models that you’re testing against are not “there” anymore since they were disposed by my merging function earlier and so they don’t have a bounding box anymore even though you still have references to them.
Or something along those lines
If you test against the merged mesh’s bounding box you’ll most probably get weird results as its bounding box will be one that has all the walls geometry inside of it.
You could just try to comment out the two lines where I dispose meshes in the function : the original wall meshes won’t be displayed but their bounding box will still be there and so I guess testing collisions against them would work ? Not sure but worth a try.
|
FeffersHat, Newbie
Posted: 02 May 2012 11:03 AM Total Posts: 21
[ # 12 ]
Oh yeah that makes sense. However, I’m just going to do collision with a 2D Array as the map is basically a grid and it’s much more efficient, although harder to maintain and create.
Thanks a ton for all the help though! :D
|