Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Projector that Respects Shadows / Spotlight with Coloured Texture

Discussion in 'Shaders' started by MaxPalmer, Jul 19, 2016.

  1. MaxPalmer

    MaxPalmer

    Joined:
    Mar 9, 2013
    Posts:
    27
    I have a requirement to project a rectangular coloured texture (e.g. a photo) onto a scene in a manner that is similar to a projector, but with additional requirements.

    The setup.
    * Given a texture, source location, horizontal/vertical FOV and direction/orientation, project the image so that it colors the surface of any objects in the scene that are 'lit' by the projected image. This is very similar to a projector, but with additional requirements:

    [1] Objects will occlude the projected texture, similar to a shadow casting spotlight, so that the area in shadow does not receive the projected image.
    [2] Only the area within the FOV will receive the projected image .
    [3] The back faces of objects will not be affected by the texture.

    The approaches I am trying are:

    [1] Using a script, update the textures of all objects lit by the scene using raycasting. This works, but has a high setup cost, both in terms of updating the textures and ensuring that the illuminated surfaces are set up correctly with unique UV areas. I've also had to do quite a bit of fiddling to minimise the number of rays that are cast and to prevent gaps in the projected texture. The other downside is that the projected image is affected by the resolution of the texture on the object.

    [2] Try to implement a colored spotlight with an appropriate rectangular cookie.
    i.e. write a shader so that any pixel that is lit by the light takes the appropriate colour from the texture, based on the light origin / pixel vector. I have some ideas about how to approach this, but being new to shaders am finding this difficult. This objects lit by the light should cast shadows.

    [3] Change the projector shader to take account of shadows and the cookie extents.

    [4] Write this as a post processed effect.

    One thing that I'm finding pretty confusing is the relationship between shadows, (individual) lights and shaders. Lights clearly affect any object that has a material that takes account of them. I presume I need to write a shader, that is applied to a material that is then applied to all objects I want to be affected? How do I ensure that I am accessing the relevant (spot)light source and not other lights? Can I have more than one of these projected light sources in my scene? If so, how many and how might it affect how I set up the lights?

    Can anyone offer advice or provide sample shader code that could do this?
     
  2. MaxPalmer

    MaxPalmer

    Joined:
    Mar 9, 2013
    Posts:
    27
    upload_2016-7-19_12-50-54.png

    Example of approach #1. Grey sphere on the right is the origin of the image. I've placed a billboard and lines projecting from this origin to illustrate the FOV and image. Textures on objects have been processed to take the projected colour information. NB there is a cube at the centre that is not set up correctly.

    A spotlight with a cookie illuminates the area I want to affect and respects shadows, but how can I set up a shader to look up the correct colour?

    upload_2016-7-19_12-55-53.png
     
  3. MaxPalmer

    MaxPalmer

    Joined:
    Mar 9, 2013
    Posts:
    27
    So I am making good progress in some areas. I now have a spotlight that can project the image onto my mesh a bit like a projector and the backs of objects are not coloured by the light.

    upload_2016-7-20_16-52-30.png


    I now want to prevent the texture being displayed in areas that are in shadow from the point of view of my spotlight.

    I've spent most of this afternoon trying to access the shadow map for the spotlight, but with no success. Can anyone help?
    I'm trying to use this construct, which seems the most promising (and have tried so many different approaches based on web searches with no luck).

    UNITY_SAMPLE_SHADOW(_ShadowMapTexture, float3(input._ShadowCoord.xy, distance));

    A few more specific questions might help:

    [1] When people talk about accessing a 'shadow map', is this a specific texture array for a specific light or something else? NB I presume I want to access the shadow map for my spotlight and this is what most examples are doing when they refer to accessing a shadow map.
    [2] How do I know whether there is anything actually in the shadow map (_ShadowMapTexture)? It seems like it's empty to me. Can I dump this out or inspect it?
    [3] How do I set up the UV coordinates correctly for sampling the spotlight's shadow map?

    I have tried the following:
    In vertexOutput vert(vertexInput input)):

    output._ShadowCoord = mul(unity_World2Shadow[0], mul(_Object2World, input.vertex));

    Where:
    struct vertexOutput {
    float4 pos : SV_POSITION;
    float4 posWorld : TEXCOORD0;
    // position of the vertex (and fragment) in world space
    float4 posLight : TEXCOORD1;
    // position of the vertex (and fragment) in light space
    float3 normalDir : TEXCOORD2;
    // surface normal vector in world space

    unityShadowCoord4 _ShadowCoord: TEXCOORD3;
    };

    [4] Assuming I can get hold of my spotlight's shadow map, how do I know if a pixel is in shadow?

    I am passing the light to pixel distance value to the UNITY_SAMPLE_SHADOW macro. Is this correct?
    i.e.:

    UNITY_SAMPLE_SHADOW(_ShadowMapTexture, float3(input._ShadowCoord.xy, distance));

    It really feels like this should be possible. Can anyone help please?
     
    bariscigal likes this.
  4. MaxPalmer

    MaxPalmer

    Joined:
    Mar 9, 2013
    Posts:
    27
    Done it, I needed to use:

    UnitySampleShadowmap(input._ShadowCoord)


    upload_2016-7-20_17-14-27.png
     
    bariscigal and AlanMattano like this.
  5. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    This makes me as emotional as Cinema Paradiso.

    Looking first image and last image looks like it loose contrast and color intensity. probably because of the additional light source.
     
    Last edited: Jul 20, 2016
  6. MaxPalmer

    MaxPalmer

    Joined:
    Mar 9, 2013
    Posts:
    27
     
  7. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    Is a grate thing Max.
     
    Last edited: Jul 25, 2016