So the second region in Elden is set in a desert and an enemy has a poison attack. Rather than doing damage over time, its main impact is an incredibly distracting visual warping effect. This is implemented with a custom shader. Shaders have a reputation for being a little bit of a black magic topic among game developers, and there's a wide range of tools to allow you to make them without writing any code. I abhor this. If you have a sufficient understanding of basic linear algebra and basic control flow of software, you have everything you need to make pretty much any shader you want. Effectively you're just passing vectors into a shader, between shaders, and then out of a shader -- with very basic arithmetic operations in between. The above shader basically follows these steps:
Since step 4, the vector field, is the only step requiring math, I'll focus on that. "Vector field" sounds scary. A vector field is simply a function that takes a pair of coordinates (such as {x=4, y=8}) and spits out another pair of coordinates (possibly the same, possibly different). So to get this distortion effect, we simply offset the texture coordinates that are coming in with the sine function. Everyone knows what a sinewave looks like: All you have to do is scale the function so that it distorts in the right proportions. The sine function takes a value from 0 to 2Pi, and outputs a value from -1 to +1. Bear with me here, code incoming: float originalx = texcoords.x; texcoords.x -= sin(texcoords.y*10) * 0.1 * waviness; texcoords.y -= sin(originalx*10) * 0.1 * waviness; We have to store the starting X coordinate because we need it for the Y coordinate calculation. This is pretty simple. We're taking the X coordinates, taking the sine of the Y coordinates times ten, then multiplying by how severe we want the effect to be. Then we just do the same in reverse for the Y coordinates. This will work, but we have a problem: The problem is, if we distort in this way, we'll go past the 0~1 range of texture coordinates and it'll reach the edge of the texture and smear. That looks bad. So we need a workaround: float originalx = texcoords.x; texcoords.x -= sin(texcoords.y*10) * 0.1 * (0.5f-abs(texcoords.x-0.5f)) * waviness; texcoords.y -= sin(originalx*10) * 0.1 * (0.5f-abs(texcoords.y-0.5f)) * waviness; We take the distance from the center of the screen (texcoords.x-0.5f)) and multiply the distortion factor by this. This way, as it processes the pixels closer and closer to the edge of the screen, it reduces the amount of distortion resulting in a smooth transition to the edge. So if you're asking, "where was the vector field in that?" -- that's it right there. We're taking coordinates and transforming them in a consistent way. That's literally all it is. Not that hard eh?
1 Comment
|