So, today is the last day of this year's Google Summmer of Code (although the date on the post will say it's August 17, it's still August 16 where I am =]). Time surely has flown by! I was really worried at the beginning of the program, there was a lot of code I had to get used to, and I still didn't know exactly how some things had to be done. But in the end, everything worked out, and I believe this project was a great success.
I was able to finish all the tasks that were on the original proposal, with minimal adaptations. I also documented everything as well as I could, both with comments in the code and posting the details in this blog. There are two demo applications as well, to show how the API should be used.
I would like to thank everyone from CrystalSpace for the opportunity, specially my mentor Andrew. People have been very helpful and friendly since our first contacts, during the GSoC applications period. I hope the code produced during this program can be put to good use.
Please feel free to contact me at anytime by mail. I will also stick around the IRC channel.
This last week I have made a few changes to the code, and I thought it would be good to make one post to talk a little about them.
First and most important, I found a problem with the demo application (not exactly a bug, more of a map misbehavior). If you plot a path going from the stairs in the basement01 sector to the basement03 sector, near the basement-dungeon sector, the path is likely to go below the stairs and through a wall. After careful examination, I realized this was actually caused by some parts of navigation meshes that were created below the stairs, due to the level geometry. Since Detour searches for the polygon nearest to the path's starting point, one of the polygons in this disconnected piece of mesh was being chosen, which caused the problem. In order to fix this, I altered the portal's polygon position for the portals that connect basement01 and basement03 in the world xml file, moving them up a little (the portal polygons were going below the stair level).
Here is the modified world file: link.
Second, I changed the DebugRender methods to return a list of csSimpleRenderMesh instead of drawing the structures directly using OpenGL. Notice that now you don't have to (read you shouldn't) call those methods every frame, only when the structure being drawn changes (you have to ask the iGraphics3D plugin to draw the meshes every frame, however).
Finally, I added another hotkey to the pathfindingtest application. Upon pressing 't', a path will be calculated between two predetermined points. This path will then be compared to a path previously calculated, and an error message will be displayed if they differ. If the paths are equal, nothing will happen.
I have added a new parameter to the iCelNavMeshParams class, polygonSearchBox. Here is a detailed description (copied from the parameter values post):
"Before creating a path, Detour finds the closest polygons in the navigation mesh to the origin and destination points. This parameter determines the dimensions of the bounding box where Detour will look for the closest polygons. The bounding box is represented by two vertices: (center + polygonSearchBox) and (center - polygonSearchBox), where center is the point one wants to find the closest polygon to.
This parameter is also used to determine if a low level path that was calculated by Detour reaches it's intended destination (Detour always returns a path, either to the destination or the closest possible point). If the distance between the two points, in each of the coordinates, is less then this parameter, then they are considered to be close enough for this purpose."
One simple way to understand this parameter using the demo application is clicking on a point that is not exactly on the navigation mesh. For example, consider clicking on the walls: the greater the y coordinate of the polygonSearchBox, the higher you can click on the wall and still have the path traced.
If some object changes position in a map, instead of rebuilding the whole navigation structure, one can update it using the iCelHNavStruct::Update() method. This method takes a bounding box and a pointer to a sector as parameters (although the sector is optional): the bounding box describes the area of the navigation mesh that one wishes to update, and the sector determines which sector should be updated. If no sector is specified, then the bounding box will be collided with each of the sectors navigation meshes' bounding boxes to determine what sectors have to be updated.
Note that this should probably not be used for objects that are on constant movement (npcs for example), since it's not very fast. This can be seen on the apppathfindingtest application by pressing 'y' (check last modifications to the demo application on this post).
Although updating a navigation structure takes some time, it is still way faster then rebuilding it.
In order to showcase the updating capabilities of the navigation structure, I have added a large stone block to the initial sector of the path finding demo application. This block moves linearly back and forth between two points near the stairs, and it is taken into account when building the navigation structure.
I also added some new hotkeys to this application, here is a description:
Finally, after a lot of efforts and a lot of hardwork, lighter2 is able to produce caustics. Also a lot of bugfixes have been made in the original code, the major one being the one with lighting produced with the photons. The power of photons had to be scaled to match the illumination of raytracer, there is no need for that now.
Ok, enough of talking here is something pleasant for your eyes.
(This image was generated without any scaling of photons, and with only photon mapping enabled for direct as well as indirect lighting)
Now, regarding the intricacies of getting photon mapping working.
1.) Added a tag into the world file regarding the material, about whether it can produce caustics or not, also if it can produce caustic, what is the refractive index of the material. (For air the refractive index is considered to be 1, also if it is not mentioned for a caustic producing material, it is assumed to be 1. So, the caustics might not be that accurate, if one doesn't mention the refractive index.)
2.) While parsing the scene, the positions (Bounding spheres) of all the meshes which contain the material which can produce caustics are stored in a list. This list is used in the photon emission stage. The point light is considered to be like a spotlight which emits photons only in the direction of these meshes while emitting caustic photons.
3.) The photon tracing is facilitated with refracting these caustic photons, these photons are traced till the time they hit a diffuse surface, and instead of reflecting these photons in random direction they are refracted using simple laws of refraction (this is the point where refractive index is required).
4.) Finally in the final gathering stage it is not just the normal photon map which is used but also the caustic photon map.
(A lot of debugging and reworking also went into this process, which took all this time)
As for the future, I am trying to gt support for direction and spotlight lights for photon mapping and caustics, and also area lighting. I plan to get these working before the submission date for GSoC, and then it would be time for optimizing lighter2, in my opinion the memory optimization should be of higher priority than time optimization.
Although building navigation structures only take a couple of seconds (at least for the maps in CrystalSpace), it's important to be able to save and load them to/from files.
Since the navigation structures are composed of one navigation mesh for each sector and some extra information (like the name of the sectors contained in the navstruct and the high level graph), I decided the best way to save them was creating a zip file, containing one file for each navmesh and one file with some general information. These files are all serialized to XML.
To save each navmesh, the iCelNavMesh::SaveToFile() method is used. It receives as a parameter a iFile, which is where it will save the data to. To save navigation structures, iCelHNavStruct::SaveToFile() is used. This is the method that will probably be called by the user. It receives a pointer to the virtual file system and a char array as parameters, and will save the zip file in the current directory of the VFS, with the name described by the char array.
To load navigation structures, iCelHNavStrucBuilder::LoadHNavStruct() is used. It receives a pointer to the VFS and a file name, just like the SaveToFile method, and expects the file to be on the current directory of the iVFS received. It will open the zip file, read the main file and then call iCelNavMeshBuilder::LoadNavMesh() for each navigation mesh. It's important to notice that the load methods are in the builder classes, so the only way to create (either new or load) both navigation meshes and structures is from the builder classes.
In the demo application, loading the navigation mesh for the castle map is significantly faster then building it.
|<< <||Current||> >>|
This is the long description for the blog named 'Blog All'.
This blog (blog #1) is actually a very special blog! It automatically aggregates all posts from all other blogs. This allows you to easily track everything that is posted on this system. You can hide this blog from the public by unchecking 'Include in public blog list' in the blogs admin.