Skip to content

Commit c270749

Browse files
committed
Add a section about coordinate spaces to spatial.rst
1 parent 1228ab4 commit c270749

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

tutorials/shaders/shader_reference/spatial_shader.rst

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,3 +507,158 @@ If you want the lights to add together, add the light contribution to ``DIFFUSE_
507507
materials from appearing in screen-space reflections or refraction.
508508
:ref:`SDFGI <doc_using_sdfgi>` sharp reflections are not visible on transparent
509509
materials (only rough reflections are visible on transparent materials).
510+
511+
512+
513+
Coordinate spaces
514+
^^^^^^^^^^^^^^^^^
515+
516+
Spatial shaders do their work across multiple coordinate spaces. Some built-in variables with the same name are in different
517+
coordinate spaces in different processor functions.
518+
519+
+-------------------------------+----------------------------------------------------------------------------------------+
520+
| Coordinate space | Description |
521+
+===============================+========================================================================================+
522+
| Model space | Also called "local space" or "local coordinates". Called "object space" in |
523+
| | other renderers. Equivalent to the local coordinates used by Transform3D. |
524+
+-------------------------------+----------------------------------------------------------------------------------------+
525+
| World space | Equivalent to the global coordinates used by Transform3D. |
526+
| | |
527+
+-------------------------------+----------------------------------------------------------------------------------------+
528+
| View space | Coordinate space relative to the camera. |
529+
| | Called "camera space" or "eye space" in other renderers. |
530+
+-------------------------------+----------------------------------------------------------------------------------------+
531+
| Clip space | TODO |
532+
+-------------------------------+----------------------------------------------------------------------------------------+
533+
| Screen space | TODO |
534+
+-------------------------------+----------------------------------------------------------------------------------------+
535+
| Normalized device coordinates | Usually not used directly. ``xy`` alues range from ``-1.0`` to ``1.0``, with |
536+
| | ``(-1.0,-1.0)`` in the ``x`` and ``y`` being the upper-left corner of the screen, |
537+
| | and ``(1.0,1.0)`` the lower right. ``z`` ranges from ``0.0`` to ``1.0`` |
538+
+-------------------------------+----------------------------------------------------------------------------------------+
539+
540+
.. note::
541+
542+
Godot 4.3 introduced a change to clip space. If you are using a shader that uses clip space directly and was
543+
originally written for an earlier version, see `this <https://godotengine.org/article/introducing-reverse-z/>`_.
544+
545+
546+
547+
Working with coordinate spaces
548+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
549+
550+
You don't need to know much matrix math in order to use coordinate spaces. You can convert vectors between different coordinate spaces by using the built-in transform matrices.
551+
552+
To transform a *position* vector ``VERTEX`` from view space to world space, multiply it by
553+
the view-to-world matrix ``INV_VIEW_MATRIX``:
554+
555+
.. code-block:: glsl
556+
557+
void fragment() {
558+
vec3 position_world = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
559+
}
560+
561+
To transform a *direction* vector, such as ``NORMAL``, change the ``z`` field of the vec4 to ``0.0`` :
562+
563+
.. code-block:: glsl
564+
565+
void fragment() {
566+
vec3 normal_world = (INV_VIEW_MATRIX * vec4(NORMAL, 0.0)).xyz;
567+
}
568+
569+
You can also compose multiple transformations together. To transform ``VERTEX`` from model space to view space, first
570+
transform it from view to world space with ``MODEL_MATRIX``, then transform it from world space to view space with ``VIEW_MATRIX``.
571+
Note the order of the matrices:
572+
573+
.. code-block:: glsl
574+
575+
void vertex() {
576+
vec3 position_view = (VIEW_MATRIX * MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
577+
}
578+
579+
You can transform to one coordinate space, do some operations, and transform back. This code scales ``VERTEX`` in model space,
580+
translates it in world space, then transforms back into model space, so it can be passed to ``fragment()``:
581+
582+
.. code-block:: glsl
583+
584+
void vertex() {
585+
VERTEX *= 2.0;
586+
vec3 position_world = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
587+
position_world += vec3(1.0);
588+
VERTEX = (inverse(MODEL_MATRIX) * vec4(position_world, 1.0)).xyz;
589+
}
590+
591+
Clip space, screen space, and normalized device coordinates
592+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
593+
594+
Transforming between view space, clip space, and screen space is more complicated. You need to use normalized device coordinates,
595+
an intermediate coordinate space.
596+
597+
View space position to screen space UV:
598+
599+
.. code-block:: glsl
600+
601+
vec2 screen_uv_from_view(vec3 position_view, mat4 projection_matrix) {
602+
vec3 position_clip = projection_matrix * vec4(position_view, 1.0);
603+
vec3 ndc = position_clip.xyz / position_clip.w;
604+
return ndc.xy * 0.5 + 0.5;
605+
}
606+
607+
Screen space UV (and depth) to view space position:
608+
609+
.. code-block:: glsl
610+
611+
vec3 view_position_from_uv_depth(vec2 screen_uv, float depth, mat4 inv_projection_matrix) {
612+
vec3 ndc = vec3((screen_uv * 2.0) - 1.0, depth);
613+
vec4 position_view = inv_projection_matrix * vec4(ndc, 1.0);
614+
return position_view.xyz /= view_position.w;
615+
}
616+
617+
Clip space to screen space:
618+
619+
.. code-block:: glsl
620+
621+
vec2 screen_uv_from_clip(vec3 position_clip, mat4 projection_matrix) {
622+
vec3 ndc = position_clip.xyz / position_clip.w;
623+
return ndc.xy * 0.5 + 0.5;
624+
}
625+
626+
Screen space to clip space:
627+
628+
.. code-block:: glsl
629+
630+
vec3 clip_from_screen_uv_depth(vec3 ndc, float w) {
631+
// TODO
632+
}
633+
634+
Sometimes you may need to work with normalized device coordinates directly:
635+
636+
Clip space to NDC:
637+
638+
.. code-block:: glsl
639+
640+
vec3 ndc_from_clip(vec4 position_clip) {
641+
return position_clip.xyz / position_clip.w;
642+
}
643+
644+
Normalized device coordinates to clip space:
645+
646+
.. code-block:: glsl
647+
648+
// TODO
649+
650+
Normalized device coordinates to screen space:
651+
652+
.. code-block:: glsl
653+
654+
vec2 screen_uv_from_ndc(vec3 ndc)) {
655+
return ndc.xy * 0.5 + 0.5;
656+
}
657+
658+
Screen space (and depth) to normalized device coordinates:
659+
660+
.. code-block:: glsl
661+
662+
vec3 ndc_from_uv_depth(vec2 screen_uv, float depth)) {
663+
return vec3((screen_uv * 2.0) - 1.0, depth);
664+
}

0 commit comments

Comments
 (0)