Plugins are the building blocks of features in a 3D Viewer. Each plugin handles its own individual feature along with serialisation and lifecycle management.
WebGi viewer uses a plugin system to add new options, rendering styles, post processing passes, and more functionality.
The plugin architecture is designed similar to other js frameworks like vue or webpack (but for 3d rendering).
All plugins follow the same basic structure, independent of the logic, with the API to add and remove plugins being always consistent (and one-liner). This makes it easy to debug, bundle, tree-shake, serialisation/deserialisation and extend functionality to the 3d viewer. It is also recommended to keep individual plugins small and handle one specific functionality.
Plugins can be dependant on other plugins. These dependencies are automatically resolved and added to the viewer at runtime. eg. SSAOPlugin is dependant on GBufferPlugin to get the depth and normal data. So, when SSAOPlugin is added to the viewer, it automatically adds GBufferPlugin before that.
Note: Plugin dependencies are different from pass/filter dependencies, which specifies how passes should be arranged in the render pipeline (effect composer).
More information about this in later articles.
The webgi project ships with a library of plugins to achieve photorealistic rendering, generating user interfaces, handling events, loading and exporting assets, building 3d models etc.
The following plugins are available in webgi and can be added by importing them similar to the viewer.
SSAA) when camera stops moving. This plugin saves the last frame texture, which can be used by other screen space effect plugins(like SSR). So, ProgressivePlugin is added as a dependency for them. To disable SSAA but add effects like SSR, simply set maxFrameCount in ProgressivePlugin to 1.SSR) based on roughness.SSRPlugin must be added separately if screen space reflections are required.SSAO)TAA) on the scene by detecting camera motion.Note: Checkout the plugin specific pages(coming soon) to get more details on the usage and API.
Plugins first need to be imported in your app to use. For that, simply import the named plugin in es6 import syntax.
// All plugins can be imported from `webgi`
import {
ViewerApp,
ProgressivePlugin, AssetManagerPlugin, TonemapPlugin, // ...others
} from "webgi";
Instantiating a plugin can be done manually(before/after creating the viewer) or it can be left to the viewer to instantiate a provided viewer class.
// creating a plugin.
const ssaa = new ProgressivePlugin(16); // 16 is an optional argument that specifies the number of frames to render before stopping.
// add to the viewer
await viewer.addPlugin(ssaa);
// or let the viewer initialize
const ssaa = await viewer.addPlugin(ProgressivePlugin, 16);
// remove the plugin when required
await viewer.removePlugin(ssaa)
Note: it is not recommended to remove and re-add plugins that have custom passes or filters once is the pipeline has been built. To disable a plugin, set
plugin.enabletofalseif it’s supported. In the case where we need a completely new set of plugins it’s best to initialise a new viewer
Plugins need to implement a simple interface to be attached to the viewer:
interface IViewerPlugin extends IEventDispatcher<string>, IUiConfigContainer, Partial<IJSONSerializable> {
// all classes must have this static property with a unique identifier value for this plugin
static readonly PluginType: string
// these plugins will be added automatically(with default settings), if they are not added yet.
dependencies?: Class<IViewerPlugin<any>>[]
// the viewer will render the next frame if this is set to true
dirty?: boolean;
// Called when this plug-in is added to the viewer
onAdded(viewer: TViewer): Promise<void>;
// Called when this plug-in is removed from the viewer
onRemove(viewer: TViewer): Promise<void>;
// Called when the viewer is disposed
onDispose(viewer: TViewer): Promise<void>;
}
There are abstract classes to create new viewer plugins with minimal boilerplate. This includes cases for plugins with a single or multiple pre/post processing pass, connecting with the DOM, serialisation and handling user input/interactions.
Check the Writing custom plugins guide and the source of existing plugins to know more.