Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terrain collision processing on GPU #45

Merged
merged 14 commits into from Mar 16, 2018

Conversation

@kvark
Copy link
Owner

commented Mar 16, 2018

Closes #44

What is it

Main purpose of the PR is to introduce an alternative code path for processing terrain collisions. The original game used software rasterization with per-pixel collisions, so doing it on GPU now is much closer in spirit than trying to tessellate the bounding shape geometry and process the samples on CPU like the old code path did.
On the way to the goal, I introduced a few more architectural changes that were needed in order to fight the technical debt but are independent:

  • full shader pre-processor, which opens the way to porting to WebGL and mobile (more to follow!)
  • nicer internal App API that combines all the methods using gfx::Factory into a single one

How it works

Every car/object gets assigned a rectangle corresponding to it's local bounds in world scale. The rectangle is allocated in an atlas texture. The object is rendered into it, with the fragment shader fetching the terrain data and producing a spring force vector, which is written into the RGBA32F pixel.

After all the tracked objects are rendered, the down-sampling begins. A number of passes that play ping-pong between two render targets and carefully down-sample each of the object footprints (individually!) by summing (not averaging!) the samples inside 2x2 grid. Extra care is taken of the odd sizes. It's using instanced quad rendering, one instance per down-sampled rectangle, with coordinates generated in the vertex shader.

Resulting target has 1 texel per object, which is then copied into a download buffer for reading on the next frame.

Why this is cool

  • first ever GPU based physics in Rust? Yes, it's domain specific, but still
  • roughly 2K lines of code
  • GPU collisions can handle large number of objects
  • somewhat addresses the problem of synchronizing the terrain changes between CPU and GPU: with GPU physics we don't need those changes instantly (if ever?) and can afford more latency. Perhaps, the game is moving in the direction of computing most of the interactions on GPU.

Appendix

Notice the debug rendering of the GPU collision mipmap at the bottom left:
vangers-gpu-collisions

PR has a run-time dependency on gfx-rs/gfx#1882 for fixed texture readbacks. That new gfx_device_gl version needs to be published, but it's not a blocker to merge this.

As for the results, well, they need more work. The car feels very bouncy, and some investigation is needed to figure out what makes the collision contact hard in the original game.

Future work:

  • figure out the hard contact mechanics and port it as well to GPU
  • rasterize in world-aligned space rather than car-local (minor)
  • optimize the read-back to avoid stalls (currently, next frame is reading)

@kvark kvark merged commit 9c02fa2 into master Mar 16, 2018

2 checks passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
continuous-integration/travis-ci/push The Travis CI build passed
Details

@kvark kvark deleted the gpu-collision branch Mar 16, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.