5
\$\begingroup\$

I have an object with a custom shader. When it is being rendered by cameraA, then I want it to render a particular way (ex red). When it is rendered by another cameraB, I want it to render a different way (ex green).

Is there some way I can tell what is the current camera rendering in the shader? Or perhaps I can toggle a boolean value in my shader between rendering of each camera? Where would I do this (OnPostRender() maybe?).

\$\endgroup\$
3
\$\begingroup\$

Changing shader properties for each camera

You can accomplish this with a script on the camera. In my example I change the color but you can extend this idea to any property in the shader.

[ExecuteInEditMode]
public class CameraMaterialChanger : MonoBehaviour {

    public Color myColor; // color you want the camera to render it as
    public Material material; // material you want the camera to change
    public string colorPropertyName; // name of the color property in the material's shader

    void OnPreRender() {
        _default = material.GetColor(colorPropertyName);
        material.SetColor(colorPropertyName, myColor);
    }

    void OnPostRender() {
        material.SetColor(colorPropertyName, _default);
    }

    private Color _default;
}

It works by changing the color on the material before rendering, and then restoring it to the original color afterwards to avoid permanently altering the material. Note that property names need to be prefixed with an underscore.

Changing the shader itself for each camera

This makes use of replacement shaders and might require more work to set up how you want.

[ExecuteInEditMode]
public class CameraShaderChanger : MonoBehaviour {

    public Shader replacementShader; // the shader you want to use with this camera
    public string replacementTag;

    void OnValidate() {
        GetComponent<Camera>().SetReplacementShader(replacementShader, replacementTag);
    }
}

Replacement shaders work the following way (from the docs):

It works like this: the camera renders the scene as it normally would. the objects still use their materials, but the actual shader that ends up being used is changed:

  • If replacementTag is empty, then all objects in the scene are rendered with the given replacement shader.
  • If replacementTag is not empty, then for each object that would be rendered:
    • The real object’s shader is queried for the tag value.
    • If it does not have that tag, object is not rendered.
    • A subshader is found in the replacement shader that has a given tag with the found value. If no such subshader is found, object is not rendered.
    • Now that subshader is used to render the object.

Also, the reverse call of SetReplacementShader(Shader, string) is ResetReplacementShader(void).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.