-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WaveSet Mesh Alpha Channel #342
Comments
Vertex color alpha stores the length of the linked edges (kinda). In the end, it's just a multiplier for the final wave displacement in the vertex shader (so if I won't pretend to fully understand what The waveset vertex shader is just a sum of sine functions of various frequencies (sortof). Like any function, it need enough samples to display correctly to avoid aliasing. In this case, the vertices are the samples. The problem is that 2^16 vertices per mesh isn't enough to display waves for wide bodies of water (and GPU tesselation wasn't an option). For this reason, artists usually put more vertices near the shore, and less towards the horizon. This way waves can still be seen near the avatar where they matter. This also makes the water cubemap more stable up close because its reflection vector is computed per-vertex and not per-pixel. Problem is, the cubemap is still VERY unstable near the horizon due to the low mesh density and wide faces. So any wave geometric movement (which also recomputes the vertex normal) will make the cubemap wobble horribly. This is where you want a vertex alpha of zero. So as an artist, you would want to paint the alpha layer white near the shores where the avatar is standing, completely black further off (even a byte value of 1/255 is too much, you really want zero), and apply shades of grey in between. I assume Cyan wanted to automate the process based solely on face area, but this is a bad idea IMHO. Their solution doesn't take the actual geostate frequency into account. Competent artists will figure it out better, and it also gives them the option to scale waves down in some areas to avoid clipping with other meshes. A final note: if you want to actually control the transparency of the water, there are two ways to do this. The first is having the vertex' Z coordinate closer to zero (object origin), which also scales geometric movement down (and maybe other stuff that I don't remember). The second option is painting the vertex' red channel, since it behaves like the alpha channel usually does (Plasma just keeps doing things backwards :P ). |
From GPU Gems:
@colincornaby Since you were writing the Metal shader for wavesets recently, does the above description of how the alpha vertex colour channel is used seem correct? |
The shader I'm looking at is an old Unity port of the GPUgems one, so it's possible I messed up on the blue/green channels. There might also be small differences between the Plasma and GPUgems version 🤷 |
Lemme review the Metal code. The Metal code is still in a half-assembly-ish-C++ state, so deriving meaning from what each of the operations means is still tough. But - generally the wave shaders do piggyback a lot of information in things like color channels. HLSL 1.1 assembly doesn't have open ended variables between the vertex and pixel shader stages, so it's really common in those shaders to stuff things inside color registers. |
The GPU Gems text makes no mention of the alpha channel, so let's assume there are differences |
From the Metal source: The filter is used in later stages for calculating the waveform. If Cyan needed to pass in per vertex data this probably would be the way to do it. I don't think HLSL 1.1 allowed for open ended vertex buffers that could have other anonymous information in there. They would have had to have shoved it in something like a color attribute/register. |
Oh, here you go. This comment is very helpful:
|
Ah, thanks for the clarification, this is much clearer now.
Shouldn't 1 be subtracted before clamping, so that the waves truly die ? The comment in your second post says wave filtering is Looks like implementing this sounds worthwile, although low-priority. I still like the idea of having artisting control over wave amplitude, but maybe the vertex' height can work for that purpose... |
I was just wondering earlier what would happen if you added bone animations to a waveset mesh... 😇 |
@Jrius It's a good question - but... here is the original HLSL assembly.
For reference, the original HLSL assembly of the vertex shader can be found here: The half-rewritten-into-C++ Metal version is here: (Always happy to have more eyes on this to get the Metal shader C++ version more clear. It would be helpful in future GLSL or newer HLSL ports.) |
If I'm reading the discussion correctly, then it sounds like having Korman generate this edge length value and stuffing it into the vertex alpha channel is desirable, assuming the Age creator has not already manually painted vertex alpha onto the waveset. |
I'm not sure in which situation this would be useful... but people always find uses for crazy ideas :D
I'm not blaming your Metal conversion, mind you, I'm blaming Cyan's assembly code. Today I had a deeper look, and it is indeed wrong like I suspected.
This makes sense since we want the waves to completely die out when the sampling frequency is too low. But in practice (since Instead we want
Oh, and also worth noting. The comment says: TL;DR: the current version of Plasma's waveset shader has a bug, and working around it is going to be annoying. So, now, what to do...
With that said, this is all just to fix a small visual glitch. I would say it's very low priority... |
Oh certainly. The MSL code was written to reproduce the HLSL code exactly. I didn't want to produce different results by renderer, which could then make ages look different by platform. Players and creators are going to need to trust that things look the same across all the renderers. The downside is I've found multiple instances where I'm pretty sure the shaders diverge from GPU Gems or the comments. Which has led to a more literal translation of the assembly to try to sidestep that. Changing these shaders is probably a wider discussion. It would change the appearance of content. As an OpenGL renderer comes online, that adds another synchronization point for changes. Metal really prefers to precompile its shaders to bitcode at compile time. And Metal 3.0 will actually compile shaders to machine code at installation time. So I don't want to go down a path of having a real time shader generator in the client which would bypass that. But if we are going to start doing more work on the shaders, it might be helpful to get them into modern HLSL and try a tool like Shader Conductor. I've never used Shader Conductor, so I'd want to do an evaluation pass on it first. But it could help us keep changes in sync. Anyway, this is probably getting really off topic. Basically: The shaders do diverge from what they should be doing for unknown reasons, it's made the Metal translation more messy and less optimal, and it would be great if we could reconcile it all in the future. |
PlasmaMax is stuffing... something... into the alpha channel of the vertex data automatically on export. See plMeshConverter.cpp
SetWaterColor()
. Figure out what's going on here and see if we need to be doing that as well.The text was updated successfully, but these errors were encountered: