diff options
| author | yum <yum.food.vr@gmail.com> | 2023-02-02 01:02:03 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2023-02-13 14:36:20 -0800 |
| commit | 7c6894614dcc3ebc5d4c8839b64f4da761b5ccf0 (patch) | |
| tree | 6232b86b09190fd162aeb67229da359971b2e517 | |
| parent | 2fc3b1b978b6e24814e9de7200865b912108bd34 (diff) | |
Begin work adding emotes
Done:
* Users can add images to Fonts/Emotes/
* The basename of that image ('clueless.png' becomes 'clueless') is the
keyword to make the image show up in game.
* Fix a bug in the shader where letters on the 2nd texture and later
would have UV outside of [0.0, 1.0]
Not yet implemented:
* transcribed words are encoded using emotes mapping
| -rw-r--r-- | Fonts/Bitmaps/emotes.png.meta | 116 | ||||
| -rw-r--r-- | Fonts/Emotes/README.md | 11 | ||||
| -rw-r--r-- | GUI/GUI/GUI/PythonWrapper.cpp | 34 | ||||
| -rw-r--r-- | GUI/package.ps1 | 1 | ||||
| -rw-r--r-- | Scripts/emotes.py | 16 | ||||
| -rw-r--r-- | Scripts/emotes_v2.py | 109 | ||||
| -rw-r--r-- | Scripts/generate_shader.py | 6 | ||||
| -rw-r--r-- | Scripts/osc_ctrl.py | 10 | ||||
| -rw-r--r-- | Scripts/transcribe.py | 33 | ||||
| -rw-r--r-- | Shaders/TaSTT_lighting_template.cginc | 55 | ||||
| -rw-r--r-- | Shaders/TaSTT_template.shader | 2 | ||||
| -rw-r--r-- | UnityAssets/Materials/TaSTT_Text.mat | 28 |
12 files changed, 380 insertions, 41 deletions
diff --git a/Fonts/Bitmaps/emotes.png.meta b/Fonts/Bitmaps/emotes.png.meta new file mode 100644 index 0000000..c2bc609 --- /dev/null +++ b/Fonts/Bitmaps/emotes.png.meta @@ -0,0 +1,116 @@ +fileFormatVersion: 2 +guid: 054057c5bf512e842854e6746e754159 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 1 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 1 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + 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 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 4096 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 2 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 4096 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 2 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 4096 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 2 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Fonts/Emotes/README.md b/Fonts/Emotes/README.md new file mode 100644 index 0000000..fb12665 --- /dev/null +++ b/Fonts/Emotes/README.md @@ -0,0 +1,11 @@ +To add emotes to the text box, place one or more .png files in this directory. +The name of the file should be the word you will say in game to make the emote +appear. + +For example,consider the following contents: + + Emotes/smile.png + Emotes/cry.png + +Saying "smile" would cause the image smile.png to show up on the text box. + diff --git a/GUI/GUI/GUI/PythonWrapper.cpp b/GUI/GUI/GUI/PythonWrapper.cpp index c2515e8..72897b7 100644 --- a/GUI/GUI/GUI/PythonWrapper.cpp +++ b/GUI/GUI/GUI/PythonWrapper.cpp @@ -11,6 +11,10 @@ using ::Logging::Log; +namespace { + constexpr const char kEmotesPickle[] = "Resources/Fonts/Bitmaps/emotes.map"; +} // namespace + class PythonProcess : public wxProcess { public: PythonProcess(std::function<void(wxProcess* proc, int ret)>&& exit_callback) : exit_cb_(exit_callback) { @@ -185,6 +189,7 @@ wxProcess* PythonWrapper::StartApp( "--window_duration_s", config.window_duration, "--cpu", config.use_cpu ? "1" : "0", "--use_builtin", config.use_builtin ? "1" : "0", + "--emotes_pickle", kEmotesPickle, }, std::move(exit_callback)); } @@ -199,6 +204,7 @@ bool PythonWrapper::GenerateAnimator( // Python script locations std::string libunity_path = "Resources/Scripts/libunity.py"; std::string libtastt_path = "Resources/Scripts/libtastt.py"; + std::string generate_emotes_path = "Resources/Scripts/emotes_v2.py"; std::string generate_params_path = "Resources/Scripts/generate_params.py"; std::string generate_menu_path = "Resources/Scripts/generate_menu.py"; std::string generate_shader_path = "Resources/Scripts/generate_shader.py"; @@ -263,6 +269,34 @@ bool PythonWrapper::GenerateAnimator( } } { + Log(out, "Generating emotes... "); + + std::string py_stdout, py_stderr; + if (InvokeWithArgs({ generate_emotes_path, + "Resources/Fonts/Emotes/", + /*board_aspect_ratio=*/ std::to_string(6), + /*texture_aspect_ratio=*/ std::to_string(2), + "Resources/Fonts/Bitmaps/emotes.png", + kEmotesPickle + }, + &py_stdout, &py_stderr)) { + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); + if (!py_stdout.empty()) { + Log(out, "\n"); + } + Log(out, py_stderr.c_str()); + if (!py_stderr.empty()) { + Log(out, "\n"); + } + } + else { + wxLogError("Failed to generate emotes: %s", py_stderr.c_str()); + Log(out, "failed!\n"); + return false; + } + } + { Log(out, "Creating {}\n", tastt_generated_dir_path.string()); std::filesystem::create_directories(tastt_generated_dir_path); } diff --git a/GUI/package.ps1 b/GUI/package.ps1 index 96e641e..74fd7c7 100644 --- a/GUI/package.ps1 +++ b/GUI/package.ps1 @@ -62,6 +62,7 @@ mkdir $install_dir/Resources > $null cp -Recurse ../Animations TaSTT/Resources/Animations
mkdir TaSTT/Resources/Fonts
cp -Recurse ../Fonts/Bitmaps TaSTT/Resources/Fonts/Bitmaps
+cp -Recurse ../Fonts/Emotes TaSTT/Resources/Fonts/Emotes
cp -Recurse ../Images TaSTT/Resources/Images
cp -Recurse Python TaSTT/Resources/Python
cp -Recurse PortableGit TaSTT/Resources/PortableGit
diff --git a/Scripts/emotes.py b/Scripts/emotes.py index 0a4ed01..6ae0930 100644 --- a/Scripts/emotes.py +++ b/Scripts/emotes.py @@ -111,16 +111,28 @@ def addImageToTexture(tex: Image, img_path: str, x: int, y:int): def parseArgs(): parser = argparse.ArgumentParser() parser.add_argument("--texture_path", type=str, help="Path to save the generated texture.") + parser.add_argument("--rows", type=str, help="The number of rows on the board") + parser.add_argument("--cols", type=str, help="The number of columns on the board") args = parser.parse_args() - if not args.texture_path: - args.texture_path = "img_texture.png" + if not args.texture_path or not args.rows or not args.cols: + print("--texture_path, --rows, --cols required", file=sys.stderr) + sys.exit(1) return args if __name__ == "__main__": args = parseArgs() + rows = int(args.rows) + cols = int(args.cols) + # board is this much wider than tall + board_aspect_ratio = 2 + # each cell a square divided into `rows`x`cols` is this much wider than tall + cell_aspect_ratio = rows / cols + # each cell is this much wider than tall + board_cell_aspect_ratio = board_aspect_ratio * cell_aspect_ratio + tex = openTexture(args.texture_path) for i in range(0, len(IMG_TEX_DATA)): filename = IMG_TEX_DATA[i][0] diff --git a/Scripts/emotes_v2.py b/Scripts/emotes_v2.py new file mode 100644 index 0000000..195e116 --- /dev/null +++ b/Scripts/emotes_v2.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 + +import argparse +import os +import pickle +import sys + +from math import floor +from PIL import Image +from typing import Any, Dict, List, Tuple + +# The character range [0x0000, 0xDFFF] is reserved for text. +# The range [0xE000, infinity) is left over for emotes. +EMOTES_LETTER_OFFSET = 0xE000 + +def superimpose_image(base_img: Image, overlay_img: Image, position: Tuple[int, int]) -> Image: + base_img.paste(overlay_img, position, overlay_img) + return base_img + +def i_to_pos(i, sm_wd, sm_ht, big_wd, big_ht) -> Tuple[int, int]: + x = i * sm_wd % big_wd + row = floor((i * sm_wd) / big_wd) + y = row * sm_ht + return int(x), int(y) + +def get_images_from_directory(directory_path: str) -> List[Tuple[Any, str]]: + images = [] + for filename in os.listdir(directory_path): + file_path = os.path.join(directory_path, filename) + if os.path.isfile(file_path) and file_path.endswith(".png"): + image = Image.open(file_path) + name = os.path.basename(filename).split('.')[0] + images.append((image, name)) + return images + +def split_resized_image(img, wd: int, ht: int) -> List[Any]: + aspect_ratio = img.width / img.height + width = int(ht * aspect_ratio) + img = img.resize((width, ht)) + + split_images = [] + for i in range(0, img.width, wd): + split_image = img.crop((i, 0, i + wd, ht)) + split_images.append(split_image) + + return split_images + +print(i_to_pos(0, 5, 10, 10, 20)) +print(i_to_pos(1, 5, 10, 10, 20)) +print(i_to_pos(2, 5, 10, 10, 20)) +print(i_to_pos(3, 5, 10, 10, 20)) + +def resize_image_with_aspect_ratio(img: Image, aspect_ratio: float) -> Image: + original_width, original_height = img.size + new_width = int(original_height * aspect_ratio) + new_height = original_height + return img.resize((new_width, new_height)) + +def resize_image_to_height(img: Image, height: int) -> Image: + aspect_ratio = img.width / img.height + new_width = int(height * aspect_ratio) + return img.resize((new_width, height)) + +class EmotesState: + def __init__(self): + self.bits = {} + + def load(self, pickle_path): + with open(pickle_path, 'rb') as f: + self.bits = pickle.load(f) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("dir", type=str, help="directory to get images from") + parser.add_argument("board_aspect_ratio", help="aspect ratio of a cell in the board") + parser.add_argument("texture_aspect_ratio", help="aspect ratio of a cell in the texture") + parser.add_argument("tex_path", type=str, help="path to save the texture to") + parser.add_argument("pickle_path", type=str, help="path to save the texture index to") + args = parser.parse_args() + + directory_path = args.dir + board_aspect_ratio = int(args.board_aspect_ratio) + texture_aspect_ratio = int(args.texture_aspect_ratio) + + base_img = Image.new("RGBA", (4096, 4096), (0, 0, 0, 0)) + images_and_filenames = get_images_from_directory(directory_path) + i = 0 + bits = {} # Dict[str, List[int]] + for img, filename in images_and_filenames: + print(f"Adding {filename}") + img = resize_image_with_aspect_ratio(img, board_aspect_ratio) + img = resize_image_to_height(img, 1024) + img_fragments = split_resized_image(img, int(1024 / texture_aspect_ratio), 1024) + img_bits = [] # List[int] + for img_fragment in img_fragments: + i = i + 1 + img_pos = i_to_pos(i, + 1024 / texture_aspect_ratio, 1024, + 4096, 4096) + print(f"{img_pos}") + superimpose_image(base_img, img_fragment, img_pos) + img_bits.append(EMOTES_LETTER_OFFSET + i) + emote_name = os.path.basename(filename).split('.')[0] + print(f"{emote_name} -> {img_bits}") + bits[emote_name] = img_bits + base_img.save(args.tex_path) + with open(args.pickle_path, 'wb') as f: + pickle.dump(bits, f) + diff --git a/Scripts/generate_shader.py b/Scripts/generate_shader.py index 9ff0bc3..cf113ec 100644 --- a/Scripts/generate_shader.py +++ b/Scripts/generate_shader.py @@ -64,8 +64,8 @@ def generateCgConstants(nbytes: int, nrows: int, ncols: int, prefix: str = "") - # case 1: # ... # -# res |= ((int) _Letter_Row00_Col00_Byte0) << (0 * 8); -# res |= ((int) _Letter_Row00_Col00_Byte1) << (1 * 8); +# res |= ((int) round(_Letter_Row00_Col00_Byte0)) << (0 * 8); +# res |= ((int) round(_Letter_Row00_Col00_Byte1)) << (1 * 8); # continue; # } # } @@ -84,7 +84,7 @@ def generateLetterAccessor(nbytes: int, nrows: int, ncols: int, prefix: str = "" lines.append(prefix + " case {}:".format(col)) for byte in range(0, nbytes): param_name = generate_utils.getShaderParamByRowColByte(row, col, byte) - lines.append(prefix + " res |= ((int) {}) << ({} * 8);".format(param_name, byte)) + lines.append(prefix + " res |= ((int) round({})) << ({} * 8);".format(param_name, byte)) lines.append(prefix + " return res;") lines.append(prefix + " default:") lines.append(prefix + " return 0;") diff --git a/Scripts/osc_ctrl.py b/Scripts/osc_ctrl.py index 93b236b..750059f 100644 --- a/Scripts/osc_ctrl.py +++ b/Scripts/osc_ctrl.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 -import argparse +from emotes_v2 import EmotesState from generate_utils import config -import generate_utils +from math import ceil from paging import MultiLinePager from pythonosc import udp_client -from math import ceil + +import argparse +import generate_utils import time # Based on a couple experiments, this seems like about as fast as we can go @@ -87,7 +89,7 @@ def updateRegion(client, region_idx, letter_encoded): # Sends one slice of `msg` to the board then returns. Slices are sent # in FIFO order; e.g., the most recently spoken words are sent last. # Returns True if done paging, False otherwise. -def pageMessage(osc_state: OscState, msg: str) -> bool: +def pageMessage(osc_state: OscState, msg: str, estate: EmotesState) -> bool: msg_slice, slice_idx = osc_state.pager.getNextSlice(msg) if slice_idx == -1: return True diff --git a/Scripts/transcribe.py b/Scripts/transcribe.py index ee76a0a..3171336 100644 --- a/Scripts/transcribe.py +++ b/Scripts/transcribe.py @@ -1,28 +1,23 @@ #!/usr/bin/env python3 +from datetime import datetime +from emotes_v2 import EmotesState +from functools import partial +from playsound import playsound + import argparse import copy -from datetime import datetime import os import osc_ctrl -from functools import partial import generate_utils -# python3 -m pip install pyaudio -# License: MIT. import pyaudio import numpy as np -# python3 -m pip install playsound==1.2.2 -# License: MIT. -from playsound import playsound import steamvr import string_matcher import sys import threading import time import wave -# python3 -m pip install git+https://github.com/openai/whisper.git -# python3 -m pip install torch -f https://download.pytorch.org/whl/torch_stable.html -# License: MIT. import whisper class Config: @@ -303,14 +298,14 @@ def transcribeAudio(audio_state, model, use_cpu: bool): audio_state.transcribe_no_change_count = 0 audio_state.transcribe_sleep_duration = audio_state.transcribe_sleep_duration_min_s -def sendAudio(audio_state, use_builtin: bool): +def sendAudio(audio_state, use_builtin: bool, estate: EmotesState): while audio_state.run_app == True: text = audio_state.committed_text + " " + audio_state.text if use_builtin: ret = osc_ctrl.pageMessageBuiltin(audio_state.osc_state, text) time.sleep(1.5) else: - ret = osc_ctrl.pageMessage(audio_state.osc_state, text) + ret = osc_ctrl.pageMessage(audio_state.osc_state, text, estate) is_paging = (ret == False) osc_ctrl.indicatePaging(audio_state.osc_state.client, is_paging) @@ -393,7 +388,7 @@ def readControllerInput(audio_state, enable_local_beep: bool, # whisper/__init__.py. Examples: tiny, base, small, medium. def transcribeLoop(mic: str, language: str, model: str, enable_local_beep: bool, use_cpu: bool, use_builtin: bool, - button: str): + button: str, estate: EmotesState): audio_state = getMicStream(mic) audio_state.language = whisper.tokenizer.TO_LANGUAGE_CODE[language] @@ -410,7 +405,7 @@ def transcribeLoop(mic: str, language: str, model: str, transcribe_audio_thd.daemon = True transcribe_audio_thd.start() - send_audio_thd = threading.Thread(target = sendAudio, args = [audio_state, use_builtin]) + send_audio_thd = threading.Thread(target = sendAudio, args = [audio_state, use_builtin, estate]) send_audio_thd.daemon = True send_audio_thd.start() @@ -459,6 +454,7 @@ if __name__ == "__main__": parser.add_argument("--cpu", type=int, help="If set to 1, use CPU instead of GPU") parser.add_argument("--use_builtin", type=int, help="If set to 1, use the text box built into the game.") parser.add_argument("--button", type=str, help="The controller button used to start/stop transcription. E.g. \"left joystick\"") + parser.add_argument("--emotes_pickle", type=str, help="The path to emotes pickle. See emotes_v2.py for details.") args = parser.parse_args() if not args.mic: @@ -482,6 +478,10 @@ if __name__ == "__main__": print("--button required", file=sys.stderr) sys.exit(1) + if not args.emotes_pickle: + print("--emotes_pickle required", file=sys.stderr) + sys.exit(1) + if args.window_duration_s: config.MAX_LENGTH_S = int(args.window_duration_s) @@ -495,11 +495,14 @@ if __name__ == "__main__": else: args.use_builtin = False + estate = EmotesState() + estate.load(args.emotes_pickle) + generate_utils.config.BYTES_PER_CHAR = int(args.bytes_per_char) generate_utils.config.CHARS_PER_SYNC = int(args.chars_per_sync) generate_utils.config.BOARD_ROWS = int(args.rows) generate_utils.config.BOARD_COLS = int(args.cols) transcribeLoop(args.mic, args.language, args.model, args.enable_local_beep, - args.cpu, args.use_builtin, args.button) + args.cpu, args.use_builtin, args.button, estate) diff --git a/Shaders/TaSTT_lighting_template.cginc b/Shaders/TaSTT_lighting_template.cginc index 386a509..15b4e41 100644 --- a/Shaders/TaSTT_lighting_template.cginc +++ b/Shaders/TaSTT_lighting_template.cginc @@ -231,7 +231,8 @@ bool InMarginRounding(float2 uv, float2 margin, float rounding, bool interior) // in the texture being sampled. float2 GetLetter(float2 uv, int nth_letter, float texture_cols, float texture_rows, - float board_cols, float board_rows) + float board_cols, float board_rows, + float margin) { // UV spans from [0,1] to [0,1]. // 'U' is horizontal; cols. @@ -248,11 +249,14 @@ float2 GetLetter(float2 uv, int nth_letter, // 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. - if (CHAR_FRAC_ROW < 0.01 || - CHAR_FRAC_COL < 0.01 || - CHAR_FRAC_ROW > 0.99 || - CHAR_FRAC_COL > 0.99) { - return float2(0, 0); + 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)); @@ -576,17 +580,20 @@ fixed4 frag(v2f i) : SV_Target float texture_cols; float texture_rows; float2 letter_uv; + bool is_emote = false; if (letter < 0xE000) { texture_cols = 128.0; texture_rows = 64.0; - letter_uv = GetLetter(uv_with_margin, letter, texture_cols, texture_rows, NCOLS, NROWS); + letter_uv = GetLetter(uv_with_margin, letter % 0x2000, texture_cols, texture_rows, NCOLS, NROWS, /*margin=*/0.02); } else { + is_emote = true; texture_cols = 8.0; - texture_rows = 8.0; - letter_uv = GetLetter(uv_with_margin, letter, texture_cols, texture_rows, 8, 4); + texture_rows = 4.0; + // This will need to be updated if we create multiple emote textures. + letter_uv = GetLetter(uv_with_margin, letter % 0x2000, texture_cols, texture_rows, NCOLS, NROWS, /*margin=*/0); } - if (letter_uv.x == 0 && letter_uv.y == 0) { + if (letter_uv.x == -1 && letter_uv.y == -1) { discard_text = true; } @@ -626,7 +633,17 @@ fixed4 frag(v2f i) : SV_Target aa_region_x = lerp(0, iddx, aa_region_x / iddx_convex); aa_region_y = lerp(0, iddy, aa_region_y / iddy_convex); - float2 cur_letter_uv = letter_uv + float2(aa_region_x, aa_region_y) * 1; + //float2 cur_letter_uv = letter_uv + float2(aa_region_x, aa_region_y); + float2 cur_letter_uv = letter_uv; + + if (is_emote) { + // Emotes are broken up into several pieces and packed tightly. Thus one + // emote may wrap around the edge of the texture. Clamping near the edge + // of the texture avoids a small line from appearing in the middle of + // these textures. + float epsilon = 0.002; + cur_letter_uv.x = clamp(cur_letter_uv.x, epsilon, 1.0 - epsilon); + } int which_texture = (int) floor(letter / (64 * 128)); [forcecase] switch (which_texture) @@ -652,9 +669,12 @@ fixed4 frag(v2f i) : SV_Target case 6: text += tex2Dgrad(_Font_0xC000_0xDFFF, cur_letter_uv, iddx, iddy); break; - default: + case 7: text += tex2Dgrad(_Img_0xE000_0xE03F, cur_letter_uv, iddx, iddy); break; + default: + // Return some distinctive pattern that will look like a bug. + return fixed4(1, 0, _SinTime[0], 1); } } text /= aa_amount; @@ -662,9 +682,10 @@ fixed4 frag(v2f i) : SV_Target // The edges of each letter cell can be slightly grey due to mip maps. // Detect this and shade it as the background. fixed3 grey = fixed3(.4,.4,.4); - if (f3ltf3(text.rgb, grey) || discard_text) { + if (f3ltf3(text.rgb, grey) || discard_text || is_emote) { + fixed4 bg; if (BG_Enable) { - return light(i, + bg = light(i, BG_BaseColor, BG_NormalMap, BG_NormalStrength, @@ -674,8 +695,12 @@ fixed4 frag(v2f i) : SV_Target BG_Emission_Mask, BG_Emission_Color); } else { - return light(i, Background_Color); + bg = light(i, Background_Color); + } + if (is_emote) { + bg.rgb = lerp(bg.rgb, text.rgb, text.w); } + return bg; } else { return light(i, Text_Color); } diff --git a/Shaders/TaSTT_template.shader b/Shaders/TaSTT_template.shader index 708300e..e92a1bd 100644 --- a/Shaders/TaSTT_template.shader +++ b/Shaders/TaSTT_template.shader @@ -40,7 +40,7 @@ _Font_0x8000_0x9FFF ("_Font 4 (unicode 0x8000 - 0x9FFFF)", 2D) = "white" {}
_Font_0xA000_0xBFFF ("_Font 5 (unicode 0xA000 - 0xBFFFF)", 2D) = "white" {}
_Font_0xC000_0xDFFF ("_Font 6 (unicode 0xC000 - 0xDFFFF)", 2D) = "white" {}
- _Img_0xE000_0xE03F ("_Images 0", 2D) = "white" {}
+ _Img_0xE000_0xE03F ("_Images", 2D) = "white" {}
_TaSTT_Indicator_0("_TaSTT_Indicator_0", float) = 0
_TaSTT_Indicator_1("_TaSTT_Indicator_1", float) = 0
diff --git a/UnityAssets/Materials/TaSTT_Text.mat b/UnityAssets/Materials/TaSTT_Text.mat index 51bf253..2739a4d 100644 --- a/UnityAssets/Materials/TaSTT_Text.mat +++ b/UnityAssets/Materials/TaSTT_Text.mat @@ -19,6 +19,26 @@ Material: m_SavedProperties: serializedVersion: 3 m_TexEnvs: + - BG_BaseColor: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - BG_Emission_Mask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - BG_Metallic: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - BG_NormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - BG_Smoothness: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} - Custom_Background: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} @@ -76,7 +96,7 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _Img_0xE000_0xE03F: - m_Texture: {fileID: 0} + m_Texture: {fileID: 2800000, guid: 054057c5bf512e842854e6746e754159, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _MainTex: @@ -96,7 +116,12 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} m_Floats: + - AA_Amount: 5 + - BG_Enable: 0 + - BG_NormalStrength: 1 + - BG_Smoothness_Invert: 1 - Emissive: 0.1 + - Enable_Dithering: 1 - Enable_Margin_Effect_Squares: 0 - Margin_Rounding_Scale: 0.11 - Margin_Scale: 0.06 @@ -510,6 +535,7 @@ Material: - _UVSec: 0 - _ZWrite: 1 m_Colors: + - BG_Emission_Color: {r: 0, g: 0, b: 0, a: 1} - Background_Color: {r: 0, g: 0, b: 0, a: 1} - Margin_Color: {r: 1, g: 1, b: 1, a: 1} - SpecularTint: {r: 1, g: 1, b: 1, a: 1} |
