AnyPortrait > Script > Custom Shader

Custom Shader


1.5.1

AnyPortrait provides a variety of commonly used shaders, but depending on the project, you may need to write a custom shader with special effects.
You can easily write a custom shader to create great rendering results by following just a few rules of AnyPortrait.
This page explains how AnyPortrait's shader basics are structured.
Based on this explanation, we hope you will write and apply a custom shader.


When you want to apply shaders you wrote, you can use the Material Library or change the properties of the mesh.
Please check the following manuals for how to change shaders.
- Material Library
- Shader for meshes


Note
This page does not cover how to write shaders.
For more information, please refer to the Unity documentation, forums, and related sites!




Shaders in AnyPortrait


AnyPortrait does not use a single shader, but rather uses a set of shaders that are appropriate for the situation.
A total of 17 shaders are applied as a set based on three factors from which shaders are derived. (Related page)
The factors are as follows.


1. Color Space
The shader is determined based on the color space of the project.
It is written based on Gamma Space, and the color calculation formula changes in the case of Linear Space.


2. Blending
Meshes are rendered using one of four blending methods.
The default is Alpha Blend, with Additive, Soft Additive, and Multiplicative slightly modifying the blending properties and the code related to alpha calculations.


3. Clipping
The mesh being clipped receives mask texture and performs additional alpha calculations.
There is also one shader that generates the mask, but it is a functional shader that performs a fixed role.


The above factors are combined to apply a total of 17 shaders to the character.
However, when you want to write a custom shader, you don't necessarily have to write all of them.
Just check the following and write only the shaders that fit the situation of your project.


- Write only one type of shader, either Gamma or Linear, depending on the color space of the project.
- If you do not use the blending option, you only need to write the Alpha Blend shader as default.
- If there is no clipped mesh, you do not need to write a clipping shader.
- The Alpha Mask shader, which creates a clipping mask, only performs a fixed role, so you do not need to create it as a custom shader.


This page first explains the rules and method for writing an "Alpha Blend" shader in the default "Gamma Space".
Then it explains the parts that need to be modified depending on the factors that determine the shader.


It might also be helpful to check out the shader codes built into the AnyPortrait package.
The shader assets are located by default in "Assets/AnyPortrait/Assets/Shaders".
It might be convenient to duplicate the provided shaders and modify the necessary parts.






How to write a basic shader


AnyPortrait's default shader is not much different from Unity's default Transparent shader.
The following code is the default shader for "Alpha Blend" in "Gamma Space", and you can add your own custom code based on it.


Note
AnyPortrait supports both Surface Shader, Fragment Shader, and Shader Graph.
This page explains based on the code of Fragment Shader, and you can apply the rules explained here appropriately according to the situation.



Let's take a look at the main parts of the shader code.


1. Properties
_Color ("2X Color (RGBA Mul)", Color) = (0.5, 0.5, 0.5, 1.0)
_MainTex ("Main Texture (RGBA)", 2D) = "white" {}

These are the properties used in the default Transparent shader of Unity and the properties used in AnyPortrait.
In general cases where the mesh is not clipped, only these properties are used.
Therefore, in custom shaders, all codes related to these two properties must be written as is.
Also, since the AnyPortrait system controls these properties, you should not modify these properties with other scripts.


