Hello!
I’m trying to get an effect working in my game but I’m a bit at a loss of how to proceed next. The idea is that there are multiple cameras (really just points with a projection matrix) that are placed around the scene. Any fragment on a mesh that is visible from any camera is colored white, and any fragment not visible is colored black. The idea would be to use the resulting black and white texture as a mask to do some other cool shader effects.
The projections don’t move while the scene is rendering so it’s fine if it’s expensive if I only have to do it once. This would be ideal really, since I’d like to support as many projections as possible.
I have it working with a single camera (image attached), but I’m not sure how to extend it to more than one. I’ve looked into possibly passing in an array of matrices, but it doesn’t really seem to fit (although I may be doing it terribly wrong).
I’ve pasted my current shader below. The array only has a single camera in it at the moment.
Any ideas are appreciated! Thank you!
Shader "Custom/Projective Mapping" {
Properties {
_MainTex ("Texture", 2D) = "black" {}
_WhiteTex ("Texture", 2D) = "white" {}
_MatricesLength ("Matrices Length", Int) = 0
}
SubShader {
Pass {
CGPROGRAM
#pragma target 3.0
#pragma vertex MyVertexProgram
#pragma fragment MyFragmentProgram
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _WhiteTex;
uniform float4x4 _ProjectionMatrices[100];
uniform float4 _CameraPositions[100];
uniform int _MatricesLength = 0;
struct VertexData {
float4 position : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct Interpolators {
float4 position : SV_POSITION;
float3 normal : TEXCOORD0;
float2 texCoord : TEXCOORD1;
float4 projCoords : TEXCOORD2;
float4 worldPos : TEXCOORD3;
};
bool inRange(float2 uv) {
return uv.x >= -1 && uv.y >= -1 && uv.x <= 1 && uv.y <= 1;
}
Interpolators MyVertexProgram(VertexData v) {
Interpolators i;
i.normal = UnityObjectToWorldNormal(v.normal);
i.texCoord = v.uv;
i.worldPos = mul(unity_ObjectToWorld, v.position);
i.projCoords = mul(_ProjectionMatrices[0], v.position);
i.position = UnityObjectToClipPos(v.position.xyz);
return i;
}
float4 MyFragmentProgram(Interpolators i) : SV_TARGET {
float2 finalCoords = i.projCoords.xy / i.projCoords.w;
float4 vTexColor = tex2D(_MainTex, i.texCoord);
float4 vProjTexColor = tex2D(_WhiteTex, finalCoords);
i.normal = normalize(i.normal);
float3 viewDir = normalize(_CameraPositions[0] - i.worldPos);
if (dot(viewDir, i.normal) < 0) {
return float4(0,0,0,0);
}
if (i.projCoords.z > 0.0)
{
if(inRange(finalCoords)) {
return saturate(vTexColor + vProjTexColor);
}
return float4(0,0,0,0);
}
return float4(0,0,0,0);
}
ENDCG
}
}
}
