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

World-space grid #872

Closed
emilk opened this issue Jan 23, 2023 · 4 comments · Fixed by #8234
Closed

World-space grid #872

emilk opened this issue Jan 23, 2023 · 4 comments · Fixed by #8234
Assignees
Labels
🟦 blueprint The data that defines our UI 🧑‍🎨 Design Requires UX/UI designer input 🔺 re_renderer affects re_renderer itself user-request This is a pressing issue for one of our users

Comments

@emilk
Copy link
Member

emilk commented Jan 23, 2023

The 3D spatial view should have an option to show the X^Y, X^Z, and Y^Z planes as grids, as common in 3D apps.

@emilk emilk added the 🔺 re_renderer affects re_renderer itself label Jan 23, 2023
@chengguizi
Copy link

Hi Rerun team, I am also interested in this feature. Showing a grid to tell the scale of the world is pretty useful feature!

@nasteyi
Copy link

nasteyi commented Mar 13, 2024

Hi!
+1, it would be very useful to have a 3D floor in a global coordinate system with adjustable cell size depending on the specifics of data you have to work with.

@Wumpf Wumpf added the user-request This is a pressing issue for one of our users label Apr 17, 2024
@Wumpf Wumpf added the 🟦 blueprint The data that defines our UI label Jul 9, 2024
@Wumpf
Copy link
Member

Wumpf commented Aug 1, 2024

There's three intertwined items we have to figure out for this:

  • what should it look like (out of the box at least) and how does it behave under zoom
  • what should be configurable
  • how do we render it in a clean fashion

References:

