summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--2ner.cginc19
-rw-r--r--2ner.shader34
-rw-r--r--Scripts/gen_atlas361
-rw-r--r--disinfo.cginc98
-rw-r--r--features.cginc8
-rw-r--r--globals.cginc26
-rw-r--r--letter_grid.cginc85
-rw-r--r--math.cginc15
-rw-r--r--pema99.cginc5
-rw-r--r--yum_pbr.cginc3
10 files changed, 649 insertions, 5 deletions
diff --git a/2ner.cginc b/2ner.cginc
index e8737a5..d9a5b4b 100644
--- a/2ner.cginc
+++ b/2ner.cginc
@@ -11,6 +11,7 @@
#include "globals.cginc"
#include "harnack_tracing.cginc"
#include "interpolators.cginc"
+#include "letter_grid.cginc"
#include "matcaps.cginc"
#include "poi.cginc"
#include "ssfd.cginc"
@@ -125,6 +126,13 @@ v2f vert(appdata v) {
o.uv01.xy = v.uv0;
o.uv01.zw = v.uv1;
+#if defined(_MIRROR_UVS_IN_MIRROR)
+ [branch]
+ if (isInMirror()) {
+ o.uv01.x = 1.0 - o.uv01.x;
+ o.uv01.z = 1.0 - o.uv01.z;
+ }
+#endif
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
o.objPos = v.vertex;
o.eyeVec.xyz = normalize(o.worldPos - _WorldSpaceCameraPos);
@@ -188,6 +196,13 @@ float4 frag(v2f i
pbr.normal = eye_effect_00.normal;
#endif
+#if defined(_LETTER_GRID)
+ LetterGridOutput letter_grid_output = LetterGrid(i);
+ pbr.albedo.rgb = lerp(pbr.albedo.rgb, letter_grid_output.albedo, letter_grid_output.albedo.a);
+ pbr.metallic = lerp(pbr.metallic, letter_grid_output.metallic, letter_grid_output.albedo.a);
+ pbr.roughness = lerp(pbr.roughness, letter_grid_output.roughness, letter_grid_output.albedo.a);
+#endif
+
[branch]
if (_Mode == 1) {
clip(pbr.albedo.a - _Clip);
@@ -208,7 +223,6 @@ float4 frag(v2f i
l.specular = max(0, l.specular);
#endif
-
pbr.albedo.rgb = visualizeInFalseColor(pbr.albedo.rgb);
float4 lit = YumBRDF(i, l, pbr);
@@ -235,6 +249,9 @@ float4 frag(v2f i
#if defined(_EMISSION) || (defined(_GLITTER) && defined(FORWARD_BASE_PASS)) || defined(OUTLINE_PASS)
lit.rgb += pbr.emission;
#endif
+#if defined(_LETTER_GRID)
+ lit.rgb += letter_grid_output.emission * letter_grid_output.albedo.a;
+#endif
UNITY_EXTRACT_FOG_FROM_EYE_VEC(i);
UNITY_APPLY_FOG(_unity_fogCoord, lit.rgb);
diff --git a/2ner.shader b/2ner.shader
index fdcb3fa..9ccb0b9 100644
--- a/2ner.shader
+++ b/2ner.shader
@@ -476,6 +476,39 @@ Shader "yum_food/2ner"
[HideInInspector] m_end_False_Color_Visualization("False color", Float) = 0
//endex
+ //ifex _Letter_Grid_Enabled==0
+ [HideInInspector] m_start_Letter_Grid("Letter grid", Float) = 0
+ [ThryToggle(_LETTER_GRID)] _Letter_Grid_Enabled("Enable", Float) = 0
+ _Letter_Grid_Texture("Glyph texture", 2D) = "black" {}
+ _Letter_Grid_Tex_Res_X("Glyph X resolution", Float) = 16
+ _Letter_Grid_Tex_Res_Y("Glyph Y resolution", Float) = 8
+ _Letter_Grid_Res_X("Cell X resolution", Range(1, 4)) = 1
+ _Letter_Grid_Res_Y("Cell Y resolution", Range(1, 4)) = 1
+ _Letter_Grid_Data_Row_0("Cell data row 0", Vector) = (0, 0, 0, 0)
+ _Letter_Grid_Data_Row_1("Cell data row 1", Vector) = (0, 0, 0, 0)
+ _Letter_Grid_Data_Row_2("Cell data row 2", Vector) = (0, 0, 0, 0)
+ _Letter_Grid_Data_Row_3("Cell data row 3", Vector) = (0, 0, 0, 0)
+ _Letter_Grid_UV_Scale_Offset("UV scale/offset", Vector) = (1, 1, 0, 0)
+ _Letter_Grid_Padding("Padding", Float) = 0.02
+ _Letter_Grid_Color("Color", Color) = (1, 1, 1, 1)
+ _Letter_Grid_Metallic("Metallic", Range(0, 1)) = 0
+ _Letter_Grid_Roughness("Roughness", Range(0 ,1)) = 0.5
+ _Letter_Grid_Emission("Emission", Range(0 ,1)) = 0.0
+ _Letter_Grid_Mask("Mask", 2D) = "white" {}
+ _Letter_Grid_Global_Offset("Global offset", Float) = 0
+ _Letter_Grid_Screen_Px_Range("Screen px range (from msdfgen)", Float) = 10
+ _Letter_Grid_Min_Screen_Px_Range("Minimum screen px range", Float) = 1
+ _Letter_Grid_Blurriness("Blurriness", Float) = 0.5
+ _Letter_Grid_Alpha_Threshold("Alpha threshold", Range(0, 1)) = 0.5
+ [HideInInspector] m_end_Letter_Grid("Letter grid", Float) = 0
+ //endex
+
+ //ifex _Mirror_UVs_In_Mirror==0
+ [HideInInspector] m_start_Mirror_UVs_In_Mirror("Mirror UVs in mirror", Float) = 0
+ [ThryToggle(_MIRROR_UVS_IN_MIRROR)] _Mirror_UVs_In_Mirror_Enabled("Enable", Float) = 0
+ [HideInInspector] m_end_Mirror_UVs_In_Mirror("Mirror UVs in mirror", Float) = 0
+ //endex
+
//ifex _Vertex_Domain_Warping_Enabled==0
[HideInInspector] m_start_Vertex_Domain_Warping("Vertex domain warping", Float) = 0
[ThryToggle(_VERTEX_DOMAIN_WARPING)]_Vertex_Domain_Warping_Enabled("Enable", Float) = 0
@@ -493,6 +526,7 @@ Shader "yum_food/2ner"
_UV_Domain_Warping_Spatial_Strength("Spatial warping strength", Float) = 0.10
_UV_Domain_Warping_Spatial_Scale("Spatial warping scale", Float) = 0.10
_UV_Domain_Warping_Spatial_Octaves("Spatial warping octaves", Float) = 1.0
+ _UV_Domain_Warping_Spatial_Speed("Spatial warping speed", Float) = 1.0
[HideInInspector] m_end_UV_Domain_Warping("UV domain warping", Float) = 0
//endex
diff --git a/Scripts/gen_atlas b/Scripts/gen_atlas
new file mode 100644
index 0000000..945a51d
--- /dev/null
+++ b/Scripts/gen_atlas
@@ -0,0 +1,361 @@
+#!/usr/bin/env python3
+
+import argparse
+import subprocess
+import os
+import json
+from PIL import Image, ImageDraw
+import random
+
+# Define the character ranges we want to include
+CHAR_RANGES = [
+ (32, 126), # Printable ASCII
+ # Add more ranges here as needed, e.g.:
+ #(160, 255), # Extended Latin
+]
+
+def calculate_grid_size(char_ranges):
+ """Calculate the smallest square grid that fits the highest character code"""
+ max_char = max(end for _, end in char_ranges)
+ grid_size = 1
+ while grid_size * grid_size < max_char:
+ grid_size += 1
+ return grid_size
+
+ATLAS_TYPES = [
+ "hardmask", # binary image
+ "softmask", # anti-aliased image
+ "sdf", # signed distance field
+ "psdf", # perpendicular distance field
+ "msdf", # multi-channel signed distance field
+ "mtsdf" # combined MSDF and true SDF
+]
+
+def calculate_font_size(resolution, base_size=None):
+ """Calculate the font size based on resolution, scaling from 512 resolution"""
+ if base_size is None:
+ base_size = 32 # Default size at 512 resolution
+ return (base_size * resolution) // 512
+
+def generate_atlas(font_path, resolution, draw_grid=False, type="msdf", font_size=None):
+ """Generates a font atlas using various distance field techniques.
+
+ This function creates a font atlas using msdf-atlas-gen, then rearranges the
+ characters to include gaps for non-printable characters. The output is saved
+ as 'atlas.png' in the current directory.
+
+ Args:
+ font_path (str): Path to the input font file (.ttf/.otf)
+ resolution (int): Width and height of the output atlas in pixels
+ draw_grid (bool, optional): If True, draws red grid lines on the output.
+ Defaults to False.
+ type (str, optional): Atlas type to generate. See ATLAS_TYPES.
+ font_size (int, optional): Base font size in pixels at 512 resolution.
+ Will be scaled for other resolutions.
+
+ Returns:
+ bool: True if atlas generation succeeded, False if an error occurred.
+
+ Raises:
+ subprocess.CalledProcessError: If msdf-atlas-gen fails to execute.
+ """
+ # Get font name from path
+ font_name = os.path.splitext(os.path.basename(font_path))[0]
+
+ # Calculate grid size based on character ranges
+ grid_size = calculate_grid_size(CHAR_RANGES)
+ cell_size = resolution // grid_size
+
+ # Calculate font size if not specified, scaling from 512 resolution
+ if font_size is None:
+ font_size = calculate_font_size(resolution)
+ else:
+ font_size = calculate_font_size(resolution, font_size)
+
+ # Convert character ranges to command-line format
+ chars_str = ", ".join(f"[{start}, {end}]" for start, end in CHAR_RANGES)
+
+ # Update the output filename to include resolution
+ output_filename = f"atlas_{font_name}_{resolution}_{type}"
+
+ cmd = [
+ "msdf-atlas-gen/build/bin/Debug/msdf-atlas-gen.exe",
+ "-font", font_path,
+ "-type", type,
+ "-format", "png",
+ "-imageout", f"{output_filename}.png",
+ "-size", str(font_size),
+ "-pxrange", "4",
+ "-dimensions", str(resolution), str(resolution),
+ "-chars", chars_str,
+ "-uniformgrid",
+ "-uniformcols", str(grid_size),
+ "-uniformcell", str(cell_size), str(cell_size),
+ "-errorcorrection", "auto-full",
+ "-scanline",
+ #"-angle", "15d",
+ "-edgecoloring", "distance"
+ ]
+
+ try:
+ print("Running msdf-atlas-gen...")
+ print("Command:", end=" ")
+ for arg in cmd:
+ if arg.startswith('-'):
+ print(f"\n {arg}", end=" ")
+ else:
+ print(arg, end=" ")
+ print()
+ result = subprocess.run(cmd, check=True, capture_output=True, text=True)
+
+ # Print the output
+ if result.stdout:
+ print("msdf-atlas-gen output:")
+ print(result.stdout)
+
+ # Rearrange the atlas to include gaps for non-printable characters
+ print("Rearranging atlas...")
+ rearrange_atlas(resolution, cell_size, cell_size, draw_grid, type, font_name)
+
+ # Generate or update Unity meta file
+ generate_unity_meta(output_filename, resolution)
+ return True
+ except subprocess.CalledProcessError as e:
+ print(f"Error generating atlas: {e}")
+ print(f"Error output: {e.stderr}")
+ return False
+
+def draw_grid_lines(image, resolution):
+ """Draw red grid lines on the image"""
+ draw = ImageDraw.Draw(image)
+ grid_size = calculate_grid_size(CHAR_RANGES)
+
+ # Draw vertical lines
+ for x in range(grid_size):
+ line_x = x * resolution // grid_size
+ draw.line([(line_x, 0), (line_x, resolution-1)], fill=(255, 0, 0), width=1)
+
+ # Draw horizontal lines
+ for y in range(grid_size):
+ line_y = y * resolution // grid_size
+ draw.line([(0, line_y), (resolution-1, line_y)], fill=(255, 0, 0), width=1)
+
+ # Draw the final borders
+ draw.line([(resolution-1, 0), (resolution-1, resolution-1)], fill=(255, 0, 0), width=1)
+ draw.line([(0, resolution-1), (resolution-1, resolution-1)], fill=(255, 0, 0), width=1)
+
+def rearrange_atlas(resolution, cell_width, cell_height, draw_grid=False, type="msdf", font_name=""):
+ """Rearrange the atlas to include gaps for non-printable characters"""
+ # Update input and output filenames to match generate_atlas format
+ input_filename = f"atlas_{font_name}_{resolution}_{type}.png"
+ original = Image.open(input_filename)
+ new_atlas = Image.new('RGBA', (resolution, resolution), (0, 0, 0, 255))
+
+ grid_size = calculate_grid_size(CHAR_RANGES)
+ cell_size = resolution // grid_size
+
+ # Track current position in the source atlas
+ source_index = 0
+
+ # Process each character range
+ for start, end in CHAR_RANGES:
+ for ascii_code in range(start, end + 1):
+ # Calculate source position (original atlas)
+ source_x = (source_index % grid_size) * cell_size
+ source_y = (source_index // grid_size) * cell_size
+
+ # Calculate target position (new atlas)
+ target_x = ((ascii_code + 1) % grid_size) * cell_size
+ target_y = ((ascii_code + 1) // grid_size) * cell_size
+
+ # Extract and paste the glyph
+ glyph = original.crop((
+ source_x,
+ source_y,
+ source_x + cell_size,
+ source_y + cell_size
+ ))
+ new_atlas.paste(glyph, (target_x, target_y))
+ source_index += 1
+
+ # Draw the grid lines only if requested
+ if draw_grid:
+ draw_grid_lines(new_atlas, resolution)
+
+ # Calculate actual used dimensions
+ used_resolution = cell_size * grid_size
+ # Crop to used dimensions and resize back to requested resolution
+ used_atlas = new_atlas.crop((0, 0, used_resolution, used_resolution))
+ final_atlas = used_atlas.resize((resolution, resolution), Image.LANCZOS)
+
+ # Save with the same filename format (no change needed since input/output are the same)
+ final_atlas.save(input_filename)
+ print("Atlas rearranged successfully!")
+
+def generate_unity_meta(basename, resolution):
+ """Generate or update Unity meta file for the atlas texture."""
+ meta_path = f"{basename}.png.meta"
+ existing_guid = None
+
+ # Try to read existing GUID if meta file exists
+ if os.path.exists(meta_path):
+ with open(meta_path, 'r') as f:
+ for line in f:
+ if 'guid: ' in line:
+ existing_guid = line.split('guid: ')[1].strip()
+ break
+
+ # Generate new GUID if none exists
+ guid = existing_guid or ''.join('%x' % random.randrange(16) for _ in range(32))
+
+ meta_template = f'''fileFormatVersion: 2
+guid: {guid}
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {{}}
+ serializedVersion: 12
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: {resolution}
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {{x: 0.5, y: 0.5}}
+ spritePixelsToUnits: 100
+ spriteBorder: {{x: 0, y: 0, z: 0, w: 0}}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: {resolution}
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: {resolution}
+ resizeAlgorithm: 0
+ textureFormat: 3
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: {resolution}
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {{}}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+'''
+
+ with open(meta_path, 'w') as f:
+ f.write(meta_template)
+
+def main():
+ parser = argparse.ArgumentParser(description='Generate a font atlas using msdf-atlas-gen')
+ parser.add_argument('font_path', help='Path to the font file (.ttf/.otf)')
+ parser.add_argument('resolution', type=int, help='Total atlas resolution (width=height)')
+ parser.add_argument('--grid', type=bool, default=False, help='Draw grid lines on the output atlas')
+ parser.add_argument('--type', type=str, default="msdf", choices=ATLAS_TYPES,
+ help='Type of atlas to generate')
+ parser.add_argument('--font-size', type=int, help='Base font size in pixels at 512 resolution. Will be scaled for other resolutions.')
+ args = parser.parse_args()
+
+ # Verify font file exists
+ if not os.path.isfile(args.font_path):
+ print(f"Error: Font file not found at {args.font_path}")
+ return
+
+ generate_atlas(args.font_path, args.resolution, draw_grid=args.grid, type=args.type, font_size=args.font_size)
+
+if __name__ == "__main__":
+ main()
diff --git a/disinfo.cginc b/disinfo.cginc
new file mode 100644
index 0000000..faa9489
--- /dev/null
+++ b/disinfo.cginc
@@ -0,0 +1,98 @@
+#include "globals.cginc"
+
+#ifndef __DISINFO_INC
+#define __DISINFO_INC
+
+/*
+ * A small font rendering library.
+ *
+ * Sample usage:
+ *
+ * fixed4 frag(v2f i) : SV_Target
+ * {
+ * float2 uv = i.uv;
+ * int2 cell_pos;
+ * float2 cell_uv;
+ * float2 res = int2(4, 4);
+ * if (!getBoxLoc(uv, 0.1, 0.9, res, cell_pos, cell_uv)) {
+ * return float4(0, 0, 0, 1);
+ * }
+ * float2 duv = float2(ddx(i.uv.x), ddy(i.uv.y)) / 4;
+ * float4 font_color = renderInBox(67, cell_uv, duv);
+ *
+ * return font_color;
+ * }
+ */
+
+// Returns false if `uv` does not fall within `bounds`.
+bool remapUVSmaller(float2 uv, float2 bottom_left, float2 top_right,
+ out float2 uvr) {
+ if (!(uv.x > bottom_left.x && uv.x < top_right.x &&
+ uv.y > bottom_left.y && uv.y < top_right.y)) {
+ return false;
+ }
+
+ uvr = uv - bottom_left;
+ uvr = uvr / (top_right - bottom_left);
+
+ return true;
+}
+
+// bounds: the left/right/top/bottom bounds of the inner UV region,
+// respectively.
+// Always returns true.
+bool remapUVBigger(float2 uv, float2 bottom_left, float2 top_right,
+ out float2 uvr) {
+ uvr = uv * (top_right - bottom_left) + bottom_left;
+
+ return true;
+}
+
+bool getBoxLoc(float2 uv, float2 bottom_left, float2 top_right,
+ int2 res, float padding, out int2 cell_pos, out float2 cell_uv)
+{
+ float2 box_uv;
+ if (!remapUVSmaller(uv, bottom_left, top_right, box_uv)) {
+ return false;
+ }
+
+ // The integer index of the cell pointed to by `uv`, on the interval
+ // [0, res.x - 1] * [0, res.y - 1]
+ cell_pos = fmod(floor(box_uv * res), res);
+
+ float2 box_sz = 1.0 / float2(res);
+ float2 cell_bot_left = (cell_pos - padding) * box_sz;
+ float2 cell_top_right = (cell_pos + 1 + padding) * box_sz;
+ if (!remapUVSmaller(box_uv, cell_bot_left, cell_top_right, cell_uv)) {
+ // This should never happen Clueless
+ return true;
+ }
+
+ return true;
+}
+
+// `c` is a character encoded as ASCII.
+float4 renderInBox(int c, float2 uv, float2 cell_uv, texture2D font, int2 font_res)
+{
+ int letter_idx = c;
+ int2 letter_pos = int2(
+ font_res.x - (letter_idx % font_res.x),
+ letter_idx / font_res.x);
+ letter_pos.x = font_res.x - letter_pos.x;
+ letter_pos.y = (font_res.y - 1) - letter_pos.y;
+ float2 letter_box_sz = 1.0 / float2(font_res);
+ float2 letter_bot_left = letter_pos * letter_box_sz;
+ float2 letter_top_right = (letter_pos + 1) * letter_box_sz;
+ float2 letter_uv;
+ remapUVBigger(cell_uv, letter_bot_left, letter_top_right, letter_uv);
+
+#if 0
+ float4 font_color = font.Sample(linear_clamp_s, letter_uv);
+#else
+ float4 font_color = font.SampleLevel(linear_repeat_s, letter_uv, 0);
+#endif
+ return font_color;
+}
+
+#endif // __DISINFO_INC
+
diff --git a/features.cginc b/features.cginc
index 2d587be..c22eb99 100644
--- a/features.cginc
+++ b/features.cginc
@@ -192,5 +192,13 @@
#pragma shader_feature_local _GLITTER_MASK
//endex
+//ifex _Letter_Grid_Enabled==0
+#pragma shader_feature_local _LETTER_GRID
+//endex
+
+//ifex _Mirror_UVs_In_Mirror==0
+#pragma shader_feature_local _MIRROR_UVS_IN_MIRROR
+//endex
+
#endif // __FEATURES_INC
diff --git a/globals.cginc b/globals.cginc
index 899f67a..3ab4c53 100644
--- a/globals.cginc
+++ b/globals.cginc
@@ -297,6 +297,7 @@ float _Vertex_Domain_Warping_Temporal_Strength;
float _UV_Domain_Warping_Spatial_Strength;
float _UV_Domain_Warping_Spatial_Scale;
float _UV_Domain_Warping_Spatial_Octaves;
+float _UV_Domain_Warping_Spatial_Speed;
#endif
#if defined(_EYE_EFFECT_00)
@@ -389,4 +390,29 @@ float _False_Color_Visualization_Luminance;
float _False_Color_Visualization_Luminance_Bounded;
#endif // _FALSE_COLOR_VISUALIZATION
+#if defined(_LETTER_GRID)
+texture2D _Letter_Grid_Texture;
+float4 _Letter_Grid_Texture_TexelSize;
+float _Letter_Grid_Tex_Res_X;
+float _Letter_Grid_Tex_Res_Y;
+float _Letter_Grid_Res_X;
+float _Letter_Grid_Res_Y;
+float4 _Letter_Grid_Data_Row_0;
+float4 _Letter_Grid_Data_Row_1;
+float4 _Letter_Grid_Data_Row_2;
+float4 _Letter_Grid_Data_Row_3;
+float4 _Letter_Grid_UV_Scale_Offset;
+float _Letter_Grid_Padding;
+float4 _Letter_Grid_Color;
+float _Letter_Grid_Metallic;
+float _Letter_Grid_Roughness;
+float _Letter_Grid_Emission;
+texture2D _Letter_Grid_Mask;
+float _Letter_Grid_Global_Offset;
+float _Letter_Grid_Screen_Px_Range;
+float _Letter_Grid_Min_Screen_Px_Range;
+float _Letter_Grid_Blurriness;
+float _Letter_Grid_Alpha_Threshold;
+#endif // _LETTER_GRID
+
#endif // __GLOBALS_INC
diff --git a/letter_grid.cginc b/letter_grid.cginc
new file mode 100644
index 0000000..0cd197d
--- /dev/null
+++ b/letter_grid.cginc
@@ -0,0 +1,85 @@
+#ifndef __LETTER_GRID_INC
+#define __LETTER_GRID_INC
+
+#include "disinfo.cginc"
+#include "features.cginc"
+#include "globals.cginc"
+#include "interpolators.cginc"
+#include "math.cginc"
+#include "texture_utils.cginc"
+
+#if defined(_LETTER_GRID)
+
+struct LetterGridOutput {
+ float4 albedo;
+ float metallic;
+ float roughness;
+ float3 emission;
+};
+
+LetterGridOutput LetterGrid(v2f i) {
+ LetterGridOutput output;
+
+ int2 cell_pos;
+ int2 font_res = int2(round(_Letter_Grid_Tex_Res_X), round(_Letter_Grid_Tex_Res_Y));
+ int2 grid_res = int2(round(_Letter_Grid_Res_X), round(_Letter_Grid_Res_Y));
+ float2 cell_uv; // uv within each letter cell
+
+ float4 scoff = _Letter_Grid_UV_Scale_Offset;
+ float2 uv = ((i.uv01.xy - 0.5) - scoff.zw) * scoff.xy + 0.5;
+
+ bool in_box = getBoxLoc(uv, 0, 1, grid_res, _Letter_Grid_Padding, cell_pos, cell_uv);
+
+ // Extract char from _Letter_Grid_Data_Row_0 et al using cell_pos.
+ cell_pos.y = (grid_res.y - cell_pos.y) - 1;
+ float c = lerp(
+ lerp(
+ _Letter_Grid_Data_Row_0[cell_pos.x],
+ _Letter_Grid_Data_Row_1[cell_pos.x],
+ cell_pos.y),
+ lerp(
+ _Letter_Grid_Data_Row_2[cell_pos.x],
+ _Letter_Grid_Data_Row_3[cell_pos.x],
+ cell_pos.y - 2),
+ cell_pos.y/2);
+ c += _Letter_Grid_Global_Offset;
+
+ float3 msd = renderInBox(c, uv, cell_uv, _Letter_Grid_Texture, font_res).rgb;
+ float sd = median(msd);
+
+ // Calculate screen pixel range
+ float screen_px_range;
+ {
+ float2 tex_size = float2(_Letter_Grid_Texture_TexelSize.zw);
+ float2 real_cell_size = floor(tex_size / grid_res); // size of cell in texels
+ float2 unit_range = _Letter_Grid_Screen_Px_Range / real_cell_size;
+ float2 screen_tex_size = 1 / fwidth(cell_uv);
+ screen_px_range = max(0.5 * dot(unit_range, screen_tex_size), _Letter_Grid_Min_Screen_Px_Range);
+ }
+
+ float screen_px_distance = screen_px_range * (sd - _Letter_Grid_Alpha_Threshold);
+ float smooth_range = (length(grid_res) / sqrt(screen_px_range)) * _Letter_Grid_Blurriness;
+ float op = smoothstep(-smooth_range, smooth_range, screen_px_distance);
+
+ // Sample mask if enabled
+ #if defined(_LETTER_GRID_MASK)
+ float mask = _Letter_Grid_Mask.Sample(linear_repeat_s, i.uv01.xy).r;
+ #else
+ float mask = 1.0;
+ #endif
+
+ op *= mask;
+
+ // Apply blending to output
+ output.albedo = float4(_Letter_Grid_Color.rgb, op * in_box);
+ output.metallic = _Letter_Grid_Metallic;
+ output.roughness = _Letter_Grid_Roughness;
+ output.emission = _Letter_Grid_Color.rgb * _Letter_Grid_Emission;
+
+ return output;
+}
+
+#endif // _LETTER_GRID
+
+#endif // __LETTER_GRID_INC
+
diff --git a/math.cginc b/math.cginc
index 2f05054..f44aa74 100644
--- a/math.cginc
+++ b/math.cginc
@@ -55,7 +55,7 @@ float rand3(float3 p)
return frac(rand3_hash(p).x);
}
-float2 domainWarp1(float x, uint octaves, float strength, float scale)
+float2 domainWarp1(float x, uint octaves, float strength, float scale, float speed)
{
[loop]
for (uint i = 0; i < octaves; i++) {
@@ -66,14 +66,14 @@ float2 domainWarp1(float x, uint octaves, float strength, float scale)
return x;
}
-float2 domainWarp2(float2 uv, uint octaves, float strength, float scale)
+float2 domainWarp2(float2 uv, uint octaves, float strength, float scale, float speed)
{
uv *= 0.001;
[loop]
for (uint i = 0; i < octaves; i++) {
uv += strength * frac(sin(float2(
dot(uv * scale, float2(12.9898, 78.233)),
- dot(uv * scale, float2(36.7539, 50.3658))) * 43758.5453123));
+ dot(uv * scale, float2(36.7539, 50.3658)))) * 43758.5453123);
}
uv *= 1000;
return uv;
@@ -198,4 +198,13 @@ float3 luminance(float3 color) {
return dot(color, float3(0.2126, 0.7152, 0.0722));
}
+float median(float3 x) {
+ // Get the min and max.
+ float x_min= min(min(x.r, x.g), x.b);
+ float x_max = max(max(x.r, x.g), x.b);
+
+ // Compute (x.r + x.g + x.b) - (x_min + x_max). This gives us the median.
+ return (x.r + x.g + x.b) - (x_min + x_max);
+}
+
#endif // __MATH_INC
diff --git a/pema99.cginc b/pema99.cginc
index 030772b..0651761 100644
--- a/pema99.cginc
+++ b/pema99.cginc
@@ -27,4 +27,9 @@ SOFTWARE.
#define glsl_mod(x,y) (((x)-(y)*floor((x)/(y))))
+bool isInMirror()
+{
+ return unity_CameraProjection[2][0] != 0.f || unity_CameraProjection[2][1] != 0.f;
+}
+
#endif // __PEMA_99_INC
diff --git a/yum_pbr.cginc b/yum_pbr.cginc
index 85d653e..71d7f2e 100644
--- a/yum_pbr.cginc
+++ b/yum_pbr.cginc
@@ -33,7 +33,8 @@ YumPbr GetYumPbr(v2f i) {
float2 raw_uv = i.uv01.xy;
#if defined(_UV_DOMAIN_WARPING)
i.uv01.xy = domainWarp2(i.uv01.xy, _UV_Domain_Warping_Spatial_Octaves,
- _UV_Domain_Warping_Spatial_Strength, _UV_Domain_Warping_Spatial_Scale);
+ _UV_Domain_Warping_Spatial_Strength, _UV_Domain_Warping_Spatial_Scale,
+ _UV_Domain_Warping_Spatial_Speed);
#endif
#if defined(OUTLINE_PASS)