{"id":276,"date":"2026-02-01T20:06:58","date_gmt":"2026-02-01T19:06:58","guid":{"rendered":"https:\/\/notkey.studio\/?p=276"},"modified":"2026-02-08T12:47:31","modified_gmt":"2026-02-08T11:47:31","slug":"godot-low-res-pixel-perfect-rendering-and-smooth-camera","status":"publish","type":"post","link":"https:\/\/notkey.studio\/en\/tutorials\/godot-low-res-pixel-perfect-rendering-and-smooth-camera\/","title":{"rendered":"Implementing low-resolution pixel-perfect rendering with a smooth camera in Godot"},"content":{"rendered":"<div class=\"et_pb_section_0 et_pb_section et_section_regular et_flex_section section_has_divider et_pb_bottom_divider\">\n<div class=\"et_pb_row_0 et_pb_row et_flex_row\">\n<div class=\"et_pb_column_0 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24\">\n<div class=\"et_pb_text_0 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>Indie game development tutorials<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_1 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h1>Implement low-resolution pixel-perfect rendering and a sub-pixel camera with Godot 4<\/h1>\n<\/div><\/div>\n\n<div class=\"et_pb_module et_pb_button_module_wrapper et_pb_button_0_wrapper\"><a class=\"et_pb_button_0 et_pb_button et_pb_bg_layout_light et_pb_module et_flex_module\" href=\"\/en\/tutorials\/\">see all tutorials<\/a><\/div>\n<\/div>\n<\/div>\n<div class=\"et_pb_bottom_inside_divider et-no-transition\"><\/div><\/div>\n\n<div class=\"et_pb_section_1 et_pb_section et_section_regular et_flex_section\">\n<div class=\"et_pb_row_1 et_pb_row et_flex_row\">\n<div class=\"et_pb_column_1 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24\">\n<div class=\"et_pb_text_2 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module bref-title\"><div class=\"et_pb_text_inner\"><p>TL;DR<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_3 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>The solution is to simulate and render the game in low resolution, pixel-perfect, in a <em>SubViewport<\/em>. This <em>SubViewport<\/em> is then resized by an integer factor and displayed in high resolution in a <em>SubViewportContainer<\/em>, itself rendered by a second camera. This camera can move freely and fluidly according to the player&#039;s velocity, while being limited to a certain distance so as never to deviate from the initial rendering.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_2 et_pb_row et_flex_row\" id=\"project\">\n<div class=\"et_pb_column_2 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24\">\n<div class=\"et_pb_text_4 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p><span>When I started assembling the <\/span><span> <\/span><a href=\"\/en\/devlogs\/first-steps-for-the-reaping-company\/\">first foundations of The Reaping Company<\/a><span>, my 2D pixel art platform game, I quickly encountered a major problem when I wanted to tackle the camera.<\/span><\/p>\n<p>I wanted to obtain a <strong>pixel-perfect world<\/strong>, That is to say, a faithful rendering of the old games where every pixel displayed on the screen actually corresponds to the &quot;playable&quot; pixel on the grid. However, I also wanted a <strong>modern camera<\/strong> which moves smoothly, not linked to those pixels precisely, because I find the &quot;notched&quot; movement too rigid and unaesthetic for a modern game.<\/p>\n<p>The problems encountered in such a project are more numerous than they appear:<\/p>\n<ul>\n<li>High resolution: Today, our screens are high resolution (1080p, 4K), while a pixel art game is low resolution. How can we guarantee a clean and consistent rendering?<\/li>\n<li><span style=\"font-size: 16px;\">Portability: How can I be sure that the image I see on my machine will be identical on another screen, with a different resolution or refresh rate?<\/span><\/li>\n<li><span style=\"font-size: 16px;\">Sub-pixel fluidity: If the game is locked onto a pixel grid, how can the camera be made more fluid than simply rigid tracking?<\/span><\/li>\n<li><span style=\"font-size: 16px;\">Synchronization: How to avoid desynchronization issues between the game&#039;s physics (the calculations) and the visual rendering (what we see)?<\/span><\/li>\n<\/ul>\n<p>I was faced with all these problems at once, and despite the documentation available online and numerous suggested solutions, none of the resources worked perfectly for me, or for many others. However, I finally came up with a solution that seems to solve everything (at least I haven&#039;t found any limitations yet)! Through this misadventure, I&#039;ll explain why traditional methods can fail and provide a step-by-step solution. <strong>achieve a retro look while maintaining a smooth camera on Godot<\/strong>.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_group_0 et_pb_group et_pb_module et_flex_group et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_video_0 et_pb_video et_pb_module et_flex_module\"><div class=\"et_pb_video_box\"><video controls><source type=\"video\/mp4\" src=\"https:\/\/notkey.studio\/wp-content\/uploads\/2026\/02\/pixel-perfect-2d-sidecroller-pixel-art-with-smooth-camera-in-godot-4.mov\" \/><\/video><\/div><\/div>\n<\/div>\n\n<div class=\"et_pb_text_5 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h2>Confronting the problem: why traditional solutions failed<\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_6 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>At the beginning of the project, I naturally used a <em>Camera2D<\/em> classic, attached to the character. The camera followed the player smoothly without requiring a single line of code. This solution was obviously temporary, because I knew that I ultimately wanted to achieve that famous blend: strict pixel-perfect and a fluid camera.<\/p>\n<p>I then turned to the many tutorials available, which generally offer a general approach: The use of a low-resolution SubViewport in which the game runs, with a shader or a script that takes care of pixel-prefect alignment.<\/p>\n<p>On my work MacBook, everything seemed to work correctly. But as soon as I tested the game on my Windows desktop PC, the rendering became catastrophic: glitches appeared <strong>ghosting<\/strong> (trails), <strong>visual duplications<\/strong> And <strong>desynchronizations<\/strong> blatant. The character sometimes seemed to glitch during its movements, giving a very unpleasant impression on screen.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_group_1 et_pb_group et_pb_module et_flex_group et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_video_1 et_pb_video et_pb_module et_flex_module\"><div class=\"et_pb_video_box\"><video controls><source type=\"video\/mp4\" src=\"https:\/\/notkey.studio\/wp-content\/uploads\/2026\/02\/desynchronisation-simulation-et-rendu-pixel-art.mov\" \/><\/video><\/div><\/div>\n<\/div>\n\n<div class=\"et_pb_text_7 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>After numerous tests, I finally identified one of the causes of the problem: the <strong>refresh rate difference<\/strong> between my screens. My MacBook runs at 60 Hz, while my PC screen is at 165 Hz.<\/p>\n<p>Godot runs its physics engine and rendering engine independently. By default, the physics engine runs at 60 ticks per second. On a 60Hz screen, everything is perfectly synchronized. However, on a 165Hz screen, the rendering engine attempts to display images before the physics engine has been updated, causing these visual artifacts.<\/p>\n<p>I tried several approaches:<\/p>\n<ul>\n<li>modifying the number of ticks per second of the physics engine (which caused collision bugs and various glitches),<\/li>\n<li>moving the camera into the _physics_process (which eliminated fluidity and introduced jitters),<\/li>\n<li>adjust various parameters related to the SubViewport.<\/li>\n<\/ul>\n<p><strong>None of these solutions has proven to be truly robust or universal.<\/strong>. The SubViewport solution stubbornly refused to work reliably on all machines.<\/p>\n<p>The videos on this topic (aarthificial, Barry&#039;s Dev Hell, Nesi, Picster) are excellent and very educational. They help to better understand the issues, but as soon as you try to reproduce these systems at home, the differences in setup mean that the result is no longer the same.<\/p>\n<p>There was clearly a viable solution in Godot 3 (notably Picster&#039;s), but it ended up <strong>broken during the upgrade to Godot 4.0<\/strong>. Many developers have experienced exactly the same thing, as evidenced by the numerous comments under these videos.<\/p>\n<p>Looking further, I also immersed myself in lengthy discussions on forums and GitHub. The conclusion that emerged from these exchanges was rather discouraging: <strong>there would be no universal solution<\/strong>, capable of operating under all conditions without jitter, flickering, or visual artifacts. From a mathematical perspective, the proposed approaches still seem <strong>involve compromises<\/strong>, and do not allow for achieving the perfect result that everyone hopes for.<\/p>\n<p>Just when I was almost ready to give up, and after seeing many different theories, I finally came up with a different idea from anything I had seen before, an approach I hadn&#039;t encountered anywhere else.<\/p>\n<p>Not being a mathematician, physicist, or expert developer, all solutions relying on complex shaders, vector calculations, or intricate mathematical adjustments seemed obscure and difficult to devise on my own. Rather than trying to understand or reinvent these ingeniously designed systems, I decided to reason more simply, almost naively, using only the elements of Godot that I already knew.<\/p>\n<p>I am not claiming that this technique is perfect, nor that it is without limitations. However, at present, it is <strong>the only solution that allowed me to obtain<\/strong> :<\/p>\n<ul>\n<li>a low-resolution pixel art game <strong>pixel-perfect<\/strong>,<\/li>\n<li>a smooth camera <strong>without jitter or trembling<\/strong>,<\/li>\n<li>a <strong>compatibility<\/strong> with all screen refresh rates,<\/li>\n<li>and one <strong>resizing<\/strong> suitable for all high resolutions.<\/li>\n<\/ul>\n<p>If you are also looking to achieve this result, I suggest we look at how to concretely implement this whole system, but first let&#039;s talk a little about the theory and the problems related to all of this.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_8 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module right\"><div class=\"et_pb_text_inner\"><h2>Understanding the fundamental problems of pixel-perfect rendering<\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_9 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>Pixel grid (sub-pixel) management<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_10 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>In a modern game engine, object positions are calculated using <strong>floating-point numbers<\/strong> (float). A character can be located at position x=10.52. This fraction corresponds to a <strong>sub-pixel position<\/strong>, which exists mathematically in the engine, but not on a pixel art screen: pixel 10.52 does not exist, either the pixel is at position 10, or at position 11.<\/p>\n<p>That is why it is recommended to <strong>render your pixel art game in low resolution<\/strong> to perfectly match the pixels of the sprites, then to <strong>resize by integer<\/strong> in high resolution. However, be aware that this isn&#039;t always so simple; I strongly encourage you to do some research on... <a href=\"https:\/\/notkey.studio\/en\/tutorials\/choosing-the-right-render-resolution-for-a-pixel-art-game\/\" target=\"_blank\" rel=\"noopener\">How to choose the right resolution for pixel art games<\/a>.<\/p>\n<p>If we let the engine handle these sub-pixel positions naively, it will try to display them by blending the colors of neighboring pixels (anti-aliasing) or by distorting the sprite unevenly. For a strict pixel art game, like The Reaping Company, this is unacceptable: each pixel must fall precisely on the grid to remain sharp. This is what we call... <strong>Pixel Snapping<\/strong>. The challenge is to apply this snapping visually without breaking the accuracy of the underlying calculations.<\/p>\n<p>Godot does have an option to manage Pixel Snapping, accessible via: Project Settings \u2192 Rendering \u2192 2D \u2192 Snap \u2192 Snap 2D Transforms to Pixel. However, using this option in combination with the fluid camera did not work correctly in my case.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_11 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>The challenge of the refresh rate (Hz)<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_12 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>This is where my switch from Mac to PC revealed everything. On a <strong>60Hz screen<\/strong>, The image is refreshed every 16.6 ms. If your physics engine is also running at 60 ticks\/sec as default, everything is synchronous.<\/p>\n<p>But on a <strong>165Hz screen<\/strong>, The rendering engine requests an image every 6 ms. Since the physics hasn&#039;t changed in the meantime, the rendering engine tries to interpolate a &quot;ghost&quot; position to fill the gap. If this interpolation isn&#039;t perfectly aligned with our pixel art logic, we get... <strong>ghosting<\/strong> : a blurry trail behind the moving character. The game seems to &quot;bleed&quot; because the screen displays positions that the game&#039;s logic has never actually validated.<\/p>\n<p>I don&#039;t know if the difference between the physics engine&#039;s ticks per second and the screen&#039;s refresh rate poses a problem in many cases, but in the configurations I tested to combine low-resolution rendering and sub-pixel camera, it caused bugs.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_13 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>The paradox of camera fluidity in pixel art<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_14 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>There is a major aesthetic conflict:<\/p>\n<ul>\n<li>If we lock the camera onto the pixel grid (pure snapping like in retro games) at the same time as the character and the game, its movement becomes <strong>jerky<\/strong>, especially during slow movements. The camera can be seen &quot;jumping&quot; from pixel to pixel, which gives it a stiff and potentially &quot;cheap&quot; look. While this could be a deliberate choice to maintain a <strong>retro aesthetic<\/strong> I accepted it, but in my case I didn&#039;t want that effect.<\/li>\n<li>If the camera is left completely free, the world&#039;s sprites appear to vibrate or deform slightly during movement, because the camera is never perfectly aligned with the textures of the scenery.<\/li>\n<\/ul>\n<p>The ideal solution must therefore allow the camera to glide with infinite mathematical precision, while ensuring that during game rendering the pixels are properly aligned.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_15 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>Physical\/Rendering Desynchronization<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_16 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>Godot separates the <em>_physics_process<\/em> (fixed calculations, 60 FPS by default) of <em>_process<\/em> (Variable rendering, as fast as possible). If you move your camera in the <em>_process<\/em> To ensure smooth movement, it may overshoot the player&#039;s actual position calculated by the physics engine. This results in micro-stuttering (<strong>jitter<\/strong>The player appears to vibrate inside the camera because the two systems are not &quot;communicating&quot; at the same frequency. Therefore, a method is needed to tell the engine: &quot;Calculate the position stably within the physics, but smooth the visual display without creating a lag.&quot;.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_17 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h2>Implement pixel-perfect rendering with a smooth camera in Godot 4<\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_18 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>Here is the solution that allowed me to resolve all the problems mentioned previously. It is based on a <strong>specific tree structure<\/strong>, designed to clearly separate low-resolution pixel-perfect rendering from high-resolution smooth camera work.<\/p>\n<p>The approach may seem unusual at first glance, but it remains relatively simple to understand and above all <strong>easy to maintain<\/strong> once it is in place.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_19 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>Determine the resolutions of the pixel art game and the final rendering<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_20 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>This step is <strong>absolutely essential<\/strong> and should not be neglected, as it directly conditions the resizing and quality of the final rendering.<\/p>\n<p>The first thing to do is to <strong>define the internal rendering resolution of the pixel art game<\/strong>, That is, the low resolution that represents the game&#039;s true pixel grid, as if it were running on an older machine. This resolution determines the <strong>Actual size of logical pixels<\/strong> of the game.<\/p>\n<p>It is essential to pay attention to:<\/p>\n<ul>\n<li>in proportion to this resolution,<\/li>\n<li>as well as to the possible integer enlargement factors towards modern resolutions.<\/li>\n<\/ul>\n<p>A poor choice at this stage can lead to inaccurate resizing or visual artifacts. I highly recommend that you learn how to <a target=\"_blank\" href=\"https:\/\/notkey.studio\/en\/tutorials\/choosing-the-right-render-resolution-for-a-pixel-art-game\/\" rel=\"noopener\">choosing the right resolution for a pixel art game<\/a> in order to make your choice.<\/p>\n<p>In our case, we will start with a <strong>resolution of 320\u00d7180px<\/strong>.<\/p>\n<p>The final rendering resolution, on the other hand, corresponds to the actual resolution at which the game will be displayed on modern screens. It is this resolution that allows for smooth camera movement while maintaining a sharp image. We are using a <strong>Full HD resolution (1920\u00d71080 px)<\/strong>, which corresponds exactly to a <strong>magnification factor x6<\/strong> compared to pixel art resolution (1920 \/ 320 = 6).<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_21 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>Stage architecture in Godot 4<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_22 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>The fundamental principle of this solution rests on a clear separation between:<\/p>\n<ul>\n<li>the game rendered in low resolution, pixel-perfect,<\/li>\n<li>and the fluid camera responsible for the final display.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_code_0 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><iframe\n  src=\"https:\/\/carbon.now.sh\/embed?bg=rgba%28255%2C255%2C255%2C0%29&#038;t=vscode&#038;wt=none&#038;l=markdown&#038;width=512&#038;ds=false&#038;dsyoff=20px&#038;dsblur=68px&#038;wc=false&#038;wa=false&#038;pv=0px&#038;ph=0px&#038;ln=false&#038;fl=1&#038;fm=Hack&#038;fs=14px&#038;lh=133%25&#038;si=false&#038;es=2x&#038;wm=false&#038;code=Root%2520%28Node2D%29%250A%25E2%2594%259C%25E2%2594%2580%2520SubViewportContainer%250A%25E2%2594%2582%2520%2520%25E2%2594%2594%25E2%2594%2580%2520SubViewport%250A%25E2%2594%2582%2520%2520%2520%2520%2520%25E2%2594%2594%25E2%2594%2580%2520LowResGame%2520%28Node2D%29%250A%25E2%2594%2582%2520%2520%2520%2520%2520%2520%2520%2520%25E2%2594%259C%25E2%2594%2580%2520LowResCamera%2520%28Camera2D%29%250A%25E2%2594%2582%2520%2520%2520%2520%2520%2520%2520%2520%25E2%2594%259C%25E2%2594%2580%2520Player%2520%28CharacterBody2D%29%250A%25E2%2594%2582%2520%2520%2520%2520%2520%2520%2520%2520%25E2%2594%2594%25E2%2594%2580%2520TileMapLayer%250A%25E2%2594%2594%25E2%2594%2580%2520HighResCamera%2520%28Camera2D%29%250A\"\n  style=\"width: 512px; height: 192px; border:0; transform: scale(1); overflow:hidden;\"\n  sandbox=\"allow-scripts allow-same-origin\">\n<\/iframe><\/div><\/div>\n\n<div class=\"et_pb_text_23 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>To achieve this, the tree structure is organized as follows:<\/p>\n<ul>\n<li><em>Root<\/em> The main scene that launches at the start of the game.<\/li>\n<li><em>SubViewportContainer<\/em> The node responsible for displaying and positioning the rendering from the <em>SubViewport<\/em>.<\/li>\n<li><em>SubViewport<\/em> : The node that allows the game to be rendered in low resolution, in a fixed and controlled manner.<\/li>\n<li><em>LowResGame<\/em> : A grouping node containing all the elements of the game.<\/li>\n<li><em>LowResCamera<\/em> The camera used to render the game in low resolution. It follows the player in a strict and rigid manner.<\/li>\n<li><em>Player<\/em> The player character.<\/li>\n<li><em>TileMapLayer<\/em> The world of gaming.<\/li>\n<li><em>HighResCamera<\/em> The camera is responsible for producing the effect of fluidity. It renders what is displayed in the <em>SubViewportContainer<\/em>.<\/li>\n<\/ul>\n<p>This architecture is key to the system: the game is rendered in a way <strong>perfectly aligned in low resolution<\/strong>, Then <strong>displayed and moved smoothly<\/strong> at a higher level.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_24 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>Godot project settings for low-resolution pixel art rendering<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_25 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>Before going any further, it is essential to properly configure certain global project parameters.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_26 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p><strong>In Project Settings \u2192 Rendering \u2192 Textures \u2192 Canvas Texture:<\/strong><\/p>\n<ul>\n<li>Default Texture Filter: Nearest<\/li>\n<\/ul>\n<p>This setting is very important; it prevents any texture interpolation and <strong>preserves the raw sharpness of pixel contours<\/strong>.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_27 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p><strong>In Project Settings \u2192 Display \u2192 Window:<\/strong><\/p>\n<ul>\n<li>Size \u2192 Viewport Width: 1920 (width determined previously)<\/li>\n<li>Size \u2192 Viewport Width: 1080 (height determined previously)<\/li>\n<\/ul>\n<p>These values correspond to the final resolution of the game. Unlike other techniques based on a low native resolution, here the project starts directly in high resolution.<\/p>\n<ul>\n<li>Size \u2192 Mode: Windowed (optional)<\/li>\n<li>Stretch \u2192 Mode: viewport<\/li>\n<li>Stretch \u2192 Appearance: keep<\/li>\n<li>Stretch \u2192 Scale Mode: integer<\/li>\n<\/ul>\n<p>These parameters guarantee: scaling by integer factors only, the complete absence of fractional pixels, and a <strong>rendered consistent<\/strong> regardless of screen resolution.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_28 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>The Player character script (Player \u2013 CharacterBody2D)<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_29 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>In addition to its own behavior (movements, jumps, collisions, etc.), the player simply needs an extra line at the end of its <em>_physics_process<\/em> :<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_code_1 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><iframe\n  src=\"https:\/\/carbon.now.sh\/embed?bg=rgba%28255%2C255%2C255%2C0%29&#038;t=vscode&#038;wt=none&#038;l=python&#038;width=512&#038;ds=false&#038;dsyoff=20px&#038;dsblur=68px&#038;wc=false&#038;wa=false&#038;pv=0px&#038;ph=0px&#038;ln=false&#038;fl=1&#038;fm=Hack&#038;fs=14px&#038;lh=133%25&#038;si=false&#038;es=2x&#038;wm=false&#038;code=global_position%2520%253D%2520global_position.round%28%29%250A\"\n  style=\"width: 512px; height: 66px; border:0; transform: scale(1); overflow:hidden;\"\n  sandbox=\"allow-scripts allow-same-origin\">\n<\/iframe><\/div><\/div>\n\n<div class=\"et_pb_text_30 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>This instruction forces the player&#039;s position to remain within integer coordinates. It allows:<\/p>\n<ul>\n<li>to maintain perfect alignment on the pixel grid,<\/li>\n<li>and to prevent ghosting once the complete system is in place.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_31 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>The game&#039;s camera script (LowResCamera \u2013 camera2D)<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_32 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>This camera must be as simple and rigid as possible. Its sole purpose is to follow the player without delay, interpolation, or smoothing effects.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_code_2 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><iframe\n  src=\"https:\/\/carbon.now.sh\/embed?bg=rgba%28255%2C255%2C255%2C0%29&#038;t=vscode&#038;wt=none&#038;l=python&#038;width=512&#038;ds=false&#038;dsyoff=20px&#038;dsblur=68px&#038;wc=false&#038;wa=false&#038;pv=0px&#038;ph=0px&#038;ln=false&#038;fl=1&#038;fm=Hack&#038;fs=14px&#038;lh=133%25&#038;si=false&#038;es=2x&#038;wm=false&#038;code=%2523%2520low_res_camera2d.gd%250Aextends%2520Camera2D%250A%250A%2540export%2520var%2520follow_target%253A%2520Node2D%250A%250Afunc%2520_process%28_delta%253A%2520float%29%2520-%253E%2520void%253A%250A%2509global_position%2520%253D%2520follow_target.global_position.round%28%29%250A\"\n  style=\"width: 512px; height: 192px; border:0; transform: scale(1); overflow:hidden;\"\n  sandbox=\"allow-scripts allow-same-origin\">\n<\/iframe><\/div><\/div>\n\n<div class=\"et_pb_text_33 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>All you need to do is assign the node <em>Player<\/em> \u00e0 <em>target<\/em>. The camera then takes the exact position of the player, which guarantees a <strong>rendered strictly pixel-perfect<\/strong>. We could also have placed this directly <em>Camera2D<\/em> as the player&#039;s child.<\/p>\n<p>The use of <em>global_position.round()<\/em> is an additional safety measure, even if the player&#039;s position is already rounded in their own script. It is also at this level that a possible <strong>vertical offset<\/strong> (Y-axis), depending on gameplay needs. No other special settings are necessary: the camera must <strong>remain as neutral as possible<\/strong>.<\/p>\n<p>At this stage, you can already test the LowResGame scene on its own. You should get:<\/p>\n<ul>\n<li>a character perfectly aligned with the grid,<\/li>\n<li>a rigid, instant camera,<\/li>\n<li>and a very zoomed-in rendering (depending on the size of your sprites and the resolution chosen).<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_34 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>The Subviewport and the subviewportcontainer<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_35 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>This is where the system really starts to take shape, but also where it&#039;s easiest to make mistakes. The parameters of these two nodes are crucial.<\/p>\n<p><strong>The SubViewport<\/strong> This allows you to &quot;freeze&quot; the low-resolution game rendering so that it displays correctly in the SubViewportContainer. The parameters to adjust are as follows:<\/p>\n<ul>\n<li>Size \u2192 1920 x 1080 px (i.e., the final resolution defined previously).<\/li>\n<li>Render Target \u2192 Update Mode \u2192 Always<\/li>\n<li>Viewport \u2192 Disable 3D \u2192 On<\/li>\n<li>Canvas Items \u2192 Default Texture Filter \u2192 Nearest<\/li>\n<li>Audio Listener \u2192 Enable 2D \u2192 On<\/li>\n<\/ul>\n<p><strong>SubViewportContainer<\/strong> The SubViewportContainer simply displays the rendering provided by the SubViewport. It must occupy the entire available area and be centered.<\/p>\n<ul>\n<li>Layout \u2192 Anchors Preset \u2192 Full Rect<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_36 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>the smooth camera (highResCamera \u2013 camera2D)<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_37 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>This camera is responsible for the\u2019<strong>game fluidity effect<\/strong>. Its settings must be configured carefully. The first step is to <strong>adjust the zoom<\/strong>. This must correspond exactly to the magnification factor determined previously. In our case, a 6x zoom:<\/p>\n<ul>\n<li>Zoom \u2192 x \u2192 6.0<\/li>\n<li>Zoom \u2192 y \u2192 6.0<\/li>\n<\/ul>\n<p>At this stage, if you launch the game, it displays correctly in 1920\u00d71080px, but with the\u2019<strong>appearance of a 320\u00d7180px game<\/strong>. The character moves correctly, the rendering is pixel-perfect, but the camera is still rigid, which is perfectly normal for now.<\/p>\n<p>We now need to add a script to this camera to introduce the smooth movement:<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_code_3 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><iframe\n  src=\"https:\/\/carbon.now.sh\/embed?bg=rgba%28255%2C255%2C255%2C0%29&#038;t=vscode&#038;wt=none&#038;l=python&#038;width=480&#038;ds=false&#038;dsyoff=20px&#038;dsblur=68px&#038;wc=false&#038;wa=false&#038;pv=0px&#038;ph=0px&#038;ln=false&#038;fl=1&#038;fm=Hack&#038;fs=14px&#038;lh=133%25&#038;si=false&#038;es=2x&#038;wm=false&#038;code=%2523%2520high_res_camera2d.gd%250Aextends%2520Camera2D%250A%250A%2540export%2520var%2520player%253A%2520CharacterBody2D%250A%2540export%2520var%2520sub_viewport_container%253A%2520SubViewportContainer%250A%2540export%2520var%2520smooth_speed%2520%253A%253D%25203.0%250A%2540export%2520var%2520velocity_influence%2520%253A%253D%25200.2%250A%250Afunc%2520_physics_process%28delta%253A%2520float%29%2520-%253E%2520void%253A%250A%2509var%2520center_pos%2520%253A%253D%2520sub_viewport_container.global_position%2520%252B%2520%28sub_viewport_container.size%2520%252F%25202%29%250A%2509%250A%2509var%2520target_offset%2520%253A%253D%2520player.velocity%2520*%2520velocity_influence%250A%2509%250A%2509var%2520max_offset%2520%253A%253D%252050.0%250A%2509target_offset.x%2520%253D%2520clamp%28target_offset.x%252C%2520-max_offset%252C%2520max_offset%29%250A%2509target_offset.y%2520%253D%2520clamp%28target_offset.y%252C%2520-max_offset%252C%2520max_offset%29%250A%2509%250A%2509var%2520target_pos%2520%253D%2520center_pos%2520%252B%2520target_offset%250A%2509%250A%2509global_position%2520%253D%2520global_position.lerp%28target_pos%252C%2520smooth_speed%2520*%2520delta%29%250A%2520%2520%2520%2520\"\n  style=\"width: 480px; height: 534px; border:0; transform: scale(1); overflow:hidden;\"\n  sandbox=\"allow-scripts allow-same-origin\">\n<\/iframe><\/div><\/div>\n\n<div class=\"et_pb_text_38 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>Let&#039;s now explain in detail how this script works and its purpose:<\/p>\n<ul>\n<li>The first step is to retrieve the <strong>central point<\/strong> of <em>SubViewportContainer<\/em>. This point represents the center of the low-resolution rendering displayed on the screen, and therefore the position towards which the high-resolution camera should naturally point.<\/li>\n<li>We then calculate a <strong>target offset based on player velocity<\/strong>. This choice is fundamental. We absolutely do not base our rendering on the player&#039;s position, as they move within their own playing area and can travel very far in all directions. Conversely, our rendering is strictly limited to the frame of the <em>SubViewportContainer<\/em> : the camera should never try to follow the player directly in this space, otherwise it will go out of frame and reveal the limitations of the rendering.<\/li>\n<li>Velocity only gives us information about the <strong>direction and intensity of movement<\/strong>, which is exactly what we need to create a natural camera anticipation, without ever losing the frame of reference.<\/li>\n<li>This offset is then clamped, in order to define a <strong>maximum distance<\/strong> to which the camera can move away from the center. This limit is important: without it, the camera could move too far, to the point of no longer displaying the character correctly or revealing the edges of the rendering. <em>SubViewportContainer<\/em>, thus revealing the deception.<\/li>\n<li>Once the offset is limited, we calculate the <strong>final target<\/strong> by adding the center of the <em>SubViewportContainer<\/em> and this clamped offset. This position is then reached progressively through interpolation (lerp), which allows us to obtain a <strong>perfectly smooth movement<\/strong>.<\/li>\n<li>Finally, all this calculation is performed in the <em>_physics_process<\/em>, in order to avoid any <strong>desynchronization<\/strong> with the character&#039;s physics. I must admit I&#039;m not entirely sure this is the best practice for a camera, using the <em>_process<\/em> This could also work. In my tests, both approaches work identically, but placing the logic in the physical loop seemed more consistent with the rest of the system.<\/li>\n<\/ul>\n<p>And that&#039;s all!<\/p>\n<p>From there, it becomes very simple to adjust the camera&#039;s behavior to suit your needs.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_39 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h3>Going further, possible improvements<\/h3>\n<\/div><\/div>\n\n<div class=\"et_pb_text_40 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>One of the great advantages of this system is its simplicity. As long as certain basic rules are followed, it is easy to maintain both strict pixel-perfect rendering and smooth camera operation, without imposing excessive constraints.<\/p>\n<p>The fundamental principles to be respected are as follows:<\/p>\n<ul>\n<li>Use a <strong>whole magnification factor<\/strong> between low resolution and high resolution.<\/li>\n<li><strong>Round<\/strong> systematically the overall position of the character with <em>global_position.round()<\/em> in order to maintain perfect alignment on the grid.<\/li>\n<li>Employ a <strong>rigid low-resolution camera<\/strong> which directly follows the character.<\/li>\n<li>Move the low-resolution rendering to a <em><strong>SubViewportContainer<\/strong><\/em>.<\/li>\n<li>Use a high-resolution camera in floating space, <strong>zoomed in<\/strong> by an integer value, based on the <strong>character&#039;s speed<\/strong> to get around, with a <strong>limit<\/strong> well defined.<\/li>\n<\/ul>\n<p>With these relatively simple criteria, numerous extensions become possible:<\/p>\n<ul>\n<li>Set up a high-definition HUD or user interface, for example attached to the HighResCamera, in order to have a perfectly clear and fixed interface on the screen.<\/li>\n<li>Dynamically adapt the final resolution based on the user&#039;s screen or settings chosen via an interface.<\/li>\n<li>Adding non-pixel-perfect elements on top of the pixel art rendering, such as particles, visual effects, or post-processing.<\/li>\n<li>Improve the camera so that it can zoom, shake, rotate, or apply any modern effect, without ever compromising the pixel-perfect rendering of the game.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_41 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><h2>To conclude<\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_42 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><p>By implementing this system in The Reaping Company, I finally managed to achieve the compromise I had been seeking from the beginning: a <strong>perfectly crisp retro rendering<\/strong>, combined with a <strong>decidedly modern feeling<\/strong>. The pixels remain strictly aligned on the grid, while the camera maintains total fluidity and remains very simple to adjust for gameplay needs.<\/p>\n<p>To be perfectly honest, I don&#039;t know if this approach is the most conventional. In any case, I&#039;ve never seen it presented this way elsewhere. It probably has its own limitations, but based on my tests and the logic behind it, I don&#039;t think it will hinder further development.<\/p>\n<p>It&#039;s mainly the <strong>the only method that allowed me to concretely correct the numerous problems<\/strong> and artifacts encountered with classical approaches.<\/p>\n<p>If you&#039;re also embarking on creating a pixel art game, don&#039;t underestimate the importance of these technical details from the outset, nor your ability to find solutions on your own. This experience allowed me to better understand the inner workings of Godot and the intricacies of its rendering pipeline!<\/p>\n<p>Thank you for reading, and I sincerely hope that this article can help some of you.<\/p>\n<p>See you soon for another devlog or a new tutorial!<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_module et_pb_button_module_wrapper et_pb_button_1_wrapper\"><a class=\"et_pb_button_1 et_pb_button et_pb_bg_layout_light et_pb_module et_flex_module\" href=\"\/en\/devlogs\/\">discover the devlogs<\/a><\/div>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Implementing pixel-perfect rendering with a smooth camera in Godot 4.6 proved far more complex than anticipated. This article details the real-world issues I encountered during production (image ghosting, jittering, high refresh rate problems) and explains how to achieve strict pixel art rendering at low resolution while maintaining a smooth, modern camera, using a robust setup that works across all screen sizes and refresh rates.<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-276","post","type-post","status-publish","format-standard","hentry","category-tutos"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Godot: Rendu Pixel-Perfect Basse R\u00e9solution et Cam\u00e9ra Fluide<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/notkey.studio\/en\/tutorials\/godot-low-res-pixel-perfect-rendering-and-smooth-camera\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Godot: Rendu Pixel-Perfect Basse R\u00e9solution et Cam\u00e9ra Fluide\" \/>\n<meta property=\"og:description\" content=\"Impl\u00e9menter un rendu pixel-perfect avec une cam\u00e9ra fluide dans Godot 4.6 s&#039;est av\u00e9r\u00e9 beaucoup plus complexe que pr\u00e9vu. Cet article d\u00e9taille les probl\u00e8mes r\u00e9els que j&#039;ai rencontr\u00e9s lors de la production (ghosting d&#039;images, jittering, probl\u00e8mes li\u00e9s \u00e0 un taux de rafra\u00eechissement \u00e9lev\u00e9) et explique comment obtenir un rendu pixel art strict \u00e0 basse r\u00e9solution tout en conservant une cam\u00e9ra fluide et moderne, avec une configuration robuste qui fonctionne sur tous les \u00e9crans et tous les taux de rafra\u00eechissement.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/notkey.studio\/en\/tutorials\/godot-low-res-pixel-perfect-rendering-and-smooth-camera\/\" \/>\n<meta property=\"og:site_name\" content=\"not!key.studio\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-01T19:06:58+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-08T11:47:31+00:00\" \/>\n<meta name=\"author\" content=\"admin@notkey.studio\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Godot: Rendu Pixel-Perfect Basse R\u00e9solution et Cam\u00e9ra Fluide\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin@notkey.studio\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/\"},\"author\":{\"name\":\"admin@notkey.studio\",\"@id\":\"https:\/\/notkey.studio\/#\/schema\/person\/c644fc56ab23c891ce34c6072cfa04ed\"},\"headline\":\"Impl\u00e9menter un rendu pixel-perfect basse r\u00e9solution avec une cam\u00e9ra fluide avec Godot 4.6\",\"datePublished\":\"2026-02-01T19:06:58+00:00\",\"dateModified\":\"2026-02-08T11:47:31+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/\"},\"wordCount\":15,\"publisher\":{\"@id\":\"https:\/\/notkey.studio\/#organization\"},\"articleSection\":[\"Tutoriels de D\u00e9veloppement de Jeux Vid\u00e9o\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/\",\"url\":\"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/\",\"name\":\"Godot: Rendu Pixel-Perfect Basse R\u00e9solution et Cam\u00e9ra Fluide\",\"isPartOf\":{\"@id\":\"https:\/\/notkey.studio\/#website\"},\"datePublished\":\"2026-02-01T19:06:58+00:00\",\"dateModified\":\"2026-02-08T11:47:31+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/notkey.studio\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Impl\u00e9menter un rendu pixel-perfect basse r\u00e9solution avec une cam\u00e9ra fluide avec Godot 4.6\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/notkey.studio\/#website\",\"url\":\"https:\/\/notkey.studio\/\",\"name\":\"not!key.studio\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/notkey.studio\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/notkey.studio\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/notkey.studio\/#organization\",\"name\":\"not!key.studio\",\"url\":\"https:\/\/notkey.studio\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/notkey.studio\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/notkey.studio\/wp-content\/uploads\/2025\/12\/logo-favicon-notkey-512w.png\",\"contentUrl\":\"https:\/\/notkey.studio\/wp-content\/uploads\/2025\/12\/logo-favicon-notkey-512w.png\",\"width\":512,\"height\":512,\"caption\":\"not!key.studio\"},\"image\":{\"@id\":\"https:\/\/notkey.studio\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/notkey.studio\/#\/schema\/person\/c644fc56ab23c891ce34c6072cfa04ed\",\"name\":\"admin@notkey.studio\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/notkey.studio\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/f26fedf79dce23937ba01b84b446c0453f1fa0eeb1b812eb16c2a8bcf1621ebb?s=96&d=retro&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/f26fedf79dce23937ba01b84b446c0453f1fa0eeb1b812eb16c2a8bcf1621ebb?s=96&d=retro&r=g\",\"caption\":\"admin@notkey.studio\"},\"sameAs\":[\"http:\/\/notkey.studio\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Godot: Pixel-Perfect Low-Resolution Rendering and Smooth Camera","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/notkey.studio\/en\/tutorials\/godot-low-res-pixel-perfect-rendering-and-smooth-camera\/","og_locale":"en_US","og_type":"article","og_title":"Godot: Rendu Pixel-Perfect Basse R\u00e9solution et Cam\u00e9ra Fluide","og_description":"Impl\u00e9menter un rendu pixel-perfect avec une cam\u00e9ra fluide dans Godot 4.6 s'est av\u00e9r\u00e9 beaucoup plus complexe que pr\u00e9vu. Cet article d\u00e9taille les probl\u00e8mes r\u00e9els que j'ai rencontr\u00e9s lors de la production (ghosting d'images, jittering, probl\u00e8mes li\u00e9s \u00e0 un taux de rafra\u00eechissement \u00e9lev\u00e9) et explique comment obtenir un rendu pixel art strict \u00e0 basse r\u00e9solution tout en conservant une cam\u00e9ra fluide et moderne, avec une configuration robuste qui fonctionne sur tous les \u00e9crans et tous les taux de rafra\u00eechissement.","og_url":"https:\/\/notkey.studio\/en\/tutorials\/godot-low-res-pixel-perfect-rendering-and-smooth-camera\/","og_site_name":"not!key.studio","article_published_time":"2026-02-01T19:06:58+00:00","article_modified_time":"2026-02-08T11:47:31+00:00","author":"admin@notkey.studio","twitter_card":"summary_large_image","twitter_title":"Godot: Rendu Pixel-Perfect Basse R\u00e9solution et Cam\u00e9ra Fluide","twitter_misc":{"Written by":"admin@notkey.studio"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/#article","isPartOf":{"@id":"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/"},"author":{"name":"admin@notkey.studio","@id":"https:\/\/notkey.studio\/#\/schema\/person\/c644fc56ab23c891ce34c6072cfa04ed"},"headline":"Impl\u00e9menter un rendu pixel-perfect basse r\u00e9solution avec une cam\u00e9ra fluide avec Godot 4.6","datePublished":"2026-02-01T19:06:58+00:00","dateModified":"2026-02-08T11:47:31+00:00","mainEntityOfPage":{"@id":"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/"},"wordCount":15,"publisher":{"@id":"https:\/\/notkey.studio\/#organization"},"articleSection":["Tutoriels de D\u00e9veloppement de Jeux Vid\u00e9o"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/","url":"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/","name":"Godot: Pixel-Perfect Low-Resolution Rendering and Smooth Camera","isPartOf":{"@id":"https:\/\/notkey.studio\/#website"},"datePublished":"2026-02-01T19:06:58+00:00","dateModified":"2026-02-08T11:47:31+00:00","breadcrumb":{"@id":"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/notkey.studio\/tutos\/godot-rendu-pixel-perfect-basse-resolution-et-camera-fluide\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/notkey.studio\/"},{"@type":"ListItem","position":2,"name":"Impl\u00e9menter un rendu pixel-perfect basse r\u00e9solution avec une cam\u00e9ra fluide avec Godot 4.6"}]},{"@type":"WebSite","@id":"https:\/\/notkey.studio\/#website","url":"https:\/\/notkey.studio\/","name":"not!key.studio","description":"","publisher":{"@id":"https:\/\/notkey.studio\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/notkey.studio\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/notkey.studio\/#organization","name":"not!key.studio","url":"https:\/\/notkey.studio\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/notkey.studio\/#\/schema\/logo\/image\/","url":"https:\/\/notkey.studio\/wp-content\/uploads\/2025\/12\/logo-favicon-notkey-512w.png","contentUrl":"https:\/\/notkey.studio\/wp-content\/uploads\/2025\/12\/logo-favicon-notkey-512w.png","width":512,"height":512,"caption":"not!key.studio"},"image":{"@id":"https:\/\/notkey.studio\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/notkey.studio\/#\/schema\/person\/c644fc56ab23c891ce34c6072cfa04ed","name":"admin@notkey.studio","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/notkey.studio\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/f26fedf79dce23937ba01b84b446c0453f1fa0eeb1b812eb16c2a8bcf1621ebb?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f26fedf79dce23937ba01b84b446c0453f1fa0eeb1b812eb16c2a8bcf1621ebb?s=96&d=retro&r=g","caption":"admin@notkey.studio"},"sameAs":["http:\/\/notkey.studio"]}]}},"_links":{"self":[{"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/posts\/276","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/comments?post=276"}],"version-history":[{"count":50,"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/posts\/276\/revisions"}],"predecessor-version":[{"id":508,"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/posts\/276\/revisions\/508"}],"wp:attachment":[{"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/media?parent=276"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/categories?post=276"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/notkey.studio\/en\/wp-json\/wp\/v2\/tags?post=276"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}