DepthMask

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
(Links, and comments in the shader source.)
(ShaderLab - DepthMask.shader)
 
(17 intermediate revisions by 5 users not shown)
Line 1: Line 1:
Author: Neil Carter ([[:User:NCarter|NCarter]])
+
Author: Neil Carter ([[:User:NCarter|NCarter]]) and Daniel Brauer ([[:User:Danielbrauer|Danielbrauer]])
  
 
== Description ==
 
== Description ==
  
 
[[Image:DepthMaskShader.png|thumb|100px|DepthMask.shader in use on the example project.]]
 
[[Image:DepthMaskShader.png|thumb|100px|DepthMask.shader in use on the example project.]]
This shader draws faces which are invisible, but which still appear in the depth buffer. This makes it possible to prevent subsequently-drawn objects from appearing behind those faces.
+
This shader draws faces which are invisible, but which still appear in the depth buffer. This allows you to prevent objects from being drawn where they are occluded by the mask.
 +
 
 +
To understand how this technique works, you should know about the [http://en.wikipedia.org/wiki/Z-buffering depth buffer] and [http://unity3d.com/support/documentation/Components/SL-SubshaderTags.html render queues] before reading further.
  
 
== Usage ==
 
== Usage ==
  
The example project shows how to use the shader to cut a hole in a water plane to prevent the water from appearing inside a boat's hull.
+
The example package shows how to use the shader to prevent the water from appearing inside a boat's hull. The setup requires two things:
  
It is necessary to use three cameras to force the rendering order:
+
# A mask object using the Depth Mask shader. This object will be drawn just after regular opaque objects, and will prevent subsequent objects from being drawn behind it.
 +
# Objects you wish to be masked must have the SetRenderQueue script attached to them. In the Inspector, change their queue from 3000 (regular geometry) to 3020 (just after the mask shader)
  
*The first draws the boat hull and all other normal objects.
+
==== Alternate Use ====
*The second draws a skin over the top of the boat's hull using the DepthMask shader.  The skin objects must be in a special layer which only this camera draws.
+
*The third draws only the water.  The water must be in its own layer and is only drawn by this camera.
+
  
The second and third cameras do not clear the colour or depth buffers.  Of course, all three cameras must also move as one, so you may want to put them in an empty GameObject to keep them together.
+
In most common scenarios, you will only need a few objects to be masked. If, however, you find that you have more objects that need to be masked than objects that do not, you might find it useful to attach the SetRenderQueue script to the masks themselves, and set their queues to 2090 (just before regular geometry). Objects that you don't want masked should have their queues set to 2080 (just before the mask shader).
  
== Example Project ==
+
== Example ==
 
+
Unity 3.4.1 package: [http://dl.dropbox.com/u/6231276/Depth%20Mask%20Example.unitypackage 111KB]
[http://www.nether.pwp.blueyonder.co.uk/nether/files/boat_2.zip boat_2.zip, 209KB]
+
 
+
----
+
 
+
''Note that the example project gives the shader the name 'HullCover.shader'.  See the [[:Talk:DepthMask|discussion]] page regarding this.''
+
  
 
==ShaderLab - DepthMask.shader==
 
==ShaderLab - DepthMask.shader==
  
<shaderlab>
+
<source lang="glsl">
Shader "DepthMask"
+
Shader "Masked/Mask" {
{
+
    SubShader
+
SubShader {
    {
+
// Render the mask after regular geometry, but before masked geometry and
        // Turn off lighting, because it's expensive and the thing is supposed to be
+
// transparent things.
        // invisible anyway.
+
 +
Tags {"Queue" = "Geometry+10" }
 +
 +
// Don't draw in the RGBA channels; just the depth buffer
 +
 +
ColorMask 0
 +
ZWrite On
 +
 +
// Do nothing specific in the pass:
 +
 +
Pass {}
 +
}
 +
}
 +
</source>
  
        Lighting Off
+
==C# - SetRenderQueue.cs==
  
        // Draw into the depth buffer in the usual way. This is probably the default,
+
<syntaxhighlight lang="csharp">
        // but it doesn't hurt to be explicit.
+
/*
 +
SetRenderQueue.cs
 +
 +
Sets the RenderQueue of an object's materials on Awake. This will instance
 +
the materials, so the script won't interfere with other renderers that
 +
reference the same materials.
 +
*/
  
        ZTest LEqual
+
using UnityEngine;
        ZWrite On
+
  
        // Don't draw the RGB colour channels, just the alpha channel.  This means
+
[AddComponentMenu("Rendering/SetRenderQueue")]
        // that nothing visible is drawn.  Ideally, I would have liked to set ColorMask
+
        // to draw nothing at all, but it doesn't seem to be possible to say anything
+
        // like ColorMask None.
+
  
        ColorMask A
+
public class SetRenderQueue : MonoBehaviour {
 +
 +
[SerializeField]
 +
protected int[] m_queues = new int[]{3000};
 +
 +
protected void Awake() {
 +
Material[] materials = renderer.materials;
 +
for (int i = 0; i < materials.Length && i < m_queues.Length; ++i) {
 +
materials[i].renderQueue = m_queues[i];
 +
}
 +
}
 +
}
 +
</syntaxhighlight>
  
        // Do nothing specific in the pass:
+
[[Category:ShaderLab]]
 
+
[[Category:C Sharp]]
        Pass {}
+
[[Category:Utility]]
    }
+
}
+
</shaderlab>
+

Latest revision as of 21:12, 16 May 2013

Author: Neil Carter (NCarter) and Daniel Brauer (Danielbrauer)

Contents

[edit] Description

DepthMask.shader in use on the example project.

This shader draws faces which are invisible, but which still appear in the depth buffer. This allows you to prevent objects from being drawn where they are occluded by the mask.

To understand how this technique works, you should know about the depth buffer and render queues before reading further.

[edit] Usage

The example package shows how to use the shader to prevent the water from appearing inside a boat's hull. The setup requires two things:

  1. A mask object using the Depth Mask shader. This object will be drawn just after regular opaque objects, and will prevent subsequent objects from being drawn behind it.
  2. Objects you wish to be masked must have the SetRenderQueue script attached to them. In the Inspector, change their queue from 3000 (regular geometry) to 3020 (just after the mask shader)

[edit] Alternate Use

In most common scenarios, you will only need a few objects to be masked. If, however, you find that you have more objects that need to be masked than objects that do not, you might find it useful to attach the SetRenderQueue script to the masks themselves, and set their queues to 2090 (just before regular geometry). Objects that you don't want masked should have their queues set to 2080 (just before the mask shader).

[edit] Example

Unity 3.4.1 package: 111KB

[edit] ShaderLab - DepthMask.shader

Shader "Masked/Mask" {
 
	SubShader {
		// Render the mask after regular geometry, but before masked geometry and
		// transparent things.
 
		Tags {"Queue" = "Geometry+10" }
 
		// Don't draw in the RGBA channels; just the depth buffer
 
		ColorMask 0
		ZWrite On
 
		// Do nothing specific in the pass:
 
		Pass {}
	}
}

[edit] C# - SetRenderQueue.cs

/*
	SetRenderQueue.cs
 
	Sets the RenderQueue of an object's materials on Awake. This will instance
	the materials, so the script won't interfere with other renderers that
	reference the same materials.
*/
 
using UnityEngine;
 
[AddComponentMenu("Rendering/SetRenderQueue")]
 
public class SetRenderQueue : MonoBehaviour {
 
	[SerializeField]
	protected int[] m_queues = new int[]{3000};
 
	protected void Awake() {
		Material[] materials = renderer.materials;
		for (int i = 0; i < materials.Length && i < m_queues.Length; ++i) {
			materials[i].renderQueue = m_queues[i];
		}
	}
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox