Search Unity

Reveal texture only when light falls on it

Discussion in 'Shaders' started by Punksmurf, Jul 16, 2009.

  1. Punksmurf

    Punksmurf

    Joined:
    Jul 15, 2009
    Posts:
    12
    Hello,

    I posted a topic about this problem in the general support area, but as it was concluded that shaders would be the solution I will continue this here.

    The real world example I'm trying to accomplish is that something's writting with invisible, UV-sensitive ink, then one shines on it with an UV-lightsource and the ink lights up so the message can be read.

    Now, I've figured out I can light something only by one lightsource and leave it unaffected by others using layers, but it still shows up black if I do not point my flashlight at it. As no light doesn't mean something invisible, this is quite understandable, but having the secret message visible spoils the surprise somewhat.

    I have attached an image with a simple quick and dirty demonstration. The 'secret message' is for now textured to a plane in a layer 'UV effect'; the culling of all lights is set to anything but 'UV effect' (so they don't effect the texture) except of course the spotlight.
    The text is black, the spots (top left, bottom right) are white. The big blob is gray and the three medium sized spots are red, green and blue from bottom to top. The rest is transparent.

    This sample uses the shader I've written. So, yes, I've looked into shaders a bit, but I'm not getting much farther than this.

    This image uses the following shader:
    Code (csharp):
    1. Shader "Self/Testshader"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.     }
    7.    
    8.     Subshader
    9.     {
    10.         Tags { "Queue" = "Transparent" }
    11.         Pass
    12.         {
    13.             Lighting On
    14.             Blend SrcAlpha OneMinusSrcAlpha
    15.  
    16.             Material {
    17.                 Diffuse (1,1,1,1)
    18.             }    
    19.  
    20.             SetTexture [_MainTex] {
    21.                 Combine texture * primary, texture * primary
    22.             }
    23.         }
    24.    }
    25. }
    I've tried numerous options for the 'Combine' line. I hoped mainly that
    Code (csharp):
    1. Combine texture * primary, primary
    would set the transparency to the intensity of the light (the spotlight is the only light affecting this particular material). However, although the insensity varies, it doesn't do anything to the alpha layer.

    Also, this only had vertex shaders and I'd like it to work with pixel shaders. To do that, I'm guessing I would have to dive into CG-code or whatever it's called?

    I hope you can help me out! Thanks in advance for your replies.
     

    Attached Files:

  2. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Here's a shader that is sort of what you want that I had kicking around for some reason:
    Code (csharp):
    1. Shader "Lighting Only" {
    2.     Properties {
    3.         _Color ("Main Color", Color) = (1,1,1,1)
    4.         _MainTex ("Base (RGB)", 2D) = "white" {}
    5.     }
    6.    
    7.     SubShader {
    8.         Blend SrcAlpha One
    9.         ZWrite Off
    10.         Tags {Queue = Transparent}
    11.         ColorMask RGB
    12.         // Vertex lights
    13.         Pass {
    14.             Tags {"LightMode" = "Vertex"}
    15.             Lighting On
    16.             Material {
    17.                 Diffuse [_Color]
    18.             }
    19.             SetTexture [_MainTex] {
    20.                 constantColor [_Color]
    21.                 Combine texture * primary DOUBLE, texture * constant
    22.             }
    23.         }
    24.     }
    25.    
    26.     Fallback "VertexLit", 2
    27.    
    28. }
    It will ignore ambient light, and only show in places where it is lit. It doesn't do per-pixel lighting. That will require some Cg which I would do but I'm pretty busy at the moment. This shader should do to be getting on with, anyway.
     
    revenz likes this.
  3. Punksmurf

    Punksmurf

    Joined:
    Jul 15, 2009
    Posts:
    12
    Whoa, thanks. It seems to be the blending mode, if I change that to the same as yours it works. I don't get those quite yet (shaders are pretty new material to me), but this is worth investigating.

    Only thing is that there are strange white artefacts around the non-transparent parts of the texture (see attached image). I'm guessing this also has something to do with with the blending mode.

    However, for now, I have something to work with indeed. This will be doing very well for our purpose (a pitch for an adventure-ish webgame). When we win (there's no if :p) I'll dive deeper into it and see what I can do.

    Thanks for the help, it is much appreciated.
     

    Attached Files:

  4. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    The arguments to the Blend function are documented in the Shaderlab docs. There are some examples there of some basic blending setups.

    For a complete understanding of the coefficients, I recommend checking out the section on blending in chapter six of the Red Book. The syntax there is for OpenGL, but it maps exactly to the Blend function and keywords. It took me a few tries before I fully understood it, but it's worth understanding.

    As for the white artifacts in your image: if you're referring to the white fringe around the circles, it looks like the colour channel of your transparent pixels contains white. This problem can be exacerbated by mipmaps and bright lighting. To get rid of it, you need to solidify your colour channel. Flaming Pear's free Solidify filter for Photoshop is great for this job.
     
  5. Punksmurf

    Punksmurf

    Joined:
    Jul 15, 2009
    Posts:
    12
    I've read the docs here, but they are not particularly clear on anything but the most superficial information. Also, things are missing. For example, whilst checking out the sourcecode of the built-in shaders I came across several fucntions not covered in the manual.

    I will check out your link, it seems quite a bit more in depth. Thanks!

    Also, thanks for the hints on the borders. By the colour channels not being 'solid', do you mean that they somehow lack colour information?
    For example, I know Flash stores (ARGB) 0x88FF0000 internally as 0x88880000 which simplifies certain calculations, but it causes loss of resolution in colour depth (noticable when you set the alpha back to 0xFF). Or am I now rambling about something completely different?!

    Edit: based on what that plugin does, it seems that it is sort of related indeed. Need to have a layer mask for the transparency now, but the colours are full bright. It is somewhat better when using the PSD as a texture, but the major improvement seems to be exporting it to PNG. That's much better than just using the PSD, even without solifidication

    By the way, your shader seems to treat the intensity of the texture colour as transparency as well; black is fully transparent and gray shows up as translucent white. This is absolutely not of an issue to me, but I thought it worth pointing out.

    As it is almost 12am again, I'm going to call it a day now. Tomorrow's my free day, but I guess I'll be popping in sometime.
     
  6. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Ah, I should've mentioned that: the Shaderlab docs are incomplete and not very helpful to beginners. It's really important that you supplement them with the built-in shader source, this forum, and other relevant documentation on shaders and graphics programming.
    What happens is that when you save a photoshop document with implicit transparency (one that shows through the checkered background), Photoshop saves the alpha channel as your would expect. However, it stores a very strange set of values in the colour channel for transparent pixels. For a lot of applications, the colour of a fully transparent pixel doesn't matter. When you are filtering linearly, however, the result is that you go from a fully opaque colour that you defined to a fully transparent colour you didn't define. In-between those two texels, the filtering ramp will show that undefined colour as it gets closer to fully transparent.

    Using the Solidify filter and an explicit alpha channel in Photoshop allows you to define the colour of every pixel, even the transparent ones. This means that the edges will be fading from an opaque colour that you defined to the same colour, but transparent.

    As you've discovered, Photoshop does something similar to the Solidify filter when it saves PNG files. While this effect will work at the highest mip level, it's not as reliable at lower ones because the colours it chooses become stranger as it gets further from defined pixels. The Solidify filter is the best bet for mip-mapped textures.

    This is intentional, as the shader was designed to act like a regular diffuse shader, but without an ambient pass. This means that it adds the contribution of the lighting equation to whatever is already in that pixel on-screen:

    Code (csharp):
    1. output = lambertianResult * diffuseTexture * tintColour * 2.0
    If the result of this equation is close to zero (black), you won't see any effect.

    What you might be after, if you want to see black, is to use the incoming light to define alpha as well as colour, and then use regular alpha blending (Blend SrcAlpha OneMinusSrcAlpha). Interestingly, you should be able to change how much a light reveals one of these textures by changing its alpha contribution, a value which is ignored by most shaders.
     
  7. Punksmurf

    Punksmurf

    Joined:
    Jul 15, 2009
    Posts:
    12
    Thanks for all your explanations, they are very helpful. I haven't had much time to put it into practice though, but I'm hoping I can soon.

    Edit/off topic: well, our demo's out there now. Our client will be pitching it to her client tomorrow. We've got good hopes, and we will know more tomorrow, albeit not likely a definite go or no go.
     
  8. cry0

    cry0

    Joined:
    Apr 9, 2009
    Posts:
    71
    First of all let me thank you all for both the topic (had the same question) and for the solution (life saver) :)

    However I wanted to pose a different question that may also be of interest for Punksmurf (BTW... good luck for the pitch):

    What if instead of the "UV light" I wanted to use "fingerprint dust". What would happens is that not only one would need the same behaviour as before, but it shoud become permanent: with each pass a per-pixel transition would be required to permanently assign a new texture to the object.

    Any clues?

    Many thanks in advance
     
  9. damienthorn

    damienthorn

    Joined:
    Oct 1, 2009
    Posts:
    28
    I'm trying to apply Brauer's shader "Lighting Only", but I'm having no success.
    In my scene there is one plane with the "secret" texture that uses the shader, but when I approach the spotlight nothing appears...
    Any hints?

    EDIT: Issue resolved...
     
  10. Muke24

    Muke24

    Joined:
    Nov 6, 2019
    Posts:
    7
    I know this thread is like 10 years old, but I have found nothing else about it or similar. How could I make it so shadows effect the transparency. So if I was to have a point light and place a cube with in front of it, it then will create a shadow over the object with the shader. But that object doesn't receive those shadows and acts as if the cube was not there. I will link some pictures for an example of what I mean.
    LightExampleNoShadow.PNG LightExampleNoShadow1.PNG
     
  11. manundi

    manundi

    Joined:
    Jun 30, 2019
    Posts:
    14
    Sorry for necroposting, but after several years there is no really good answer for this problem!

    Any help?