Both of these have a whole bunch of things in common

  • very thin, ui-constant sized lines (lines don't get smaller in the distance)
    • generally try not to get in the way!
  • fading everything but cardinal lines (every tenth line?)
  • fading in the distance

On cardinal lines: The problem mostly arises with zooming out. Fading lines is pretty much a must, otherwise the screen becomes gradually fully opaque no matter how small the lines are. So typically one would just fade everything but every tenth line (configurable?). That introduces a cardinality which likely should be expressed with a slightly different shader and/or thickness. Blender does this really well imho.

Another thing shown here is highlighting for cardinal axis. Blender has this configurable (for all axis independently!) but I'd keep this out for the moment, worth considering adding to the options.

Also seen in the blender clip is fading of the unlimited grid with distance which can be important to avoid artifacts as well. Unity actually just clips the lines off at some point. Which is also perfectly fine as long as the lines stay thin!


Unlike back in the day when this was first logged we now have a system in place for configuring views, and this is a great fit for that, so let's start by what the rough data modelling for this could look like:

table LineGuides3D {
    /// Whether the grid is visible.
    ///
    /// Default is true.
    visible: rerun.components.Visible ("attr.rerun.component_optional", nullable);

    /// The type of the grid.
    grid_type: rerun.blueprint.components.LineGuides3DType ("attr.rerun.component_optional", nullable);

    /// How the grid is oriented.
    orientation: rerun.blueprint.components.PlaneOrientation ("attr.rerun.component_optional", nullable);

    /// How thick the lines should be.
    ///
    /// Default is 0.5 ui unit. TODO: figure out exact value.
    // TODO: should we restrict this to small ui-based values? Scene values might be problematic.
    // TODO: alternatively, don't support this at all? Many professional tools don't seem to bother
    line_thickness: rerun.components.Radius ("attr.rerun.component_optional", nullable);

    /// Grid spacing of one line to the next.
    ///
    /// May differ per direction.
    ///
    /// Default is 1.0 in both directions.
    spacing: rerun.blueprint.components.GridSpacing ("attr.rerun.component_optional", nullable);

    /// Color of the grid lines.
    ///
    /// Default depends on background color
    // TODO: can we do inter-property in a sane way?
    color: rerun.components.Color ("attr.rerun.component_optional", nullable);

    /// Optional center of the grid, only relevant for non-infinite grids.
    center: rerun.components.Position3D ("attr.rerun.component_optional", nullable);

    /// Optional extent of the grid, only relevant for non-infinite grids.
    extent: rerun.components.HalfSize3D ("attr.rerun.component_optional", nullable);
}

enum LineGuides3DType: byte {
    /// A quasi-infinite grid is shown.
    Infinite (default),
    /// A finite grid anchored at a certain position.
    FinitePositioned,
}


enum PlaneOrientation: byte {
    /// A grid is shown in the XY plane.
    Xy (default),
    /// A grid is shown in the YZ plane.
    Yz,
    /// A grid is shown in the XZ plane.
    Xz,
}

Which brings us to the surprisingly hard topic of rendering:

There's Ben Golu's pristine grid shader which is quality-wise perfect (also comes in versions for grid zooming and cardinal line highlighting) and can easily handle all fading out requirements. However, getting intersection with objects (we don't want a plane) can be tricky. And most importantly, all the complexity in it comes from the fact that it's not after constant pixel width lines, which all of the reference examples used:

But there’s a catch. Most example grid shaders, like this one, use screen space width lines. That can be preferred over a texture based grid in a lot of use cases, and honestly probably what most people want. But it’s not what I’m trying to achieve.

That said there's still a lot to be learned from this article regardless!

As long as we use thin constant-pixel-width-lines our line shader may just do the right thing for us.
However, distance fade is still a concern for infinite grid that's hard to address since all lines converge to a solid (likely flickery) color.
For sufficiently thin lines it could be sufficient to have half of them shortened just when we know that they're getting too close together (this may be a shader or just some simple logic upon feeding the line renderer, note this is camera dependent). Questionable if this is quality-wise good enough.

Considerations for using a "shader on the plane" approach instead of a geometry (line renderer) based one

  • much better filter/blending can be achieved easily (see linked blog post above)
    • especially fading becomes easy
  • clean intersection / depth buffer interaction gets hard quickly!
    • possible workaround is to render the line-plane with alpha blending after the background (today background is rendered last). In order to facilitate some degree of interaction with alpha blended objects that render later, depth buffer write stays enabled and pixels that are barely visible are discarded
    • Counter point: Unity just ignores transparent object interaction with the grid!
    • Opaque: image
    • Transparent with alpha=255 (so fully opaque still, but different rendering mode): image
    • this indicates that the grid itself is seen as an object with transparency and Unity doesn't sort order independent transparency, so it can't solve this.
      • I believe if everything else is right, the same compromise is acceptable for us!
  • Potential quality & cpu side perf advantages need to be weighed against added complexity in render pipeline and perf costs on what amounts to almost a fullscreen pass (although technically drawn as a plane, it may fill the entire screen most of the time!)

So what should we do? I'm not sure right now. It's likely worth starting with our line renderer and see how bad it gets before working through an adjusted version of the "pristine grid" shader.

Not supporting world-space line widths seems the right way forward regardless, I don't think there's any practical reason for it.

@Wumpf
Copy link
Member

Wumpf commented Aug 1, 2024

Found blender's grid shader
https://github.com/blender/blender/blob/main/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl
(Don't copy anything as is, it's GPL licensed!)There's interesting things to be learned here - for instance lines are faded in the moment they are apart more than 4 pixels

The fact that there's so much going on in there to get the fading right makes me think more and more that using the general purpose line renderer is a dead end.

@emilk emilk added the 🧑‍🎨 Design Requires UX/UI designer input label Aug 5, 2024
@Wumpf Wumpf self-assigned this Nov 27, 2024
Wumpf added a commit that referenced this issue Nov 28, 2024
### Related

This is the first half of

* #872

The second half is here:
* #8234

### What

Implements a "world grid" to be used later in the spatial views of the
viewer.
Haven't tested yet how suitable this is for 2D views, might need some
adjustments.

## Video

Youtube unfortunately compresses this a lot and Github doesn't let me
upload any significant amount of video
(click me)
[![youtube video of world grid
v1](http://img.youtube.com/vi/Ho-iGdmJi4Q/0.jpg)](http://www.youtube.com/watch?v=Ho-iGdmJi4Q
"World Grid v1")

## Screenshots

Analytical anti-aliasing (shown is what is supposed to be a 1ui unit ==
2pixel wide line):
<img width="1215" alt="image"
src="https://github.com/user-attachments/assets/702b82ac-2629-4aa5-9304-0cd3c4d87fc5">

Distance has only the cardinal lines (== every tenth line). Those fade
eventually as well:
<img width="747" alt="image"
src="https://github.com/user-attachments/assets/ebe6b2c9-37e5-4406-8d28-5260cf2940d4">

Fading is based on "how many lines coincide here" which makes fading
view dependent rather than distance dependent:
<img width="439" alt="image"
src="https://github.com/user-attachments/assets/9bea7a42-9edc-4a7d-be19-9498a1f29fdf">
(this makes this hopefully robust for many usecases)

Grid intersects non-transparent geometry (transparent geometry will be
ignored in the future. previous surveying showed that this is common and
not a biggy)
<img width="426" alt="image"
src="https://github.com/user-attachments/assets/19de2cc9-015d-4fdd-a275-096768119a9e">

Grid fades at acute viewing angles (because empirically and
unsurprisingly it looks weird if we don't!)
<img width="1437" alt="image"
src="https://github.com/user-attachments/assets/2a05b8e5-9915-4dda-9a54-4db829e22ac3">

Tested image quality to be satisfying on high dpi (ui unit == 2 pixels)
and low dpi (ui unit == pixel).

## How does it work

* Draw a large shader generated plane (mostly because setting up vertex
buffers is just more hassle 😄 )
    * depth test enabled
    * depth write disabled
    * premultiplied alpha blend
* make sure we draw this after the background (reminder: we first draw
solid, then background)
* Fragment shader looks at 2d coordinate on the plane and decides how
"liney" it is
* using screen space derivatives (ddx/ddy) we figure out how far to go
on the plane to achieve a certain line thickness
   * fades:
        * fade if the line density gets too high
        * fade if view angle is too acute relative  
   * ... lot's of details documented in the shader code!

I considered just drawing a screen space triangle, but drawing a plane
that moves with the camera has lots of advantages:
* don't have to manipulate depth
    * faster since early z just works
    * less thinking required!
* don't cover things above the horizon - even if only the grid is
visible, less pixels will be shaded

## Known shortcomings

* various hardcoded values around how fading works. Tricky to formalize
this better, but likely good enough
* Doesn't look equally good at all pixel widths, but decent for the
range we care
* every tenth line is a "cardinal line", that's nice but it stops there
- "infinite" amount of cardinal lines would be nicer
* Experimented with that but so far didn't get anything that was
compelling. Having many order-of-magnitude lines looks way too busy
imho, it needs a mechanism that limits that to two.
* Blender's 2D view does this really well, but in 3D they only do two
cardinals as well.

## Try it yourself

Controls:
- Space: Pause
- G: Toggle camera mode

native:
```
cargo run -p re_renderer_examples --bin world_grid
```

web:
```
cargo run-wasm -p re_renderer_examples --bin world_grid
```


## Backend testing matrix

* [x] Metal
* [x] Vulkan
* [x] WebGL
* [x] WebGPU
@Wumpf Wumpf closed this as completed in 601afc8 Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🟦 blueprint The data that defines our UI 🧑‍🎨 Design Requires UX/UI designer input 🔺 re_renderer affects re_renderer itself user-request This is a pressing issue for one of our users
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants