PPU sprite priority: Difference between revisions
(The internals still weren't crystal clear, so adding a new section) |
mNo edit summary |
||
Line 17: | Line 17: | ||
== Detailed internals of the sprite priority quirk == | == Detailed internals of the sprite priority quirk == | ||
During sprite evaluation the PPU copies the sprites that are in y range from the primary to the secondary OAM, from which eight internal sprite output units are then initialized. These sprite output units are wired such that the lowest-numbered unit that outputs a non-transparent always wins, regardless of sprite priority and regardless of what the background pixel at the corresponding location is. | During sprite evaluation the PPU copies the sprites that are in y range from the primary to the secondary OAM, from which eight internal sprite output units are then initialized. These sprite output units are wired such that the lowest-numbered unit that outputs a non-transparent always wins, regardless of front/back sprite priority and regardless of what the background pixel at the corresponding location is. | ||
Hence, when a back-priority sprite is hidden behind non-bg background pixels, it will still hide output from higher-numbered sprite output units wherever it has a non-transparent pixel. | Hence, when a back-priority sprite is hidden behind non-bg background pixels, it will still hide output from higher-numbered sprite output units wherever it has a non-transparent pixel. |
Revision as of 17:03, 20 April 2013
In the NES PPU, each sprite has two values that affect priority, or what appears behind what: the index of the sprite within OAM (0 to 63), and the priority bit (attribute 2 bit 5, set to 0 for front or 1 for back). In some cases, putting a back-priority sprite in front of a front-priority sprite can let the background show through and cover up the front-priority sprite. Super Mario Bros. 3 uses this for power-ups sprouting from blocks, putting a blank block "behind" the block at a low index and then putting the power-up "behind" that at a high index. (You can see the corners of this blank block when Mario hits a note block in World 1-2, as the note block becomes more squared off.)
The Nintendo DS PPU handles priority the "obvious" way,[1] and some NES emulator developers initially think the NES PPU handles it the same way:
- Front priority sprites in front
- The background plane in the middle
- Back priority sprites in back
What really happens in the NES PPU is conceptually more like this:
- During sprite evaluation for each scanline (cycles 256 to 319), the eight frontmost sprites on this line get drawn front (lower index) to back (higher index) into a buffer, taking only the first opaque pixel that matches each X coordinate. Priority does not affect ordering in this buffer but is saved with each pixel.
- The background gets drawn to a separate buffer.
- For each pixel in the background buffer, the corresponding sprite pixel replaces it only if the sprite pixel is opaque and front priority.
The buffers don't actually exist as full-scanline buffers inside the PPU but instead as a set of counters and shift registers. The above logic is implemented a pixel at a time, as PPU rendering explains.
Detailed internals of the sprite priority quirk
During sprite evaluation the PPU copies the sprites that are in y range from the primary to the secondary OAM, from which eight internal sprite output units are then initialized. These sprite output units are wired such that the lowest-numbered unit that outputs a non-transparent always wins, regardless of front/back sprite priority and regardless of what the background pixel at the corresponding location is.
Hence, when a back-priority sprite is hidden behind non-bg background pixels, it will still hide output from higher-numbered sprite output units wherever it has a non-transparent pixel.