|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
@@ -0,0 +1,367 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="717"
|
||||
height="213"
|
||||
viewBox="0 0 189.70625 56.356252"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="stretch.svg">
|
||||
<defs
|
||||
id="defs2">
|
||||
<marker
|
||||
inkscape:stockid="TriangleInS"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker6303"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path6301"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
transform="scale(-0.2)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleInS"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker6215"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path6213"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
transform="scale(-0.2)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker6133"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="TriangleInS">
|
||||
<path
|
||||
transform="scale(-0.2)"
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
id="path6131" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker5841"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="TriangleInS">
|
||||
<path
|
||||
transform="scale(-0.2)"
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
id="path5839" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleInS"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker5679"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path5677"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
transform="scale(-0.2)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker5495"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="TriangleInS"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
transform="scale(-0.2)"
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
id="path5493" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker5319"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="TriangleInS"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
transform="scale(-0.2)"
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
id="path5317" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleInM"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="TriangleInM"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4636"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
transform="scale(-0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Sstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Sstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4512"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
transform="scale(0.2) translate(6,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleInS"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="TriangleInS"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path4639"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#ff0505;stroke-width:1pt;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
transform="scale(-0.2)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker4821"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4819"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#ff0505;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
transform="scale(1.1) translate(1,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow2Lstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4518"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#ff0505;stroke-opacity:1;fill:#ff0505;fill-opacity:1"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
transform="scale(1.1) translate(1,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Lstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4500"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
|
||||
transform="scale(0.8) translate(12.5,0)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.95868201"
|
||||
inkscape:cx="250.0218"
|
||||
inkscape:cy="102.43412"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:snap-page="false"
|
||||
inkscape:snap-global="true"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="1027"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-240.64373)">
|
||||
<rect
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.05833328;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect4498"
|
||||
width="50.154053"
|
||||
height="35.322506"
|
||||
x="69.7761"
|
||||
y="244.69925" />
|
||||
<rect
|
||||
y="244.69925"
|
||||
x="132.2177"
|
||||
height="35.322506"
|
||||
width="50.154053"
|
||||
id="rect4770"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.05833328;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="244.69925"
|
||||
x="7.3344326"
|
||||
height="35.322506"
|
||||
width="50.154053"
|
||||
id="rect4772"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.05833328;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#e40b0b;stroke-width:1.05833328;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 71.18943,246.07916 h 47.3274 v 32.56264 h -47.3274 z"
|
||||
id="rect4774"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#e40b0b;stroke-width:1.05833328;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 8.7477624,246.07916 H 25.139557 v 10.89769 H 8.7477624 Z"
|
||||
id="path4783"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#e40b0b;stroke-width:1.05833328;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 148.72414,256.56665 h 17.14119 v 11.58766 h -17.14119 z"
|
||||
id="path4789"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0505;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInS)"
|
||||
d="m 75.523807,251.13928 3.512737,3.70788"
|
||||
id="path4791"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5315"
|
||||
d="m 113.77476,251.13928 -3.51274,3.70788"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0505;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker5679)" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5489"
|
||||
d="m 75.523807,274.24705 3.512737,-3.70788"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0505;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker5495)" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0505;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker5319)"
|
||||
d="m 113.77476,274.24705 -3.51274,-3.70788"
|
||||
id="path5491"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5831"
|
||||
d="m 137.38698,251.13928 3.51273,3.70788"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0505;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker5841)" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0505;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker6133)"
|
||||
d="m 175.63793,251.13928 -3.51274,3.70788"
|
||||
id="path5833"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0505;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker6303)"
|
||||
d="m 137.38698,274.24705 3.51273,-3.70788"
|
||||
id="path5835"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5837"
|
||||
d="m 175.63793,274.24705 -3.51274,-3.70788"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0505;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker6215)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46666622px;line-height:125%;font-family:Arial;-inkscape-font-specification:'Arial, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="15.906008"
|
||||
y="291.34055"
|
||||
id="text6841"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6839"
|
||||
x="15.906008"
|
||||
y="291.34055"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46666622px;font-family:Arial;-inkscape-font-specification:'Arial, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332px">Disabled</tspan></text>
|
||||
<text
|
||||
id="text6845"
|
||||
y="291.40256"
|
||||
x="89.536987"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46666622px;line-height:125%;font-family:Arial;-inkscape-font-specification:'Arial, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46666622px;font-family:Arial;-inkscape-font-specification:'Arial, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332px"
|
||||
y="291.40256"
|
||||
x="89.536987"
|
||||
sodipodi:role="line"
|
||||
id="tspan6851">2D</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46666622px;line-height:125%;font-family:Arial;-inkscape-font-specification:'Arial, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="140.88435"
|
||||
y="290.54886"
|
||||
id="text6849"><tspan
|
||||
sodipodi:role="line"
|
||||
x="140.88435"
|
||||
y="290.54886"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46666622px;font-family:Arial;-inkscape-font-specification:'Arial, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332px"
|
||||
id="tspan6855">Viewport</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -4,3 +4,6 @@ Rendering
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:name: toc-learn-features-rendering
|
||||
|
||||
viewports
|
||||
multiple_resolutions
|
||||
|
||||
@@ -0,0 +1,454 @@
|
||||
.. _doc_multiple_resolutions:
|
||||
|
||||
Multiple resolutions
|
||||
====================
|
||||
|
||||
The problem of multiple resolutions
|
||||
-----------------------------------
|
||||
|
||||
Developers often have trouble understanding how to best support multiple
|
||||
resolutions in their games. For desktop and console games, this is more or less
|
||||
straightforward, as most screen aspect ratios are 16:9 and resolutions
|
||||
are standard (720p, 1080p, 1440p, 4K, …).
|
||||
|
||||
For mobile games, at first, it was easy. For many years, the iPhone and iPad
|
||||
used the same resolution. When *Retina* was implemented, they just doubled
|
||||
the pixel density; most developers had to supply assets in default and double
|
||||
resolutions.
|
||||
|
||||
Nowadays, this is no longer the case, as there are plenty of different screen
|
||||
sizes, densities, and aspect ratios. Non-conventional sizes are also becoming
|
||||
increasingly popular, such as ultrawide displays.
|
||||
|
||||
For 3D games, there is not much of a need to support multiple resolutions (from
|
||||
the aesthetic point of view). The 3D geometry will just fill the screen based on
|
||||
the field of view, disregarding the aspect ratio. The main reason one may want
|
||||
to support this, in this case, is for *performance* reasons (running in lower
|
||||
resolution to increase frames per second).
|
||||
|
||||
For 2D and game UIs, this is a different matter, as art needs to be created
|
||||
using specific pixel sizes in software such as Photoshop, GIMP or Krita.
|
||||
|
||||
Since layouts, aspect ratios, resolutions, and pixel densities can change so
|
||||
much, it is no longer possible to design UIs for every specific screen.
|
||||
Another method must be used.
|
||||
|
||||
One size fits all
|
||||
-----------------
|
||||
|
||||
The most common approach is to use a single *base* resolution and
|
||||
then fit it to everything else. This resolution is how most players are expected
|
||||
to play the game (given their hardware). For mobile, Google has useful `stats
|
||||
<https://developer.android.com/about/dashboards>`_ online, and for desktop,
|
||||
Steam `also does <https://store.steampowered.com/hwsurvey/>`_.
|
||||
|
||||
As an example, Steam shows that the most common *primary display resolution* is
|
||||
1920×1080, so a sensible approach is to develop a game for this resolution, then
|
||||
handle scaling for different sizes and aspect ratios.
|
||||
|
||||
Godot provides several useful tools to do this easily.
|
||||
|
||||
Base size
|
||||
---------
|
||||
|
||||
A base size for the window can be specified in the Project Settings under
|
||||
**Display → Window**.
|
||||
|
||||
.. image:: img/screenres.png
|
||||
|
||||
However, what it does is not completely obvious; the engine will *not*
|
||||
attempt to switch the monitor to this resolution. Rather, think of this
|
||||
setting as the "design size", i.e. the size of the area that you work
|
||||
with in the editor. This setting corresponds directly to the size of the
|
||||
blue rectangle in the 2D editor.
|
||||
|
||||
There is often a need to support devices with screen and window sizes
|
||||
that are different from this base size. Godot offers many ways to
|
||||
control how the viewport will be resized and stretched to different
|
||||
screen sizes.
|
||||
|
||||
.. note::
|
||||
|
||||
Godot follows a modern approach to multiple resolutions. The engine will
|
||||
never change the monitor's resolution on its own. While changing the
|
||||
monitor's resolution is the most efficient approach, it's also the least
|
||||
reliable approach as it can leave the monitor stuck on a low resolution if
|
||||
the game crashes. This is especially common on macOS or Linux which don't
|
||||
handle resolution changes as well as Windows.
|
||||
|
||||
Changing the monitor's resolution also removes any control from the game
|
||||
developer over filtering and aspect ratio stretching, which can be important
|
||||
to ensure correct display for pixel art games.
|
||||
|
||||
On top of that, changing the monitor's resolution makes alt-tabbing in and
|
||||
out of a game much slower since the monitor has to change resolutions every
|
||||
time this is done.
|
||||
|
||||
Resizing
|
||||
--------
|
||||
|
||||
There are several types of devices, with several types of screens, which
|
||||
in turn have different pixel density and resolutions. Handling all of
|
||||
them can be a lot of work, so Godot tries to make the developer's life a
|
||||
little easier. The :ref:`Viewport <class_Viewport>`
|
||||
node has several functions to handle resizing, and the root node of the
|
||||
scene tree is always a viewport (scenes loaded are instanced as a child
|
||||
of it, and it can always be accessed by calling
|
||||
``get_tree().get_root()`` or ``get_node("/root")``).
|
||||
|
||||
In any case, while changing the root Viewport params is probably the
|
||||
most flexible way to deal with the problem, it can be a lot of work,
|
||||
code and guessing, so Godot provides a simple set of parameters in the
|
||||
project settings to handle multiple resolutions.
|
||||
|
||||
Stretch settings
|
||||
----------------
|
||||
|
||||
Stretch settings are located in the project settings and provide several options:
|
||||
|
||||
.. image:: img/stretchsettings.png
|
||||
|
||||
Stretch Mode
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The **Stretch Mode** setting defines how the base size is stretched to fit
|
||||
the resolution of the window or screen.
|
||||
|
||||
.. image:: img/stretch.png
|
||||
|
||||
The animations below use a "base size" of just 16×9 pixels to
|
||||
demonstrate the effect of different stretch modes. A single sprite, also
|
||||
16×9 pixels in size, covers the entire viewport, and a diagonal
|
||||
:ref:`Line2D <class_Line2D>` is added on top of it:
|
||||
|
||||
.. image:: img/stretch_demo_scene.png
|
||||
|
||||
.. Animated GIFs are generated from:
|
||||
.. https://github.com/ttencate/godot_scaling_mode
|
||||
|
||||
- **Stretch Mode = Disabled** (default): No stretching happens. One
|
||||
unit in the scene corresponds to one pixel on the screen. In this
|
||||
mode, the **Stretch Aspect** setting has no effect.
|
||||
|
||||
This is a good option if you want full control over every screen
|
||||
pixel, and is probably the best option for 3D games.
|
||||
|
||||
.. image:: img/stretch_disabled_expand.gif
|
||||
|
||||
- **Stretch Mode = 2D**: In this mode, the size specified in
|
||||
display/width and display/height in the project settings is
|
||||
stretched to cover the whole screen (taking the **Stretch Aspect**
|
||||
setting into account). This means that everything is rendered
|
||||
directly at the target resolution. 3D is largely unaffected,
|
||||
while in 2D, there is no longer a 1:1 correspondence between sprite
|
||||
pixels and screen pixels, which may result in scaling artifacts.
|
||||
|
||||
This is a good option if your 2D artwork has a sufficiently high
|
||||
resolution and does not require pixel-perfect rendering. Consider
|
||||
enabling texture filtering and mipmapping on your 2D textures and
|
||||
fonts.
|
||||
|
||||
.. image:: img/stretch_2d_expand.gif
|
||||
|
||||
- **Stretch Mode = Viewport**: Viewport scaling means that the size of
|
||||
the root :ref:`Viewport <class_Viewport>` is set precisely to the
|
||||
base size specified in the Project Settings' **Display** section.
|
||||
The scene is rendered to this viewport first. Finally, this viewport
|
||||
is scaled to fit the screen (taking the **Stretch Aspect** setting into
|
||||
account).
|
||||
|
||||
This mode is useful when working with pixel-precise games, or for the
|
||||
sake of rendering to a lower resolution to improve performance.
|
||||
|
||||
.. image:: img/stretch_viewport_expand.gif
|
||||
|
||||
Stretch Aspect
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The second setting is the stretch aspect. Note that this only takes effect if
|
||||
**Stretch Mode** is set to something other than **Disabled**.
|
||||
|
||||
In the animations below, you will notice gray and black areas. The black
|
||||
areas are added by the engine and cannot be drawn into. The gray areas
|
||||
are part of your scene, and can be drawn to. The gray areas correspond
|
||||
to the region outside the blue frame you see in the 2D editor.
|
||||
|
||||
- **Stretch Aspect = Ignore**: Ignore the aspect ratio when stretching
|
||||
the screen. This means that the original resolution will be stretched
|
||||
to exactly fill the screen, even if it's wider or narrower. This may
|
||||
result in nonuniform stretching: things looking wider or taller than
|
||||
designed.
|
||||
|
||||
.. image:: img/stretch_viewport_ignore.gif
|
||||
|
||||
- **Stretch Aspect = Keep**: Keep aspect ratio when stretching the
|
||||
screen. This means that the viewport retains its original size
|
||||
regardless of the screen resolution, and black bars will be added to
|
||||
the top/bottom of the screen ("letterboxing") or the sides
|
||||
("pillarboxing").
|
||||
|
||||
This is a good option if you know the aspect ratio of your target
|
||||
devices in advance, or if you don't want to handle different aspect
|
||||
ratios.
|
||||
|
||||
.. image:: img/stretch_viewport_keep.gif
|
||||
|
||||
- **Stretch Aspect = Keep Width**: Keep aspect ratio when stretching the
|
||||
screen. If the screen is wider than the base size, black bars are
|
||||
added at the left and right (pillarboxing). But if the screen is
|
||||
taller than the base resolution, the viewport will be grown in the
|
||||
vertical direction (and more content will be visible to the bottom).
|
||||
You can also think of this as "Expand Vertically".
|
||||
|
||||
This is usually the best option for creating GUIs or HUDs that scale,
|
||||
so some controls can be anchored to the bottom
|
||||
(:ref:`doc_size_and_anchors`).
|
||||
|
||||
.. image:: img/stretch_viewport_keep_width.gif
|
||||
|
||||
- **Stretch Aspect = Keep Height**: Keep aspect ratio when stretching
|
||||
the screen. If the screen is taller than the base size, black
|
||||
bars are added at the top and bottom (letterboxing). But if the
|
||||
screen is wider than the base resolution, the viewport will be grown
|
||||
in the horizontal direction (and more content will be visible to the
|
||||
right). You can also think of this as "Expand Horizontally".
|
||||
|
||||
This is usually the best option for 2D games that scroll horizontally
|
||||
(like runners or platformers).
|
||||
|
||||
.. image:: img/stretch_viewport_keep_height.gif
|
||||
|
||||
- **Stretch Aspect = Expand**: Keep aspect ratio when stretching the
|
||||
screen, but keep neither the base width nor height. Depending on the
|
||||
screen aspect ratio, the viewport will either be larger in the
|
||||
horizontal direction (if the screen is wider than the base size) or
|
||||
in the vertical direction (if the screen is taller than the original
|
||||
size).
|
||||
|
||||
.. image:: img/stretch_viewport_expand.gif
|
||||
|
||||
.. tip::
|
||||
|
||||
To support both portrait and landscape mode with a similar automatically
|
||||
determined scale factor, set your project's base resolution to be a *square*
|
||||
(1:1 aspect ratio) instead of a rectangle. For instance, if you wish to design
|
||||
for 1280×720 as the base resolution but wish to support both portrait and
|
||||
landscape mode, use 720×720 as the project's base window size in the
|
||||
Project Settings.
|
||||
|
||||
To allow the user to choose their preferred screen orientation at run-time,
|
||||
remember to set **Display > Window > Handheld > Orientation** to ``sensor``.
|
||||
|
||||
Stretch Shrink
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The **Shrink** setting allows you to add an extra scaling factor on top of
|
||||
what the **Stretch** options above already provide. The default value of 1
|
||||
means that no scaling occurs.
|
||||
|
||||
If, for example, you set **Shrink** to 4 and leave **Stretch Mode** on
|
||||
**Disabled**, each unit in your scene will correspond to 4×4 pixels on the
|
||||
screen.
|
||||
|
||||
If **Stretch Mode** is set to something other than **Disabled**, the size of
|
||||
the root viewport is scaled down by the **Shrink** factor, and pixels
|
||||
in the output are scaled up by the same amount. This is rarely useful for
|
||||
2D games, but can be used to increase performance in 3D games
|
||||
by rendering them at a lower resolution.
|
||||
|
||||
From scripts
|
||||
^^^^^^^^^^^^
|
||||
|
||||
To configure stretching at runtime from a script, use the
|
||||
``get_tree().set_screen_stretch()`` method (see
|
||||
:ref:`SceneTree.set_screen_stretch() <class_SceneTree_method_set_screen_stretch>`).
|
||||
|
||||
Common use case scenarios
|
||||
-------------------------
|
||||
|
||||
The following settings are recommended to support multiple resolutions and aspect
|
||||
ratios well.
|
||||
|
||||
Desktop game
|
||||
^^^^^^^^^^^^
|
||||
|
||||
**Non-pixel art:**
|
||||
|
||||
- Set the base window width to ``1920`` and window height to ``1080``. If you have a
|
||||
display smaller than 1920×1080, set **Test Width** and **Test Height** to
|
||||
lower values to make the window smaller when the project starts.
|
||||
- Alternatively, if you're targeting high-end devices primarily, set the base
|
||||
window width to ``3840`` and window height to ``2160``.
|
||||
This allows you to provide higher resolution 2D assets, resulting in crisper
|
||||
visuals at the cost of higher memory usage and file sizes.
|
||||
Note that this will make non-mipmapped textures grainy on low resolution devices,
|
||||
so make sure to follow the instructions described in
|
||||
:ref:`doc_multiple_resolutions_reducing_aliasing_on_downsampling`.
|
||||
- Set the stretch mode to ``2d``.
|
||||
- Set the stretch aspect to ``expand``. This allows for supporting multiple aspect ratios
|
||||
and makes better use of tall smartphone displays (such as 18:9 or 19:9 aspect ratios).
|
||||
- Configure Control nodes' anchors to snap to the correct corners using the **Layout** menu.
|
||||
|
||||
**Pixel art:**
|
||||
|
||||
- Set the base window size to the viewport size you intend to use. Most pixel art games
|
||||
use viewport sizes between 256×224 and 640×480. Higher viewport sizes will
|
||||
require using higher resolution artwork, unless you intend to show more of the
|
||||
game world at a given time.
|
||||
- Set the stretch mode to ``viewport``.
|
||||
- Set the stretch aspect to ``keep`` to enforce a single aspect ratio (with
|
||||
black bars). As an alternative, you can set the stretch aspect to ``expand`` to
|
||||
support multiple aspect ratios.
|
||||
- If using the ``expand`` stretch aspect, Configure Control nodes' anchors to
|
||||
snap to the correct corners using the **Layout** menu.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``viewport`` stretch mode provides low-resolution rendering that is then
|
||||
stretched to the final window size. If you are OK with sprites being able to
|
||||
move or rotate in "sub-pixel" positions or wish to have a high resolution 3D
|
||||
viewport, you should use the ``2d`` stretch mode instead of the ``viewport``
|
||||
stretch mode.
|
||||
|
||||
Godot currently doesn't have a way to enforce integer scaling when using the
|
||||
``2d`` or ``viewport`` stretch mode, which means pixel art may look bad if the
|
||||
final window size is not a multiple of the base window size.
|
||||
To fix this, use an add-on such as the `Integer Resolution Handler <https://github.com/Yukitty/godot-addon-integer_resolution_handler>`__.
|
||||
|
||||
Mobile game in landscape mode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Godot is configured to use landscape mode by default. This means you don't need
|
||||
to change the display orientation project setting.
|
||||
|
||||
- Set the base window width to ``1280`` and window height to ``720``.
|
||||
- Alternatively, if you're targeting high-end devices primarily, set the base
|
||||
window width to ``1920`` and window height to ``1080``.
|
||||
This allows you to provide higher resolution 2D assets, resulting in crisper
|
||||
visuals at the cost of higher memory usage and file sizes. Many devices have
|
||||
even higher resolution displays (1440p), but the difference with 1080p is
|
||||
barely visible given the small size of smartphone displays.
|
||||
Note that this will make non-mipmapped textures grainy on low resolution devices,
|
||||
so make sure to follow the instructions described in
|
||||
:ref:`doc_multiple_resolutions_reducing_aliasing_on_downsampling`.
|
||||
- Set the stretch mode to ``2d``.
|
||||
- Set the stretch aspect to ``expand``. This allows for supporting multiple aspect ratios
|
||||
and makes better use of tall smartphone displays (such as 18:9 or 19:9 aspect ratios).
|
||||
- Configure Control nodes' anchors to snap to the correct corners using the **Layout** menu.
|
||||
|
||||
Mobile game in portrait mode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Set the base window width to ``720`` and window height to ``1080``.
|
||||
- Alternatively, if you're targeting high-end devices primarily, set the base
|
||||
window width to ``1080`` and window height to ``1920``.
|
||||
This allows you to provide higher resolution 2D assets, resulting in crisper
|
||||
visuals at the cost of higher memory usage and file sizes. Many devices have
|
||||
even higher resolution displays (1440p), but the difference with 1080p is
|
||||
barely visible given the small size of smartphone displays.
|
||||
Note that this will make non-mipmapped textures grainy on low resolution devices,
|
||||
so make sure to follow the instructions described in
|
||||
:ref:`doc_multiple_resolutions_reducing_aliasing_on_downsampling`.
|
||||
- Set **Display > Window > Handheld > Orientation** to ``portrait``.
|
||||
- Set the stretch mode to ``2d``.
|
||||
- Set the stretch aspect to ``expand``. This allows for supporting multiple aspect ratios
|
||||
and makes better use of tall smartphone displays (such as 18:9 or 19:9 aspect ratios).
|
||||
- Configure Control nodes' anchors to snap to the correct corners using the **Layout** menu.
|
||||
|
||||
Non-game application
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Set the base window width and height to the smallest window size that you intend to target.
|
||||
This is not required, but this ensures that you design your UI with small window sizes in mind.
|
||||
- Keep the stretch mode to its default value, ``disabled``.
|
||||
- Keep the stretch aspect to its default value, ``ignore``
|
||||
(its value won't be used since the stretch mode is ``disabled``).
|
||||
- You can define a minimum window size by setting ``OS.min_window_size`` in a
|
||||
script's ``_ready()`` function. This prevents the user from resizing the application
|
||||
below a certain size, which could break the UI layout.
|
||||
|
||||
.. note::
|
||||
|
||||
Godot doesn't support manually overriding the 2D scale factor yet, so it is
|
||||
not possible to have hiDPI support in non-game applications. Due to this, it
|
||||
is recommended to leave **Allow Hidpi** disabled in non-game applications to
|
||||
allow for the OS to use its low-DPI fallback.
|
||||
|
||||
hiDPI support
|
||||
-------------
|
||||
|
||||
By default, Godot projects aren't considered DPI-aware by the operating system.
|
||||
This is done to improve performance on low-end systems, since the operating
|
||||
system's DPI fallback scaling will be faster than letting the application scale
|
||||
itself (even when using the ``viewport`` stretch mode).
|
||||
|
||||
However, the OS-provided DPI fallback scaling doesn't play well with fullscreen
|
||||
mode. If you want crisp visuals on hiDPI displays or if project uses fullscreen,
|
||||
it's recommended to enable **Display > Window > Dpi > Allow Hidpi** in the
|
||||
Project Settings.
|
||||
|
||||
**Allow Hidpi** is only effective on Windows and macOS. It's ignored on all
|
||||
other platforms.
|
||||
|
||||
.. note::
|
||||
|
||||
The Godot editor itself is always marked as DPI-aware. Running the project
|
||||
from the editor will only be DPI-aware if **Allow Hidpi** is enabled in the
|
||||
Project Settings.
|
||||
|
||||
.. _doc_multiple_resolutions_reducing_aliasing_on_downsampling:
|
||||
|
||||
Reducing aliasing on downsampling
|
||||
---------------------------------
|
||||
|
||||
If the game has a very high base resolution (e.g. 3840×2160), aliasing might
|
||||
appear when downsampling to something considerably lower like 1280×720.
|
||||
Aliasing can be made less visible by shrinking all images by a factor of 2
|
||||
upon loading. This can be done by calling the method below before
|
||||
the game data is loaded::
|
||||
|
||||
VisualServer.texture_set_shrink_all_x2_on_set_data(true)
|
||||
|
||||
Alternatively, you can also enable mipmaps on all your 2D textures. However,
|
||||
enabling mipmaps will increase memory usage which may be problematic on low-end
|
||||
mobile devices.
|
||||
|
||||
Handling aspect ratios
|
||||
----------------------
|
||||
|
||||
Once scaling for different resolutions is accounted for, make sure that
|
||||
your *user interface* also scales for different aspect ratios. This can be
|
||||
done using :ref:`anchors <doc_size_and_anchors>` and/or :ref:`containers
|
||||
<doc_gui_containers>`.
|
||||
|
||||
Field of view scaling
|
||||
---------------------
|
||||
|
||||
The 3D Camera node's **Keep Aspect** property defaults to the **Keep Height**
|
||||
scaling mode (also called *Hor+*). This is usually the best value for desktop
|
||||
games and mobile games in landscape mode, as widescreen displays will
|
||||
automatically use a wider field of view.
|
||||
|
||||
However, if your 3D game is intended to be played in portrait mode, it may make
|
||||
more sense to use **Keep Width** instead (also called *Vert-*). This way,
|
||||
smartphones with an aspect ratio taller than 16:9 (e.g. 19:9) will use a
|
||||
*taller* field of view, which is more logical here.
|
||||
|
||||
Scaling 2D and 3D elements differently using Viewports
|
||||
------------------------------------------------------
|
||||
|
||||
Using multiple Viewport nodes, you can have different scales for various
|
||||
elements. For instance, you can use this to render the 3D world at a low
|
||||
resolution while keeping 2D elements at the native resolution. This can improve
|
||||
performance significantly while keeping the HUD and other 2D elements crisp.
|
||||
|
||||
This is done by using the root Viewport node only for 2D elements, then creating
|
||||
a Viewport node to display the 3D world and displaying it using a
|
||||
ViewportContainer or TextureRect node. There will effectively be two viewports
|
||||
in the final project. One upside of using TextureRect over ViewportContainer is
|
||||
that it allows enable linear filtering. This makes scaled 3D viewports look
|
||||
better in many cases.
|
||||
|
||||
See the
|
||||
`3D viewport scaling demo <https://github.com/godotengine/godot-demo-projects/tree/master/viewport/3d_scaling>`__
|
||||
for examples.
|
||||
@@ -0,0 +1,254 @@
|
||||
.. _doc_viewports:
|
||||
|
||||
Using Viewports
|
||||
===============
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Think of a :ref:`Viewport <class_Viewport>` as a screen onto which the game is projected. In order
|
||||
to see the game, we need to have a surface on which to draw it; that surface is
|
||||
the Root :ref:`Viewport <class_Viewport>`.
|
||||
|
||||
.. image:: img/viewportnode.png
|
||||
|
||||
|
||||
:ref:`Viewports <class_Viewport>` can also be added to the scene so that there
|
||||
are multiple surfaces to draw on. When we are drawing to a :ref:`Viewport <class_Viewport>`
|
||||
that is not the Root, we call it a render target. We can access the contents
|
||||
of a render target by accessing its corresponding :ref:`texture <class_ViewportTexture>`.
|
||||
By using a :ref:`Viewport <class_Viewport>` as a render target,
|
||||
we can either render multiple scenes simultaneously or we can render to
|
||||
a :ref:`texture <class_ViewportTexture>` which is applied to an object in the scene, for example a dynamic
|
||||
skybox.
|
||||
|
||||
:ref:`Viewports <class_Viewport>` have a variety of use cases, including:
|
||||
|
||||
- Rendering 3D objects within a 2D game
|
||||
- Rendering 2D elements in a 3D game
|
||||
- Rendering dynamic textures
|
||||
- Generating procedural textures at runtime
|
||||
- Rendering multiple cameras in the same scene
|
||||
|
||||
What all these use cases have in common is that you are given the ability to
|
||||
draw objects to a texture as if it were another screen and can then choose
|
||||
what to do with the resulting texture.
|
||||
|
||||
Input
|
||||
-----
|
||||
|
||||
:ref:`Viewports <class_Viewport>` are also responsible for delivering properly adjusted and
|
||||
scaled input events to all their children nodes. Typically, input is received by the
|
||||
nearest :ref:`Viewport <class_Viewport>` in the tree, but you can set :ref:`Viewports <class_Viewport>` not to receive input by checking
|
||||
'Disable Input' to 'on'; this will allow the next nearest :ref:`Viewport <class_Viewport>` in the tree to capture
|
||||
the input.
|
||||
|
||||
.. image:: img/input.png
|
||||
|
||||
For more information on how Godot handles input, please read the :ref:`Input Event Tutorial<doc_inputevent>`.
|
||||
|
||||
Listener
|
||||
--------
|
||||
|
||||
Godot supports 3D sound (in both 2D and 3D nodes); more on this can be
|
||||
found in the :ref:`Audio Streams Tutorial<doc_audio_streams>`. For this type of sound to be
|
||||
audible, the :ref:`Viewport <class_Viewport>` needs to be enabled as a listener (for 2D or 3D).
|
||||
If you are using a custom :ref:`Viewport <class_Viewport>` to display your :ref:`World <class_World>`, don't forget
|
||||
to enable this!
|
||||
|
||||
Cameras (2D & 3D)
|
||||
-----------------
|
||||
|
||||
When using a :ref:`Camera <class_Camera>` /
|
||||
:ref:`Camera2D <class_Camera2D>`, cameras will always display on the
|
||||
closest parent :ref:`Viewport <class_Viewport>` (going towards the root). For example, in the
|
||||
following hierarchy:
|
||||
|
||||
.. image:: img/cameras.png
|
||||
|
||||
CameraA will display on the Root :ref:`Viewport <class_Viewport>` and it will draw MeshA. CameraB
|
||||
will be captured by the :ref:`Viewport <class_Viewport>` Node along with MeshB. Even though MeshB is in the scene
|
||||
hierarchy, it will still not be drawn to the Root :ref:`Viewport <class_Viewport>`. Similarly MeshA will not
|
||||
be visible from the :ref:`Viewport <class_Viewport>` node because :ref:`Viewport <class_Viewport>` nodes only
|
||||
capture nodes below them in the hierarchy.
|
||||
|
||||
There can only be one active camera per :ref:`Viewport <class_Viewport>`, so if there is more
|
||||
than one, make sure that the desired one has the "current" property set,
|
||||
or make it the current camera by calling:
|
||||
|
||||
::
|
||||
|
||||
camera.make_current()
|
||||
|
||||
By default, cameras will render all objects in their world. In 3D, cameras can use their
|
||||
:ref:`cull_mask <class_Camera_property_cull_mask>` property combined with the
|
||||
:ref:`VisualInstance's <class_VisualInstance>` :ref:`layer <class_VisualInstance_property_layers>`
|
||||
property to restrict which objects are rendered.
|
||||
|
||||
Scale & stretching
|
||||
------------------
|
||||
|
||||
:ref:`Viewports <class_Viewport>` have a "size" property, which represents the size of the :ref:`Viewport <class_Viewport>`
|
||||
in pixels. For :ref:`Viewports <class_Viewport>` which are children of :ref:`ViewportContainers <class_viewportcontainer>`,
|
||||
these values are overridden, but for all others, this sets their resolution.
|
||||
|
||||
It is also possible to scale the 2D content and make the :ref:`Viewport <class_Viewport>` resolution
|
||||
different from the one specified in size, by calling:
|
||||
|
||||
::
|
||||
|
||||
viewport.set_size_override(true, Vector2(width, height)) # Custom size for 2D.
|
||||
viewport.set_size_override_stretch(true) # Enable stretch for custom size.
|
||||
|
||||
The root :ref:`Viewport <class_Viewport>` uses this for the stretch options in the project
|
||||
settings. For more information on scaling and stretching visit the :ref:`Multiple Resolutions Tutorial <doc_multiple_resolutions>`
|
||||
|
||||
Worlds
|
||||
------
|
||||
|
||||
For 3D, a :ref:`Viewport <class_Viewport>` will contain a :ref:`World <class_World>`. This
|
||||
is basically the universe that links physics and rendering together.
|
||||
Spatial-based nodes will register using the :ref:`World <class_World>` of the closest
|
||||
:ref:`Viewport <class_Viewport>`. By default, newly created :ref:`Viewports <class_Viewport>` do not contain a :ref:`World <class_World>` but
|
||||
use the same as their parent :ref:`Viewport <class_Viewport>` (the root :ref:`Viewport <class_Viewport>` always contains a
|
||||
:ref:`World <class_World>`, which is the one objects are rendered to by default). A :ref:`World <class_World>` can
|
||||
be set in a :ref:`Viewport <class_Viewport>` using the "world" property, and that will separate
|
||||
all children nodes of that :ref:`Viewport <class_Viewport>` from interacting with the parent
|
||||
:ref:`Viewport's <class_Viewport>` :ref:`World <class_World>`. This is especially useful in scenarios where, for
|
||||
example, you might want to show a separate character in 3D imposed over
|
||||
the game (like in StarCraft).
|
||||
|
||||
As a helper for situations where you want to create :ref:`Viewports <class_Viewport>` that
|
||||
display single objects and don't want to create a :ref:`World <class_World>`, :ref:`Viewport <class_Viewport>` has
|
||||
the option to use its own :ref:`World <class_World>`. This is useful when you want to
|
||||
instance 3D characters or objects in a 2D :ref:`World <class_World2D>`.
|
||||
|
||||
For 2D, each :ref:`Viewport <class_Viewport>` always contains its own :ref:`World2D <class_World2D>`.
|
||||
This suffices in most cases, but in case sharing them may be desired, it
|
||||
is possible to do so by setting the :ref:`Viewport's <class_Viewport>` :ref:`World2D <class_World2D>` manually.
|
||||
|
||||
For an example of how this works, see the demo projects `3D in 2D <https://github.com/godotengine/godot-demo-projects/tree/master/viewport/3d_in_2d>`_ and `2D in 3D <https://github.com/godotengine/godot-demo-projects/tree/master/viewport/2d_in_3d>`_ respectively.
|
||||
|
||||
Capture
|
||||
-------
|
||||
|
||||
It is possible to query a capture of the :ref:`Viewport <class_Viewport>` contents. For the root
|
||||
:ref:`Viewport <class_Viewport>`, this is effectively a screen capture. This is done with the
|
||||
following code:
|
||||
|
||||
::
|
||||
|
||||
# Retrieve the captured Image using get_data().
|
||||
var img = get_viewport().get_texture().get_data()
|
||||
# Flip on the Y axis.
|
||||
# You can also set "V Flip" to true if not on the root Viewport.
|
||||
img.flip_y()
|
||||
# Convert Image to ImageTexture.
|
||||
var tex = ImageTexture.new()
|
||||
tex.create_from_image(img)
|
||||
# Set Sprite Texture.
|
||||
$sprite.texture = tex
|
||||
|
||||
But if you use this in ``_ready()`` or from the first frame of the :ref:`Viewport's <class_Viewport>` initialization,
|
||||
you will get an empty texture because there is nothing to get as texture. You can deal with
|
||||
it using (for example):
|
||||
|
||||
::
|
||||
|
||||
# Wait until the frame has finished before getting the texture.
|
||||
yield(VisualServer, "frame_post_draw")
|
||||
# You can get the image after this.
|
||||
|
||||
Viewport Container
|
||||
------------------
|
||||
|
||||
If the :ref:`Viewport <class_Viewport>` is a child of a :ref:`ViewportContainer <class_viewportcontainer>`, it will become active and display anything it has inside. The layout looks like this:
|
||||
|
||||
.. image:: img/container.png
|
||||
|
||||
The :ref:`Viewport <class_Viewport>` will cover the area of its parent :ref:`ViewportContainer <class_viewportcontainer>` completely
|
||||
if :ref:`Stretch<class_viewportcontainer_property_stretch>` is set to ``true`` in :ref:`ViewportContainer <class_viewportcontainer>`.
|
||||
Note: The size of the :ref:`ViewportContainer <class_viewportcontainer>` cannot be smaller than the size of the :ref:`Viewport <class_Viewport>`.
|
||||
|
||||
Rendering
|
||||
---------
|
||||
|
||||
Due to the fact that the :ref:`Viewport <class_Viewport>` is an entryway into another rendering surface, it exposes a few
|
||||
rendering properties that can be different from the project settings. The first is MSAA; you can
|
||||
choose to use a different level of MSAA for each :ref:`Viewport <class_Viewport>`; the default behavior is DISABLED.
|
||||
You can also set the :ref:`Viewport <class_Viewport>` to use HDR, HDR is very useful for when you want to store values in the texture that are outside the range 0.0 - 1.0.
|
||||
|
||||
If you know how the :ref:`Viewport <class_Viewport>` is going to be used, you can set its Usage to either 3D or 2D. Godot will then
|
||||
restrict how the :ref:`Viewport <class_Viewport>` is drawn to in accordance with your choice; default is 3D.
|
||||
The 2D usage mode is slightly faster and uses less memory compared to the 3D one. It's a good idea to set the :ref:`Viewport <class_Viewport>`'s Usage property to 2D if your viewport doesn't render anything in 3D.
|
||||
|
||||
.. note::
|
||||
|
||||
If you need to render 3D shadows in the viewport, make sure to set the viewport's *Shadow Atlas Size* property to a value higher than 0.
|
||||
Otherwise, shadows won't be rendered. For reference, the Project Settings define it to 4096 by default.
|
||||
|
||||
Godot also provides a way of customizing how everything is drawn inside :ref:`Viewports <class_Viewport>` using “Debug Draw”.
|
||||
Debug Draw allows you to specify one of four options for how the :ref:`Viewport <class_Viewport>` will display things drawn
|
||||
inside it. Debug Draw is disabled by default.
|
||||
|
||||
.. image:: img/default_scene.png
|
||||
|
||||
*A scene drawn with Debug Draw disabled*
|
||||
|
||||
The other three options are Unshaded, Overdraw, and Wireframe. Unshaded draws the scene
|
||||
without using lighting information so all the objects appear flatly colored the color of
|
||||
their albedo.
|
||||
|
||||
.. image:: img/unshaded.png
|
||||
|
||||
*The same scene with Debug Draw set to Unshaded*
|
||||
|
||||
Overdraw draws the meshes semi-transparent with an additive blend so you can see how the meshes overlap.
|
||||
|
||||
.. image:: img/overdraw.png
|
||||
|
||||
*The same scene with Debug Draw set to Overdraw*
|
||||
|
||||
Lastly, Wireframe draws the scene using only the edges of triangles in the meshes.
|
||||
|
||||
.. note::
|
||||
|
||||
The effects of the Wireframe mode are only visible in the editor, not while the project is running.
|
||||
|
||||
Render target
|
||||
-------------
|
||||
|
||||
When rendering to a :ref:`Viewport <class_Viewport>`, whatever is inside will not be
|
||||
visible in the scene editor. To display the contents, you have to draw the :ref:`Viewport's <class_Viewport>` :ref:`ViewportTexture <class_ViewportTexture>` somewhere.
|
||||
This can be requested via code using (for example):
|
||||
|
||||
::
|
||||
|
||||
# This gives us the ViewportTexture.
|
||||
var rtt = viewport.get_texture()
|
||||
sprite.texture = rtt
|
||||
|
||||
Or it can be assigned in the editor by selecting "New ViewportTexture"
|
||||
|
||||
.. image:: img/texturemenu.png
|
||||
|
||||
and then selecting the :ref:`Viewport <class_Viewport>` you want to use.
|
||||
|
||||
.. image:: img/texturepath.png
|
||||
|
||||
Every frame, the :ref:`Viewport <class_Viewport>`'s texture is cleared away with the default clear color (or a transparent
|
||||
color if :ref:`Transparent Bg<class_Viewport_property_transparent_bg>` is set to ``true``). This can be changed by setting :ref:`Clear Mode<class_Viewport_property_render_target_clear_mode>` to Never or Next Frame.
|
||||
As the name implies, Never means the texture will never be cleared, while next frame will
|
||||
clear the texture on the next frame and then set itself to Never.
|
||||
|
||||
By default, re-rendering of the :ref:`Viewport <class_Viewport>` happens when the
|
||||
:ref:`Viewport <class_Viewport>`'s :ref:`ViewportTexture <class_ViewportTexture>` has been drawn in a frame. If visible, it will be
|
||||
rendered; otherwise, it will not. This behavior can be changed to manual
|
||||
rendering (once), or always render, no matter if visible or not. This flexibility
|
||||
allows users to render an image once and then use the texture without
|
||||
incurring the cost of rendering every frame.
|
||||
|
||||
|
||||
Make sure to check the Viewport demos! Viewport folder in the demos
|
||||
archive available to download, or
|
||||
https://github.com/godotengine/godot-demo-projects/tree/master/viewport
|
||||