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 - project to back faces problem

Discussion in 'Editor & General Support' started by ytrewq, Sep 11, 2012.

  1. ytrewq

    ytrewq

    Joined:
    Aug 5, 2012
    Posts:
    42
    (Unity 3.5.5) Then using projector, it projects the mask to back side of the object, wich is not visible from the point of projector. This applyes both to custom made projectors and standard blob shadow projector, wich comes with Unity.

    It's sad, because baked and may be manually edited projective shadow through the semitransparent or colored glass looks great, and this effect most probably is not achivable by real time shadows even in Unity Pro.

    Is there some way to solve backface projection problem? It's seems that where is no simple solution, may be a custom shader is requred.
     
  2. ytrewq

    ytrewq

    Joined:
    Aug 5, 2012
    Posts:
    42
    In these two images the problem example with standard blob shadow, projected from above the sphere. The shadow is on both upper and lower side of the sphere. Does anyone know how to fix this?
     

    Attached Files:

    Last edited: Sep 14, 2012
  3. musiko

    musiko

    Joined:
    Mar 5, 2013
    Posts:
    4
    Apologize for bumping an old topic, but I am having the same issues and could not find the solution in the web/forum. Would anyone please help? Thanks in advance!
     
  4. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    924
    I'm interested in knowing if there's a solution as well.
    Did you solve the issue somehow in the meantime?
     
  5. thehen2

    thehen2

    Joined:
    Apr 1, 2014
    Posts:
    54
    +1 I need a solution for this.
     
  6. Quaker_SDR

    Quaker_SDR

    Joined:
    Jun 21, 2013
    Posts:
    39
    any solutions ???
     
  7. jlstevo

    jlstevo

    Joined:
    Aug 30, 2013
    Posts:
    2
    I am also currently looking for a solution to this, I have used a falloff texture as described here: http://docs.unity3d.com/Manual/class-Projector.html. I have also played with the settings "Alpha from Greyscale", "Generate Mip Maps", "Border Mip Maps" and "Wrap Mode" with no avail.
     
  8. bitbotlabs

    bitbotlabs

    Joined:
    Jul 27, 2015
    Posts:
    2
    I modified the projector multiply shader's vertex program to set the alpha of the shadow based on the vertex's normal.

    o.uvFalloff.a = max(0,sign(v.normal.y - 0.9));

    In my case, i didnt want to see the shadow on anything that doesn't have a normal.y = 1 (straight up). You could do something similar to remove the shadow from anything with a negative normal.y.
     
  9. monotoan

    monotoan

    Joined:
    Feb 13, 2015
    Posts:
    11
    Here's a slightly more flexible version of the @bitbotlabs solution above.

    This finds the cosine of the angle between the forward vector of the projector (i.e. the light direction) and the normal of any surface the projector is hitting. (The dot product of two vectors is the standard way to find for this.) This will return 1 when the two vectors are parallel, 0 when they're perpendicular and -1 when they are pointing in exactly opposite directions. So when this value is less than zero, it means the surface is facing toward the projector and should receive the shadow.

    I multiply that value by -1 and clamp it to convert to a zero-to-one alpha range where surfaces with normals pointing directly toward the projector will return one, then smoothly reduce until any point with a normal pointing perpendicular to or away from the projector will return zero.

    Code (CSharp):
    1. o.uvFalloff.a = clamp(-1*dot(normalize(_ProjectorDir), v.normal),0,1);
    Note that "_ProjectorDir" is a variable I declared in the shader, e.g.:

    Code (CSharp):
    1. fixed3 _ProjectorDir;
    I then pass this value in from a script on my projector using something like:

    Code (CSharp):
    1. material.SetVector("_ProjectorDir",transform.forward);
     
    Last edited: Mar 3, 2017
  10. GamesMadeRight

    GamesMadeRight

    Joined:
    Apr 18, 2017
    Posts:
    12
    Not to revive a dead thread... but this actually helped me a ton, I still had to wrestle the shader in order to get it to work, with the help of an engineer.

    This is a combo of the solutions above, I still have a component on my projector that sets the vector on update.

    I also took out the color and the falloff texture bc they didnt really make much sense to me :).


    Here is the final shader we came up with:

    Code (CSharp):
    1. 'unity_ProjectorClip'
    2.  
    3. Shader "Projector/Light" {
    4.     Properties {
    5.         _ShadowTex ("Cookie", 2D) = "" {}
    6.         _ProjectorDir ("_ProjectorDir", Vector) = (0,0,0,0)
    7.     }
    8.  
    9.     Subshader {
    10.         Tags {"Queue"="Transparent"}
    11.         Pass {
    12.             ZWrite Off
    13.             ColorMask RGB
    14.             Blend OneMinusDstColor One
    15.             Offset -1, -1
    16.  
    17.             CGPROGRAM
    18.             #pragma vertex vert
    19.             #pragma fragment frag
    20.             #pragma multi_compile_fog
    21.             #include "UnityCG.cginc"
    22.        
    23.             struct v2f {
    24.                 float4 uvShadow : TEXCOORD0;
    25.                 float4 uvFalloff : TEXCOORD1;
    26.                 UNITY_FOG_COORDS(2)
    27.                 float4 pos : SV_POSITION;
    28.             };
    29.  
    30.             struct VertexInput {
    31.                 float4 vertex : POSITION;
    32.                 fixed3 normal : NORMAL;
    33.             };
    34.        
    35.             float4x4 unity_Projector;
    36.             float4x4 unity_ProjectorClip;
    37.             fixed4 _ProjectorDir;
    38.  
    39.             v2f vert (VertexInput v)
    40.             {
    41.                 v2f o;
    42.                 o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    43.                 o.uvShadow = mul (unity_Projector, v.vertex);
    44.                 o.uvFalloff = mul (unity_ProjectorClip, v.vertex);
    45.                 UNITY_TRANSFER_FOG(o,o.pos);
    46.                 o.uvFalloff.a = clamp(-1*dot(normalize(_ProjectorDir), v.normal),0,1);
    47.  
    48.                 return o;
    49.             }
    50.        
    51.             fixed4 _Color;
    52.             sampler2D _ShadowTex;
    53.        
    54.             fixed4 frag (v2f i) : SV_Target
    55.             {
    56.                 fixed4 texS = tex2Dproj (_ShadowTex, UNITY_PROJ_COORD(i.uvShadow));
    57.                 fixed4 res = texS * ceil(abs(i.uvFalloff.a)) ;
    58.            
    59.                 return res;
    60.             }
    61.             ENDCG
    62.         }
    63.     }
    64. }
    65.  
     
  11. SashaFutureColossal

    SashaFutureColossal

    Joined:
    Oct 22, 2016
    Posts:
    1
    ^ Thanks a lot for posting this solution. I was able to implement, and I can see that the backfacing areas of my mesh had their alphas lowered down to zero via this line: o.uvFalloff.a = clamp(-1*dot(normalize(_ProjectorDir), v.normal),0,1);

    However instead of changing the alpha of those backfaces, i would like to just have the projector ignore those faces (not render my projection to them) but maintain their alpha. Does that make sense?

    I don't understand shader code enough to implement that change so I'm not sure how to achieve this. I would really appreciate any suggestions! Thanks
     
  12. Mehrdad995

    Mehrdad995

    Joined:
    Jul 17, 2013
    Posts:
    46
    I don't have enough knowledge as well but I think it must be something like this

    instead of
    Code (CSharp):
    1. o.uvFalloff.a = clamp(-1*dot(normalize(_ProjectorDir), v.normal),0,1);
    use this
    Code (CSharp):
    1. o.uvFalloff.rgb *= clamp(-1*dot(normalize(_ProjectorDir), v.normal),0,1);
    this must make the projected texture black on back-facing area
    but if you mean no texture on that part at all then its the same as making the alpha to zero like the solution you wrote cuz zero alpha means nothing to show.
    however I havn't tested this and I can't guaranty if this gonna work or not.
     
    Last edited: Mar 18, 2018
  13. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,513
    As _ProjectorDir is in world space, so will v.normal have to be converted to world space:

    Code (CSharp):
    1. float3 worldNormal = mul(unity_ObjectToWorld, float4(v.normal, 0.0)).xyz;
    2.                 o.uvFalloff.a = clamp(-dot(_ProjectorDir, worldNormal), 0, 1);
     
  14. unity_IFkq1QrcZifEAg

    unity_IFkq1QrcZifEAg

    Joined:
    Jan 9, 2019
    Posts:
    5
    Here's a shader i sort of poorly hacked together from this example and several others (like this https://forum.unity.com/threads/projector-shader-with-angle-limitation.406876/ ) and includes a masking ability

    I made it so that the cutoff angle was adjustable, but it doesn't really make sense to me (and it might not be very efficient)
    Code (CSharp):
    1. // Upgrade NOTE: replaced '_Projector' with 'unity_Projector'
    2. // Upgrade NOTE: replaced '_ProjectorClip' with 'unity_ProjectorClip'
    3. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    4.  
    5. // Upgrade NOTE: replaced '_Projector' with 'unity_Projector'
    6.  
    7. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    8.  
    9. // Upgrade NOTE: replaced '_Projector' with 'unity_Projector'
    10. // Upgrade NOTE: replaced '_ProjectorClip' with 'unity_ProjectorClip'
    11.  
    12. Shader "AdditiveMaskNoBack"
    13.     {
    14.         Properties
    15.         {
    16.             _Color("Main Color", Color) = (1,1,1,1)
    17.             _ShadowTex("Cookie", 2D) = "" {}
    18.         _MaskTex("Mask", 2D) = "gray" {}
    19.             _FalloffTex("FallOff", 2D) = "" {}
    20.             _AngleLimit("Angle Limit (rad)", Float) = .9
    21.         }
    22.  
    23.             Subshader
    24.             {
    25.                 Tags {"Queue" = "Transparent"}
    26.                 Pass
    27.                 {
    28.                     ZWrite Off
    29.                     AlphaTest Greater 0
    30.                     ColorMask RGB
    31.                     Blend SrcAlpha OneMinusSrcAlpha
    32.                     Offset -1, -1
    33.  
    34.                     CGPROGRAM
    35.                     #pragma vertex vert
    36.                     #pragma fragment frag
    37.                     #pragma multi_compile_fog
    38.                     #include "UnityCG.cginc"
    39.  
    40.                     struct v2f {
    41.                         float4 uvShadow : TEXCOORD0;
    42.                         float4 uvMask : TEXCOORD1;
    43.                         float4 uvFalloff : TEXCOORD2;
    44.                         half projAngle : TEXCOORD3;
    45.                         UNITY_FOG_COORDS(2)
    46.                         float4 pos : SV_POSITION;
    47.                     };
    48.  
    49.             struct vertexInput
    50.             {
    51.                 float4 vertex : POSITION;
    52.                 float4 texcoord : TEXCOORD0;
    53.             };
    54.  
    55.                     float4x4 unity_Projector;
    56.                     float4x4 unity_ProjectorClip;
    57.                     half3 projNormal;
    58.  
    59.                     inline half angleBetween(half3 vector1, half3 vector2)
    60.                     {
    61.                         return acos(dot(vector1, vector2) / (length(vector1) * length(vector2)));
    62.                     }
    63.  
    64.                     v2f vert(float4 vertex : POSITION, float3 normal : NORMAL, float4 texcoord : TEXCOORD0)
    65.                     {
    66.                         v2f o;
    67.                         o.pos = UnityObjectToClipPos(vertex);
    68.                         o.uvShadow = mul(unity_Projector, vertex);
    69.                         o.uvMask = mul(unity_Projector, vertex);
    70.                         o.uvFalloff = mul(unity_ProjectorClip, vertex);
    71.                         projNormal = mul(unity_Projector, normal);
    72.                         o.projAngle = abs(angleBetween(half3(0,0,-1), projNormal));
    73.                         UNITY_TRANSFER_FOG(o,o.pos);
    74.                         return o;
    75.                     }
    76.  
    77.                     fixed4 _Color;
    78.                     sampler2D _ShadowTex;
    79.                     float4 _ShadowTex_ST;
    80.                     sampler2D _MaskTex;
    81.                     sampler2D _FalloffTex;
    82.                     half _AngleLimit;
    83.  
    84.                     fixed4 frag(v2f i) : SV_Target
    85.                     {
    86.                         if (i.projAngle <_AngleLimit) //||1)
    87.                         {
    88.                             fixed4 texS = tex2Dproj(_ShadowTex, UNITY_PROJ_COORD(i.uvShadow));
    89.                             fixed4 mask = tex2Dproj(_MaskTex, UNITY_PROJ_COORD(i.uvMask));
    90.                             texS.rgba *= _Color.rgba;
    91.                             texS *= mask.a;
    92.  
    93.                             fixed4 texF = tex2Dproj(_FalloffTex, UNITY_PROJ_COORD(i.uvFalloff));
    94.                             //fixed4 res = texS * texF.a;
    95.                                 //i.projAngle;
    96.  
    97.                             //fixed4 res = texS * texF.a * step(-_AngleLimit, i.projAngle);
    98.                             fixed4 res = texS * texF.a* ceil(abs(i.uvFalloff.a));
    99.                             //
    100.                             UNITY_APPLY_FOG_COLOR(i.fogCoord, res, fixed4(0,0,0,0));
    101.                             return res;
    102.                         }
    103.                         else
    104.                         {
    105.                             //return fixed4(.5, .5, 1, 1); positive purple alpha for debugging
    106.                             return fixed4(.5, .5, 1, 0);
    107.  
    108.                         }
    109.                     }
    110.                     ENDCG
    111.                 }
    112.             }
    113.     }
     
  15. agentHein

    agentHein

    Joined:
    Apr 16, 2019
    Posts:
    1
    If you want the multiply shadow and get rid of white background on texture,leave the alpha alone and clamp the uvshadow instead of falloff.a,this way white colors on otherside become invisible by multiply effect.
    Code (CSharp):
    1. o.uvShadow *= clamp(-1*dot(normalize(_ProjectorDir),v.normal),0,1);
     
  16. KayH

    KayH

    Joined:
    Jan 6, 2017
    Posts:
    107
    I had the same problem and found this thread looking for a fix.

    I used monotoan's solution (as well as Partel-Lang's worldNormal) but I replaced this line:

    Code (CSharp):
    1. o.uvFalloff.a = clamp(-1*dot(normalize(_ProjectorDir), v.normal),0,1);
    with this one:

    Code (CSharp):
    1. o.uvFalloff.a *= max(0, sign(-dot(_ProjectorDir, worldNormal)));
    Since we only care about whether the surface is facing away from the light source, there is no need to normalize _ProjectorDir. We do want to avoid to get a range between 0 and 1 though because that would result in the shadow becoming lighter on angled surfaces. So I use sign to get full opacity for everything larger than 0. And max to avoid negative alpha.

    Thanks for sharing your solutions.
     
    Last edited: Sep 7, 2020
  17. IllidanS4

    IllidanS4

    Joined:
    Jul 23, 2013
    Posts:
    7
    No need for an extra variable; Unity gives you all the necessary tools already:
    Code (CSharp):
    1. -normalize(mul((float3x3)unity_Projector, v.normal)).z
    The 4th row/column in a matrix is only used for transforming positions, but if we are dealing with a vector, just cast the matrix to
    float3x3
    and it will remain a vector in the same space. The rest will obtain the negated size of the vector in the projection forward direction ‒ 1 if directly opposite the projector, -1 for a parallel back face, and 0 if perpendicular.