AnyPortrait > Manual > Mosaic effect using Grab Pass

Mosaic effect using Grab Pass


To implement special effects using AnyPortrait and Unity, you may need a texture representation of the "currently rendered screen."
Unity uses a feature called "Grab Pass" to retrieve the screen as a texture.
This page explains the Grab Pass, using the example of implementing the "Mosaic effect," a frequently requested feature.




Grab Pass and the Render Pipeline


To implement effects like mosaics, we need to retrieve the screen texture just before the mesh corresponding to the mosaic area is rendered.
This means that the rendering process must be paused and the frame buffer up to that point must be copied to a temporary texture.
This is accomplished using the "Grab Pass" function. (Unity Manual)
And you can easily implement screen effects by using the Grab Texture generated from this Grab Pass.


However, how you implement the effect using Grab Pass depends on your project's render pipeline.




In the Built-In Render Pipeline, you can freely call Grab Pass to retrieve Grab Texture while meshes are being rendered.
This is because Grab Texture is generated immediately when Grab Pass is specified in the shader that requires Grab Texture (in this case, the mosaic effect shader).




However, URP doesn't natively support Grab Pass.
While there is a shader function that functions similarly to Grab Pass, it's not suitable for this case because it only renders "opaque meshes".
Therefore, you need to write your own "Renderer Feature" that functions as Grab Pass.
However, Renderer Feature cannot be called during mesh rendering; it can only be called per camera and rendering event.
Therefore, to retrieve the "rendered meshes before mosaicing," you need to separate the camera.




Mosaic Effect in the Built-In Render Pipeline




We've set up the example as shown above.
We added an image and mesh to be the mosaic area and named it "Mosaic Mask."


Now let's write a shader that renders the mosaic effect. (Writing custom shaders)



This shader takes a Grab Texture and applies it to the RGB of the mesh for rendering.
At this time, the round function and the _NumMosaicBlocks property are used to change the UVs in specific size units.




Return to the AnyPortrait editor.
(1) With the Mesh Group selected, select the "Mosaic Mask" mesh.
(2) In the Shader Setting option, change the "Material Set" value to "Custom Shader."




(1) Assign the previously created mosaic shader.
(2) Set the value of the "_NumMosaicBlocks" property in the shader code above here. Click the Add Custom Property button and set the property name, type, and value.




After Bake and returning to the Unity scene to run the game, you'll see the mosaic effect applied, as shown above.
Since the "Mosaic Mask" mesh is an object within AnyPortrait, you can make it transparent or allow it to move freely according to animation.




Mosaic Effect in URP


In URP, you need to write the following three scripts, including shaders:


1. Renderer Feature to Reproduce Grab Pass
: URP does not have a Grab Pass.
Therefore, you must create your own Renderer Feature to implement Grab Pass.


2. Script to change mesh layers
: Renderer Feature operates when the camera and layer change.
Therefore, the "normal meshes" and "mosaic mask meshes" must be placed on separate layers.


3. Mosaic Shader Graph
: You need to create a mosaic shader using Shader Graph.




First, let's implement Grab Pass by writing a Renderer Feature.
However, the Renderer Feature API has changed significantly since URP 13 and is incompatible with the other APIs.
Therefore, before writing a Renderer Feature, you must check the URP version.
(Related official manual)


(1) Open Unity's Package Manager and set Packages to "In Project."
(2) Installed Unity packages will be displayed. Select Universal RP.
(3) Check the version. In the image above, it's 12.1.1, so you need a script written before URP 13.


Rather than detailing the Renderer Feature on this page, we'll leverage an open-source script developed by an external developer.
If your URP version is older than 13, you can obtain the Renderer Feature for Grab Pass script from the following link.
GrabScreenFeature by Refsa (MIT License) : Github page, Download copy


If your URP version is 13 or later, you can obtain the Renderer Feature for Grab Pass (Including Unity 6) script from the following link.
Notably, this developer implemented two versions of Renderer Feature.
With the introduction of Render Graph in Unity 6, the APIs have changed.
Download the appropriate version based on whether you're using Render Graph, as described below.
- If using Render Graph: "GrabScreenFeatureRenderGraphAPI.cs"
- If not using Render Graph: "GrabScreenFeatureU6.cs"
GrabPassU6 by Smajlovycc (MIT License) : Github page, Download copy




