Hi, I have developped a special shader to visualize scientific data, by applying some rules, determined only during runtime. Now, this shader does not work properly in the scene editor. To provide the user a meaningful object representation in the scene editor, I want to attach another shader to be used in scene preview. Is that possible? Thanks.
Likewise. Often, I'm working directly in clip space, and the only option is to not render layers with those objects in the Scene view. Sometimes that's fine, but other times, it would be nice to have a visualization in 3D space, only for the Scene view. Also, for 2D games, you don't have to waste the calculations necessary for perspective: Code (csharp): position = UNITY_MATRIX_MVP[3]; position.xy += mul( float2x2(UNITY_MATRIX_MVP), vertex.xy ); But then, you can't use a perspective camera in the scene view without that mesh disappearing. I'd like that not to be the case, without having to account for the last two entries of the fourth row of UNITY_MATRIX_MVP changing based on camera type.
Do the preprocessor defines work in shaders? #ifdef UNITY_EDITOR and such? edit; Actually, even play mode would still count as Unity editor, so that's pointless.
As I am still interested in a solution, I bring this thread back to live.... @Lulucifer: can you share some more thoughts on your LOD approach? Is it possible to decide for which shader to use in scene editor only based on LOD? Otherwise, I think it could be done programaticaly in the shader code by passing a boolean which is different during play mode. But this would blow up shader code, which already is multi-pass.
I assume, by the LOD thing... you add in another subshader with a really high LOD value, that'll get used in the editor. Then at run-time in your game (when it starts) you tell it to limit the shader LOD to something below that value (meaning any SubShader with a LOD above that will be ignored). http://docs.unity3d.com/Documentation/Components/SL-ShaderLOD.html
Great suggestion with LOD usage. It works for me really well, it'll do until perhaps there's a built in conditional compile for the Editor view.
There is nothing provided by Unity, no. There's no consistent way to detect the scene view purely in a shader either. The best solution I know of is to use Camera.onPreRender to detect and set a global keyword or property. Code (csharp): using System; using UnityEngine; [ExecuteInEditMode] public class SceneViewShaderHelper : MonoBehaviour { #if UNITY_EDITOR private int _isSceneViewID = Shader.PropertyToID("_IsSceneView"); public void OnEnable() { Camera.onPreRender += SetIfSceneViewCamera; } public void OnDisable() { Camera.onPreRender -= SetIfSceneViewCamera; } public void SetIfSceneViewCamera(Camera cam) { // Scene View camera is named "SceneCamera" if (cam.gameObject.name == "SceneCamera") { Shader.EnableKeyword("SCENE_VIEW"); Shader.SetGlobalFloat(_isSceneViewID, 1f); } // Inspector preview for materials, models, and prefabs is named "Preview Scene Camera" // else if (cam.gameObject.name == "Preview Scene Camera") // { // Shader.EnableKeyword("SCENE_VIEW"); // Shader.SetGlobalFloat(_isSceneViewID, 2f); // } // Otherwise this is a game view or other user camera else { Shader.DisableKeyword("SCENE_VIEW"); Shader.SetGlobalFloat(_isSceneViewID, 0f); } // You can double check the camera names if something breaks in the future // Debug.Log(cam); } #endif } I then add this to a game object in the scene which I set to be editor only so it gets excluded from builds. In the shader, depending on what you're doing, you can use a #pragma multi_compile _ SCENE_VIEW and / or int _isSceneView; to switch to scene view specific code. The one thing to be mindful of is there's no way to prevent that shader variant / code from being included in standalone builds, though if you use the keyword they shouldn't "cost" anything apart from an increase in package size for the unused shader variants. The other option is to use command buffers to render entirely different objects / materials in the main camera and scene camera.
It's funny I tried this callback way, but it didn't work for me. I wasn't even getting callbacks from the scene camera, only the game cameras. I must have been doing something wrong. I also tried adding a component onto the scene camera, and it kinda worked, but also unity instantly removed it. What ended up working for me was creating two CommandBuffers with their only job being to enable and disable a shader keyword. One runs before forward opaque, the other after forward alpha. Then I also added that keyword to our shader stripper. The EditorOnly tag is really cool though! Didn't know about that. (Now don't get me started on why the unity tag system is a broken mess...)
My guess is you used cam.OnPreRender. cam.OnPreRender and Camera.onPreRender are subtly different, with the later being a delegate for all cameras, and the prior being only for a specific camera. The component script above does not need to be on a game object with a camera, it doesn't even need to be a child of a camera ... there doesn't even need to be a camera in the scene! https://docs.unity3d.com/ScriptReference/Camera.OnPreRender.html https://docs.unity3d.com/ScriptReference/Camera-onPreRender.html
Haven't tried it but this looks like what you're after: https://docs.unity3d.com/ScriptReference/SceneView.SetSceneViewShaderReplace.html