├── .gitignore ├── thumbnail.jpg ├── shadersrc ├── bin │ ├── ShaderCompile.exe │ ├── process_shaders_single.ps1 │ └── process_shaders.ps1 ├── example_flip_ps2x.hlsl ├── build_single_shader.bat ├── example_depth_ps2x.hlsl ├── template_ps2x.hlsl ├── compile_shader_list.txt ├── example_chromaticaberration_ps2x.hlsl ├── example_wave_ps2x.hlsl ├── example_glitch_ps2x.hlsl ├── example_blackhole_ps2x.hlsl ├── example_spin_ps2x.hlsl ├── example_square_ps2x.hlsl ├── example_ascii_ps2x.hlsl ├── example_hearts_ps2x.hlsl ├── common.hlsl ├── example_sdf_ps2x.hlsl └── build_shaders.bat ├── materials └── effects │ └── shaders │ ├── glyph_msdf.vtf │ ├── glyph_sdf.vtf │ ├── example_flip.vmt │ ├── example_ascii.vmt │ ├── example_depth.vmt │ ├── example_square.vmt │ ├── example_wave.vmt │ ├── example_hearts.vmt │ ├── example_spin.vmt │ ├── example_glitch.vmt │ ├── example_sdf.vmt │ ├── example_chromaticaberration.vmt │ ├── template.vmt │ └── example_blackhole.vmt ├── .vscode ├── launch.json └── tasks.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.vcs 2 | *.inc 3 | sound.cache -------------------------------------------------------------------------------- /thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ficool2/sdk_screenspace_shaders/HEAD/thumbnail.jpg -------------------------------------------------------------------------------- /shadersrc/bin/ShaderCompile.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ficool2/sdk_screenspace_shaders/HEAD/shadersrc/bin/ShaderCompile.exe -------------------------------------------------------------------------------- /materials/effects/shaders/glyph_msdf.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ficool2/sdk_screenspace_shaders/HEAD/materials/effects/shaders/glyph_msdf.vtf -------------------------------------------------------------------------------- /materials/effects/shaders/glyph_sdf.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ficool2/sdk_screenspace_shaders/HEAD/materials/effects/shaders/glyph_sdf.vtf -------------------------------------------------------------------------------- /shadersrc/example_flip_ps2x.hlsl: -------------------------------------------------------------------------------- 1 | // Example shader that flips the screen horizontally 2 | 3 | #include "common.hlsl" 4 | 5 | float4 main( PS_INPUT i ) : COLOR 6 | { 7 | float2 uv = i.uv; 8 | uv.x = 1.0 - uv.x; 9 | return tex2D(TexBase, uv); 10 | } 11 | -------------------------------------------------------------------------------- /shadersrc/build_single_shader.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM Check if an argument was provided 4 | if "%~1"=="" ( 5 | echo Drag and drop a shader file onto this script 6 | pause 7 | exit /b 8 | ) 9 | 10 | bin\ShaderCompile.exe /O 3 -ver 20b -shaderpath "%cd%" %1 -------------------------------------------------------------------------------- /shadersrc/example_depth_ps2x.hlsl: -------------------------------------------------------------------------------- 1 | // Example shader that displays the depth buffer 2 | // NOTE: the depth buffer in Source only extends 192 units! 3 | 4 | #include "common.hlsl" 5 | 6 | float4 main( PS_INPUT i ) : COLOR 7 | { 8 | float4 color = tex2D(TexBase, i.uv); 9 | float depth = 1.0 - color.w; 10 | return float4(depth, depth, depth, 1.0); 11 | } 12 | -------------------------------------------------------------------------------- /shadersrc/template_ps2x.hlsl: -------------------------------------------------------------------------------- 1 | // Template shader that does nothing interesting 2 | 3 | // This contains parameters, etc that all shaders have available 4 | // All shaders should include this 5 | #include "common.hlsl" 6 | 7 | // entry point 8 | float4 main( PS_INPUT i ) : COLOR 9 | { 10 | // copy each framebuffer pixel 1:1 (effectively does nothing) 11 | float4 result = tex2D(TexBase, i.uv.xy); 12 | 13 | return result; 14 | } 15 | -------------------------------------------------------------------------------- /shadersrc/compile_shader_list.txt: -------------------------------------------------------------------------------- 1 | // Add the shaders to compile below here 2 | // NOTE: shaders must be suffixed with _ps2x 3 | 4 | template_ps2x.hlsl 5 | 6 | example_wave_ps2x.hlsl 7 | example_glitch_ps2x.hlsl 8 | example_blackhole_ps2x.hlsl 9 | example_flip_ps2x.hlsl 10 | example_hearts_ps2x.hlsl 11 | example_ascii_ps2x.hlsl 12 | example_square_ps2x.hlsl 13 | example_spin_ps2x.hlsl 14 | example_depth_ps2x.hlsl 15 | example_chromaticaberration_ps2x.hlsl 16 | example_sdf_ps2x.hlsl -------------------------------------------------------------------------------- /shadersrc/example_chromaticaberration_ps2x.hlsl: -------------------------------------------------------------------------------- 1 | // Chromatic Aberration shader 2 | 3 | #include "common.hlsl" 4 | 5 | float4 main( PS_INPUT i ) : COLOR 6 | { 7 | float2 uv = i.uv; 8 | 9 | float2 d = abs((uv - 0.5) * 2.0); 10 | d = pow(d, float2(2.0, 2.0)); 11 | 12 | float4 r = tex2D(TexBase, uv - d * 0.015); 13 | float4 g = tex2D(TexBase, uv); 14 | float4 b = tex2D(TexBase, uv + d * 0.015); 15 | 16 | return float4(r.r, g.g, b.b, 1.0); 17 | } -------------------------------------------------------------------------------- /shadersrc/example_wave_ps2x.hlsl: -------------------------------------------------------------------------------- 1 | // Example shader that applies a wave distortion effect to the screen 2 | 3 | #include "common.hlsl" 4 | 5 | #define Time Constants0.x 6 | #define Frequency Constants0.y 7 | #define Amplitude Constants0.z 8 | 9 | float4 main( PS_INPUT i ) : COLOR 10 | { 11 | float2 offset; 12 | offset.x = sin(i.uv.y * Frequency + Time) * Amplitude; 13 | offset.y = cos(i.uv.x * Frequency + Time * 1.5) * Amplitude; 14 | 15 | float2 new_uv = i.uv + offset; 16 | 17 | return tex2D(TexBase, new_uv); 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Build Current Shader", 9 | "type": "PowerShell", 10 | "request": "launch", 11 | "script": "${workspaceFolder}/shadersrc/bin/process_shaders_single.ps1", 12 | "cwd": "${workspaceFolder}/shadersrc", 13 | "args": [ 14 | "-Version", 15 | "20b", 16 | "${file}" 17 | ] 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /materials/effects/shaders/example_flip.vmt: -------------------------------------------------------------------------------- 1 | screenspace_general 2 | { 3 | $pixshader "example_flip_ps20" 4 | 5 | $basetexture "_rt_FullFrameFB" 6 | $texture1 "" 7 | $texture2 "" 8 | $texture3 "" 9 | 10 | $x360appchooser 1 11 | $ignorez 1 12 | $fix_fb 32768 13 | " 1.0 || uv.y < -1.0 || uv.y > 1.0) 29 | { 30 | col = float4(0.0, 0.0, 0.0, 0.0); 31 | } 32 | else 33 | { 34 | float4 pix = tex2D(Tex1, uv * 0.5 + 0.5); 35 | float alpha = pix.w; 36 | col = pix * sqrt(abs(dot(dir, norm))); 37 | col.w = alpha; 38 | } 39 | 40 | return col; 41 | } 42 | -------------------------------------------------------------------------------- /shadersrc/example_square_ps2x.hlsl: -------------------------------------------------------------------------------- 1 | // Example shader that displays a colored square in the middle of the screen 2 | 3 | #include "common.hlsl" 4 | 5 | bool ContainsSquare(float2 screen_point, float2 square_center, float square_size) 6 | { 7 | float half_size = square_size * 0.5; 8 | return screen_point.x >= (square_center.x - half_size) 9 | && screen_point.x <= (square_center.x + half_size) 10 | && screen_point.y >= (square_center.y - half_size) 11 | && screen_point.y <= (square_center.y + half_size); 12 | } 13 | 14 | float4 main( PS_INPUT i ) : COLOR 15 | { 16 | // background color with full transparency 17 | float4 color = float4(0.0, 0.0, 0.0, 0.0); 18 | 19 | // map from normalized to screen cordinates [0, 1] -> [0, size] 20 | float2 uv = i.uv; 21 | float2 screen_point = uv / TexBaseSize; 22 | 23 | // center of screen in screen coordinates 24 | float square_size = 200.0; 25 | float2 square_center = (1.0 / TexBaseSize) * 0.5; 26 | 27 | // check if pixel is inside the square 28 | if (ContainsSquare(screen_point, square_center, square_size)) 29 | { 30 | color = float4(1.0, 0.0, 0.0, 1.0); 31 | } 32 | 33 | return color; 34 | } 35 | -------------------------------------------------------------------------------- /shadersrc/bin/process_shaders_single.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [Parameter(Mandatory=$true)][System.IO.FileInfo]$File, 4 | [Parameter(Mandatory=$true)][string]$Version, 5 | [Parameter(Mandatory=$false)][System.UInt32]$Threads 6 | ) 7 | 8 | if ($Version -notin @("20b", "30", "40", "41", "50", "51")) { 9 | return 10 | } 11 | 12 | # Create a vmt file from template if it doesn't exist 13 | $baseName = $File.BaseName -replace "_ps2x$", "" 14 | $templatePath = Join-Path $PSScriptRoot "../../materials/effects/shaders/template.vmt" 15 | $vmtPath = Join-Path $PSScriptRoot "../../materials/effects/shaders/$baseName.vmt" 16 | 17 | if ((Test-Path $templatePath) -and -not (Test-Path $vmtPath)) { 18 | $content = Get-Content $templatePath -Raw 19 | $content = $content -replace '\$pixshader\s+"[^"]*"', "`$pixshader `"$baseName`_ps20`"" 20 | Set-Content -Path $vmtPath -Value $content 21 | } 22 | 23 | if ($Threads -ne 0) { 24 | & "$PSScriptRoot\ShaderCompile" "/O" "3" "-threads" $Threads "-ver" $Version "-shaderpath" $File.DirectoryName $File.Name 25 | return 26 | } 27 | 28 | & "$PSScriptRoot\ShaderCompile" "/O" "3" "-ver" $Version "-shaderpath" $File.DirectoryName $File.Name 29 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Build Current Shader", 6 | "type": "shell", 7 | "command": "powershell", 8 | "args": [ 9 | "-NoLogo", 10 | "-ExecutionPolicy", 11 | "Bypass", 12 | "-Command", 13 | "bin\\process_shaders_single.ps1", 14 | "-Version", 15 | "20b", 16 | "${file}" 17 | ], 18 | "group": "build", 19 | "presentation": { 20 | "reveal": "always", 21 | "panel": "shared" 22 | }, 23 | "problemMatcher": [], 24 | "options": { 25 | "cwd": "${workspaceFolder}/shadersrc" 26 | } 27 | }, 28 | { 29 | "label": "Build All Shaders", 30 | "type": "shell", 31 | "command": ".\\build_shaders.bat", 32 | "args": [ 33 | "compile_shader_list" 34 | ], 35 | "problemMatcher": [], 36 | "group": "build", 37 | "presentation": { 38 | "reveal": "always", 39 | "panel": "shared" 40 | }, 41 | "options": { 42 | "cwd": "${workspaceFolder}/shadersrc" 43 | } 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /shadersrc/example_ascii_ps2x.hlsl: -------------------------------------------------------------------------------- 1 | // Example shader that displays pixels as ASCII characters 2 | // Adapted from https://www.shadertoy.com/view/lssGDj 3 | 4 | #include "common.hlsl" 5 | 6 | float character(int n, float2 p) 7 | { 8 | p = floor(p * float2(-4.0, -4.0) + 2.5); 9 | if (clamp(p.x, 0.0, 4.0) == p.x) 10 | { 11 | if (clamp(p.y, 0.0, 4.0) == p.y) 12 | { 13 | int a = int(round(p.x) + 5.0 * round(p.y)); 14 | int s = n / (int)pow(2, a); // n >> a 15 | if ((s % 2) == 1) // & 1 16 | return 1.0; 17 | } 18 | } 19 | return 0.1; // 0.0 is too dark 20 | } 21 | 22 | float4 main( PS_INPUT i ) : COLOR 23 | { 24 | // see below for why this is needed 25 | // https://www.gamedev.net/blogs/entry/1848486-understanding-half-pixel-and-half-texel-offsets/ 26 | float2 half_pix = float2(0.5, 0.5) * TexBaseSize; 27 | 28 | float2 pix = (i.uv + half_pix) * (1.0 / TexBaseSize); 29 | float3 col = tex2D(TexBase, floor(pix / 8.0) * 8.0 / (1.0 / TexBaseSize)).rgb; 30 | 31 | float gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b; 32 | int n = 4096; 33 | if (gray > 0.2) n = 65600; // : 34 | if (gray > 0.3) n = 163153; // * 35 | if (gray > 0.4) n = 15255086; // o 36 | if (gray > 0.5) n = 13121101; // & 37 | if (gray > 0.6) n = 15252014; // 8 38 | if (gray > 0.7) n = 13195790; // @ 39 | if (gray > 0.8) n = 11512810; // # 40 | 41 | float2 p = fmod(pix / 4.0, 2.0) - float2(1.0, 1.0); 42 | return float4(col * character(n, p), 1.0); 43 | } 44 | -------------------------------------------------------------------------------- /shadersrc/bin/process_shaders.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [Parameter(Mandatory=$true, ValueFromPipeline=$true)][System.IO.FileInfo]$File, 4 | [Parameter(Mandatory=$true)][string]$Version, 5 | [Parameter(Mandatory=$false)][System.UInt32]$Threads 6 | ) 7 | 8 | if ($Version -notin @("20b", "30", "40", "41", "50", "51")) { 9 | return 10 | } 11 | 12 | $fileList = $File.OpenText() 13 | while ($null -ne ($line = $fileList.ReadLine())) { 14 | if ($line -match '^\s*$' -or $line -match '^\s*//') { 15 | continue 16 | } 17 | 18 | # Create a vmt file from template for each shader if it doesn't exist 19 | $baseName = [System.IO.Path]::GetFileNameWithoutExtension($line) -replace "_ps2x$", "" 20 | $templatePath = Join-Path $PSScriptRoot "../../../materials/effects/shaders/template.vmt" 21 | $vmtPath = Join-Path $PSScriptRoot "../../../materials/effects/shaders/$baseName.vmt" 22 | 23 | if ((Test-Path $templatePath) -and -not (Test-Path $vmtPath)) { 24 | $content = Get-Content $templatePath -Raw 25 | $content = $content -replace '\$pixshader\s+"[^"]*"', "`$pixshader `"$baseName`_ps20`"" 26 | Set-Content -Path $vmtPath -Value $content 27 | } 28 | 29 | if ($Threads -ne 0) { 30 | & "$PSScriptRoot\ShaderCompile" "/O" "3" "-threads" $Threads "-ver" $Version "-shaderpath" $File.DirectoryName $line 31 | continue 32 | } 33 | 34 | & "$PSScriptRoot\ShaderCompile" "/O" "3" "-ver" $Version "-shaderpath" $File.DirectoryName $line 35 | } 36 | $fileList.Close() 37 | -------------------------------------------------------------------------------- /materials/effects/shaders/example_chromaticaberration.vmt: -------------------------------------------------------------------------------- 1 | screenspace_general 2 | { 3 | // Shader to use 4 | // NOTE: Use '_ps20' suffix only (the engine corrects it to 'ps20b') 5 | $pixshader "example_chromaticaberration_ps20" 6 | 7 | // Textures to use 8 | // Use _rt_FullFrameFB to fetch the screen texture (framebuffer) 9 | $basetexture "_rt_FullFrameFB" 10 | $texture1 "" 11 | $texture2 "" 12 | $texture3 "" 13 | 14 | // Mandatory parameters, do not change these 15 | $x360appchooser 1 16 | $ignorez 1 17 | $fix_fb 32768 18 | " 20 | REM **************** 21 | 22 | setlocal 23 | set arg_filename=%ARG1% 24 | set shadercompilecommand=ShaderCompile.exe 25 | set targetdir=shaders 26 | set SrcDirBase=..\.. 27 | set shaderDir=shaders 28 | set SDKArgs=-local 29 | 30 | if "%ARG1%" == "" goto usage 31 | set inputbase=%ARG1% 32 | 33 | REM ignore -dx9_30 34 | if /i "%ARG6%" == "-dx9_30" shift /6 35 | 36 | if /i "%ARG6%" == "-force30" goto set_force30_arg 37 | goto set_force_end 38 | :set_force30_arg 39 | set IS30=1 40 | goto set_force_end 41 | :set_force_end 42 | 43 | if /i "%ARG2%" == "-game" goto set_mod_args 44 | goto build_shaders 45 | 46 | REM **************** 47 | REM USAGE 48 | REM **************** 49 | :usage 50 | echo. 51 | echo "usage: buildshaders [-game] [gameDir if -game was specified] [-source sourceDir]" 52 | echo " gameDir is where gameinfo.txt is (where it will store the compiled shaders)." 53 | echo " sourceDir is where the source code is (where it will find scripts and compilers)." 54 | echo "ex : buildshaders myshaders" 55 | echo "ex : buildshaders myshaders -game c:\steam\steamapps\sourcemods\mymod -source c:\mymod\src" 56 | goto :end 57 | 58 | REM **************** 59 | REM MOD ARGS - look for -game or the vproject environment variable 60 | REM **************** 61 | :set_mod_args 62 | 63 | if not exist "bin\ShaderCompile.exe" goto NoShaderCompile 64 | set ChangeToDir=%SrcDirBase%\bin\ 65 | 66 | if /i "%ARG4%" NEQ "-source" goto NoSourceDirSpecified 67 | set SrcDirBase=%~5 68 | 69 | REM ** use the -game parameter to tell us where to put the files 70 | set targetdir=%~3\shaders 71 | 72 | if not exist "%inputbase%.txt" goto InvalidInputFile 73 | 74 | goto build_shaders 75 | 76 | REM **************** 77 | REM ERRORS 78 | REM **************** 79 | :InvalidInputFile 80 | echo Error: "%inputbase%.txt" is not a valid file. 81 | goto end 82 | 83 | :NoSourceDirSpecified 84 | echo ERROR: If you specify -game on the command line, you must specify -source. 85 | goto usage 86 | goto end 87 | 88 | :NoShaderCompile 89 | echo - ERROR: ShaderCompile.exe doesn't exist in devtools\bin 90 | goto end 91 | 92 | REM **************** 93 | REM BUILD SHADERS 94 | REM **************** 95 | :build_shaders 96 | 97 | rem echo -------------------------------- 98 | rem echo %inputbase% 99 | rem echo -------------------------------- 100 | REM make sure that target dirs exist 101 | REM files will be built in these targets and copied to their final destination 102 | if not exist %shaderDir% mkdir %shaderDir% 103 | if not exist %shaderDir%\fxc mkdir %shaderDir%\fxc 104 | REM Nuke some files that we will add to later. 105 | 106 | set SHVER=20b 107 | if defined IS30 ( 108 | set SHVER=30 109 | ) 110 | 111 | title %ARG1% %SHVER% 112 | 113 | echo Building inc files and worklist for %inputbase%... 114 | 115 | powershell -NoLogo -ExecutionPolicy Bypass -Command "bin\process_shaders.ps1 -Version %SHVER% '%inputbase%.txt'" 116 | 117 | %TTEXE% -diff %tt_start% 118 | echo Done! 119 | echo. 120 | 121 | REM **************** 122 | REM END 123 | REM **************** 124 | :end 125 | 126 | pause -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sdk_screenspace_shaders 2 | SDK that allows you to easily create custom screenspace pixel shaders for Source games. 3 | 4 | ![screenshot](thumbnail.jpg) 5 | 6 | # Background 7 | It has been discovered that the Source engine supports loading custom pixel shaders, via a completely undocumented shader named `screenspace_general`. 8 | The pixel shaders so far have been proven to work on the following: 9 | - Screen overlays 10 | - Brushes 11 | - Models 12 | - info_overlay 13 | - Decals 14 | - Particles 15 | 16 | Such custom shaders can be packed into maps or downloaded by servers, and it works on both Windows and Linux. 17 | However in Portal 2 and CS:GO, they do not allow loading shaders outside of the `platform` directory, so custom shaders cannot be used by maps or servers there. 18 | Garry's Mod also cannot load custom shaders outside of the main `garrysmod` directory, therefore workshop addons or maps cannot use them. See the [relevant issue](https://github.com/Facepunch/garrysmod-requests/issues/2564). 19 | 20 | This has only been extensively tested on Team Fortress 2 and Counter-Strike: Source, but it should also work for Day of Defeat Source, Half Life 2 etc. 21 | 22 | Left 4 Dead 2 and Portal 2 have an extended version of this shader which also supports setting a custom vertex shader. Setting up a custom vertex shader has not been researched yet. 23 | 24 | # Usage 25 | This repository contains everything required to compile shaders, you do not need to download anything else. 26 | 27 | Go into the `shadersrc` folder and run `build_shaders.bat`. This should build the template and example shaders successfully. 28 | The generated shaders are in the `shaders` folder. You can drag and drop a shader onto the `build_shader.bat` to only compile a specific shader. 29 | 30 | Create a new folder in your game's `custom` folder such as `my_shaders`. 31 | Copy the `shaders` folder to that new folder, then copy the `materials` folder from this repository to your new folder as well. 32 | 33 | Test if the shaders work by loading any map and running this command in console: 34 | `sv_cheats 1;r_screenoverlay effects/shaders/example_wave`. 35 | You should see your screen get deformed in a wavy-like pattern. 36 | 37 | ## Creating a Shader 38 | To create a new shader, copy the `template_ps2x.hlsl` file and rename it to whatever you like. This example will rename it to `coolshader_ps2x.hlsl` (note: do not change the `_ps2x` suffix). 39 | 40 | Add this new shader to the list in `compile_shader_list.txt`. 41 | After you run `build_shaders.bat` again, your new shader should now get compiled. 42 | 43 | Next up, you will need to copy the auto-generated VMT for your shader. Go into `materials/effects/shaders/` and copy the vmt file (e.g. `coolshader.vmt`). You can put this file in your custom `my_shaders` folder using the same `materials/effects/shaders` file structure, or the regular game directory. 44 | 45 | ### VSCode 46 | If you are using VSCode, this repo includes a launch.json and a tasks.json to build the shaders using VSCode's build/debug commands. 47 | 48 | Clone this repository and open the main `sdk_screenspace_shaders` folder in VSCode by going to File > Open Folder. Alternatively you can press Ctrl + K + O or Ctrl + M + O. 49 | 50 | You can now press either Ctrl + Shift + D and select "Build Current Shader". Alternatively, press Ctrl + Shift + B to either build the current shader or all shaders (same as `build_shaders.bat`). 51 | 52 | ## Applying the Shader 53 | Your new shader is now setup, and you can overlay it on players using two methods: 54 | 55 | - `SetScriptOverlayMaterial` (only in TF2 and HL2DM): Fire the `SetScriptOverlayMaterial` input on the !activator with `effects/shaders/coolshader` parameter (or use the equivalent VScript function). 56 | - `r_screenoverlay` : Use a [point_clientcommand](https://developer.valvesoftware.com/wiki/point_clientcommand) and fire the `Command` input with `r_screenoverlay effects/shaders/coolshader` as the parameter on the !activator. 57 | 58 | Note: in TF2 and HL2DM, you can stack shaders across two overlays together using both `SetScriptOverlayMaterial` and `r_screenoverlay`. 59 | 60 | On brushes/info_overlay/decals, change the $basetexture (or whatever texture you are sampling) to your desired brush texture. 61 | 62 | On models, do the same thing as brushes, but also add `$softwareskin 1` and `$translucent 1` to the vmt. Both are required for the shader to work correctly. In the .qc, add `$mostlyopaque` as well. 63 | 64 | ## Modifying the Shader 65 | If you are new to shaders, they are written in a language named HLSL. You can find plenty of guides about this online. This repository comes with multiple example shaders that you can reference. 66 | 67 | The basic overview is that the shader code is run for *every* pixel on the screen. Each shader receives a texture coordinate representing where this pixel is, and it must return the new RGBA color value of the pixel at this position. 68 | 69 | [Shadertoy](https://www.shadertoy.com/) is a good website to look for inspiration or see how things are done. Note that these are written in GLSL, a similar language to HLSL with some differences (see below). 70 | 71 | The screenspace pixel shader provided by the engine comes with support for up to 4 textures and 16 customizable float constants. The textures and constants can be modified dynamically in the VMT (see template.vmt), especially with material proxies. 72 | 73 | To allow the shader to work on anything that isn't a screen overlay, the `$x360appchooser 1` variable must be set (enables vertex transformations, the template sets this to 1 by default). 74 | Unfortunately, in L4D2 and Portal 2 this variable does not exist, therefore vertices are not transformed by the view projection matrix. 75 | This could be workarounded by defining a custom vertex shader (not researched yet). 76 | 77 | ### Porting GLSL to HLSL 78 | 79 | Shaders written in GLSL can be ported to HLSL with some changes as follows. This is not a comprehensive list, there may be more changes required. 80 | 81 | * Different main function form (copy it from the examples) 82 | * `vec2`, `vec3`, `vec4` -> `float2`, `float3`, `float4` 83 | * `mat2`, `mat3`, `mat4` -> `float2x2`, `float3x3`, `float4x4` 84 | * `texture` -> `tex2D` 85 | * `atan` -> `atan2` 86 | * `fract` -> `frac` 87 | * `mix` -> `lerp` 88 | * `fma` -> `mad` 89 | * Constructors need all arguments e.g. `vec3(1.0)` -> `float(1.0, 1.0, 1.0)` 90 | * Origin in GLSL is bottom left. In HLSL it's top left. (UV y coordinate is flipped) 91 | * Shadertoy passes texture coordinates (`fragCoord`) in pixel form (0-width, 0-height). Source passes `baseTextureCoord` in normalized form (0-1, 0-1). The texture dimensions can be recovered using `TexBaseSize` etc. 92 | * GLSL is matrix column-major while HLSL is row-major. Matrices need to be re-ordered (i.e. transposed) 93 | 94 | ## Reloading the Shader 95 | Unfortunately, the shaders cannot be directly reloaded in-game without restarting the game itself. 96 | 97 | But there is a workaround: you can rename a recompiled shader to something else, change the $pixshader in the VMT to this new name, then type `mat_reloadmaterial ` to reload it. 98 | 99 | ## Packing the Shader 100 | If using these in a map: you will need to manually include the shader files if packing with VIDE or CompilePal, as they will not autodetect the files. 101 | 102 | # Limitations 103 | * Custom pixel shaders do not work on DirectX 8. The screen will simply render like normal. 104 | * Source is old and the shaders do not support everything that modern pixel shaders can offer, as the only shader model supported is 2.0b. For example, repeating for-loops don't exist, instead the compiler expands the instructions (which can lead to the instruction limit being hit quickly for large or complex loops). 105 | * Native lightmap is not available if applying these to brush textures (it shouldbe be possible to sample a 2nd texture as the lightmap to workaround this) 106 | * Texture dimension constants are not available in Left 4 Dead 2 and Portal 2 (no workaround known yet) 107 | 108 | # Credits 109 | This repository uses a jerryrigged shader setup from [Source SDK 2013](https://github.com/ValveSoftware/source-sdk-2013) and the [standalone shader compiler](https://github.com/SCell555/ShaderCompile) by SCell555. 110 | Some examples are adapted from [Shadertoy](https://www.shadertoy.com/). --------------------------------------------------------------------------------