- Home /
How do you animate a projector's projection?
Hi!
I'm trying to project a texture with transparency on to a surface with the projector/multiply shader. This is working, however I would also like to be able to fade the whole picture in and out through animation. How is this possible?
Cheers!
Please rename the question to make it easier to deter$$anonymous$$e what the question is. :)
Answer by skovacs1 · Oct 14, 2010 at 06:28 PM
Projector Light Material
If you change the main color of the projector's material, the projection will "fade out".
projectorFade.js
var duration : float = 1.0f; var color : Color = color.white; var projector : Projector;
function Start() { projector = GetComponent(Projector); if(!projector || !projector.material || projector.material.color.a == 0) return; color = projector.material.color; }
function FadeOut() { if(!projector || !projector.material) return; var lerp: float = 0.0f; while(lerp < 1.0f) { lerp += Time.deltaTime / duration; projector.material.color = Color.Lerp(color, Color.clear, lerp); yield; } }
function FadeIn() { if(!projector || !projector.material) return; var lerp: float = 0.0f; while(lerp < 1.0f) { lerp += Time.deltaTime / duration; projector.material.color = Color.Lerp(Color.clear, color, lerp); yield; } }
Projector Multiply Material
This shader doesn't have a main color, making this a bit harder. The simplest way is to modify the shader to get this to do what you want, adding a main color. This will make the above scripts with a few changes work for this shader as well.
Something like lerping the output with a primary color should do the trick, but it won't color the shadow so we're really only using the alpha:
Shader "Projector/Multiply" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _ShadowTex ("Cookie", 2D) = "gray" { TexGen ObjectLinear } _FalloffTex ("FallOff", 2D) = "white" { TexGen ObjectLinear } }
Subshader { Tags { "RenderType"="Transparent-1" } Pass { ZWrite Off Fog { Color (1, 1, 1) } Color [_Color] AlphaTest Greater 0 ColorMask RGB Blend DstColor Zero Offset -1, -1 SetTexture [_ShadowTex] { combine texture, ONE - texture Matrix [_Projector] } SetTexture [_ShadowTex] { combine previous lerp(Primary) Primary } SetTexture [_FalloffTex] { constantColor (1,1,1,0) combine previous lerp (texture) constant Matrix [_ProjectorClip] } } } }
projectorFade.js
var duration : float = 1.0f; var alpha : float = 1.0f; var projector : Projector;
function Start() { projector = GetComponent(Projector); if(!projector || !projector.material || projector.material.color.a == 0) return; alpha = projector.material.color.a; }
function FadeOut() { if(!projector || !projector.material) return; var lerp: float = 0.0f; while(lerp < 1.0f) { lerp += Time.deltaTime / duration; projector.material.color.a = Mathf.Lerp(alpha, 0.0f, lerp); yield; } }
function FadeIn() { if(!projector || !projector.material) return; var lerp: float = 0.0f; while(lerp < 1.0f) { lerp += Time.deltaTime / duration; projector.material.color.a = Mathf.Lerp(0.0f, alpha, lerp); yield; } }
Alternatives
You could write a script that would change the texture used in the material with SetPixels, etc, but this would be costly and needless at run-time when a simple shader/material color change will do.
Warning
Since the material is shared, any other projectors using this exact material will fade out as well. If you don't want this, you will need to create one or more separate materials for projectors that you don't want sharing the behaviour.
Animating in the Animation Window
If you wanted to animate this in the animation window for whatever reason (maybe you need it to sync with part of another animation or you want more control over the curves), you would need to approach the problem a little differently because projector materials are not exposed in the animation view.
You can use the effect of the shared material described above. If you were to include some other object (plane or whatever) as a child of your projector with the exact same material as the projector applied to it, you could animate the material. If you disable the renderer on the object, the material should still animate, but this object won't actually be rendered. It's a bit awkward, but it should do the trick.
Or you can use some simple code to set the material's color explicitly every frame and then animate the color in the script:
SetProjectorColor.js
var color : Color = Color.white; var projector : Projector;
function Start() { projector = GetComponent(Projector); }
function Update() { if(!projector || !projector.material) return; projector.material.color = color; }
or
SetProjectorAlpha.js
var alpha : float = 1.0f; var projector : Projector;
function Start() { projector = GetComponent(Projector); }
function Update() { if(!projector || !projector.material) return; projector.material.color.a = alpha; }
ok, thanks for changing the title.. I misunderstood :/ . I can't really get the script to work thou. I copy this into a blank javaScript, and drops it to my projector. Then I change the "projector:" in the inspector part of the script. But when I try to change the color nothing happens to my projection. Am I missing out on something?
You don't have to change the projector part in the inspector - that's what the GetComponent in Start is for. To make it fade in or out, you need to call the FadeIn() or FadeOut() functions respectively when you want to fade in or out. You will need to get the instance of the script and call them. Somewhere you would have the GameObject reference to the projector (get it with GameObject.FindWithTag (or GameObject.Find if you don't call it too often)) and then use var script : projectorFade = projectorReference.GetComponent(projectorFade);. You then call script.FadeIn();.
aha ;) ok, thanks man. Will it be possible to animate it under the projector in the animation tab then?
Ah. That's a different problem. Because you cannot animate directly in the animation window materials on projectors and other GameObjects to which the material is not applied directly (because the material is not exposed in the animation window), you would need to approach the problem differently. There are two solutions: do it in a script every frame or animate the shared material somewhere else. I will update the answer with the implementation of these.