unexpected geometry in Rapier-class Terramax tunnel exit
At the exit to the first tunnel in Terramax in Rapier class, there are some "concrete" textured polygons (GT3s) that do not appear in the PSX version.
I haven't been able to track down why they appear. Someone reported these to me on my repo, derived from rewrite (and I confirmed they are present in Linux and web builds of rewrite) so I thought I would share this here.
Incorrect (rewrite Linux build):
Correct (PSX):
Judging from my 2015 wipeout-viewer: https://phoboslab.org/wipeout/ ...
... this thing is probably visible in the DOS/PSX version as well, but only from the other side (going backwards on the track).
wipeout-rewrite disables backface culling when drawing track geometry, but the wipeout-viewer does not. Culling backfaces everywhere can't be the answer, as it leads to ugly artifacts like missing the back half of this structure in Altima:
which is not culled on the PSX:
but is culled on DOS:
Not sure what the right behavior is. Should only certain primitive types be backface culled?
You said "track geometry" above. Are you making a distinction between scene objects and track sections when you say "track geometry"?
Reproduced the visually correct for Rapier Terramax result by having backface culling enabled for scene_draw . I also reproduce the incorrect structures.
@phoboslab after your writeup about culling, a PSX libgpu file format doc and some code comments in object.c reminded me about the Playstation distinction between single sided and double sided polys. There's a really easy solution to this that gives correct results for the structures and that tunnel exit. Working on PR now.
Should only certain primitive types be backface culled? -- the comments in object.c seem to suggest you already were going to look at using the primitive flag to handle this :-)
These are both with the same renderer now. General purpose solution incoming.
// TODO: check for PRM_SINGLE_SIDED
Good idea to leave some comments for yourself that you then never read again ._.
Problems:
- With OpenGL (and probably other renderers) en-/disabling backface culling per primitive is a bad idea, as it needs a buffer flush.
- Going through the primitive list twice is quite the crutch :/
- If you separate single/double sided primitives on load, you have to be careful with the few functions that manipulate primitives directly (those in
scene.cand the animated exhaust plumes inship.c).
We could enable culling everywhere and draw double sided polys twice: once as is, once with flipped normals. Maybe add a flag to tris_t and handle the flipping and submitting twice in the renderer!? I wonder how many of the polys are double sided and if it would have a big performance impact to submit them twice...
(Edit: Fun Fact: normals are loaded for each .prm but never used. They would only be necessary for drawing dynamic lights. So for now, only flipping the order of vertices would be enough.)
Rant:
But IMHO the best solution would be to leave the renderer as it is and fix the scene geometry instead. This wall straight up shouldn't be there. This port requires very specifically assembled data already anyway; might as well fix the data.
The whole object format is needlessly complex. If I could find the time/muse I'd want to rewrite this all. Come up with a format that just stores triangles instead of this cacophony of 20 different primitive types. Build some tools around importing/exporting geometry in blender, fix the scene geometry and touch it up in places (add some mountains) to allow for longer draw distances.
Some stats on single vs double sided polys in objects:
Altima - Venom
load: wipeout/track02/scene.prm
total single 8221, double 201
Terramax - Rapier
load: wipeout/track06/scene.prm
total single 6869, double 187
Far fewer double-sided polys than single-sided.
I did one more evolution of the attempt I made last night. I have a solution that trades off a bit of extra memory use for not iterating over the entire set of primitives twice per object (by creating arrays of Primitive ** by polygon side-ness when loading an object).
It only requires two calls to render_set_cull_backface per object. It seems to work well enough in my VM environment. FPS in thousands, no noticeable performance issue from state flushing or anything.
Next attempt is going to be to just draw twice with both vertex orders.
Will update PR accordingly.
Only seeing GT3/GT4/sprites loaded as double-sided.
Leaving culling on for scenery and drawing double-sided polys twice with opposite winding orders did work and was performant enough for modern PC even in a VM/software OpenGL environment.