**Smooth Parallax - Pixel Renderer Devlog #2 — Transcript & Summary | SozAI**
Source: https://sozai.app/transcript/smooth-parallax-pixel-renderer-devlog-2/

Devlog #2 on Astortion's pixel renderer: how parallax scrolling and integer upscaling combine into a parallax pass with smooth, pixel-perfect layers.

## Key Takeaways

- Parallax scrolling is achieved by offsetting layers relative to a central reference layer using a ratio of depth distances.
- Rendering at native resolution and upscaling by an integer factor keeps pixel art and procedural effects clean.
- Separating scene layers in the render pipeline and compositing them after upscaling enables smooth, independent parallax motion.
- Packing many layers into one texture keeps the rendering cost low because the native resolution is small.

## What the video covers

- Continues the Astortion pixel renderer walkthrough, building on the deferred shading technique covered in the previous video.
- Explains parallax scrolling as a perspective effect: distant objects appear to move slower relative to the camera than near ones.
- Describes separating scene objects into depth layers and offsetting them relative to a central reference layer using similar-triangles math.
- Shows how the parallax ratio controls behavior: zero is the central layer, negatives move layers forward, values up to one push layers toward infinity (static), and values above one invert the parallax.
- Covers integer upscaling of the native resolution (480x270 for gameplay, 240x135 for cutscenes) so every native pixel maps to a square block of screen pixels.
- Upscaling keeps procedural lights and shadows pixel-perfect and lets sprites be reused via scaling and rotation without manual pixel alignment.
- Identifies the core problem: applying parallax before upscaling yields choppy camera movement in one-native-pixel steps.
- Proposes upscaling layers first, then scrolling them smoothly and independently.
- Implementation: packs up to 16 layers (4x4 layout) into a single G-Buffer texture, storing transparency for later compositing.
- Each layer is rendered with an adjusted, pixel-grid-snapped camera and a configured viewport; lights are rendered per layer the same way.

## Chapters

1. 00:00 Introduction and recap of deferred shading
2. 00:21 Understanding perspective and parallax scrolling
3. 01:30 Layer offset math and parallax ratio
4. 03:32 Integer upscaling and native resolution
5. 04:39 Goal of the parallax pass
6. 04:59 Rendering layers into a packed G-Buffer
7. 06:18 Lights, upscaling, and smooth compositing
8. 07:27 Border handling and what comes next

Answers

## Questions about this video

Why does the video render parallax layers before upscaling instead of after?

Applying parallax before upscaling would make the camera move in steps of one native pixel at a time, which looks jerky. By upscaling each layer first and then offsetting the upscaled quads, the layers stay pixel-perfect while the camera scrolls smoothly.

What does a parallax ratio of 1 or higher do?

A ratio of 1 places the layer at an infinite distance, so it appears static, which suits skies or suns. Values above 1 invert the parallax, simulating a camera rotating around the scene's center.

Why is it efficient to render 16 layers separately?

The native resolution is very small, so the total rendered area across all layers is roughly the size of a Full HD texture. The performance cost is therefore negligible.

## Full Transcript — Download SRT & Markdown

00:02

Speaker A

We're continuing the walkthrough of the pixel renderer for Astortion. Last time, we explored a technique called deferred shading used for rendering lights.

00:10

Speaker A

Today we'll combine it with the rest of the parallax pass to see the whole rendering process.

00:15

Speaker A

But first, we need to understand two other ingredients of this pass: parallax scrolling and upscaling.

00:21

Speaker A

Parallax scrolling aims to simulate the effect caused by perspective, in which objects further away seem to move slower relative to the camera than objects that are closer.

00:30

Speaker A

This happens because our eyes and cameras don't just gather the light that hits them directly. But rather, they use lenses that focus the light from a wider angle, increasing their field of view.

00:39

Speaker A

You can see that the further away we are from the camera, the bigger the visible area gets. But its size with respect to the view remains the same.

00:46

Speaker A

