Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

[SOLVED] Project caustics texture from light direction

Discussion in 'Shaders' started by flogel, Aug 24, 2019.

  1. flogel

    flogel

    Joined:
    Aug 10, 2018
    Posts:
    109
    I basically have a caustics texture that i want to project coming from the light direction of my main directional light. Planar Mapping should be the solution to this, for example using just this line of code to project it from the xy plane of the world works pretty straight forward.
    Code (CSharp):
    1. fixed caustics = tex2D(_CausticsTex, IN.worldPos.xy);
    I thought of replacing the world position with _WorldSpaceLightPos0.xy, which should be the light direction vectors, but it just results in a glitchy color change. Does somebody has an idea how to solve this?
     
  2. tmcthee

    tmcthee

    Joined:
    Mar 8, 2013
    Posts:
    82
    Could you create the correct UVs in your graphics package? Maya, blender whatever?
     
    flogel likes this.
  3. mouurusai

    mouurusai

    Joined:
    Dec 2, 2011
    Posts:
    341
    Why you not use light cookie?
    I think you can use "unity_WorldToLight" matrix to project texture coords.
     
    Last edited: Aug 24, 2019
    flogel likes this.
  4. flogel

    flogel

    Joined:
    Aug 10, 2018
    Posts:
    109
    That's not possible, because it should be a seamless projection across the objects, ignoring their original uvs.

    I also thought about it, but for example, i cant mask a light cookie to under beneath a give surface, in my case, the water surface. (Atleast i don't know any way how) Also I'm nor sure how light cookies play with batching and so on.

    That's why i want to have the caustics on each object themself and just blend it in based on an height number from the watersurface. And the light direction as projection base would be perfect for giving it directionality.
     
  5. flogel

    flogel

    Joined:
    Aug 10, 2018
    Posts:
    109
    Ok, so i tried around with unity_WorldToLight and it goes into the right direction, but still has two errors- So this is the code im using now:
    Code (CSharp):
    1. float2 lightSpaceUVs = mul(unity_WorldToLight , float4(IN.worldPos, 1)).xy;
    First, it seems to work ok, but when i look with my camera from a specific angle on it, theres some glitching happening? I noticed this in general with light pos stuff-

    And secondly, theres some weird stuff with the definiton of unity_WorldToLight. I need to define the float4x4 unity_WorldToLight for it to be declared, because else he wouldnt find the matrix. Then he says tho, that its a redefiniton. Now when i add #inculde "Autolight.cginc", where this is supposed to be and i delete the redef in my shader, he just can't find it anymore-

    (Also this only seems to work in deferred, as in forward, the texture doesn't get moved at all-)
     
    Last edited: Aug 27, 2019
  6. mouurusai

    mouurusai

    Joined:
    Dec 2, 2011
    Posts:
    341
    I was try use that matrix, no luck, I have no clue how to use it without cookie.
    Pass worldToLocalMatrix from script, it's do the job if you have only one light source.
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [ExecuteInEditMode]
    4. public class SetLightMatrix : MonoBehaviour
    5. {
    6.     void Update()
    7.     {
    8.         Matrix4x4 mat = transform.worldToLocalMatrix;
    9.         Shader.SetGlobalMatrix("PrjMatrix", mat);
    10.     }
    11. }
     
    flogel likes this.
  7. flogel

    flogel

    Joined:
    Aug 10, 2018
    Posts:
    109
    @mouurusai Works like a charm! Used it for this caustic effect of mine ouo b

    Caustics_2_Screenshot.png
     
  8. GameDevCouple

    GameDevCouple

    Joined:
    Oct 5, 2013
    Posts:
    2,473
    Flogel can you give a bit of rundown on how to get caustics to be applied to multiple materials but look like the same caustics?

    Right now I have a caustics shader working and it looks lovely except that each object has its own caustics. Any help you can provide will really help me, I have been pulling my hair out for a few days and you seem best placed to answer this!
     
    flogel likes this.
  9. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    5,256
    Probably use world coordinate
     
    flogel likes this.
  10. GameDevCouple

    GameDevCouple

    Joined:
    Oct 5, 2013
    Posts:
    2,473
    Can you elaborate a bit on that? Ive only been learning shaders for about 18 months so I am still not the best!

    Wouldnt I also need to use the depth buffer to some degree?

    Anyone that can shed a bit more light on this I will be very happy!

    Alternatively I can make a new thread if anyone thinks thats pertinent

    @flogel any help you can provide will be greatly appreciated. I will repay you in kind words and virtual hugs!
     
    flogel likes this.
  11. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    5,256
    Well basically if you want to have the caustic being coherent to the world coordinate (ie seamless between multiple object) you must project onto that set of coordinate, if each object have different caustic references, but coherent to themselves, so you probably is in object space. If the caustics move with the object, then you are in object space. Just find the part that use coordinate and replace with world space, it's not specific to shader, it's just teh basic logic.

    Try to find shadow casting algo lik in cat like coding tutorial and look at teh part where the read the texture.
     
    GameDevCouple and flogel like this.
  12. flogel

    flogel

    Joined:
    Aug 10, 2018
    Posts:
    109
    Sweet! Glad that's working for you atleast! About the coherent look across objects, @neoshaman is quite right regarding the worldcoordinates.

    It's actually quite simple to atleast get some world coordinate textures going, it gets a bit more complicated when adding in the lightdirection though! Does the light direction stuff already works for you? Would be awesome if you could share your code her!

    For example you can just use the worldpos.xz as the UV coordinates of a texture and already have a texture projected from the top onto every object! You can do cool stuff with that alone already! (Isn't regarding your problem tho, just a general hint)
     
    GameDevCouple likes this.
  13. GameDevCouple

    GameDevCouple

    Joined:
    Oct 5, 2013
    Posts:
    2,473
    So I was following the alan zucconi tutorial that I am pretty sure is based on a tweet of yours, and ended up with the following:

    Code (CSharp):
    1.  
    2. // Caustics UV
    3.                     fixed2 uv = IN.uv_MainTex * _Caustics1_ST.xy + _Caustics1_ST.zw;
    4.                     uv += _Caustics1_Speed * _Time.y;
    5.                    
    6.                     // Sampling
    7.                    
    8.                       // RGB split
    9.                     fixed s = _SplitRGB;
    10.                     fixed r = tex2D(_CausticsTex, uv + fixed2(+s, +s)).r;
    11.                     fixed g = tex2D(_CausticsTex, uv + fixed2(+s, -s)).g;
    12.                     fixed b = tex2D(_CausticsTex, uv + fixed2(-s, -s)).b;
    13.                    
    14.                     fixed3 caustics1 = fixed3(r, g, b);
    15.            
    16.                     // Caustics 2 sampling
    17.                     uv = IN.uv_MainTex * _Caustics2_ST.xy + _Caustics2_ST.zw;
    18.                     uv += _Caustics2_Speed * _Time.y;
    19.                
    20.                     // Sampling
    21.                      s = _SplitRGB;
    22.                      r = tex2D(_CausticsTex, uv + fixed2(+s, +s)).r;
    23.                      g = tex2D(_CausticsTex, uv + fixed2(+s, -s)).g;
    24.                      b = tex2D(_CausticsTex, uv + fixed2(-s, -s)).b;
    25.                    
    26.                     fixed3 caustics2 = fixed3(r, g, b);
    27.          
    28.                    
    29.                     // Blend
    30.                     o.Albedo.rgb += min(caustics1, caustics2) * _CausticsStrength;
    It samples twice and blends between and the effect is working great, but as far as I can see its seperate per object right now.

    So based on what you were saying about worldPos.xz, would I put that in the

    Code (CSharp):
    1.             fixed r = tex2D(_CausticsTex, uv + fixed2(+s, +s)).r;
    2.                     fixed g = tex2D(_CausticsTex, uv + fixed2(+s, -s)).g;
    3.                     fixed b = tex2D(_CausticsTex, uv + fixed2(-s, -s)).b;
    bit in the place of the uv co-ordinates (keeping the +s -s bit as thats for the RGB split effect)?

    Also I noticed you said worldPos.xz but in the original comment at the top of this thread you used xy, just checking which I should be using?

    Thanks for getting back so fast :)
     
    flogel likes this.
  14. flogel

    flogel

    Joined:
    Aug 10, 2018
    Posts:
    109
    Yes, exactly! This should now be in world space from the top (i think-)

    .xz are the coordinates when you want to project it from top, while .xy are from the side in world space. I'm can't exactly remember why I used .xy specifically, but i probably worked this way with the lightmatrix in combination. Using the world coordinates only will give you a top or side view in worldspace. (That's why the lightmatrix is super helpful, since it projects the same worldspace coordinates from the sun direction)

    I hope this clears the whole thing up a bit!
     
    GameDevCouple likes this.
  15. GameDevCouple

    GameDevCouple

    Joined:
    Oct 5, 2013
    Posts:
    2,473
    Okay fantastic, thanks so much that really helps a lot :) Will give this a go when I get home from work :) Thanks again!
     
  16. flogel

    flogel

    Joined:
    Aug 10, 2018
    Posts:
    109
    Half a year later now and I found out, that you can actually use the built-in unity_WorldToShadow[0] Matrix, instead of making an extra script, that sets the matrix of your main directional light global. Just makes things easier~
     
unityunity