- Home /
Need some help with transparency script
Hi guys, I have this script here which when activated changes the shader of all objects to be transparent. The problem though is that they stay transparent even after the script is deactivated. Is there an easy way to return them to their original shader after the script is deactivated?
Here is the script:
function Update () {
var hits : RaycastHit[];
hits = Physics.RaycastAll (transform.position, transform.forward, 9999);
// Change the material of all hit colliders
// to use a transparent Shader
for (var i = 0;i < hits.Length; i++) {
var hit : RaycastHit = hits[i];
var renderer = hit.collider.renderer;
if (renderer && this.GetComponentInChildren(aimmode).inScope == true) {
renderer.material.shader = Shader.Find("Transparent/Diffuse");
renderer.material.color.a = .9;
}
else if (renderer && this.GetComponentInChildren(aimmode).inScope == false) {
return;
}
}
}
Answer by aldonaletto · Sep 03, 2011 at 04:06 AM
Are you doing this shader replacement every Update? It's very time consumming! I would separate in two funcitons: one to make objects transparent, and other to restore the original shaders:
var hits: RaycastHit[]; var shaders: Shader[];
function SetTransparent(){ // set objects to transparent hits = Physics.RaycastAll (transform.position, transform.forward, 9999); shaders = new Shader[hits.Length]; // create array of old shaders var newShader = Shader.Find("Transparent/Diffuse"); // find new shader only once for (var i = 0; i < hits.Length; i++) { var hit : RaycastHit = hits[i]; var renderer = hit.collider.renderer; if (renderer && this.GetComponentInChildren(aimmode).inScope == true) { shaders[i] = renderer.material.shader; // save original shader renderer.material.shader = newShader; renderer.material.color.a = .9; } else { shaders[i] = null; // ensure that non replaced shaders are null if (renderer && this.GetComponentInChildren(aimmode).inScope == false) return; }
} }
function RestoreShaders(){ // restore all shaders for (var j = 0; j < hits.Length; j++){ if (shaders[j]){ // restore shader, if modified var hit : RaycastHit = hits[j]; var renderer = hit.collider.renderer; renderer.material.shader = shaders[j]; } } }
Answer by ObviouslyInsane · Sep 03, 2011 at 05:08 AM
Thanks aldonaletto. I am using your script now and the transparency part works but the RestoreShaders function isn't being called. I used a debug.log to test it.
I would like the RestoreShaders function to be called after this part:
else {
shaders[i] = null; // ensure that non replaced shaders are null
if (renderer && this.GetComponentInChildren(aimmode).inScope == false) return;
But if you call RestoreShaders at this point you will not even see the transparency effect, because it's executed in the same Update cycle. The idea is to call SetTransparent to make transparent all objects hit, then call RestoreShaders when you want to restore them. SetTransparent lets the arrays hits and shaders ready to be used by RestoreShaders. You should not call SetTransparent again until you've restored the shaders, or the arrays will be modified and some objects will never be restored. $$anonymous$$aybe your original logic isn't compatible with this arrangement - it seems you were enabling and disabling the script, while now you should call SetTransparent and RestoreShaders.
That's correct. I have this script attached to a weapon so whenever the weapon is in scope I want SetTransparent to be called and when they leave scope I want RestoreShaders to be called.
Answer by ObviouslyInsane · Sep 03, 2011 at 08:55 PM
Ok here is the revised script:
var shadersRestored = true;
var hits: RaycastHit[];
var shaders: Shader[];
function Update(){
if(this.GetComponentInChildren(aimmode).inScope == true && shadersRestored == true)
SetTransparent();
else if(this.GetComponentInChildren(aimmode).inScope == false && shadersRestored == false)
RestoreShaders();
}
function SetTransparent(){ // set objects to transparent
hits = Physics.RaycastAll (transform.position, transform.forward, 9999);
shaders = new Shader[hits.Length]; // create array of old shaders
var newShader = Shader.Find("Transparent/Diffuse"); // find new shader only once
for (var i = 0; i < hits.Length; i++) {
var hit : RaycastHit = hits[i];
var renderer = hit.collider.renderer;
if (renderer) {
shaders[i] = renderer.material.shader; // save original shader
renderer.material.shader = newShader;
renderer.material.color.a = .9;
shadersRestored = false;
Debug.Log("Shaders NOT Restored!");
}
else {
shaders[i] = null; // ensure that non replaced shaders are null
}
}
}
function RestoreShaders(){ // restore all shaders
for (var j = 0; j < hits.Length; j++){
if (shaders[j]) { // restore shader, if modified
var hit : RaycastHit = hits[j];
var renderer = hit.collider.renderer;
renderer.material.shader = shaders[j];
shadersRestored = true;
Debug.Log("Shaders Restored!");
}
}
}
Now at this line: for (var j = 0; j < hits.Length; j++){ I am getting an error saying "Object reference not set to an instance of an object." Can you go into a little more detail as to what I need to do? Also I know its not good to keep these in the Update function I will move it once I get this working.
You can keep your code in Update like you did: the functions will only be called once because you made good use of your flag shadersRestored - it only allows one call to SetTransparent, which must be balanced later by a call to RestoreShaders. When you set inScope to true, SetTransparent is called once, and RestoreShaders will be called only once too when inScope becomes false.
About the error: I tested this script and it worked fine. I had to change the Update function just to simplify my test:
var shadersRestored = true; var hits: RaycastHit[]; var shaders: Shader[];
function Update(){ if(Input.Get$$anonymous$$eyDown("x")){ if (shadersRestored) SetTransparent(); else RestoreShaders(); } } And it worked very well.
You could get this error in the first if case GetComponentInChildren could not find the script aimmode, but I just can't think how this error could appear in the last for.
Are you sure that's really the line where the error was flagged? Or maybe the error is appearing in an older version of this script? - I made this mistake a couple of times: I created a new copy of my script with a similar name and edited it, but forgot to remove the older version from the object, which gave me weird errors until I noticed what was happening.
Wow, so I was at my wit's end with this and decided to restart Unity just in case and it works perfectly now. Took a long time but its finished. Thanks again for all your help I could not have done it without you!