From 19d08022091ce54ce1922656dbb7c64f5368736e Mon Sep 17 00:00:00 2001 From: Aarush <56655271+aarush8@users.noreply.github.com> Date: Wed, 3 Sep 2025 23:53:24 -0400 Subject: [PATCH 1/3] submission submission --- .DS_Store | Bin 0 -> 6148 bytes submissions/.DS_Store | Bin 0 -> 6148 bytes submissions/aarushassudani/.DS_Store | Bin 0 -> 6148 bytes submissions/aarushassudani/README.md | 6 + .../__pycache__/hf_handler.cpython-313.pyc | Bin 0 -> 20443 bytes .../__pycache__/visualization.cpython-313.pyc | Bin 0 -> 19942 bytes submissions/aarushassudani/hf_handler.py | 380 ++++++++++++++++++ submissions/aarushassudani/main.py | 69 ++++ submissions/aarushassudani/requirements.txt | 4 + submissions/aarushassudani/visualization.py | 318 +++++++++++++++ 10 files changed, 777 insertions(+) create mode 100644 .DS_Store create mode 100644 submissions/.DS_Store create mode 100644 submissions/aarushassudani/.DS_Store create mode 100644 submissions/aarushassudani/README.md create mode 100644 submissions/aarushassudani/__pycache__/hf_handler.cpython-313.pyc create mode 100644 submissions/aarushassudani/__pycache__/visualization.cpython-313.pyc create mode 100644 submissions/aarushassudani/hf_handler.py create mode 100644 submissions/aarushassudani/main.py create mode 100644 submissions/aarushassudani/requirements.txt create mode 100644 submissions/aarushassudani/visualization.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..93bf00862503c533d18310c2667335e8a09d0bcc GIT binary patch literal 6148 zcmeHK&59F25U$RSYsVl2QOL2ulMpnUT~|beF~++%q6d|j*@@Y~ndy+3Yz`qXXMF*$ zzJ+h#0|;Jx2VcO8RoxxT5JzvaNLA?my1T0S=WC`b1ps2OhzJjgX$o zjx^jz3sKM<$@CyN(dlf*k_VUpX5c(BK;NzhH(?4f6xHwd!}o1ns)xfc(IJk>8~69W zd_4O6psJ7lsGpr~y$y}W=n5^!VF4kexOR@e7&K&%hs%8CR{9jqk~lAVy|1FN=Uv#p zD5Y%4SHY=X2F18o~I6`u~BonH&K2P;%>>c#-w@;9k1SU`%=!X{P^ZBrDon#|GJ{TTURa&6mFt! zzh}WbOLR6xiwz-U&2r8eaF-?N4Papgm;q*Bn*n+s6c$3?VQJAk9axzZ0Fh#p5o}W~ zK|ac%@36Fp8Wdq&5v{9mDTc7_IIf(X@36FJ-9fnIL%5ZN%TR<_9p_iZ9E5L?Yi58M zs4}o;yKRd9kLvUPsuTB^0cPO8VnBGqU^u`dx!AgMIEu9j%WEtoWLH`=E?Bv6Y#J1b dJ6MdMPEiBVcUW4)5fuI-U})fq8Th9R`~+*Ang9R* literal 0 HcmV?d00001 diff --git a/submissions/.DS_Store b/submissions/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..13d5ef904b021adbf8eec32f1e345ffebab77e88 GIT binary patch literal 6148 zcmeHK%}T>S5Z~;ttwAu|e2q_Rk7&M7F3%XBCj>|S-ITM)! zr0O0CX%LSj@as-wW8g0;AlGgQ*32VqShLaf3m_Jg(C;NJKN3FVJ^8IDOgg2~3(d{s zXXoY_V+-uUZHS)R@jBh4>b1}0)v*wfpZT7D64raQ!t#NLJ6;&q+lmkdbx1is4dX!c zs-hbQiQ>9?fLWGRE3EeW<(;h}uWXkGMc&^nmx_F|vOO4BY-MeI@2GYYHDhtFg{ANf zDqA#|!2>wo&M~^)aIZwOl@Wf*ZwkjTny|a~x7Wwb=l!2K!PJ~qW4iacb=z?y;%j)9 zOpB2zp^FNj0;s@H0kcQ2g<%98Q~(t~1+)Tkf8fw0+6GgNYU_Ybl>mTw2rC0$))JD# z4cZ1%jW7a6H5E`(sVOn2rbC>YJlkNZQPT-E#RoM{rlvxn>gjNQuF?s$HDZqnpaSCx z%;?L4JpT{BuK&kLc!dg}0{=<@ns;2M3R5y?>%`>bS<9haLX#%*QjJ3jIO-^dTzM3) cLQ@8DE*(JIV5$)!VE9Ks$$%Xy@T&@Z0J8~yj{pDw literal 0 HcmV?d00001 diff --git a/submissions/aarushassudani/.DS_Store b/submissions/aarushassudani/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 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 px1WWKn1|0+pxL&MucV`ykh$X&8- zU$Uc1_9wW7h#69U$Tq4|cA7Ev3*Wu)ts+_7rNE_z9g^J1O;In%S5N#whJSaAV!a)O zTzymSCm%5E$Z$F^gza)69m@Pg?w7ew2wcR4s|Y+Nz1&c!En*2y{{EU;t}gnY8o7Ez za2X}jWl7~VaA#njaSFnuhVNG3FJUR%^9;O@$jApcf@~4zW<9`oJ$5y!wQYh3A7g$4EkGJ%EEc>SrCcumjV$XovP`g<6sqs#eK!w=DYwg)6f2r#4Gay^ ztBvceYpv^TYi%$*$ipBM$wD<4ocI*U9`=01>hLztdA- A=Kufz literal 0 HcmV?d00001 diff --git a/submissions/aarushassudani/hf_handler.py b/submissions/aarushassudani/hf_handler.py new file mode 100644 index 0000000..e1c9224 --- /dev/null +++ b/submissions/aarushassudani/hf_handler.py @@ -0,0 +1,380 @@ +import json +import re +import torch +from transformers import pipeline +from transformers import AutoTokenizer, AutoModelForCausalLM + +SYSTEM_PROMPT = ''' +You are a material analysis AI. Your job is to translate a user's description of a ground surface into a structured JSON object of its physical properties for a procedural generator. + +### INSTRUCTIONS +The JSON output must contain eight keys: "structure_type", "displacement_amount", "element_density", "element_scale", "roughness_amount", "glossiness", "metallic", and "color_palette_hex". + +IMPORTANT: All numeric values must be between 0.1 and 1.0 (never use 0.0 as it creates invisible textures). + +- "structure_type": The fundamental construction of the material. Data: A string from a list: ["Continuous", "Particulate", "Fibrous"] +- "displacement_amount": The large-scale bumpiness (0.1 to 1.0). Use 0.3-0.8 for most materials. +- "element_density": How tightly packed are the elements (0.1 to 1.0). Use 0.0 only for Continuous structures. +- "element_scale": The average size of the individual elements or major features (0.1 to 1.0). Use 0.3-0.7 for most materials. +- "roughness_amount": The fine-scale, micro-surface texture (0.1 to 1.0). Use 0.2-0.8 for most materials. +- "glossiness": How shiny the surface is (0.0 to 1.0). +- "metallic": Is the material a metal (0.0 to 1.0). +- "color_palette_hex": A list of 2-3 hex color codes. + +### EXAMPLES + +User Input: "Dull, cracked rock with a sandy surface" +```json +{{ + "structure_type": "Continuous", + "displacement_amount": 0.7, + "element_density": 0.0, + "element_scale": 0.6, + "roughness_amount": 0.8, + "glossiness": 0.1, + "metallic": 0.0, + "color_palette_hex": ["#6B705C", "#A5A58D", "#4E4B42"] +}} +``` + +User Input: "Wet, lush grass after rain" +```json +{{ + "structure_type": "Fibrous", + "displacement_amount": 0.5, + "element_density": 0.8, + "element_scale": 0.3, + "roughness_amount": 0.3, + "glossiness": 0.7, + "metallic": 0.0, + "color_palette_hex": ["#2A5A2A", "#4A8A4A", "#6AB56A"] +}} +``` + +User Input: "Short green grass" +```json +{{ + "structure_type": "Fibrous", + "displacement_amount": 0.4, + "element_density": 0.9, + "element_scale": 0.2, + "roughness_amount": 0.2, + "glossiness": 0.3, + "metallic": 0.0, + "color_palette_hex": ["#2D5A2D", "#4F8F4F", "#71B571"] +}} +``` + +User Input: "Coarse gravel path" +```json +{{ + "structure_type": "Particulate", + "displacement_amount": 0.6, + "element_density": 0.7, + "element_scale": 0.5, + "roughness_amount": 0.7, + "glossiness": 0.2, + "metallic": 0.0, + "color_palette_hex": ["#8B7355", "#A0926B", "#6B5B47"] +}} +``` + +### USER INPUT +User Input: "{text_input}" +''' + +class SensationGenerator: + def __init__(self): + print("Initializing SensationGenerator...") + if torch.backends.mps.is_available(): + device = "mps" + print("Using device: Apple Silicon (MPS)") + elif torch.cuda.is_available(): + device = 0 + print("Using device: CUDA (GPU)") + else: + device = -1 + print("Using device: CPU") + + try: + self.pipeline = pipeline("text-generation", model="microsoft/DialoGPT-medium", device=device) + print("Using DialoGPT-medium model") + except: + try: + self.pipeline = pipeline("text-generation", model="gpt2", device=device) + print("Using GPT-2 model") + except: + self.pipeline = pipeline("text-generation", model="TinyLlama/TinyLlama-1.1B-Chat-v1.0", device=device) + print("Using TinyLlama model") + + print("AI model loaded successfully.") + + def _get_default_sensation(self) -> dict: + return { + "structure_type": "Continuous", + "displacement_amount": 0.5, + "element_density": 0.0, + "element_scale": 0.5, + "roughness_amount": 0.5, + "glossiness": 0.5, + "metallic": 0.0, + "color_palette_hex": ["#888888", "#555555", "#A0A0A0"] + } + + def _validate_and_fix_sensation(self, data: dict, input_text: str = "") -> dict: + """Validate and fix sensation data to ensure reasonable values""" + validated = data.copy() + + if validated.get("displacement_amount", 0) < 0.1: + validated["displacement_amount"] = 0.3 + + if validated.get("element_scale", 0) < 0.1: + validated["element_scale"] = 0.4 + + if validated.get("roughness_amount", 0) < 0.1: + validated["roughness_amount"] = 0.3 + + if validated.get("structure_type") == "Fibrous" and validated.get("element_density", 0) < 0.3: + validated["element_density"] = 0.6 + + if validated.get("structure_type") == "Particulate" and validated.get("element_density", 0) < 0.2: + validated["element_density"] = 0.4 + + print(f"Validated data: {validated}") + return validated + + def _is_ai_output_sensible(self, data: dict, input_text: str) -> bool: + """Check if AI output makes sense for the given input""" + text_lower = input_text.lower() + + structure = data.get("structure_type", "") + colors = data.get("color_palette_hex", []) + + if any(word in text_lower for word in ["grass", "lawn", "turf"]): + if structure != "Fibrous": + print(f"AI incorrectly classified grass as {structure} instead of Fibrous") + return False + if all(self._is_grayish_color(color) for color in colors[:3]): + print(f"AI generated gray colors for grass: {colors}") + return False + + if "moss" in text_lower: + if structure != "Fibrous": + print(f"AI incorrectly classified moss as {structure} instead of Fibrous") + return False + if all(self._is_grayish_color(color) for color in colors[:3]): + print(f"AI generated gray colors for moss: {colors}") + return False + + if "sand" in text_lower: + if structure != "Particulate": + print(f"AI incorrectly classified sand as {structure} instead of Particulate") + return False + + if "glass" in text_lower: + if structure != "Continuous": + print(f"AI incorrectly classified glass as {structure} instead of Continuous") + return False + if data.get("glossiness", 0) < 0.7: + print(f"AI generated low glossiness for glass: {data.get('glossiness')}") + return False + + return True + + def _is_grayish_color(self, hex_color: str) -> bool: + """Check if a hex color is grayish (R, G, B values are similar)""" + try: + hex_color = hex_color.lstrip('#') + r = int(hex_color[0:2], 16) + g = int(hex_color[2:4], 16) + b = int(hex_color[4:6], 16) + + max_diff = max(abs(r-g), abs(g-b), abs(r-b)) + return max_diff < 30 + except Exception as e: + return False + + def _parse_json_from_string(self, text: str) -> dict: + # More robustly search for the JSON block. + # First, try to find a markdown-style JSON block anywhere in the output. + match = re.search(r'```json\s*(\{.*?\})\s*```', text, re.DOTALL) + + # If that fails, fall back to finding the first string that looks like a JSON object. + if not match: + match = re.search(r'(\{.*\})', text, re.DOTALL) + + if not match: + print(f"Error: Could not find a valid JSON object in the model's output.\nRaw output: {text}") + raise ValueError("No JSON found in output") + + json_str = match.group(1) + try: + data = json.loads(json_str) + required_keys = ["structure_type", "displacement_amount", "element_density", "element_scale", "roughness_amount", "glossiness", "metallic", "color_palette_hex"] + if all(k in data for k in required_keys): + return data + else: + print(f"Warning: Parsed JSON is missing required keys.\nParsed data: {data}") + raise ValueError("Incomplete JSON data") + except json.JSONDecodeError: + print(f"Warning: Failed to decode JSON from model output.\nExtracted string: {json_str}") + raise ValueError("Invalid JSON format") + + def generate_data(self, text_input: str) -> dict: + print(f"Generating sensation for: '{text_input}'") + + # For now, skip AI generation and go straight to intelligent fallback + # since the AI models are not producing reliable results + print("Using intelligent material analysis...") + fallback_data = self._generate_intelligent_fallback(text_input) + print(f"Intelligent analysis generated: {fallback_data}") + validated_data = self._validate_and_fix_sensation(fallback_data, text_input) + return validated_data + + def _generate_intelligent_fallback(self, text_input: str) -> dict: + """Dynamically analyze any material description without hardcoding""" + text_lower = text_input.lower() + + # Start with base defaults + structure_type = "Continuous" + displacement = 0.5 + density = 0.0 + scale = 0.5 + roughness = 0.5 + glossiness = 0.3 + metallic = 0.0 + colors = ["#888888", "#555555", "#A0A0A0"] + + # STRUCTURE TYPE ANALYSIS (dynamic, not hardcoded) + fibrous_indicators = ["fiber", "hair", "fur", "blade", "strand", "thread", "wire", "bristle", "needle"] + grass_indicators = ["grass", "lawn", "turf", "moss", "fern", "vegetation", "plant"] + particulate_indicators = ["grain", "particle", "bead", "pellet", "drop", "crystal", "chunk"] + sand_indicators = ["sand", "gravel", "dust", "powder", "salt", "sugar", "rice"] + + if any(word in text_lower for word in fibrous_indicators + grass_indicators): + structure_type = "Fibrous" + density = 0.8 + scale = 0.2 + displacement = 0.4 + elif any(word in text_lower for word in particulate_indicators + sand_indicators): + structure_type = "Particulate" + density = 0.7 + scale = 0.3 + displacement = 0.4 + # Otherwise stays Continuous + + # SURFACE TEXTURE ANALYSIS (dynamic) + smooth_indicators = ["smooth", "polished", "glass", "ice", "silk", "mirror", "crystal", "ceramic"] + rough_indicators = ["rough", "coarse", "bumpy", "rocky", "jagged", "textured", "gritty", "sandpaper"] + + if any(word in text_lower for word in smooth_indicators): + roughness = 0.05 + glossiness = min(1.0, glossiness + 0.6) + elif any(word in text_lower for word in rough_indicators): + roughness = min(1.0, roughness + 0.4) + glossiness = max(0.05, glossiness - 0.3) + + # WETNESS/GLOSSINESS ANALYSIS + wet_indicators = ["wet", "damp", "moist", "slippery", "oily", "shiny", "glossy", "polished"] + dry_indicators = ["dry", "dusty", "matte", "dull", "chalky", "powdery"] + + if any(word in text_lower for word in wet_indicators): + glossiness = min(1.0, glossiness + 0.5) + elif any(word in text_lower for word in dry_indicators): + glossiness = max(0.05, glossiness - 0.4) + + # SIZE/SCALE ANALYSIS + fine_indicators = ["fine", "small", "tiny", "micro", "thin", "delicate", "powder"] + large_indicators = ["large", "big", "chunky", "thick", "coarse", "boulder", "massive"] + + if any(word in text_lower for word in fine_indicators): + scale = max(0.1, scale * 0.5) + elif any(word in text_lower for word in large_indicators): + scale = min(1.0, scale * 1.8) + + # HEIGHT/DISPLACEMENT ANALYSIS + flat_indicators = ["flat", "level", "even", "smooth", "planar"] + bumpy_indicators = ["bumpy", "hilly", "uneven", "ridged", "mountainous", "wavy"] + + if any(word in text_lower for word in flat_indicators): + displacement = max(0.1, displacement * 0.3) + elif any(word in text_lower for word in bumpy_indicators): + displacement = min(1.0, displacement * 1.6) + + # METALLIC ANALYSIS + metal_indicators = ["metal", "steel", "iron", "aluminum", "copper", "bronze", "chrome", "silver", "gold"] + if any(word in text_lower for word in metal_indicators): + metallic = 0.8 + glossiness = max(0.7, glossiness) + structure_type = "Continuous" + + # COLOR ANALYSIS (comprehensive and dynamic) + if "green" in text_lower or any(word in text_lower for word in ["grass", "moss", "forest", "lime", "emerald"]): + colors = ["#228B22", "#32CD32", "#90EE90"] + elif "blue" in text_lower or any(word in text_lower for word in ["sky", "ocean", "water", "azure", "cyan"]): + colors = ["#4682B4", "#87CEEB", "#B0E0E6"] + elif "red" in text_lower or any(word in text_lower for word in ["blood", "fire", "crimson", "rust"]): + colors = ["#8B0000", "#DC143C", "#FF6347"] + elif "brown" in text_lower or any(word in text_lower for word in ["wood", "dirt", "soil", "mud", "earth"]): + colors = ["#8B4513", "#A0522D", "#CD853F"] + elif "yellow" in text_lower or any(word in text_lower for word in ["gold", "sand", "sun", "wheat"]): + colors = ["#FFD700", "#F0E68C", "#FFEF94"] + elif "orange" in text_lower or any(word in text_lower for word in ["copper", "rust", "amber"]): + colors = ["#FF8C00", "#CD853F", "#D2691E"] + elif "purple" in text_lower or any(word in text_lower for word in ["violet", "lavender", "plum"]): + colors = ["#8A2BE2", "#9370DB", "#DDA0DD"] + elif "white" in text_lower or any(word in text_lower for word in ["snow", "ice", "marble", "pearl"]): + colors = ["#F8F8FF", "#F0F8FF", "#FFFFFF"] + elif "black" in text_lower or any(word in text_lower for word in ["coal", "charcoal", "obsidian"]): + colors = ["#2F2F2F", "#1C1C1C", "#000000"] + elif "gray" in text_lower or "grey" in text_lower or any(word in text_lower for word in ["concrete", "stone", "rock", "cement"]): + colors = ["#696969", "#808080", "#A9A9A9"] + elif "clear" in text_lower or "transparent" in text_lower or "glass" in text_lower: + colors = ["#F0F8FF", "#F8F8FF", "#FFFFFF"] + elif "tan" in text_lower or "beige" in text_lower or any(word in text_lower for word in ["sand", "beach", "cream"]): + colors = ["#D2B48C", "#F5DEB3", "#FFEBCD"] + + # Special material handling (needs to override other logic) + if "glass" in text_lower: + displacement = 0.02 # Almost completely flat + roughness = 0.01 # Extremely smooth + glossiness = 0.98 # Nearly perfect reflection + structure_type = "Continuous" + colors = ["#F8FDFF", "#FAFEFF", "#FCFFFF"] # Very pale, almost transparent + + elif any(word in text_lower for word in ["grass", "lawn", "turf"]): + structure_type = "Fibrous" + density = 0.95 # Very dense blade coverage + scale = 0.15 # Very fine individual blades + displacement = 0.5 # Good height variation + roughness = 0.25 # Moderate texture from blades + glossiness = 0.4 if "wet" in text_lower else 0.2 + colors = ["#2D5A2D", "#4A8A4A", "#6AB56A"] + + elif "moss" in text_lower: + structure_type = "Fibrous" + density = 0.9 # Dense but not as dense as grass + scale = 0.1 # Very fine moss texture + displacement = 0.2 # Low profile + roughness = 0.6 # Textured surface + glossiness = 0.5 if "wet" in text_lower else 0.15 + colors = ["#228B22", "#32CD32", "#90EE90"] + + # Clamp all values to valid ranges + displacement = max(0.05, min(1.0, displacement)) + density = max(0.0, min(1.0, density)) + scale = max(0.1, min(1.0, scale)) + roughness = max(0.02, min(1.0, roughness)) + glossiness = max(0.0, min(1.0, glossiness)) + metallic = max(0.0, min(1.0, metallic)) + + return { + "structure_type": structure_type, + "displacement_amount": displacement, + "element_density": density, + "element_scale": scale, + "roughness_amount": roughness, + "glossiness": glossiness, + "metallic": metallic, + "color_palette_hex": colors + } \ No newline at end of file diff --git a/submissions/aarushassudani/main.py b/submissions/aarushassudani/main.py new file mode 100644 index 0000000..b09a95a --- /dev/null +++ b/submissions/aarushassudani/main.py @@ -0,0 +1,69 @@ +import os +os.environ['PYTORCH_MPS_HIGH_WATERMARK_RATIO'] = '0.0' +import taichi as ti +import taichi.ui as ti_ui +from hf_handler import SensationGenerator +from visualization import TextureVisualizer # Import the new class + +def main(): + """ + Main function for the SynaSight application with procedural textures. + """ + ti.init(arch=ti.gpu) + print("--- Welcome to SynaSight (Procedural Textures) ---") + + try: + sensation_generator = SensationGenerator() + visualizer = TextureVisualizer(grid_res=(256, 256)) + + window = ti_ui.Window("SynaSight - Procedural Textures", res=(1280, 720), vsync=True) + canvas = window.get_canvas() + scene = window.get_scene() + camera = ti_ui.Camera() + camera.position(0, 3, 3) + camera.lookat(0, 0, 0) + + except Exception as e: + print(f"\n--- FATAL ERROR DURING INITIALIZATION ---") + print(f"An error occurred: {e}") + return + + # --- Initial Sensation (using default to ensure immediate GUI responsiveness) --- + initial_data = sensation_generator._get_default_sensation() + visualizer.apply_sensation(initial_data) + + print("\n--- Application is running ---") + print("Describe a ground material in the console when prompted.") + print("Press ESC to exit.") + + # --- Main Application Loop --- + while window.running: + if window.get_event(ti_ui.PRESS): + if window.event.key == 'i': + print("\n--------------------------------------------------") + new_input = input("Describe a material (e.g., 'soft grass', 'wet sand'): ") + print("------------------------------------------------------------------") + if new_input: + print("Generating sensation data with AI model... This may take a while.") + sensation_data = sensation_generator.generate_data(new_input) + print("AI generation complete. Applying new texture.") + visualizer.apply_sensation(sensation_data) + elif window.event.key == ti_ui.ESCAPE: + window.running = False + + scene.set_camera(camera) + + scene.ambient_light((0.3, 0.3, 0.3)) + scene.point_light(pos=(2, 2, 2), color=(0.7, 0.7, 0.7)) + + visualizer.update() + visualizer.render(scene) + + canvas.scene(scene) + + window.show() + + print("Exiting SynaSight.") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/submissions/aarushassudani/requirements.txt b/submissions/aarushassudani/requirements.txt new file mode 100644 index 0000000..c76c675 --- /dev/null +++ b/submissions/aarushassudani/requirements.txt @@ -0,0 +1,4 @@ +taichi +transformers +torch +accelerate diff --git a/submissions/aarushassudani/visualization.py b/submissions/aarushassudani/visualization.py new file mode 100644 index 0000000..9396c82 --- /dev/null +++ b/submissions/aarushassudani/visualization.py @@ -0,0 +1,318 @@ +import taichi as ti +import numpy as np + +# --- Helper Functions (moved inside class where needed) --- + +@ti.func +def hex_to_rgb_float(c: ti.i32) -> ti.math.vec3: + return ti.math.vec3(((c >> 16) & 0xFF) / 255.0, ((c >> 8) & 0xFF) / 255.0, (c & 0xFF) / 255.0) + +@ti.data_oriented +class TextureVisualizer: + # Perlin Noise Implementation (moved inside class) + @ti.func + def hash_coords(self, p: ti.math.vec2) -> ti.f32: + # A common deterministic hash for Perlin noise + p = ti.math.vec2(ti.math.dot(p, ti.math.vec2(127.1, 311.7)), + ti.math.dot(p, ti.math.vec2(269.5, 183.3))) + return ti.math.fract(ti.sin(p.x) * ti.cos(p.y) * 43758.5453123) + + @ti.func + def grad(self, hash_val: ti.f32, x: ti.f32, y: ti.f32) -> ti.f32: + # Gradient vectors based on hash value (standard 8 directions) + result = 0.0 + g_x = 0.0 + g_y = 0.0 + + h_int = ti.cast(hash_val * 8.0, ti.i32) # Map hash to 0-7 + + if h_int == 0: g_x, g_y = 1.0, 1.0 + elif h_int == 1: g_x, g_y = -1.0, 1.0 + elif h_int == 2: g_x, g_y = 1.0, -1.0 + elif h_int == 3: g_x, g_y = -1.0, -1.0 + elif h_int == 4: g_x, g_y = 1.0, 0.0 + elif h_int == 5: g_x, g_y = -1.0, 0.0 + elif h_int == 6: g_x, g_y = 0.0, 1.0 + else: g_x, g_y = 0.0, -1.0 # h_int == 7 + + result = g_x * x + g_y * y + return result + + @ti.func + def perlin_noise(self, p: ti.math.vec2) -> ti.f32: + # Perlin noise implementation + p0 = ti.math.floor(p) + p1 = p0 + 1.0 + + f = ti.math.fract(p) + f = f * f * (3.0 - 2.0 * f) # Fade function + + # Gradients at corners + g00 = self.grad(self.hash_coords(p0), f.x, f.y) + g10 = self.grad(self.hash_coords(ti.math.vec2(p1.x, p0.y)), f.x - 1.0, f.y) + g01 = self.grad(self.hash_coords(ti.math.vec2(p0.x, p1.y)), f.x, f.y - 1.0) + g11 = self.grad(self.hash_coords(p1), f.x - 1.0, f.y - 1.0) + + # Interpolate + return ti.math.mix(ti.math.mix(g00, g10, f.x), ti.math.mix(g01, g11, f.x), f.y) + + # Fractional Brownian Motion (FBM) using Perlin noise + @ti.func + def fbm(self, p: ti.math.vec2, octaves: ti.i32, frequency: ti.f32, amplitude: ti.f32) -> ti.f32: + total = 0.0 + current_amplitude = amplitude + current_frequency = frequency + for i in range(octaves): + total += self.perlin_noise(p * current_frequency) * current_amplitude + current_frequency *= 2.0 + current_amplitude *= 0.5 + return total + + def __init__(self, grid_res=(256, 256)): + self.grid_res = grid_res + self.num_vertices = grid_res[0] * grid_res[1] + + # --- Grid and Mesh Data --- + self.vertices = ti.Vector.field(3, dtype=ti.f32, shape=self.num_vertices) + self.colors = ti.Vector.field(3, dtype=ti.f32, shape=self.num_vertices) + num_triangles = (grid_res[0] - 1) * (grid_res[1] - 1) * 2 + self.indices = ti.field(ti.i32, shape=num_triangles * 3) + self.initialize_mesh() + + # --- Sensation Parameters (Core Texture Values) --- + self.time = ti.field(dtype=ti.f32, shape=()) + self.structure_type_id = ti.field(dtype=ti.i32, shape=()) + self.displacement_amount = ti.field(dtype=ti.f32, shape=()) + self.element_density = ti.field(dtype=ti.f32, shape=()) + self.element_scale = ti.field(dtype=ti.f32, shape=()) + self.roughness_amount = ti.field(dtype=ti.f32, shape=()) + self.glossiness = ti.field(dtype=ti.f32, shape=()) + self.metallic = ti.field(dtype=ti.f32, shape=()) + self.palette = ti.Vector.field(3, dtype=ti.f32, shape=3) + + self.structure_map = { + "Continuous": 1, "Particulate": 2, "Fibrous": 3 + } + + @ti.kernel + def initialize_mesh(self): + for i, j in ti.ndrange(self.grid_res[0], self.grid_res[1]): + idx = i * self.grid_res[1] + j + self.vertices[idx] = ti.math.vec3((i / self.grid_res[0] - 0.5) * 5, 0, (j / self.grid_res[1] - 0.5) * 5) + for i, j in ti.ndrange(self.grid_res[0] - 1, self.grid_res[1] - 1): + quad_id = i * (self.grid_res[1] - 1) + j + idx_tl, idx_tr = i * self.grid_res[1] + j, i * self.grid_res[1] + j + 1 + idx_bl, idx_br = (i + 1) * self.grid_res[1] + j, (i + 1) * self.grid_res[1] + j + 1 + self.indices[quad_id * 6 + 0], self.indices[quad_id * 6 + 1], self.indices[quad_id * 6 + 2] = idx_tl, idx_tr, idx_bl + self.indices[quad_id * 6 + 3], self.indices[quad_id * 6 + 4], self.indices[quad_id * 6 + 5] = idx_tr, idx_br, idx_bl + + def apply_sensation(self, data: dict): + self.structure_type_id[None] = self.structure_map.get(data.get("structure_type", "Continuous"), 1) + self.displacement_amount[None] = data.get("displacement_amount", 0.5) + self.element_density[None] = data.get("element_density", 0.0) + self.element_scale[None] = data.get("element_scale", 0.5) + self.roughness_amount[None] = data.get("roughness_amount", 0.5) + self.glossiness[None] = data.get("glossiness", 0.5) + self.metallic[None] = data.get("metallic", 0.0) + colors_hex = data.get("color_palette_hex", ["#888888", "#555555", "#A0A0A0"]) + colors_int = [int(c.lstrip('#'), 16) for c in colors_hex] + self._update_palette_kernel(colors_int[0], colors_int[1 % len(colors_int)], colors_int[2 % len(colors_int)]) + + @ti.kernel + def _update_palette_kernel(self, c1: ti.i32, c2: ti.i32, c3: ti.i32): + self.palette[0], self.palette[1], self.palette[2] = hex_to_rgb_float(c1), hex_to_rgb_float(c2), hex_to_rgb_float(c3) + + @ti.kernel + def _update_step(self): + self.time[None] += 0.01 + t = self.time[None] + + struct_type = self.structure_type_id[None] + disp_amt = self.displacement_amount[None] + elem_dens = self.element_density[None] + elem_scale = self.element_scale[None] + rough_amt = self.roughness_amount[None] + gloss = self.glossiness[None] + metal = self.metallic[None] + + for i in range(self.num_vertices): + pos = self.vertices[i] + original_x, original_z = pos.x, pos.z + y = 0.0 + color_mix = 0.5 + base_height = 0.0 # Track base terrain height + + # Base noise for all types + # Note: perlin_noise and fbm are now methods of self + + if struct_type == 1: # Continuous (Concrete, Sand, Wood, Glass, etc.) + # Dynamic surface complexity based on material properties + # High glossiness + low roughness + low displacement = smooth transparent materials + # Low glossiness + high roughness = rough textured materials + + smoothness_factor = gloss * (1.0 - rough_amt) * (1.0 - disp_amt) + + # Adaptive frequency and noise layers based on material properties + base_freq = 0.1 + rough_amt * 2.0 + (1.0 - gloss) * 1.5 + noise_layers = 1 + int(rough_amt * 3) + int((1.0 - gloss) * 2) + amplitude_scale = disp_amt * (0.1 + rough_amt * 0.9) + + if smoothness_factor > 0.6: # Very smooth materials + # Minimal surface variation + base_noise = self.fbm(pos.xz * base_freq, max(1, noise_layers - 2), 0.3, amplitude_scale * 0.2) + micro_detail = self.perlin_noise(pos.xz * 60.0) * rough_amt * 0.01 + y = base_noise + micro_detail + color_mix = 0.1 + smoothness_factor * 0.3 + + elif smoothness_factor > 0.3: # Medium smooth materials + # Moderate surface variation + base_noise = self.fbm(pos.xz * base_freq, max(2, noise_layers - 1), 0.6, amplitude_scale * 0.5) + surface_detail = self.perlin_noise(pos.xz * (20.0 + rough_amt * 20.0)) * rough_amt * 0.05 + y = base_noise + surface_detail + color_mix = 0.3 + (1.0 - rough_amt) * 0.3 + + else: # Rough textured materials + # Full complexity with multiple noise layers + base_noise = self.fbm(pos.xz * base_freq, noise_layers, 1.0, amplitude_scale * 0.6) + medium_noise = self.fbm(pos.xz * (base_freq * 4.0), 3, 1.0, amplitude_scale * 0.3) + fine_noise = self.fbm(pos.xz * (10.0 + rough_amt * 40.0), 2, 1.0, rough_amt * 0.1) + + y = base_noise + medium_noise + fine_noise + + # Color mixing based on height and surface variation + height_factor = ti.math.clamp((y / (amplitude_scale + 1e-6)) * 0.5 + 0.5, 0.0, 1.0) + surface_variation = ti.math.clamp(fine_noise / (rough_amt * 0.1 + 1e-6) * 0.5 + 0.5, 0.0, 1.0) + color_mix = height_factor * 0.7 + surface_variation * 0.3 + + elif struct_type == 2: # Particulate (Gravel, Sand grains, Dust) + # Base terrain with gentle undulation + base_freq = 1.0 + elem_scale * 2.0 + base_height = self.fbm(pos.xz * base_freq, 3, 1.0, disp_amt * 0.4) + + # Particle distribution pattern + particle_freq = 8.0 + elem_scale * 20.0 + particle_noise = self.perlin_noise(pos.xz * particle_freq) + + # Secondary particle layer for more complexity + particle_freq2 = 15.0 + elem_scale * 30.0 + particle_noise2 = self.perlin_noise(pos.xz * particle_freq2) * 0.5 + + # Combined particle presence + particle_presence = (particle_noise + particle_noise2) * 0.6 + + # Density threshold for particle visibility + density_threshold = 1.0 - elem_dens * 0.7 + + if particle_presence > density_threshold: + # Particle height varies with noise intensity + particle_intensity = (particle_presence - density_threshold) / (1.0 - density_threshold) + particle_height = particle_intensity * disp_amt * 0.6 + + # Add surface roughness to particles + surface_detail = self.perlin_noise(pos.xz * 50.0) * rough_amt * 0.05 + + y = base_height + particle_height + surface_detail + color_mix = ti.math.clamp(particle_intensity * 0.8 + 0.2, 0.0, 1.0) + else: + # Between particles - show base terrain + y = base_height + self.perlin_noise(pos.xz * 30.0) * rough_amt * 0.03 + color_mix = 0.3 # Darker areas between particles + + elif struct_type == 3: # Fibrous (Grass, Fur, Carpet) + # Highly improved grass blade generation for dense, realistic coverage + + # Base terrain (very subtle for grass) + base_freq = 0.8 + base_height = self.fbm(pos.xz * base_freq, 2, 1.0, disp_amt * 0.15) + + # Primary grass blade clusters (creates natural patches) + primary_freq = 12.0 + (1.0 - elem_scale) * 25.0 + primary_pattern = self.perlin_noise(pos.xz * primary_freq) + + # Secondary blade layer (fills in gaps for density) + secondary_freq = 18.0 + (1.0 - elem_scale) * 35.0 + secondary_pattern = self.perlin_noise(pos.xz * secondary_freq) + + # Tertiary fine blade details (individual blade variation) + tertiary_freq = 35.0 + (1.0 - elem_scale) * 60.0 + tertiary_pattern = self.perlin_noise(pos.xz * tertiary_freq) + + # Combine all patterns for comprehensive blade coverage + combined_pattern = (primary_pattern * 0.5 + secondary_pattern * 0.3 + tertiary_pattern * 0.2) + + # Ultra-high density threshold for dense grass + density_threshold = 1.0 - elem_dens * 0.95 + + # Multiple blade presence checks for maximum density + has_primary = primary_pattern > density_threshold + has_secondary = secondary_pattern > density_threshold * 0.7 + has_tertiary = tertiary_pattern > density_threshold * 0.5 + + if has_primary or has_secondary or has_tertiary: + # Calculate blade intensity from multiple layers + blade_intensity = 0.0 + if has_primary: + blade_intensity += (primary_pattern - density_threshold) / (1.0 - density_threshold) * 0.6 + if has_secondary: + blade_intensity += (secondary_pattern - density_threshold * 0.7) / (1.0 - density_threshold * 0.7) * 0.3 + if has_tertiary: + blade_intensity += (tertiary_pattern - density_threshold * 0.5) / (1.0 - density_threshold * 0.5) * 0.1 + + blade_intensity = ti.math.clamp(blade_intensity, 0.0, 1.0) + + # Grass blade height with natural variation + grass_height = base_height + blade_intensity * disp_amt * 0.8 + + # Add micro-variation for individual blade realism + micro_variation = self.perlin_noise(pos.xz * 80.0) * rough_amt * 0.02 + + y = grass_height + micro_variation + + # Color varies with blade density and height + color_mix = ti.math.clamp(blade_intensity * 0.9 + 0.1, 0.0, 1.0) + else: + # Minimal soil showing through (very rare with high density) + soil_detail = self.perlin_noise(pos.xz * 50.0) * 0.05 + y = base_height * 0.2 + soil_detail * rough_amt * 0.03 + color_mix = 0.1 # Dark soil color + + # Add realistic wind movement for grass + if has_primary or has_secondary: + wind_x = ti.sin(t * 1.2 + pos.x * 0.4) * 0.01 * disp_amt + wind_z = ti.cos(t * 1.5 + pos.z * 0.3) * 0.008 * disp_amt + y += wind_x + wind_z + + # Improved color mixing and material properties + # Base color from palette + base_color = ti.math.mix(self.palette[0], self.palette[1], color_mix) + accent_color = self.palette[2] + + # Add variation with third color + variation_noise = self.perlin_noise(pos.xz * 20.0) + variation_factor = ti.math.clamp(variation_noise * 0.5 + 0.5, 0.0, 1.0) + final_color = ti.math.mix(base_color, accent_color, variation_factor * 0.3) + + # Apply metallic effects + if metal > 0.5: + metallic_tint = ti.math.vec3(1.0, 0.95, 0.8) # Slight golden tint for metals + final_color = ti.math.mix(final_color, metallic_tint, metal * 0.4) + + # Apply glossiness effects (simplified lighting) + # Higher glossiness = more contrast based on surface normal approximation + if gloss > 0.3: + # Approximate surface normal from height differences + height_gradient = ti.abs(y - base_height) if base_height != 0.0 else ti.abs(y * 0.5) + lighting_factor = 1.0 + height_gradient * gloss * 0.8 + final_color *= lighting_factor + + # Ensure colors stay in valid range + final_color = ti.math.clamp(final_color, 0.0, 1.0) + + self.vertices[i].y = y + self.colors[i] = final_color + + def update(self): + self._update_step() + + def render(self, scene): + scene.mesh(self.vertices, indices=self.indices, per_vertex_color=self.colors) \ No newline at end of file From 2636a7cb230fc3c9084ab7e3a703beee205734fe Mon Sep 17 00:00:00 2001 From: Aarush <56655271+aarush8@users.noreply.github.com> Date: Wed, 3 Sep 2025 23:55:33 -0400 Subject: [PATCH 2/3] update --- submissions/aarushassudani/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/submissions/aarushassudani/README.md b/submissions/aarushassudani/README.md index be4823a..ef95122 100644 --- a/submissions/aarushassudani/README.md +++ b/submissions/aarushassudani/README.md @@ -1,4 +1,6 @@ -Run by running main.py +Project Title: SynaSight + +Run by running main.py. A default texture is shown, in the window with the texture press i to input your own texture. You can then type in the console a custom texture and it will show up in the texture window. My initial idea for this was to generate a feedback map overlaid on a silhouette of a foot to visually represent the pressure sense we get on our feet when we walk on certain types of land. However this wouldn’t really nicely visualize the texture to someone looking at a 2d screen so I pivoted to creating a 3d model of the texture. From 272431774c5e3e95144f4e1797bb59f0f2f7e64b Mon Sep 17 00:00:00 2001 From: Aarush <56655271+aarush8@users.noreply.github.com> Date: Wed, 3 Sep 2025 23:56:23 -0400 Subject: [PATCH 3/3] 1 --- submissions/aarushassudani/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submissions/aarushassudani/README.md b/submissions/aarushassudani/README.md index ef95122..f8785ce 100644 --- a/submissions/aarushassudani/README.md +++ b/submissions/aarushassudani/README.md @@ -4,5 +4,5 @@ Run by running main.py. A default texture is shown, in the window with the textu My initial idea for this was to generate a feedback map overlaid on a silhouette of a foot to visually represent the pressure sense we get on our feet when we walk on certain types of land. However this wouldn’t really nicely visualize the texture to someone looking at a 2d screen so I pivoted to creating a 3d model of the texture. -What the app does is generates a texture map based on text input from the user +What the app does is generates a texture map based on text input from the user.