Shader Chunk Migrations
Introduction
The PlayCanvas Engine's material shader chunk system is undergoing substantial changes in order to support a more flexible material system. Please see this page for more context.
In order to help users migrate their existing custom shader chunks, this page lists the changes made to chunks and organizes them by engine release (starting v1.51).
Chunk API Versions
The debug version of the Engine will report any API changes to the runtime console when it detects overridden chunks. For example:
Once an application's chunks have been updated to the latest API they must be flagged as such. For example, after updating a material's custom chunks to the latest engine release (say v1.55), specify this in the chunks object as follows:
material.chunks.diffusePS = '...';
material.chunks.APIVersion = pc.CHUNKAPI_1_55;
By doing this you will no longer see warning messages in the console.
Chunk changes
The following tables break down the chunk changes by Engine release.
Engine v1.70
Chunk | Changes |
---|---|
refractionDynamicPS |
|
refractionCubePS |
|
Engine v1.65
In 1.62, global variables used to pass the values between the front end back end chunks were grouped into structures LitShaderArguments, IridescenceArgs, ClearcoatArgs and SheenArgs. Those were causing multiple compatibility issues on Android devices, and so in 1.65, these are being converted back to global variables. For example litShaderArgs.albedo
is now litArgs_albedo
.
These are the new global variables:
// Surface albedo absorbance
vec3 litArgs_albedo;
// Transparency
float litArgs_opacity;
// Emission color
vec3 litArgs_emission;
// Normal direction in world space
vec3 litArgs_worldNormal;
// Ambient occlusion amount, range [0..1]
float litArgs_ao;
// Light map color
vec3 litArgs_lightmap;
// Light map direction
vec3 litArgs_lightmapDir;
// Surface metalness factor, range [0..1]
float litArgs_metalness;
// The f0 specularity factor
vec3 litArgs_specularity;
// Specularity intensity factor, range [0..1]
float litArgs_specularityFactor;
// The microfacet glossiness factor, range [0..1]
float litArgs_gloss;
// Glossiness of the sheen layer, range [0..1]
float litArgs_sheen_gloss;
// The color of the f0 specularity factor for the sheen layer
vec3 litArgs_sheen_specularity;
// Transmission factor (refraction), range [0..1]
float litArgs_transmission;
// Uniform thickness of medium, used by transmission, range [0..inf]
float litArgs_thickness;
// Index of refraction
float litArgs_ior;
// Iridescence effect intensity, range [0..1]
float litArgs_iridescence_intensity;
// Thickness of the iridescent microfilm layer, value is in nanometers, range [0..1000]
float litArgs_iridescence_thickness;
// The normal used for the clearcoat layer
vec3 litArgs_clearcoat_worldNormal;
// Intensity of the clearcoat layer, range [0..1]
float litArgs_clearcoat_specularity;
// Glossiness of clearcoat layer, range [0..1]
float litArgs_clearcoat_gloss;
These are the chunk that had their signature changed to accept individual members, instead of the whole structures:
- endPS
- metalnessModulatePS
- outputAlphaPS
- outputAlphaPremulPS
- fresnelSchlickPS
- iridescenceDiffractionPS
- lightmapAddPS
- lightmapDirAddPS
- refractionCubePS
- refractionDynamicPS
Engine v1.62
In PlayCanvas, we have two sets of shader chunks, one set we refer to as the shader frontend, which provide values for the arguments passed to our lighting algorithm, also called the shader backend.
With 1.62, we are creating a clearer distinction between these two, such that the values passed to the backend are well defined and known in advance, not automatically generated. This allows for writing a fully custom shader that can interface with our lighting code just like how our native materials do.
As a result of that, almost all backend chunks have been changed to accommodate for the split. This means that any custom backend shader chunks must move away from using globals to using the arguments passed to them by the lighting backend.
This change also makes some chunks, such as the clearcoat specific ones, redundant, as their functions have become reusable when their no longer reliant on global values.
Changes
This release breaks most lit/frag chunks. Most of these chunks have had their signatures changed to accept the various values they need, instead of relying on globals. With that said, most globals are still set in the shader. An example of this change is:
vec3 combineColor() {
vec3 ret = vec3(0);
ret = dAlbedo * dDiffuseLight;
...
}
Is now expressed:
vec3 combineColor(vec3 albedo, vec3 sheenSpecularity, float clearcoatSpecularity) {
vec3 ret = vec3(0);
ret = albedo * dDiffuseLight;
...
}
Where we previously had globals, in 1.62 they are packed into structs, these structs are the primary LitShaderArgs which is defined as such:
struct LitShaderArguments
{
// Transparency
float opacity;
// Normal direction in world space
vec3 worldNormal;
// Surface albedo absorbance
vec3 albedo;
// Transmission factor (refraction), range [0..1]
float transmission;
// Uniform thickness of medium, used by transmission, range [0..inf]
float thickness;
// The f0 specularity factor
vec3 specularity;
// The microfacet glossiness factor, range [0..1]
float gloss;
// Surface metalness factor, range [0..1]
float metalness;
// Specularity intensity factor, range [0..1]
float specularityFactor;
// Ambient occlusion amount, range [0..1]
float ao;
// Emission color
vec3 emission;
// Light map color
vec3 lightmap;
// Light map direction
vec3 lightmapDir;
// Iridescence extension arguments
IridescenceArgs iridescence;
// Clearcoat extension arguments
ClearcoatArgs clearcoat;
// Sheen extension arguments
SheenArgs sheen;
};
The last three arguments are our shading extensions. IridescenceArgs is defined as such:
struct IridescenceArgs
{
// Iridescence effect intensity, range [0..1]
float intensity;
// Thickness of the iridescent microfilm layer, value is in nanometers, range [0..1000]
float thickness;
};
ClearcoatArgs:
struct ClearcoatArgs
{
// Intensity of the clearcoat layer, range [0..1]
float specularity;
// Glossiness of clearcoat layer, range [0..1]
float gloss;
// The normal used for the clearcoat layer
vec3 worldNormal;
};
SheenArgs:
struct SheenArgs
{
// Glossiness of the sheen layer, range [0..1]
float gloss;
// The color of the f0 specularity factor for the sheen layer
vec3 specularity;
};
Chunk | Changes |
---|---|
ambient(Constant/Env/SH) |
|
aoDiffuseOcc |
|
aoSpec(Occ/OccConst/OccConstSimple/OccSimple) |
|
combine |
|
clusteredLight |
|
clusteredLightShadow |
|
combine |
|
end |
|
fallOff(InvSquared/Linear) |
|
fresnelSchlick |
|
iridescenceDiffraction |
|
lightDiffuseLambert |
|
lightSheen |
|
lightSpecular(AnisoGGX/Blinn/Phong) |
|
lightmap(DirAdd/Add) |
|
ltc |
|
metalnessModulate |
|
output(Alpha/AlphaPremul) |
|
reflDir(Aniso) |
|
reflection(CC/Cube/Env/EnvHQ/Sphere/SphereLow) |
|
reflectionSheen |
|
refraction(Cube/Dynamic) |
|
shadow(Common/Coord/CoordPerspZBuffer |
|
shadow(EVSM/EVSMn/Standard/StandardGL2/VSM8) |
|
spot |
|
TBN(-/ObjectSpace/derivative/fast) |
|
Engine v1.60
Chunk | Changes |
---|---|
clearCoatGlossPS |
|
glossPS |
|
sheenGlossPS |
|
Engine v1.57
In 1.57, almost all front-end chunks have been changed to minimize the amount of samplers used by the shader. This is an optional feature, however it's recommended to follow the same coding style to reduce the amount of samplers used by the shader. The following chunks are affected by it:
Chunk |
---|
aoPS |
clearCoatPS |
clearCoatGlossPS |
clearCoatNormalPS |
diffusePS |
diffuseDetailMapPS |
emissivePS |
metalnessPS |
normalMapPS |
normalDetailMapPS |
opacityPS |
parallaxPS |
sheenPS |
sheenGlossPS |
specularPS |
specularityFactorPS |
thicknessPS |
transmissionPS |
This is also supported in custom front-end chunks, given that your chunk piggybacks on the pre-existing material samplers. To support this method in your chunks, what you'd need to do is:
- Remove the sampler uniform declaration from the chunk
- Replace the sampler name with the
$SAMPLER
macro
For example:
uniform sampler2D texture_aoMap;
void getAO() {
dAo = 1.0;
#ifdef MAPTEXTURE
dAo *= texture2DBias(texture_aoMap, $UV, textureBias).$CH;
#endif
#ifdef MAPVERTEX
dAo *= saturate(vVertexColor.$VC);
#endif
}
Would be converted to:
void getAO() {
dAo = 1.0;
#ifdef MAPTEXTURE
dAo *= texture2DBias($SAMPLER, $UV, textureBias).$CH;
#endif
#ifdef MAPVERTEX
dAo *= saturate(vVertexColor.$VC);
#endif
}
This allows the engine to automatically pick the sampler uniform to use, thus potentially reducing the total number of samplers. But note, this is only supported for front-end chunks.
Engine v1.56
Chunk | Changes |
---|---|
combineXXXX |
|
refractionPS |
|
refractionCubePS |
|
refractionDynamicPS |
|
sheenPS |
|
sheenGlossPS |
|
reflectionEnvHQPS |
|
thicknessPS |
|
bakeDirLmEndPs |
|
bakeLmEndPS |
|
Engine v1.55
Chunk | Changes |
---|---|
clearCoatNormalPS |
|
clusteredLightPS |
|
combinePS |
|
combineXXXX |
|
diffusePS |
|
diffuseDetailMapPS |
|
endPS |
|
emissivePS |
|
fresnelSchlickPS |
|
lightmapSingleVert.js |
|
lightmapDirPS , lightmapSinglePS |
|
lightmapAddPS , lightmapDirAddPS |
|
lightSpecularAnisoGGXPS |
|
lightSpecularBlinnPS , lightSpecularPhongPS |
|
ltcPS |
|
normalMapFastPS |
|
normalMapPS |
|
normalDetailMapPS |
|
normalVertexPS |
|
metalnessPS |
|
metalnessModulatePS |
|
reflectionCC |
|
specularAaNonePS , specularAaToksvigPS , specularAaToksvigFastPS |
|
startPS |
|
specularPS |
|
specularityFactorPS |
|