S&box Wiki

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).