 Lighting |
Posted - 3/21/2006 2:47:26 PM | More fixes over the last few days. I really feel almost done with the graphics, but then something doesn't look right, and I find out things are quite broken, and have to go in and fix them.
The main thing I fixed this weekend was the entity lighting, which was, how shall we say - completely broken. The diffuse terms were working, which is the largest part of the lighting, but the specular was totally off, and the entity lighting was not consistent with the terrain & static geometry lighting. Also, entity ambient lighting was always 0.2, 0.2, 0.2, and now properly uses the values set by the level designer.
I had a bear of a time remembering how to transform the eye vector into tangent space of a skinned model, even though I believe I was the first to propose the solution to this ( skinning the basis vectors and then going through this modified matrix ) in mid-to-late 2000. I forgot that the tangent space matrix is defined to go from model->tangent space, so you must go world->model->tangent if dealing with an instanced object or animated mesh.
Since the per-pixel lighting on the models was recent, I hadn't taken this into account properly with the specular. When I tried to make the android shiny, it didn't work. A bit of investigation revealed that nothing was shiny anymore.
I also fixed the weapon lighting, which was previously tied to the holding character's lighting in a way that caused even shadow receiving characters ( like your player model ) to darken & brighten overall. Now the weapons use the character's center position as the place to check their lighting from, but store their own light values.
Another fix involved the customizable entity facets not being loaded properly.
I added a rim lighting option to entities. This calculates a 1-n.e term during the ambient pass, so it increases a character's ambient on the edges of the character to give a softer look on clothes, etc. It's pretty subtle on the main char, but looks good on the cultist.

Today I fixed something with the shadow & occlusion ray caster that was driving me crazy for a long time. I finally fixed it b/c the new cave level made the problem incredibly apparent. Basically, when casting a shadow ray towards a light from a piece of geometry, it's possible you will hit the same geometry chunk you are casting from, so you need to somehow offset from the spot, or ignore close hits. If you ignore close hits, or simply offset in the normal direction, you will get a nice bright spot in sharp corners, where you don't hit the triangle 90 degrees from you b/c it's too close to where you started.

One solution I put in today is to make a version of your static geometry with completely shared normals ( even previously sharp edges ). Once you have this, you can offset the raycast start location in this shared normal direction. This way you will push yourself out of corners before casting the ray, allowing the ray to legitimately hit the nearby corners if it should.

| |
 Culling & Open Position |
Posted - 3/16/2006 9:03:07 PM | 
Over the past couple of weeks I have been primarily working on the performance. I can finally say that I'm pretty happy with it.
The new LOD system sped up the rendering & animation a good bit.
The Cell / Portal / Anti-Portal system is working well also, really speeding up all 3 levels right now.
Doors & keys now work, so you can't just go anywhere without the proper key. OMG - gameplay!
I also made doors so they can have an associated portal with them. You add a 'portal' facet to the door, and give it the portal name, like 'Portal_0123', and when the door closes, it will disable the portal, culling the cell contents more aggressively, and when the door is partly open, the portal is marked enabled, and the system processes the cell as normal.
This can be used in certain levels to completely cut off part of the level either before you get there, or after you achieve something. I was thinking the final crypt boss area could have a spiked wall come out and block your return, and this would cut off the portal to save framerate.
I just added better shadow culling. Now I don't bother rendering shadow maps to objects that are more than 3 meters away from the view frustum, as measured by the direction from the light. In other words, if the light is to the left, it takes the object's
visual bounding box, extends it 3 meters to the right, then checks if that is partly visible. If not, it doesn't even render the shadow map at all. This was a large boost on the temple level, where it was drawing a shadow map for every shadow casting entity every frame.
I also changed the skybox to render after the diffuse geometry & z are rendered to save fillrate & bandwidth.
Next week is GDC. If any of you are coming out, I am talking on Thursday at the NVIDIA Performance Tools talk, where I will be demonstrating NVPerfHUD with Ancient Galaxy.
We are also looking for a coder local to the Bay Area ( Our office is in Sunnyvae ) who wants to join the team, either part-time or full-time. Paid programmers as well as interns can apply. At this point, I don't think someone remote will work, as we have a lot of integration to do.
If there are any game designer types, we will be setting up an alpha night in a few weeks. If you are interested in giving design & gameplay feedback, send me an e-mail at simmer@gmail.com.
| |
| Wednesday, March 15, 2006 |
 LOD Love |
