Forked from quizcanners/Unity Fragment Shader Cheat Sheet .cs
Created
February 7, 2020 21:08
-
-
Save smkplus/8df53c7262a91fe4a35a9ffb433b7cf4 to your computer and use it in GitHub Desktop.
To keep snippets of code for Shaders. Just some stuff that I often use but also often forget because brain=poo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html | |
//https://github.com/TwoTailsGames/Unity-Built-in-Shaders/blob/master/CGIncludes/UnityCG.cginc - Most interesting stuff ;) | |
//https://github.com/TwoTailsGames/Unity-Built-in-Shaders/tree/master/CGIncludes | |
//https://docs.unity3d.com/Manual/SL-Shader.html | |
//http://developer.download.nvidia.com/CgTutorial/cg_tutorial_appendix_e.html | |
//https://unity3d.com/how-to/shader-profiling-and-optimization-tips | |
//https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html | |
//http://www.deepskycolors.com/archive/2010/04/21/formulas-for-Photoshop-blending-modes.html | |
//http://www.iquilezles.org/blog/ | |
//Properties | |
[PerRendererData][NoScaleOffset]_MainTex("Albedo", 2D) = "white" {} | |
// Image UI elements throw error in Build if Material(It's Shader) doesn't have _MainTex, so keep it here even if not used. | |
// [PerRendererData] - For UI, to hide it from material inspector; | |
// [NoScaleOffset] - To Hide scale and offset editing window - usefult if the are not utilized in shader | |
// Alternative Default Values: "white", "black", "gray", "bump", "red" | |
_Color("Color", Color) = (1,1,1,1) | |
_SomeSlider("Reflectiveness or something", Range(0,1)) = 0 | |
[HideInInspector]_ProjTexPos("Screen Space Position", Vector) = (0,0,0,0) | |
// [HideInInspector] - no need to show this in inspector | |
_Test("Any value", float) = 1 | |
// MULTICOMPILE & SHADER FEATURE | |
[KeywordEnum(None, Regular, Combined)] _BUMP ("Bump Map", Float) = 0 | |
#pragma shader_feature ___ _BUMP_NONE _BUMP_REGULAR _BUMP_COMBINED | |
//Toggle | |
[Toggle(_BLABLA)] thisDoesntMatter ("Some Bla Bla BLa", Float) = 0 | |
#pragma multi_compile ____ _BLABLA // Will Build all variations. (For changing via script) (___ = Also compile a version without any defines ) | |
#pragma shader_feature _FEATUREA _FEATUREB // Will Build only used variations. (To configure shader in Editor only) | |
//Management | |
// From script you can set this keywords | |
renderer.material.EnableKeyword("_BLABLABLA"); | |
// or | |
Shader.EnableKeyword("_BLABLABLA") | |
// To Apply Offset | |
//#define TRANSFORM_TEX(uv,_NameTex) (uv.xy * _NameTex_ST.xy + _NameTex_ST.zw) | |
uv = uv*_MainTex_ST.xy + _MainTex_ST.zw; // _MainTex_ST needs to be defined in the variables section (not the Parameters section) | |
// Screen Position | |
float4 screenPos : TEXCOORD1; // v2f | |
o.screenPos = ComputeScreenPos(o.pos); // vert | |
float2 screenUV = i.screenPos.xy / i.screenPos.w; // frag (Returns in 01 range (if on screen)) | |
// To do POINT Sampling: | |
float2 pointUV = (floor(uv * _MainTex_TexelSize.zw) + 0.5) * _MainTex_TexelSize.xy; | |
// Pixel Perfect Sampling (https://www.quizcanners.com/single-post/2018/10/03/Pixel-Perfect-Shader) | |
// To Feed _ProjTexPos to UI shader I use (in C# script): | |
var pos = RectTransformUtility.WorldToScreenPoint(mainCamera, rectTransform.position); // can pass null if there is only one camera | |
pos.Scale(new Vector2(1f / Screen.width, 1f / Screen.height)); | |
Vector2 scale = rect.rect.size; | |
scale = new Vector2(Mathf.Max(0, (scale.x - scale.y) / scale.x), Mathf.Max(0, (scale.y - scale.x) / scale.y)); // Scale is for rounded courners | |
material.SetVector("_ProjTexPos", pos.ToVector4(scale)); | |
// In Fragment | |
float2 inPix = (screenUV - _ProjTexPos.xy)*_ScreenParams.xy; // _ProjTexPos - UV position on screen of lower left edge (optional) | |
// _ScreenParams.xy - a Unity provided global variable (But you still need to declare it) | |
float2 texUV = inPix * _ProjTex_TexelSize.xy; // * _TexName_TexelSize - float4 Provided By Unity | |
//Optionally: | |
// If more then one texture needs to be sampled this way replace the previous line with | |
float2 tex1UV = inPix * tex1_TexelSize.xy | |
float2 tex2UV = inPix * tex2_TexelSize.xy | |
//if screen UV is the center of the object | |
texUV += 0.5; | |
// if There is a change that texture may have resolution that is not divisible by two: | |
texUV += _ProjTex_TexelSize.xy*0.5*(fmod(_ProjTex_TexelSize.zw, 2)); | |
// For sampling you can use tex2Dlod since mip level will always be 0: | |
float4 col = tex2Dlod(_ProjTex, float4(texUV,0,0)); // Without lod Unity shader will have additional calculations for mip level (I think) | |
// Scaling Non Power of 2 texture to fit inside a square quad. (Keeping the correct relation of width and height) | |
// *To scale texture to fill the quad replace max with min | |
// v2f: | |
float2 mainTexScale : TEXCOORD8; | |
// vert: | |
float relation = _MainTex_TexelSize.w / _MainTex_TexelSize.z; | |
o.mainTexScale.x = max(1, relation); | |
o.mainTexScale.y = max(1, 1 / relation); | |
// frag: | |
float2 scaledUV = ((i.texcoord.xy-0.5) * i.mainTexScale.xy) + 0.5; | |
//* Note: The way Unity UI works is, if it looks like edges are being cut from your UI, set "Mesh Type" to "Full Rect" | |
// in import settings of your sprite. | |
// Smooth Pixelation Sampling | |
const float sharpness = 40; | |
float2 perfTex = (floor(IN.uv_MainTex.xy*_MainTex_TexelSize.z) + 0.5) * _MainTex_TexelSize.x; | |
float2 off = (IN.uv_MainTex.xy - perfTex); | |
float2 diff = (abs(off) * _MainTex_TexelSize.z); | |
float2 edge = saturate((diff * 2 - 1)*sharpness + 1); | |
perfTex += off * edge; | |
float2 diff = (abs(off) * _MainTex_TexelSize.z); | |
// To Also get the border: | |
edge = saturate((diff * 2 - 1)*sharpness*0.1 + 1); // In some usages the are between pixels contains other pixels, then border needs to be less sharp to fully cover that area. | |
float border = max(edge.x, edge.y); | |
// To Get MipLevel | |
_MainTex_TexelSize.zw *= modifier; // Optional | |
float2 px = _MainTex_TexelSize.z * ddx(uv); | |
float2 py = _MainTex_TexelSize.w * ddy(uv); | |
return (max(0, 0.5 * log2(max(dot(px, px), dot(py, py))))); | |
// Parallax | |
//vert: | |
float3x3 objectToTangent = float3x3( | |
v.tangent.xyz, | |
cross(v.normal, v.tangent.xyz) * v.tangent.w, | |
v.normal | |
); | |
tangentViewDir = mul(objectToTangent, ObjSpaceViewDir(v.vertex)); | |
//frag | |
tangentViewDir = normalize(tangentViewDir); | |
i.tangentViewDir.xy /= (i.tangentViewDir.z + 0.42); | |
i.uv.xy += tangentViewDir.xy; | |
// Rounded Courners (i.texcootd.zw can be reaplced with _ProjTexPos.zw from above. If this shader is used with Pix Perfect Projection) | |
// struct v2f | |
float4 texcoord : TEXCOORD2; | |
// Vert: | |
float2 scale = _MainTex_TexelSize.zw; | |
o.texcoord.zw = float2 (max(0, (scale.x - scale.y) / scale.x), max(0, (scale.y - scale.x) / scale.y)); | |
// Frag | |
// Stretch | |
float _Blur = (1 - i.color.a); // Using UI component color to fade out | |
float2 uv = abs(i.texcoord.xy - 0.5) * 2; | |
uv = max(0, uv - i.texcoord.zw) / (1 - i.texcoord.zw); | |
// Courners | |
uv -= _Courners; | |
float deCourners = 1 - _Courners; | |
uv = max(0, uv) / deCourners; | |
uv *= uv; | |
col.a = saturate((1 - uv.x - uv.y) * 20 * (1 - _Blur)*deCourners); | |
// Stretch Part Without texture (using object's scale transform): | |
// script: | |
Vector2 scale = transform.localScale; | |
if (stretch.x > 0) | |
stretch.x = scale.x > scale.y ? ((scale.x - scale.y) / scale.x) : 0; | |
else stretch.x = 0; | |
if (scale.y > 0) | |
stretch.y = scale.y > scale.x ? ((scale.y - scale.x) / scale.y) : 0; | |
else stretch.y = 0; | |
// Feed to material | |
renderer.material.SetVector("_Stretch", stretch); | |
// frag: | |
// Stretch | |
float2 uv = abs(i.texcoord.xy - 0.5) * 2; | |
uv -= _Stretch; | |
float2 upStretch = 1 - _Stretch; | |
uv = max(0, uv) / upStretch; | |
// Courners | |
// .... Same as Courners part above | |
// Fit Sprite Sampling to Fill Screen Without stretching the texture: | |
// In script: | |
float screenAspect = ((float)Screen.width) / Screen.height; | |
float texAspect = ((float)bgTex.width) / bgTex.height; | |
Vector2 aspectCorrection = Vector2.one; | |
if (screenAspect > texAspect) | |
aspectCorrection.y = (texAspect / screenAspect); | |
else | |
aspectCorrection.x = (screenAspect / texAspect); | |
// In Shader | |
float2 uv = (screenUV.xy - 0.5)*aspectCorrection.xy + 0.5; | |
// Tile/ Offset | |
float4 _MainTex_TexelSize; // Texture Size (zw = width,heigth ; xy = 1/width, 1/height) | |
uniform float4 _MainTex_ST; // Tile Offset | |
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); // Tile Offset needs to be declared (the line above) | |
// View Direction | |
float3 viewDir : TEXCOORD0; | |
o.viewDir.xyz = (WorldSpaceViewDir(v.vertex)); | |
i.viewDir.xyz = normalize(i.viewDir.xyz); | |
// World Normal | |
o.normal.xyz = normalize(UnityObjectToWorldNormal(v.normal)); // can be done if vert | |
// World Position | |
float3 wpos : TEXCOORD3; | |
o.wpos = mul(unity_ObjectToWorld, v.vertex).xyz; | |
// ------- To Modify In World Space: | |
v.vertex += mul(unity_WorldToObject, offx,offy,offz, 0); | |
// Reflect: | |
float dotprod = max(0, dot(worldNormal, i.viewDir.xyz)); | |
float3 reflected = normalize(i.viewDir.xyz - 2 * (dotprod)*worldNormal); | |
// Tangent Transformation: | |
float3 tspace0 : TEXCOORD3; | |
float3 tspace1 : TEXCOORD4; | |
float3 tspace2 : TEXCOORD5; | |
// ...... vert | |
float3 wTangent = UnityObjectToWorldDir(v.tangent.xyz); | |
float tangentSign = v.tangent.w * unity_WorldTransformParams.w; | |
float3 wBitangent = cross(wNormal, wTangent) * tangentSign; | |
o.tspace0 = half3(wTangent.x, wBitangent.x, wNormal.x); | |
o.tspace1 = half3(wTangent.y, wBitangent.y, wNormal.y); | |
o.tspace2 = half3(wTangent.z, wBitangent.z, wNormal.z); | |
// ..... frag | |
worldNormal.x = dot(i.tspace0, tnormal); | |
worldNormal.y = dot(i.tspace1, tnormal); | |
worldNormal.z = dot(i.tspace2, tnormal); | |
// Shadow | |
SHADOW_COORDS(2) | |
TRANSFER_SHADOW(o); | |
float shadow = SHADOW_ATTENUATION(i); | |
// Color Bleed (https://www.quizcanners.com/single-post/2018/04/02/Color-Bleeding-in-Shader) | |
float3 mix = col.gbr + col.brg; | |
col.rgb += mix * mix*amount; | |
// Rotation | |
float2 rotUV = i.texcoord.xy - 0.5; | |
float si = sin(angle); | |
float co = cos(angle); | |
float tx = rotUV.x; | |
float ty = rotUV.y; | |
rotUV.x = (co * tx) - (si * ty); | |
rotUV.y = (si * tx) + (co * ty); | |
rotUV += 0.5; | |
// Get Angle in 01 space | |
const float PI2 = 3.14159265359 * 2; | |
float angle = atan2(-uv.x, -uv.y)+0.001; | |
angle = saturate(max(angle, | |
PI2 + min(0, angle) | |
- max(0, angle*999999) | |
)/ PI2); | |
// Change Between two textures/Colors/States etc using Unity's time | |
float lerp = (_CosTime.z + 1) * 0.5; // Time.x,y,z,w - from slowest to fastest | |
// Lerp between two transparent textures | |
float rgbLerp = col2.a*lerp; | |
rgbLerp = saturate(rgbLerp * 2 / (col.a + rgbLerp + 0.0001)); // Add some value to avoid division by 0 | |
col.a = col2.a * lerp + col.a * (1 - lerp); | |
col.rgb = col2.rgb * rgbLerp + col.rgb * (1 - rgbLerp); | |
// Color Light Bleed Effect | |
float3 mix = col.gbr + col.brg; | |
col.rgb += mix * mix*0.02; // Arbitrary value |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment