Closed lKomus closed 7 years ago
Could you provide savestate for older version of Project64 or for another emulator?
This and #1181 are the same problem. N64 uses fixed point arithmetic and non-trivial clamp of the result. Negative value of a color is clamped to zero, but if its absolute value is large enough it can became one! Here the board has color -1. GL clamps it to zero and it is black. N64 clamps it to 1 and it is white. Glide64 uses a hack, which somehow works for this case, but not for #1181
Shader code to fix it looks like this:
if (color1.r < -0.51) color1.r = 1.0; else if (color1.r < 0.0) color1.r = 0.0;
if (color1.g < -0.51) color1.g = 1.0; else if (color1.g < 0.0) color1.g = 0.0;
if (color1.b < -0.51) color1.b = 1.0; else if (color1.b < 0.0) color1.b = 0.0;
This looks ugly. Can somebody suggest better code? Preferably one vector operation.
Sorry I wasn't available until now. Here's a savestate made with PJ64 1.6 MISCHIEF MAKERS.pj.zip
ivec4 color1_temp = ivec4(clamp(color1, -1, 0)/-0.51)*1000; //This results in 0 or >1000 if we convert to integer, 1000 was selected for being a large number.
color1 = color1+color1_temp ; //You end up with either the same number or a number much greater than 1
With the above, if a component was <= -0.51, you end up with a number much greater than one, which will get clamped to 1.
The result of clamp(color1, -1, 0)/-0.51*1000
needs to be casted to an ivec4. Is there an easy way to do that?
I probably missed something, but your code will map any negative value to 1. Values -0.51 < c < 0 must be clamped to zero.
Yeah, it's just pseudo code, so it's not exact, but I'll demonstrate: With an input vec4 of (-0.45, -0.45, -0.45, -0.45);
vec4 temp1 = clamp(color1, -1, 0); //temp1 = (-0.45, -0.45, -0.45, -0.45);
temp1 = temp1/-0.51; //temp1 = (0.88, 0.88, 0.88, 0.88);
ivec4 temp2 = temp1; // Cast this to an integer somehow? temp2 = (0, 0, 0, 0)
ivec4 temp2 = temp2*1000; //temp2 = (0, 0, 0, 0)
color1 = color1 + temp2; //Cast temp2 back to a float somehow? Then you end up with color1 of (-0.45, -0.45, -0.45, -0.45)
Now with an input vec4 of (-0.6, -0.6, -0.6, -0.6);
vec4 temp1 = clamp(color1, -1, 0); //temp1 = (-0.6, -0.6, -0.6, -0.6);
temp1 = temp1/-0.51; //temp1 = (1.17, 1.17, 1.17, 1.17);
ivec4 temp2 = temp1; // Cast this to an integer somehow? temp2 = (1, 1, 1, 1)
ivec4 temp2 = temp2*1000; //temp2 = (1000, 1000, 1000, 1000)
color1 = color1 + temp2; //Cast temp2 back to a float somehow? Then you end up with color1 of (999.4, 999.4, 999.4, 999.4)
A positive value would give the same result as the first case. This only works ok if there is an easy way to cast between ivec4 and vec4.
I guess to cast a vec4 to a ivec4 you could do
ivec4 temp = ivec4(int(color1.r), int(color1.g), int(color1.b), int(color1.a));
and the same backwards... Any easier way?
This code does the trick
vec3 clampColor = clamp(color1, -1.0, 0.0)/-0.51;
ivec3 iClampColor = ivec3(clampColor)*1000;
color1 = clamp(color1 + vec3(iClampColor), 0.0, 1.0);
Thanks!
@lKomus thanks for the save
No problem!
The fix is in https://github.com/gonetz/GLideN64/tree/color_clamp branch. @fzurita , @loganmc10 Please check that I that fix does not break anything.
Tested GLES 3.1 and GLES 2.0 on one Android device. Everything seems to look the same, which is what we expect unless you run into this specific circumstance.
The change seems simple enough that I don't think different devices will act differently.
Yes. I was need to be sure that these modifications will compile without issues. Thanks!
By the way, if you want to compile Mupen64plus-ae yourself, it's much easier now. All you need is Android Studio 2.2, clone the mupen64plus-ae github and open it using Android Studio. It should all compile and run right off the bat.
There is one difference with my approach than yours that I'm not sure you noticed. Mine is checking for <= -0.51
your checks for < -0.51
'''< -0.51''' is more right. I guess, that intended bound is -0.5, but N64 uses fixed point arithmetic, which impossible to correctly reproduce with floats. -0.5 bound produces wrong result, -0.51 bound works correct. Precise bound is somewhere near -0.506.
OK, so it sounds that it won't make much of a difference since we were not precisely accurate in the first place.
It does not make any difference because combiners rarely produce negative color values. This game was full of strange bugs caused by too creative use of hardware capabilities. BTW, I need to check, how large positive color values are clamped by N64. It does not care if value negative or positive, it just manipulates with bits. Probably, if color value is above 1.5 it should be clamped to 0.
The same mechanism can be applied to clamp 1.5 to zero.
Yes, but I'm not sure that it is used somewhere. It can be just waste of GPU resources.
Just noticed that contrary to what Glide64 shows, the question border should be white on real hardware
The bar beneath Events should be blue:
This is to provide points of references just in case. Plugin used is Angrylion
@lKomus How do they look on GLideN64?
I can't compile GLideN64, so I can't tell you how they look on the color-clamp branch.
On the latest compiled master, the bar is just black, like everything else that needs the color clamp (I'm assuming it needs that).
Also I checked videos of Mischief Makers on Youtube to make sure that the plugin isn't rendering the wrong color.
EDIT: There's also a bar under the name of the events when you're doing them, this one should be white.
GLideN64 renders it in black.
Is casting booleans to floats a bad thing?
You could always write
color1 = color1 + (-color1)*float(color1<0.0) + vec3(float(color1<0.51));
The first addend clamps to 0 if negative and the second adds 1 more if it is a large negative.
Edit: I made a mistake. It must be made on a per coordinate basis, so the step function can be used to apply the same idea.
color1 = color1 + (-color1)*step(color1, vec3(0.0)) + step(color1, vec3(-0.51));
I like it better than my solution since it gets rid of the random 1000 in the middle.
@standard-two-simplex Thanks!
I wonder if this is the same problem as this in Paper Mario:
I don't think those are supposed to be black.
Actually, I think that black is supposed to be full alpha.
This is a frame buffer effect. It worked ok on desktop last time I checked it. May be it was broken recently.
I just checked full OpenGL mode in shield TV and it was broken there. I don't think there is much difference between the Full OpenGL mode in Android and the desktop version.
Does it work correct with texture enhancements disabled?
The paper Mario effect does not work correctly with texture enhancements disabled.
Ok, please give me a savestate.
Here you go for mupen64plus: Paper mario.sav.zip
Talk while standing on the opposite side of the orb.
Thanks! The same on desktop, yes.
Reminds me how all plugins but GLideN64 and Angrylion's can't emulate the alpha of tennis ball trace properly in Mario Tennis (the orb shows with an ugly black background much like in that Paper Mario pic) How did GLideN64 accomplish that feat?
tennis ball trace is also fb effect, which blends texture of already rendered buffer with texture of the ball.
I fixed that crystal ball issue in Paper Mario.
Ok, I just verified that Paper Mario is fixed.
Confirmed to be fixed in last master!
This was tested with GLideN64's last master, it used to work with Glide64.
GLideN64
Glide64
![project64_2016-10-18_09-35-15](https://cloud.githubusercontent.com/assets/4800879/19468588/7ae4cf32-9517-11e6-85df-7c9c2860ae5d.png)
Savestate: Mischief Makers (U) (V1.0).pj.zip