the Twarchive

This is a record of a twitter thread, originally posted in 2022

Thew
@AmazingThew

im gonna play Final Fantasy XIII (2009)

widely regarded as The Last One They Made Before The Roman Numerals Got Too Big For Anyone To Remember How Roman Numerals Work

Thew
@AmazingThew

this game is extremely good, as proven by the fact that everyone on /r/gaming in 2010 fucking hated it

Thew
@AmazingThew

Playing the PC version bc I've kind of always wanted to see what this game looks like in renderdoc. Hopefully I can get that working at some point

Shadow filtering seems to be broken/nonexistent on PC but tbh I don't know if that's the port's fault or if the PS3 never had it

Thew
@AmazingThew

also as much as I love old hardware, I don't have a PS3 have yall ever tried using a 360 in the Present Day?? Basically the last thing microsoft did before retiring the console was completely ruin the launcher so it's utterly miserable to use now lol

Thew
@AmazingThew

love trying to play a videogame and having to click through fifteen screens of ads while an omnipresent kinect avatar performs nauseating dances

The New Xbox Experience absolutely nailed the Mark Zuckerberg Virtual Reality Teleconference Purgatory aesthetic fully a decade early

Thew
@AmazingThew

wonder if you can hack a 360 to retvrn to THE BLADES

...anyway, final fantasy

Thew
@AmazingThew

okay actually now I'm googling whether you can get THE BLADES back on an old 360 and the answer is a solid "probably" if you have an old enough hardware revision but step 1 is "solder a raspberry pi onto the JTAG pads on the motherboard" so uhhh looks like a wild ride

Thew
@AmazingThew

also: oh yeah remember the red ring of death

nearly every blades-era 360 ever manufactured eventually melted itself so apparently they're Extremely Rare now lol

Thew
@AmazingThew

oh hell yeah this is so needlessly expensive

this entire cutscene is just "the gang rides a platform" but they're casually pushing buttons and moving levers on this giant construction machine and it's all totally bespoke animation for no reason

Thew
@AmazingThew

it's incredible that square made it to like 2016 without ever realizing you're supposed to have producers and they're supposed to prioritize tasks for the artists

Thew
@AmazingThew

secret to gamedev success: just let your artists just do whatever and go insane polishing things no one will ever see and also have so much money left over from the 90s that you can just keep doing this for basically forever

Thew
@AmazingThew

It rules how the gods are like physically present in the world and everything seemingly revolves around them, but every time you actually SEE one it's like a thousand-foot-tall fucked up sculpture being hauled around by military helicopters

Thew
@AmazingThew

it's been ten years since I played this originally, so I've forgotten most of it

IIRC though most of the plot is barely comprehensible, but it's like that BECAUSE the gods are alien and incomprehensible, and then their inscrutability is used to reinforce power

Thew
@AmazingThew

vanille's weapon is four whips attached to a set of antlers on a stick, which she finds behind a rock

Thew
@AmazingThew

it is now time for The Girl Run Cycle

Thew
@AmazingThew

the design of this first dungeon is really cool

it keeps swapping between three groups of characters, who don't know each other and all arrived here independently, and they're all accidentally unlocking doors for each other so everyone's proceeding forward in parallel

Thew
@AmazingThew

lmaooo this rules

there are several different cornering animations for different speeds and radii

for the fastest/tightest one she does a little hop, and you can kind of jank it up by jiggling the stick in certain ways

if you do it a few times she gets dizzy and stops lol

Thew
@AmazingThew

tfw you made a complex system of cornering animations but as soon as any player notices it exists they immediately try to break it

Thew
@AmazingThew

the setting for this game is "everybody lives on the interior surface of a sphere the size of the moon, with a giant hole blasted through one side" which is INCREDIBLY cool

but also, IIRC you barely ever get a clear look at it? Almost always obscured by clouds or sightlines

Thew
@AmazingThew

What If Halo But Orb

Thew
@AmazingThew

people complained about this game being full of hallways but like look at this hallway dude come on

Thew
@AmazingThew

I played this at launch in 2010 and haven't revisited it since then, but I played the sequels more recently so I recall most of their plot

It's very funny watching some of the character arcs being set up here, given the WILD decisions the writers made later lol

Thew
@AmazingThew

serah doomed to her time-traveling greek tragedy arc meanwhile lightning's playing majora's mask ten million years in the future like I AM GOING TO KEEP MURDERING GODS UNTIL EITHER MORALE IMPROVES OR I RUN OUT OF GODS

Thew
@AmazingThew

you should play the final fantasy 13 sequels they are very good and also batshit

Thew
@AmazingThew

god this environment art

a bunch of buildings collapse into a lake and then the water gets turned into crystals so you're walking around between colossal frozen waves

the way the color shifts as the light filters through thick/thin waves is just absurdly good

Thew
@AmazingThew

really curious how much of that is baked light simulation, or if the artists just went in and hand-painted vertex colors until it looked perfect

Thew
@AmazingThew

even when you stare at it enough to work out which parts are fins/cards and which parts are geo, the illusion still holds up perfectly because they somehow blended across almost every seam

Thew
@AmazingThew

This area was one of the main reasons I'm hoping I can get renderdoc hooked up at some point

like how the hell is this a 360 game

Thew
@AmazingThew

okay I just spent the last 3 hours failing to get a gpu capture lmao

worked out how to launch it without steam breaking renderdoc, eventually realized it's dx9 and thus incompatible, finally got it hooked via DXVK dx9->vulkan shim, but trying to record a capture crashes the game

Thew
@AmazingThew

tried nsight with the DXVK trick too, but it turns out nsight doesn't support 32-bit apps at all lol

only option I haven't tried at this point is installing visual studio 2017 and one of the old-ass versions of the nsight plugin that still supported d3d9

i am going to bed now

Thew
@AmazingThew

LETS FUCKIN GOOOO

Thew
@AmazingThew

big thanks to @PlunkOrg for pointing me towards GFXReconstruct

extremely cool utility that records *every vulkan API call* into a big stream of frames, which can then be played back on the gpu without involving the actual videogame

then you can hook THAT with renderdoc lol

Thew
@AmazingThew

I got a few captures of this area but tbh I might not be able to get any from anywhere else in the game

this entire process has like ten thousand failure points; I spent 2 days on this and got it working for like 30 minutes and then it stopped working for no obvious reason lol