Posted - 3/15/2006 11:52:41 AM | Well, my partner found a nice perf problem with the way we were using Cal3d. We suspected there was something wrong there, b/c it just seemed too slow considering how many folks are using it successfully.
Turns out we were calling setLodLevel() every frame, which should be called in discreet steps instead.
This morning I added lod facets to the entities, so that they track their current lod, at what lod distance they switch, and how many lods they should use.
While debugging that, I found a nice perf problem on the crypt level, where for point lights, each visible entity was potentially doing a raycast to each light on the level each frame, rather than just those he might be near, so I fixed that as well.
I added keys & locked doors yesterday, and in the process added a field to each facet record that specifies whether that field should be reloaded from the db every level load or whether it remains customizable by the game and/or designer. This way you can place the same door entity, and customize its locked/unlocked state without having to make two entity types. On the other hand, if there is a facet that is permanent, like "type", this one is reloaded from disk on a level load, so that if that changes, there is no need to rebuild the level.
| |
 More Portal-rific |
Posted - 3/14/2006 1:07:20 PM | Found yet another set of issues with the portal system, caused by a combination of two portals leading from one cell into another and one of them crossing the camera's near clip plane.
We tried to lay out a level making every cell only able to have one portal out of it per wall, but that was a pain, so we had to fix it for real.
I didn't want to use a purely 3d solution of clipping one portal polygon to another, as they could become non-convex ( imagine a triangular piece of a portal seend through a square portal ), so I wanted to maintain the 2d bounding rect method of intersection, but the fact that I wasn't updating the z extents of the view frusta was causing the portal system to get into loops.
Earlier methods of tagging portals with frame counters or putting them in sets didn't work b/c you can end up going through one portal to another portal more than once per frame ( again the case of multiple portals leading to one room ).
The solution was a hybrid - we use the same code the anti-portals use to construct a 3d frustum from the plane of the portal as the near plane, and the sides from the eye point and the portal edges. This frustum is used to reject other portals that don't cross it. The fact that the frustum near plane is the portal itself prevents the traversal from going backwards in an infinite loop. If we had mirrors or non-euclidean portals, we would need another scheme. If the new portal is not rejected, it is converted to 2d as before for intersection.
This series of fixes seems to have finally done the job, and we aren't able to get any of the previously failing cases to do anything strange.
I also fixed the fog culling issue - I was using the world bounds for the entities instead of the visual bounds for the fog culling step, which rarely caused a mismatch.
| |
 Update |
Posted - 3/13/2006 12:53:17 PM | Well, I'm not going to claim the portal and anti-portal system is totally debugged, but it's definitely closer. I found a rare instance where some geometry would drop out when the camera's near plane intersected the portal.
I took out the clamping code for the portal, and instead test the portal's points vs the near plane of the frustum, and if it's fully outside ( possible if the camera is one on side of the portal and the player on the other ) or partially clipped, then I just use the existing viewport and don't try to clip or clamp it. This fixed the issue of dropouts.
I further simplified the portal / cell layout this weekend. Instead of the cells looking for neighbor cells via overlap, and portals in the cell/cell intersection area, I switched to a much more forgiving and simpler portal-based approach.
Fow now I removed the detection of cell neighbors, but will add it in later as a rarely-used method where the designer can flag certain cells as neighbors via facets.
I ran into issues with the portals when a cell partly overlapped many portals. The new scheme takes each portal, grows it by 2 meters in each dimension, and queries for intersecting cells. It then walks through these cells and takes the 2 with the largest volume intersection with the expanded portal as the two cells conntected by the portal. This way if a cell overlaps a corner of a portal, it doesn't matter, and the cells don't even have to exactly touch the portal to be hooked up.
Right now I'm debugging a fog culling issue, and drinking Diet Dr. Skipper. This is sooo glamorous. ;)
| |
 Update |
Posted - 3/11/2006 12:00:58 PM | Well, the portals and anti-portals are finally debugged. Yesterday morning I fixed the last of the few remaining issues.
There was a serious but with the portal traversal code that for some reason only showed up very rarely. I was recomputing a new projection matrix for each portal in view, in order to calculate a smaller frustum, but then I was passing this matrix down during recursion. This created a problem when projecting the portals to NDC space, as the space changed every time there was a portal traversal. Just keeping the main projection matrix fixed this.
I also stopped calling my frustum culling method ignoring the near plane, and instead added a method that uses the view position as the near plane position. This should provide better culling to things behind the viewer.
Additionaly, I found the anti-portals were only culling from one side, so I added code to find the distance of the camera to the plane of the anti-portal. If too small, I skip the anti-portal, as it wouldn't be good for culling and also may create a degenerate frustum. If the distance to the portal is negative, I create the portal planes with opposite winding order triangles, so the anti-portals work front & back.
Yesterday I attempted to portalize the crypt level, and was having a hard time with it, so I made some much simpler user interface methods. Now you can select several triangles to define the bounding box of where you want the cell, portal or anti-portal to go, then hit a button and the appropriate viz item will be created based on the box you specify.
Next I will add a button to shrink cells so they don't overlap when they're not supposed to.
I also changed the water shader to be a bit more realistic with the fresnel term, and fix it when a large part of the water was in shadow.