2. Basic Pass
Pass
{
    Tags { "LightMode" = "ForwardBase" }
    ZWrite Off
...
: Here is the code for the basic rendering pass.
The basic pass is specified as above because there is a separate pass for shadow casting.
If you do not write a shadow pass, you can omit the "Tags { "LightMode" = "ForwardBase" }" part.
Since we do not do Z Write, we set this value to Off.


3. Blending
Blend SrcAlpha OneMinusSrcAlpha
: Blending code for the "Alpha Blend" shader.


4. Color calculation
fixed4 col = tex2D(_MainTex, i.uv);
col.rgb *= _Color.rgb * 2.0f;
col.a *= _Color.a;
return col;
: AnyPortrait's color operation formula is "2X Multiply".
So RGB needs to be multiplied by 2 additionally.
This code changes depending on blending.


5. Shadow Pass
Pass
{
    Tags { "LightMode" = "ShadowCaster" }
    ZWrite On
...
}
: For the "Alpha Blend" mesh, you need to be able to generate shadows depending on the option.
Therefore, you need to write a "ShadowCaster" pass that generates shadows.
This pass only plays a role in generating shadows, so you can write it as in the example above.
If you write it in the Surface Shader way, you don't need to write this pass.




Shaders in Linear Space


The above example is shader code in Gamma Space, if the color space of the project is Linear Space, you need to modify the "Color calculation" part.
In the above basic code, let's modify the frag function of the basic pass ("ForwardBase") as follows.



In Linear Space, if a value raised to the power of 2.2 is applied to the color compared to Gamma Space, it appears closer to the original image color.
So, even though it is the "2X Multiply" operation rule as above, we multiply it by "4.595" instead of "2", and the final RGB is also raised to the power of "2.2".
This change should be applied regardless of the blending type.




Shaders based on Blending options


By changing the mesh options, you can render in the "Alpha Blend", "Additive", "Soft Additive", and "Multiplicative" methods in addition to the default blending method.
You need to write a shader for each blending method, but you can easily write it by slightly modifying the code of "Alpha Blend" above.
Blending options other than "Alpha Blend" are mainly for visual effects, so it is recommended not to write a pass that generates shadows.


For the three types of blending, you just need to modify some codes in the shader, "Blend" and "frag function".
Also, unlike Alpha Blend, we omit the shadow generation pass, so you can delete the "LightMode" designation code.
The following example includes the codes for all three types of blending, so you can check the comments and compile the necessary codes.



1. Blending Options
Blend One One // Additive
Blend OneMinusDstColor One // Soft Additive
Blend DstColor SrcColor // Multiplicative
: Depending on your mesh's blending options, you can choose one of the above codes.
(Soft Additive may not be supported if you use Shader Graph.)


2. Delete Multi Pass
// Tags { "LightMode" = "ForwardBase" }
: Since the shadow generation pass is gone, you can delete the code related to the multi-pass.
Also delete the shadow generation pass code.


3. Modify Color calculation
(1) Additive or Soft Additive
col.rgb *= col.a;
col.a = 1.0f;

(2) Multiplicative
col.rgb = col.rgb * (col.a) + float4(0.5f, 0.5f, 0.5f, 1.0f) * (1.0f - col.a);
col.a = 1.0f;

: Change the final color to match the blending, and change the Alpha value to 1.
The color calculation formulas for Additive and Soft Additive are the same.




Shader applied to the Clipped meshes


The Clipped meshes are rendered by a separate shader.
The shader for clipping receives the rendering result of the mesh that creates the clipping mask in texture format and adds an operation to prevent some of it from being rendered.
You can add the clipping property and the clipping operation to the basic shader.
Also, the clipping shader does not need to generate shadows in Alpha Blend, so you can write it as a single pass.
This is because it is included in the shadow of the mask mesh.
The following example is a shader for Alpha Blend in Gamma Space, and can be modified to match the explanation above.



1. Properties
_MaskTex ("Mask Texture (A)", 2D) = "white" {}
_MaskScreenSpaceOffset ("Mask Screen Space Offset (XY_Scale)", Vector) = (0, 0, 0, 1)
: Add a mask texture to the property for clipping mask processing.
If you add a property like the above, AnyPortrait will automatically handle clipping rendering.
_MaskScreenSpaceOffset is a property to apply the clipping mask based on the screen coordinate system.


sampler2D _MaskTex;
float4 _MaskScreenSpaceOffset;
: You also need to add variables to match the added properties.


2. Screen Space Position Semantic
float4 screenPos : TEXCOORD1;
: Clipping masks are processed in screen space.
Therefore, the position of the vertex in screen space must be calculated in the vertex shader and passed to the fragment shader.


o.screenPos = ComputeScreenPos(o.vertex);
: Add code to calculate the position in screen coordinates in the vertex shader.


3. Setting alpha channel value by mask
float2 screenUV = i.screenPos.xy / max(i.screenPos.w, 0.0001f);
screenUV -= float2(0.5f, 0.5f);
screenUV.x *= _MaskScreenSpaceOffset.z;
screenUV.y *= _MaskScreenSpaceOffset.w;
screenUV.x += _MaskScreenSpaceOffset.x * _MaskScreenSpaceOffset.z;
screenUV.y += _MaskScreenSpaceOffset.y * _MaskScreenSpaceOffset.w;
screenUV += float2(0.5f, 0.5f);
col.a *= tex2D(_MaskTex, screenUV).r;
: This is the formula for calculating the clipping mask and applying it to the alpha channel.
Please write it as it is, as it is a unique formula used in the AnyPortrait system.




Using Keywords in Shaders


You can use keywords to compile a single shader code into multiple versions.
You can use keywords in shaders using the features added in AnyPortrait v1.5.1.
You can see related information about keywords in the following official Unity documentation.
- Unity Manual


Here's an example shader where color operations change based on the keyword "SPECIAL_COLOR".



1. Declaring keywords
#pragma multi_compile __ SPECIAL_COLOR
: Declare keywords using the #pragma multi_compile syntax.
In this example, a new keyword called "SPECIAL_COLOR" is declared.
You can use keywords in Unity using the "multi_compile" and "shader_feature" directives that generate shader variants, or the "dynamic_branch" directive that generates dynamic branches.
However, since AnyPortrait generates materials dynamically, you cannot use "shader_feature" that compiles shader variants based on assets.


2. Writing code branches
#ifdef SPECIAL_COLOR
col.rgb *= fixed3(0.0f, 1.0f, 0.0f);
#endif
: Write to behave differently depending on the keyword.
If you use "multi_compile", use the "#ifdef, #else, #elif, #endif" directives, and if you use "dynamic_branch", use the "if ( )" statement.
In this example, if the "SPECIAL_COLOR" keyword is enabled, only the color of the green channel is rendered.


To use keywords, you need to set them in Material Library.
For more information, please refer to the Related page.




(1) Open the Material Library.
(2) Add a property option named "SPECIAL_COLOR", set it to "Keyword" type, and set it to "Enable".




If you bake and run it, you can see that the rendering result changes depending on whether the keyword is activated or not, as shown above.