On the other hand, if we place a sphere in front of the camera and start moving it away, its size on the screen will decrease. This should be pretty intuitive.

00:54

Speaker A

Here, the circle takes half the visible area, and so its size is half that of the screen.

00:59

Speaker A

But as we move further away, the proportions change. The visible area grows bigger, while the size of our sphere remains the same.

01:07

Speaker A

The same thing happens with movement. If we place two spheres at different distances from the camera and move them by the same amount, they'll appear to travel different distances on the screen.

01:16

Speaker A

This is exactly what causes the parallax effect. Of course, in most cases, it's the camera that's moving, but the result is the same.

01:23

Speaker A

Our spheres move with the same velocity relative to the camera, but their speeds perceived on the screen are different.

01:30

Speaker A

To simulate this effect with a simple 2D camera, first, we need to separate objects into layers based on how far away we want them to be.

01:38

Speaker A

I'll plot these layers on a top-down view to better visualize that. I'll also mark the center of each layer.

01:45

Speaker A

If we move our camera to the left, you'll notice that the centers of our layers are still perfectly aligned.

01:50

Speaker A

Now imagine that we're using a perspective camera instead. For something like this to happen, all the centers need to lie on the same straight line passing through the camera.

01:58

Speaker A

Which means that the background layers moved further than the foreground ones. To fix this, we can use the central layer as the reference point and offset the rest to keep the traveled distance the same.

02:11

Speaker A

Going back to our simple camera, we can see how the layers are actually offset.

02:17

Speaker A

We can use some trigonometry to figure out what this offset should be, exactly. We know that this vector represents the displacement of the camera.

02:24

Speaker A

And since these two triangles are \*\*similar\*\*, we can say that the offset divided by the camera displacement is equal to the distance from the central layer divided by the distance from the camera.

02:35

Speaker A

Solving for offset will give us the following formula. Notice how we don't really need specific values here, only the ratio between these two distances.

02:44

Speaker A

This ratio is pretty handy when controlling the parallax effect. The value of zero denotes the central layer. Negative values will move the layers to the foreground.

02:53

Speaker A

And positive values will go to the background, all the way to one, which will put the layer at an infinite distance from the camera.

03:00

Speaker A

In practice, it means that the layer will appear static. This can be useful for things like the sky or sun that should always be visible.

03:08

Speaker A

But we can go even further than that. Values above one will invert the parallax.

03:13

Speaker A

It doesn't really make sense in our perspective analogy, but we can use it to create an illusion of a camera rotating around the center of the scene.

03:21

Speaker A

This is the basic idea behind parallax scrolling. Now let's talk about upscaling. Astortion is first rendered in its native resolution. Here, pixels of the sprites have the same size as the pixels of the render texture.

03:34

Speaker A

Once this is done, the texture can be scaled up to match the size of the screen.

03:37

Speaker A

The result looks best if we scale the texture by a whole number. This ensures that each native pixel is represented by a square made up of screen pixels.

03:45

Speaker A

In contrast, using non-integers would result in some pixels becoming rectangles. How the native resolution is selected could be a video on its own.

03:53

Speaker A

For now, all you need to know is that, if possible, Astortion uses 480x270 pixels for gameplay, and for some important cutscenes, 240x135 pixels.

04:05

Speaker A

These resolutions nicely scale to the most common displays. The biggest advantage of upscaling is that it makes sure all procedural effects, such as lights and shadows, are pixel-perfect.

04:18

Speaker A

We also don't need to manually align our sprites to the pixel grid since they'll end up pixelated regardless.

04:24

Speaker A

This lets us repurpose a lot of assets by scaling and rotating them while keeping the style consistent.

04:30

Speaker A

Going back to the bigger picture. The job of the parallax pass is to reconcile parallax scrolling with upscaling.

04:36

Speaker A

The simplest approach would be to apply the parallax first and then upscale everything at once.

04:41

Speaker A

But this makes the camera move in fixed steps: one native pixel at a time.

