Parallax Examples?

User avatar
jakenastysnake
Posts: 17
Joined: Thu Mar 14, 2019 10:06 pm
Location: NC

Parallax Examples?

Post by jakenastysnake » Wed Mar 27, 2019 5:43 am

Love the effect and think it gives some good depth to screens. Would anyone with some basic examples of how they pulled off the technique be willing to share? I would greatly appreciate the knowledge!
User avatar
chronicleroflegends
Posts: 190
Joined: Thu Sep 06, 2018 3:51 am

Re: Parallax Examples?

Post by chronicleroflegends » Wed Mar 27, 2019 6:21 pm

Parallax is really difficult effect to pull off on the NES, because you do not really have different 'layers' for your background tiles.

The only person I have seen make a similar effect/may be able to help is Kasumi. But it's likely going to involve some heavy custom scripting.
~Do you believe in legends? ~
My Games: Nix: The Paradox Relic
User avatar
Mugi
Posts: 781
Joined: Thu Dec 27, 2018 8:30 pm

Re: Parallax Examples?

Post by Mugi » Wed Mar 27, 2019 6:32 pm

mapper 30 makes parallaxing slightly complicated since the mapper doesnt have scanline counter, which basically gives one easy option out.
you can use sprite0 to do a screensplit for a single parallaxing effect on screen but that also means that you will lose the ability to use the tile hud, as the parallax would reserve the sprite0 for it's own purpose (sprite0 is only usable once per frame)

i considered doing this since im not using the tile hud so my game currently doesnt use sprite0 for anything, but it's not really high on the priority list at the moment.
i will make a write up about that assuming i actually do it (would be neat for parallaxing a title screen logo or something simple like that.)
"what are you up to?" "Oh, not much... just... Parallaxing"
- Raftronaut
User avatar
jakenastysnake
Posts: 17
Joined: Thu Mar 14, 2019 10:06 pm
Location: NC

Re: Parallax Examples?

Post by jakenastysnake » Wed Mar 27, 2019 9:53 pm

chronicleroflegends wrote:
Wed Mar 27, 2019 6:21 pm
Parallax is really difficult effect to pull off on the NES, because you do not really have different 'layers' for your background tiles.

The only person I have seen make a similar effect/may be able to help is Kasumi. But it's likely going to involve some heavy custom scripting.
Hmm, I see. I'm still learning the ins and outs of ASM scripting so i should probably put that on the back burner until I get better.

By the way, I checked out your game Nix: The Paradox Relic. Awesome job man! I've mainly been watching the NESMaker tutorials. Are there any other tutorials/resources you'd recommend?
User avatar
jakenastysnake
Posts: 17
Joined: Thu Mar 14, 2019 10:06 pm
Location: NC

Re: Parallax Examples?

Post by jakenastysnake » Wed Mar 27, 2019 10:04 pm

Mugi wrote:
Wed Mar 27, 2019 6:32 pm
mapper 30 makes parallaxing slightly complicated since the mapper doesnt have scanline counter, which basically gives one easy option out.
you can use sprite0 to do a screensplit for a single parallaxing effect on screen but that also means that you will lose the ability to use the tile hud, as the parallax would reserve the sprite0 for it's own purpose (sprite0 is only usable once per frame)

i considered doing this since im not using the tile hud so my game currently doesnt use sprite0 for anything, but it's not really high on the priority list at the moment.
i will make a write up about that assuming i actually do it (would be neat for parallaxing a title screen logo or something simple like that.)
I have a basic hud using the sprite0 in my current project. If you do happen to do anything with parallaxing in the future I'd love to see what you make. A write up would be great for beginners like me!
User avatar
Kasumi
Posts: 261
Joined: Fri Mar 09, 2018 11:13 pm

Re: Parallax Examples?

Post by Kasumi » Thu Mar 28, 2019 3:23 am

This got long...

