How to project a line over objects

Hi was wondering if anyone knows a efficient and mobile friendly way to project a line over objects like seen in the image

alt text


Probably not the most efficient but you could have a sequential series of raycasts down from the knife and where ever they hit, create a transparent red dot, if close enough together would look like a line.

You can do this with a decal shader, i.e. a shader that projects its texture onto what is behind the object. Make sure that your camera renders depth textures for this to work (this may already be the case but can be explicitly enabled via camera.depthTextureMode). Also note that this shader only works for perspective projection (but a similar one could be written for orthographic projection).

Shader "Unlit/Decal" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
    SubShader {
        Tags { "Queue"="Transparent" }
        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite Off

        Pass {
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct v2f {
                float4 vertex : SV_POSITION;
                float4 object : TEXCOORD0;
                float4 screen : TEXCOORD1;

            sampler2D _MainTex;
            sampler2D _CameraDepthTexture;

            v2f vert (float4 vertex : POSITION) {
                v2f o;
                o.object = vertex;
                o.vertex = UnityObjectToClipPos(vertex);
                o.screen = ComputeScreenPos(o.vertex);
                return o;
            float3 ReconstructWorldPos(float4 object, float4 screen) {
                float depth = LinearEyeDepth(tex2Dproj(_CameraDepthTexture, screen));
                float3 ray = WorldSpaceViewDir(object);
                ray /= dot(ray, normalize(UNITY_MATRIX_V[2].xyz));
                return _WorldSpaceCameraPos - ray * depth;

            fixed4 frag (v2f i) : SV_Target {
                float3 world = ReconstructWorldPos(i.object, i.screen);
                float4 object = mul(unity_WorldToObject, float4(world, 1));
                float2 uv = object.xz + 0.5;

                clip((1 - uv) * uv);

                return tex2D(_MainTex, uv);

Here is how it works:

  1. Use _CameraDepthTexture to get the depth of the pixel (kinda like its distance to the camera but not quite)
  2. Multiply this depth by the view direction and add that to the camera position to get the world position of the pixel
  3. Transform the world position to object space so that moving and rotating the object also affects the texture
  4. Use object space x and z coordinates as texture coordinates.

Example usage of decal shader