-1

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

blue
  • 7,175
  • 16
  • 81
  • 179

2 Answers2

1

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

sharimken
  • 169
  • 5
0

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.

  • Hey. Thanks for this nuanced answer. I did everything as described but theres no visible image effect. I included screenshots in my answer – blue Jun 25 '21 at 03:43
  • I don't think the script is being executed. – blue Jun 25 '21 at 03:56
  • Are you using a Scriptable render pipeline like URP or HDRP ? Because according to the [documentation](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnRenderImage.html), the OnRenderImage method is not supported in this case. On my machine the instructions worked using the "3D" Template that can be found when creating a new project. It also seems to work for the "VR" Template, since the effect was visible in game view, but i do not have a VR headset to fully test this. – user16254388 Jun 25 '21 at 21:10
  • if you need a Scriptable render pipeline, the [documentation](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnRenderImage.html) states the following: "OnRenderImage is not supported in the Scriptable Render Pipeline. To create custom fullscreen effects in the Universal Render Pipeline (URP), use the ScriptableRenderPass API. To create custom fullscreen effects in the High Definition Render Pipeline (HDRP), use a Fullscreen Custom Pass." – user16254388 Jun 25 '21 at 21:11
  • Ok this is helpful thank you. I'm using URP. I'll research as well but is there an easy way to convert your ApplyImageEffect script to ScriptableRenderPass? – blue Jun 25 '21 at 21:36