|
| 1 | +.. _doc_xr_full_screen_effects: |
| 2 | + |
| 3 | +XR full screen effects |
| 4 | +====================== |
| 5 | + |
| 6 | +When adding custom full screen effects to your XR application, one approach is |
| 7 | +using a full screen quad and applying effects to that quad's shader. |
| 8 | +Add a :ref:`MeshInstance3D <class_MeshInstance3D>` node |
| 9 | +to your scene as a child of your :ref:`XRCamera3D <class_XRCamera3D>`, |
| 10 | +and set the ``mesh`` property to a :ref:`QuadMesh <class_QuadMesh>`. |
| 11 | +Set the width and height of the quad to ``2``. |
| 12 | + |
| 13 | +.. image:: img/xr_full_screen_effects_starting_quad.webp |
| 14 | + |
| 15 | +You can then add a shader to your quad to make it cover the screen. This is done by setting the |
| 16 | +vertex shader's ``POSITION`` built-in to ``vec4(VERTEX.xy, 1.0, 1.0)``. |
| 17 | +However, when creating an effect that is centered straight ahead in the user's view |
| 18 | +(such as a vignette effect), the end result may look incorrect in XR. |
| 19 | + |
| 20 | +Below shows captures of the right-eye view with a vignette shader, both from the headset and the render target itself. |
| 21 | +The left captures are an unmodified shader; the right captures adjust the full screen quad using the projection matrix. |
| 22 | +While the capture on the left is centered in the render target, it is off-center in the headset view. |
| 23 | +But, after applying the projection matrix, we see that the effect is centered in the headset itself. |
| 24 | + |
| 25 | +.. image:: img/xr_full_screen_effects_vignette_before_after.webp |
| 26 | + |
| 27 | +Applying the projection matrix |
| 28 | +------------------------------ |
| 29 | + |
| 30 | +To properly center the effect, the ``POSITION`` of the full screen quad |
| 31 | +needs to take the asymmetric field of view into account. To do this while also ensuring the quad |
| 32 | +has full coverage of the entire render target, we can subdivide the quad and apply the projection matrix |
| 33 | +to the inner vertices. Let's increase the subdivide width and depth of the quad. |
| 34 | + |
| 35 | +.. image:: img/xr_full_screen_effects_ending_quad.webp |
| 36 | + |
| 37 | +Then, in the vertex function of our shader, we apply an offset from the projection matrix to |
| 38 | +the inner vertices. Here's an example of how you might do this with the above simple vignette shader: |
| 39 | + |
| 40 | +.. code-block:: glsl |
| 41 | +
|
| 42 | + shader_type spatial; |
| 43 | + render_mode depth_test_disabled, skip_vertex_transform, unshaded, cull_disabled; |
| 44 | +
|
| 45 | + // Modify VERTEX.xy using the projection matrix to correctly center the effect. |
| 46 | + void vertex() { |
| 47 | + vec2 vert_pos = VERTEX.xy; |
| 48 | +
|
| 49 | + if (length(vert_pos) < 0.99) { |
| 50 | + vec4 offset = PROJECTION_MATRIX * vec4(0.0, 0.0, 1.0, 1.0); |
| 51 | + vert_pos += (offset.xy / offset.w); |
| 52 | + } |
| 53 | +
|
| 54 | + POSITION = vec4(vert_pos, 1.0, 1.0); |
| 55 | + } |
| 56 | +
|
| 57 | + void fragment() { |
| 58 | + ALBEDO = vec3(0.0); |
| 59 | + ALPHA = dot(UV * 2.0 - 1.0, UV * 2.0 - 1.0) * 2.0; |
| 60 | + } |
| 61 | +
|
| 62 | +
|
| 63 | +.. note:: For more info on asymmetric FOV and its purpose, see this |
| 64 | + `Meta Asymmetric Field of View FAQ <https://developers.meta.com/horizon/documentation/unity/unity-asymmetric-fov-faq/>`_. |
| 65 | + |
| 66 | +Limitations |
| 67 | +----------- |
| 68 | + |
| 69 | +This full screen effect method has no performance concerns for per-pixel effects such as the above vignette shader. |
| 70 | +However, it is not recommended to read from the screen texture when using this technique. |
| 71 | +Full screen effects that require reading from the screen texture effectively disable all rendering performance optimizations in XR. |
| 72 | +This is because, when reading from the screen texture, Godot makes a full copy of the render buffer; |
| 73 | +this drastically increases the workload for the GPU and can create performance concerns. |
0 commit comments