Today I've made some editor improvements, and am going to mainly work on gameplay-related things, such as adding key support to doors, etc.
| |
 Almost Done with Portals |
Posted - 3/9/2006 3:03:48 PM | As of last night, the cell / portal / anti-portal system is working in the engine and showing nice speed-ups.
I ran into some interesting bugs and issues while debugging it :
- My code initially didn't correctly handle two frustums pointing from cell A to cell B. If an object was only visible through cell B and A was processed first, the object disappeared.
- The code finds the cells containing the camera point, but culls portals based on the camera's view frustum. See a problem? The space between the near plane and the camera location was the issue. If a portal lay between the camera & the near plane, it was culled, and large parts of the level would disappear from view. The fix was to add a new culling method to my frustum class that skipped the near plane.
- Negative w values. When transforming the portals to Normalized Device Coordinate space, 0 w values might wreak havok, and dividing a vertex position by a negative w puts it in front of the camera but mirrored. One solution is to actually clip the portal to the near plane, but a simpler one is, for vertices behind the near plane - force them to the edges of the screen. If the x < 0, make x = -1, else x = 1; etc.
The last thing we accomplished was to make the anti-portals work. These are quads that have a frustum constructed from the viewpoint and the face and edges quad itself. For this I needed to add another frustum culling method - this one that would skip the far plane.
After all potentially visibly cells are processed, I find all anti-portals in the view frustum, and then cull them vs the cell / portal system. Any surviving ones get added to a per-frame list of active anti-portals.
When an object survives the view frustum & cell checks, it then gets tested vs each anti-portal. If one anti-portal frustum completely encloses the box, the box is considered culled.
I need to a check so that if the camera is too close to the plane of the quad to skip anti-portal checks with it, b/c the frustum created will be invalid.
In the shots below, the anti-portal is red, and is embeded in a solid wall.



| |
 Portalized |
Posted - 3/8/2006 10:53:27 AM | Late last week I started running some of the older levels with the new camera angle. The crypt and poison levels had been running slow for quite a while, but I didn't really investigate.
When I ran the crypt through nvperfhud, I saw huge areas of the level being needlessly rendered that were in the view frustum, but occluded.
Bringing the camera closer to and behind the player had clearly changed the performance profile, and required some sort of better culling mechanism than view frustum and fog culling.
So, I decided to implement a cell & portal system to speed up some of these bad areas, and hopefully bring up the overall speed as well.
Now, AG doesn't use bsp's or heightfields or other geometry structures that lend themselves to easy culling - it just has a polygon soup that is broken into ~1000 polygon groups at level build time.
Years ago, I had invesitgated several approaches to automatic portal generation and occlusion culling, but in retrospect, it's so much easier if you have an easy, sloppy mechanism in the level editor to manually set up cells & portals.
The current scheme works like so :
Designers place oriented & scaled bounding boxes in the level to serve as cells ( or zones ). If two cells' boxes overlap, then those cells are considered neighbors and are always mutually visible.
If cells overlap with a portal between them, then they are not neighbors, and they can only see each other through one or more portals or a chain of mutual neighbors.
At runtime, the camera's cell or cells are found. If there is more than one cell ( possibly b/c of overlap ), they are each processed in turn. If no cell is found, portal culling is disabled for that frame.
If this cell has neighbors, they are added to the potentially visible list. If the cell has portals ( cell->portal->cell and neighbor relationships are determined at build time ), then if the portal is within the current frustum, a smaller frustum is constructed from the camera and the portal's viewspace extents, and then the portal's other cell is recursively processed with this smaller frustum.
When this process finishes, the engine has a set of potentially visible cells.
If a set of geometry, or an object's visual bounding box touches a cell, then the geometry is tested vs all of the cell's frusta to see if it touches those. If it touches any, in any of its cells, it's drawn, otherwise it's culled.
A cell can have multiple frusta if there are more than one portal from the same or nearby cells seeing into it.
After getting this working, the fps in one bad part of the crypt level went from 18 fps to 62 fps. Yes!
Today I will probably add some level editor features to make layout of cells & portals simpler, and add the anti-portals as well.



