S&box Wiki

Getting rid of Tex2D macros

Getting rid of Texture2D/Sample macros

This is a probably little bit too detailed article for beginner people. If this article is too dumb then feel free to edit or nuke it.

In foreseeable future, some macros like all variations of CreateTexture2D might become obsolete. In this article you'll see a simple example how can you use Texture2D and SamplerState in your shader code to avoid using CreateTexture2D / Tex2DS macros.

CreateTexture2D to Texture2D, Tex2DS to Sample()

Currently, most shaders use CreateTexture2D or CreateTexture2DWithoutSampler macros to create a new texture variable, and then Tex2DS to sample it inside the main pixel shader function. This is how code usually looks like:

// This is an EXAMPLE for creating & sampling Texture2D using macros. // It's recommended to avoid using such macros as they might break in future. PS { #define CUSTOM_MATERIAL_INPUTS // Create an input for our Color map, this will show up in material editor. CreateInputTexture2D( Color, Srgb, 8, "", "_color", "Material,10/10", Default3( 1.0, 1.0, 1.0 ) ); // Create a Texture2D variable called "g_tColor" from "Color" input box using CreateTexture2DWithoutSampler macro CreateTexture2DWithoutSampler( g_tColor ) < Channel( RGB, Box( Color ), Srgb ); OutputFormat( BC7 ); SrgbRead( true ); >; {...} // Entry point for pixel shader float4 MainPs( PixelInput i ) : SV_Target0 { // Sample g_tColor texture and store it in a local variable float3 l_tColor = Tex2DS( g_tColor, g_sAniso, i.vTextureCoords.xy ).rgb; {...} } }

Instead of using CreateTexture2D, you can simply create a new Texture2D variable using native HLSL features and add the annotation like in previous example:

PS { #define CUSTOM_MATERIAL_INPUTS // Create an input for our Color map, this will show up in material editor. We still need this. CreateInputTexture2D( Color, Srgb, 8, "", "_color", "Material,10/10", Default3( 1.0, 1.0, 1.0 ) ); // Create a Texture2D with required annotation, but now without any macros. Does the same thing as CreateTexture2DWithoutSampler. Texture2D g_tColor < Channel( RGB, Box( Color ), Srgb ); OutputFormat( BC7 ); SrgbRead( true ); >; {...} }

And then instead of sampling your new Texture2D using Tex2D/Tex2DS macro, simply use .Sample( SamplerState, UV ). In this code example, we will use built-in sampler state g_sAniso, so you won't need to create a new sampler.

float4 MainPs( PixelInput i ) : SV_Target0 { // Sample g_tColor texture and store it in a local variable, but now without using any macros. float3 l_tColor = g_tColor.Sample( g_sAniso, v.TextureCoords.xy ); {...} }

In this code example, we're using g_sAniso as a sampler. This is one of built-in samplers that are always available, in most cases that's all what you will need for your shader. If you're looking for a full list of pre-defined samplers, or more details about how sampler states work, check the documentation for Sampler States in s&box docs.

If you can't find a built-in sampler that meets your requirements, you can create your own. For example, we need a sampler with AddressU and AddressV set to CLAMP, and point filtering enabled. Before the MainPs block, declare a new ShaderState variable and set up sampler states in the annotation:

SamplerState MyNewSampler < Filter( POINT ); AddressU( CLAMP ); AddressV( CLAMP ); >;

In MainPs block, you can now sample your Texture2D object using a new sampler like this:

float3 l_tColor = g_tColor.Sample( MyNewSampler, v.TextureCoords.xy );

Other examples

If you are using Texture2D arrays, approach to replace macros with native HLSL code will be almost identical. Instead of CreateTexture2DArray macro, declare a new object Texture2DArray name. To sample a Texture2DArray object, do .Sample( sampler, uv.xyz ).

If you're working with Texture2DMS, CreateTexture2DMS macro will be just Texture2DMS<float> name. Don't forget about including annotations to your Texture2D declarations.

But why?

Most IDEs do not understand these macros, and they can make things more confusing for beginners. These macros exist in engine's code since very early days of Source 2 and apparently were required back when it had to compile stuff for DX9, DX11 and OpenGL.

Instead of fiddling with CreateTexture2DWithoutSampler, Tex2DS and other macros, you can just use <object>.Sample( sampler, uv ) function for all types of Texture2Ds, and IDEs will understand it. s&box has a bunch of built-in samplers so in most cases you won't need to create a new sampler state for every shader, but even if you'll need to do this, it's very easy.