xemu-project / xemu

Original Xbox Emulator for Windows, macOS, and Linux (Active Development)
https://xemu.app
Other
2.8k stars 279 forks source link

Halo 2: Able to see other objects through objects close to you #55

Open Alastair0100 opened 4 years ago

Alastair0100 commented 4 years ago

Also can depend on viewing angle aswell as how close objects are to you from my testing

Title: 4d530064

image image image image

Shoegzer commented 2 years ago

Confirmed in testing here too.

Relevant test specs:

Triticum0 commented 2 years ago

This also affects Wallace & Gromit in Project Zoo, Miami Vice, Tom Clancy's Splinter Cell and Serious Sam

RageXbox commented 2 years ago

Here’s a log for this. Halo 2 seethrough.log

abaire commented 2 years ago

This looks like it may be a depth buffer precision issue, stepping through the draws in renderdoc I see depth buffer values for the more distant draws that are suspiciously close to but less than the nearby correct nearer geometry with odd discontinuities (e.g., if I follow the plane of a wall that is being cut out, I see values that follow a linear trend then jump to higher values where the earlier draw is peeking through, then resume within the expected interpolated range after the slice).

Halo2 uses a non-standard clip range:

nv2a_pgraph_method 0: NV20_KELVIN_PRIMITIVE<0x97> -> NV097_SET_CLIP_MIN<0x394> (0x437FFFFF => 255.999985)
nv2a_pgraph_method 0: NV20_KELVIN_PRIMITIVE<0x97> -> NV097_SET_CLIP_MAX<0x398> (0x4B7FFFFF => 16777215.000000)

though it at least uses the same range throughout all of the draws in the frame I traced.

I've previously found that the technique xemu employs to attempt to map screen coords produced by the nv2a shaders back into OpenGL-friendly NDC has some issues when dealing with unusual clip ranges (e.g., #843). This may be part of what is happening here.

Shootfast commented 1 year ago

Not sure if this is helpful at all, but in my naive attempt to debug this issue in Renderdoc, I found that commenting out this line of the vertex shader completely fixes the "see-through" issue (though also adds other problems).

Might that point away from it being a depth buffer precision issue, and perhaps point towards it being a problem converting the screen space to clip space?

polymetal0 commented 5 months ago

Thanks to your comment, I accidentally got Skybox working!

polymetal0 commented 5 months ago

Upon further research, I'm positive @Shootfast is right about that line being the issue. Completely removing that if statement fixes the see through issue, but it does break other things specifically in Halo 2.

I'm pretty sure it has to do with the normalization taking place right after that statement, but I don't know if it is possible to get the true range for oPos.w to get sth like this:

if (z_perspective) {
        mstring_append(body, 
            //"    oPos.z = oPos.w;\n"
            "    oPos.z = 2.0 * (oPos.w - /*newClipRangeMin*/) / (/*newClipRangeMax*/ - /*newClipRangeMin*/) - 1.0;\n" 
        );
    } else {
        mstring_append(body, 
            "  if (clipRange.y != clipRange.x) {\n"
            "    oPos.z = 2.0 * (oPos.z - clipRange.x) / ((clipRange.y - clipRange.x)) - 1.0;\n"
            "  }\n"  
        );
    }  
   mstring_append(body,
    //"  if (clipRange.y != clipRange.x) {\n"
    //"    oPos.z = 2.0 * (oPos.z - clipRange.x) / ((clipRange.y - clipRange.x)) - 1.0 ;\n"
    //"  }\n" 

I have tried all combinations I could come up with and nothing worked, does anyone have any clue as to how to proceed?

Edit: maybe related to #843 ?

New edit: my bad, it was actually clamping z to 1 what brought dynamic shadows back. But this still confirms that there's something wrong with oPos.w's range

polymetal0 commented 5 months ago

Some screenshots:

Latest release: halo2

Removing if statement: halo2 2

polymetal0 commented 5 months ago

I made an attempt at fixing this in #1651, among other things. Feel free to test it with any other games where this issue appears 👍

coldhex commented 3 months ago

I've also fixed this here with other Halo 2 fixes: https://github.com/coldhex/xemu/tree/halo2fixes

I think the fundamental issue is that when z_perspective is true, it implies w-buffering and the w-values are not being interpolated with perspective correction. I solved it by writing the perspective correct w-values to gl_FragDepth in the fragment shader.