Search Unity

[SOLVED] Project caustics texture from light direction

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

  1. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    142
    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:
    119
    Could you create the correct UVs in your graphics package? Maya, blender whatever?
     
    flogelz likes this.
  3. mouurusai

    mouurusai

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

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    142
    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. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    142
    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:
    350
    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. }
     
    flogelz likes this.
  7. flogelz

    flogelz

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

    Caustics_2_Screenshot.png
     
  8. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,977
    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!
     
    flogelz likes this.
  9. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    Probably use world coordinate
     
    flogelz likes this.
  10. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,977
    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!
     
    flogelz likes this.
  11. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    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.
     
    MadeFromPolygons and flogelz like this.
  12. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    142
    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)
     
    MadeFromPolygons likes this.
  13. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,977
    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 :)
     
    flogelz likes this.
  14. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    142
    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!
     
    MadeFromPolygons likes this.
  15. MadeFromPolygons

    MadeFromPolygons

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

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    142
    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~
     
  17. MingZi_

    MingZi_

    Joined:
    Mar 6, 2019
    Posts:
    5
    Hi, flogel! This post helps me a lot, thanks.
    Unfortunately, "unity_WorldToLight" in Unity 2019.4.11f still has some trouble to use. But the method @mouurusai put forward works fun, and i get the correct result.
    As the method using "unity_WorldToShadow[0]", the caustics changes strangely while moving cam.
    Code (CSharp):
    1.  half2 uv = mul(unity_WorldToShadow[0], float4(i.worldPos, 1)).xy;
    Any wrong with this code?
    Thanks