How, given that I want to use surface shaders (the answer can be, just use fragment and vertex shaders, you know how to use those!), does one convert from a vertex’s worldPos (given by the input structure to the surface shader) to the same position in the “screen space” of a random camera (not the main camera, so using the input structure’s screenPos will not work).
A little background. My scene has 2 cameras. In a shader for the second camera, I want to find the position of the given vertex in the first camera’s “screen”. So, analogous to the “screenPos” of that vertex for the first camera.
I’m currently passing a matrix into the structure via a script. Each piece of geometry in my little scene has this script.
using UnityEngine;
using System.Collections;
public class SetLightVPMatrixInMaterial : MonoBehaviour {
public Camera lightCamera;
// Matrix used to go from [-1, 1] to [0, 1] in each axis
private Matrix4x4 bias;
// Use this for initialization
void Start () {
bias = new Matrix4x4();
bias.SetColumn(0, new Vector4(0.5f, 0.0f, 0.0f, 0.0f));
bias.SetColumn(1, new Vector4(0.0f, 0.5f, 0.0f, 0.0f));
bias.SetColumn(2, new Vector4(0.0f, 0.0f, 0.5f, 0.0f));
bias.SetColumn(3, new Vector4(0.5f, 0.5f, 0.5f, 1.0f));
}
// Update is called once per frame
void Update () {
// Fetch the light camera's modelviewprojection matrix
if ( lightCamera )
{
// Moving from unit cube [-1,1] to [0,1]
Matrix4x4 vpMatrix = bias * lightCamera.projectionMatrix * lightCamera.worldToCameraMatrix;
// Set the viewProjection matrix to a value in the material
renderer.material.SetMatrix("_LightViewProjectionMatrix", vpMatrix);
}
}
}
In the shader I do the following
struct Input {
// Analogous to the in attributes in GLSL shaders
float3 worldPos;
};
void surf (Input IN, inout SurfaceOutput o) {
// Convert the worldPos to the light's coordinate system to compute the UV coordinates of
// the given vertex for the light's render texture
float4 lightScreenPosW = mul(_LightViewProjectionMatrix, float4(IN.worldPos, 1));
float3 lightScreenPos = lightScreenPosW.xyz / lightScreenPosW.w;
This code seemingly gives me something close. I believe the lightScreenPos.x and y are what I want them to be, but I don’t think that lightScreenPos.z is what I expect. I want that value to be the value of the current vertex being run through the shader’s z position as being viewed by the camera that I pass into the script above.
I read something along the lines that using camera.worldToCameraMatrix has some issues with z coordinates, but I’ve tried fiddling and haven’t been able to fix too much.
So how to I go from a worldPos to a camera’s screen space that isn’t the current camera?