These macros indicate that the former CG shader programming language (C for Graphics) has been replaced by High-Level Shading Language (HLSL), although the shader syntax and functionality are basically identical. Shader files in Unity are written using the ShaderLab syntax to define shader properties, SubShaders, and Passes. For URP, the shader code inside those Passes is written in HLSL.

While most of the ShaderLab hasn’t changed compared to the Built-In Render Pipeline, shaders written for that pipeline are automatically disabled by the URP due to changes in the internal lighting process between the two pipelines. This means that shaders handle lighting differently in URP compared to the Built-in Render Pipeline.

The Built-in Render Pipeline performs separate shader passes for every light that reaches an object, whereas URP handles all lighting and shading in a single Pass via arrays. This difference leads to distinct structures for storing light data in URP as well as new shading libraries with new conventions.

Unity will use the first SubShader block that is supported on the GPU. If the first SubShader block doesn’t have a “RenderPipeline” = “UniversalPipeline” tag, it won’t run in URP. Instead, Unity will try to run the next SubShader (if any). If none of the SubShaders are supported, Unity will render the well-known magenta-colored error shader.

A SubShader can contain multiple Pass blocks, but each of them should be tagged with a specific LightMode. As URP uses a single-pass Forward Renderer, only the first “UniversalForward” Pass supported by the GPU will be used to render objects.

Fortunately, the shader upgrader does the hard work for you and automatically converts Unity’s built-in shaders to URP shaders. But what about custom shaders?

Source: Unity Technologies Blog