The screen renders from left to right, top to bottom. While the screen is rendering (done by NES' picture processing unit, or PPU), the CPU is running separately. The CPU can talk to the PPU. If the CPU provides no new information to the PPU, the PPU will render a 256x240 region starting from the coordinate that was last given to it by the CPU.

The NES has four 256x240 screens in memory. It's easiest to describe them as laid out in a 2x2 rectangle. Usually two are identical to each other. (Either the left 2 screens are identical and the right 2 screens are identical, or the top two screens are identical and the bottom two screens are identical.)

If the PPU ever gets to the end of the 2x2 rectangle while rendering, it will wrap back to the beginning. (Say it reaches the right edge, but still has more pixels to draw. It will grab the rest from the left edge.) Another way to think about it is that that 2x2 rectangle repeats infinitely in all directions.

Visual time. Here is what the screens in memory look like when the left 2 screens are the same and the right 2 screens are the same:
Image
Here is what the screens in memory look like when the top 2 screens are the same and the bottom two screens are the same:
Image

To break down the above: You've got a 512x480 image that repeats endlessly in all directions. You can tell the PPU to start drawing at any point within that infinitely repeating canvas, and it will draw the 256x240 pixels for the screen starting at that point.

But here's where things get interesting (and dense)! You can specify a new point while it's still in the middle of drawing the screen. Super Mario Bros. and NES Maker both do this for their HUDs. They say, "PPU, start drawing from the top left corner of the 2x2 rectangle". But once all the horizontal lines of the HUD have been drawn, they say, "PPU, start drawing from the pixel immediately below the HUD in the 2x2 rectangle, and X pixels into the 2x2 rectangle." (Where X is the scroll position.)

And here's where things get more interesting. There's not really a limit to how many times you can tell the PPU to start drawing from a different place. (Well, there are rules to it, but lets ignore that for now.) So here's Rad Racer:

Image
Notice the four screens don't really change as the road changes shape. All that's happening is the CPU telling the PPU to keep drawing from different parts of the road multiple times throughout the entire screen.

And that's essentially what a parallax does (or at least the main way they're done). "For rows 0-32 draw at 0, 0. For rows 33-64 draw at 16, 33. For rows 65-96 draw at 24, 65". It just sets the X positions to draw from so they move at different speeds. (one pixel of movement in one section is two pixels of movement in another)

