summaryrefslogtreecommitdiffstats
path: root/Shaders/STT_text.cginc
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2023-08-09 18:54:17 -0700
committeryum <yum.food.vr@gmail.com>2023-08-09 18:54:17 -0700
commit3bf013dc3b5479f4fbb458d44801403afe0bb1d2 (patch)
treed91ef918797b2036e1005afa1e9b221d293b696f /Shaders/STT_text.cginc
parent1285caf31578d758c2b52b915eedb17cc12a1826 (diff)
Add ray-marched custom chatbox
* Refactor shader code to make development easier. Templates are now as small as possible. * Update scaling code. Use Unity scaling instead of a blendshape. * Check in a fuckton of shader FOSS. Mostly unused. * Update TaSTT.fbx. Now has 6 faces instead of 2.
Diffstat (limited to 'Shaders/STT_text.cginc')
-rw-r--r--Shaders/STT_text.cginc187
1 files changed, 187 insertions, 0 deletions
diff --git a/Shaders/STT_text.cginc b/Shaders/STT_text.cginc
new file mode 100644
index 0000000..1e7a96e
--- /dev/null
+++ b/Shaders/STT_text.cginc
@@ -0,0 +1,187 @@
+#ifndef __STT_TEXT_INC__
+#define __STT_TEXT_INC__
+
+#include "stt_generated.cginc"
+
+float Enable_Dithering;
+
+SamplerState linear_clamp_sampler;
+
+Texture2D _Font_0x0000_0x1FFF;
+float4 _Font_0x0000_0x1FFF_TexelSize;
+Texture2D _Font_0x2000_0x3FFF;
+float4 _Font_0x2000_0x3FFF_TexelSize;
+Texture2D _Font_0x4000_0x5FFF;
+float4 _Font_0x4000_0x5FFF_TexelSize;
+Texture2D _Font_0x6000_0x7FFF;
+float4 _Font_0x6000_0x7FFF_TexelSize;
+Texture2D _Font_0x8000_0x9FFF;
+float4 _Font_0x8000_0x9FFF_TexelSize;
+Texture2D _Font_0xA000_0xBFFF;
+float4 _Font_0xA000_0xBFFF_TexelSize;
+Texture2D _Font_0xC000_0xDFFF;
+float4 _Font_0xC000_0xDFFF_TexelSize;
+Texture2D _Img_0xE000_0xE03F;
+float4 _Img_0xE000_0xE03F_TexelSize;
+
+float2 AddMarginToUV(float2 uv, float2 margin)
+{
+ float2 lo = float2(-margin.x / 2, -margin.y / 2);
+ float2 hi = float2(1.0 + margin.x / 2, 1.0 + margin.y / 2);
+
+ return clamp(lerp(lo, hi, uv), 0.0, 1.0);
+}
+
+// Generate a random number on [0, 1].
+float prng(float2 p)
+{
+ return frac(sin(dot(p, float2(561.0, 885.0))) * 776.2) / 2.0;
+}
+
+bool f3ltf3(fixed3 a, fixed3 b)
+{
+ return a[0] < b[0] &&
+ a[1] < b[1] &&
+ a[2] < b[2];
+}
+
+// Write the nth letter in the current cell and return the value of the
+// pixel.
+// `texture_rows` and `texture_cols` indicate how many rows and columns are
+// in the texture being sampled.
+float2 GetLetterUV(float2 uv, int nth_letter,
+ float texture_cols, float texture_rows,
+ float board_cols, float board_rows,
+ float margin)
+{
+ // UV spans from [0,1] to [0,1].
+ // 'U' is horizontal; cols.
+ // 'V' is vertical; rows.
+ //
+ // I want to divide the mesh into an m x n grid.
+ // I want to know what grid cell I'm in. This is simply u * m, v * n.
+
+ // OK, I know what cell I'm in. Now I need to know how far across it I
+ // am. Produce a float in the range [0, 1).
+ float CHAR_FRAC_COL = uv.x * board_cols - floor(uv.x * board_cols);
+ float CHAR_FRAC_ROW = uv.y * board_rows - floor(uv.y * board_rows);
+
+ // Avoid rendering pixels right on the edge of the slot. If we were to
+ // do this, then that value would get stretched due to clamping
+ // (AddMarginToUV), resulting in long lines on the edge of the display.
+ float lo = margin / 2;
+ float hi = 1.0 - margin / 2;
+ if (margin != 0 &&
+ (CHAR_FRAC_ROW < lo ||
+ CHAR_FRAC_COL < lo ||
+ CHAR_FRAC_ROW > hi ||
+ CHAR_FRAC_COL > hi)) {
+ return float2(-1, -1);
+ }
+
+ float LETTER_COL = fmod(nth_letter, floor(texture_cols));
+ float LETTER_ROW = floor(texture_rows) - floor(nth_letter / floor(texture_cols));
+
+ float LETTER_UV_ROW = (LETTER_ROW + CHAR_FRAC_ROW - 1.00) / texture_rows;
+ float LETTER_UV_COL = (LETTER_COL + CHAR_FRAC_COL) / texture_cols;
+
+ float2 result;
+ result.x = LETTER_UV_COL;
+ result.y = LETTER_UV_ROW;
+
+ return result;
+}
+
+float4 GetLetter(float2 uv) {
+ fixed4 text = fixed4(0, 0, 0, 0);
+ bool discard_text = false;
+
+ uint letter = GetLetterParameter(uv);
+
+ float texture_cols;
+ float texture_rows;
+ float2 letter_uv;
+ bool is_emote = false;
+ if (letter < 0xE000) {
+ letter_uv = GetLetterUV(uv, letter % 0x2000, TEXTURE_NCOLS, TEXTURE_NROWS, BOARD_NCOLS, BOARD_NROWS, /*margin=*/0.02);
+ } else {
+ is_emote = true;
+ texture_cols = 16.0;
+ texture_rows = 8.0;
+ // This will need to be updated if we create multiple emote textures.
+ letter_uv = GetLetterUV(uv, letter % 0x2000, texture_cols, texture_rows, BOARD_NCOLS, BOARD_NROWS, /*margin=*/0);
+ }
+
+ if (letter_uv.x == -1 && letter_uv.y == -1) {
+ discard_text = true;
+ }
+
+ // We use ddx/ddy to get the correct mipmaps of the font textures. This
+ // confers 2 main benefits:
+ // 1. We don't use as much VRAM for distant players.
+ // 2. Glyphs anti-alias much more nicely.
+ const float iddx = ddx(letter_uv.x);
+ const float iddy = ddy(letter_uv.y);
+
+ if (Enable_Dithering && !is_emote) {
+ // Add noise to UV.
+ // Here, iddx and iddy tell us how big the current UV cell is with respect to
+ // screen space (i.e. how many pixels wide it is).
+ float noise = frac(prng(letter_uv) + _Time[0]);
+ letter_uv.x += (noise - 0.5) * iddx / 4.0;
+ letter_uv.y += (noise - 0.5) * iddy / 4.0;
+ }
+
+ int which_texture = (int) floor(letter / (uint) (64 * 128));
+ [forcecase] switch (which_texture)
+ {
+ case 0:
+ // Divide iddx, iddy by 2.0 to remain on a higher-detail mip level for
+ // longer.
+ text += _Font_0x0000_0x1FFF.SampleGrad(linear_clamp_sampler,
+ letter_uv, iddx / 2.0, iddy / 2.0);
+ break;
+ case 1:
+ text += _Font_0x2000_0x3FFF.SampleGrad(linear_clamp_sampler,
+ letter_uv, iddx / 2.0, iddy / 2.0);
+ break;
+ case 2:
+ text += _Font_0x4000_0x5FFF.SampleGrad(linear_clamp_sampler,
+ letter_uv, iddx / 2.0, iddy / 2.0);
+ break;
+ case 3:
+ text += _Font_0x6000_0x7FFF.SampleGrad(linear_clamp_sampler,
+ letter_uv, iddx / 2.0, iddy / 2.0);
+ break;
+ case 4:
+ text += _Font_0x8000_0x9FFF.SampleGrad(linear_clamp_sampler,
+ letter_uv, iddx / 2.0, iddy / 2.0);
+ break;
+ case 5:
+ text += _Font_0xA000_0xBFFF.SampleGrad(linear_clamp_sampler,
+ letter_uv, iddx / 2.0, iddy / 2.0);
+ break;
+ case 6:
+ text += _Font_0xC000_0xDFFF.SampleGrad(linear_clamp_sampler,
+ letter_uv, iddx / 2.0, iddy / 2.0);
+ break;
+ case 7:
+ text += _Img_0xE000_0xE03F.SampleGrad(linear_clamp_sampler,
+ letter_uv, iddx / 2.0, iddy / 2.0);
+ break;
+ default:
+ // Return some distinctive pattern that will look like a bug.
+ return fixed4(1, 0, _SinTime[0], 1);
+ }
+
+ // The edges of each letter cell can be slightly grey due to mip maps.
+ // Detect this and shade it as the background.
+ fixed3 grey = 0.5;
+ if (f3ltf3(text.rgb, grey) || discard_text || is_emote) {
+ return 0;
+ }
+ return fixed4(text.rgb, 1);
+}
+
+#endif // __STT_TEXT_INC__
+