ValveSoftware / ValveSoftware/source-sdk-2013
VBSP generates wrong collision for some brushes
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 10k
- Forks
- 3k
- Avg merge
- 8d 11h
- Merged PRs (30d)
- 2
Description
https://github.com/user-attachments/assets/f1d71779-8400-446a-bdbf-93a9e2a9738f
trikz_kyoto_fix
setpos 13485.354492 -10322.815430 -12656.668945
Explanation
The issue lies with
https://github.com/ValveSoftware/source-sdk-2013/blob/3300848d8a25ef6403c91f82a4cd97d6daefbc06/src/utils/vbsp/map.cpp#L471
Once an edge bevel plane is calculated, it is checked for correctness.
https://github.com/ValveSoftware/source-sdk-2013/blob/3300848d8a25ef6403c91f82a4cd97d6daefbc06/src/utils/vbsp/map.cpp#L564-L606
Afterwards CMapFile::FindFloatPlane is used to insert it into the map (line 601), but the function only does so after trying to SnapPlane to an axial one.
https://github.com/ValveSoftware/source-sdk-2013/blob/3300848d8a25ef6403c91f82a4cd97d6daefbc06/src/utils/vbsp/map.cpp#L336-L349
Aside from invalidating the earlier checks, this rounding will make the bevel plane's normal identical to one of the six mandatory axial brush sides added/verified earlier in CMapFile::AddBrushBevels. But convex brushes simply can't have two sides with the same normal, so the result is an incorrect collision against AABB (the only thing that uses bevel planes).
Such bevels are generated for edges that nearly coincide with an axial plane. For me, this occurs when copy-pasting or moving a brush: a vertex originally aligned to the unit grid gets shifted slightly.
Fix
Removing the rounding will do the job, but for edges less than a hundred units long, such bevels aren't really noticeable. So you might want to ignore them entirely if the edge is short, as this would also help stay under the maximum plane count.
To fix collision on already compiled maps, one could create a plugin that, after a level change, iterates through the map's brushes and removes every axial brush side beyond the first six.
Update: wrote my own fix https://github.com/L0jk4/AxialBevelRemover
Extra
Map from the clip decompiled with bevels taken into account to reflect AABB collision:
An exaggerated illustration of what's going on:
A visualization with accurate calculations:
https://www.desmos.com/calculator/dtupjyjppy
Another little bug
https://github.com/user-attachments/assets/6a2d8be1-ca89-440a-8528-7b79fb2ac93e
If an edge's direction is close enough to one of the axes, then it doesn't get any bevels. Therefore, brushes with such edges suffer a loss in collision accuracy:
https://github.com/ValveSoftware/source-sdk-2013/blob/3300848d8a25ef6403c91f82a4cd97d6daefbc06/src/utils/vbsp/map.cpp#L546-557
Thanks to Maru for helping me compile vbsp and tweaking bspsrc.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/utils/vbsp/map.cpp, reading CMapFile::AddBrushBevels, FindFloatPlane, and SnapPlane around the linked lines. Reproduce the reported collision with the linked map position, then trace both bevel-plane rounding and the near-axis edge case. Done means the affected brushes produce correct collision geometry without introducing invalid or duplicate axial planes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- game-dev, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100