Thew
@AmazingThew

Okay! Here's the bulk of geometry rendering, not including particle effects and postprocessing:

Thew
@AmazingThew

Surprising no one: it's a completely ordinary forward renderer, no HDR, no PBR, no AO, no color grading, minimal postprocessing (bloom, zoom-blur light shafts, DoF in cutscenes)

the character shaders are pretty fancy, but even then it's still all single-pass forward rendering

Thew
@AmazingThew

gonna dig into some details but the tl;dr for "why does this game look so good" is basically just "because the artists did an insanely good job" lol

Thew
@AmazingThew

this is probably a DXVK thing and not actually part of the game engine, but lmao at this 3D, 1x1x1, 1-channel UINT texture

(its value is 0)

Thew
@AmazingThew

what if a zero was a Cube

Thew
@AmazingThew

First three buffers:
Character shadows
Environment shadows
Depth-only pass

there's no shadow cascades, just two separate shadow maps for characters and bigger stuff

the depth map is only used in postprocessing; none of the regular materials ever sample from it

Thew
@AmazingThew

the environment shadowmap is interesting, because the game already has lightmaps with baked shadows

the environment shadows appear to be coming entirely from hand-placed shadowcaster meshes that line up with the baked shadows in important places

Thew
@AmazingThew

I think this exists entirely so that when the characters walk into a baked shadow, they get hit with a corresponding realtime shadow so the lighting still works

Check out the soft (baked) shadow on the ground, and the hard (realtime shadowmap) shadow on the character

Thew
@AmazingThew

Next up is opaque rendering, which is.... basically everything except particles. The ice fins/cards and even the characters' hair is all opaque, using alpha-to-coverage pretty much everywhere

Thew
@AmazingThew

First thing rendered is the skybox

I have no idea what's going on with this texture layout lol. 2x4 grid, with one tile for the ceiling and.... 7 for the sides? The box itself isn't square either so the texel density is Weird

looks fine in actual practice though

Thew
@AmazingThew

Next: big cool ruin thing

