Lighting on merged Object3Ds

Started by AeroShark333, December 03, 2021, 01:37:22 AM

Previous topic - Next topic

AeroShark333

Quote from: EgonOlsen on January 04, 2022, 08:48:28 PM
To be sure: Which device are you using that has this issue? As said, I tried it on a S7 and it works fine. It also works fine in the emulator. I fails on the LG G4.
The videos I sent before are made from an emulator; but I get the same results on my phone (Samsung Galaxy Note 9)

Quote from: EgonOlsen on January 04, 2022, 08:48:28 PM
Ok, it's cleary some kind of shader bug. Not in the shader code itself but in the shader compiler of some devices. Or in the GPU...I don't know...
I went through some debugging myself...
I believe it might not be a shader bug after all (or maybe a solvable one still..?)
It appears as if the shininess value(s) is/are not transferred properly to the merged Object3D for some reason..?  ???

According to my IDE (Android Studio in debugging mode) the shininess value sometimes is 0.0 instead of 1.0
I want to stress the "sometimes" above here... it seems that for the merged Object3D, it is sometimes 0.0 and sometimes 1.0..?
I assume it is for different parts of the merged Object3D that it is sometimes 0.0 and sometimes 1.0

I'm tracking the shininess value from here:
GLES20.java [line 282~284 according to IDE's decompiler]
if (newShader.shininessHandle != 0) {
            GLES20.glUniform1f(newShader.shininessHandle, this.shininess);
        }


Expectation:
Expected shininess: 1.0
Expected spec_color: vec3(0.0)
Expected result: 0.0*x^1.0 = 0.0*x = 0.0

Experiment:
Measured shininess: 0.0
(Expected) spec_color: vec3(0.0)
Expected result: 0.0*x^0.0 = 0.0*1.0 = 0.0

Quote from: EgonOlsen on January 04, 2022, 08:48:28 PMA zero vector multiplied by some value (in this case the result of the pow()-calculation) should be...a zero vector. Because, as we all know, 0 times something is still 0. Turns out, that some devices beg to differ.
I would have expected this too even with the shininess that seems to fluctuate...

Quote from: EgonOlsen on January 04, 2022, 08:48:28 PMClearly, specPart has to be a zero vector as well in all cases. But it's not. shininess on the other hand is set to 1. However, it too seems to fluctuate in value as well while the shader is executing, which is actually impossible. It's supposed to stay fixed once the shader is executed for a given mesh, hence the name "uniform". Or maybe it doesn't fluctuate but evaluating it in the shader goes wrong for the same reasons that 0 times something is something else rather than 0.
specPart should always be a zero vector... There seems to be some kind of shader bug there as I agree with the previous statement (0 times x is 0).
To me, it seems that the GPU/driver/OpenGL does not handle "pow(..., x) with x an uniform/non-constant equal to 0" in a shader well.
Though, it seems that this value of 0 is sort of unintented as shininess should be 1?
Therefore, the bug can be avoided by making sure the Java code doesn't supply a zero value I guess..? Or something...

From the OpenGL ES Shading Language sheet:
https://www.khronos.org/files/opengles_shading_language.pdf
[section 8.2, page 65]
QuotegenType pow (genType x, genType y)
Returns x raised to the y power, i.e., x^y
Results are undefined if x < 0.
Results are undefined if x = 0 and y <= 0.
I believe it might not be a shader bug after all since the shader might deal with "Results are undefined if x = 0 and y <= 0"
Though mathematically 0^0 should exist still...
And when you try pow(0.0, 0.0), it still does the multiplication correctly later and zeroes it out...  :o
But when you try pow(0.0, shininess), it breaks again...
What I think is that pow(0.0, 0.0) evaluates to 1.0 and pow(0.0, shininess) evaluates to 'undefined', although they are basically the same...
I guess the shader becomes unpredictable when dealing with 'undefined' values.
And I guess some devices are able to handle the 0.0 values in pow() well still and don't cause any visual bugs...

Quote from: EgonOlsen on January 04, 2022, 08:48:28 PM
Are you by any chance already using your own shaders? I that case, we could just cut the specular part (if not used, that is) and call it a day. If not, it might be worth considering to do so.
I'm not using my own shaders (yet) but I might go that way (probably will be based of default shaders)...

Quote from: EgonOlsen on January 04, 2022, 08:48:28 PMI'm not sure what to do here.
I suggest the following solutions:
1. Make sure that a merged Object3D does not have 0 shininess values
2. Make sure that when the shininess value is altered, the Java code will only allow to pass shininess > 0 values. (excluding 0).
3. Make sure that the GLSL shader code can handle 0 shininess values by setting a minimal value. Replace "shininess" with "max(shininess, 0.00001)"
4. Make sure that the GLSL shader code can handle 0 shininess values by adding an offset. Replace "shininess" with "shininess+0.00001"
5. Make sure that the GLSL shader code can handle the first pow term properly. Replace "max(0.0" with "max(0.00001,"
I believe all these solutions would work but I currently ranked them from best to worse...
Personally, I'd only do both 1 and 2... I guess it is best to 'sanitize' the input variables; rather than to fix it in a later stage...

EgonOlsen

#16
Strange that this happens in the emulator as well in your case. It doesn't for me.

Anyhow...

Quote
According to my IDE (Android Studio in debugging mode) the shininess value sometimes is 0.0 instead of 1.0
I want to stress the "sometimes" above here... it seems that for the merged Object3D, it is sometimes 0.0 and sometimes 1.0..?
I assume it is for different parts of the merged Object3D that it is sometimes 0.0 and sometimes 1.0

That's what I noticed as well (but by doing some checks in the shader on the device instead of by using a debugger). In your case, it seems to be 1 for the red part and 0 for the green (or vice versa, but something like that). And I also think that multiplying with an undefined value might cause these problems. However, if I set it to 0 or 1 manually, the problem goes away (at least for me), which is not what I would expect.

But maybe you are right. Maybe I'm setting it wrongly. That would explain why it only happens when using multiple textures, because that would cause the object to be split into several parts and it looks like as if I'm setting it correctly for one part but not for the other. Albeit I'm completely in the dark on why that should happen...I'll look into it some more...

AeroShark333

Thanks for looking into it.

I believe compiler might be smart enough in some cases for the pow(x,y) function:
If you manually set y = 0.0, then the compiler probably gets rid of the pow(x,y) altogether and replaces it with a constant value.
If you set y = shininess, then the compiler cannot get rid of the pow(x,y) evaluation as it's dependent on a non-constant value (which could potentially change during runtime).
I believe the compiler-level pow() evaluation goes well or something, but the runtime-level pow() does not..?
I don't know, I'm not an expert on this but this is what I'm guessing :p
Maybe interesting: https://www.shadertoy.com/view/slKSWc

Little late but best wishes for the New Year! :)

EgonOlsen

Happy new year to you as well.

I had a look and I think that I've identified the issue. Can you please give this jar a try: https://jpct.de/download/beta/jpct_ae.jar ?

AeroShark333

Quote from: EgonOlsen on January 06, 2022, 03:07:06 PM
Happy new year to you as well.

I had a look and I think that I've identified the issue. Can you please give this jar a try: https://jpct.de/download/beta/jpct_ae.jar ?
Works like a charm! :D

It fixed both the test case and the original rendering bug.
Thanks for the support (as always) :)

EgonOlsen

Good to hear. This flaw was in there since the very first version of jPCT-AE. Strange that nobody ever noticed it before. I guess it has been mitigated by the fact that it only affects some devices and that you have to use Object3Ds which are using more than one texture combination, which isn't a common use case when you are loading your objects from a file.