I want to show my small tips. Hope it will helpful for you.
For mobile development, it is the most important to have as few DIPs/batches as you can. And some popular blending modes often are Additive and Alpha blend. If you use both of this for particles it will break batching because you need different shaders for this. But you can use just one shader for both types of blending.
Here is a shader code for Unity3D.
Edited version. Thanks bgolus for advice!
/* Alpha and Additive blending in one shader.
* If all color components are under 128, it will be like alpha blending.
* if the brightest color component goes from 128 to 255, it will decrease alphablend contribution and will look more like additive blending.
* if the brightest color component is 255, it will use 100% additive blending.
* You must use premultiplied RGB channel.
* Created by Alex Fedotovskikh
*/
Shader "FX/_Common/Add_AlphaBlend" {
Properties {
_Color ("Multiplier", Color) = (1,1,1,1)
_MainTex ("MainTex", 2D) = "white" {}
_ColorMul ("Color Multiplier", float) = 1
}
SubShader {
Tags {
"IgnoreProjector"="True"
"Queue"="Transparent"
"RenderType"="Transparent"
}
Pass {
Name "FORWARD"
Tags {
"Queue"="Transparent"
}
ZWrite Off
Cull Off
Blend One OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#pragma target 2.0
#include "UnityCG.cginc"
uniform float4 _Color;
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform float _ColorMul;
struct appdata {
half4 vertex : POSITION;
half2 texcoord : TEXCOORD0;
half4 color : COLOR;
};
struct v2f {
half4 pos : POSITION;
half2 texcoord : TEXCOORD0;
half4 color : COLOR;
};
v2f vert(appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
v.color *= _Color;
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
float alphaBlendFactor = 1.0f - saturate(max(max(v.color.r, v.color.g), v.color.b) * 2.0f - 1.0f); // 1 = alphablend, 0 = additive blend
o.color.rgb = v.color.rgb * v.color.a * lerp(_ColorMul, 2.0f, alphaBlendFactor);
o.color.a = v.color.a * alphaBlendFactor;
return o;
}
fixed4 frag(v2f i) : COLOR
{
fixed4 color;
fixed4 tex = tex2D(_MainTex, i.texcoord);
color = tex * i.color;
return color;
}
ENDCG
}
}
FallBack "Diffuse"
}
And comparision with standart Unity shaders.
Would it better to write all future tips in that place or separately?
Whatâs the benefit of using this vs a straight pre-multiplied shader if youâre already using a pre-multiple texture? If you want alpha blend just animate the color and alpha together. If you want purely additive just set the alpha to zero.
Also thereâs a lot of cruft in this shader. The âLightModeâ should not be âForwardBaseâ for an unlit shader, nor should it have #pragma multi_compile_fwdbase or #define UNITY_PASS_FORWARDBASE, youâre forcing Unity to generate additional shader variants for a shader that does not need them. It also shouldnât have a fallback defined unless you want this shader to cast square shadows.
Youâre also passing the texcoord as a float3 value but the alpha blend factor never gets used in the fragment shader. This doesnât really do anything bad since internally passed values are always 4 components regardless of how you specify them and the shader compiler will optimize it away, it just causes confusion.
It should be noted the premultipled alpha particle shader that ships with Unity is broken and isnât actually a proper premultiplied shader. It incorrectly multiplies the color and alpha by the alpha. This means the alpha falloff is squared instead of linear! It also removes the ability to control the alpha separately from the color so you can do additive and alpha blend in the same shader. The default particle material uses that shader too.
Hereâs my version of a premultiplied alpha shader. It requires a little more care with picking colors in the particle system, but should be faster, especially for mobile.
Do you need the TRANSFORM_TEX macro if you arenât scaling or translating? Iâve removed it from most of my shaders unless they are used with tiling textures.
Cool, yeah I have shaders that are almost identical. I went on an optimization blitz for a few weeks recently so Iâve been staring at stuff like this. Unity 5 has also disabled the fragmentoption apparently:
Compilation directives that donât do anything starting with Unity 5.0 and can be safely removed: #pragma glsl, #pragma glsl_no_auto_normalization, #pragma profileoption, #pragma fragmentoption. https://docs.unity3d.com/Manual/SL-ShaderPrograms.html
It gives me an easy and predictable way to set right color into gradients. If you use usual alpha pre-multiplied shader it forces you to change color when you want to change just an alpha. For example, you have some gradient and a middle alpha key is 43. You decided to set it a little few, like 27. With usual alpha pre-multiplied shader you must calculate a percentage of alpha changing for saving blend operation because you donât need spontaneously changing alpha blend to additive or something middle. Your calculation will be like that (43-27)/255 * currentColorInProperPositionOfGradient = that portion of reducing of color for each component. I donât want to care about color if I change just alpha component. Thatâs my point.
Thank you, man! Very useful information! It seems just something like old inheritance generated ShaderForge. I trust it, unfortunately, and didnât even care about that. Have to remove already. =)
Oh, that a shame⊠Sorry. Missed that during changing original shader. Thanks!
Itâs so cheap. After compiling it will be just one Mad operation for vec2 in a vertex shader. But it will give you a comfortable way to use that shader for geometry too.
I fairly frequently will intentionally fade out pre-multiplied particle effects with unmatched alpha and color so it goes to a subtle additive before fading out completely. However I donât find adjusting the color gradient to match the alpha to be all that hard to do, especially in Unity. Just select the color you want, switch to HSV and type in â* (alpha/255)â on the value line. Basically you can do all that calculation inline with the value input.
TRANSFORM_TEX is cheap, but it too breaks batching just like any other value changing on the material. Unity can batch billboard particle systems and mesh particle systems, and meshes all together if they use the exact same material. Because of the way Unity does batching youâre better off using multiple meshes with manually adjusted UVs or scripts using additional vertex streams to adjust UVs. The later is what Unity already does for flipbook UVs on mesh particles and lightmap UVs internally.
Hi, guys!
I translated my slides to English made for DevGamm conference. Hope you will like it and find here something useful.
I recommend to download it to watch videos and read the text below each slide.
mathematically itâs something like depthFade = (zBuffer_z - pixel_z) / fadeDistance * opaque;
but this approach makes fadeout border thinner when a camera looks parallel to a plane intersecting with a geometry of fx or particles.
As a VFX geometry, I used a sphere trying to make a magic shield rising from a ground.
And you can see here is a bug - height of a shield is getting thinner.
So we need to correct it. The Idea here is a compensation of difference between depths (zBuffer_z - pixel_z) by an angle between Ńamera vector and a normal map of a plane on the back. But we canât read a normal map because it is a forward pass. So we need to reconstuct it from derivatives and zBuffer. See a figure below.