04:46

Speaker A

Depending on what you're going for, this may be the desired effect. But with Astortion, I'd like to go the other way around.

04:52

Speaker A

Upscale the parallax layers first to keep them pixel-perfect, but then scroll them smoothly, independent of each other.

04:59

Speaker A

So let's take a look at how to achieve this. Just like in the previous video, we start by preparing the G-Buffer.

05:04

Speaker A

But since we want the parallax layers to scroll independently, we'll need a way to render and store them individually.

05:10

Speaker A

We can use the fact that the native resolution is relatively small and pack all layers into a single bigger texture.

05:17

Speaker A

Astortion uses a 4x4 layout, which results in 16 possible layers. But in this simple presentation, we'll only be using four.

05:24

Speaker A

We will also store the transparency in our color texture. This will let us put the layers together later on.

05:30

Speaker A

Let's start the rendering from the back-most layer. At this point, it should already be offset using our formula for parallax scrolling.

05:37

Speaker A

But we'll also need to adjust the camera to align it with the pixel grid of this layer.

05:41

Speaker A

This snapping will stabilize the pixelated sprites and effects so they don't jitter when the camera is moving.

05:48

Speaker A

Put a pin on this vector we used to offset the camera. We're gonna need it later.

05:53

Speaker A

Lastly, we configure the rendering viewport so that the layer ends up in the correct spot.

05:58

Speaker A

And then render all objects belonging to this layer. We repeat the same process for the remaining layers.

06:03

Speaker A

Intuitively, rendering 16 layers like that may seem inefficient. In practice, however, the performance impact is negligible. Remember that the native resolution is tiny, so the overall area we actually need to render is roughly the size of a Full HD texture.

06:18

Speaker A

With the G-Buffer ready, we can move on to the lights. Here, we follow a similar process: adjust the camera, set the viewport, render all lights from the layer, rinse and repeat.

06:29

Speaker A

The final step is to upscale our layers and put them together. To achieve this, we'll prepare a dedicated mesh. It will consist of fullscreen quads stacked on top of each other.

06:38

Speaker A

Each will have the UV coordinates that map to the corresponding layer in our shaded color texture. Rendering this mesh using a simple orthographic projection will effectively scale up and merge our layers in one go.

06:50

Speaker A

The resulting parallax isn't smooth, though. This is where the offset vectors from our camera come into play.

06:56

Speaker A

For example, when rendering this layer, we had to move the camera a little bit to the left.

07:00

Speaker A

So now we'll move the quad for this layer by the same amount. This will neatly smooth out the camera movement.

07:07

Speaker A

The last issue we need to address is this missing information around the borders. The solution is to extend the camera by one native pixel in each direction and expand our mesh to reflect that.

07:20

Speaker A

This will give it enough padding to always cover the entire screen, even with the offset.

07:25

Speaker A

Of course, it means that

07:34

Speaker A

This is the general idea behind the Parallax Pass but we're not finished yet. Having all the layers rendered separately opens the door to some interesting effects Such as depth of field and volumetric fog, which we'll cover in the upcoming videos.

07:48

Speaker A

But that's all I've got for you today. Thanks so much to all my patrons.

07:51

Speaker A

Thank you for watching. And until next time.

Topics: parallax scrolling pixel art upscaling deferred shading G-Buffer 2D rendering game development Astortion devlog camera offset

Study this video

- [Flashcards from this video](https://sozai.app/tools/ai-flashcard-generator/?from=transcript&id=86383)
- [Quiz on this video](https://sozai.app/tools/quiz-generator/?from=transcript&id=86383)

Free, made by AI from this transcript. No signup.


---
This is the markdown twin of https://sozai.app/transcript/smooth-parallax-pixel-renderer-devlog-2/ — the same content, without the markup.
Published by SozAI (https://sozai.app). Reuse and quotation are allowed with attribution and a link back.
Machine-readable index: https://sozai.app/llms.txt · data API: https://sozai.app/api/