Once you've prepared the Renderer Feature Script for your URP version, configure URP in your project.
Create and designate a URP Asset in Project Settings > Graphics > Default Render Pipeline.
Depending on your Unity version, you may also need to configure platform-specific render pipelines.




Unity 6 and later introduced a new feature called Render Graph.
Depending on whether you use this feature, the API for Renderer Feature changes.
If you don't use scripts for Render Graph, you can enable Compatibility Mode to use the Renderer Feature written with the legacy API.
Enabling this option disables Render Graph.




Now, let's apply the Renderer Feature.
(1) Select the URP Renderer Data asset from the URP asset applied to the project.
(2) Click the Add Renderer Feature button and select the Renderer Feature for Grab Pass that you previously downloaded from open source or created yourself.




Added Renderer Feature for Grab Pass.
Check or change some properties.


1. Texture Name
: This is the name of the Grab Texture.
Remember the name, as we will use it in the shader graph for the mosaic effect.
You can change it if necessary.


2. Layer Mask
: This option specifies the layers of the objects to be included in Grab Texture.
Select only the target layers to be included in the mosaic, as "None" or "Everything" will not work properly.
Here, only the "Default" layer is specified.


Earlier, we explained that "normal meshes" and "mosaic mask meshes" must be rendered separately.
Therefore, we need to separate the layers and cameras to ensure that the "mosaic mask mesh" is rendered separately.




(1) Open Project Settings > Tags and Layers.
(2) Create a layer named "MosaicFX" in the blank space under Layers.




(1) Duplicate the existing camera rendering the character ("Main Camera") and name it "Mosaic Camera." From the second camera onward, also delete the Audio Listener component.
(2) Change the Render Type to "Overlay."
(3) Set the Culling Mask value to select only the "MosaicFX" layer.




(1) Select the original camera, "Main Camera" again.
(2) Exclude the "MosaicFX" layer from the Culling Mask value.




(3) Register "Mosaic Camera" in Stack > Cameras.


The scene has been set up so that the "Mosaic Mask Mesh" can be rendered separately.
However, because the "Mosaic Mask Mesh" resides within the AnyPortrait character, it shares the same layer as the other meshes.
Therefore, we need to write a new script to render the mesh on the "MosaicFX" layer and the "Mosaic Camera" layer.





(1) Create a new GameObject to apply the script.
(2) Add the script you created and set its values.
- Portrait: Specify the target character.
- Layer Name: Enter "MosaicFX," the layer where the mosaic mask mesh will be rendered.
- Mesh Names: Enter the name of the mosaic mask mesh within the mesh group.


Now finally, we create the "Mosaic Shader Graph".




Create a new shader graph of type "Sprite Unlit, Transparent, Alpha Blend".
You can learn how to write a shader graph for AnyPortrait at Related page, only the properties related to the mosaic effect are introduced here.
(1) In addition to the basic properties, add the properties "_NumMosaicBlocks (Float)" and "_GrabPassTransparent (Texture2D)".
(2) Set the properties of these two properties as follows:


1. _NumMosaicBlocks
: The number of mosaic blocks.
The property name is the same as the previously introduced Built-In mosaic shader property, and the mosaic mask mesh within the AnyPortrait character can pass the value.


2. _GrabPassTransparent
: The property name of the Grab Texture.
It must be the same as the "Texture Name" value of the Renderer Feature previously added as the Grab Pass.
The Show In Inspector (or Exposed, depending on the version) option must be disabled.




Complete the shader graph as shown in the image above.
(View larger image)
You can think of it as rewriting the mosaic shader from the Built-In Example in graph form.




Apply the mosaic shader for URP to the AnyPortrait character.
(1) Select the "Mosaic Mask" mesh.
(2) If the settings in the Built-In are complete, assign the "Mosaic Shader Graph Asset for URP" you just created to the Custom Shader.
(If the Custom Shader option isn't set, please refer to the corresponding section of the implementation description in the Built-In.)




(1) Select the Root Unit.
(2) Click the Material Library button.
(3) Create and select a material set from the URP material presets.
(4) Click the Default Material button to turn it on.




(1) Click the Bake button.
(2) Select the Settings tab.
(3) Change the Render Pipeline value to "Scriptable Render Pipeline."




If you do Bake and run the game, you can see that the mosaic effect works normally even in URP.