Skip to main content

How the shader draws one frame

This page is an explanation. To pick a surface mode right now, see the Basic Settings Guide.

In one line​

MingToon splits one material into six passes. The surface mode changes the render state those passes use, all at once.

The counts here are the numbers declared in the source

They are not the number of draws that actually go out in one frame. Baking, feature toggles, the camera and the lights all change it. Check the real count in Frame Debugger.

What happens​

The Built-in shader declares six passes.

OrderPassWhat it does
1FORWARD_BASE_BACKFACEDraws the far side first in two-sided two-pass
2FORWARD_BASEMain light, ambient light, main surface effects
3FORWARD_ADDAdditional lights such as point and spot
4TRANSPARENT_DEPTH_PREPASSWrites depth first, without color
5OUTLINE_HULL_DIRECTThe Normal Outline drawn by expanding the mesh
6SHADOW_CASTERLight shadows and Built-in camera depth

URP has a different pass layout. Do not apply this order or count to it. In URP, outlines and depth effects are wired up as Renderer Features. See Supported Environments as well.

Main surface​

Most surface effects are calculated in pass 2. Turn on two-sided two-pass and pass 1 takes the far side.

Ordinary transparency does not write depth in the pass that draws color. When pass 4 lays down depth first without color, the outline does not punch through its own surface. In exchange it can hide translucent layers behind it, so it is not a switch that solves every sorting problem.

Shadows and camera depth​

Three things are separate conditions. Pass 6 being alive, this surface entering camera depth, and this surface casting a light shadow.

A surface does not enter camera depth just because the pass exists. Camera depth participation decides whether another material's depth effects read this surface as an occluder.

What surface mode actually changes​

Surface modeRenderTypeQueueBlendZWriteDepth prepass
OpaqueOpaque2000One / ZeroOnNone
CutoutTransparentCutout2450One / ZeroOnNone
Semi-TransparentOpaque2499SrcAlpha / OneMinusSrcAlphaOnNone
TransparentTransparent3000SrcAlpha / OneMinusSrcAlphaOffYes

Semi-Transparent blends color and still writes depth. Queue 2499 sits inside the opaque range, so it sorts front to back. In that order the nearest face needs depth to win. This is why two-sided hair does not paint its inner strands over the outer ones.

Transparent sorts back to front and does not write depth. This mode is for a single material that mixes an opaque body, see-through shorts and a skirt.

Shader keywords​

Each module's keyword and properties work together. A keyword being on does not mean the effect is always visible on screen. The overall effects toggle, the material role, strength, textures and camera depth are conditions too.

Layer tier keywords​

ModuleAdditional tiers
Surface Layer_MING_STACK_4, _MING_STACK_10
Normal Layer_MING_NORMAL_2, _MING_NORMAL_5
MatCap Layer_MING_MATCAP_2, _MING_MATCAP_5

The tier sets the slot range that gets compiled. The actual layer count is also used for runtime branching.

What that constrains​

  • Cutting layers within the same tier leaves the compiled code the same size. It only shrinks when you cross a tier boundary.
  • Even with a path that removes triangles in an inactive pass, vertex processing and draw submission are not free.
  • The editable shader keeps code around so values can change. Check the actual reduction in the baked shader.
  • VRChat fallback follows the VRCFallback tag and host policy, and does not reproduce MingToon's effects.