wipeout-rewrite icon indicating copy to clipboard operation
wipeout-rewrite copied to clipboard

unexpected geometry in Rapier-class Terramax tunnel exit

Open jnmartin84 opened this issue 8 months ago • 9 comments

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): Image

Correct (PSX):

Image

jnmartin84 avatar Apr 21 '25 21:04 jnmartin84

Judging from my 2015 wipeout-viewer: https://phoboslab.org/wipeout/ ... Image Image

... 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:

Image

which is not culled on the PSX:

Image

but is culled on DOS:

Image

Not sure what the right behavior is. Should only certain primitive types be backface culled?

phoboslab avatar Apr 21 '25 21:04 phoboslab

You said "track geometry" above. Are you making a distinction between scene objects and track sections when you say "track geometry"?

jnmartin84 avatar Apr 22 '25 00:04 jnmartin84

Reproduced the visually correct for Rapier Terramax result by having backface culling enabled for scene_draw . I also reproduce the incorrect structures.

jnmartin84 avatar Apr 22 '25 01:04 jnmartin84

@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 :-)

jnmartin84 avatar Apr 22 '25 01:04 jnmartin84

Image

Image

These are both with the same renderer now. General purpose solution incoming.

jnmartin84 avatar Apr 22 '25 01:04 jnmartin84

// 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.c and the animated exhaust plumes in ship.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.

phoboslab avatar Apr 22 '25 07:04 phoboslab

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.

jnmartin84 avatar Apr 22 '25 12:04 jnmartin84

Only seeing GT3/GT4/sprites loaded as double-sided.

jnmartin84 avatar Apr 22 '25 12:04 jnmartin84

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.

jnmartin84 avatar Apr 23 '25 00:04 jnmartin84