foundryvtt / foundryvtt

Public issue tracking and documentation for Foundry Virtual Tabletop - software connecting RPG gamers in a shared multiplayer environment with an intuitive interface and powerful API.
https://foundryvtt.com/
202 stars 10 forks source link

Varying variable interpolation of very long and thin triangles produces artifacts on some hardware #6957

Open aaclayton opened 2 years ago

aaclayton commented 2 years ago

Originally in GitLab by @dev7355608

Environment Details

Issue Description

More details and solution here: https://discord.com/channels/170995199584108546/892854414774247454/900095463326367847

image

aaclayton commented 2 years ago

Flagging this as blocked since its an upstream driver problem.

aaclayton commented 2 years ago

Originally in GitLab by @dev7355608

No difference.

aaclayton commented 2 years ago

Originally in GitLab by @Feu-Secret

If you have access to an Intel HD 530 and Radeon, could you test something for me? Doing the same tests but changing the Angle graphics backend in chrome://flags

You should be able to test D3D9, D3D11, D3D11_on_12, and maybe OpenGL

image

aaclayton commented 2 years ago

Originally in GitLab by @dev7355608

I updated my Intel Graphics driver to check again. First I noticed that I had my iGPU completely disabled the entire time, and I actually didn't test my HD530 back then. I actually tested the Google SwiftShader renderer, which produces this:

image

No artifacts with the Microsoft Basic Render Driver, which Firefox uses.

So with the latest Intel HD drivers it still get some "snow" (flickering pixels) but it doesn't look nearly as bad as on AMD hardware:

image

Regarding latest AMD GPUs being ok: I checked the Radeon RX 6600 again, which is half a year old: latest drivers, but still the test fails:

image

Then there's the issue that there're graphics cards out there like Radeon R9 300 series and others that no longer receive driver updates. This is probably a very widespread issue (at least on Radeon hardware) and it would probably take a long time for drivers to rollout.

aaclayton commented 2 years ago

Originally in GitLab by @Feu-Secret

Ok. I have a couple of reports from the FVTT helpers. The problem seems resolved with the latest Intel drivers on Intel HD Series, but persists with some AMD ones (seems ok for latest AMD GPU cards). Reports show that this is not a hardware limitation (precision, etc.). The problem, here, are drivers. I'll contact directly AMD.

aaclayton commented 2 years ago

Originally in GitLab by @dev7355608

I've got this data from messaging a couple of people with the test and they sent me a screenshot and GPU name back. If you want more details and a larger sample size, maybe we could create a survey on the FVTT or League discord.

aaclayton commented 2 years ago

Originally in GitLab by @Feu-Secret

Do you still have access to these GPU? Could you tell me if it's on Linux/Windows and the versions of the drivers?

aaclayton commented 2 years ago

Originally in GitLab by @dev7355608

I know that it's not optimal, but the other solution is to try to subdivide the mesh in thousands and thousands of well-shaped triangles. That isn't great for performance either.

aaclayton commented 2 years ago

Originally in GitLab by @dev7355608

I'm not sure what the problem is (if it's a driver problem or hardware limitation). But this is the list of graphics cards I was able to test:

aaclayton commented 2 years ago

Originally in GitLab by @Feu-Secret

@dev7355608 The annoying side of this is that varyings are computed in the fragment shader, for each texel. Using real varyings from the vertex involves less overhead (and interpolation is a very fast operation).

aaclayton commented 2 years ago

Originally in GitLab by @dev7355608

The important part with the solution:

Update: I scrapped the method of subdividing the edges to create smaller triangles sizes, mostly because triangulation methods don't like colinear points on edges (at least earcut doesn't) and accuracy problems, which isn't easy to fix. So I chose a different approach: I got rid of all varyings (vUvs and vSamplerUvs). Instead I transform gl_FragCoord.xy back to world/local space by applying all inverse transformations: screen space -> clip space -> apply inverse projectionMatrix -> apply inverse translationMatrix and then construct vUvs with the origin and radius of the light source. Perfect results with this method.

// Fragment shader
vec3 worldPosition = projectionMatrixInverse * vec3(((gl_FragCoord.xy - viewportFrame.xy) / viewportFrame.zw) * 2.0 - 1.0, 1.0);
vec2 localPosition = (translationMatrixInverse * worldPosition).xy - origin;

vUvs = (localPosition / radius + 1.0) / 2.0;
vSamplerUvs = worldPosition.xy / screenDimensions;

Managing all those (global) uniforms and transforms can be made pretty simple by extending pixi. I can provide more detail if necessary.

aaclayton commented 2 years ago

Originally in GitLab by @Feu-Secret

It looks like a faulty driver implementation. We had a problem with Integrated Graphics which was resolved with the latest recent drivers. Getting rid of the varyings is not something that should be considered imo, it is an essential block of shader programming. @dev7355608 Could you communicate to me the exact specifications of the faulty example? Hardware, system/OS, GPU brand, GPU driver version.

aaclayton commented 2 years ago

Details from Discord:

SecretFire I recently discovered something, I'd like to share. The geometry of inset/offset edges can be very long, very thin triangles. It seems like some GPUs do not like those and fail to interpolate shader varying variables accurately. So long edges need to be subdivided to limit the length of the edge triangles: then the interpolation does not fail. So we have to generate more geometry for the edges, and therefore also more for the inner polygon itself, because the mesh must fit together perfectly to guarantee gap-less rendering.

I haven't tested a lot of different GPUs yet to figure out, which GPUs wouldn't need the subdivision and which do. I wrote a test here: https://www.pixiplayground.com/#/edit/u5lycLFuMC136XzWKKLSN.

This might also be a problem for the triangulation of the polygon in general: earcut (and any other triangulation methods that do not add additional points) can produce very long and thin triangles and this is sometimes unavoidable without introducing addition vertices.

This all depends on the scene / scene size / size of the polygon of course and on the shader (some shaders might not care so much about the inaccuracy and it wouldn't make a difference). But it's probably necessary to subdivide if the point source shader needs distance to the origin. That's how I discovered it: I rendered the los polygon geometry in a large map with a shader that additionally draws the fov in another color with a smooth, but fixed-length (not proportional to the size of the radius los polygon) transition. It produced similar (but not as extreme) artifacts on the edge strips as the test above.

image

caewok commented 2 years ago

FYI, no issues running with either Metal or OpenGL 4.1 on a Mac M1 processor. (The "angle" flag in chrome switches between those two.)