Open Gillou68310 opened 9 years ago
the problem is that clipping does not work properly for GLES, the heart and the map arrows are clipped away. Adding a hack is a bad idea, it needs to be fixed properly because other games are affected as well. The characters and vehicles in Star Wars Ep1 racer are cut off. The desktop version does not have these problems.
Adding a hack is a bad idea, it needs to be fixed properly because other games are affected as well.
I totally agree, I just provided the hack as a possible temporary solution ;-)
@purplemarshmallow - could you explain why do you think that it is clipping and why these particular polygons are clipped?
I think it's the same problem as in rice video Rice Video has this comment:
// Hack needed to show flashing last heart and map arrows in Zelda OoT & MM
// It renders at Z cordinate = 0.0f that gets clipped away
// So we translate them a bit along Z to make them stick
I remember similar problem on desktop too. Polygon may not use depth compare at all, as this heart rectangle, but if it has negative z it will be clipped. I tried to force z to zero, but it causes problems with fog. So, I just disabled z-clipping for ucodes, which do not use near-far clipping. Desktop GL allows to do that. GL ES does not. If it clip polygons with Z==0 it's bad. Glide64 uses software clipping and culling, so this problem resolved on plugin's side. It was done because Glide3x API does not provide polygons clipping. I don't want to make custom clipping when I have built in GL one. From the other side, the only alternative for GL ES is a hack. @Gillou68310 - as I understand, your patch does the same trick - translates vertices a bit along Z, right?
Exact.
Here's the value to fix duke nukem zero hour:
gSP.matrix.projection[3][2] += 1.f;
@Gillou68310 Wouldn't it be possible to add the depth bias after the projection matrix is applied to the vertex (somewhere in gsPProcesVertex(), I think), and in a way so that this bias is independent of the y coordinate?
It would involve changing the values of the near and far plane, but if no native clipping has to be done this would not affect it negatively.
The good thing would be that if the bias is chosen wisely, it would be quite a legit approach.
@Gillou68310 Wouldn't it be possible to add the depth bias after the projection matrix is applied to the vertex (somewhere in gsPProcesVertex(), I think), and in a way so that this bias is independent of the y coordinate?
Sure putting vtx.z += 0.5f;
in gsPProcesVertex() produces the same effect (zelda) ;-)
It would involve changing the values of the near and far plane, but if no native clipping has to be done this would not affect it negatively.
I'm not sure to understand why this would be necessary?
I'm sure sure to understand why this would be necessary?
I did not explain myself very clearly. What I meant is that an element in the near plane would now have z-coordinate different to 0 (or whatever he is intended to have). Z-compare effects would have problems if comparing something transformed to something not transformed.
I believe the equivalent to your code would be vtx.z += 0.5f*vtx.y
. I believe it would be possible to find values m,n such that,
vtx.z = (vtx.z+m)/n
would give correct graphics. In your case it also does assuming 0.5*vtx.y
is positive and big enough.
I did not explain myself very clearly. What I meant is that an element in the near plane would now have z-coordinate different to 0 (or whatever he is intended to have). Z-compare effects would have problems if comparing something transformed to something not transformed.
It makes sense, thanks for the clarifications, however I'm not sure how we should deal with this.
I believe it would be possible to find values m,n such that, vtx.z = (vtx.z+m)/n would give correct graphics
You mean "m" and "n" being 2 constants compatible with all games?
BTW setting vtx.z += 4.f;
fixes the z-clipping issue in starwars ep1, while I was not able to fix it via the projection matrix.
You mean "m" and "n" being 2 constants compatible with all games?
Yes I meant that. m
should be big enough to guarantee that vtx.z+m
is positive, but not so big as to create a rounding error in OGL floating point format. And n
can be any number (a power of 2 for simplicity) to make sure final values are within the OGL standards.
The numbers depend on the fixed point format of the N64 and the floating point format of OpenGL. I will think about them this night, and see if I can come up with them.
Ok I let you do the math, I'm not good at it anyway ;-)
Mmm so N64 uses 32 bit fixed point. I was expecting less. That can not be perfectly approximated with floats, and will make the this approach (actually any hardware accelerated approach) error prone.
Try m=32768, n=2; m=128, n=257/256;
Edit: Changed values. I also noticed that gspF3DNoN only disables near clipping. Therefore, the previous approach will change far clipping. In order to maintain far clipping correct, the coordinate of the far plane should be maintained at the same place. The formula doing so would be,
m = z_far*(n-1)
Is z_far
known?
Here's another hack to fix both mario 64 and mario kart 64 background (blue sky) with widescreen hack enable:
if(gSP.matrix.projection[3][2] == -1.f) vtx.w *= ogl.getAdjustScale();
@standard-two-simplex I not sure to understand how to implement your method :-S
Add a line vtx.z = (vtx.z + 32768.f)/2.f
like in the example you gave before.
BTW setting vtx.z += 4.f; fixes the z-clipping issue in starwars ep1, while I was not able to fix it via the projection matrix.
I think it will screw the backgrounds though.
Is z_far known?
Yes. It is set by viewport command. z_max = view_trans[2] + view_scale[2]
Add a line vtx.z = (vtx.z + 32768.f)/2.f like in the example you gave before.
It doesn't looks good:
I think it will screw the backgrounds though.
Hum the background looks good to me.
Here's another hack to fix both mario 64 and mario kart 64 background (blue sky) with widescreen hack enable:
A hack for the hack :) Well, why not?
:-)
I might have pushed everything behind the far plane.
vtx.z = (vtx.z + gSP.viewport.farz)/2f;
@standard-two-simplex sorry for the delay, the new equation is a lot better! No more missing heart on zelda but no more fog also :-( Same for episode 1 racer. But we're definetly getting closer ;-)
No more missing heart on zelda but no more fog also :-(
Manipulations with z will also break depth buffer based effects, e.g. coronas in zelda. Probably it can be solved by applying reverse transformation to buffer z.
I had not thought about fog, but it will screw the z compare effects too, and lighting and other effects possibly. It would require modifying everything, and since it is a hacky approach, better not to do it.
@gonetz What about changing the viewport instead? Changing the value of nearz.
Probably it can be solved by applying reverse transformation to buffer z.
Also what do you mean by that?
What about changing the viewport instead? Changing the value of nearz.
Do you know how to do it with GLES?
Also what do you mean by that?
vtx.z is original vertex z. We apply a transformation to it before sending it to video card, e.g.
vtx.z = (vtx.z + gSP.viewport.farz)/2f;
To emulate depth buffer effect, plugin reads depth buffer from video card. We know that depth value is transformed, so we apply reverse transformation to read values:
z = 2*z - gSP.viewport.farz;
Do you know how to do it with GLES?
No, I don't know about GL. I was wondering if changing the value of the variable nearz could help.
To emulate depth buffer effect, plugin reads depth buffer from video card. We know that depth value is transformed, so we apply reverse transformation to read values:
I see. Thanks for the explanation.
No, I don't know about GL. I was wondering if changing the value of the variable nearz could help.
No. nearz/farz not used for vertex z calculation.
@Gillou68310 - please try this patch: https://drive.google.com/file/d/0B0YqMPjGo3B2c1VhQ3NESWp0WWc/view?usp=sharing
I tested that it fixes missing heart problem. Please check: does it work for other issues?
Just tried, both zelda games are perfect but duke nukem zero hour + star wars episode 1 still have the issue :-(
I found this while googling http://stackoverflow.com/questions/5960757/how-to-emulate-gl-depth-clamp-nv
It will not work for GLES2 (gl_FragDepth not writable) but maybe it's worth giving it a try on GLES3.x
Removing the (gSP.geometryMode & G_ZBUFFER) == 0
condition fixes the z-clipping issue for all games but of course some triangles now have a depth of 0 were they shouldn't.
Replacing ```(gSP.geometryMode & G_ZBUFFER) == 0
by ((gDP).otherMode).depthCompare == 0
fixes duke nukem + zelda. Star wars still have issues.
What kind of problem is in Star wars? My hack may fix only polygons which look like sprites.
I investigated only missing heart problem. Missing polygon has vertices with z = -1.3 w = 1.0. Thus, z/w < -1 and polygon z-clipped. Zelda ucode is NoN, that is it does not use near clipping. So, polygon is not clipped by original hardware. GLideN64 set z-clipping off on desktop, so desktop version works too. GL ES does not support z-clipping disabling. Thus, we can't solve all problems with z-clipping on mobile platforms. IMO, only sprite-looking polygons can be solved without breaking anything else, and only for case when z-buffer is not used at all during polygon draw. (gSP.geometryMode & G_ZBUFFER) == 0 condition ensures it. In that case we can set any z, which ensure that vertex will be between near-far clipping planes. My GBI.isNoN() condition is probably redundant. At least, my current code always set z-clipping off when depth buffer is not used.
What kind of problem is in Star wars? My hack may fix only polygons which look like sprites.
It makes sense because in episode 1 racer z-clipping issue is on non sprites polygons. However on duke nukem, z-clipping issue is on sprite polygons but it is not fixed with your hack.
Star wars is an example of the near clipping, which can't be fixed with harmless hacks. Duke Nukem can be fixed, but my (gSP.geometryMode & G_ZBUFFER) == 0 condition is too strong. This one is enough:
if (GBI.isNoN() && gDP.otherMode.depthCompare == 0 && gDP.otherMode.depthUpdate == 0)
Ok so let's merge this hack. If star wars is proved to not use depth buffer based effects we can always use the vtx.z += 4.f
hack just for this game. Hopefully no other games are affected by z-clipping issue.
Ok.
If star wars is proved to not use depth buffer based effects we can always use the vtx.z += 4.f hack just for this game.
Too bad :-(
The Zelda missing hart hack originated from DaedalusX64. I came up with this hack since the Play station portable(PSP) just like GLES has issues with polygon clipping and I figured that I could just modify the matrix transform slightly to make the hart (and map arrows) end up inside the NDC box and avoid the clipping. Anyways Gonetz hack is more elegant solution for "billboards" if it can be made to work. But it will never work for true geometry. N64 used a strange way to handle near field geometry and could turn off near field clipping to which is why Star Wars Episode I looks like it does when NDC clipping is turned on.
Anyways Gonetz hack is more elegant solution for "billboards" if it can be made to work. But it will never work for true geometry.
True. I mentioned it in my description for this hack.
The issue in Star Wars Ep I Racer is still there, can't see the vehicle you're driving, only the rockets.
Tested on my phone (Mali T860-MP2, I think it supports GLES3.2)
Near plane clipping not supported on GLES devices.
Glide64mk2 was able to get around the lack of ability to disable near plane clipping. I'm not quite sure how yet though.
Glide64 does software polygons clipping.
Should this be closed?
Here's a hack to fix the missing heart in both zelda games: https://github.com/Gillou68310/GLideN64/commit/1ddecf779935c8d7d9a3200074b283feccdf409f
Weird thing is this hack is only necessary for GLES versions (GLES2 and GLES3, I couldn't check GLES3.1) the desktop version doesn't seems to need it. It might be interesting to understand why this is working fine on desktop.