There's even a caveat the comes with that. See this tweet:
You can't have something in a row not move while the rest of the row does move (or at least the way main this is done). This is because of how the PPU renders (left to right, top to bottom). If you want the top half of the screen to be different from the bottom of the screen, it's one change in the middle that will affect the rest. To make the left half the screen different from the right half of the screen, you have to make two changes on every single row. And since the CPU is running while the PPU is, this basically means 100% of the CPU would be used doing only this. (There are probably other reasons why it's not possible or feasible.)

But here's the issue with doing this. The CPU is running while the PPU is. To make the change at say... row 32, you have to pass the new starting position EXACTLY then. And the PPU can't tell the CPU it's at row 32. So the CPU has to keep track of how much time has passed between when the PPU started at row zero (which the PPU does tell the CPU about) and row 32.

While the CPU is counting time, it can't do much else as far as game logic. (Game logic makes decisions, different decisions take different amounts of time, and we need to give the message to the PPU at an exact time.)

There's one saving grace. That's Sprite Zero. The PPU tells the CPU when it starts at row zero. And the PPU can notify the CPU when a specific sprite has an opaque pixel overlap with an opaque pixel background. The CPU can wait for this notification to give the PPU ONE new point on any given frame. (Even then, the CPU can't really do much else while waiting...)

Suppose you want to make a change in the middle of the screen. You are using HALF THE AVAILABLE CPU TIME PER FRAME just waiting. Half of time you could be spending on calculating object collisions, half the time you could be spending on lots of things.

Some cartridges allow the cartridge to notify the CPU when the PPU starts on certain rows. (And in a way that there's no time spent on the actual waiting.) NES Maker's cartridge cannot do this. So it can't do more than one split without extreme, time wasting code. (Interestingly, Rad Racer's cartridge also cannot do that. It is entirely extreme code.)

There are two other ways to do parallax effects, but both require reasonably strong understanding of how to talk to the PPU. Maybe for some other post... this got long.

Edit: Or I guess the basic example is already in NES Maker's code. GameEngineData/Routines/Basic/MainASM.asm. But it's only basic due to the prerequisite knowledge of the rest of this post. ;)

ctrl+F WaitSprite0. It loops until the PPU reports the pixels are overlapping. (a bit gets set in $2002 when this is true. This is also why the game freezes when sprite 0 isn't set up properly. If pixels will never overlap, the CPU will never leave this loop.) The writes to $2005 are the X and Y position for where to start drawing from. To do a really basic parallax (instead of a HUD), what you'd do is write a different X position to $2005 for the beginning of the screen (as opposed to always zero like the HUD, "; start with no scroll for status bar"), and this HUD code would set the scroll properly for the rest of the screen assuming you set sprite 0 correctly.

All bets are off once you want to do more than one split. That's the wild west.
User avatar
jakenastysnake
Posts: 17
Joined: Thu Mar 14, 2019 10:06 pm
Location: NC

Re: Parallax Examples?

Post by jakenastysnake » Thu Mar 28, 2019 4:51 am

@kasumi

Dude.. Kudos for the explanation and visuals. Definitely gives me something to bite into and play around with. Thanks a ton!

So glad I found this forum lol
User avatar
Kasumi
Posts: 261
Joined: Fri Mar 09, 2018 11:13 pm

Re: Parallax Examples?

Post by Kasumi » Thu Mar 28, 2019 5:36 am

An addendum/correction. The rectangle that infinitely repeats is 512x480, but only single bytes are written to $2005. The writes to $2005 (usually) choose where within a single screen. To choose which of the four screens, is a write to $2000. (The lowest bits choose which of the four screens: http://wiki.nesdev.com/w/index.php/PPU_ ... _.3E_write )

There are other complications, though. Giving a new X position to the PPU is relative easy. Giving a new Y position to the PPU is pretty complicated: https://wiki.nesdev.com/w/index.php/PPU ... 2FY_scroll

I was incorrect when saying the second write to $2005 is the Y position. It normally would be, but midscreen, the wiki claims it doesn't have the effect it normally does. (I haven't tested this, I've only done the crazy way in the link above.)

There's actually a lot to consider, though. Scrolling writes new tiles which could overwrite that you're trying to parallax.
Image
(In addition to telling the PPU to start at a new place, you can actually tell it other things. This is how some games can display more than 256 tiles like Smash TV's title screen or display a textbox without the font appearing in the level graphics.)
The other ways to parallax are:
1. bank swapping (which is probably not too good an option for NES Maker, since only four frames are available for it. Your parallax could only be four unique scroll positions). Metal Storm does it this way, and that's also how it has parallax that has still things and moving things on the same row. (But it dedicates a very significant amount of its total graphics space to the effect. You need a page of tiles in every unique pixel position for all things that will move.) This method is super easy to do, and takes effectively no CPU time, though.
2. Writing unique tiles. This is NES Maker viable, and can similarly allow things on the same row to scroll at different speeds. Battletoads uses it for a vertical parallax on this level:

Note that the sides of the hole are scrolling at a different speed than the center. This is done by writing each tile index that's meant to move with an identical tile offset by 1 pixel. The screen scrolls normally, but the tiles displayed are offset, creating the effect.

But doing 2 within NES Maker means knowing very, very deeply about the maximum amount of time its other PPU updates will take. Writing tiles takes a lot of time, and there is a very small amount of time where you're able to do it safely every frame. It's reasonably hard to do most types of parallax without a pretty good understanding of the PPU.

Well, the bank switching method is simple, but requires bank switching knowledge.
User avatar
jakenastysnake
Posts: 17
Joined: Thu Mar 14, 2019 10:06 pm
Location: NC

Re: Parallax Examples?

Post by jakenastysnake » Thu Mar 28, 2019 6:19 pm

Thanks again guys. Really appreciate it!
User avatar
Dirk
Posts: 389
Joined: Fri Mar 09, 2018 5:30 am

Re: Parallax Examples?

Post by Dirk » Thu Aug 22, 2019 4:51 pm

I just discovered this thread. Wow, thank you Kasumi for your great explanations and for accompanying them with great illustrations! Always a pleasure to read your postings.
-----
Disclaimer: English is not my first language, so mistakes are bound to happen.
Post Reply