Skip to content

Latest commit

 

History

History
133 lines (93 loc) · 7.04 KB

ClippingPrimitive.md

File metadata and controls

133 lines (93 loc) · 7.04 KB

Clipping Primitive

The ClippingPrimitive behaviors allow for performant plane, sphere, and box shape clipping with the ability to specify which side of the primitive to clip against (inside or outside) when used with MRTK shaders.

primitive clipping gizmos

Note

ClippingPrimitives utilize clip/discard instructions within shaders and, by default, disables Unity's ability to batch clipped renderers. Take these performance implications in mind when utilizing clipping primitives. See Instancing for further details.

ClippingPlane.cs, ClippingSphere.cs, and ClippingBox.cs can be used to easily control clipping primitive properties. Use these components with the following shaders to leverage clipping scenarios.

  • Mixed Reality Toolkit/Standard
  • Mixed Reality Toolkit/TextMeshPro
  • Mixed Reality Toolkit/Text3DShader

Examples

The ClippingExamples, MaterialGallery, and ClippingInstancedExamples scenes demonstrate usage of the ClippingPrimitive behaviors, and can be found at: MRTK/Examples/Demos/StandardShader/Scenes/

Instancing

In order to avoid assumptions when enabling shader features, by default ClippingPrimitives instance the Renderers' materials. This disables Unity's ability to batch the Renderers' draw calls through GPU instancing.

To enable batching you need to take these steps:

  • Ensure every group of objects that you want batched share the same material, and only that group uses that material.
  • Ensure that material has Enable GPU Instancing checked on.
  • Check on Apply To Shared Material for the relevant ClippingPrimitive(s) in the Unity Inspector.

The Unity Frame Debugger is a great tool for validating that objects are being batched as intended.

Clipping with Multiple Primitives

By default only one ClippingPrimitive can clip a renderer at a time. If your project requires more than one ClippingPrimitive to influence a renderer the sample code below demonstrates how to achieve this.

Note

Having multiple ClippingPrimitives clip a renderer will increase pixel shader instructions and will impact performance. Please profile these changes within your project.

Different Types

How to have two different ClippingPrimitives clip a render, e.g. a ClippingSphere and ClippingBox at the same time?

This change would enable having up to one instance of each primitive type affect the same Renderer:

// Within MRTK/Core/StandardAssets/Shaders/MixedRealityStandard.shader (or another MRTK shader) change:

#pragma multi_compile _ _CLIPPING_PLANE _CLIPPING_SPHERE _CLIPPING_BOX

// to:

#pragma multi_compile _ _CLIPPING_PLANE
#pragma multi_compile _ _CLIPPING_SPHERE
#pragma multi_compile _ _CLIPPING_BOX

Note

The above change will incur additional shader compilation time.

Same Type

How to have two of the same ClippingPrimitives clip a render, e.g two ClippingBoxes at the same time?

This change would enable two ClippingBoxes at the same time:

// 1) Add the below MonoBehaviour to your project:

[ExecuteInEditMode]
public class SecondClippingBox : ClippingBox
{
    /// <inheritdoc />
    protected override string Keyword
    {
        get { return "_CLIPPING_BOX2"; }
    }

    /// <inheritdoc />
    protected override string ClippingSideProperty
    {
        get { return "_ClipBoxSide2"; }
    }

    /// <inheritdoc />
    protected override void Initialize()
    {
        base.Initialize();

        clipBoxSizeID = Shader.PropertyToID("_ClipBoxSize2");
        clipBoxInverseTransformID = Shader.PropertyToID("_ClipBoxInverseTransform2");
    }
}

// 2) Within MRTK/Core/StandardAssets/Shaders/MixedRealityStandard.shader (or another MRTK shader) add the following multi_compile pragma:

#pragma multi_compile _ _CLIPPING_BOX2

// 3) In the same shader change:

#if defined(_CLIPPING_PLANE) || defined(_CLIPPING_SPHERE) || defined(_CLIPPING_BOX)

// to:

#if defined(_CLIPPING_PLANE) || defined(_CLIPPING_SPHERE) || defined(_CLIPPING_BOX) || defined(_CLIPPING_BOX2)

// 4) In the same shader add the following shader variables:

#if defined(_CLIPPING_BOX2)
    UNITY_DEFINE_INSTANCED_PROP(fixed, _ClipBoxSide2)
    UNITY_DEFINE_INSTANCED_PROP(float4x4, _ClipBoxInverseTransform2)
#endif

// 5) In the same shader change:

#if defined(_CLIPPING_BOX)
    fixed clipBoxSide = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxSide);
    float4x4 clipBoxInverseTransform = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxInverseTransform);
    primitiveDistance = min(primitiveDistance, PointVsBox(i.worldPosition.xyz, clipBoxInverseTransform) * clipBoxSide);
#endif

// to:

#if defined(_CLIPPING_BOX)
    fixed clipBoxSide = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxSide);
    float4x4 clipBoxInverseTransform = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxInverseTransform);
    primitiveDistance = min(primitiveDistance, PointVsBox(i.worldPosition.xyz, clipBoxInverseTransform) * clipBoxSide);
#endif
#if defined(_CLIPPING_BOX2)
    fixed clipBoxSide2 = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxSide2);
    float4x4 clipBoxInverseTransform2 = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxInverseTransform2);
    primitiveDistance = min(primitiveDistance, PointVsBox(i.worldPosition.xyz, clipBoxInverseTransform2) * clipBoxSide2);
#endif

Finally, add a ClippingBox and SecondClippingBox component to your scene and specify the same Renderer for both boxes. The Renderer should now be clipped by both boxes.

See also