Revision Difference
Getting_rid_of_Tex2D_macros#561589
<cat>Material.ShaderReference</cat>⤶
<title>Getting rid of Tex2D macros</title>⤶
⤶
# Getting rid of Texture2D/Sample macros⤶
<note>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.</note>⤶
⤶
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: ⤶
⤶
```cs⤶
// 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: ⤶
⤶
```cs⤶
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. ⤶
⤶
```cs⤶
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 );⤶
⤶
{...}⤶
}⤶
```⤶
⤶
If you're looking for more details about how sampler states work, check the documentation for [Sampler States in s&box docs](https://docs.facepunch.com/s/sbox-dev/doc/sampler-states-LlJc7ymJkq). 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: ⤶
```cs⤶
SamplerState MyNewSampler < Filter( POINT ); AddressU( CLAMP ); AddressV( CLAMP ); >;⤶
```⤶
⤶
In `MainPs` block, you can now sample your Texture2D object using a new sampler like this: ⤶
```cs⤶
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](https://docs.facepunch.com/s/sbox-dev/doc/sampler-states-LlJc7ymJkq).