- Home /
How to render all opaque meshes with the same effect?
I have a specular outline shader that I want to be used on all opaque meshes of the scene whenever a specific camera renders. The shader is working properly when it is manually applied to some material. The shader is as follows:
Shader "Custom/Outline" {
Properties {
_Color ("Main Color", Color) = (.5,.5,.5,1)
_OutlineColor ("Outline Color", Color) = (1,0.5,0,1)
_Outline ("Outline width", Range (0.0, 0.1)) = .05
_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
_Shininess ("Shininess", Range (0.03, 1)) = 0.078125
_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
}
SubShader {
Tags { "Queue"="Overlay" "RenderType"="Opaque" }
Pass {
Name "OUTLINE"
Tags { "LightMode" = "Always" }
Cull Off
ZWrite Off
// Uncomment to show outline always.
//ZTest Always
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : POSITION;
float4 color : COLOR;
};
float _Outline;
float4 _OutlineColor;
v2f vert(appdata v) {
// just make a copy of incoming vertex data but scaled according to normal direction
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
float3 norm = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
float2 offset = TransformViewToProjection(norm.xy);
o.pos.xy += offset * o.pos.z * _Outline;
o.color = _OutlineColor;
return o;
}
float4 frag(v2f fromVert) : COLOR {
return fromVert.color;
}
ENDCG
}
UsePass "Specular/FORWARD"
}
FallBack "Specular"
}
The camera used fot the effect has just a script component which setups the shader replacement:
using UnityEngine;
using System.Collections;
public class DetectiveEffect : MonoBehaviour {
public Shader EffectShader;
// Use this for initialization
void Start () {
this.camera.SetReplacementShader(EffectShader, "RenderType=Opaque");
}
// Update is called once per frame
void Update () {
}
}
Unfortunately, whenever I use this camera I just see the background color. Any ideas?
Answer by tanoshimi · Oct 24, 2013 at 06:33 AM
You've misunderstood the way that replacement tags in SetReplacementShader work - I had exactly the same problem, and I find the documentation not to be clear (not helped by the fact that the link to the "Rendering with Replaced Shaders" topic from the http://docs.unity3d.com/Documentation/ScriptReference/Camera.RenderWithShader.html page is borked :(
Your Start() function should not specify the replacement tag value, only the key, like this:
camera.SetReplacementShader (EffectShader, "RenderType");
Then, your replacement shader, EffectShader, should contain different Subshaders with key-value tags for each RenderType that you want to replace, e.g.:
Shader "EffectShader" {
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
...
}
}
SubShader {
Tags { "RenderType"="SomethingElse" }
Pass {
...
}
}
...
}
SetReplacementShader will look through all the objects in the scene and, instead of using their normal shader, use the first subshader which has a matching value for the specified key (e.g. in this example, any objects whose shader has Rendertype="Opaque" tag will be replaced by first subshader in EffectShader, any objects with RenderType="SomethingElse" shader will use second replacement subshader). Any objects whose shader does not have a matching tag value for the specified key in the replacement shader will not be rendered.
At least, that's what I think happens - I've had many issues wrestling with aspects of SetReplacementShader and eventually rolled my own replacement instead. Good luck!
Your answer
Follow this Question
Related Questions
EdgeDetectEffectNormals flips camera 0 Answers
Post processing effect on depth only camera. 1 Answer
Shader to a Camera 1 Answer
Setting up a simple depth-based Shader Replacement material? 0 Answers
effect on clipping plane 1 Answer