MinionArt’s example shader is alpha tested. Or more specifically it’s using AlphaToMask On, which is enabling alpha to coverage and desktop GPUs fall back to regular alpha testing when MSAA is not enabled.
If you’re looking to you alpha blending you must use a two pass shader which renders the back faces first and then the front faces, or approximate the back face using an analytical or precomputed SDF of some kind.
Why? Because correct and efficient sorting of transparency is an unsolved problem for real time rendering.
Thanks for the answer! I’ve spent some time trying to understand it and have now decided to lean for the two pass solution. My issue now though is doing the right semantics for two passes.
I followed this mega simple tutorial here from 2020: https://www.codinblack.com/shader-pass-and-multi-pass-shader/
and it does not work for me. Like, I literally copy pasted the code, and the outline did not appear. Is it cause I’m in URP w forward renderer? Is there some new semantic for two pass shaders that I’m not aware of?
Here’s my code for me trying to do two passes on my shader. One with the liquid pixel stuff, and the second being all white.
Yes. URP does not support multi pass shaders. Or more specifically does not support two lit passes in a single shader. You can only do a single unlit pass and a single lit pass per shader. For URP you have to do it with a Render Feature or multiple materials.
For clarification, you can have one pass with Tags{ "LightMode" = "UniversalForward" } and one pass with no "LightMode" tag or Tags{ "LightMode" = "SRPDefaultUnlit" }.
Thanks bgolus! I made it work with by using the LightMode passes. Although since the intention of these passes has to do with light I feel like there’s probably something wrong with my approach. Perhaps you might know of this?
Also, there are some calculations that I have to do for both passes in the fragment function, yet the calculations are to attain the same output value. Is there a way to pass this output value from one pass to another as a uniform variable (I think that’s the term)?
float4 frag (Interpolator i) : SV_Target
{
// [...]
// evil calculations creating values A, B, and C
// [...]
float outputIwantInBothFragPasses = A + B + C;
}
Instead of doing the calculations in both fragment functions
I mean, technically yes, but not in a way that’ll be faster than calculating it in both pass separately.
Generally speaking uniforms are assigned by the CPU before rendering begins and cannot be changed by the GPU afterwards. There are some tricks using structured buffers or render textures that can be abused to pass data between passes, in which case the uniforms aren’t being changed per-say, but rather the data in the object assigned to a uniform. But this is can be complicated when being used in a real world setup and, as I said, isn’t likely to be faster than just calculating the data again. GPUs can do a lot of math very fast, usually way faster than passing data around.