I'm currently working on the visuals for my game. Currently, it looks like this:
.
Using a composite shader, I am able to colour the light and dark areas of the objects on the default layer. Now I would like to be able to add pure white objects to the scene as well. As can be seen on the image, this seems to work at first glance, but my current solution has one major flaw: The white objects are not occluded by the other geometry.
Now, as I understand, with a camera's culling mask only set to one layer, this camera will exclusively render the objects of that layer, not taking into account any geometry on other layers, correct?
Is there a way to get that information back in, so I can make highlights that are occluded by the other geometry?
The current code looks like this (Disclaimer: It's a solution I got from a colleague which I slightly adapted while I can find my way around C#, I'm always stumped when it comes to Shaderlab):
CompositeEffect.cs:
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
[AddComponentMenu("Image Effects/Composite")]
public class CompositeEffect : MonoBehaviour
{
public Camera lightCamera;
public Camera darkCamera;
public Camera highlightsCamera;
public Shader compositeShader;
public float contrast = 0.8f;
Material _material;
Material material {
get {
if (_material == null)
_material = new Material (compositeShader);
_material.hideFlags = HideFlags.HideAndDontSave;
return _material;
}
}
Vector2 renderScreenSize = Vector2.zero;
RenderTexture lightTex;
RenderTexture darkTex;
RenderTexture highlightTex;
// []
// Called by the camera to apply the image effect
void OnRenderImage (RenderTexture source, RenderTexture destination) {
if (!lightCamera || !darkCamera)
return;
contrast = Mathf.Clamp01 (contrast);
Vector2 currScreenSize = new Vector2 (Screen.width, Screen.height);
if (!lightCamera.targetTexture || !lightCamera.targetTexture ||
!lightTex || !darkTex || !highlightsCamera.targetTexture || !highlightTex || renderScreenSize != currScreenSize)
{
RecreateTextures (currScreenSize);
AssignTextures ();
}
lightCamera.Render ();
darkCamera.Render ();
highlightsCamera.Render ();
// assign textures for blending
material.SetTexture ("_Tex1", lightCamera.targetTexture);
material.SetTexture ("_Tex2", darkCamera.targetTexture);
material.SetTexture("_Tex3", highlightsCamera.targetTexture);
material.SetFloat("_Contrast", contrast * 0.5f);
// blend maintexture and blendtexture using blendmap
Graphics.Blit(source,destination,material);
}
}
Shader:
Shader "Hidden/Composite" {
Properties {
_MainTex ("Main Texture (RGBA)", RECT) = "transparent" {}
_Tex1 ("Texture 1 (RGB)", RECT) = "white" {}
_Tex2 ("Texture 2 (RGB)", RECT) = "white" {}
_Tex3 ("Texture 2 (RGB)", RECT) = "transparent" {}
_Contrast ("Contrast", Range (0,0.5)) = 0.4
}
Category {
SubShader {
Pass {
ZTest Off
Cull Off
ZWrite Off
Fog { Mode Off }
CGPROGRAM
// profiles arbfp1
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
float _Contrast;
sampler2D _MainTex : register(s0);
sampler2D _Tex1 : register(s1);
sampler2D _Tex2 : register(s2);
sampler2D _Tex3 : register(s3);
struct v2f {
float4 pos : POSITION;
float2 uvMainTex : TEXCOORD0;
float2 uvTex1 : TEXCOORD1;
float2 uvTex2 : TEXCOORD2;
float2 uvTex3 : TEXCOORD3;
};
v2f vert( appdata_img v )
{
v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
o.uvMainTex = MultiplyUV( UNITY_MATRIX_TEXTURE0, v.texcoord);
o.uvTex1 = MultiplyUV( UNITY_MATRIX_TEXTURE1, v.texcoord);
o.uvTex2 = MultiplyUV( UNITY_MATRIX_TEXTURE2, v.texcoord);
o.uvTex3 = MultiplyUV( UNITY_MATRIX_TEXTURE3, v.texcoord);
return o;
}
float4 frag (v2f i) : COLOR
{
float4 col0 = tex2D(_Tex1, i.uvTex1); // Colour overlay (paints dark parts of model)
float4 col1 = tex2D(_Tex2, i.uvTex2); // Background colour (paints light parts of model)
float4 col2 = tex2D(_Tex3, i.uvTex3); // Highlights
float4 mainCol = tex2D(_MainTex, i.uvMainTex);
float lum = Luminance( mainCol.rgb ); // get _MainTex luminance
lum = smoothstep(0+_Contrast,1-_Contrast,lum); // set contrast
// float4 output = col0 * (1-lum) + col1 * lum ; // blend _Tex1 and _Tex2 by luminance of _MainTex
float4 output = col0 * (1-lum) + col1 * lum + col2; // All three textures
// float4 output = col0 + col1 * lum; // add second texture on top let's try that.
//float4 output = col0 * col1; // multiply (untested)
return output;
}
ENDCG
SetTexture [_MainTex] {}
SetTexture [_Tex1] {}
SetTexture [_Tex2] {}
SetTexture [_Tex3] {}
}
}
}
Fallback off
}
Edit: Would it be possible to create a shaders for such objects and define a specific `RenderType` tag (like "highlight") in them so I could use a replacement shader in the camera that renders those objects and leaves everything else black? How would I do that?
