- Home /
Writing a fixed function shader to render occluded GL lines with a different alpha
I'm trying to write a multi-pass shader that I'll be using for colouring lines and shapes drawn by the various GL
methods. The intention of the shader is to render visible parts of the shapes using the supplied colour in GL.Color()
, and rendering occluded parts using a transparent variant of that colour. However, for some reason my shader can only achieve one of those two goals, and not both at the same time.
Here's my current shader:
Shader "Custom/GLShader" {
SubShader {
BindChannels {
Bind "vertex", vertex
Bind "color", color
}
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Cull Off
Fog { Mode Off }
}
Pass
{
Blend SrcAlpha One
ZTest Greater
ZWrite Off
Cull Off
Fog { Mode Off }
}
}
Fallback "Diffuse"
}
And here's the relevant parts of the C# script attached to my main camera:
public Shader glShader;
private Material glMat;
void Awake()
{
glMat = new Material(glShader);
}
void OnPostRender()
{
glMat.SetPass(0);
GL.PushMatrix();
GL.Begin(GL.QUADS);
GL.Color(Color.red);
GL.Vertex3(0, 0, 0);
GL.Vertex3(5F, 0, 0);
GL.Vertex3(5f, 5F, 0);
GL.Vertex3(0, 5f, 0);
GL.End();
GL.PopMatrix();
}
This results in the visible parts of the shape being rendered properly, but not the occluded parts:
Swapping the two Passes in the shader, I can get the occluded part to render now, but the visible parts are now missing:
I feel like I've misunderstood how a Pass works, and need some clarification on how I can tweak the shader to make this work - or if that isn't possible, what the best approach for this would be that I could still use in conjunction with my C# code.
I did find some similar questions like the shader provided at Render Occluded pixels to gray color, but I'm not sure how to adapt that to how I'm currently drawing shapes (since they won't have a texture, only a colour given by GL.Color()
.
Answer by Bunny83 · Aug 07, 2016 at 01:49 PM
Well, you only render one pass of your shader. You have to do this:
void OnPostRender()
{
GL.PushMatrix();
for (int i = 0; i < glMat.passCount; i++)
{
glMat.SetPass(i);
GL.Begin(GL.QUADS);
GL.Color(Color.red);
GL.Vertex3(0, 0, 0);
GL.Vertex3(5F, 0, 0);
GL.Vertex3(5f, 5F, 0);
GL.Vertex3(0, 5f, 0);
GL.End();
}
GL.PopMatrix();
}
A lot people seem to not fully understand what a second pass actually means. It means the whole object has to be drawn again, just with a different pass. That's why a second pass usually causes another "drawcall". That's also why Unity now seperates those in the stats window and lists "SetPass calls" seperately.
Hmm, anyway to tell unity to use the same verticies as "the last pass"? Or should we cache that stuff ourselves? (obviously no diff in your example, I'm talking about more procedural based stuff.)
No you can't. That's the point of the GL immediate mode. What you pass in as data is processed immediately as soon as GL.End is invoked. At this point the vertex data is passed to the GPU and causes a "drawcall". So if you have multiple passes you have to "cache" the content yourself. That's why in most cases where the shader gets a bit more complex it's way easier to use a $$anonymous$$esh / $$anonymous$$eshFilder / $$anonymous$$eshRenderer setup.
Of course you can't change the pass / shader in-between GL.Begin and GL.End. SetPass is part of the shader setup for one or multiple drawcalls. When SetPass is called the GPU pipeline will be flushed and will setup the new shader (shader as it's seen from the GPU where a shader is a vertex & fragment shader function). GL.Begin initiates a drawcall and GL.End will finish it.
That makes a lot of sense! I definitely failed to make the connection between shader passes and SetPass(), even though it seems so clear to me now.
Your answer

Follow this Question
Related Questions
Why Unity compiled shader doesn't use the GLSLPROGRAM/GLSL syntax? 0 Answers
GL - Shader not working in Android 1 Answer
How do you hide a shader property? 2 Answers
Logical BlendOp not working 0 Answers
Shader - What is float3.xy? 1 Answer