| |
 Frustacular |
Posted - 3/4/2006 4:44:58 PM | This last week was one of the most productive weeks since I started on this fulltime in July.
Over the past couple of days we've made many improvements & fixes :
- New smooth lighting code for non-shadow receiving entities.
- Proper lighting for weapon models in character hands.
- One fewer rendering pass during directional light rendering.
- Fixed shadow frusta to be shorter - only to light range.
- Fixed shadow frusta to reflect actual visual bbox.
- Fixed the debris to use debris atlas texure so that debris matches the color of the texture it is derived from.
- Changed facets to always be reloaded from the csv file on entity creation. This changes the entities from a prototype-based system to a class system.
- Fixed the entity turning code to be more consistent as well as simpler and more readable.
- Stopped calling animation code when entity has been dead for over two seconds.
The smooth lighting code worked very well for being so simple. It's too slow to make all entities ( doors, enemies, etc. ) receive actual world shadows and shadows from other entities, so I needed an alternate approach. For a long time, I've had code to do several jittered ray casts through the scene towards a light in order to compute an occlusion percentage, but it's not super fast when doing like 9 ray casts per frame, per entity, and it doesn't always look that good, when an entity suddenly shifts lighting very quickly.
I managed to fix both issues at once, by adding a light amount facet to each entity, and doing a single raycast per light per visible entity per frame, and then smoothly averaging the new value into the old values. So, I effectively replaced spatial smoothing ( by doing 9 samples ) with temporal smoothing, with 1 sample averaged in over many frames. I gotta say, it looks very good, even on the main character, altough I think we will keep him receiving real shadows by default.
The weapons were rendering as .x files, rather than as true entities, which meant that they weren't being lit per-pixel, and couldn't have their own visible state or animations, so I fixed that. This brought up the issue of how to do shadowing for entities attached to other entities, like weapons. One option would be to have them use their own shadowing term, and the other was to have them use the entity's shadow term.
I ended up using the attachee's entity shadow term to ensure the gun wasn't brighter or darker than the entity carrying it.
Gameplay-wise, the AI received more tweaks, including the AI now tracking down the player rather than hiding so much. We also added in the two-handed gun aiming stance. When you right click, you can't move, and your character shifts to the more accurate two-handed gun stance, and the laser sight appears and can be used to aim at the enemies.
This makes a for nice little rhythm where you right click, aim at the enemy, shoot of a burst of 5 shots, then let go of the right button and dodge to the side, then take aim again.



| |
 Better and Better |
Posted - 3/2/2006 10:02:05 PM | Well, we made may performance and look improvments over the last couple of days.
I changed the particles, debris and needle rendering to occur in one large batch, which helped performance during battle sequences.
The debris changes ( from when you shoot a wall, causing visible damage ) made it so that I could no longer draw the debris chunks with the actual texture, at the actual spot the bullet hit. This was most useful on multi-colored walls or floors, where there was a painted and stone area on the same texture.
Today I made a routine to go through all of the materials, and render a little 3x3 swatch using point sprites to a 256x256 atlas texture. In the next few days I'll update the code so that the debris uses this swatch for the material color, rather than an artist-specified color in the material definition.

The main character and the android can now walk and fire simultaneously, and the other characters should be fixed soon when they are re-exported with separate animations.

I improved the fog culling, and saved an pass through the entities when shadowing from the sunlight.
Yesterday I fixed the laser sight so it moves smoother, and adjusted the higgs pistol so it's more fun to shoot.
Looks like the attachment system will need a few more tweaks to make the attachments actual game entities, rather than just .x meshes.
Also looks like we're CPU bound due to Cal3d, so we may end up moving the animation to the GPU in the next couple of days.
Still need to fix the material system to be more flexible, and work with the sounds better...
| |
|
| S | M | T | W | T | F | S | | | | 1 | | 3 | | 5 | 6 | 7 | | | 10 | | 12 | | | | | 17 | 18 | 19 | 20 | | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | |
OPTIONS
Track this Journal
ARCHIVES
December, 2009
August, 2009
July, 2009
June, 2009
June, 2008
May, 2008
October, 2007
September, 2007
August, 2007
July, 2007
June, 2007
May, 2007
April, 2007
March, 2007
February, 2007
January, 2007
December, 2006
November, 2006
September, 2006
August, 2006
July, 2006
June, 2006
May, 2006
April, 2006
March, 2006
February, 2006
January, 2006
December, 2005
November, 2005
October, 2005
September, 2005
August, 2005
July, 2005
|