
Developer: JPLee
Email: leegoonz@163.com
JP Lee | creating Game | Patreon
Unity Version.

Rendering pipeline: Standard RP.
Summary.
Most of the latest game development is produced in a linear space.
However, I had to develop it in an environment that uses gamma space at the request of someone.
His game was not a game with many characters, so it was an environment that could be freely developed.
But it was a mobile game.
The development difficulty is not high, but I would like to write down what I developed.
I hope it helps.
Texture Channel information.

Albedo with Roughness
Albedo uses an RGB channel, and roughness for expressing light is an alpha channel.


A Roughness texture is stored in the channel.
The closer it is to white, the less glossy it is.
The closer it is to black, the stronger the amount of gloss.
This was converted directly into Linear Space inside the shader.
BRDF TEXTURE
LUT texture management.

The format should be RGB24.

I think the final texture size is 512 * 512.
This texture should not be compressed.
If it is due to Memory bandwidth, it can sometimes be slow on old hardware.
In particular, there was a problem with Xiaomi products using Qualcomm GPUs (released in 2015).
In that case, reduce the size to 256.
Implementation.
alf2 brdfUV = FLOAT2((dot(lightDirection,normalTDirection)0.5+0.5),(dot(_LightColor0.rgb,half3(0.22,0.707,0.071))_SkinToneScale));
half2 blendNormalTex = lerp(_SurfaceTa
Code language: C++ (cpp)
brdfUV.x = normalFinalDirection * 0.5 + 0.5;
half2 brdfUV_Blur = brdfUV.xy;
half4 _SkinBRDF_var = tex2D(_SkinBRDF,brdfUV_Blur); // Clamp Wrap Mode
Code language: C++ (cpp)
Normal map.


If you see this screen in the editor edit screen, you need to ignore it.
I have to follow the rules for the UnpackNormal function of the shader I created.
Normal Map uses a total of two types, but it is stored in a single texture.
One texture is stored in the RG (xy) of the texture, and another one is stored in the BA (xy) channel.
Each z value is calculated directly from the shader as dot product with sqrt.
Channel combined structure like below.

Default surface normal ( Used to XY )


Blurry normal for Scattering shading.


Normal map texture import setting.

It does not use Unity’s NormalMap encoding method.
Texture Type is Default
sRGB (Color Texture) is Off
Implementation.
uniform sampler2D _SurfaceTangentMap;
Code language: C++ (cpp)
adding sampler.
inline half3 JP_UnpackNormalRG(half2 packednormal)
{
half3 normal;
normal.xy = packednormal.xy * 2 - 1;
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
return normal;
}
Code language: C++ (cpp)
Let’s see how to handle surface normal map and blurry normal map.
half3 _SurfaceTangentMap_Local = JP_UnpackNormalRG(_SurfaceTangentTex.xy);
half3 normalT = normalize(_SurfaceTangentMap_Local);
FLOAT3 normalTDirection = mul( normalT, tangentTransform );// Perturbed normals
FLOAT3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
half2 brdfUV = FLOAT2((dot(lightDirection,normalTDirection)*0.5+0.5),(dot(_LightColor0.rgb,half3(0.22,0.707,0.071))*_SkinToneScale));
half2 blendNormalTex = lerp(_SurfaceTangentTex.zw , _SurfaceTangentTex.xy, brdfUV.x);
half3 normalT_Final = normalize(JP_UnpackNormalRG(blendNormalTex.xy));
FLOAT3 normalDirectionFinal = mul( normalT_Final , tangentTransform);
float normalFinalDirection = dot( normalDirectionFinal, lightDirection );
Code language: C++ (cpp)
There is also a technique using DDX and DDY.
In Opengl3.1, there is no big problem even if you use this.
I’ll cover the implementation of this in the next topic.
Shader Map.
It is an important texture in skin expression.

Information on the curvature of the skin or the transmission weight of the face is stored in the R channel.
Occlusion information for light is recorded on the G channel.
In my shader, I used G channel information in addition to the Occlusion effect, so I saved it in the Shader map.
Color Transformation regulations for Linear space rendering When We use to Gamma mode in Unity3D Project.
Material Descriptions.

Roughness with Reflection
Multiply the Roughness texture and Roghness variable values to express the glossiness of the skin surface.
Reflection creates a reflected light effect.
This is linked to the final Roughness expression.
The above two values are greatly influenced by Tone Mapper.
SkinBRDF
For skin expression, we need to calculate SkinBRDF.
Default is on.
Skin Brdf Attenuation
Skin Brdf Attenuation slightly obscures the shadow boundary and the skin boundary.
Default is on.
The reason for implementing this feature is that Soft Shadow cannot be used in mobile rendering, and if you need to use Soft Shadow, you must implement your own shadow.
If you can’t implement shadows yourself, it’s best to use this feature as much as possible to blur the boundaries between the shadow and skin areas.
This can be modified with the Skin Tone Scale and BRDF Attenuation values.
You need to find a suitable range for both values.

Implementation.
//attenuation *= pow(_SkinBRDF_var , _AttenuationScale);
half attenuation = _UseBrdfAtten?LIGHT_ATTENUATION(i) * (saturate( ( (normalFinalDirection * 0.5 + 0.5) * 2.0) * 2.0 - 1.0)) * pow(_SkinBRDF_var , _AttenuationScale ):LIGHT_ATTENUATION(i);
Code language: C++ (cpp)

Skin Tone Color
It is the Scattering colour of the skin.
Skin Trans Map
The R channel is used as a depth value for skin scattering.
The G channel is used for the Occlusion effect.
See ShaderMap for information on texture information.
BackLight Dir
It is a fake lighting direction.
This is for skin penetration effect only.
SubLighting
Indirect lighting was added without using auxiliary light.
It creates a lighting effect from the side.
You can turn it on or off and modify the intensity with Lighting Intensity.
On a mobile screen, if the gloss is strong, it tends to look whiter than the original color.
Therefore, it is not desirable to give Lighting Intensity too strong.


Implementation.
#include "./Common/JPStandardCoreForward.cginc"
Code language: C++ (cpp)
Define to include code path like this.
TONE MAPPER
Assuming that no post-processing is used, Tone mapping is implemented and applied directly inside the shader.
When rendering in Gamma space, the most noticeable part is that the specular part of the light is finally calculated in the gamma space, resulting in the feeling that the skin color is displaced.
This is to remove the characteristics of Gamma space as much as possible using TONE MAPPER.
Implementation.


Complete shader code.
Example
Pre integrated skin shader under Gamma space dev. | JP Lee on Patreon