OpenBVE
OpenBVE copied to clipboard
Fix: issue with partial transparency
This PR fixes the issue pointed out in https://github.com/leezer3/OpenBVE/issues/466#issuecomment-619619294. This issue occurs in at least v1.4.3.0 and later main programs and v1.7.0.0 and later viewers. This PR reverts the drawing of partially transparent faces to the viewer's method up to 1.6.0.0.
-
v1.4.3.0 (Main program)
-
v1.6.0.0 (RouteViewer)
-
v1.7.0.0 (RouteViewer)
-
This PR (RouteViewer)
-
This PR (Main program)
Very nice.
I'll take a proper look later or tomorrow
If I read what you've done right, I'm not entirely sure this isn't just hiding the issue in this case.
Essentially, if I understand what you've done, this code is pulling the transparent and semi-transparent faces into two disparate lists & drawing the semi-transparent faces separately afterwards. The issue with the linked file is that the drawing order is wrong https://github.com/leezer3/OpenBVE/issues/466#issuecomment-622055633
It shouldn't matter which list they're in.
Our real issue is where it selects the vertices to sort by here: https://github.com/leezer3/OpenBVE/blob/master/source/LibRender2/Objects/ObjectLibrary.cs#L245 It's using a simple implementation of the painters algorithm, which breaks when dealing with overlapping polygons.
Definitely hiding the issue. You'll see what I mean if you drop this tree with a replacement PNG texture in:
See what you think of this, it's a hack based on https://www.alecjacobson.com/weblog/?p=2750
if (Interface.CurrentOptions.TransparencyMode == TransparencyMode.Performance)
{
SetBlendFunc();
SetAlphaFunc(AlphaFunction.Greater, 0.0f);
GL.DepthMask(false);
foreach (FaceState face in VisibleObjects.AlphaFaces)
{
face.Draw();
}
}
else
{
SetAlphaFunc(AlphaFunction.Greater, 0.0f);
GL.Disable(EnableCap.CullFace);
GL.DepthFunc(DepthFunction.Less);
foreach (FaceState face in VisibleObjects.AlphaFaces)
{
face.Draw();
}
GL.Enable(EnableCap.CullFace);
GL.CullFace(CullFaceMode.Front);
GL.DepthFunc(DepthFunction.Always);
foreach (FaceState face in VisibleObjects.AlphaFaces)
{
face.Draw();
}
GL.Enable(EnableCap.CullFace);
GL.CullFace(CullFaceMode.Front);
GL.DepthFunc(DepthFunction.Lequal);
foreach (FaceState face in VisibleObjects.AlphaFaces)
{
face.Draw();
}
GL.Enable(EnableCap.CullFace);
GL.CullFace(CullFaceMode.Back);
GL.DepthFunc(DepthFunction.Always);
foreach (FaceState face in VisibleObjects.AlphaFaces)
{
face.Draw();
}
GL.Disable(EnableCap.CullFace);
GL.DepthFunc(DepthFunction.Lequal);
foreach (FaceState face in VisibleObjects.AlphaFaces)
{
face.Draw();
}
ResetOpenGlState();
}
You also need to add the following to the ResetOpenGlState function:
GL.CullFace(CullFaceMode.Front);
This will be slower at the minute on the old renderer, as display lists are broken. (and it obviously adds 3 draw passes for each face) I suppose we could possibly add this (or another approach) under the quality option, and keep the current as the middle.
I'll take a look at it over the weekend.
My change may be wrong, but I've tried your suggestion and it doesn't seem to solve the problem.
Can you push your changes to GitHub?
Well, I would like to investigate techniques such as order-independent transparency. (for both performance and quality)
Also, we should change the transparency option item names to "Performance" and "Quality". It's hard to tell what the current names "Sharp" and "Smooth" are.