Small lat-long envmap (no "reflection probes" it's 2009 shiny stuff is 100% vibes-based)

Incredibly badass color map

Probably specular map? Squashed to half res on one axis

(not shown because I can only post four images) global lightmap/mask texture

Thew
@AmazingThew

notably: NO NORMAL MAPS

there's basically no realtime lighting in this game, except on the characters (who do use normals)

baked lightmaps and detailed shading painted into the textures was good enough for the PS2 and it's good enough for 2009

tbh it's good enough for 2022 too

Thew
@AmazingThew

*skipping a bunch of stuff that isn't really visible on this frame* CRYSTALS

Thew
@AmazingThew

The bigger crystals use a cool rainbowy envmap, a giant atlas of incredibly cool-looking crystal images, and a mask that's used to blend some stuff in the fragment shader

The smaller ones just use this super pretty atlas of crystal/splash shapes (last image)

Thew
@AmazingThew

notably, all the crystal meshes are batched REALLY aggressively

almost every card in the whole level that uses that "spray" atlas is sent through in one draw call, which is like 8500 quads

all rendered with alpha-to-coverage

Thew
@AmazingThew

the chonkier crystals that use full geo instead of cards are essentially planar UV'd?

they're sort of sword-shaped, with all the faces on one side being mapped flat onto one of the crystal images, and all the faces on the other side just being mirrored

Thew
@AmazingThew

renderdoc doesn't provide a good way to visualize texture mapping on meshes, unfortunately

if you spend enough of your life staring at green-orange-red UV debug colors though, eventually you don't see the matrix code anymore

Thew
@AmazingThew

I worked out how the rainbowy refraction/iridescence effect works but it was too many moving parts to fit into one tweet so I made you a timecube diagram

Thew
@AmazingThew

looking at it in motion, I totally thought it was refracting/distorting the background in some way, but nope

there IS no grabpass/scene texture! The only screenspace effects are post processes. The whole effect is just two textures modulated by a mask

Thew
@AmazingThew

the actual 3D vector used for the envmap lookup COULD be fairly elaborate (reverse engineering fragment-shader math is pretty difficult even with renderdoc), but just from looking at it I don't think it's more complex than "refract the eye ray through the vertex normal"

Thew
@AmazingThew

(reading decompiled SPIR-V (pronounced "spurve") is a nightmare BUT renderdoc can show you all the varyings passed *into* the frag shader, and in this case it looks a lot like world pos + view pos + world normal, which would be exactly what you'd need for refracted eye ray)

Thew
@AmazingThew

other Crystal Stuff:

The blue/white color variation is from vertex colors

They aren't lightmapped, so yeah I think the crystals are probably just hand-blended with their surroundings via vertex colors

Normal attributes are in 0-1 range? Also some other constant packed into w

Thew
@AmazingThew

no tangents obv, since no normal maps

really wonder how much actual lighting is being done in the frag shader here. No lightmaps but it's def affected by the general blue-green ambient color. Ambient light seems to have a directional component, so probably needs normals for that

Thew
@AmazingThew

okay that's enough gazing at crystals

it is time for Hair

Thew
@AmazingThew

unfortunately there's not a lot I can do to reverse-engineer this one, because it's mostly just tech-art shader magic

technically speaking I COULD read the shaders, but it's dx9 bytecode cross-compiled to SPIR-V cross compiled to GLSL, so its about 1600 lines of this:

Thew
@AmazingThew

Notably though: this is all still single-pass forward rendering. No intermediate buffers or multi pass effects; it just draws the whole thing in one go with alpha-to-coverage

Thew
@AmazingThew

Lots of textures bound for the hair, including four different mask channels and two curve lookups. This is what I mean by "tech-art shader magic" lol; no way to tell what these are controlling exactly but they're clearly tuning a LOT of parameters

Thew
@AmazingThew

Have you ever asked yourself, "what information is stored in the vertex attributes of Lightning's hair mesh in the hit videogame Final Fantasy XIII (2009)"?

I have wondered this for thirteen years

Thew
@AmazingThew

honestly this kind of "no energy conservation, just vibes" tech-art approach where everything's made of hand-authored masks and curves modulating parameters to nail a look is my fav part of graphics work

but then those nerds at disney invented PBR and now I have to do integrals

Thew
@AmazingThew

microfacet [derogatory]

Thew
@AmazingThew

re: GPU skinning:
Yeah!

Characters and enemies all seem to have those weight maps in vertex attributes. Models are submitted to the GPU in T poses, and then the vertex shader outputs a fully skeleton'd mesh

(also, flipped horizontally)

Thew
@AmazingThew

upon further reflection, I think the horizontal flip might actually be from DXVK, to correct the handedness flip between d3d9 and vulkan

Thew
@AmazingThew

Square's artists are masters of the female form

Thew
@AmazingThew

One odd detail:
Character models seem to be authored in absurdly tiny units? Like smaller than millimeters

I know computer graphics has no intrinsic scale and all, but it's still pretty disorienting to look at a vertex position attribute and see like Twenty Seven Thousand lol

Thew
@AmazingThew

The range for vertex positions seems to be around +/- 28,000 and they're clearly ints

16-bit signed ints have a very similar range. Maybe the original game stored position attributes in 16bit ints, and either the PC port or DXVK turned them into floats later?

Thew
@AmazingThew

either that or Lightning's height is canonically like 55 kilometers

Thew
@AmazingThew

oh hey! this is actually a vulkan thing!

turns out vulkan actually has a format specifically for ints interpreted as floats. So yeah, the vertex positions for characters are indeed stored in 16-bit signed ints

Thew
@AmazingThew

skin rendering is, unsurprisingly, more tech-art magic, with approximately ten thousand different mask textures which modulate Cool Stuff in the skin shader

Thew
@AmazingThew

come to think of it: the face UVs are mirrored. How's normal mapping work on mirrored UVs? I've never had to think through this before lol, can you just invert the tangent vectors on the mirrored verts?

too tired to work out the math rn; maybe one of yall already knows

Thew
@AmazingThew

This is one of my favorite tricks so far:

so lightning has these cool arm bracelets right

the arm texels are pretty stretched out; there's not really enough resolution for the zigzag pattern on the upper one

if you look at the texture, there's just a shadow in its place

Thew
@AmazingThew

HOWEVER: there are two small textures bound along with everything else: a 128x128 normal map, and a 64x64 2-channel mask

these obviously look like the bracelet, but only sort of

Thew
@AmazingThew

Turns out: Her arm actually has an entire extra set of UVs, just for the bracelet

the UVs are rotated 45 degrees, so the pixel rows/columns form the zigzag shape. So even though the resolution is low, there's no aliasing along the bracelet's edge

Thew
@AmazingThew

So the shader samples the regular color texture using the main UVs, and samples the bracelet textures, and then lerps between the two based on the bracelet mask

result is a perfectly localized area of sharp detail, blended over top of an area that uses a much lower texel density

Thew
@AmazingThew

this is cool as hell!

also: the actual color of the bracelet isn't coming out of a texture. It seems to use the green channel of the mask and just color it directly in the frag shader

feels like they were REALLY getting squeezed for texture memory here

Thew
@AmazingThew

additional radness:
the smaller bracelet is just straight up pixel art

real PS2 hours; gotta make every texel count

Thew
@AmazingThew

After skin rendering we get the rest of lightning's clothes/armor and sword

Not a lot to talk about here; seems like basically the same approach as the hair/skin shaders: Regular color+normals, and then gradient lookup textures and tons of masks

super pretty texture work though

Thew
@AmazingThew

One SUPER interesting detail I skipped earlier: While they're clearly not doing PBR, they ARE using pre-convolved reflection probes!

Like from an artistic standpoint, "everything is reflective; rougher objects just have blurrier reflections" is still really effective on its own

Thew
@AmazingThew

There's four different 64x64x6 cubemap textures, each showing a progressively blurrier image of the surroundings

When it renders characters, every draw call has at least one or two of these things bound, depending on how shiny the materials are

Thew
@AmazingThew

I really love this, because you don't necessarily NEED all the energy-conservation and metallic/dielectric BRDF stuff to make materials look good. You can arrive at the same blurred speculars and fresnel techniques just through observation and good artistic intuition

Thew
@AmazingThew

I have a pet theory that this is actually why we saw so much cheesy glowing-edges fresnel stuff in the early years of the 360 era

like a lot of it was obv "wow look SHADERS" but I think a lot of artists just intuitively GOT the fact that most stuff gets shinier at grazing angles

Thew
@AmazingThew

oh hey I just noticed: renderdoc can actually show individual MSAA samples

so here, you can actually watch alpha-to-coverage doing its thing. Every subsample clips the hair texture at a different alpha threshold, so when the samples are averaged it gets nicely blended

Thew
@AmazingThew

anyway, with that I'm finally done with opaque rendering lmao
(except for uhhhhhhhh the big frozen waves terrain pieces because they aren't visible in this capture so I guess I have to do them later)

Proceeding onward to TRANSPARENT RENDERING

Thew
@AmazingThew

Thankfully there's very little transparency going on. Mostly just particle effects, which aren't super prominent in this area

mainly all that's being added is a bunch of tiny little crystal sparkles floating in the air. Really effective in motion but barely noticeable in stills

Thew
@AmazingThew

BUT HOLD ON:
Each little sparkle is two quads. One using a texture atlas with some halos on it, and then a smaller one in the center with a crystal texture

if I counted correctly there are exactly 100 of these particles

Thew
@AmazingThew

okay so, batch them, draw all the halos first and then all the crystals right. two draw calls

WRONG

THEY ARE INTERLEAVED

TWO HUNDRED INDIVIDUAL DRAW CALLS

Thew
@AmazingThew

I can only assume this is a bug introduced in the PC port lmao

renderdoc says the *entire frame* is 354 draw calls, I can't imagine they actually shipped a console game with more than half the draw calls being individual 1px-high particles

Thew
@AmazingThew

Alright I finally got through all the normal rendering. Maybe soon I can play the videogame

next up: Copying the frame into a lower-res buffer and thresholding the brightest pixels. It is Time for Bloom

Thew
@AmazingThew

Bloom implementation is completely standard. The thresholded image is copied into six successively lower-res buffers, each buffer is run through a ~5px two-pass blur, then all six levels are stacked up and blended back over the original image

nothing surprising here

Thew
@AmazingThew

This is all LDR, so no tonemapping, and apparently also no color grading

Everything drawn up until this point has looked kinda too dark. Bloom significantly brightens the image, so all the lighting and color choices have been made with this in mind

Thew
@AmazingThew

actually I take that back: there is color grading, it's just very subtle and doesn't happen until later

Thew
@AmazingThew

Next up: light shafts

This seems to be the only effect that actually uses the depth-only pass that was rendered at the beginning (presumably DoF also uses it but that's not enabled here)

to start, it draws a big blurry halo behind everything

Thew
@AmazingThew

The position of the halo lines up with this foggy/glowy bit on the skybox

also fun: the halo isn't a texture; it's just drawn directly in the frag shader. No reason to waste vram when you can just use smoothstep()

Thew
@AmazingThew

From here it just does a zoom blur, drawing the texture over top of itself recursively until it gets reasonably smooth

the buffers are tiny (320x180) so it's probably plenty fast even though it's a ton of sampling

Thew
@AmazingThew

This gets blended over the image, but it's really subtle. They're really not trying to make it into a big flashy Cool Graphics effect

Thew
@AmazingThew

It's a lot easier to see in motion, but I love how restrained it is. It's not NEXT-GEN HD GOD RAYS like.... basically every other game from 2009 lol, it just gives this really nice feeling of haze in the air

Thew
@AmazingThew

FINAL STEP:
COLOR GRADING

yeah I thought there wasn't any color grading but it turns out I just missed it lol

It's similarly restrained, just adding a bit of vignette and pushing the shadows greenward

Thew
@AmazingThew

Uses another 1D gradient instead of a full LUT

no way to confirm for sure, but it's probably just using the pixel luminance to index into the texture and look up a tint

Thew
@AmazingThew

anyway yeah! That's the whole frame!

Thew
@AmazingThew

I think what strikes me the most is how tightly the color and luminance are controlled through every step. The final color grade doesn't even need to touch the lumance; it's already perfectly utilizing the available dynamic range

like, look at this fuckin Flawless histogram

Thew
@AmazingThew

The color/exposure precision is fun to look at, because like, Assassin's Creed II is pretty representative of how most AAA stuff looked at the time. It came out a month before this

"every shadow crushed, every highlight blown" was like The Xbox Three Sixty Guarantee

Thew
@AmazingThew

and like, not to make this A Dunk or anything; I liked ac2 and it had a lot of very impressive art and tech stuff going on

but NOTHING ELSE looked like this game at the time

Thew
@AmazingThew

tbh that's why I'm spending so much time digging into it

I have a distinct memory of playing this in college and getting to this crystal area and just being like "how the hell did they even DO this"

12 years later I'm like "huh I probably actually know how to answer that now"

Thew
@AmazingThew

Cursed Image

Thew
@AmazingThew

BONUS POSTS:
So I still wanted to figure out how the terrain rendering works, right. The other capture didn't really show any of the giant crystal waves, so now I gotta dig into a different frame

Thew
@AmazingThew

Surprising no one: turns out these are yet another "just a bunch of masks and multiple UV sets and a big pile of opaque tech-art" material

renderdoc can show us the ingredients, but not precisely how they're used

Thew
@AmazingThew

BUT

renderdoc can capture absolutely everything going IN to the shader

it can give me an image of what comes OUT of the shader

maybe I can just... figure out what it does by making my own shader from the same inputs

Thew
@AmazingThew

We Have Final Fantasy XIII At Home

Thew
@AmazingThew

SO: Input textures
Got two big color maps, two single-channel masks from some textures we've seen before, and an environment map

notably these are all 2k resolution. Might have been lower on consoles? Although there are VERY few textures this big, so maybe they needed the res

Thew
@AmazingThew

Vertex buffers have the usual positions and normals, plus two color attributes and three UV sets

Thew
@AmazingThew

Side note: remember earlier I couldn't figure out why all the normals are in 0-1 range

turns out the blindingly obvious answer was just "they're R8G8B8_UNORMs lol"

surprisingly low precision but I can't argue with the visual quality

Thew
@AmazingThew

So to figure out how all these inputs are used, I saved out the vertex and index buffers from renderdoc, and generated a mesh from them in unity, so now I can make shaders that read all the attributes and textures

(actually did two of them, bc the terrain is in multiple chunks)

Thew
@AmazingThew

First UV set is tiles. This corresponds with the big crystal texture; it's pretty much the base for the whole material

the way the tile boundaries flow along the curves of the mesh is really well executed

Thew
@AmazingThew

Second UV set is interesting. It's essentially decals; you can see how it sort of targets specific areas, mapped back to different regions on that cool atlas texture

Thew
@AmazingThew

Third UV set is pretty clearly lightmaps, just from its shape, so we just need the red channel from the big lightmap texture

for some reason it's stored inverted, so it took me a minute to work out that it was, in fact, actually lighting lol

looks super cool in any case

Thew
@AmazingThew

The solid black areas are underneath other static geometry, i.e. all the big metal ruins lying around the map

the bright values underneath the waves seem to just be exaggerated bounce lighting, although it's so strong it maybe kinda contributes to the "translucent crystal" look

Thew
@AmazingThew

so that answers this question from a week ago

the waves do use baked lighting, but it's just a single-channel shadow term; no colored light filtering through glass. All the glowy translucent colors are from vertex painting and careful texture placement

Thew
@AmazingThew

so the first vertex-color attribute seems to be basically an emissive term, except it's weird because it lightens AND darkens

the values are all centered around 1, so I think the idea is it gets multiplied with other lighting values to push the result up/down

Thew
@AmazingThew

I feel like the "1 is neutral" aspect would make these kind of a pain to author (even visualizing them is somewhat annoying) but in any case they definitely seem to be hand painted

Thew
@AmazingThew

LAST INPUT BEFORE WE CAN PUT STUFF TOGETHER:

The second vertex color attribute is a float3 but they all have the same value, oddly

clearly this is a mask for Something

Thew
@AmazingThew

alright shader time, finally

Turns out that vertex mask selects between the two UV sets. Hides all the seams in the decal layer by blending in the base layer

now we've got really nice-looking organic texture work everywhere

Thew
@AmazingThew

So this is a good start, but everything is clearly WAY brighter than in the actual game

we can multiply the baked lightmap in there, but there's clearly a lot more that needs to happen re: lighting

Thew
@AmazingThew

This is where I gotta start Winging It

there's no way to know how their lighting engine works exactly. I'm not even certain the static geo HAS dynamic lighting

so I'm gonna just look at a bunch of screenshots and start recoloring textures in various shades of blue

Thew
@AmazingThew

there are infinite ways you could go about this. I'm basically gradient-mapping between two colors but there are lots of other options the game artists could have used

they're definitely punching up the contrast though; this is all vfx-y pow/bias/smoothstep range-remapping stuff

Thew
@AmazingThew

The lightmap definitely isn't just multiplied through; it seems to be shifting the colors in some way

so for a start, let's just pick a different set of colors to tint the textures, and use the lightmap to lerp between them

getting Somewhere at least

Thew
@AmazingThew

So at this point we've making use of:
- All three UV channels
- Both crystal textures
- The lightmap texture
- One of the two color attributes

Still unused are:
- Emissive vertex colors
- Environment map
- That one-channel grunge texture that was packed into one of the masks

Thew
@AmazingThew

I had a mostly-working prototype and a bunch more screenshots to get through but then I went to bed and realized I was probably way overthinking a few parts so uhhhhhhhhh brb i guess

Thew
@AmazingThew

I really like these fissures where they lined up the edges of the geometry with this crack texture from the decal map

(there's geo that closes the gaps, obviously, it just isn't in this draw call)

Thew
@AmazingThew

Okay so I don't have answers yet but

remember earlier I was like "figuring out how the lighting works is probably too hard" well ehhh what if I tried anyway

Thew
@AmazingThew

The only input data that's relevant to lighting is a 1-channel baked lightmap and some vertex colors

(okay and also giant cbuffer of 255 float4s containing almost every shader uniform for every draw call in a big pile but hopefully that isn't important 🙃 )

Thew
@AmazingThew

okay what's the most dirt-simple circa-2002 lighting model

ambient color + direct color * lightmap

might as well try it. I'm gonna multiply the "emissive-ish" vert color in there too, since it seems intended to modulate the final lighting in some way

result looks... passable?

Thew
@AmazingThew

Tried adding the textures back in but it's pretty clearly incorrect. Hard to tell how exactly though. The game has WAY more contrast and color variation

Thew
@AmazingThew

started wondering if I can screw with renderdoc to visualize JUST the lighting component

I know the decompiled shader code looks like some Cyber Hacker Shit but it's at least sorta reasonably straightforward to find where the textures are being sampled

Thew
@AmazingThew

did some Cyber Hacker Shit, replaced the main texture samples with solid white, so now we should be seeing the lighting term by itself

....yeah okay there's a LOT going on here. Placed next to my direct+ambient test, you can see there's like multiple levels of extra stuff

Thew
@AmazingThew

I'll keep poking at this for a bit but I doubt I'll fully replicate the real lighting

This is interesting though! It means that, in addition to all the extremely skilled modeling/texture work, at a pure technology level this game DOES use a pretty sophisticated lighting model

Thew
@AmazingThew

lmao I got it

Thew
@AmazingThew

I'll break down how it works later but my brain is toast rn

just spent an entire evening reading decompiled spurve lol

Thew
@AmazingThew

fused-multiply-add like what if lerp was a giant pain in the ass to read

Thew
@AmazingThew

you cant do two maths at the same time thats cheating

Thew
@AmazingThew

OKAY SO
Lighting turned out to be very close to what I had guessed, but with a bunch of tuning parameters that I could only find by digging through the shader decompilation lol

Thew
@AmazingThew

Gotta finish explaining the textures first though

Previously On This Thread: there's two main color textures with separate UV sets, one big tiling map and a bunch of (essentially) decals. A mask stored in vertex colors is used to blend between them

Thew
@AmazingThew

There's still two more textures though: an environment map, and this mask that was packed into one of the crystal atlases

Thew
@AmazingThew

I was thinking the mask was like a tiling detail layer or something, but after an embarrassing amount of time I realized it actually corresponds to the main crystal texture. If you invert it, you can see it masks out the brightest details of the base texture

Thew
@AmazingThew

It's hard to tell without seeing it in motion, but in the actual game the dark areas are shiny/reflective (i.e. envmap), and the bright areas are opaque

it gives this really convincing appearance of smooth, shiny crystal, covered in a surface layer of cracks and scratches

Thew
@AmazingThew

...so the mask texture is basically just a "reflectiveness" map

just use it to lerp between the base texture and the environment map, and we get this

still clearly not "correct" but definitely on the right track

Thew
@AmazingThew

Interestingly, a lot of the darker blue colors aren't actually coming from the lighting OR the base textures, but are actually just because the environment map is blue

rather than accurately mirroring the scene like a probe would, it's a unique piece of this one material's look

Thew
@AmazingThew

anyway long story short this is where I went insane and started reading the shader decompilation

an activity known as Spurve Scrying

Thew
@AmazingThew

turns out, before it blends the envmap and the base texture, the reflectiveness mask gets multiplied by a hardcoded 0.5 lol

Thew
@AmazingThew

also the reflection vector that samples the envmap turned out to be mirrored and rotated 90 degrees but whatever

fixing that and including the magic 0.5 scalar produces the Finally Final For Real This Time Final Fantasy texture contribution

Thew
@AmazingThew

I like this a lot. Turns out I was overthinking things; it's not so much "tech-art shader magic" as basically just well-executed multitexturing, with a couple magic constants

once you sample all the right maps with the right uvs and pick the right masks, the blending is just:

Thew
@AmazingThew

if john khronosgroup didn't want me calling it spurve then he shouldn't have named it spurve

Thew
@AmazingThew

okay with texturing out of the way: LIGHTING

here's my first guess vs reverse-engineered version vs ground truth:

Thew
@AmazingThew

To recap, the inputs here are:
- Single-channel lightmap, stored inverted (shadow is 1, light is 0)
- Emissive-like RGB values stored in vertex colors
- Giant uniform cbuffer with 255 unnamed float4s lol

Thew
@AmazingThew

THANKFULLY the the shader actually only cares about three of the uniforms, and two of them were pretty clearly just colors

Thew
@AmazingThew

So my first guess for the lighting model was old-school ambient+direct, right

turns out it's even simpler, it's just a shadow color, and an implied light color of 1

so instead of ambient+direct*lightmap, it's just lerp(shadowcolor, white, lightmap)

it's Weird about it though

Thew
@AmazingThew

not worth explaining the decompilation, but the logic ends up equivalent to this:

Thew
@AmazingThew

Remember the lightmap is stored inverted? I think this was done so that the shadow intensity could be adjusted with a single multiply

since 1 in the lightmap means shadow, that 1.1 scalar pushes all the values darker, overshooting the lerp and boosting shadow intensity

Thew
@AmazingThew

here's what dragging that "shadow intensity" constant between 0 and 2 looks like

Thew
@AmazingThew

since it's hardcoded, there was no way I'd ever have found it without spurve spelunking. At least its purpose is pretty clear though

Using the darker blue color from the uniforms, and a constant of exactly 1.10000002384185791015625, we get the final, correct lightmap term:

Thew
@AmazingThew

The vertex colors, at least, are straightforward

Like I said earlier, they're roughly centered around 1, so by multiplying them with the rest of the lighting they can both increase or decrease the lighting intensity

Thew
@AmazingThew

since the lightmap is 1 channel and the vertex colors are RGB, they add a ton of subtlety to the end result

imo the vertex colors are really the main thing that makes the lighting look good

(also note the colors are kinda blown out here; there's a reason for that later)

Thew
@AmazingThew

this isn't a surprise given what we've already seen, but it's still very cool:

Basically all of the super pretty glowing translucency stuff is coming from [presumably] hand-painted vertex colors, adding and subtracting color from the baked lighting until the effect looks good

Thew
@AmazingThew

okay next up: FOG

jk im skipping fog

it's just fog who cares. the other light-blue color in the uniform array was the fog color. alpha controls the falloff distance

Thew
@AmazingThew

I guess it's worth noting the fog strength appears (appears) to be derived from the vertex Z position in NDC space

meaning the fog changes if you change the camera's near/far clip planes

that was probably annoying to work with

Thew
@AmazingThew

Oh yeah also notable:

No part of the lighting relies on normals. No N Dot L or fresnel term or anything; all the lighting is completely static

The vertex normals are only required in order to sample the environment map

Thew
@AmazingThew

anyway

Now that we've got final texture contribution and final lighting term, just multiply them together to get the final color

...except it's still slightly too bright

Thew
@AmazingThew

Turns out there's still one more step in the shader. There's that third uniform that had a bunch of numbers with unclear purposes

here's where they're used, if you feel like nerdsniping yourself:

Thew
@AmazingThew

"1.06383" and "-0.06383" both have the same fractional value.
I'm gonna guess those are both the same user-facing variable X, and "1+X" and "-X" are being calculated on the CPU and passed in, to save some fragment instructions

If that's the case, this code is equivalent to:

Thew
@AmazingThew

If you play around with these variables, it's immediately clear what they're doing to the final image:

Brightness and contrast knobs!

Thew
@AmazingThew

Behold!

This is incredibly cool, because like, this is all before postprocessing right. It's like... preprocessing. Directly manipulating the material colors after textures and lighting have been applied

Thew
@AmazingThew

Why have global tonemapping when you can just have per-material tonemapping

Thew
@AmazingThew

I skipped over it but there's another uniform that's multiplied with the result, seemingly as an optional color tint. It's unused here (values all 1), but the color was presumably exposed to the artists

Thew
@AmazingThew

This feels tightly connected to the histogram stuff I talked about earlier. There are SO MANY tools here to let the artists tweak colors and intensities in order to dial in a perfect exposure

Thew
@AmazingThew

Beyond just authoring textures, they can change the color and intensity of the baked shadows, paint light/shadow and hue shifts into the lighting via vertex colors, tint the result AFTER lighting, and finally tweak brightness/contrast of the end result

Thew
@AmazingThew

Obviously none of this is terribly surprising if you're used to pre-PBR workflows, but we've been in PBR Land for like a decade+

I am Not Young and my whole career has been metallic-rough maps and BRDFs

really fun to dig into this and see so much control exposed to the artists

Thew
@AmazingThew

PBR's Whole Deal is simulating light and then using global postprocessing to control how that light interacts with a camera

but sometimes a camera isn't the right metaphor dude. sometimes you just want to let artists pick colors that look good

Thew
@AmazingThew

So, with the final tuning knobs added, we can combine everything and get The Correct Result

(note this is all before the game's post processing runs, so it's much darker than the final frame)

Thew
@AmazingThew

Out of curiosity I tried to see if I could get unity's bloom to resemble the real thing and: it looks like ass lmao

Thew
@AmazingThew

In fairness this isn't really unity's fault

The game is using LDR bloom where you threshold the image and remap the result so it's extra intense

Unity's trying to bloom overexposed HDR values, which would normally be oversaturated to begin with. Without that it gets washed out

Thew
@AmazingThew

Anyway! I am Done!

I have answered all of my questions about Final Fantasy XIII's crystal rendering technology

god that took... most of my free time for a week and a half. or i guess twelve years depending on how you count

Thew
@AmazingThew

here's the shader if you would like to make your own Final Fantasy XIII

Thew
@AmazingThew

I'm going to play Final Fantasy XIII (2009) now

Thew
@AmazingThew

shoutouts to lightning finalfantasy's insanely ripped shoulders

Thew
@AmazingThew

lightning finalfantasy obliterating a cop with the most complicated punch ever conceived

Thew
@AmazingThew

she is punching this man for like four entire seconds

Thew
@AmazingThew

STEALTH

Thew
@AmazingThew

an important thing you should know about Final Fantasy XIII is that Troy Baker rides a motorcycle made out of women

Thew
@AmazingThew

Final Fantasy XIII: Troy Baker Rides a Motorcycle Made Out of Women

Thew
@AmazingThew

also the motorcycle fight is mechanically incomprehensible and comes totally out of nowhere and has no thematic connection to the rest of the game

all the other summons are like manifestations of the characters' self doubt but the first one is just "what if motorcycle horny"

Thew
@AmazingThew

also it's only on screen for like two seconds but we do get this cool prerendered shot of the horizon curving upward like Orb Halo

Thew
@AmazingThew

lmao lightning rules. eight hours into the game and she goes "fuck this I'm killing god" and leaves the party

Thew
@AmazingThew

there's a whole cutscene where she brings it up and everyone else is like "wait how would even help" and her answer is just I DON'T TAKE ORDERS FROM GODS

Thew
@AmazingThew

extremely cool: the horizon is like slightly weirdly too high up, because of the whole "we live in a giant orb so the ocean is curved" thing

I don't think I even noticed this the first time I played it; the game calls so little attention to its own setting

Thew
@AmazingThew

come to think of it, I don't think ANYTHING in the early cutscenes or dialog even mention the orb thing

there's an explanation in the codex if you go looking for it, but the writers really don't seem concerned with making sure you get it

Thew
@AmazingThew

as a visual/thematic metaphor it's as just ridiculously unsubtle as the Midgar plate (it's literally named Cocoon lmao), but in FF7 every person you meet complains about the rich guys that paved over the sky and then you get the train map that's a 3D model of the whole city

Thew
@AmazingThew

but here's it's just never really mentioned

you'd think they'd treat it as a Big Reveal when you eventually break OUT of the cocoon, but IIRC it just assumes you read the wiki in the menu so even then it's just kind of "oh hey there's the orb. neat"

Thew
@AmazingThew

I don't think this was unintentional either?

like they just committed REALLY hard to an in-medias-res concept, do a degree that really alienated a ton of players. but it's still like.... I can respect the audacity of just Going For It that confidently

Thew
@AmazingThew

is this gackt

Thew
@AmazingThew

I love that lightning is presented as this battle-hardened ice-cold operator, when her entire military career has been as a security guard at a beach resort and the actual explanation for her personality is that she's just kind of a jerk

Thew
@AmazingThew

I'm not even making a joke really; it's pretty much the actual text

Thew
@AmazingThew

remember when gamers were like "lightning sucks she's just cloud but a girl" and im like YOU THINK THAT'S A *BAD* THING???

Thew
@AmazingThew

Like ten hours in we finally get the first clear shot of a distant landscape and the upward-curving horizon

even then there's so much haze and clouds and sick-ass molten crystal sundogs (??) that it's still, like, pretty easy to miss the fact that there's land in the sky

Thew
@AmazingThew

it's a bit easier to see without twitter video compression

Thew
@AmazingThew

I could just keep posting screenshots of Skyboxes Where The Horizon Is Slightly Weird forever lol

it's such a cool detail that I completely never noticed the first time I played this

Thew
@AmazingThew

insanely cool phone design

Thew
@AmazingThew

this was the last good phone ever designed

steve jobs ruined everything and then sora and the FFXV bros just got regular-ass touchscreen slabs

even the splatoon kids aren't allowed anything cooler than iphone but triangle

Thew
@AmazingThew

I don't want a smartphone I want a pocket computer that does all the internet/navigation/camera/app stuff with No Telephony and then separately for the extremely rare occasions when I need to make voice calls I want this thing

Thew
@AmazingThew

(I would also accept any of the phone designs from macross frontier)

Thew
@AmazingThew

I really like this city environment. Neat sense of scale with like multiple layers of bigger and bigger buildings in the distance

Also really cool use of materials. Wood and stone and glass and tile all look distinct, despite just having envmaps and static lighting to work with

Thew
@AmazingThew

you eventually work your way through the city and end up on the rooftops and it does The Dark Souls Thing where you can see a bunch of places you passed through earlier

Thew
@AmazingThew

Hope's dad is wearing the worst tie in the history of videogames

Thew
@AmazingThew

as much as I like this game and am loathe to acknowledge the opinions of Gamers, I must concede that, yeah, the whole hope/snow story arc is extremely boring and irritating

Thew
@AmazingThew

it's thematically interesting, but I think the problem is we're never given any reason to LIKE either of these guys before their Flaw Arc starts

so instead of "compelling characters in conflict" it's just "15 hours of two insufferable shitheads who suck ass"

Thew
@AmazingThew

this is worsened by the fact that, for a big chunk of it, these two guys are the only people in your combat party and their jobs are essentially Bard and Tank

so it's two insufferable assholes who suck and also CANNOT INFLICT DAMAGE so every fight takes 6x longer than normal lol

Thew
@AmazingThew

oh hell yes

fuck an alexa; an Elegant and Modern home assistant is a levitating orbcone tethered to the floor by like 20 eurorack patch cables and operated by the world's least ergonomic ergo keyboard

Thew
@AmazingThew

if this game had come out ten years later, every artist I know on here would be at like *debilitating* levels of horny over this Evil Glasses OL With Stun Baton character who appears to be wearing a full body stocking under a trench coat

Thew
@AmazingThew

wow it's got god rays I can't believe the incredible power of the playstation 4 pro

Thew
@AmazingThew

Mods Are Asleep Post Vanille With A Gun

Thew
@AmazingThew

gay!! gay!!!

Thew
@AmazingThew

maybe the wildest thing about replaying this game is that in 2010 I was still a whole-ass Presbyterian and was like vaguely uncomfortable with the Overt Lesbianism and now 12 years later im like HELL YEAH STOP PUTTING STRAIGHT PPL IN VIDEOGAMES

character development arc i guess

Thew
@AmazingThew

motomu toriyama defeating calvinism with the power of gay anime

Thew
@AmazingThew

immediately after vanille and fang are reunited it finally unlocks the ability to eject all of the boys from your party

Thew
@AmazingThew

metal gear, huh

Thew
@AmazingThew

me @ almost every boss in this game

Thew
@AmazingThew

"what if we made an rpg where buff/debuff classes were actually really good and important"

it rules

Thew
@AmazingThew

this game's combat system is incredibly cool; I genuinely don't understand why all the redditgamers convinced themselves to dislike it

Thew
@AmazingThew

"all you do is hit Auto and the game plays itself" no it doesn't??? The whole thing is designed around proactively switching classes; you're supposed to micromanage roles, not individual attacks

you assign jobs to everyone and then the "auto" button is actually just "execute"

Thew
@AmazingThew

you have to constantly keep buffs and debuffs and stagger damage and "sustain stagger" damage all maintained simultaneously

if you're doing it right you're swapping classes every 1-2 turns. If you're NOT doing that you will get straight up killed by basic-ass popcorn enemies

Thew
@AmazingThew

it's super fun!

It's not wildly difficult but it's FAST and you're constantly Doing stuff. If you're on top of things you can keep enemies locked down for the whole fight and win quickly, but if you ever stop paying attention even totally basic encounters can kill you in seconds

Thew
@AmazingThew

honestly gamers do this thing where if enough of them decide a game is Bad then that becomes the official party line and then a bunch of them invent a litany of totally bizarre criticisms to justify that decision post-facto

Thew
@AmazingThew

like I distinctly remember a redditor complaining about vanille's "fake australian accent" (vanille's voice actress is Literally From Australia but apparently the fact that she doesn't sound like the crocodile hunter means the game is bad)

Thew
@AmazingThew

anyway I suspect this is what happened re: /r/gamers and the combat system lol

like the game definitely has its share of Problems that you could get mad about but the combat system really isn't one of them

Thew
@AmazingThew

(Also you can just not like things! You can even dislike things you think are Good! You're allowed to have tastes! You aren't *required* to invent a reason why a work is Objectively Deficient if the vibes just don't really click with you! god)

Thew
@AmazingThew

anyway ill stop getting mad at redditors from 2010 now

Thew
@AmazingThew

oh yeah forgot to post this one earlier

turns out there's actually Lore for vanille's weirdass antler-whip-yoyo-staff weapon

apparently it's a lasso for catching robotdragons so her Dragoon GF can fly them. like the worm hooks from dune but like more gay

Thew
@AmazingThew

canonically speaking the answer is France

Thew
@AmazingThew

ooorb

Thew
@AmazingThew

upsetting: behemoths in this game wear jeans

Thew
@AmazingThew

OH MY GOD IS THAT KARL THE ORB

Thew
@AmazingThew

this is uhhhh way too hard to explain but there's an orb named Karl in XIII-2. like it's just an orb you can talk to and it's like "hi im Karl"

I think I may have stumbled into a side quest about Orb Lore

Thew
@AmazingThew

Really digging the texture work on these rocks. Still no normal maps, just in-texture lighting that generally matches the scene

I'm assuming it's done the same way as the crystal waves: big tiling texture blended against TONS of hand-placed decals on separate UVs

Thew
@AmazingThew

Neat attention to detail here: The textures with harsh lighting are blended away where the baked lightmap transitions to shadow

those ridges aren't normal mapped; it's just carefully-applied multitexturing

Thew
@AmazingThew

hall of fame elevator design. myst III exile ass elevator design

Thew
@AmazingThew

this is possibly the most incomprehensible cutscene square has ever made

why is there an f-zero race
where is literally any of this occurring
why is the camera moving like that
what the Fuck is even happening

it's like Michael Bay's Haloid or something what the actual hell lmao

Thew
@AmazingThew

I had to trim the beginning to fit under twitter's length constraint but rest assured: there is no context. the first several minutes are just space racecars lining up like the beginning of the phantom menace podrace, absolutely out of nowhere

incredible work

Thew
@AmazingThew

lots of extremely cool megastructure stuff towards the end of the game

I really like how their chosen aesthetic for sci-fi architecture is like a cross between a luxury handbag outlet store and the trackmania nations forever stadium

Thew
@AmazingThew

also I didn't mention this when I was digging through renderdoc, but the game uses a 40 degree FOV lmao

Thew
@AmazingThew

it's part of why the game looks so good (long lenses make everything look better, it's a deliberate aesthetic choice despite what Some You Tube Ass Holes told the gamers), but it does make taking nice screenshots of the environments very difficult lol

Thew
@AmazingThew

Instead of finishing final fantasy xiii I have ended up doing a bunch of the endgame quest stuff and it's..... not very good lol

I remember ppl arguing with the Ornate Hallway Haters by being like "it opens up later!" but it opens up into something less fun than ornate hallways

Thew
@AmazingThew

there's a big huge map but the only thing you do is talk to statues that tell you to go kill a monster on the other side of the map. You (mostly) can't fast travel, and the quests are all numbered so it immediately tells you you'll be doing this like 70 times lmao

Thew
@AmazingThew

maybe worth it for this cutscene though

there are a handful of super special unique bosses, and then when you challenge one of the later ones this happens

Thew
@AmazingThew

the death animation with the crystal flying out is normally what plays when you defeat one of the special bosses. it's also a totally unique enemy design that has not appeared in any previous fight

they fully modeled/animated a new boss for this one-off fakeout gag lol

Thew
@AmazingThew

extremely cool-looking final dungeon

Thew
@AmazingThew

also after like 55 hours the minimap being an oval is STILL messing with my head

it looks exactly like it was supposed to be a circle in 4:3 and then widescreen stretched out the UI (like basically ever PS2 game including FFXII)

but no they just made it like that, on purpose

Thew
@AmazingThew

Really cool texture work on on these floor panels

recall from earlier that static meshes have no normal maps or realtime lighting, so this is all textures/masks

looks like the envmap reflections are modulated by the little tile pattern, so it appears bumpy even without normals

Thew
@AmazingThew

screenshots to elude twitter video compression

also the various Tech Greebles underneath the glass look really cool too

Thew
@AmazingThew

oh wow this is rad

again, no realtime lighting on static geo, so all specularity comes from envmaps

Check out how the reflections on the floor are blocked by shadows

I think they're using the baked shadow map to mask out the envmap term, in order to fake specular occlusion?

Thew
@AmazingThew

I haven't seen them use this anywhere else, although maybe I just wasn't looking close enough

the trick only works under fairly limited lighting+view directions, but since it's a really constrained boss arena it works perfectly

Thew
@AmazingThew

ridiculously good lighting

Thew
@AmazingThew

there's a really subtle fresnel glow that they ONLY use on fabric to give it a sort of peach-fuzz look

Tons of 360/PS3 games used fresnel effects for rim lighting and stuff but this is far more carefully applied than anything else I can remember seeing

Thew
@AmazingThew

also this is one of my all-time favorite boss designs

Thew
@AmazingThew

cinematic parallels

Thew
@AmazingThew

Interesting side effect of GPU skinning is it seems to be running out of precision when it does closeups on this very large animated model

it's visible on the characters too sometimes, although usually much less severe. Probably unnoticeable at 720p on consoles

Thew
@AmazingThew

actually uhh looks like video compression hid most of it. Basically the vertices are wiggling around like a PSX game. You can see it most easily on those spikes on the crown

[SIDE NOTE afaik psx vertex wiggle was actually a rasterizer quirk and not primarily a precision thing]

Thew
@AmazingThew

fellas is it gay for two lesbians to stop the majora's mask moon from ending the world by transforming into an 800km pillar of crystallized homosexuality