Outline Shader in VR
Hi,
I have a problem with implementing an outline shader (based on this tutorial: https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/) in VR.
When running the game without an attached Vive, everything displays correctly:
As you can see the block in the front is correctly outlined.
When I run it in VR, two things happen:
1) When I look at the selected object I see the outline twice 2) If I look away from the object, I see the outline only once, but at the wrong position.
This seems to be due to the shader being performed twice (maybe only on the screen space) and therefore not correctly displaying the shader in VR. Can anyone clarify? Here's my sample code:
Script attached to the camera:
using UnityEngine;
using System.Collections;
public class PostEffect : MonoBehaviour
{
Camera AttachedCamera;
public Shader Post_Outline;
public Shader DrawSimple;
Camera TempCam;
Material Post_Mat;
void Start ()
{
AttachedCamera = GetComponent<Camera>();
TempCam = new GameObject().AddComponent<Camera>();
TempCam.enabled = false;
Post_Mat = new Material(Post_Outline);
}
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
//set up a temporary camera
TempCam.CopyFrom(AttachedCamera);
TempCam.clearFlags = CameraClearFlags.Color;
TempCam.backgroundColor = Color.black;
//cull any layer that isn't the outline
TempCam.cullingMask = 1 << LayerMask.NameToLayer("Outline");
//make the temporary rendertexture
RenderTexture TempRT = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.ARGB32);
//put it to video memory
TempRT.Create();
//set the camera's target texture when rendering
TempCam.targetTexture = TempRT;
//flip the camera, since VR image is somehow upside down
TempCam.ResetWorldToCameraMatrix();
TempCam.ResetProjectionMatrix();
TempCam.projectionMatrix = TempCam.projectionMatrix * Matrix4x4.Scale(new Vector3(1, -1, 1));
//render all objects this camera can render, but with our custom shader.
TempCam.RenderWithShader(DrawSimple,"");
Graphics.Blit(source, destination);
//copy the temporary RT to the final image
Graphics.Blit(TempRT, destination, Post_Mat);
//release the temporary RT
TempRT.Release();
}
}
Shader that renders selected objects in white:
//This shader goes on the objects themselves. It just draws the object as white, and has the "Outline" tag.
Shader "Custom/DrawSimple"
{
SubShader
{
ZWrite Off
ZTest Always
Lighting Off
Pass
{
CGPROGRAM
#pragma vertex VShader
#pragma fragment FShader
struct VertexToFragment
{
float4 pos:POSITION;
};
//just get the position correct
VertexToFragment VShader(VertexToFragment i)
{
VertexToFragment o;
o.pos=UnityObjectToClipPos(i.pos);
return o;
}
//return white
fixed4 FShader():COLOR0
{
return fixed4(1,1,1,1);
}
ENDCG
}
}
}
Post-Processing shader that does the actual outline:
Shader "Custom/Post Outline"
{
Properties
{
_MainTex("Main Texture",2D)="white"{}
}
SubShader
{
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
sampler2D _MainTex;
//<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
float2 _MainTex_TexelSize;
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 pos : POSITION;
float2 uvs : TEXCOORD0;
};
v2f vert (appdata_base v)
{
v2f o;
//Despite the fact that we are only drawing a quad to the screen, Unity requires us to multiply vertices by our MVP matrix, presumably to keep things working when inexperienced people try copying code from other shaders.
o.pos = UnityObjectToClipPos(v.vertex);
//Also, we need to fix the UVs to match our screen space coordinates. There is a Unity define for this that should normally be used.
o.uvs = o.pos.xy / 2 + 0.5;
return o;
}
half4 frag(v2f i) : COLOR
{
//arbitrary number of iterations for now
int NumberOfIterations=5;
//split texel size into smaller words
float TX_x=_MainTex_TexelSize.x;
float TX_y=_MainTex_TexelSize.y;
//and a final intensity that increments based on surrounding intensities.
float ColorIntensityInRadius;
//if something already exists underneath the fragment, discard the fragment.
if(tex2D(_MainTex,i.uvs.xy).r>0)
{
discard;
}
//for every iteration we need to do horizontally
for(int k=0;k<NumberOfIterations;k+=1)
{
//for every iteration we need to do vertically
for(int j=0;j<NumberOfIterations;j+=1)
{
//increase our output color by the pixels in the area
ColorIntensityInRadius+=tex2D(
_MainTex,
i.uvs.xy+float2
(
(k-NumberOfIterations/2)*TX_x,
(j-NumberOfIterations/2)*TX_y
)
).r;
}
}
//output some intensity of teal
return ColorIntensityInRadius*half4(0,1,1,1);
}
ENDCG
}
//end pass
}
//end subshader
}
//end shader
Your answer
![](https://koobas.hobune.stream/wayback/20220612150706im_/https://answers.unity.com/themes/thub/images/avi.jpg)