Split standard material into frontend and backend
Background
Up till now the standard material has been responsible for all parts of the rendering pipeline. Standard material defines an "uber shader" interface for artists to specify the surface properties like diffuse, specular, roughness etc. (We call these properties the material frontend). The standard material also implements the runtime lighting system, including lights, IBL, dynamic shadows and everything else needed to render the surface. (We call this the material backend).
(As an aside, in deferred rendering the components written into the g-buffer can be thought of as the frontend. While the lighting passes which use the g-buffer and generate the final image are the material backend).
The current standard material structure means that users have limited scope for customising the look of materials. Either users must make do with the features provided by the uber shader interface, or they must customise the shader chunk system. Unfortunately the shader chunk system is undocumented, open to change, difficult to debug and results in very brittle code.
For these reasons, we propose to split out the lighting backend from the monolithic standard material. Doing so will mean we can leverage the runtime lighting system with any arbitrary frontend.
The new lighting backend will be used by the standard material as well as the shader-editor (currently in development).
Todo:
- [x] extract the backend parts of standard.js (done in #4254)
- [x] restructure shader chunks so there is a formal frontend and backend split (done in #4254)
- [x] provide runtime support to notify application developers if chunks have changed (#4343)
- [ ] restructure the options builder into frontend and backend (see options builder) (done in PR #)
- [ ] implement an engine example of custom frontend shader using the new material backend (done in PR #)
Will this deprecate shader chunks and the current approach of providing custom chunks?
Will this deprecate shader chunks and the current approach of providing custom chunks?
No not at all.
But we have started splitting chunks into frontend and backend, see the directory structure:
standardare the standard material frontend chunkslitare the material backend chunks
We will try make as few changes to the standard chunks as possible, so users can continue to override these without future breakages. The backend lit chunks though might change in future and will likely break projects that have these chunks overridden.
The frontend is considered a blackbox and is responsible for providing the following (optional) values to the backend:
| component | variable | type | space |
|---|---|---|---|
| emission | dEmission |
vec3 | |
| alpha | dAlpha |
float | |
| normal | dNormalMap |
vec3 | tangent |
| albedo | dAlbedo |
vec3 | |
| glossiness | dGlossiness |
float | |
| specularity | dSpecularity |
vec3 | |
| ambient occlusion | dAo |
float | |
| lightmap | dLightmap |
vec3 | |
| lightmap direction | dLightmapDir |
vec3 | |
| clear coat specularity | ccSpecularity |
float | |
| clear coat glossiness | ccGlossiness |
float | |
| clear coat normal | ccNormalMap |
vec3 | tangent |
In addition the frontend is responsible for:
- alpha test discard
In order for the frontend to have access to world and camera space, the fragment shader must calculate data in the following order:
- backend calculates world space vertex normal (
normalVertexPS) - backend calculates world space view direction (
viewDirPS) - based on these the backend calculates TBN matrix (used to transform from tangent/geometry space to world space)
- frontend executes, outputs emission, diffuse, tangent space normal etc has access to TBN
- backend calculates lighting and outputs final color/depth
Minor point on naming, but why are all variables prepended with d except clear coat ones, which are cc? Wouldn't more consistent naming be:
dSpecularityCC
or
dCCSpecularity
What does d mean anyway?
Also, normals, when unpacked, they are no more a map, but just normals.
I suggest we close this now. I know the example isn't written. Maybe open a new issue for that?
Done!