Editor/templates/Skybox.cs

An editor-only template for a Shader Graph skybox shader. Defines available feature flags and a large HLSL shader template string that builds a skydome shader with custom vertex and pixel paths, pushing the box to the far plane and rendering it behind the scene.

Obfuscated Code
namespace Editor.ShaderGraphExtras;
public static class SGESkyboxTemplate
{
	public static Dictionary<string, bool> Features => new()
	{
		{ "SupportsAlbedo", true},
		{ "SupportsEmission", false },
		{ "SupportsOpacity", false },
		{ "SupportsNormal", false },
		{ "SupportsRoughness", false },
		{ "SupportsMetalness", false },
		{ "SupportsAmbientOcclusion", false },
		{ "SupportsPositionOffset", false },
		{ "SupportsPixelDepthOffset", false},

		{ "SupportsLitShadingModel", false},
		{ "SupportsUnlitShadingModel", true},
		{ "SupportsCustomShadingModel", false},

		{ "SupportsOpaqueBlendMode", false},
		{ "SupportsMaskedBlendMode", false},
		{ "SupportsTranslucentBlendMode", false},
		{ "SupportsDynamicBlendMode", false},
		{ "SupportsCustomBlendMode", true}
	};

	public static string Code => @"
HEADER
{{
	Description = ""{0}"";
}}

FEATURES
{{
	#include ""common/features.hlsl""
{1}
}}

MODES
{{
	Forward();
}}

COMMON
{{
{2}
	#include ""common/shared.hlsl""
	#include ""procedural.hlsl""
}}

struct VertexInput
{{
	float4 vPositionOs : POSITION < Semantic( PosXyz ); >;
{3}
}};

struct PixelInput
{{
	// Graph nodes (World Position, view vector, triplanar, ...) emit
	// ""i.vPositionWithOffsetWs.xyz + g_vHighPrecisionLightingOffsetWs.xyz"",
	// so this field has to exist even though the sky builds its own position.
	float3 vPositionWithOffsetWs : TEXCOORD1;
	float3 vRayWs : TEXCOORD2;

	#if ( PROGRAM == VFX_PROGRAM_VS )
		float4 vPositionPs : SV_Position;
	#endif
	#if ( PROGRAM == VFX_PROGRAM_PS )
		float4 vPositionSs : SV_Position;
	#endif
{4}
}};

VS
{{
	// NOTE: no ""common/vertex.hlsl"" here -- it defines ProcessVertex/FinalizeVertex
	// in terms of VS_CommonProcessing, which only exists for the standard vertex
	// input path. The sky box builds its own position, so it isn't needed.
	#include ""system.fxc""
{5}{6}{7}
	PixelInput MainVs( VertexInput v )
	{{
		PixelInput i;

		// Push the box out to the far plane and keep it centred on the camera
		// so the sky never intersects world geometry.
		float flSkyboxScale = g_flNearPlane + g_flFarPlane;
		float3 vPositionWs = g_vCameraPositionWs.xyz + v.vPositionOs.xyz * flSkyboxScale;

		i.vPositionPs = Position3WsToPs( vPositionWs );

		// Camera-relative, matching the standard vertex path -- graph nodes add
		// g_vHighPrecisionLightingOffsetWs back on to recover absolute world space.
		i.vPositionWithOffsetWs = vPositionWs - g_vHighPrecisionLightingOffsetWs.xyz;
		i.vRayWs = normalize( v.vPositionOs.xyz );
{8}
		return i;
	}}
}}

PS
{{
	// Our PixelInput has none of the standard mesh fields (normals, tangents,
	// lightmap UVs), so Material::Init( PixelInput ) can't read them. This
	// switches it to the empty Material::Init() -- see common/material.hlsl.
	#define CUSTOM_MATERIAL_INPUTS 1

	#include ""common/pixel.hlsl""
{9}{10}{11}
	// Sky renders behind everything: no depth write, reversed-Z far plane test.
	RenderState( CullMode, NONE );
	RenderState( DepthWriteEnable, false );
	RenderState( DepthEnable, true );
	RenderState( DepthFunc, GREATER_EQUAL );

	BoolAttribute( sky, true );

	float4 MainPs( PixelInput i ) : SV_Target0
	{{
		Material m = Material::Init();
		m.Albedo = float3( 0, 0, 0 );
		m.Opacity = 1;
{12}
		m.Opacity = saturate( m.Opacity );
{13}
	}}
}}";
}