three-gpu-pathtracer icon indicating copy to clipboard operation
three-gpu-pathtracer copied to clipboard

WebGLPathTracer: Automatically position model to avoid numeric precision problems

Open Drosaca opened this issue 1 year ago • 9 comments

Describe the bug I loaded a 3D model and applied OrbitControls to it. The path tracing work fine when the model is at the origin (0,0,0). However, after repositioning the model far from the origin and moving the camera to the new position, the path tracing is rendered on a low-quality texture, while the default renderer displays the correct texture.

chrome_raUJgxWO8g (1)

Expected behavior expected this at position ("x": -3761603.743620786, "y": 4105279.00727716, "z": 3870314.8490743843) and not only at (0,0,0)

chrome_HIKeW216JU

Repro Model can't upload: "We don’t support that file type." can be downloaded from here: https://mega.nz/file/faxFkAjI#kYYd7T3MVEgmjj6cC1PhPiqNpT2yaYaOaATuFIlTatc original source: https://sketchfab.com/3d-models/starlink-spacex-satellite-0a60f6720c5141c9a1c6d71aac108b31

  • Device: Desktop,
  • OS: Windows,
  • GPU: NVidia
  • Browser: Chrome,
  • Browser Version: [130.0.6723.119]
  • Three.js version: [r169] //using react wrapper @react-three/fiber[^8.17.9]
  • Library version: [^0.0.23] //using react wrapper @react-three/gpu-pathtracer[^0.2.0]

Drosaca avatar Nov 14 '24 10:11 Drosaca

Try increasing the textureSize parameter: https://github.com/gkjohnson/three-gpu-pathtracer?tab=readme-ov-file#texturesize

AntonPalmqvist avatar Nov 14 '24 16:11 AntonPalmqvist

When submitting an issue please follow the template and submit the information that's requested - you haven't provided enough information to say exactly what the issue is.

My guess is that this is related to floating point precision at large numbers away from zero (though you haven't said how far). This is something that's not currently handled internally so assuming that's what the issue is you'll have to adjust the model position and camera to be near zero.

gkjohnson avatar Nov 14 '24 18:11 gkjohnson

When submitting an issue please follow the template and submit the information that's requested - you haven't provided enough information to say exactly what the issue is.

My guess is that this is related to floating point precision at large numbers away from zero (though you haven't said how far). This is something that's not currently handled internally so assuming that's what the issue is you'll have to adjust the model position and camera to be near zero.

Ok I updated the issue, the far away value is "x": -3761603.743620786, "y": 4105279.00727716, "z": 3870314.8490743843. it looks like a low poly version of my object when it's far but only with the path traced version.

Drosaca avatar Nov 14 '24 23:11 Drosaca

Try increasing the textureSize parameter: https://github.com/gkjohnson/three-gpu-pathtracer?tab=readme-ov-file#texturesize

I tried with 4096 but it doesn't change anything :(

Drosaca avatar Nov 15 '24 00:11 Drosaca

Ok I updated the issue, the far away value is "x": -3761603.743620786, "y": 4105279.00727716, "z": 3870314.8490743843. it looks like a low poly version of my object when it's far but only with the path traced version.

Yes these numbers are very large and will likely cause numeric precision issues when rendering. I recommend moving the camera and model closer to the origin to address the issue. This could probably be fixed automatically by the renderer but it would need to be implemented.

I tried with 4096 but it doesn't change anything :(

Yeah this won't help in this case, unfortunately, since it's a numeric problem.

gkjohnson avatar Nov 17 '24 04:11 gkjohnson

I recently read a chapter from Ray Tracing Gems 2 here that seem to address this exact issue. In Chapter 34 Ingo Wald suggests moving ray origin along the direction closer to the intersected primitive and perform test. The resulting distance should be modified afterwards to reflect the origin displacement. With regards to choosing the distance to move he writes following:

Even more generally, if one does have access to the bounding volume hierarchy traverser’s distance to the leaf node that contained the primitive (or if one used any sort of early-out bounding box test), then the distance to this bounding volume is an excellent choice.

With this, it sounds like the fix should be implemented in the three-mesh-bvh shader traversal step.

TheBlek avatar Sep 10 '25 03:09 TheBlek

Thanks @TheBlek. That may be one area for improvement but the fundamental issue here is that the geometry is transformed by the world matrices that use giant floating point values and merged into a monolothic model resulting in precision loss for the triangle vertices. You can see that the triangles are shifted significantly here (rasterized vs path traced view):

Image Image

Moving the triangles (and therefore camera) closer to the origin would help reduce any precision loss from these large values. Three.js specifically precomputes "cameraViewMatrix" on the CPU to take advantage of Javascript's 64-bit precision (and shifting the matrix values to be closer to an origin, ie the camera position) before uploading to the GPU in order to avoid these types of artifacts for calculations that need to be done on the graphic card. Ideally we'd be doing something similar here.

The type of precision issue discussed in the linked Chapter 34 is also important but I believe a different type of precision issue.

gkjohnson avatar Sep 11 '25 04:09 gkjohnson

the geometry is transformed by the world matrices that use giant floating point values and merged into a monolothic model resulting in precision loss for the triangle vertices.

Oh, now I think I get it. Pathtracer intersection code is happening in the world space, whereas projection during rasterization - in view space. Because of that rasterization view is unaffected by the precision loss when the camera is close to the object. Yeah, trick from the book is useless here.

We could shift the model into view space at the intersection time but that could be pretty slow because of matrix-vector multiplication happening for each vertex.

We could, on the other hand, pass each object individually and then shift the ray into each model's geometry space to perform an intersection. But then we lose on the traversal performance because we need to look at each object. Sounds like some kind of TLAS from https://github.com/gkjohnson/three-mesh-bvh/issues/388 or maybe https://github.com/gkjohnson/three-mesh-bvh/issues/651 would help here.

TheBlek avatar Sep 11 '25 07:09 TheBlek

Sounds like some kind of TLAS from gkjohnson/three-mesh-bvh#388 or maybe gkjohnson/three-mesh-bvh#651 would help here.

Yes these kinds of structures are still on my list - I'd like some to do some custom physics work, as well. I may be able to take another look at these raw data structures in the coming months.

gkjohnson avatar Sep 11 '25 07:09 gkjohnson