Achieve this painterly compositing in Unity?

1k Views Asked by At

I've achieved this painterly effect in Blender via compositing but I need to know whether it's possible in Unity - after some google searches and going thru the Unity Asset Store I don't see anything. The effect -

enter image description here enter image description here

With Blender this is achieved through displacement and a canvas pattern. How can I do this Unity, specifically in VR?

EDIT: Here's what I have per the answer below, but no image effect is achieved:

enter image description here enter image description here

2

There are 2 best solutions below

0
On BEST ANSWER

For URP or HDRP, there is an actual simple way to apply your full screen shader fx in this way, which looks similar to traditional method "OnRenderImage()".

Firstly, you have to register two events:

    Camera Cam;
    void OnEnable()
    {
        RenderPipelineManager.endCameraRendering += RenderPipelineManager_endCameraRendering;
        RenderPipelineManager.beginCameraRendering += RenderPipelineManager_beginCameraRendering;
    }

    void OnDisable()
    {
        RenderPipelineManager.endCameraRendering -= RenderPipelineManager_endCameraRendering;
        RenderPipelineManager.beginCameraRendering -= RenderPipelineManager_beginCameraRendering;
    }

The second part is copying the Camera texture, and Blit() with shader.

    private void RenderPipelineManager_beginCameraRendering(ScriptableRenderContext context, Camera camera)
    {
        Cam.targetTexture = rt;
    }

    private void RenderPipelineManager_endCameraRendering(ScriptableRenderContext context, Camera camera)
    {
        Cam.targetTexture = null;

        //Apply your shader here
        Graphics.Blit(rt, null as RenderTexture, material);
    }

*Above suggested method is referring to FM Color, which includes advanced painting styles with shader maths.

enter image description here

5
On

Effects like this one are typically achieved using Image Effect shaders, or Compute shaders in Unity 3D. While Compute shaders tend to be more performant and flexible, they are often harder to implement. The following script and image effect shader can be used to achieve results similar to yours and might point you in the right direction:

without effect

with effect

(I used pretty low resolution textures to render these images and far better results can be achieved by just using better textures)

Create a new Image Effect Shader using Create > Shader > Image Effect Shader, call it Painterliness and replace its content with:

Shader "ImageEffects/Painterliness"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _NoiseTex ("Displacement Noise", 2D) = "white" {}
        _CanvasTex ("Canvas", 2D) = "white" {}
        _DisplacementTiling  ("Displacement tiling", Range(0.0, 10)) = 1
        _Displacement  ("Displacement", Range(0.0, 0.5)) = 0.01
        _CanvasTiling  ("Canvas tiling", Range(0.0, 10)) = 1
        _CanvasStrength  ("Canvas strength", Range(0.0, 5)) = 0.5
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            sampler2D _NoiseTex;
            sampler2D _CanvasTex;
            float _DisplacementTiling;
            float _Displacement;
            float _CanvasTiling;
            float _CanvasStrength;

            fixed4 frag (v2f i) : SV_Target
            {
                float2 offset = (tex2D(_NoiseTex, i.uv *
                    _DisplacementTiling).rg * 2 - 1) * _Displacement;
                fixed4 col = tex2D(_MainTex, i.uv + offset);
                fixed4 canvas = clamp(1 - _CanvasStrength + tex2D(_CanvasTex,
                    i.uv * _CanvasTiling) * _CanvasStrength, 0, 1);
                return col * canvas;
            }
            ENDCG
        }
    }
}

Then create a material and select this shader under ImageEffects > Painterliness for the material. Select a Colorful Noise Texture for "Displacement Noise" (this one for example) and a (grayscale) Texture for "Canvas" (this one for example).

Create a new c# scrtipt, call it ApplyImageEffect and replace its content with:

using UnityEngine;

[ExecuteInEditMode]
public class ApplyImageEffect : MonoBehaviour
{
    public Material mat;
    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if(mat)
            Graphics.Blit(src, dest, mat);
    }
}

Add ApplyImageEffect.cs to your main camera and assign the material to it. The effect should be visible in your Game View at that point and can be tweaked within the material.

I am unsure, if image effects like this one are supported in VR, but theoretically, this should work similarly for stereoscopic rendering.