diff --git a/Zenith.NET.slnx b/Zenith.NET.slnx index 1bb103a8..5aff3b15 100644 --- a/Zenith.NET.slnx +++ b/Zenith.NET.slnx @@ -1,9 +1,9 @@  + - diff --git a/documents/images/Zenith.NET-Logo.png b/documents/images/Zenith.NET-Logo.png index 15188b2e..5dd004f2 100644 Binary files a/documents/images/Zenith.NET-Logo.png and b/documents/images/Zenith.NET-Logo.png differ diff --git a/documents/images/Zenith.NET-Logo.svg b/documents/images/Zenith.NET-Logo.svg index 540762a1..91836d0c 100644 --- a/documents/images/Zenith.NET-Logo.svg +++ b/documents/images/Zenith.NET-Logo.svg @@ -1,15 +1,20 @@ - + - - - + + + + + + + + - - - - - - + + + + + + @@ -17,17 +22,24 @@ + - - - - - + + + + + + + + + + - + + Zenith.NET \ No newline at end of file diff --git a/documents/images/Zenith.NET.png b/documents/images/Zenith.NET.png index 00fcc02a..b7862c71 100644 Binary files a/documents/images/Zenith.NET.png and b/documents/images/Zenith.NET.png differ diff --git a/documents/images/Zenith.NET.svg b/documents/images/Zenith.NET.svg index d2f3cb66..0e2e45db 100644 --- a/documents/images/Zenith.NET.svg +++ b/documents/images/Zenith.NET.svg @@ -1,10 +1,25 @@  - - - + + + + + + + + + + + - + + + + + + + + @@ -13,11 +28,20 @@ - + + - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/documents/templates/public/main.css b/documents/templates/public/main.css index 35f944cd..e992ff7f 100644 --- a/documents/templates/public/main.css +++ b/documents/templates/public/main.css @@ -1,114 +1,109 @@ /** - * Zenith.NET Documentation Theme - * Modern Liquid Glass theme for DocFX + * Zenith.NET Documentation — "Signal" Theme + * A modern, luminous design language for GPU programming docs. */ /* ========================================================================== - 1. CSS Variables + 1. Design Tokens ========================================================================== */ :root { - --zenith-primary: #0969DA; - --zenith-secondary: #0969DA; - --zenith-gradient: linear-gradient(135deg, #0969DA 0%, #2188ff 100%); - --zenith-text: #0d1117; - --zenith-text-muted: #7d8590; - --zenith-bg: #ffffff; - --zenith-bg-light: #f6f8fa; - --zenith-border: #d0d7de; - --zenith-link: #0969DA; - --zenith-link-hover: #0550ae; - --radius-sm: 8px; - --radius-md: 12px; - --radius-lg: 16px; - --radius-xl: 24px; - --radius-2xl: 32px; - --elevation-3: 0 10px 20px rgba(0, 0, 0, 0.08), 0 3px 6px rgba(0, 0, 0, 0.05); - --elevation-4: 0 14px 28px rgba(0, 0, 0, 0.1), 0 5px 10px rgba(0, 0, 0, 0.06); - --glass-bg: rgba(255, 255, 255, 0.15); - --glass-bg-solid: rgba(255, 255, 255, 0.95); - --glass-blur: 20px; - --glass-blur-strong: 40px; - --glass-saturate: 180%; - --glass-border: rgba(0, 0, 0, 0.1); - --glass-border-hover: rgba(9, 105, 218, 0.4); - --glass-refraction: rgba(255, 255, 255, 0.9); - --glass-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); - --glass-shadow-elevated: 0 8px 32px rgba(0, 0, 0, 0.12); - --glass-divider: rgba(0, 0, 0, 0.1); - --surface-tint: rgba(9, 105, 218, 0.06); - --motion-standard: cubic-bezier(0.2, 0, 0, 1); + /* Brand gradient endpoints */ + --brand-blue: #2563EB; + --brand-violet: #7C3AED; + /* Functional accent (flat fallback) */ + --accent: #2563EB; + --accent-hover: #1D4ED8; + --accent-soft: rgba(37, 99, 235, 0.08); + --accent-soft-mid: rgba(37, 99, 235, 0.14); + --accent-ring: rgba(37, 99, 235, 0.30); + /* Text hierarchy */ + --text-primary: #0F172A; + --text-secondary: #475569; + --text-tertiary: #94A3B8; + /* Surfaces */ + --bg: #FAFAFA; + --surface: #FFFFFF; + --surface-raised: #FFFFFF; + --surface-sunken: #F1F5F9; + /* Borders */ + --border: #E2E8F0; + --border-strong: #CBD5E1; + /* Elevations */ + --shadow-xs: 0 1px 2px rgba(0,0,0,0.05); + --shadow-sm: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.04); + --shadow-md: 0 4px 12px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.04); + --shadow-lg: 0 12px 32px rgba(0,0,0,0.08), 0 4px 8px rgba(0,0,0,0.04); + /* Radii */ + --radius-xs: 4px; + --radius-sm: 6px; + --radius-md: 10px; + --radius-lg: 14px; + --radius-full: 9999px; + /* Motion */ + --ease: cubic-bezier(0.22, 1, 0.36, 1); + --duration: 0.18s; + /* Gradients */ + --gradient-brand: linear-gradient(135deg, var(--brand-blue), var(--brand-violet)); + --gradient-subtle: linear-gradient(135deg, rgba(37,99,235,0.05), rgba(124,58,237,0.05)); + --gradient-glow: linear-gradient(135deg, rgba(37,99,235,0.12), rgba(124,58,237,0.12)); } [data-bs-theme="dark"] { - --zenith-primary: #58a6ff; - --zenith-secondary: #58a6ff; - --zenith-text: #e6edf3; - --zenith-text-muted: #8b949e; - --zenith-bg: #0d1117; - --zenith-bg-light: #161b22; - --zenith-border: #30363d; - --zenith-link: #58a6ff; - --zenith-link-hover: #a5d6ff; - --elevation-3: 0 10px 20px rgba(0, 0, 0, 0.4), 0 3px 6px rgba(0, 0, 0, 0.3); - --elevation-4: 0 14px 28px rgba(0, 0, 0, 0.5), 0 5px 10px rgba(0, 0, 0, 0.35); - --glass-bg: rgba(13, 17, 23, 0.15); - --glass-bg-solid: rgba(22, 27, 34, 0.92); - --glass-border: rgba(48, 54, 61, 0.8); - --glass-border-hover: rgba(88, 166, 255, 0.4); - --glass-refraction: rgba(255, 255, 255, 0.08); - --glass-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); - --glass-shadow-elevated: 0 8px 32px rgba(0, 0, 0, 0.5); - --glass-divider: rgba(48, 54, 61, 0.8); - --surface-tint: rgba(88, 166, 255, 0.1); + --brand-blue: #60A5FA; + --brand-violet: #A78BFA; + --accent: #60A5FA; + --accent-hover: #93C5FD; + --accent-soft: rgba(96, 165, 250, 0.10); + --accent-soft-mid: rgba(96, 165, 250, 0.18); + --accent-ring: rgba(96, 165, 250, 0.30); + --text-primary: #F1F5F9; + --text-secondary: #94A3B8; + --text-tertiary: #64748B; + --bg: #09090B; + --surface: #18181B; + --surface-raised: #1E1E22; + --surface-sunken: #111114; + --border: rgba(255,255,255,0.08); + --border-strong: rgba(255,255,255,0.14); + --shadow-xs: 0 1px 2px rgba(0,0,0,0.30); + --shadow-sm: 0 1px 3px rgba(0,0,0,0.40), 0 1px 2px rgba(0,0,0,0.30); + --shadow-md: 0 4px 12px rgba(0,0,0,0.40), 0 2px 4px rgba(0,0,0,0.30); + --shadow-lg: 0 12px 32px rgba(0,0,0,0.50), 0 4px 8px rgba(0,0,0,0.35); + --gradient-subtle: linear-gradient(135deg, rgba(96,165,250,0.06), rgba(167,139,250,0.06)); + --gradient-glow: linear-gradient(135deg, rgba(96,165,250,0.15), rgba(167,139,250,0.15)); } /* ========================================================================== - 2. Base Styles + 2. Base ========================================================================== */ body { - background-color: var(--zenith-bg); + background-color: var(--bg); + color: var(--text-primary); padding-top: 60px !important; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; position: relative; } - body::before, - body::after { + /* Page-wide decorative mesh gradient */ + body::before { content: ''; position: fixed; - border-radius: 50%; - filter: blur(150px); + inset: 0; pointer-events: none; - z-index: -1; - } - - body::before { - background: #0969DA; - width: 800px; - height: 800px; - top: -300px; - right: -200px; - opacity: 0.12; - } - - body::after { - background: #06b6d4; - width: 500px; - height: 500px; - bottom: -100px; - left: -50px; - opacity: 0.1; + z-index: 0; + background: radial-gradient(50% 40% at 20% 20%, rgba(37,99,235,0.06) 0%, transparent 70%), radial-gradient(45% 35% at 75% 30%, rgba(124,58,237,0.05) 0%, transparent 70%), radial-gradient(40% 40% at 50% 80%, rgba(37,99,235,0.04) 0%, transparent 70%); } [data-bs-theme="dark"] body::before { - background: #58a6ff; - opacity: 0.15; + background: radial-gradient(50% 40% at 20% 20%, rgba(96,165,250,0.08) 0%, transparent 70%), radial-gradient(45% 35% at 75% 30%, rgba(167,139,250,0.07) 0%, transparent 70%), radial-gradient(40% 40% at 50% 80%, rgba(96,165,250,0.05) 0%, transparent 70%); } -[data-bs-theme="dark"] body::after { - background: #22d3ee; - opacity: 0.12; +::selection { + background: var(--accent-soft-mid); + color: var(--text-primary); } /* ========================================================================== @@ -123,11 +118,11 @@ header.bg-body, left: 0 !important; right: 0 !important; z-index: 1030 !important; - background: var(--glass-bg) !important; - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)) !important; - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)) !important; + background: color-mix(in srgb, var(--bg) 85%, transparent) !important; + backdrop-filter: blur(12px) saturate(1.4) !important; + -webkit-backdrop-filter: blur(12px) saturate(1.4) !important; border: none !important; - border-bottom: 1px solid var(--glass-border) !important; + border-bottom: 1px solid var(--border) !important; box-shadow: none !important; } @@ -135,51 +130,31 @@ header.bg-body, --bs-dropdown-bg: transparent; position: absolute !important; top: 100% !important; - background: var(--glass-bg-solid) !important; - backdrop-filter: blur(var(--glass-blur-strong)) saturate(var(--glass-saturate)) !important; - -webkit-backdrop-filter: blur(var(--glass-blur-strong)) saturate(var(--glass-saturate)) !important; - border: 1px solid var(--glass-border) !important; - border-radius: var(--radius-xl) !important; - box-shadow: var(--glass-shadow-elevated) !important; - padding: 0.5rem !important; - margin-top: 0.5rem !important; + background: color-mix(in srgb, var(--surface) 95%, transparent) !important; + backdrop-filter: blur(16px) !important; + -webkit-backdrop-filter: blur(16px) !important; + border: 1px solid var(--border) !important; + border-radius: var(--radius-md) !important; + box-shadow: var(--shadow-lg) !important; + padding: 4px !important; + margin-top: 4px !important; overflow: visible; z-index: 1040 !important; } - .dropdown-menu::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 40%; - background: linear-gradient(180deg, var(--glass-refraction) 0%, transparent 100%); - pointer-events: none; - opacity: 0.3; - border-radius: var(--radius-xl) var(--radius-xl) 0 0; - z-index: 0; - } - .dropdown-item { - position: relative; - z-index: 1; - border-radius: var(--radius-md) !important; - transition: all 0.2s var(--motion-standard) !important; - color: var(--zenith-text) !important; + border-radius: var(--radius-sm) !important; + transition: all var(--duration) var(--ease) !important; + color: var(--text-primary) !important; + padding: 6px 10px !important; } .dropdown-item:hover, .dropdown-item:focus { - background: var(--surface-tint) !important; - color: var(--zenith-primary) !important; + background: var(--accent-soft) !important; + color: var(--accent) !important; } -[data-bs-theme="dark"] .dropdown-item:hover, -[data-bs-theme="dark"] .dropdown-item:focus { - color: var(--zenith-link) !important; -} - .navbar #navbar, .navbar #navbar > * { display: flex; @@ -188,39 +163,34 @@ header.bg-body, .navbar .navbar-nav { display: flex; - gap: 0.25rem; + gap: 2px; } .navbar .nav-link { position: relative; - padding: 0.5rem 0.875rem !important; + padding: 6px 12px !important; border-radius: var(--radius-sm) !important; - font-size: 0.9rem !important; + font-size: 0.875rem !important; font-weight: 500 !important; - color: var(--zenith-text-muted) !important; - transition: all 0.15s var(--motion-standard) !important; + color: var(--text-secondary) !important; + transition: all var(--duration) var(--ease) !important; text-decoration: none !important; } - .navbar .nav-link:hover, - .navbar .nav-link.active { - background: var(--surface-tint) !important; - color: var(--zenith-primary) !important; + .navbar .nav-link:hover { + background: var(--accent-soft) !important; + color: var(--text-primary) !important; } .navbar .nav-link.active { + color: var(--accent) !important; font-weight: 600 !important; } -[data-bs-theme="dark"] .navbar .nav-link:hover, -[data-bs-theme="dark"] .navbar .nav-link.active { - color: var(--zenith-link) !important; -} - .navbar .icons { display: flex; align-items: center; - gap: 0.25rem; + gap: 2px; } .navbar .icons > a.btn, @@ -228,30 +198,25 @@ header.bg-body, display: inline-flex !important; align-items: center !important; justify-content: center !important; - width: 36px !important; - height: 36px !important; + width: 34px !important; + height: 34px !important; padding: 0 !important; border-radius: var(--radius-sm) !important; - color: var(--zenith-text-muted) !important; - transition: all 0.15s var(--motion-standard) !important; + color: var(--text-secondary) !important; + transition: all var(--duration) var(--ease) !important; } .navbar .icons > a.btn:hover, .navbar .icons .dropdown > a.btn:hover { - background: var(--surface-tint) !important; - color: var(--zenith-primary) !important; + background: var(--accent-soft) !important; + color: var(--accent) !important; } .navbar .icons > a.btn i, .navbar .icons .dropdown > a.btn i { - font-size: 1.1rem; + font-size: 1.05rem; } -[data-bs-theme="dark"] .navbar .icons > a.btn:hover, -[data-bs-theme="dark"] .navbar .icons .dropdown > a.btn:hover { - color: var(--zenith-link) !important; -} - #logo { height: 50px; } @@ -262,47 +227,59 @@ header.bg-body, .hero { text-align: center; - padding: 2rem 2rem 3rem 2rem; + padding: 4rem 2rem 4.5rem; +} + +.hero-content { + max-width: 720px; + margin: 0 auto; } .hero-logo { - width: 100px; - height: 100px; - margin-bottom: 1.5rem; - filter: drop-shadow(0 4px 12px rgba(138, 50, 180, 0.35)); + width: 80px; + height: 80px; + margin-bottom: 1.75rem; + filter: drop-shadow(0 4px 12px rgba(37,99,235,0.20)); +} + +[data-bs-theme="dark"] .hero-logo { + filter: drop-shadow(0 4px 16px rgba(96,165,250,0.30)); } .hero h1 { width: fit-content; - margin: 0 auto 0.5rem auto; + margin: 0 auto 0.5rem; font-size: 3.5rem; font-weight: 800; - background: linear-gradient(90deg, #512BD4 0%, #C239B3 100%); + letter-spacing: -0.035em; + line-height: 1.1; + border: none; + background: var(--gradient-brand); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; - border: none; } .hero-tagline { - font-size: 1.35rem; + font-size: 1.25rem; font-weight: 500; - margin: 0 0 1rem 0; - color: var(--zenith-text); + margin: 0 0 1rem; + color: var(--text-primary); + letter-spacing: -0.01em; } .hero-description { - font-size: 1.1rem; - max-width: 650px; - margin: 0 auto 2rem auto; - color: var(--zenith-text-muted); + font-size: 1.05rem; + max-width: 560px; + margin: 0 auto 2.25rem; + color: var(--text-secondary); line-height: 1.7; } .hero-buttons { display: flex; justify-content: center; - gap: 1rem; + gap: 0.75rem; flex-wrap: wrap; } @@ -310,64 +287,51 @@ header.bg-body, .btn, button.btn, a.btn { - border-radius: var(--radius-md) !important; + border-radius: var(--radius-sm) !important; } .hero-buttons .btn { - display: inline-block; - padding: 0.85rem 2rem; - font-size: 1rem; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.625rem 1.5rem; + font-size: 0.9rem; font-weight: 600; text-decoration: none; border: none; outline: none; - transition: all 0.2s ease; + transition: all var(--duration) var(--ease); + gap: 0.375rem; } - .hero-buttons .btn:focus, - .hero-buttons .btn:focus-visible, - .hero-buttons .btn:active { - outline: none !important; + .hero-buttons .btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; } .hero-buttons .btn-primary { - background: var(--zenith-gradient); - color: white; - box-shadow: 0 4px 16px rgba(9, 105, 218, 0.3); + background: var(--gradient-brand); + color: #FFFFFF; + box-shadow: var(--shadow-sm), 0 0 0 1px rgba(37,99,235,0.10); } .hero-buttons .btn-primary:hover { - transform: translateY(-2px); - box-shadow: 0 8px 24px rgba(9, 105, 218, 0.4); - } - - .hero-buttons .btn-primary:focus, - .hero-buttons .btn-primary:focus-visible { - box-shadow: 0 4px 16px rgba(9, 105, 218, 0.3) !important; + box-shadow: var(--shadow-md), 0 0 20px rgba(37,99,235,0.20); + transform: translateY(-1px); } .hero-buttons .btn-secondary { - position: relative; - background: var(--glass-bg) !important; - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - color: var(--zenith-text); - border: 1px solid var(--glass-border); - box-shadow: var(--glass-shadow); - overflow: hidden; + background: var(--surface) !important; + color: var(--text-primary); + border: 1px solid var(--border-strong) !important; + box-shadow: var(--shadow-xs); } .hero-buttons .btn-secondary:hover { - border-color: var(--glass-border-hover); - color: var(--zenith-primary); - transform: translateY(-2px); - box-shadow: var(--glass-shadow-elevated); - } - - .hero-buttons .btn-secondary:focus, - .hero-buttons .btn-secondary:focus-visible { - border-color: var(--glass-border) !important; - box-shadow: var(--glass-shadow) !important; + border-color: var(--accent) !important; + color: var(--accent); + transform: translateY(-1px); + box-shadow: var(--shadow-sm); } /* ========================================================================== @@ -377,58 +341,34 @@ header.bg-body, .features { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 1.5rem; + gap: 1rem; margin: 2rem 0; } .feature { - position: relative; - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - padding: 1.75rem; - border-radius: var(--radius-xl); - border: 1px solid var(--glass-border); - box-shadow: var(--glass-shadow); - transition: all 0.3s var(--motion-standard); - overflow: hidden; + padding: 1.5rem; + border-radius: var(--radius-md); + border: 1px solid var(--border); + background: var(--surface); + transition: all var(--duration) var(--ease); } - .feature::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 50%; - background: linear-gradient(180deg, var(--glass-refraction) 0%, transparent 100%); - pointer-events: none; - opacity: 0.2; - border-radius: var(--radius-xl) var(--radius-xl) 0 0; - } - .feature:hover { - border-color: var(--glass-border-hover); - box-shadow: var(--glass-shadow-elevated); - transform: translateY(-4px); - } - - .feature h3, - .feature p { - position: relative; - z-index: 1; + border-color: var(--border-strong); + box-shadow: var(--shadow-md); + transform: translateY(-2px); } .feature h3 { - font-size: 1.2rem; + font-size: 1.05rem; font-weight: 600; - margin: 0 0 0.75rem 0; - color: var(--zenith-text); + margin: 0 0 0.5rem; + color: var(--text-primary); } .feature p { - font-size: 0.95rem; - color: var(--zenith-text-muted); + font-size: 0.875rem; + color: var(--text-secondary); margin: 0; line-height: 1.6; } @@ -449,52 +389,41 @@ header.bg-body, } .tech-group h4 { - font-size: 1rem; + font-size: 0.7rem; font-weight: 600; - color: var(--zenith-text-muted); - margin: 0 0 1rem 0; + color: var(--text-tertiary); + margin: 0 0 0.75rem; text-transform: uppercase; - letter-spacing: 0.05em; + letter-spacing: 0.1em; } .tech-icons { display: flex; flex-wrap: wrap; justify-content: center; - gap: 1rem; + gap: 0.625rem; } .tech-item { - position: relative; display: flex; align-items: center; justify-content: center; - padding: 0.75rem 1.25rem; - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - border: 1px solid var(--glass-border); - border-radius: var(--radius-lg); - box-shadow: var(--glass-shadow); - transition: all 0.3s var(--motion-standard); - overflow: hidden; + padding: 0.5rem 1rem; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + transition: all var(--duration) var(--ease); } .tech-item:hover { - border-color: var(--glass-border-hover); - transform: translateY(-2px); - box-shadow: var(--glass-shadow-elevated); + border-color: var(--accent-ring); + background: var(--accent-soft); } .tech-item .tech-text { - position: relative; - z-index: 1; - font-size: 0.95rem; + font-size: 0.875rem; font-weight: 600; - background: var(--zenith-gradient); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; + color: var(--accent); } /* ========================================================================== @@ -504,61 +433,36 @@ header.bg-body, .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); - gap: 1.5rem; + gap: 1rem; margin: 2rem 0; } .card { - position: relative; display: flex; flex-direction: column; - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - padding: 2rem; - border-radius: var(--radius-xl); - border: 1px solid var(--glass-border); - box-shadow: var(--glass-shadow); - transition: all 0.3s var(--motion-standard); - overflow: hidden; + padding: 1.5rem; + border-radius: var(--radius-md); + border: 1px solid var(--border); + background: var(--surface); + transition: all var(--duration) var(--ease); } - .card::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 50%; - background: linear-gradient(180deg, var(--glass-refraction) 0%, transparent 100%); - pointer-events: none; - opacity: 0.15; - border-radius: var(--radius-xl) var(--radius-xl) 0 0; - } - .card:hover { - border-color: var(--glass-border-hover); - box-shadow: var(--glass-shadow-elevated); - transform: translateY(-4px); - } - - .card h3, - .card p, - .card a { - position: relative; - z-index: 1; + border-color: var(--border-strong); + box-shadow: var(--shadow-md); + transform: translateY(-2px); } .card h3 { - font-size: 1.25rem; + font-size: 1.05rem; font-weight: 600; - margin: 0 0 0.75rem 0; - color: var(--zenith-text); + margin: 0 0 0.5rem; + color: var(--text-primary); } .card p { - font-size: 0.95rem; - color: var(--zenith-text-muted); + font-size: 0.875rem; + color: var(--text-secondary); margin: 0; line-height: 1.6; flex-grow: 1; @@ -567,14 +471,15 @@ header.bg-body, .card a { display: inline-block; margin-top: 1rem; - color: var(--zenith-primary); + color: var(--accent); + font-size: 0.8125rem; font-weight: 600; text-decoration: none; - transition: color 0.2s ease; + transition: color var(--duration) var(--ease); } .card a:hover { - color: var(--zenith-secondary); + color: var(--accent-hover); } /* ========================================================================== @@ -585,16 +490,16 @@ header.bg-body, display: flex; flex-direction: column; margin: 2rem 0; - --step-number-size: 52px; - --step-line-width: 2px; + --step-size: 44px; + --step-line: 2px; } .workflow-step { display: flex; align-items: center; - gap: 1.5rem; + gap: 1.25rem; position: relative; - padding-bottom: 1.5rem; + padding-bottom: 1.25rem; } .workflow-step:last-child { @@ -604,68 +509,55 @@ header.bg-body, .workflow-step:not(:last-child)::after { content: ''; position: absolute; - left: calc((var(--step-number-size) - var(--step-line-width)) / 2); + left: calc((var(--step-size) - var(--step-line)) / 2); top: 50%; - width: var(--step-line-width); + width: var(--step-line); height: 100%; - background: var(--zenith-gradient); - opacity: 0.4; + background: var(--border-strong); z-index: 0; } .step-number { - width: var(--step-number-size); - height: var(--step-number-size); - min-width: var(--step-number-size); + width: var(--step-size); + height: var(--step-size); + min-width: var(--step-size); border-radius: 50%; - background: var(--zenith-gradient); - color: white; - font-size: 1.25rem; + background: var(--gradient-brand); + color: #FFFFFF; + font-size: 1rem; font-weight: 700; display: flex; align-items: center; justify-content: center; - box-shadow: var(--elevation-3); z-index: 1; flex-shrink: 0; + box-shadow: var(--shadow-sm), 0 0 0 3px var(--bg); } .step-content { - position: relative; flex: 1; - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - padding: 1.25rem 1.5rem; - border-radius: var(--radius-xl); - border: 1px solid var(--glass-border); - box-shadow: var(--glass-shadow); - transition: all 0.3s var(--motion-standard); - overflow: hidden; + padding: 1rem 1.25rem; + border-radius: var(--radius-md); + border: 1px solid var(--border); + background: var(--surface); + transition: all var(--duration) var(--ease); } .step-content:hover { - transform: translateY(-2px); - border-color: var(--glass-border-hover); - box-shadow: var(--glass-shadow-elevated); - } - - .step-content h4, - .step-content p { - position: relative; - z-index: 1; + border-color: var(--border-strong); + box-shadow: var(--shadow-sm); } .step-content h4 { - font-size: 1.1rem; + font-size: 0.95rem; font-weight: 600; - margin: 0 0 0.5rem 0; - color: var(--zenith-text); + margin: 0 0 0.25rem; + color: var(--text-primary); } .step-content p { - font-size: 0.95rem; - color: var(--zenith-text-muted); + font-size: 0.875rem; + color: var(--text-secondary); margin: 0; line-height: 1.6; } @@ -679,38 +571,31 @@ header.bg-body, display: flex; justify-content: center; flex-wrap: wrap; - gap: 0.75rem; + gap: 0.5rem; } .community-badges { - gap: 1rem; + gap: 0.875rem; margin: 2rem 0; } .hero-badges { - margin-top: 1.5rem; + margin-top: 1.75rem; } .community-badges a, .hero-badges a { - transition: transform 0.2s ease, opacity 0.2s ease; + transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease); } .community-badges a:hover, .hero-badges a:hover { - transform: translateY(-2px); - } - - .hero-badges a { - opacity: 0.9; - } - - .hero-badges a:hover { - opacity: 1; + transform: translateY(-1px); + opacity: 0.80; } .hero-badges img { - height: 24px; + height: 22px; } /* ========================================================================== @@ -718,43 +603,36 @@ header.bg-body, ========================================================================== */ .tech-bar { - position: relative; display: flex; justify-content: center; align-items: center; gap: 2rem; flex-wrap: wrap; - padding: 1.5rem 2rem; - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - border-radius: var(--radius-2xl); - border: 1px solid var(--glass-border); - box-shadow: var(--glass-shadow); + padding: 1rem 2rem; + background: var(--surface); + border-radius: var(--radius-lg); + border: 1px solid var(--border); margin-bottom: 2rem; - overflow: hidden; } .tech-bar-group { - position: relative; - z-index: 1; display: flex; align-items: center; - gap: 0.75rem; + gap: 0.5rem; } .tech-bar-label { - font-size: 0.85rem; + font-size: 0.7rem; font-weight: 600; - color: var(--zenith-text-muted); + color: var(--text-tertiary); text-transform: uppercase; - letter-spacing: 0.05em; + letter-spacing: 0.1em; } .tech-bar-items { - font-size: 1rem; - font-weight: 500; - background: var(--zenith-gradient); + font-size: 0.875rem; + font-weight: 600; + background: var(--gradient-brand); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; @@ -762,8 +640,8 @@ header.bg-body, .tech-bar-divider { width: 1px; - height: 24px; - background: var(--glass-border); + height: 20px; + background: var(--border-strong); } /* ========================================================================== @@ -773,52 +651,41 @@ header.bg-body, .highlight-grid { display: grid; grid-template-columns: repeat(2, 1fr); - gap: 1rem; + gap: 0.75rem; margin: 2rem 0; } .highlight-item { - position: relative; display: flex; align-items: flex-start; - gap: 1rem; - padding: 1.25rem; - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - border-radius: var(--radius-xl); - border: 1px solid var(--glass-border); - box-shadow: var(--glass-shadow); - transition: all 0.3s var(--motion-standard); - overflow: hidden; + gap: 0.875rem; + padding: 1.125rem 1.25rem; + background: var(--surface); + border-radius: var(--radius-md); + border: 1px solid var(--border); + transition: all var(--duration) var(--ease); } .highlight-item:hover { - transform: translateY(-2px); - border-color: var(--glass-border-hover); - box-shadow: var(--glass-shadow-elevated); + border-color: var(--border-strong); + box-shadow: var(--shadow-sm); } -.highlight-icon, -.highlight-text { - position: relative; - z-index: 1; -} - .highlight-icon { - font-size: 1.5rem; + font-size: 1.2rem; line-height: 1; flex-shrink: 0; + margin-top: 1px; } .highlight-text { - font-size: 0.95rem; - color: var(--zenith-text-muted); - line-height: 1.5; + font-size: 0.875rem; + color: var(--text-secondary); + line-height: 1.55; } .highlight-text strong { - color: var(--zenith-text); + color: var(--text-primary); font-weight: 600; } @@ -829,50 +696,38 @@ header.bg-body, .feature-list { display: flex; flex-direction: column; - gap: 0.75rem; + gap: 0.375rem; margin: 2rem 0; } .feature-list-item { - position: relative; display: flex; align-items: baseline; gap: 1rem; - padding: 1rem 1.25rem; - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - border-radius: var(--radius-xl); - border: 1px solid var(--glass-border); - box-shadow: var(--glass-shadow); - transition: all 0.3s var(--motion-standard); - overflow: hidden; + padding: 0.75rem 1.125rem; + background: var(--surface); + border-radius: var(--radius-sm); + border: 1px solid var(--border); + transition: all var(--duration) var(--ease); } .feature-list-item:hover { - transform: translateY(-2px); - border-color: var(--glass-border-hover); - box-shadow: var(--glass-shadow-elevated); + border-color: var(--border-strong); + background: var(--accent-soft); } -.feature-list-title, -.feature-list-desc { - position: relative; - z-index: 1; -} - .feature-list-title { - font-size: 1rem; + font-size: 0.875rem; font-weight: 600; - color: var(--zenith-text); + color: var(--text-primary); white-space: nowrap; - min-width: 160px; + min-width: 140px; } .feature-list-desc { - font-size: 0.95rem; - color: var(--zenith-text-muted); - line-height: 1.5; + font-size: 0.875rem; + color: var(--text-secondary); + line-height: 1.55; } /* ========================================================================== @@ -881,27 +736,26 @@ header.bg-body, .cta-section { display: flex; - align-items: center; - gap: 3rem; - padding: 2.5rem; - background: var(--zenith-gradient); - border-radius: var(--radius-2xl); + align-items: stretch; + gap: 2.5rem; + padding: 2rem 2.25rem; + background: var(--gradient-subtle); + border-radius: var(--radius-lg); + border: 1px solid var(--border); margin: 2rem 0; - box-shadow: var(--elevation-4); position: relative; overflow: hidden; } + /* Subtle accent line at top */ .cta-section::before { content: ''; position: absolute; top: 0; left: 0; right: 0; - height: 50%; - background: linear-gradient(180deg, rgba(255, 255, 255, 0.15) 0%, transparent 100%); - pointer-events: none; - border-radius: var(--radius-2xl) var(--radius-2xl) 0 0; + height: 2px; + background: var(--gradient-brand); } .cta-main { @@ -909,82 +763,85 @@ header.bg-body, } .cta-main h3 { - font-size: 1.75rem; + font-size: 1.375rem; font-weight: 700; - color: white; - margin: 0 0 0.75rem 0; + color: var(--text-primary); + margin: 0 0 0.5rem; + letter-spacing: -0.01em; } .cta-main p { - font-size: 1.05rem; - color: rgba(255, 255, 255, 0.9); - margin: 0 0 1.5rem 0; + font-size: 0.95rem; + color: var(--text-secondary); + margin: 0 0 1.25rem; line-height: 1.6; } .cta-main .btn-primary { - display: inline-block; - padding: 0.85rem 2rem; - font-size: 1rem; + display: inline-flex; + align-items: center; + padding: 0.625rem 1.5rem; + font-size: 0.9rem; font-weight: 600; text-decoration: none; - border-radius: var(--radius-md) !important; + border-radius: var(--radius-sm) !important; border: none; outline: none; - background: white; - color: var(--zenith-primary); - transition: all 0.2s ease; + background: var(--gradient-brand); + color: #FFFFFF; + transition: all var(--duration) var(--ease); + box-shadow: var(--shadow-sm); } .cta-main .btn-primary:hover { - background: #f0f0f0; - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); + box-shadow: var(--shadow-md), 0 0 20px rgba(37,99,235,0.18); + transform: translateY(-1px); } - .cta-main .btn-primary:focus, - .cta-main .btn-primary:focus-visible, - .cta-main .btn-primary:active { - outline: none !important; - box-shadow: none !important; + .cta-main .btn-primary:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; } .cta-links { display: flex; flex-direction: column; - gap: 1rem; + align-items: flex-end; + justify-content: center; + margin-left: auto; + gap: 0.5rem; } .cta-link { display: flex; align-items: center; - gap: 0.75rem; - padding: 1rem 1.5rem; - background: rgba(255, 255, 255, 0.1); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - border: 1px solid rgba(255, 255, 255, 0.18); - border-radius: var(--radius-md); + justify-content: flex-start; + gap: 0.625rem; + padding: 0.625rem 1.125rem; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-sm); text-decoration: none; - transition: all 0.3s var(--motion-standard); - min-width: 180px; + transition: all var(--duration) var(--ease); + min-width: 200px; } .cta-link:hover { - background: rgba(255, 255, 255, 0.15); - border-color: rgba(255, 255, 255, 0.3); - transform: translateY(-2px); + border-color: var(--accent-ring); + background: var(--accent-soft); text-decoration: none; + transform: translateY(-1px); + box-shadow: var(--shadow-sm); } .cta-link-icon { - font-size: 1.25rem; + font-size: 1rem; } .cta-link-text { - font-size: 1rem; + font-size: 0.875rem; font-weight: 600; - color: white; + color: var(--text-primary); } /* ========================================================================== @@ -992,108 +849,96 @@ header.bg-body, ========================================================================== */ article { - color: var(--zenith-text); - line-height: 1.7; + font-size: 0.95rem; + color: var(--text-primary); + line-height: 1.75; } article h1 { - font-size: 2.25rem; - font-weight: 700; - color: var(--zenith-text); - margin: 0 0 1.5rem 0; + font-size: 2rem; + font-weight: 750; + color: var(--text-primary); + margin: 0 0 1.5rem; padding-bottom: 0.75rem; - border-bottom: 3px solid transparent; - border-image: var(--zenith-gradient); - border-image-slice: 1; + border-bottom: 1px solid var(--border); + letter-spacing: -0.025em; } article h2 { - font-size: 1.75rem; + font-size: 1.4rem; font-weight: 700; - color: var(--zenith-text); - margin: 2.5rem 0 1rem 0; + color: var(--text-primary); + margin: 2.5rem 0 1rem; position: relative; - padding-left: 1rem; + padding-left: 0.875rem; + letter-spacing: -0.02em; } article h2::before { content: ''; position: absolute; left: 0; - top: 0.1em; - bottom: 0.1em; - width: 4px; - background: var(--zenith-gradient); + top: 0.15em; + bottom: 0.15em; + width: 3px; + background: var(--gradient-brand); border-radius: 2px; } article h3 { - font-size: 1.35rem; - font-weight: 600; - color: var(--zenith-text); - margin: 2rem 0 0.75rem 0; + font-size: 1.15rem; + font-weight: 650; + color: var(--text-primary); + margin: 2rem 0 0.625rem; + letter-spacing: -0.01em; } article h4 { - font-size: 1.1rem; + font-size: 1rem; font-weight: 600; - color: var(--zenith-text); - margin: 1.5rem 0 0.5rem 0; + color: var(--text-primary); + margin: 1.5rem 0 0.5rem; } article p { - margin: 0 0 1rem 0; - color: var(--zenith-text); + margin: 0 0 1rem; + color: var(--text-primary); } article a { - color: var(--zenith-link); + color: var(--accent); text-decoration: none; - transition: color 0.2s ease; + transition: color var(--duration) var(--ease); } article a:hover { - color: var(--zenith-link-hover); + color: var(--accent-hover); text-decoration: underline; + text-underline-offset: 2px; } article ul, article ol { - margin: 0 0 1rem 0; + margin: 0 0 1rem; padding-left: 1.5rem; } article li { - margin-bottom: 0.5rem; - color: var(--zenith-text); + margin-bottom: 0.375rem; + color: var(--text-primary); } + /* Code blocks */ article pre { position: relative; - border-radius: var(--radius-xl); - border: 1px solid var(--glass-border); - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); + border-radius: var(--radius-md); + border: 1px solid var(--border); + background: var(--surface-sunken); margin: 1.5rem 0; overflow: hidden; - box-shadow: var(--glass-shadow); + box-shadow: var(--shadow-xs); } - article pre::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 40%; - background: linear-gradient(180deg, var(--glass-refraction) 0%, transparent 100%); - pointer-events: none; - opacity: 0.15; - border-radius: var(--radius-xl) var(--radius-xl) 0 0; - z-index: 0; - } - article pre .code-action, article pre .btn.code-action, article pre button.btn { @@ -1105,14 +950,12 @@ article { } article pre code { - position: relative; - z-index: 1; display: block; - padding: 1rem; + padding: 1.125rem; margin: 0; overflow-x: auto; - font-size: 0.875rem; - line-height: 1.6; + font-size: 0.8125rem; + line-height: 1.7; background: transparent; } @@ -1127,98 +970,73 @@ article { } article pre code::-webkit-scrollbar-thumb { - background: var(--glass-divider); + background: var(--border-strong); border-radius: 3px; } article pre code::-webkit-scrollbar-thumb:hover { - background: var(--zenith-text-muted); + background: var(--text-tertiary); } article code { - font-size: 0.875rem; - font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', Consolas, monospace; + font-size: 0.8125rem; + font-family: 'Cascadia Code', 'JetBrains Mono', 'Fira Code', Consolas, monospace; } + /* Inline code */ article p code, article li code, article td code { - position: relative; - background: var(--glass-bg); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - color: var(--zenith-primary); - padding: 0.2rem 0.5rem; - border-radius: var(--radius-sm); - font-size: 0.85rem; - border: 1px solid var(--glass-border); + background: var(--accent-soft); + color: var(--accent); + padding: 0.125rem 0.4rem; + border-radius: var(--radius-xs); + font-size: 0.8rem; + border: 1px solid var(--accent-ring); font-weight: 500; } -[data-bs-theme="dark"] article p code, -[data-bs-theme="dark"] article li code, -[data-bs-theme="dark"] article td code { - color: var(--zenith-link); -} - -article hr { - border: none; - border-top: 1px solid var(--zenith-border); - margin: 3rem 0; -} - -article blockquote { - position: relative; - padding: 1.25rem 1.5rem; - margin: 1.5rem 0; - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - border-radius: var(--radius-xl); - border: 1px solid var(--glass-border); - box-shadow: var(--glass-shadow); - overflow: hidden; -} - - article blockquote::before { - content: ''; - position: absolute; - left: 0; - top: 0; - bottom: 0; - width: 4px; - background: var(--zenith-gradient); - border-radius: var(--radius-xl) 0 0 var(--radius-xl); + article hr { + border: none; + border-top: 1px solid var(--border); + margin: 2.5rem 0; } - article blockquote p { + article blockquote { position: relative; - z-index: 1; - margin: 0; - color: var(--zenith-text); - font-size: 1rem; - line-height: 1.7; + padding: 0.875rem 1.25rem; + margin: 1.5rem 0; + background: var(--gradient-subtle); + border-radius: 0 var(--radius-sm) var(--radius-sm) 0; + border-left: 3px solid var(--accent); } - article blockquote p:not(:last-child) { - margin-bottom: 0.75rem; + article blockquote p { + margin: 0; + color: var(--text-secondary); + font-size: 0.9rem; + line-height: 1.65; } -article img:not(#logo):not(.hero-logo):not([src*="shields.io"]):not([src*="badge"]) { - max-width: 100%; - height: auto; - border-radius: var(--radius-xl); - margin: 1.5rem 0; - box-shadow: var(--glass-shadow); - border: 1px solid var(--glass-border); - transition: all 0.3s var(--motion-standard); -} + article blockquote p:not(:last-child) { + margin-bottom: 0.5rem; + } - article img:not(#logo):not(.hero-logo):not([src*="shields.io"]):not([src*="badge"]):hover { - box-shadow: var(--glass-shadow-elevated); - transform: scale(1.01); + /* Images */ + article img:not(#logo):not(.hero-logo):not([src*="shields.io"]):not([src*="badge"]) { + max-width: 100%; + height: auto; + border-radius: var(--radius-md); + margin: 1.5rem 0; + box-shadow: var(--shadow-md); + border: 1px solid var(--border); + transition: box-shadow var(--duration) var(--ease); } + article img:not(#logo):not(.hero-logo):not([src*="shields.io"]):not([src*="badge"]):hover { + box-shadow: var(--shadow-lg); + } + #logo, .hero-logo, .hero-badges img, @@ -1246,9 +1064,9 @@ article figure { article figcaption { text-align: center; - font-size: 0.9rem; - color: var(--zenith-text-muted); - margin-top: 0.75rem; + font-size: 0.8125rem; + color: var(--text-secondary); + margin-top: 0.5rem; font-style: italic; } @@ -1264,15 +1082,13 @@ article > table { article table { width: 100% !important; margin: 0 !important; - font-size: 0.95rem !important; + font-size: 0.875rem !important; border-collapse: separate !important; border-spacing: 0 !important; - border: 1px solid var(--glass-border) !important; - border-radius: var(--radius-xl) !important; - background: var(--glass-bg) !important; - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)) !important; - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)) !important; - box-shadow: var(--glass-shadow) !important; + border: 1px solid var(--border) !important; + border-radius: var(--radius-md) !important; + background: var(--surface) !important; + box-shadow: var(--shadow-xs) !important; } .table-responsive { @@ -1280,45 +1096,44 @@ article table { } article thead { - background: var(--surface-tint) !important; + background: var(--surface-sunken) !important; } article th { - padding: 1rem 1.25rem !important; + padding: 0.75rem 1rem !important; text-align: center !important; + font-size: 0.75rem !important; font-weight: 600 !important; - color: var(--zenith-text) !important; + text-transform: uppercase !important; + letter-spacing: 0.06em !important; + color: var(--text-tertiary) !important; background: transparent !important; border: none !important; } article thead tr th:first-child { - border-top-left-radius: var(--radius-xl) !important; + border-top-left-radius: var(--radius-md) !important; } article thead tr th:last-child { - border-top-right-radius: var(--radius-xl) !important; + border-top-right-radius: var(--radius-md) !important; } article tbody tr { - transition: background 0.2s ease !important; + transition: background var(--duration) var(--ease) !important; } article tbody tr:hover { - background: rgba(9, 105, 218, 0.06) !important; + background: var(--accent-soft) !important; } -[data-bs-theme="dark"] article tbody tr:hover { - background: rgba(88, 166, 255, 0.08) !important; -} - article td { - padding: 0.875rem 1.25rem !important; + padding: 0.625rem 1rem !important; text-align: left !important; - color: var(--zenith-text) !important; + color: var(--text-primary) !important; background: transparent !important; border: none !important; - border-top: 1px solid var(--glass-divider) !important; + border-top: 1px solid var(--border) !important; } article tbody tr:first-child td { @@ -1326,16 +1141,16 @@ article tbody tr:first-child td { } article tbody tr:last-child td:first-child { - border-bottom-left-radius: var(--radius-xl) !important; + border-bottom-left-radius: var(--radius-md) !important; } article tbody tr:last-child td:last-child { - border-bottom-right-radius: var(--radius-xl) !important; + border-bottom-right-radius: var(--radius-md) !important; } article th:not(:last-child), article td:not(:last-child) { - background-image: linear-gradient(to bottom, transparent 20%, var(--glass-divider) 20%, var(--glass-divider) 80%, transparent 80%) !important; + background-image: linear-gradient(to bottom, transparent 15%, var(--border) 15%, var(--border) 85%, transparent 85%) !important; background-size: 1px 100% !important; background-position: right !important; background-repeat: no-repeat !important; @@ -1352,28 +1167,22 @@ article td a { .status-yes, .status-no { display: inline-block; - padding: 0.25rem 0.75rem; - border-radius: 9999px; - font-size: 0.85rem; + padding: 0.15rem 0.5rem; + border-radius: var(--radius-full); + font-size: 0.75rem; font-weight: 600; } .status-yes { - background: linear-gradient(135deg, rgba(9, 105, 218, 0.12) 0%, rgba(33, 136, 255, 0.12) 100%); - color: #0969DA; - border: 1px solid rgba(9, 105, 218, 0.3); -} - -[data-bs-theme="dark"] .status-yes { - background: linear-gradient(135deg, rgba(88, 166, 255, 0.15) 0%, rgba(88, 166, 255, 0.08) 100%); - color: #58a6ff; - border-color: rgba(88, 166, 255, 0.4); + background: var(--accent-soft); + color: var(--accent); + border: 1px solid var(--accent-ring); } .status-no { - background: var(--zenith-bg-light); - color: var(--zenith-text-muted); - border: 1px solid var(--zenith-border); + background: var(--surface-sunken); + color: var(--text-tertiary); + border: 1px solid var(--border); } /* ========================================================================== @@ -1381,16 +1190,13 @@ article td a { ========================================================================== */ .alert { - position: relative; - padding: 1rem 1.25rem; + padding: 0.875rem 1.125rem; margin: 1.5rem 0; - border-radius: var(--radius-lg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - box-shadow: var(--glass-shadow); - font-size: 0.95rem; + border-radius: var(--radius-sm); + border-left-width: 3px !important; + font-size: 0.875rem; line-height: 1.6; - color: var(--zenith-text); + color: var(--text-primary); } .alert p:last-child { @@ -1408,146 +1214,134 @@ article td a { } .alert-primary { - background: rgba(9, 105, 218, 0.08); - border: 1px solid rgba(9, 105, 218, 0.2); + background: rgba(37, 99, 235, 0.05); + border: 1px solid rgba(37, 99, 235, 0.15); + border-left-color: var(--accent) !important; } .alert-primary a { - color: #0969DA; + color: var(--accent); } .alert-secondary { - background: rgba(107, 114, 128, 0.08); - border: 1px solid rgba(107, 114, 128, 0.2); + background: var(--surface-sunken); + border: 1px solid var(--border); + border-left-color: var(--border-strong) !important; } .alert-secondary a { - color: #4b5563; + color: var(--text-secondary); } .alert-success { - background: rgba(34, 197, 94, 0.08); - border: 1px solid rgba(34, 197, 94, 0.2); + background: rgba(22, 163, 74, 0.05); + border: 1px solid rgba(22, 163, 74, 0.15); + border-left-color: #16A34A !important; } .alert-success a { - color: #16a34a; + color: #16A34A; } .alert-danger { - background: rgba(239, 68, 68, 0.08); - border: 1px solid rgba(239, 68, 68, 0.2); + background: rgba(220, 38, 38, 0.05); + border: 1px solid rgba(220, 38, 38, 0.15); + border-left-color: #DC2626 !important; } .alert-danger a { - color: #dc2626; + color: #DC2626; } .alert-warning { - background: rgba(245, 158, 11, 0.08); - border: 1px solid rgba(245, 158, 11, 0.2); + background: rgba(217, 119, 6, 0.05); + border: 1px solid rgba(217, 119, 6, 0.15); + border-left-color: #D97706 !important; } .alert-warning a { - color: #d97706; + color: #D97706; } .alert-info { - background: rgba(6, 182, 212, 0.08); - border: 1px solid rgba(6, 182, 212, 0.2); + background: rgba(6, 182, 212, 0.05); + border: 1px solid rgba(6, 182, 212, 0.15); + border-left-color: #0891B2 !important; } .alert-info a { - color: #0891b2; + color: #0891B2; } .alert-light { - background: rgba(255, 255, 255, 0.5); - border: 1px solid var(--glass-border); + background: var(--surface-sunken); + border: 1px solid var(--border); + border-left-color: var(--border-strong) !important; } .alert-light a { - color: var(--zenith-primary); + color: var(--accent); } .alert-dark { - background: rgba(31, 41, 55, 0.1); - border: 1px solid rgba(31, 41, 55, 0.2); + background: var(--surface-sunken); + border: 1px solid var(--border-strong); + border-left-color: var(--text-secondary) !important; } .alert-dark a { - color: #1f2937; + color: var(--text-primary); } +/* Dark mode alert overrides */ [data-bs-theme="dark"] .alert-primary { - background: rgba(88, 166, 255, 0.1); - border-color: rgba(88, 166, 255, 0.25); + background: rgba(96, 165, 250, 0.06); + border-color: rgba(96, 165, 250, 0.18); + border-left-color: var(--accent) !important; } [data-bs-theme="dark"] .alert-primary a { - color: #58a6ff; - } - -[data-bs-theme="dark"] .alert-secondary { - background: rgba(156, 163, 175, 0.1); - border-color: rgba(156, 163, 175, 0.25); -} - - [data-bs-theme="dark"] .alert-secondary a { - color: #d1d5db; + color: var(--accent); } [data-bs-theme="dark"] .alert-success { - background: rgba(74, 222, 128, 0.1); - border-color: rgba(74, 222, 128, 0.25); + background: rgba(74, 222, 128, 0.06); + border-color: rgba(74, 222, 128, 0.18); + border-left-color: #4ADE80 !important; } [data-bs-theme="dark"] .alert-success a { - color: #86efac; + color: #86EFAC; } [data-bs-theme="dark"] .alert-danger { - background: rgba(248, 113, 113, 0.1); - border-color: rgba(248, 113, 113, 0.25); + background: rgba(248, 113, 113, 0.06); + border-color: rgba(248, 113, 113, 0.18); + border-left-color: #F87171 !important; } [data-bs-theme="dark"] .alert-danger a { - color: #fca5a5; + color: #FCA5A5; } [data-bs-theme="dark"] .alert-warning { - background: rgba(251, 191, 36, 0.1); - border-color: rgba(251, 191, 36, 0.25); + background: rgba(251, 191, 36, 0.06); + border-color: rgba(251, 191, 36, 0.18); + border-left-color: #FBBF24 !important; } [data-bs-theme="dark"] .alert-warning a { - color: #fcd34d; + color: #FCD34D; } [data-bs-theme="dark"] .alert-info { - background: rgba(34, 211, 238, 0.1); - border-color: rgba(34, 211, 238, 0.25); + background: rgba(34, 211, 238, 0.06); + border-color: rgba(34, 211, 238, 0.18); + border-left-color: #22D3EE !important; } [data-bs-theme="dark"] .alert-info a { - color: #67e8f9; - } - -[data-bs-theme="dark"] .alert-light { - background: rgba(255, 255, 255, 0.08); -} - - [data-bs-theme="dark"] .alert-light a { - color: var(--zenith-link); - } - -[data-bs-theme="dark"] .alert-dark { - background: rgba(55, 65, 81, 0.3); - border-color: rgba(75, 85, 99, 0.4); -} - - [data-bs-theme="dark"] .alert-dark a { - color: #e5e7eb; + color: #67E8F9; } /* ========================================================================== @@ -1565,50 +1359,31 @@ article td a { height: fit-content !important; max-height: calc(100vh - 100px) !important; overflow-y: auto !important; - background: var(--glass-bg) !important; - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)) !important; - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)) !important; - border: 1px solid var(--glass-border) !important; - border-radius: var(--radius-xl) !important; - box-shadow: var(--glass-shadow) !important; - padding: 0.875rem !important; + background: var(--surface) !important; + border: 1px solid var(--border) !important; + border-radius: var(--radius-md) !important; + box-shadow: var(--shadow-xs) !important; + padding: 0.75rem !important; margin-top: 1rem !important; } - .affix::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 50%; - background: linear-gradient(180deg, var(--glass-refraction) 0%, transparent 100%); - pointer-events: none; - opacity: 0.15; - border-radius: var(--radius-xl) var(--radius-xl) 0 0; - z-index: 0; - } - .affix > h5, .affix .border-bottom { - position: relative; - z-index: 1; display: block !important; width: 100% !important; - text-align: center !important; - font-size: 0.8rem !important; + text-align: left !important; + font-size: 0.6875rem !important; font-weight: 600 !important; - color: var(--zenith-text) !important; - margin: 0 0 0.5rem 0 !important; - padding: 0 !important; + color: var(--text-tertiary) !important; + margin: 0 0 0.5rem !important; + padding: 0 0.25rem 0.5rem !important; border: none !important; + border-bottom: 1px solid var(--border) !important; text-transform: uppercase; - letter-spacing: 0.05em; + letter-spacing: 0.08em; } .affix ul { - position: relative; - z-index: 1; display: flex !important; flex-direction: column !important; gap: 1px !important; @@ -1624,13 +1399,13 @@ article td a { .affix ul li a { display: block !important; - padding: 0.4rem 0.625rem !important; + padding: 0.3rem 0.5rem !important; margin: 0 !important; - border-radius: var(--radius-sm) !important; + border-radius: var(--radius-xs) !important; font-size: 0.8rem !important; font-weight: 500 !important; text-decoration: none !important; - transition: all 0.15s var(--motion-standard) !important; + transition: all var(--duration) var(--ease) !important; background: transparent !important; border: 1px solid transparent !important; cursor: pointer !important; @@ -1641,11 +1416,11 @@ article td a { } .affix .link-body-emphasis { - color: var(--zenith-text) !important; + color: var(--text-primary) !important; } .affix .link-secondary { - color: var(--zenith-text-muted) !important; + color: var(--text-secondary) !important; font-size: 0.75rem !important; font-weight: 400 !important; } @@ -1653,14 +1428,8 @@ article td a { .affix ul li a:hover, .affix ul li.active > a, .affix ul li a.active { - background: var(--surface-tint) !important; - color: var(--zenith-primary) !important; - border-color: var(--glass-border) !important; - } - - .affix ul li.active > a, - .affix ul li a.active { - border-color: var(--glass-border-hover) !important; + background: var(--accent-soft) !important; + color: var(--accent) !important; } .affix ul ul { @@ -1670,49 +1439,36 @@ article td a { gap: 0 !important; } -[data-bs-theme="dark"] .affix ul li a:hover, -[data-bs-theme="dark"] .affix ul li.active > a, -[data-bs-theme="dark"] .affix ul li a.active { - color: var(--zenith-link) !important; -} - .toc { padding: 0.5rem !important; } .toc .nav > li > a, .toc .nav > li > .expand-stub + a { - padding: 0.625rem 1rem !important; - margin: 2px 0 !important; - border-radius: var(--radius-lg) !important; - color: var(--zenith-text-muted) !important; - font-size: 0.9rem !important; + padding: 0.4rem 0.75rem !important; + margin: 1px 0 !important; + border-radius: var(--radius-sm) !important; + color: var(--text-secondary) !important; + font-size: 0.8125rem !important; font-weight: 500 !important; - transition: all 0.2s var(--motion-standard) !important; + transition: all var(--duration) var(--ease) !important; display: block !important; text-decoration: none !important; - position: relative !important; background: transparent !important; } .toc .nav > li > a:hover, .toc .nav > li > .expand-stub + a:hover { - background: var(--glass-bg) !important; - color: var(--zenith-primary) !important; - backdrop-filter: blur(8px) !important; - -webkit-backdrop-filter: blur(8px) !important; + background: var(--accent-soft) !important; + color: var(--accent) !important; } .toc .nav > li.active > a, .toc .nav > li.active > .expand-stub + a, .toc .nav > li > a.active { - background: var(--glass-bg) !important; - backdrop-filter: blur(var(--glass-blur)) !important; - -webkit-backdrop-filter: blur(var(--glass-blur)) !important; - color: var(--zenith-primary) !important; + background: var(--accent-soft-mid) !important; + color: var(--accent) !important; font-weight: 600 !important; - border: 1px solid var(--glass-border) !important; - box-shadow: var(--glass-shadow) !important; } .toc .nav > li.active > a::before, @@ -1722,33 +1478,33 @@ article td a { left: 0 !important; top: 20% !important; bottom: 20% !important; - width: 3px !important; - background: var(--zenith-gradient) !important; + width: 2px !important; + background: var(--accent) !important; border-radius: 0 2px 2px 0 !important; } .toc .nav > li > .expand-stub { - width: 32px !important; - height: 32px !important; + width: 26px !important; + height: 26px !important; display: inline-flex !important; align-items: center !important; justify-content: center !important; - border-radius: var(--radius-sm) !important; + border-radius: var(--radius-xs) !important; cursor: pointer !important; - transition: all 0.2s var(--motion-standard) !important; - margin-right: 4px !important; + transition: all var(--duration) var(--ease) !important; + margin-right: 2px !important; flex-shrink: 0 !important; background: transparent !important; } .toc .nav > li > .expand-stub:hover { - background: var(--glass-bg) !important; + background: var(--accent-soft) !important; } .toc .nav > li > .expand-stub::before { - font-size: 0.75rem !important; - color: var(--zenith-text-muted) !important; - transition: transform 0.2s var(--motion-standard) !important; + font-size: 0.65rem !important; + color: var(--text-tertiary) !important; + transition: transform var(--duration) var(--ease) !important; } .toc .nav > li.in > .expand-stub::before, @@ -1757,59 +1513,42 @@ article td a { } .toc .nav .nav { - padding-left: 0.75rem !important; - margin-left: 0.75rem !important; - border-left: 2px solid var(--glass-divider) !important; + padding-left: 0.625rem !important; + margin-left: 0.625rem !important; + border-left: 1px solid var(--border) !important; } .toc .nav .nav > li > a { - font-size: 0.85rem !important; - padding: 0.5rem 0.875rem !important; - color: var(--zenith-text-muted) !important; - border-radius: var(--radius-sm) !important; + font-size: 0.78rem !important; + padding: 0.35rem 0.625rem !important; + color: var(--text-secondary) !important; + border-radius: var(--radius-xs) !important; } .toc .nav .nav > li > a:hover, .toc .nav .nav > li.active > a { - background: var(--surface-tint) !important; - color: var(--zenith-primary) !important; + background: var(--accent-soft) !important; + color: var(--accent) !important; } .toc .nav .nav > li.active > a { font-weight: 600 !important; } -[data-bs-theme="dark"] .toc .nav > li > a:hover, -[data-bs-theme="dark"] .toc .nav > li > .expand-stub + a:hover, -[data-bs-theme="dark"] .toc .nav > li.active > a, -[data-bs-theme="dark"] .toc .nav > li.active > .expand-stub + a, -[data-bs-theme="dark"] .toc .nav > li > a.active, -[data-bs-theme="dark"] .toc .nav .nav > li > a:hover, -[data-bs-theme="dark"] .toc .nav .nav > li.active > a { - color: var(--zenith-link) !important; -} - - [data-bs-theme="dark"] .toc .nav > li.active > a::before, - [data-bs-theme="dark"] .toc .nav > li > a.active::before { - background: linear-gradient(180deg, #58a6ff 0%, #a5d6ff 100%) !important; - } - +/* Sidebar filter / search */ .sidefilter .filter-input, .sidetoc .filter, .sidebar input.form-control[type="search"], #toc .filter input.form-control { - position: relative !important; - background: var(--glass-bg) !important; - backdrop-filter: blur(var(--glass-blur)) !important; - -webkit-backdrop-filter: blur(var(--glass-blur)) !important; - border: 1px solid var(--glass-border) !important; - border-radius: var(--radius-lg) !important; - padding: 0.625rem 1rem 0.625rem 2.25rem !important; - font-size: 0.85rem !important; - color: var(--zenith-text) !important; - transition: all 0.2s ease !important; + background: var(--surface-sunken) !important; + border: 1px solid var(--border) !important; + border-radius: var(--radius-sm) !important; + padding: 0.4rem 0.875rem 0.4rem 2rem !important; + font-size: 0.8rem !important; + color: var(--text-primary) !important; + transition: all var(--duration) var(--ease) !important; width: 100% !important; - box-shadow: var(--glass-shadow) !important; + box-shadow: none !important; } .sidefilter .filter-input:focus, @@ -1817,24 +1556,17 @@ article td a { .sidebar input.form-control[type="search"]:focus, #toc .filter input.form-control:focus { outline: none !important; - border-color: #0969DA !important; - box-shadow: var(--glass-shadow), 0 0 0 3px rgba(9, 105, 218, 0.15) !important; + border-color: var(--accent) !important; + box-shadow: 0 0 0 3px var(--accent-ring) !important; + background: var(--surface) !important; } -[data-bs-theme="dark"] .sidefilter .filter-input:focus, -[data-bs-theme="dark"] .sidetoc .filter:focus, -[data-bs-theme="dark"] .sidebar input.form-control[type="search"]:focus, -[data-bs-theme="dark"] #toc .filter input.form-control:focus { - border-color: #58a6ff !important; - box-shadow: var(--glass-shadow), 0 0 0 3px rgba(88, 166, 255, 0.2) !important; -} - -.sidefilter .filter-input::placeholder, -.sidetoc .filter::placeholder, -.sidebar input.form-control[type="search"]::placeholder, -#toc .filter input.form-control::placeholder { - color: var(--zenith-text-muted) !important; -} + .sidefilter .filter-input::placeholder, + .sidetoc .filter::placeholder, + .sidebar input.form-control[type="search"]::placeholder, + #toc .filter input.form-control::placeholder { + color: var(--text-tertiary) !important; + } #toc .filter { position: relative !important; @@ -1843,11 +1575,11 @@ article td a { #toc .filter i { position: absolute !important; - left: 0.75rem !important; + left: 0.5rem !important; top: 50% !important; transform: translateY(-50%) !important; - color: var(--zenith-text-muted) !important; - font-size: 0.9rem !important; + color: var(--text-tertiary) !important; + font-size: 0.8rem !important; z-index: 1 !important; pointer-events: none !important; } @@ -1864,7 +1596,7 @@ article td a { } #toc .flex-fill.overflow-y-auto > ul > li { - margin-top: 2px !important; + margin-top: 1px !important; padding: 0 !important; } @@ -1881,7 +1613,7 @@ article td a { display: flex !important; flex-wrap: wrap !important; align-items: stretch !important; - border-radius: var(--radius-sm) !important; + border-radius: var(--radius-xs) !important; } #toc .flex-fill.overflow-y-auto li.expander > .expand-stub, @@ -1895,11 +1627,11 @@ article td a { #toc .flex-fill.overflow-y-auto li.expander.active > .expand-stub, #toc .flex-fill.overflow-y-auto li.expander.active > a, #toc .flex-fill.overflow-y-auto li.expander > a.active { - background: var(--surface-tint) !important; + background: var(--accent-soft) !important; } #toc .flex-fill.overflow-y-auto li.expander:hover > a { - color: var(--zenith-primary) !important; + color: var(--accent) !important; } #toc .flex-fill.overflow-y-auto li .expand-stub { @@ -1908,12 +1640,12 @@ article td a { justify-content: center !important; width: calc(var(--toc-expand-width) + 0.5rem) !important; height: auto !important; - min-height: 28px !important; - border-radius: var(--radius-sm) 0 0 var(--radius-sm) !important; - transition: all 0.15s var(--motion-standard) !important; + min-height: 26px !important; + border-radius: var(--radius-xs) 0 0 var(--radius-xs) !important; + transition: all var(--duration) var(--ease) !important; cursor: pointer !important; flex-shrink: 0 !important; - padding: 0.5rem 0 0.5rem 0.5rem !important; + padding: 0.4rem 0 0.4rem 0.4rem !important; } #toc .flex-fill.overflow-y-auto li .expand-stub::before { @@ -1921,31 +1653,31 @@ article td a { } #toc .flex-fill.overflow-y-auto li.expander > a { - border-radius: 0 var(--radius-sm) var(--radius-sm) 0 !important; - padding: 0.5rem 0.5rem 0.5rem 0.125rem !important; + border-radius: 0 var(--radius-xs) var(--radius-xs) 0 !important; + padding: 0.4rem 0.4rem 0.4rem 0.125rem !important; } #toc .flex-fill.overflow-y-auto li.expander > ul { width: 100% !important; flex-basis: 100% !important; - margin-top: 4px !important; - margin-bottom: 4px !important; + margin-top: 2px !important; + margin-bottom: 2px !important; } #toc .flex-fill.overflow-y-auto li > a { display: inline-block !important; - padding: 0.5rem 0.625rem !important; + padding: 0.35rem 0.4rem !important; margin: 0 !important; - border-radius: var(--radius-sm) !important; - font-size: 0.85rem !important; + border-radius: var(--radius-xs) !important; + font-size: 0.8rem !important; font-weight: 500 !important; text-decoration: none !important; - transition: all 0.15s var(--motion-standard) !important; + transition: all var(--duration) var(--ease) !important; background: transparent !important; border: 1px solid transparent !important; cursor: pointer !important; line-height: 1.3 !important; - color: var(--zenith-text-muted) !important; + color: var(--text-secondary) !important; flex: 1 !important; } @@ -1954,16 +1686,14 @@ article td a { } #toc .flex-fill.overflow-y-auto li:not(.expander) > a:hover { - background: var(--surface-tint) !important; - color: var(--zenith-primary) !important; - border-color: var(--glass-border) !important; + background: var(--accent-soft) !important; + color: var(--accent) !important; } #toc .flex-fill.overflow-y-auto li.active > a, #toc .flex-fill.overflow-y-auto li > a.active { - background: var(--surface-tint) !important; - color: var(--zenith-primary) !important; - border-color: var(--glass-border-hover) !important; + background: var(--accent-soft-mid) !important; + color: var(--accent) !important; font-weight: 600 !important; } @@ -1974,7 +1704,7 @@ article td a { } #toc .flex-fill.overflow-y-auto ul ul li { - margin-top: 2px !important; + margin-top: 1px !important; } #toc .flex-fill.overflow-y-auto ul ul li:first-child { @@ -1982,17 +1712,10 @@ article td a { } #toc .flex-fill.overflow-y-auto ul ul li > a { - font-size: 0.8rem !important; - padding: 0.35rem 0.5rem !important; + font-size: 0.75rem !important; + padding: 0.25rem 0.375rem !important; } -[data-bs-theme="dark"] #toc .flex-fill.overflow-y-auto li.expander:hover > a, -[data-bs-theme="dark"] #toc .flex-fill.overflow-y-auto li:not(.expander) > a:hover, -[data-bs-theme="dark"] #toc .flex-fill.overflow-y-auto li.active > a, -[data-bs-theme="dark"] #toc .flex-fill.overflow-y-auto li > a.active { - color: var(--zenith-link) !important; -} - /* ========================================================================== 19. Breadcrumb Navigation ========================================================================== */ @@ -2006,64 +1729,56 @@ article td a { flex-wrap: wrap; align-items: center; gap: 0.25rem; - padding: 0.625rem 1rem; + padding: 0.4rem 0.75rem; margin: 0; - background: var(--glass-bg); - backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); - border: 1px solid var(--glass-border); - border-radius: var(--radius-lg); - box-shadow: var(--glass-shadow); + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-sm); list-style: none; } .breadcrumb-item { display: flex; align-items: center; - font-size: 0.85rem; - color: var(--zenith-text-muted); + font-size: 0.8rem; + color: var(--text-secondary); } .breadcrumb-item a { - color: var(--zenith-text-muted); + color: var(--text-secondary); text-decoration: none; - padding: 0.25rem 0.5rem; - border-radius: var(--radius-sm); - transition: all 0.15s var(--motion-standard); + padding: 0.15rem 0.3rem; + border-radius: var(--radius-xs); + transition: all var(--duration) var(--ease); } .breadcrumb-item a:hover { - color: var(--zenith-primary); - background: var(--surface-tint); + color: var(--accent); + background: var(--accent-soft); text-decoration: none; } .breadcrumb-item + .breadcrumb-item::before { content: ''; display: inline-block; - width: 6px; - height: 6px; - margin-right: 0.5rem; - border-right: 1.5px solid var(--zenith-text-muted); - border-top: 1.5px solid var(--zenith-text-muted); + width: 5px; + height: 5px; + margin-right: 0.3rem; + border-right: 1.5px solid var(--text-tertiary); + border-top: 1.5px solid var(--text-tertiary); transform: rotate(45deg); - opacity: 0.6; } .breadcrumb-item:last-child { - color: var(--zenith-text); + color: var(--text-primary); font-weight: 500; } .breadcrumb-item:last-child a { - color: var(--zenith-text); + color: var(--text-primary); pointer-events: none; } -[data-bs-theme="dark"] .breadcrumb-item a:hover { - color: var(--zenith-link); -} - /* ========================================================================== 20. Hide UI Elements ========================================================================== */ @@ -2084,29 +1799,12 @@ a[href^="https"]::after { ========================================================================== */ @media (max-width: 768px) { - header.bg-body, - .navbar { - background: var(--glass-bg-solid) !important; - } - - .actionbar { - display: flex; - align-items: center; - gap: 0.75rem; - } - - .actionbar > button { - flex-shrink: 0; - margin-top: 0 !important; - margin-left: 0 !important; - } - .hero { - padding: 1.5rem 1.5rem 2rem 1.5rem; + padding: 2.5rem 1.25rem 3rem; } .hero h1 { - font-size: 2.5rem; + font-size: 2.25rem; } .hero-tagline { @@ -2114,36 +1812,36 @@ a[href^="https"]::after { } .hero-description { - font-size: 1rem; + font-size: 0.95rem; } .hero-logo { - width: 80px; - height: 80px; + width: 64px; + height: 64px; } .tech-item { - padding: 0.5rem 1rem; + padding: 0.4rem 0.75rem; } .workflow { - --step-number-size: 40px; + --step-size: 38px; } .step-number { - font-size: 1rem; + font-size: 0.9rem; } .step-content { - padding: 1rem; + padding: 0.875rem 1rem; } article h1 { - font-size: 1.75rem; + font-size: 1.625rem; } article h2 { - font-size: 1.5rem; + font-size: 1.25rem; padding-left: 0.75rem; position: relative; } @@ -2153,31 +1851,31 @@ a[href^="https"]::after { display: block; position: absolute; left: 0; - top: 0.1em; - bottom: 0.1em; + top: 0.15em; + bottom: 0.15em; width: 3px; - background: var(--zenith-gradient); + background: var(--gradient-brand); border-radius: 2px; } article h3 { - font-size: 1.2rem; + font-size: 1.05rem; } article pre { - border-radius: 8px; + border-radius: var(--radius-sm); } .status-yes, .status-no { - padding: 0.2rem 0.5rem; - font-size: 0.75rem; + padding: 0.1rem 0.4rem; + font-size: 0.7rem; } .tech-bar { flex-direction: column; - gap: 1rem; - padding: 1.25rem 1.5rem; + gap: 0.75rem; + padding: 0.875rem 1.125rem; } .tech-bar-group { @@ -2196,12 +1894,12 @@ a[href^="https"]::after { } .highlight-item { - padding: 1rem; + padding: 0.875rem; } .feature-list-item { flex-direction: column; - gap: 0.5rem; + gap: 0.25rem; } .feature-list-title { @@ -2210,39 +1908,57 @@ a[href^="https"]::after { .cta-section { flex-direction: column; - padding: 2rem 1.5rem; + padding: 1.5rem 1.25rem; text-align: center; } + .cta-section::before { + /* Shift gradient line to left side on mobile */ + left: 0; + right: auto; + top: 0; + bottom: 0; + width: 3px; + height: 100%; + } + .cta-main h3 { - font-size: 1.5rem; + font-size: 1.25rem; } .cta-links { width: 100%; + align-items: stretch; } .cta-link { justify-content: center; + width: 100%; min-width: auto; } .breadcrumb { - padding: 0.5rem 0.75rem; - border-radius: var(--radius-md); + padding: 0.35rem 0.5rem; } .breadcrumb-item { - font-size: 0.8rem; + font-size: 0.75rem; } - .breadcrumb-item a { - padding: 0.2rem 0.375rem; - } - .alert { - padding: 0.875rem 1rem; - font-size: 0.9rem; - border-radius: var(--radius-md); + padding: 0.75rem 0.875rem; + font-size: 0.8125rem; } + + .actionbar { + display: flex; + align-items: center; + gap: 0.75rem; + } + + .actionbar > button { + flex-shrink: 0; + margin-top: 0 !important; + margin-left: 0 !important; + } } diff --git a/documents/templates/public/main.js b/documents/templates/public/main.js index 0eef3ecb..c080a739 100644 --- a/documents/templates/public/main.js +++ b/documents/templates/public/main.js @@ -1,9 +1,67 @@ export default { - iconLinks: [ - { - icon: 'github', - href: 'https://github.com/qian-o/Zenith.NET', - title: 'GitHub' + iconLinks: [ + { + icon: 'github', + href: 'https://github.com/qian-o/Zenith.NET', + title: 'GitHub' + } + ], + start: () => { + // Hide inherited type info sections (inheritance, implements, inheritedMembers, derivedClasses) + for (const dl of document.querySelectorAll('dl.typelist.inheritance, dl.typelist.implements, dl.typelist.inheritedMembers, dl.typelist.derivedClasses')) { + dl.style.display = 'none'; + } + + // Hide protected and override members from API pages + for (const code of document.querySelectorAll('.codewrapper pre code')) { + const text = code.textContent.trim(); + if (!/^protected\s/.test(text) && !/\boverride\b/.test(text)) continue; + + const wrapper = code.closest('.codewrapper'); + if (!wrapper) continue; + + const toHide = []; + + // Walk backward from codewrapper to collect h3 header and anchor + let el = wrapper; + while (el) { + toHide.push(el); + if (el.tagName === 'H3') { + // Also grab the preceding overload anchor + const prev = el.previousElementSibling; + if (prev && prev.tagName === 'A' && prev.dataset.uid) { + toHide.push(prev); + } + break; + } + el = el.previousElementSibling; + } + + // Walk forward from codewrapper to collect parameters, returns, etc. + let next = wrapper.nextElementSibling; + while (next && next.tagName !== 'H3' && next.tagName !== 'H2' && + !(next.tagName === 'A' && next.dataset.uid)) { + toHide.push(next); + next = next.nextElementSibling; + } + + toHide.forEach(e => e.style.display = 'none'); + } + + // Hide empty section headers (e.g. "Constructors" when all constructors are hidden) + for (const h2 of document.querySelectorAll('article h2.section')) { + let next = h2.nextElementSibling; + let hasVisibleMember = false; + while (next && next.tagName !== 'H2') { + if (next.tagName === 'H3' && next.style.display !== 'none') { + hasVisibleMember = true; + break; + } + next = next.nextElementSibling; + } + if (!hasVisibleMember) { + h2.style.display = 'none'; + } + } } - ] } \ No newline at end of file diff --git a/documents/toc.yml b/documents/toc.yml index e677fc21..b1d527b5 100644 --- a/documents/toc.yml +++ b/documents/toc.yml @@ -1,8 +1,11 @@ - name: Docs href: docs/ + homepage: docs/index.md - name: Tutorials href: tutorials/ + homepage: tutorials/index.md - name: API href: api/ + homepage: api/index.md diff --git a/documents/tutorials/advanced/mesh-shading.md b/documents/tutorials/advanced/mesh-shading.md index 30fb3996..30771e2b 100644 --- a/documents/tutorials/advanced/mesh-shading.md +++ b/documents/tutorials/advanced/mesh-shading.md @@ -74,11 +74,19 @@ internal unsafe class MeshShadingRenderer : IRenderer struct Vertex { - float3 Position; + private float4 PositionAndPadding; - float3 Normal; + private float4 NormalAndPadding; float2 TexCoord; + + private float padding0; + + private float padding1; + + property float3 Position { get { return PositionAndPadding.xyz; } } + + property float3 Normal { get { return NormalAndPadding.xyz; } } }; struct Meshlet @@ -92,6 +100,13 @@ internal unsafe class MeshShadingRenderer : IRenderer uint PrimitiveCount; }; + struct Triangle + { + private uint4 IndicesAndPadding; + + property uint3 Indices { get { return IndicesAndPadding.xyz; } } + }; + struct TransformConstants { float4x4 MVP; @@ -108,36 +123,36 @@ internal unsafe class MeshShadingRenderer : IRenderer ConstantBuffer transform; StructuredBuffer vertices; - StructuredBuffer indices; + StructuredBuffer indices; StructuredBuffer meshlets; [shader("mesh")] [numthreads(MaxPrimitives, 1, 1)] [outputtopology("triangle")] - void MSMain(in uint groupId : SV_GroupID, - in uint groupThreadId : SV_GroupThreadID, + void MSMain(in uint groupID : SV_GroupID, + in uint groupThreadID : SV_GroupThreadID, OutputVertices outVertices, OutputIndices outIndices) { - Meshlet meshlet = meshlets[groupId]; + Meshlet meshlet = meshlets[groupID]; SetMeshOutputCounts(meshlet.VertexCount, meshlet.PrimitiveCount); - if (groupThreadId < meshlet.VertexCount) + if (groupThreadID < meshlet.VertexCount) { - Vertex vertex = vertices[meshlet.VertexOffset + groupThreadId]; + Vertex vertex = vertices[meshlet.VertexOffset + groupThreadID]; VertexOutput output; output.Position = mul(float4(vertex.Position, 1.0), transform.MVP); output.Normal = vertex.Normal; output.TexCoord = vertex.TexCoord; - outVertices[groupThreadId] = output; + outVertices[groupThreadID] = output; } - if (groupThreadId < meshlet.PrimitiveCount) + if (groupThreadID < meshlet.PrimitiveCount) { - outIndices[groupThreadId] = indices[meshlet.PrimitiveOffset + groupThreadId]; + outIndices[groupThreadID] = indices[meshlet.PrimitiveOffset + groupThreadID].Indices; } } @@ -216,14 +231,26 @@ internal unsafe class MeshShadingRenderer : IRenderer new() { Position = new(-0.5f, -0.5f, 0.5f), Normal = new( 0, -1, 0), TexCoord = new(0, 0) } ]; - uint[] cubeIndices = + Triangle[] cubeTriangles = [ - 0, 1, 2, 0, 2, 3, - 4, 5, 6, 4, 6, 7, - 8, 9, 10, 8, 10, 11, - 12, 13, 14, 12, 14, 15, - 16, 17, 18, 16, 18, 19, - 20, 21, 22, 20, 22, 23 + // Front face + new() { I0 = 0, I1 = 1, I2 = 2 }, + new() { I0 = 0, I1 = 2, I2 = 3 }, + // Back face + new() { I0 = 4, I1 = 5, I2 = 6 }, + new() { I0 = 4, I1 = 6, I2 = 7 }, + // Left face + new() { I0 = 8, I1 = 9, I2 = 10 }, + new() { I0 = 8, I1 = 10, I2 = 11 }, + // Right face + new() { I0 = 12, I1 = 13, I2 = 14 }, + new() { I0 = 12, I1 = 14, I2 = 15 }, + // Top face + new() { I0 = 16, I1 = 17, I2 = 18 }, + new() { I0 = 16, I1 = 18, I2 = 19 }, + // Bottom face + new() { I0 = 20, I1 = 21, I2 = 22 }, + new() { I0 = 20, I1 = 22, I2 = 23 } ]; Meshlet[] meshlets = @@ -233,7 +260,7 @@ internal unsafe class MeshShadingRenderer : IRenderer VertexOffset = 0, VertexCount = (uint)cubeVertices.Length, PrimitiveOffset = 0, - PrimitiveCount = (uint)cubeIndices.Length / 3 + PrimitiveCount = (uint)cubeTriangles.Length } ]; meshletCount = (uint)meshlets.Length; @@ -247,14 +274,14 @@ internal unsafe class MeshShadingRenderer : IRenderer }); vertexBuffer.Upload(cubeVertices, 0); - // Create index buffer (3 uints per triangle = uint3 in shader) + // Create index buffer (Triangle struct per triangle) indexBuffer = App.Context.CreateBuffer(new() { - SizeInBytes = (uint)(sizeof(uint) * cubeIndices.Length), - StrideInBytes = sizeof(uint) * 3, // uint3 stride + SizeInBytes = (uint)(sizeof(Triangle) * cubeTriangles.Length), + StrideInBytes = (uint)sizeof(Triangle), Flags = BufferUsageFlags.ShaderResource }); - indexBuffer.Upload(cubeIndices, 0); + indexBuffer.Upload(cubeTriangles, 0); meshletBuffer = App.Context.CreateBuffer(new() { @@ -362,37 +389,61 @@ internal unsafe class MeshShadingRenderer : IRenderer /// /// Vertex structure with position and normal. /// -[StructLayout(LayoutKind.Sequential)] +[StructLayout(LayoutKind.Explicit, Size = 48)] file struct Vertex { + [FieldOffset(0)] public Vector3 Position; + [FieldOffset(16)] public Vector3 Normal; + [FieldOffset(32)] public Vector2 TexCoord; } +/// +/// Triangle indices for mesh shading. +/// +[StructLayout(LayoutKind.Explicit, Size = 16)] +file struct Triangle +{ + [FieldOffset(0)] + public uint I0; + + [FieldOffset(4)] + public uint I1; + + [FieldOffset(8)] + public uint I2; +} + /// /// Meshlet structure defining a chunk of geometry. /// -[StructLayout(LayoutKind.Sequential)] +[StructLayout(LayoutKind.Explicit, Size = 16)] file struct Meshlet { + [FieldOffset(0)] public uint VertexOffset; + [FieldOffset(4)] public uint VertexCount; + [FieldOffset(8)] public uint PrimitiveOffset; + [FieldOffset(12)] public uint PrimitiveCount; } /// /// Transform constants for the mesh. /// -[StructLayout(LayoutKind.Sequential)] +[StructLayout(LayoutKind.Explicit, Size = 64)] file struct TransformConstants { + [FieldOffset(0)] public Matrix4x4 MVP; } ``` @@ -436,15 +487,19 @@ Always check `Capabilities.MeshShadingSupported` before using mesh shading featu ### Meshlet Data Structure ```csharp -[StructLayout(LayoutKind.Sequential)] +[StructLayout(LayoutKind.Explicit, Size = 16)] file struct Meshlet { + [FieldOffset(0)] public uint VertexOffset; + [FieldOffset(4)] public uint VertexCount; + [FieldOffset(8)] public uint PrimitiveOffset; + [FieldOffset(12)] public uint PrimitiveCount; } ``` @@ -459,8 +514,8 @@ Each meshlet describes a chunk of geometry: [shader("mesh")] [numthreads(MaxPrimitives, 1, 1)] [outputtopology("triangle")] -void MSMain(in uint groupId : SV_GroupID, - in uint groupThreadId : SV_GroupThreadID, +void MSMain(in uint groupID : SV_GroupID, + in uint groupThreadID : SV_GroupThreadID, OutputVertices outVertices, OutputIndices outIndices) ``` @@ -516,7 +571,7 @@ The `MeshShadingPipelineDesc` requires: - `Mesh` - The compiled mesh shader - `Pixel` - The compiled pixel shader - `ResourceLayout` - Resource bindings (same as graphics pipelines) -- `ObjectThreadGroupSizeX/Y/Z` - Must match `[numthreads()]` in the amplification shader (if used) +- `AmplificationThreadGroupSizeX/Y/Z` - Must match `[numthreads()]` in the amplification shader (if used) - `MeshThreadGroupSizeX/Y/Z` - Must match `[numthreads()]` in the mesh shader ## Amplification Shader (Optional) @@ -531,8 +586,8 @@ struct AmplificationPayload [shader("amplification")] [numthreads(32, 1, 1)] -void ASMain(in uint groupId : SV_GroupID, - in uint groupThreadId : SV_GroupThreadID) +void ASMain(in uint groupID : SV_GroupID, + in uint groupThreadID : SV_GroupThreadID) { // Frustum culling, LOD selection, etc. bool visible = /* culling logic */; @@ -540,7 +595,7 @@ void ASMain(in uint groupId : SV_GroupID, if (visible) { AmplificationPayload payload; - payload.MeshletIndices[groupThreadId] = groupId * 32 + groupThreadId; + payload.MeshletIndices[groupThreadID] = groupID * 32 + groupThreadID; // Dispatch mesh shading workgroups DispatchMesh(visibleCount, 1, 1, payload); @@ -560,8 +615,6 @@ void ASMain(in uint groupId : SV_GroupID, Congratulations! You've completed all Zenith.NET tutorials. -For a complete rendering example combining multiple techniques, check out the [SponzaScene](https://github.com/qian-o/Zenith.NET/tree/master/sources/Experiments/SponzaScene) sample which demonstrates a deferred renderer with ray traced global illumination. - ## Source Code > [!TIP] diff --git a/documents/tutorials/advanced/ray-tracing.md b/documents/tutorials/advanced/ray-tracing.md index 06e66530..cb0ca2f8 100644 --- a/documents/tutorials/advanced/ray-tracing.md +++ b/documents/tutorials/advanced/ray-tracing.md @@ -61,13 +61,15 @@ internal unsafe class RayTracingRenderer : IRenderer private const string ShaderSource = """ struct Sphere { - float3 Center; + private float4 CenterAndRadius; - float Radius; + private float4 ColorAndPadding; - float3 Color; + property float3 Center { get { return CenterAndRadius.xyz; } } - float Padding; + property float Radius { get { return CenterAndRadius.w; } } + + property float3 Color { get { return ColorAndPadding.xyz; } } }; RaytracingAccelerationStructure scene; @@ -384,16 +386,16 @@ internal unsafe class RayTracingRenderer : IRenderer new() { AccelerationStructure = floorBlas, - InstanceID = 0, - InstanceMask = 0xFF, + ID = 0, + Mask = 0xFF, Transform = Matrix4x4.Identity, Flags = RayTracingInstanceFlags.None }, new() { AccelerationStructure = sphereBlas, - InstanceID = 1, - InstanceMask = 0xFF, + ID = 1, + Mask = 0xFF, Transform = Matrix4x4.Identity, Flags = RayTracingInstanceFlags.None } @@ -501,16 +503,17 @@ internal unsafe class RayTracingRenderer : IRenderer /// /// Sphere definition for procedural geometry. /// -[StructLayout(LayoutKind.Sequential)] +[StructLayout(LayoutKind.Explicit, Size = 32)] file struct Sphere { + [FieldOffset(0)] public Vector3 Center; + [FieldOffset(12)] public float Radius; + [FieldOffset(16)] public Vector3 Color; - - public float Padding; } ``` @@ -611,16 +614,16 @@ tlas = buildCmd.BuildAccelerationStructure(new TopLevelAccelerationStructureDesc new() { AccelerationStructure = floorBlas, - InstanceID = 0, - InstanceMask = 0xFF, + ID = 0, + Mask = 0xFF, Transform = Matrix4x4.Identity, ... }, new() { AccelerationStructure = sphereBlas, - InstanceID = 1, - InstanceMask = 0xFF, + ID = 1, + Mask = 0xFF, Transform = Matrix4x4.Identity, ... } diff --git a/documents/tutorials/getting-started/spinning-cube.md b/documents/tutorials/getting-started/spinning-cube.md index 27b1be9f..9a94e529 100644 --- a/documents/tutorials/getting-started/spinning-cube.md +++ b/documents/tutorials/getting-started/spinning-cube.md @@ -229,13 +229,16 @@ file struct Vertex(Vector3 position, Vector4 color) /// /// MVP transformation matrices. /// -[StructLayout(LayoutKind.Sequential)] +[StructLayout(LayoutKind.Explicit, Size = 192)] file struct MVPConstants { + [FieldOffset(0)] public Matrix4x4 Model; + [FieldOffset(64)] public Matrix4x4 View; + [FieldOffset(128)] public Matrix4x4 Projection; } ``` @@ -268,13 +271,16 @@ dotnet run ### MVP Constants Structure ```csharp -[StructLayout(LayoutKind.Sequential)] +[StructLayout(LayoutKind.Explicit, Size = 192)] file struct MVPConstants { + [FieldOffset(0)] public Matrix4x4 Model; + [FieldOffset(64)] public Matrix4x4 View; + [FieldOffset(128)] public Matrix4x4 Projection; } ``` diff --git a/documents/tutorials/intermediate/indirect-drawing.md b/documents/tutorials/intermediate/indirect-drawing.md index 608148bc..a601c712 100644 --- a/documents/tutorials/intermediate/indirect-drawing.md +++ b/documents/tutorials/intermediate/indirect-drawing.md @@ -290,22 +290,26 @@ file struct Vertex(Vector3 position, Vector4 color) /// /// Per-instance transformation and color data. /// -[StructLayout(LayoutKind.Sequential)] +[StructLayout(LayoutKind.Explicit, Size = 80)] file struct InstanceData { + [FieldOffset(0)] public Matrix4x4 Model; + [FieldOffset(64)] public Vector4 Color; } /// /// View and projection matrices. /// -[StructLayout(LayoutKind.Sequential)] +[StructLayout(LayoutKind.Explicit, Size = 128)] file struct ViewConstants { + [FieldOffset(0)] public Matrix4x4 View; + [FieldOffset(64)] public Matrix4x4 Projection; } ``` diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index 6e1e086a..5929646b 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -5,21 +5,21 @@ - + - - + + + - - + diff --git a/sources/Experiments/CornellBox/App.cs b/sources/Experiments/CornellBox/App.cs new file mode 100644 index 00000000..d0c30ef2 --- /dev/null +++ b/sources/Experiments/CornellBox/App.cs @@ -0,0 +1,202 @@ +using System.Numerics; +using CornellBox.Handlers; +using CornellBox.Helpers; +using CornellBox.Renderers; +using Hexa.NET.ImGui; +using Silk.NET.Input; +using Silk.NET.Windowing; +using Zenith.NET; +using Zenith.NET.DirectX12; +using Zenith.NET.Metal; +using Zenith.NET.Vulkan; + +namespace CornellBox; + +internal static class App +{ + private static readonly IWindow window; + private static readonly IInputContext input; + private static readonly SwapChain swapChain; + private static readonly ImGuiHandler imGui; + private static readonly CameraHandler camera; + private static readonly PathTracingRenderer? pathTracer; + private static readonly RasterizationRenderer rasterizer; + + private static Renderer activeRenderer; + private static int currentMode; + + static App() + { + if (OperatingSystem.IsWindows()) + { + Context = GraphicsContext.CreateDirectX12(useValidationLayer: true); + } + else if (OperatingSystem.IsLinux()) + { + Context = GraphicsContext.CreateVulkan(useValidationLayer: true); + } + else + { + Context = GraphicsContext.CreateMetal(useValidationLayer: true); + } + + Context.ValidationMessage += static (sender, args) => Console.WriteLine($"[{args.Source} - {args.Severity}] {args.Message}"); + + window = Window.Create(WindowOptions.Default with { API = GraphicsAPI.None }); + window.Size = new(1280, 720); + window.Initialize(); + window.Center(); + + input = window.CreateInput(); + + Surface surface; + if (OperatingSystem.IsWindows()) + { + surface = Surface.Win32(window.Native!.Win32!.Value.Hwnd, Width, Height); + } + else if (OperatingSystem.IsLinux()) + { + surface = Surface.Xlib(window.Native!.X11!.Value.Display, (nint)window.Native.X11.Value.Window, Width, Height); + } + else + { + surface = Surface.Apple(CocoaHelper.CreateLayer(window.Native!.Cocoa!.Value), Width, Height); + } + + swapChain = Context.CreateSwapChain(new() { Surface = surface, ColorTargetFormat = PixelFormat.B8G8R8A8UNorm, DepthStencilTargetFormat = PixelFormat.D32FloatS8UInt }); + imGui = new(input, swapChain.FrameBuffer.Output); + camera = new(input, Matrix4x4.CreateTranslation(278f, 273f, -800f)) + { + Speed = 240.0f, + FarPlane = 2000.0f + }; + + rasterizer = new(); + + if (Context.Capabilities.RayTracingSupported) + { + activeRenderer = pathTracer = new(); + currentMode = 0; + } + else + { + activeRenderer = rasterizer; + currentMode = 1; + } + } + + public static GraphicsContext Context { get; } + + public static uint Width => (uint)window.FramebufferSize.X; + + public static uint Height => (uint)window.FramebufferSize.Y; + + public static Vector2 DpiScale => (Vector2)window.FramebufferSize / (Vector2)window.Size; + + public static void Run() + { + window.Update += delta => + { + if (Width is 0 || Height is 0) + { + return; + } + + uint width = (uint)(Width / DpiScale.X); + uint height = (uint)(Height / DpiScale.Y); + + imGui.Update(delta, width, height); + camera.Update(delta, width, height); + + // ImGui + { + ImGui.GetBackgroundDrawList().AddImage(imGui.Binding(activeRenderer.Color), new(0, 0), new(Width / DpiScale.X, Height / DpiScale.Y)); + + ImGui.SetNextWindowPos(new(10, 10), ImGuiCond.FirstUseEver); + if (ImGui.Begin("Cornell Box", ImGuiWindowFlags.AlwaysAutoResize)) + { + ImGui.Text($"Backend: {Context.Backend}"); + ImGui.Text(Context.Capabilities.DeviceName); + + ImGui.Separator(); + + ImGui.Text("Render Mode:"); + + if (Context.Capabilities.RayTracingSupported) + { + if (ImGui.RadioButton("Path Tracing", currentMode is 0) && currentMode is not 0) + { + pathTracer!.FrameCount = 0; + + currentMode = 0; + activeRenderer = pathTracer; + } + + ImGui.SameLine(); + } + + if (ImGui.RadioButton("Rasterization", currentMode is 1) && currentMode is not 1) + { + currentMode = 1; + activeRenderer = rasterizer; + } + + ImGui.Separator(); + + if (currentMode is 0 && pathTracer is not null) + { + ImGui.Text($"SPP: {pathTracer.FrameCount}"); + } + + ImGui.Text($"FPS: {ImGui.GetIO().Framerate:F1}"); + } + ImGui.End(); + } + + activeRenderer.Update(camera); + }; + + window.Render += _ => + { + if (Width is 0 || Height is 0) + { + return; + } + + CommandBuffer commandBuffer = Context.Graphics.CommandBuffer(); + + activeRenderer.Render(commandBuffer); + + imGui.Render(commandBuffer, swapChain.FrameBuffer, ClearValues.Default); + + commandBuffer.Submit(true); + + swapChain.Present(); + }; + + window.Resize += _ => + { + if (Width is 0 || Height is 0) + { + return; + } + + pathTracer?.Resize(Width, Height); + rasterizer.Resize(Width, Height); + swapChain.Resize(Width, Height); + }; + + window.Run(); + + pathTracer?.Dispose(); + rasterizer.Dispose(); + imGui.Dispose(); + swapChain.Dispose(); + input.Dispose(); + window.Dispose(); + + Context.Dispose(); + + Console.WriteLine("Exited cleanly."); + } +} diff --git a/sources/Experiments/SponzaScene/Assets/Fonts/msyh.ttf b/sources/Experiments/CornellBox/Assets/Fonts/msyh.ttf similarity index 100% rename from sources/Experiments/SponzaScene/Assets/Fonts/msyh.ttf rename to sources/Experiments/CornellBox/Assets/Fonts/msyh.ttf diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/.clang-format b/sources/Experiments/CornellBox/Assets/Shaders/.clang-format similarity index 100% rename from sources/Experiments/SponzaScene/Assets/Shaders/.clang-format rename to sources/Experiments/CornellBox/Assets/Shaders/.clang-format diff --git a/sources/Experiments/CornellBox/CONVENTIONS.md b/sources/Experiments/CornellBox/CONVENTIONS.md new file mode 100644 index 00000000..455deeea --- /dev/null +++ b/sources/Experiments/CornellBox/CONVENTIONS.md @@ -0,0 +1,792 @@ +# CornellBox Development Conventions + +## Overview + +A dual-mode Cornell Box renderer built on the Zenith.NET multi-backend GPU framework (DirectX12 / Vulkan / Metal). +Two rendering modes switchable via ImGui radio buttons at runtime: + +- **Path Tracing** (mode 0): `ComputePipeline` + inline `RayQuery<>`, progressive accumulation with NEE (Next Event Estimation), Cook-Torrance PBR BRDF (GGX + Schlick Fresnel + Smith G), GGX importance sampling for specular, cosine-weighted hemisphere for diffuse, Russian roulette, environment sky light on ray miss. Only available when `Context.Capabilities.RayTracingSupported` is true. +- **Rasterization** (mode 1): `GraphicsPipeline` + Blinn-Phong lighting, point light at ceiling, hemisphere ambient, ACES tonemapping. Always available as fallback. + +## Current State (2026-03-30) + +- All files implemented and compiling successfully +- DX12 validation layer clean +- Camera initial position: (278, 273, -800), Speed=240, FarPlane=2000, looks into the box +- Swap chain format: B8G8R8A8UNorm color + D32FloatS8UInt depth/stencil +- `Renderer` abstract base class unifies both renderers (`Update` / `Render` / `Resize` + `IDisposable`) +- `activeRenderer` field in App.cs dispatches calls polymorphically + +### Render Loop (App.cs) + +1. `imGui.Update()` → `camera.Update()` → `activeRenderer.Update(camera)` +2. ImGui window: backend info, render mode radio buttons, SPP counter (path tracing only), FPS +3. Create `CommandBuffer` +4. `imGui.Render(commandBuffer, swapChain.FrameBuffer, ClearValues.Default)` — ImGui clears swap chain and renders UI overlay +5. `activeRenderer.Render(commandBuffer)` — renderer writes to its own Color texture, displayed via ImGui `AddImage` +6. `commandBuffer.Submit(true)` → `swapChain.Present()` + +### Disposal Order + +`pathTracer` → `rasterizer` → `imGui` → `swapChain` → `input` → `window` → `Context` + +## Project Structure + +``` +CornellBox/ +├── App.cs # Lifecycle, ImGui mode switching, activeRenderer dispatch +├── Program.cs # Entry point +├── CONVENTIONS.md # This file +├── Renderers/ +│ ├── Renderer.cs # Abstract base class: Color / DepthStencil / FrameBuffer management +│ ├── PathTracingRenderer.cs # ComputePipeline + RayQuery path tracing (NEE + PBR BRDF) +│ └── RasterizationRenderer.cs # GraphicsPipeline + Blinn-Phong +├── Handlers/ +│ ├── CameraHandler.cs # 6DOF camera (WASD+QE, right-click mouselook) +│ └── ImGuiHandler.cs # ImGui integration (input forwarding, font loading) +├── Helpers/ +│ ├── BindingHelper.cs # Multi-backend resource binding index assignment +│ ├── CornellBoxGeometry.cs # Shared geometry factory (Vertex, Material) +│ ├── CocoaHelper.cs # macOS Metal layer creation +│ └── Extensions.cs # ImGui.Overlay extension +└── Assets/ + └── Fonts/msyh.ttf # Chinese font for ImGui +``` + +## GPU Alignment Rules + +### Slang Side + +- **Never** use bare `float3` in ConstantBuffer / StructuredBuffer structs +- Pack `float3` into `float4`, use `private` field + `property` accessor +- If the next field after `float3` is a scalar (`float` / `uint`), merge them into one `float4` with a meaningful combined name (e.g. `NormalAndMaterialID`, `AlbedoAndEmission`); if there is no natural scalar to pair, use `XXXAndPadding` +- **Only** `float3` needs the `float4` + property pattern; scalar types (`float`, `uint`, `int`, `float4x4`, etc.) can be declared directly as normal fields +- Pad trailing bytes with `private float paddingN` to reach 16-byte boundary +- Vertex I/O structs (VSInput) also use `private float4` + `property` for consistency — semantic annotations go on the backing field +- PSInput interpolators can use `float3` directly (controlled by semantic output) +- Attributes go **above** properties, blank line between fields + +```slang +struct Vertex +{ + private float4 PositionAndPadding; + + private float4 NormalAndMaterialID; + + property float3 Position { get { return PositionAndPadding.xyz; } } + + property float3 Normal { get { return NormalAndMaterialID.xyz; } } + + property uint MaterialID { get { return asuint(NormalAndMaterialID.w); } } +}; + +struct Material +{ + private float4 AlbedoAndEmission; + + float Metallic; + + float Roughness; + + private float padding0; + + private float padding1; + + property float3 Albedo { get { return AlbedoAndEmission.xyz; } } + + property float Emission { get { return AlbedoAndEmission.w; } } +}; + +struct CameraParams +{ + float4x4 InvView; + + float4x4 InvProjection; + + private float4 PositionAndPadding; + + uint FrameCount; + + uint Width; + + uint Height; + + private float padding0; + + property float3 Position { get { return PositionAndPadding.xyz; } } +}; +``` + +### C# Side + +- Use `LayoutKind.Explicit` + `FieldOffset` for precise offset control +- Specify `Size` to ensure total size matches Slang side +- C# structs use split, human-readable fields (`Position`, `Normal`, `MaterialID`) — the GPU-side packing is handled by `FieldOffset` matching the Slang `float4` layout +- ConstantBuffer requires 256-byte alignment (`BufferUsageFlags.Constant`) +- Attributes go **above** the field, blank line between fields + +```csharp +[StructLayout(LayoutKind.Explicit, Size = 160)] +file struct CameraParams +{ + [FieldOffset(0)] + public Matrix4x4 InvView; + + [FieldOffset(64)] + public Matrix4x4 InvProjection; + + [FieldOffset(128)] + public Vector3 Position; + + [FieldOffset(144)] + public uint FrameCount; + + [FieldOffset(148)] + public uint Width; + + [FieldOffset(152)] + public uint Height; +} +``` + +### Alignment Quick Reference + +| Type | Size | Alignment | Notes | +|------|------|-----------|-------| +| `float` / `uint` / `int` | 4B | 4B | | +| `float2` / `uint2` | 8B | 8B | | +| `float4` / `uint4` | 16B | 16B | Use instead of float3 | +| `float4x4` | 64B | 16B | `Matrix4x4` | +| struct | - | 16B boundary | Total size must be multiple of 16 | + +### Vertex Input Layout + +Vertex buffers use `InputLayout` + `ElementFormat`. The C# struct uses split fields with `FieldOffset`, while Slang uses `private float4` + `property` for both StructuredBuffer and vertex input: + +```csharp +// 32 bytes — used by both renderers +[StructLayout(LayoutKind.Explicit, Size = 32)] +internal struct Vertex +{ + [FieldOffset(0)] + public Vector3 Position; // maps to PositionAndPadding.xyz + + [FieldOffset(16)] + public Vector3 Normal; // maps to NormalAndMaterialID.xyz + + [FieldOffset(28)] + public uint MaterialID; // maps to NormalAndMaterialID.w +} +``` + +Slang StructuredBuffer struct (path tracing): + +```slang +struct Vertex +{ + private float4 PositionAndPadding; + + private float4 NormalAndMaterialID; + + property float3 Position { get { return PositionAndPadding.xyz; } } + + property float3 Normal { get { return NormalAndMaterialID.xyz; } } + + property uint MaterialID { get { return asuint(NormalAndMaterialID.w); } } +}; +``` + +Slang vertex input struct (rasterization) — same layout with semantic annotations: + +```slang +struct VSInput +{ + private float4 PositionAndPadding : POSITION0; + + private float4 NormalAndMaterialID : NORMAL0; + + property float3 Position { get { return PositionAndPadding.xyz; } } + + property float3 Normal { get { return NormalAndMaterialID.xyz; } } + + property uint MaterialID { get { return asuint(NormalAndMaterialID.w); } } +}; +``` + +`InputLayout` matches the `float4 + float4` backing fields: + +```csharp +InputLayout inputLayout = new(); +inputLayout.Add(new() { Format = ElementFormat.Float4, Semantic = ElementSemantic.Position }); +inputLayout.Add(new() { Format = ElementFormat.Float4, Semantic = ElementSemantic.Normal }); +``` + +## Resource Creation Patterns + +### Buffer + +```csharp +// Vertex buffer (AccelerationStructure flag needed for ray tracing) +buffer = App.Context.CreateBuffer(new() +{ + SizeInBytes = (uint)(sizeof(Vertex) * vertices.Length), + StrideInBytes = (uint)sizeof(Vertex), + Flags = BufferUsageFlags.Vertex | BufferUsageFlags.AccelerationStructure +}); +buffer.Upload(vertices, 0); + +// ConstantBuffer (256B aligned, MapWrite for per-frame update) +cbuffer = App.Context.CreateBuffer(new() +{ + SizeInBytes = (uint)sizeof(CameraParams), + StrideInBytes = (uint)sizeof(CameraParams), + Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite +}); + +// StructuredBuffer (read-only) +sbuffer = App.Context.CreateBuffer(new() +{ + SizeInBytes = (uint)(sizeof(Material) * count), + StrideInBytes = (uint)sizeof(Material), + Flags = BufferUsageFlags.ShaderResource +}); +``` + +### Texture (UAV / Accumulation Buffer) + +```csharp +texture = App.Context.CreateTexture(new() +{ + Type = TextureType.Texture2D, + Format = PixelFormat.R32G32B32A32Float, + Width = width, Height = height, Depth = 1, + MipLevels = 1, ArrayLayers = 1, + SampleCount = SampleCount.Count1, + Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess +}); +``` + +## Acceleration Structure Build Pattern + +```csharp +CommandBuffer buildCmd = App.Context.Graphics.CommandBuffer(); + +// BLAS — one per geometry group +blas = buildCmd.BuildAccelerationStructure(new BottomLevelAccelerationStructureDesc +{ + Geometries = [new() + { + Type = RayTracingGeometryType.Triangles, + Triangles = new() + { + VertexBuffer = vertexBuffer, + VertexFormat = PixelFormat.R32G32B32Float, + VertexCount = vertexCount, + VertexStrideInBytes = (uint)sizeof(Vertex), + IndexBuffer = indexBuffer, + IndexFormat = IndexFormat.UInt32, + IndexCount = indexCount, + Transform = Matrix4x4.Identity + }, + Flags = RayTracingGeometryFlags.Opaque + }], + Flags = AccelerationStructureBuildFlags.PreferFastTrace +}); + +// TLAS — references all BLAS instances +tlas = buildCmd.BuildAccelerationStructure(new TopLevelAccelerationStructureDesc +{ + Instances = [ + new() + { + AccelerationStructure = blas, + ID = 0, + Mask = 0xFF, + Transform = Matrix4x4.Identity, + Flags = RayTracingInstanceFlags.None + } + ], + Flags = AccelerationStructureBuildFlags.PreferFastTrace +}); + +buildCmd.Submit(waitForCompletion: true); +``` + +## Pipeline Creation Patterns + +### ComputePipeline (Path Tracing) + +```csharp +resourceLayout = App.Context.CreateResourceLayout(new() +{ + Bindings = BindingHelper.Bindings( + new() { Type = ResourceType.AccelerationStructure, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute } + ) +}); + +using Shader cs = App.Context.LoadShaderFromSource(ShaderSource, "CSMain", ShaderStageFlags.Compute); +pipeline = App.Context.CreateComputePipeline(new() +{ + Compute = cs, + ResourceLayout = resourceLayout, + ThreadGroupSizeX = 16, ThreadGroupSizeY = 16, ThreadGroupSizeZ = 1 +}); +``` + +### GraphicsPipeline (Rasterization) + +```csharp +using Shader vs = App.Context.LoadShaderFromSource(ShaderSource, "VSMain", ShaderStageFlags.Vertex); +using Shader ps = App.Context.LoadShaderFromSource(ShaderSource, "PSMain", ShaderStageFlags.Pixel); + +pipeline = App.Context.CreateGraphicsPipeline(new() +{ + RenderStates = new() + { + RasterizerState = RasterizerStates.CullBack, + DepthStencilState = DepthStencilStates.Default, + BlendState = BlendStates.Opaque + }, + Vertex = vs, Pixel = ps, + ResourceLayout = resourceLayout, + InputLayouts = [inputLayout], + PrimitiveTopology = PrimitiveTopology.TriangleList, + Output = App.SwapChain.FrameBuffer.Output +}); +``` + +## Resource Binding Pattern + +Declaration order in ResourceLayout Bindings = declaration order in shader = resource order in ResourceTable. + +```csharp +// Layout declaration order +Bindings = BindingHelper.Bindings( + new() { Type = ResourceType.AccelerationStructure, ... }, // [0] scene + new() { Type = ResourceType.ConstantBuffer, ... }, // [1] camera + new() { Type = ResourceType.StructuredBuffer, ... }, // [2] vertices + new() { Type = ResourceType.StructuredBuffer, ... }, // [3] indices + new() { Type = ResourceType.StructuredBuffer, ... }, // [4] materials + new() { Type = ResourceType.TextureReadWrite, ... }, // [5] accumTexture + new() { Type = ResourceType.TextureReadWrite, ... }, // [6] outputTexture +); + +// Shader declares in same order: +// RaytracingAccelerationStructure scene; +// ConstantBuffer camera; +// StructuredBuffer vertices; +// StructuredBuffer indices; +// StructuredBuffer materials; +// RWTexture2D accumTexture; +// RWTexture2D outputTexture; + +// ResourceTable passes in same order +resourceTable = App.Context.CreateResourceTable(new() +{ + Layout = resourceLayout, + Resources = [tlas, cameraBuffer, vertexBuffer, indexBuffer, materialBuffer, accumTexture, Color] +}); +``` + +`BindingHelper.Bindings()` handles per-backend index differences transparently. + +## Render Loop Patterns + +### Compute Output → Color Texture + +```csharp +cmd.SetPipeline(computePipeline); +cmd.SetResourceTable(resourceTable); +cmd.Dispatch(dispatchX, dispatchY, 1); +``` + +The compute shader writes directly to the base class `Color` texture (bound as `outputTexture` UAV in the ResourceTable). No `CopyTexture` needed — ImGui displays it via `AddImage`. + +### Graphics RenderPass → SwapChain + +```csharp +cmd.BeginRenderPass(App.SwapChain.FrameBuffer, new() +{ + ColorValues = [new(0.51f, 0.518f, 0.557f, 1)], + Depth = 1.0f, Stencil = 0, + Flags = ClearFlags.All +}); +cmd.SetPipeline(graphicsPipeline); +cmd.SetResourceTable(resourceTable); +cmd.SetVertexBuffer(vertexBuffer, 0, 0); +cmd.SetIndexBuffer(indexBuffer, 0, IndexFormat.UInt32); +cmd.DrawIndexed(indexCount, 1, 0, 0, 0); +cmd.EndRenderPass(); +``` + +## Resize Pattern + +Resources to rebuild on size change: + +- Texture (accumulationTexture) +- ResourceTable (references Texture) +- Reset path tracing FrameCount to 0 + +No rebuild needed: Buffer, Pipeline, ResourceLayout, acceleration structures. + +```csharp +public void Resize(uint width, uint height) +{ + base.Resize(width, height); // recreates Color + DepthStencil + FrameBuffer + + resourceTable?.Dispose(); + resourceTable = null; + accumulationTexture?.Dispose(); + accumulationTexture = null; + + FrameCount = 0; + // Lazy rebuild on next Render call +} +``` + +## Dispose Order + +Release in reverse creation order — downstream first, upstream last: + +``` +ResourceTable → Pipeline → ResourceLayout +→ Texture (accumulation) +→ TLAS → BLAS[] +→ Buffer (camera / material / index / vertex) +``` + +## Cornell Box Geometry Data (CornellBoxGeometry.cs) + +- Coordinate range 0~560 (standard Cornell Box specification) +- 16 quads (64 vertices, 96 indices): 5 walls + 5 short block faces + 5 tall block faces + 1 light +- 6 material groups: 0=red left wall, 1=green right wall, 2=white surfaces (ceiling/floor/back wall), 3=light, 4=short block (smooth diffuse), 5=tall block (metallic mirror) +- Each quad → 4 vertices + 6 indices (2 triangles) +- Normals auto-computed via `normalize(cross(v1-v0, v2-v0))` +- Material ID stored in `Vertex.MaterialID` (C#), packed into `NormalAndMaterialID.w` on GPU via `FieldOffset(28)` overlapping the `float4` w-component +- Material colors: red(0.63,0.06,0.06), green(0.14,0.45,0.09), white(0.73,0.71,0.68), light(1.0,0.85,0.6)+emission=25, short block(0.73,0.71,0.68)+roughness=0.3, tall block(0.95,0.93,0.88)+metallic=1.0+roughness=0.05 + +### Shared Data Types + +```csharp +// 32 bytes — used by both renderers +[StructLayout(LayoutKind.Explicit, Size = 32)] +internal struct Vertex +{ + [FieldOffset(0)] + public Vector3 Position; + + [FieldOffset(16)] + public Vector3 Normal; + + [FieldOffset(28)] + public uint MaterialID; +} + +// 32 bytes — PBR material with metallic/roughness +[StructLayout(LayoutKind.Explicit, Size = 32)] +internal struct Material +{ + [FieldOffset(0)] + public Vector3 Albedo; + + [FieldOffset(12)] + public float Emission; + + [FieldOffset(16)] + public float Metallic; + + [FieldOffset(20)] + public float Roughness; +} +``` + +## Renderer Base Class (Renderer.cs) + +```csharp +internal abstract class Renderer : IDisposable +{ + public Texture Color { get; private set; } + public Texture DepthStencil { get; private set; } + public FrameBuffer FrameBuffer { get; private set; } + + abstract void Update(CameraHandler camera); + abstract void Render(CommandBuffer commandBuffer); + virtual void Resize(uint width, uint height); // recreates Color + DepthStencil + FrameBuffer + virtual void Dispose(); // disposes FrameBuffer + DepthStencil + Color +} +``` + +- Constructor calls `Resize(App.Width, App.Height)` to create initial resources +- `Resize()`: Disposes then recreates `Color` (B8G8R8A8UNorm, RenderTarget | ShaderResource | UnorderedAccess), `DepthStencil` (D32FloatS8UInt), and `FrameBuffer` +- `Color` texture is used by path tracer as compute output target, and displayed via ImGui `AddImage` in App.cs +- Subclasses call `base.Resize()` / `base.Dispose()` to manage these shared resources + +## PathTracingRenderer Details + +### Overview + +- **Pipeline**: `ComputePipeline` with `[numthreads(16,16,1)]`, entry point `CSMain` +- **Shader**: Inline Slang raw string literal +- **Algorithm**: 8-bounce path tracing + NEE (Next Event Estimation) + Cook-Torrance PBR BRDF + Russian roulette (bounce ≥ 2) +- **Accumulation**: R32G32B32A32Float UAV texture, progressive average with jittered subpixel sampling +- **Tonemapping**: ACES filmic + gamma correction +- **Environment**: Gradient sky light on ray miss (warm ground → cool sky) +- **Output**: Tonemapped + gamma-corrected to `Color` texture (base class, B8G8R8A8UNorm) + +### Shader Structs + +```slang +struct Vertex // StructuredBuffer — private float4 + property +struct Material // StructuredBuffer — private float4 + property +struct CameraParams // ConstantBuffer — float4x4 × 2, private float4 Position, uint × 3 + padding +``` + +### Resource Bindings (7 slots) + +| Index | Type | Shader Variable | Description | +|-------|------|-----------------|-------------| +| 0 | AccelerationStructure | `scene` | TLAS for ray queries | +| 1 | ConstantBuffer | `camera` | CameraParams (160B) | +| 2 | StructuredBuffer | `vertices` | Vertex[] (32B stride) | +| 3 | StructuredBuffer | `indices` | uint[] | +| 4 | StructuredBuffer | `materials` | Material[] (32B stride) | +| 5 | TextureReadWrite | `accumTexture` | R32G32B32A32Float accumulation buffer | +| 6 | TextureReadWrite | `outputTexture` | Base class `Color` texture (compute write target) | + +### Shader Functions + +| Function | Purpose | +|----------|---------| +| `pcgHash(uint)` | PCG hash for RNG seed | +| `randomFloat(inout uint)` | Returns [0,1) float, advances seed | +| `cosineSampleHemisphere(float3, inout uint)` | Cosine-weighted hemisphere sampling around normal | +| `traceShadowRay(float3, float3, float)` | Shadow ray test using `RayQuery` | +| `sampleLightDirect(float3, float3, float3, Material, inout uint)` | NEE: uniform sample on ceiling light quad, Cook-Torrance BRDF, geometry term | +| `DistributionGGX(float, float)` | GGX normal distribution function | +| `GeometrySchlickGGX(float, float)` | Schlick-GGX geometry sub-function | +| `GeometrySmith(float, float, float)` | Smith geometry function (combined) | +| `FresnelSchlick(float, float3)` | Schlick Fresnel approximation | +| `evaluateBRDF(float3, float3, float3, Material)` | Full Cook-Torrance BRDF evaluation (diffuse + specular) | +| `sampleGGXHalfVector(float3, float, inout uint)` | GGX importance sampling for specular half-vector | +| `tracePath(float3, float3, inout uint)` | Main path tracing loop (8 bounces max) | +| `CSMain(uint3)` | Entry point: generate ray, trace, accumulate, ACES tonemap, gamma-correct | + +### Path Tracing Algorithm (`tracePath`) + +1. For each bounce (max 8): + - Trace primary ray via `RayQuery` + - On miss → add environment sky contribution (`lerp` warm ground to cool sky based on `direction.y`) → break + - Compute hit position, interpolate normal via barycentric weights from index/vertex buffers + - Flip normal if back-facing (`dot(normal, direction) > 0`) + - If emissive material: accumulate emission on bounce 0 only, then break (prevents double-counting with NEE) + - Non-emissive: add NEE contribution via `sampleLightDirect()` using Cook-Torrance BRDF + - Probabilistic BRDF sampling: compute `specProb` from F0 and metallic, then: + - With probability `specProb`: GGX importance sample half-vector → reflect → specular throughput (clamped to 10) + - Otherwise: cosine-weighted hemisphere → diffuse throughput + - Russian roulette (bounce ≥ 2): survival probability = max component of throughput + - Per-sample radiance clamped to 30 to suppress fireflies + +### Light Constants (hardcoded) + +```slang +static const float3 LightMin = float3(213.0, 548.6, 227.0); +static const float3 LightMax = float3(343.0, 548.6, 332.0); +static const float LightArea = 13650.0; // (343-213) * (332-227) +static const float3 LightNormal = float3(0.0, -1.0, 0.0); +``` + +### Camera Ray Generation (`CSMain`) + +1. RNG seed: `pcgHash(pixel.x + pixel.y * Width + FrameCount * Width * Height)` +2. Jittered subpixel offset → UV → NDC (y-flipped) +3. `InvProjection` → local direction → `InvView` → world direction +4. Origin = `camera.Position` + +### Accumulation + +- `FrameCount == 0`: overwrite `accumTexture` with new sample +- `FrameCount > 0`: add to existing accumulation +- Running average: `accumulated.rgb / (FrameCount + 1)` +- ACES tonemapping: `saturate((x * (2.51x + 0.03)) / (x * (2.43x + 0.59) + 0.14))` +- Gamma correction: `pow(avg, 1/2.2)` → `outputTexture` + +### Camera Change Detection + +```csharp +if (view != lastView || projection != lastProjection) +{ + lastView = view; + lastProjection = projection; + FrameCount = 0; // reset accumulation +} +``` + +### C# Side CameraParams (160B) + +```csharp +[StructLayout(LayoutKind.Explicit, Size = 160)] +file struct CameraParams +{ + [FieldOffset(0)] public Matrix4x4 InvView; + [FieldOffset(64)] public Matrix4x4 InvProjection; + [FieldOffset(128)] public Vector3 Position; + [FieldOffset(144)] public uint FrameCount; + [FieldOffset(148)] public uint Width; + [FieldOffset(152)] public uint Height; +} +``` + +### Buffer Setup + +- `vertexBuffer`: ShaderResource | AccelerationStructure +- `indexBuffer`: ShaderResource | AccelerationStructure +- `materialBuffer`: ShaderResource +- `cameraBuffer`: Constant | MapWrite (per-frame upload) +- Acceleration structures: single BLAS (all geometry, PreferFastTrace) → single TLAS (one instance) + +### Resize / Lifecycle + +- `Resize()`: calls `base.Resize()`, disposes `resourceTable` + `accumulationTexture`, set to null for lazy rebuild +- `Render()`: if resources are null → create `accumulationTexture` (R32G32B32A32Float) + `resourceTable`, reset `FrameCount` +- `Dispatch()`: `ceil(Width/16) × ceil(Height/16) × 1` +- `FrameCount++` after each dispatch + +### Dispose Order + +``` +base (FrameBuffer + DepthStencil + Color) +→ resourceTable → accumulationTexture +→ pipeline → resourceLayout +→ tlas → blas +→ cameraBuffer → materialBuffer → indexBuffer → vertexBuffer +``` + +## RasterizationRenderer Details + +### Overview + +- **Pipeline**: `GraphicsPipeline` with Vertex + Pixel shaders, entry points `VSMain` / `PSMain` +- **Shader**: Inline Slang raw string literal +- **Algorithm**: Blinn-Phong shading with point light, hemisphere ambient, ACES tonemapping +- **Output**: Renders directly to `FrameBuffer` (base class) via render pass + +### Shader Structs + +```slang +struct Material // StructuredBuffer — private float4 + property +struct RasterConstants // ConstantBuffer — float4x4 × 3, private float4 × 3 + properties +struct VSInput // Vertex input — private float4 × 2 + properties (Position, Normal, MaterialID) +struct PSInput // Interpolated — float4 Position, float3 WorldPos, float3 Normal, nointerpolation uint MaterialID +``` + +### Resource Bindings (2 slots) + +| Index | Type | Shader Variable | Stages | Description | +|-------|------|-----------------|--------|-------------| +| 0 | ConstantBuffer | `cb` | Vertex + Pixel | RasterConstants (240B) | +| 1 | StructuredBuffer | `materials` | Pixel | Material[] (32B stride) | + +### Vertex Shader (`VSMain`) + +1. Transform position: `worldPos = mul(float4(input.Position, 1.0), cb.Model)` +2. Clip space: `mul(mul(worldPos, cb.View), cb.Projection)` +3. Pass world position, transformed normal, MaterialID to PSInput +4. MaterialID via `asuint(NormalAndMaterialID.w)` through VSInput property, passed as `nointerpolation uint` + +### Pixel Shader (`PSMain`) + +1. **Emissive check**: if `mat.Emission > 0` → Reinhard tonemapping: `color / (color + 1)` → gamma correct → return +2. **Blinn-Phong**: + - Hemisphere ambient: `albedo * lerp(0.06, 0.15, N.y * 0.5 + 0.5)` (brighter on upward-facing surfaces) + - Diffuse: `albedo * lightColor * NdotL * atten` + - Specular: `lightColor * pow(NdotH, 64) * atten * 0.1` + - Distance attenuation: `1 / (1 + 0.000005 * dist²)` +3. ACES tonemapping: `saturate((x * (2.51x + 0.03)) / (x * (2.43x + 0.59) + 0.14))` +4. Gamma correction: `pow(color, 1/2.2)` + +### Light Configuration + +- Point light position: (278, 548, 280) +- Light color: (2.0, 1.8, 1.4) +- Ambient factor: hemisphere-based (0.06 bottom to 0.15 top) +- Specular exponent: 64, weight: 0.1 + +### C# Side RasterConstants (240B) + +```csharp +[StructLayout(LayoutKind.Explicit, Size = 240)] +file struct RasterConstants +{ + [FieldOffset(0)] public Matrix4x4 Model; // Identity + [FieldOffset(64)] public Matrix4x4 View; + [FieldOffset(128)] public Matrix4x4 Projection; + [FieldOffset(192)] public Vector3 LightPos; // maps to private float4 LightPosAndPadding + [FieldOffset(208)] public Vector3 LightColor; // maps to private float4 LightColorAndPadding + [FieldOffset(224)] public Vector3 CameraPos; // maps to private float4 CameraPosAndPadding +} +``` + +### Pipeline Configuration + +- RasterizerState: `CullNone` (camera is inside the box) +- DepthStencilState: `Default` +- BlendState: `Opaque` +- PrimitiveTopology: `TriangleList` +- InputLayout: Float4 (POSITION) + Float4 (NORMAL), stride = 32 + +### Buffer Setup + +- `vertexBuffer`: Vertex only +- `indexBuffer`: Index only +- `materialBuffer`: ShaderResource +- `constantBuffer`: Constant | MapWrite (per-frame upload) +- `resourceTable`: created once in constructor (no size-dependent resources) + +### Render Pass + +```csharp +cmd.BeginRenderPass(FrameBuffer, clearValues, resourceTable); +cmd.SetPipeline(pipeline); +cmd.SetResourceTable(resourceTable); +cmd.SetVertexBuffer(vertexBuffer, 0, 0); +cmd.SetIndexBuffer(indexBuffer, 0, IndexFormat.UInt32); +cmd.DrawIndexed(indexCount, 1, 0, 0, 0); +cmd.EndRenderPass(); +``` + +Clear values: color (0.51, 0.518, 0.557, 1) matching environment sky, depth 1.0, stencil 0, ClearFlags.All + +### Resize / Lifecycle + +- `Resize()`: only `base.Resize()` — no renderer-specific size-dependent resources +- No `accumulationTexture`, no `resourceTable` rebuild needed + +### Dispose Order + +``` +base (FrameBuffer + DepthStencil + Color) +→ pipeline → resourceTable → resourceLayout +→ constantBuffer → materialBuffer → indexBuffer → vertexBuffer +``` + +## DX12 Specific Notes + +- `BindingHelper` assigns DX12 register indices by type: CBV(b), SRV(t), UAV(u), Sampler(s) independently numbered +- Vulkan numbers all bindings sequentially; Metal uses argument buffer index + +## C# Code Style + +- Prefer `is` / `is not` pattern matching over `==` / `!=` for comparisons +- Use full `using` imports, short type names in code (no `Namespace.Type` inline references) +- `file struct` for shader-mirrored GPU structs (scoped to the file that uses them) +- Shaders inlined as `const string ShaderSource = """...""";` (raw string literal) +- Collection expressions: `[]` for empty, `[.. spread]` for conversion +- Target-typed `new()` for object initializers +- `static readonly` fields for framework objects created once +- Blank line between each field / property / method diff --git a/sources/Experiments/SponzaScene/SponzaScene.csproj b/sources/Experiments/CornellBox/CornellBox.csproj similarity index 84% rename from sources/Experiments/SponzaScene/SponzaScene.csproj rename to sources/Experiments/CornellBox/CornellBox.csproj index a52f6fac..65e6ad06 100644 --- a/sources/Experiments/SponzaScene/SponzaScene.csproj +++ b/sources/Experiments/CornellBox/CornellBox.csproj @@ -6,7 +6,6 @@ - @@ -15,7 +14,6 @@ - diff --git a/sources/Experiments/SponzaScene/Models/CameraController.cs b/sources/Experiments/CornellBox/Handlers/CameraHandler.cs similarity index 94% rename from sources/Experiments/SponzaScene/Models/CameraController.cs rename to sources/Experiments/CornellBox/Handlers/CameraHandler.cs index 315db75d..769c4cdb 100644 --- a/sources/Experiments/SponzaScene/Models/CameraController.cs +++ b/sources/Experiments/CornellBox/Handlers/CameraHandler.cs @@ -1,22 +1,22 @@ using System.Numerics; using Silk.NET.Input; -namespace SponzaScene.Models; +namespace CornellBox.Handlers; -internal class CameraController +internal class CameraHandler { private readonly HashSet keyDowns = []; private Vector2? lastMousePosition; - public CameraController(IInputContext inputContext, Matrix4x4 initial) + public CameraHandler(IInputContext input, Matrix4x4 initial) { - IMouse mouse = inputContext.Mice[0]; + IMouse mouse = input.Mice[0]; mouse.MouseDown += Mouse_MouseDown; mouse.MouseUp += Mouse_MouseUp; mouse.MouseMove += Mouse_MouseMove; - IKeyboard keyboard = inputContext.Keyboards[0]; + IKeyboard keyboard = input.Keyboards[0]; keyboard.KeyDown += OnKeyDown; keyboard.KeyUp += OnKeyUp; diff --git a/sources/Experiments/SponzaScene/Models/SilkImGuiController.cs b/sources/Experiments/CornellBox/Handlers/ImGuiHandler.cs similarity index 95% rename from sources/Experiments/SponzaScene/Models/SilkImGuiController.cs rename to sources/Experiments/CornellBox/Handlers/ImGuiHandler.cs index 51e75287..4fbd18ea 100644 --- a/sources/Experiments/SponzaScene/Models/SilkImGuiController.cs +++ b/sources/Experiments/CornellBox/Handlers/ImGuiHandler.cs @@ -4,22 +4,22 @@ using Zenith.NET; using Zenith.NET.Extensions.ImGui; -namespace SponzaScene.Models; +namespace CornellBox.Handlers; -internal class SilkImGuiController : ImGuiController, IImGuiPlatformBindings +internal class ImGuiHandler : ImGuiController, IImGuiPlatformBindings { private readonly IMouse mouse; private readonly IKeyboard keyboard; - public SilkImGuiController(IInputContext inputContext, Output output, ImGuiColorSpace colorSpace) : base(App.Context, output, colorSpace, Path.Combine(AppContext.BaseDirectory, "Assets", "Fonts", "msyh.ttf"), OtherSetup) + public ImGuiHandler(IInputContext input, Output output) : base(App.Context, output, ImGuiColorSpace.Legacy, Path.Combine(AppContext.BaseDirectory, "Assets", "Fonts", "msyh.ttf"), OtherSetup) { - mouse = inputContext.Mice[0]; + mouse = input.Mice[0]; mouse.MouseDown += OnMouseDown; mouse.MouseUp += OnMouseUp; mouse.MouseMove += OnMouseMove; mouse.Scroll += OnMouseScroll; - keyboard = inputContext.Keyboards[0]; + keyboard = input.Keyboards[0]; keyboard.KeyDown += OnKeyDown; keyboard.KeyUp += OnKeyUp; keyboard.KeyChar += OnKeyChar; @@ -216,6 +216,7 @@ private static ImGuiKey TranslateInputKeyToImGuiModifier(Key key) private static void OtherSetup(ImGuiIOPtr io) { io.ConfigFlags |= ImGuiConfigFlags.DockingEnable; + io.DisplayFramebufferScale = App.DpiScale; } public void SetCursor(ImGuiMouseCursor cursor) diff --git a/sources/Experiments/CornellBox/Helpers/BindingHelper.cs b/sources/Experiments/CornellBox/Helpers/BindingHelper.cs new file mode 100644 index 00000000..a4b30688 --- /dev/null +++ b/sources/Experiments/CornellBox/Helpers/BindingHelper.cs @@ -0,0 +1,89 @@ +using Zenith.NET; + +namespace CornellBox.Helpers; + +internal static class BindingHelper +{ + public static ResourceBinding[] Bindings(params ResourceBinding[] bindings) + { + switch (App.Context.Backend) + { + case Backend.DirectX12: + { + uint cbvIndex = 0; + uint srvIndex = 0; + uint uavIndex = 0; + uint samplerIndex = 0; + + for (int i = 0; i < bindings.Length; i++) + { + ref ResourceBinding binding = ref bindings[i]; + + binding = binding with + { + Index = binding.Type switch + { + ResourceType.ConstantBuffer => cbvIndex++, + + ResourceType.StructuredBuffer or + ResourceType.Texture or + ResourceType.AccelerationStructure => srvIndex++, + + ResourceType.StructuredBufferReadWrite or + ResourceType.TextureReadWrite => uavIndex++, + + ResourceType.Sampler => samplerIndex++, + + _ => binding.Index + } + }; + } + } + break; + + case Backend.Vulkan: + { + for (int i = 0; i < bindings.Length; i++) + { + ref ResourceBinding binding = ref bindings[i]; + + binding = binding with { Index = (uint)i }; + } + } + break; + + case Backend.Metal: + { + uint bufferIndex = 0; + uint textureIndex = 0; + uint samplerIndex = 0; + + for (int i = 0; i < bindings.Length; i++) + { + ref ResourceBinding binding = ref bindings[i]; + + binding = binding with + { + Index = binding.Type switch + { + ResourceType.ConstantBuffer or + ResourceType.StructuredBuffer or + ResourceType.StructuredBufferReadWrite or + ResourceType.AccelerationStructure => bufferIndex++, + + ResourceType.Texture or + ResourceType.TextureReadWrite => textureIndex++, + + ResourceType.Sampler => samplerIndex++, + + _ => binding.Index + } + }; + } + } + break; + } + + return bindings; + } +} diff --git a/sources/Experiments/SponzaScene/Helpers/CocoaHelper.cs b/sources/Experiments/CornellBox/Helpers/CocoaHelper.cs similarity index 97% rename from sources/Experiments/SponzaScene/Helpers/CocoaHelper.cs rename to sources/Experiments/CornellBox/Helpers/CocoaHelper.cs index a9d83612..acb3879d 100644 --- a/sources/Experiments/SponzaScene/Helpers/CocoaHelper.cs +++ b/sources/Experiments/CornellBox/Helpers/CocoaHelper.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace SponzaScene.Helpers; +namespace CornellBox.Helpers; internal static partial class CocoaHelper { @@ -32,4 +32,4 @@ public static nint CreateLayer(nint cocoa) return layer; } -} \ No newline at end of file +} diff --git a/sources/Experiments/CornellBox/Helpers/CornellBoxGeometry.cs b/sources/Experiments/CornellBox/Helpers/CornellBoxGeometry.cs new file mode 100644 index 00000000..2291e636 --- /dev/null +++ b/sources/Experiments/CornellBox/Helpers/CornellBoxGeometry.cs @@ -0,0 +1,147 @@ +using System.Numerics; +using System.Runtime.InteropServices; + +namespace CornellBox.Helpers; + +internal static class CornellBoxGeometry +{ + public static void Create(out Vertex[] vertices, out uint[] indices, out Material[] materials) + { + List verticesList = []; + List indicesList = []; + + // 0: Left wall (red) + AddQuad(verticesList, + indicesList, + new(552.8f, 0.0f, 0.0f), + new(549.6f, 0.0f, 559.2f), + new(556.0f, 548.8f, 559.2f), + new(556.0f, 548.8f, 0.0f), + 0); + + // 1: Right wall (green) + AddQuad(verticesList, + indicesList, + new(0.0f, 0.0f, 559.2f), + new(0.0f, 0.0f, 0.0f), + new(0.0f, 548.8f, 0.0f), + new(0.0f, 548.8f, 559.2f), + 1); + + // 2: Ceiling (white) + AddQuad(verticesList, + indicesList, + new(556.0f, 548.8f, 0.0f), + new(556.0f, 548.8f, 559.2f), + new(0.0f, 548.8f, 559.2f), + new(0.0f, 548.8f, 0.0f), + 2); + + // 3: Floor (white) + AddQuad(verticesList, + indicesList, + new(552.8f, 0.0f, 0.0f), + new(0.0f, 0.0f, 0.0f), + new(0.0f, 0.0f, 559.2f), + new(549.6f, 0.0f, 559.2f), + 2); + + // 4: Back wall (white) + AddQuad(verticesList, + indicesList, + new(549.6f, 0.0f, 559.2f), + new(0.0f, 0.0f, 559.2f), + new(0.0f, 548.8f, 559.2f), + new(556.0f, 548.8f, 559.2f), + 2); + + // 5-9: Short block + AddQuad(verticesList, indicesList, new(130.0f, 165.0f, 65.0f), new(82.0f, 165.0f, 225.0f), new(240.0f, 165.0f, 272.0f), new(290.0f, 165.0f, 114.0f), 4); + AddQuad(verticesList, indicesList, new(290.0f, 0.0f, 114.0f), new(290.0f, 165.0f, 114.0f), new(240.0f, 165.0f, 272.0f), new(240.0f, 0.0f, 272.0f), 4); + AddQuad(verticesList, indicesList, new(130.0f, 0.0f, 65.0f), new(130.0f, 165.0f, 65.0f), new(290.0f, 165.0f, 114.0f), new(290.0f, 0.0f, 114.0f), 4); + AddQuad(verticesList, indicesList, new(82.0f, 0.0f, 225.0f), new(82.0f, 165.0f, 225.0f), new(130.0f, 165.0f, 65.0f), new(130.0f, 0.0f, 65.0f), 4); + AddQuad(verticesList, indicesList, new(240.0f, 0.0f, 272.0f), new(240.0f, 165.0f, 272.0f), new(82.0f, 165.0f, 225.0f), new(82.0f, 0.0f, 225.0f), 4); + + // 10-14: Tall block + AddQuad(verticesList, indicesList, new(423.0f, 330.0f, 247.0f), new(265.0f, 330.0f, 296.0f), new(314.0f, 330.0f, 456.0f), new(472.0f, 330.0f, 406.0f), 5); + AddQuad(verticesList, indicesList, new(423.0f, 0.0f, 247.0f), new(423.0f, 330.0f, 247.0f), new(472.0f, 330.0f, 406.0f), new(472.0f, 0.0f, 406.0f), 5); + AddQuad(verticesList, indicesList, new(472.0f, 0.0f, 406.0f), new(472.0f, 330.0f, 406.0f), new(314.0f, 330.0f, 456.0f), new(314.0f, 0.0f, 456.0f), 5); + AddQuad(verticesList, indicesList, new(314.0f, 0.0f, 456.0f), new(314.0f, 330.0f, 456.0f), new(265.0f, 330.0f, 296.0f), new(265.0f, 0.0f, 296.0f), 5); + AddQuad(verticesList, indicesList, new(265.0f, 0.0f, 296.0f), new(265.0f, 330.0f, 296.0f), new(423.0f, 330.0f, 247.0f), new(423.0f, 0.0f, 247.0f), 5); + + // 15: Light + AddQuad(verticesList, + indicesList, + new(343.0f, 548.6f, 227.0f), + new(343.0f, 548.6f, 332.0f), + new(213.0f, 548.6f, 332.0f), + new(213.0f, 548.6f, 227.0f), + 3); + + vertices = [.. verticesList]; + indices = [.. indicesList]; + materials = + [ + new() { Albedo = new(0.63f, 0.06f, 0.06f), Emission = 0.00f, Metallic = 0.0f, Roughness = 0.90f }, + new() { Albedo = new(0.14f, 0.45f, 0.09f), Emission = 0.00f, Metallic = 0.0f, Roughness = 0.90f }, + new() { Albedo = new(0.73f, 0.71f, 0.68f), Emission = 0.00f, Metallic = 0.0f, Roughness = 0.90f }, + new() { Albedo = new(1.00f, 0.85f, 0.60f), Emission = 25.0f, Metallic = 0.0f, Roughness = 0.50f }, + new() { Albedo = new(0.73f, 0.71f, 0.68f), Emission = 0.00f, Metallic = 0.0f, Roughness = 0.30f }, + new() { Albedo = new(0.95f, 0.93f, 0.88f), Emission = 0.00f, Metallic = 1.0f, Roughness = 0.05f } + ]; + } + + private static void AddQuad(List vertices, + List indices, + Vector3 v0, + Vector3 v1, + Vector3 v2, + Vector3 v3, + uint materialID) + { + Vector3 normal = Vector3.Normalize(Vector3.Cross(v1 - v0, v2 - v0)); + + uint startIndex = (uint)vertices.Count; + + vertices.Add(new() { Position = v0, Normal = normal, MaterialID = materialID }); + vertices.Add(new() { Position = v1, Normal = normal, MaterialID = materialID }); + vertices.Add(new() { Position = v2, Normal = normal, MaterialID = materialID }); + vertices.Add(new() { Position = v3, Normal = normal, MaterialID = materialID }); + + indices.Add(startIndex); + indices.Add(startIndex + 1); + indices.Add(startIndex + 2); + indices.Add(startIndex); + indices.Add(startIndex + 2); + indices.Add(startIndex + 3); + } +} + +[StructLayout(LayoutKind.Explicit, Size = 32)] +internal struct Vertex +{ + [FieldOffset(0)] + public Vector3 Position; + + [FieldOffset(16)] + public Vector3 Normal; + + [FieldOffset(28)] + public uint MaterialID; +} + +[StructLayout(LayoutKind.Explicit, Size = 32)] +internal struct Material +{ + [FieldOffset(0)] + public Vector3 Albedo; + + [FieldOffset(12)] + public float Emission; + + [FieldOffset(16)] + public float Metallic; + + [FieldOffset(20)] + public float Roughness; +} diff --git a/sources/Experiments/CornellBox/Helpers/Extensions.cs b/sources/Experiments/CornellBox/Helpers/Extensions.cs new file mode 100644 index 00000000..1ae53d40 --- /dev/null +++ b/sources/Experiments/CornellBox/Helpers/Extensions.cs @@ -0,0 +1,29 @@ +using Hexa.NET.ImGui; + +namespace CornellBox.Helpers; + +internal static class Extensions +{ + private const ImGuiWindowFlags OverlayFlags = ImGuiWindowFlags.NoDecoration + | ImGuiWindowFlags.AlwaysAutoResize + | ImGuiWindowFlags.NoSavedSettings + | ImGuiWindowFlags.NoFocusOnAppearing + | ImGuiWindowFlags.NoInputs + | ImGuiWindowFlags.NoMove; + + extension(ImGui) + { + public static void Overlay(string name, Action action) + { + ImGui.SetNextWindowPos(new(10, 10), ImGuiCond.Always, new(0, 0)); + ImGui.SetNextWindowBgAlpha(0.35f); + + if (ImGui.Begin(name, OverlayFlags)) + { + action(); + + ImGui.End(); + } + } + } +} diff --git a/sources/Experiments/CornellBox/Program.cs b/sources/Experiments/CornellBox/Program.cs new file mode 100644 index 00000000..a819be71 --- /dev/null +++ b/sources/Experiments/CornellBox/Program.cs @@ -0,0 +1,3 @@ +using CornellBox; + +App.Run(); \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Properties/launchSettings.json b/sources/Experiments/CornellBox/Properties/launchSettings.json similarity index 65% rename from sources/Experiments/SponzaScene/Properties/launchSettings.json rename to sources/Experiments/CornellBox/Properties/launchSettings.json index 3b290fac..7e4d81fb 100644 --- a/sources/Experiments/SponzaScene/Properties/launchSettings.json +++ b/sources/Experiments/CornellBox/Properties/launchSettings.json @@ -1,10 +1,10 @@ { "profiles": { - "SponzaScene": { + "CornellBox": { "commandName": "Project" }, - "SponzaScene (WSL)": { + "CornellBox (WSL)": { "commandName": "WSL2" } } -} +} \ No newline at end of file diff --git a/sources/Experiments/CornellBox/Renderers/PathTracingRenderer.cs b/sources/Experiments/CornellBox/Renderers/PathTracingRenderer.cs new file mode 100644 index 00000000..161535ca --- /dev/null +++ b/sources/Experiments/CornellBox/Renderers/PathTracingRenderer.cs @@ -0,0 +1,646 @@ +using System.Numerics; +using System.Runtime.InteropServices; +using CornellBox.Handlers; +using CornellBox.Helpers; +using Zenith.NET; +using Zenith.NET.Extensions.Slang; +using Buffer = Zenith.NET.Buffer; + +namespace CornellBox.Renderers; + +internal unsafe class PathTracingRenderer : Renderer +{ + private const uint ThreadGroupSize = 16; + + private const string ShaderSource = """ + struct Vertex + { + private float4 PositionAndPadding; + + private float4 NormalAndMaterialID; + + property float3 Position { get { return PositionAndPadding.xyz; } } + + property float3 Normal { get { return NormalAndMaterialID.xyz; } } + + property uint MaterialID { get { return asuint(NormalAndMaterialID.w); } } + }; + + struct Material + { + private float4 AlbedoAndEmission; + + float Metallic; + + float Roughness; + + private float padding0; + + private float padding1; + + property float3 Albedo { get { return AlbedoAndEmission.xyz; } } + + property float Emission { get { return AlbedoAndEmission.w; } } + }; + + struct CameraParams + { + float4x4 InvView; + + float4x4 InvProjection; + + private float4 PositionAndPadding; + + uint FrameCount; + + uint Width; + + uint Height; + + private float padding0; + + property float3 Position { get { return PositionAndPadding.xyz; } } + }; + + RaytracingAccelerationStructure scene; + ConstantBuffer camera; + StructuredBuffer vertices; + StructuredBuffer indices; + StructuredBuffer materials; + RWTexture2D accumTexture; + RWTexture2D outputTexture; + + // Light geometry constants (hardcoded ceiling light quad) + static const float3 LightMin = float3(213.0, 548.6, 227.0); + static const float3 LightMax = float3(343.0, 548.6, 332.0); + static const float LightArea = (343.0 - 213.0) * (332.0 - 227.0); + static const float3 LightNormal = float3(0.0, -1.0, 0.0); + static const float PI = 3.14159265; + + float DistributionGGX(float NdotH, float roughness) + { + float a = roughness * roughness; + float a2 = a * a; + float denom = NdotH * NdotH * (a2 - 1.0) + 1.0; + return a2 / (PI * denom * denom); + } + + float GeometrySchlickGGX(float NdotX, float roughness) + { + float r = roughness + 1.0; + float k = (r * r) / 8.0; + return NdotX / (NdotX * (1.0 - k) + k); + } + + float GeometrySmith(float NdotV, float NdotL, float roughness) + { + return GeometrySchlickGGX(NdotV, roughness) * GeometrySchlickGGX(NdotL, roughness); + } + + float3 FresnelSchlick(float cosTheta, float3 F0) + { + return F0 + (1.0 - F0) * pow(saturate(1.0 - cosTheta), 5.0); + } + + float3 evaluateBRDF(float3 N, float3 V, float3 L, Material mat) + { + float roughness = max(mat.Roughness, 0.04); + float NdotL = max(dot(N, L), 0.0); + float NdotV = max(dot(N, V), 0.001); + float3 H = normalize(V + L); + float NdotH = max(dot(N, H), 0.0); + float HdotV = max(dot(H, V), 0.0); + + float3 F0 = lerp(float3(0.04, 0.04, 0.04), mat.Albedo, mat.Metallic); + + float D = DistributionGGX(NdotH, roughness); + float G = GeometrySmith(NdotV, NdotL, roughness); + float3 F = FresnelSchlick(HdotV, F0); + + float3 specular = D * G * F / (4.0 * NdotV * NdotL + 0.0001); + + float3 kD = (1.0 - F) * (1.0 - mat.Metallic); + float3 diffuse = kD * mat.Albedo / PI; + + return diffuse + specular; + } + + float3 sampleGGXHalfVector(float3 N, float roughness, inout uint seed) + { + float a = roughness * roughness; + + float r1 = randomFloat(seed); + float r2 = randomFloat(seed); + + float phi = 2.0 * PI * r1; + float cosTheta = sqrt((1.0 - r2) / (1.0 + (a * a - 1.0) * r2)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + + float3 w = N; + float3 helper = abs(w.x) > 0.99 ? float3(0.0, 1.0, 0.0) : float3(1.0, 0.0, 0.0); + float3 u = normalize(cross(helper, w)); + float3 v = cross(w, u); + + return normalize(u * cos(phi) * sinTheta + v * sin(phi) * sinTheta + w * cosTheta); + } + + uint pcgHash(uint input) + { + uint state = input * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; + } + + float randomFloat(inout uint seed) + { + seed = pcgHash(seed); + return float(seed) / 4294967295.0; + } + + float3 cosineSampleHemisphere(float3 normal, inout uint seed) + { + float r1 = randomFloat(seed); + float r2 = randomFloat(seed); + + float phi = 2.0 * 3.14159265 * r1; + float sinTheta = sqrt(r2); + float cosTheta = sqrt(1.0 - r2); + + float3 w = normal; + float3 helper = abs(w.x) > 0.99 ? float3(0.0, 1.0, 0.0) : float3(1.0, 0.0, 0.0); + float3 u = normalize(cross(helper, w)); + float3 v = cross(w, u); + + return normalize(u * cos(phi) * sinTheta + v * sin(phi) * sinTheta + w * cosTheta); + } + + bool traceShadowRay(float3 origin, float3 direction, float maxDist) + { + RayDesc shadowRay; + shadowRay.Origin = origin; + shadowRay.Direction = direction; + shadowRay.TMin = 0.001; + shadowRay.TMax = maxDist - 0.001; + + RayQuery shadowQuery; + shadowQuery.TraceRayInline(scene, RAY_FLAG_NONE, 0xFF, shadowRay); + + while (shadowQuery.Proceed()) {} + + return shadowQuery.CommittedStatus() != COMMITTED_NOTHING; + } + + float3 sampleLightDirect(float3 hitPos, float3 hitNormal, float3 V, Material mat, inout uint rng) + { + float u = randomFloat(rng); + float v = randomFloat(rng); + + float3 lightPoint = float3( + lerp(LightMin.x, LightMax.x, u), + LightMin.y, + lerp(LightMin.z, LightMax.z, v) + ); + + float3 toLight = lightPoint - hitPos; + float dist = length(toLight); + float3 L = toLight / dist; + + float NdotL = dot(hitNormal, L); + if (NdotL <= 0.0) + { + return float3(0.0, 0.0, 0.0); + } + + float lightCosine = max(dot(LightNormal, -L), 0.0); + if (lightCosine <= 0.0) + { + return float3(0.0, 0.0, 0.0); + } + + if (traceShadowRay(hitPos + hitNormal * 0.001, L, dist)) + { + return float3(0.0, 0.0, 0.0); + } + + Material lightMat = materials[3]; + float3 lightEmission = lightMat.Albedo * lightMat.Emission; + + float pdf = 1.0 / LightArea; + float3 brdf = evaluateBRDF(hitNormal, V, L, mat); + float geometryTerm = NdotL * lightCosine / (dist * dist); + + return lightEmission * brdf * geometryTerm / pdf; + } + + float3 tracePath(float3 origin, float3 direction, inout uint rng) + { + float3 throughput = float3(1.0, 1.0, 1.0); + float3 radiance = float3(0.0, 0.0, 0.0); + + for (int bounce = 0; bounce < 8; bounce++) + { + RayDesc ray; + ray.Origin = origin; + ray.Direction = direction; + ray.TMin = 0.001; + ray.TMax = 100000.0; + + RayQuery query; + query.TraceRayInline(scene, RAY_FLAG_NONE, 0xFF, ray); + + while (query.Proceed()) {} + + if (query.CommittedStatus() == COMMITTED_NOTHING) + { + float3 skyColor = lerp(float3(0.15, 0.12, 0.10), float3(0.30, 0.35, 0.45), saturate(direction.y * 0.5 + 0.5)); + radiance += throughput * skyColor; + break; + } + + uint primIdx = query.CommittedPrimitiveIndex(); + float2 bary = query.CommittedTriangleBarycentrics(); + float t = query.CommittedRayT(); + float3 hitPos = origin + direction * t; + + uint i0 = indices[primIdx * 3 + 0]; + uint i1 = indices[primIdx * 3 + 1]; + uint i2 = indices[primIdx * 3 + 2]; + + Vertex v0 = vertices[i0]; + Vertex v1 = vertices[i1]; + Vertex v2 = vertices[i2]; + + float3 baryWeights = float3(1.0 - bary.x - bary.y, bary.x, bary.y); + float3 normal = normalize( + v0.Normal * baryWeights.x + + v1.Normal * baryWeights.y + + v2.Normal * baryWeights.z + ); + + if (dot(normal, direction) > 0.0) + { + normal = -normal; + } + + Material mat = materials[v0.MaterialID]; + + if (mat.Emission > 0.0) + { + if (bounce == 0) + { + radiance += throughput * mat.Albedo * mat.Emission; + } + + break; + } + + float3 V = -direction; + + radiance += throughput * sampleLightDirect(hitPos, normal, V, mat, rng); + + float3 F0 = lerp(float3(0.04, 0.04, 0.04), mat.Albedo, mat.Metallic); + float roughness = max(mat.Roughness, 0.04); + float specWeight = max(F0.r, max(F0.g, F0.b)); + float diffWeight = (1.0 - specWeight) * (1.0 - mat.Metallic); + float total = specWeight + diffWeight; + float specProb = specWeight / total; + + float3 newDir; + float NdotV = max(dot(normal, V), 0.001); + + if (randomFloat(rng) < specProb) + { + float3 H = sampleGGXHalfVector(normal, roughness, rng); + newDir = reflect(-V, H); + + float NdotL = dot(normal, newDir); + if (NdotL <= 0.0) + { + break; + } + + float NdotH = max(dot(normal, H), 0.0); + float HdotV = max(dot(H, V), 0.0); + + float3 F = FresnelSchlick(HdotV, F0); + float G = GeometrySmith(NdotV, NdotL, roughness); + + float3 specThroughput = F * G * HdotV / (NdotV * NdotH * specProb + 0.0001); + throughput *= min(specThroughput, float3(10.0, 10.0, 10.0)); + } + else + { + newDir = cosineSampleHemisphere(normal, rng); + + float3 H = normalize(V + newDir); + float HdotV = max(dot(H, V), 0.0); + + float3 F = FresnelSchlick(HdotV, F0); + float3 kD = (1.0 - F) * (1.0 - mat.Metallic); + + throughput *= kD * mat.Albedo / (1.0 - specProb + 0.0001); + } + + origin = hitPos + normal * 0.001; + direction = newDir; + + if (bounce >= 2) + { + float p = max(throughput.r, max(throughput.g, throughput.b)); + + if (randomFloat(rng) > p) + { + break; + } + + throughput /= p; + } + } + + return radiance; + } + + [numthreads(16, 16, 1)] + void CSMain(uint3 dispatchThreadID : SV_DispatchThreadID) + { + uint2 pixel = dispatchThreadID.xy; + + if (pixel.x >= camera.Width || pixel.y >= camera.Height) + { + return; + } + + uint rng = pcgHash(pixel.x + pixel.y * camera.Width + camera.FrameCount * camera.Width * camera.Height); + + float2 jitter = float2(randomFloat(rng), randomFloat(rng)); + float2 uv = (float2(pixel) + jitter) / float2(camera.Width, camera.Height); + float2 ndc = uv * 2.0 - 1.0; + ndc.y = -ndc.y; + + float4 target = mul(float4(ndc, 1.0, 1.0), camera.InvProjection); + float3 localDir = normalize(target.xyz / target.w); + float3 direction = normalize(mul(float4(localDir, 0.0), camera.InvView).xyz); + float3 origin = camera.Position; + + float3 color = tracePath(origin, direction, rng); + color = min(color, float3(30.0, 30.0, 30.0)); + + float4 prev = accumTexture[pixel]; + float4 accumulated; + + if (camera.FrameCount == 0) + { + accumulated = float4(color, 1.0); + } + else + { + accumulated = prev + float4(color, 1.0); + } + + accumTexture[pixel] = accumulated; + + float3 avg = accumulated.rgb / float(camera.FrameCount + 1); + + // ACES tonemapping + float3 a = avg * (avg * 2.51 + 0.03); + float3 b = avg * (avg * 2.43 + 0.59) + 0.14; + avg = saturate(a / b); + + avg = pow(avg, 1.0 / 2.2); + outputTexture[pixel] = float4(avg, 1.0); + } + """; + + private readonly Buffer vertexBuffer; + private readonly Buffer indexBuffer; + private readonly Buffer materialBuffer; + private readonly Buffer cameraBuffer; + private readonly BottomLevelAccelerationStructure blas; + private readonly TopLevelAccelerationStructure tlas; + private readonly ResourceLayout resourceLayout; + private readonly ComputePipeline pipeline; + + private Texture? accumulationTexture; + private ResourceTable? resourceTable; + + private Matrix4x4 lastView; + private Matrix4x4 lastProjection; + + public PathTracingRenderer() + { + CornellBoxGeometry.Create(out Vertex[] vertices, out uint[] indices, out Material[] materials); + + vertexBuffer = App.Context.CreateBuffer(new() + { + SizeInBytes = (uint)(sizeof(Vertex) * vertices.Length), + StrideInBytes = (uint)sizeof(Vertex), + Flags = BufferUsageFlags.ShaderResource | BufferUsageFlags.AccelerationStructure + }); + vertexBuffer.Upload(vertices, 0); + + indexBuffer = App.Context.CreateBuffer(new() + { + SizeInBytes = (uint)(sizeof(uint) * indices.Length), + StrideInBytes = sizeof(uint), + Flags = BufferUsageFlags.ShaderResource | BufferUsageFlags.AccelerationStructure + }); + indexBuffer.Upload(indices, 0); + + materialBuffer = App.Context.CreateBuffer(new() + { + SizeInBytes = (uint)(sizeof(Material) * materials.Length), + StrideInBytes = (uint)sizeof(Material), + Flags = BufferUsageFlags.ShaderResource + }); + materialBuffer.Upload(materials, 0); + + cameraBuffer = App.Context.CreateBuffer(new() + { + SizeInBytes = (uint)sizeof(CameraParams), + StrideInBytes = (uint)sizeof(CameraParams), + Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite + }); + + CommandBuffer commandBuffer = App.Context.Graphics.CommandBuffer(); + + blas = commandBuffer.BuildAccelerationStructure(new BottomLevelAccelerationStructureDesc + { + Geometries = + [ + new() + { + Type = RayTracingGeometryType.Triangles, + Triangles = new() + { + VertexBuffer = vertexBuffer, + VertexFormat = PixelFormat.R32G32B32Float, + VertexCount = (uint)vertices.Length, + VertexStrideInBytes = (uint)sizeof(Vertex), + IndexBuffer = indexBuffer, + IndexFormat = IndexFormat.UInt32, + IndexCount = (uint)indices.Length, + Transform = Matrix4x4.Identity + }, + Flags = RayTracingGeometryFlags.Opaque + } + ], + Flags = AccelerationStructureBuildFlags.PreferFastTrace + }); + + tlas = commandBuffer.BuildAccelerationStructure(new TopLevelAccelerationStructureDesc + { + Instances = + [ + new() + { + AccelerationStructure = blas, + ID = 0, + Mask = 0xFF, + Transform = Matrix4x4.Identity, + Flags = RayTracingInstanceFlags.None + } + ], + Flags = AccelerationStructureBuildFlags.PreferFastTrace + }); + + commandBuffer.Submit(waitForCompletion: true); + + resourceLayout = App.Context.CreateResourceLayout(new() + { + Bindings = BindingHelper.Bindings + ( + new() { Type = ResourceType.AccelerationStructure, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, + new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute } + ) + }); + + using Shader computeShader = App.Context.LoadShaderFromSource(ShaderSource, "CSMain", ShaderStageFlags.Compute); + + pipeline = App.Context.CreateComputePipeline(new() + { + Compute = computeShader, + ResourceLayout = resourceLayout, + ThreadGroupSizeX = ThreadGroupSize, + ThreadGroupSizeY = ThreadGroupSize, + ThreadGroupSizeZ = 1 + }); + } + + public uint FrameCount { get; set; } + + public override void Update(CameraHandler camera) + { + Matrix4x4 view = camera.View; + Matrix4x4 projection = camera.Projection; + + if (view != lastView || projection != lastProjection) + { + lastView = view; + lastProjection = projection; + + FrameCount = 0; + } + + Matrix4x4.Invert(view, out Matrix4x4 invView); + Matrix4x4.Invert(projection, out Matrix4x4 invProjection); + + cameraBuffer.Upload([new() + { + InvView = invView, + InvProjection = invProjection, + Position = camera.Position, + FrameCount = FrameCount, + Width = App.Width, + Height = App.Height + }], 0); + } + + public override void Render(CommandBuffer commandBuffer) + { + if (resourceTable is null || accumulationTexture is null) + { + accumulationTexture = App.Context.CreateTexture(new() + { + Type = TextureType.Texture2D, + Format = PixelFormat.R32G32B32A32Float, + Width = App.Width, + Height = App.Height, + Depth = 1, + MipLevels = 1, + ArrayLayers = 1, + SampleCount = SampleCount.Count1, + Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess + }); + + resourceTable = App.Context.CreateResourceTable(new() + { + Layout = resourceLayout, + Resources = [tlas, cameraBuffer, vertexBuffer, indexBuffer, materialBuffer, accumulationTexture, Color] + }); + } + + commandBuffer.SetPipeline(pipeline); + commandBuffer.SetResourceTable(resourceTable); + + commandBuffer.Dispatch((App.Width + ThreadGroupSize - 1) / ThreadGroupSize, (App.Height + ThreadGroupSize - 1) / ThreadGroupSize, 1); + + FrameCount++; + } + + public override void Resize(uint width, uint height) + { + base.Resize(width, height); + + resourceTable?.Dispose(); + resourceTable = null; + + accumulationTexture?.Dispose(); + accumulationTexture = null; + + FrameCount = 0; + } + + public override void Dispose() + { + base.Dispose(); + + resourceTable?.Dispose(); + accumulationTexture?.Dispose(); + + pipeline.Dispose(); + resourceLayout.Dispose(); + tlas.Dispose(); + blas.Dispose(); + cameraBuffer.Dispose(); + materialBuffer.Dispose(); + indexBuffer.Dispose(); + vertexBuffer.Dispose(); + } +} + +[StructLayout(LayoutKind.Explicit, Size = 160)] +file struct CameraParams +{ + [FieldOffset(0)] + public Matrix4x4 InvView; + + [FieldOffset(64)] + public Matrix4x4 InvProjection; + + [FieldOffset(128)] + public Vector3 Position; + + [FieldOffset(144)] + public uint FrameCount; + + [FieldOffset(148)] + public uint Width; + + [FieldOffset(152)] + public uint Height; +} diff --git a/sources/Experiments/CornellBox/Renderers/RasterizationRenderer.cs b/sources/Experiments/CornellBox/Renderers/RasterizationRenderer.cs new file mode 100644 index 00000000..5bb33d23 --- /dev/null +++ b/sources/Experiments/CornellBox/Renderers/RasterizationRenderer.cs @@ -0,0 +1,284 @@ +using System.Numerics; +using System.Runtime.InteropServices; +using CornellBox.Handlers; +using CornellBox.Helpers; +using Zenith.NET; +using Zenith.NET.Extensions.Slang; +using Buffer = Zenith.NET.Buffer; + +namespace CornellBox.Renderers; + +internal unsafe class RasterizationRenderer : Renderer +{ + private const string ShaderSource = """ + struct Material + { + private float4 AlbedoAndEmission; + + float Metallic; + + float Roughness; + + private float padding0; + + private float padding1; + + property float3 Albedo { get { return AlbedoAndEmission.xyz; } } + + property float Emission { get { return AlbedoAndEmission.w; } } + }; + + struct RasterConstants + { + float4x4 Model; + + float4x4 View; + + float4x4 Projection; + + private float4 LightPosAndPadding; + + private float4 LightColorAndPadding; + + private float4 CameraPosAndPadding; + + property float3 LightPos { get { return LightPosAndPadding.xyz; } } + + property float3 LightColor { get { return LightColorAndPadding.xyz; } } + + property float3 CameraPos { get { return CameraPosAndPadding.xyz; } } + }; + + ConstantBuffer cb; + StructuredBuffer materials; + + struct VSInput + { + private float4 PositionAndPadding : POSITION0; + + private float4 NormalAndMaterialID : NORMAL0; + + property float3 Position { get { return PositionAndPadding.xyz; } } + + property float3 Normal { get { return NormalAndMaterialID.xyz; } } + + property uint MaterialID { get { return asuint(NormalAndMaterialID.w); } } + }; + + struct PSInput + { + float4 Position : SV_POSITION; + + float3 WorldPos : TEXCOORD0; + + float3 Normal : TEXCOORD1; + + nointerpolation uint MaterialID : TEXCOORD2; + }; + + PSInput VSMain(VSInput input) + { + float4 worldPos = mul(float4(input.Position, 1.0), cb.Model); + + PSInput output; + output.Position = mul(mul(worldPos, cb.View), cb.Projection); + output.WorldPos = worldPos.xyz; + output.Normal = normalize(mul(float4(input.Normal, 0.0), cb.Model).xyz); + output.MaterialID = input.MaterialID; + + return output; + } + + float4 PSMain(PSInput input) : SV_TARGET + { + Material mat = materials[input.MaterialID]; + + if (mat.Emission > 0.0) + { + float3 emissive = mat.Albedo * mat.Emission; + float3 mapped = emissive / (emissive + 1.0); + return float4(pow(mapped, 1.0 / 2.2), 1.0); + } + + float3 N = normalize(input.Normal); + float3 worldPos = input.WorldPos; + float3 L = normalize(cb.LightPos - worldPos); + float3 V = normalize(cb.CameraPos - worldPos); + float3 H = normalize(L + V); + + float NdotL = max(dot(N, L), 0.0); + float NdotH = max(dot(N, H), 0.0); + float spec = pow(NdotH, 64.0); + + float dist = length(cb.LightPos - worldPos); + float atten = 1.0 / (1.0 + 0.000005 * dist * dist); + + float hemiFactor = N.y * 0.5 + 0.5; + float3 ambient = mat.Albedo * lerp(0.06, 0.15, hemiFactor); + float3 diffuse = mat.Albedo * cb.LightColor * NdotL * atten; + float3 specular = cb.LightColor * spec * atten * 0.1; + + float3 color = ambient + diffuse + specular; + + // ACES tonemapping + float3 a = color * (color * 2.51 + 0.03); + float3 b = color * (color * 2.43 + 0.59) + 0.14; + color = saturate(a / b); + + color = pow(color, 1.0 / 2.2); + return float4(color, 1.0); + } + """; + + private readonly Buffer vertexBuffer; + private readonly Buffer indexBuffer; + private readonly Buffer materialBuffer; + private readonly Buffer constantBuffer; + private readonly uint indexCount; + private readonly ResourceLayout resourceLayout; + private readonly ResourceTable resourceTable; + private readonly GraphicsPipeline pipeline; + + public RasterizationRenderer() + { + CornellBoxGeometry.Create(out Vertex[] vertices, out uint[] indices, out Material[] materials); + + indexCount = (uint)indices.Length; + + vertexBuffer = App.Context.CreateBuffer(new() + { + SizeInBytes = (uint)(sizeof(Vertex) * vertices.Length), + StrideInBytes = (uint)sizeof(Vertex), + Flags = BufferUsageFlags.Vertex + }); + vertexBuffer.Upload(vertices, 0); + + indexBuffer = App.Context.CreateBuffer(new() + { + SizeInBytes = (uint)(sizeof(uint) * indices.Length), + StrideInBytes = sizeof(uint), + Flags = BufferUsageFlags.Index + }); + indexBuffer.Upload(indices, 0); + + materialBuffer = App.Context.CreateBuffer(new() + { + SizeInBytes = (uint)(sizeof(Material) * materials.Length), + StrideInBytes = (uint)sizeof(Material), + Flags = BufferUsageFlags.ShaderResource + }); + materialBuffer.Upload(materials, 0); + + constantBuffer = App.Context.CreateBuffer(new() + { + SizeInBytes = (uint)sizeof(RasterConstants), + StrideInBytes = (uint)sizeof(RasterConstants), + Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite + }); + + resourceLayout = App.Context.CreateResourceLayout(new() + { + Bindings = BindingHelper.Bindings + ( + new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Vertex | ShaderStageFlags.Pixel }, + new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Pixel } + ) + }); + + resourceTable = App.Context.CreateResourceTable(new() + { + Layout = resourceLayout, + Resources = [constantBuffer, materialBuffer] + }); + + InputLayout inputLayout = new(); + inputLayout.Add(new() { Format = ElementFormat.Float4, Semantic = ElementSemantic.Position }); + inputLayout.Add(new() { Format = ElementFormat.Float4, Semantic = ElementSemantic.Normal }); + + using Shader vertexShader = App.Context.LoadShaderFromSource(ShaderSource, "VSMain", ShaderStageFlags.Vertex); + using Shader pixelShader = App.Context.LoadShaderFromSource(ShaderSource, "PSMain", ShaderStageFlags.Pixel); + + pipeline = App.Context.CreateGraphicsPipeline(new() + { + RenderStates = new() + { + RasterizerState = RasterizerStates.CullNone, + DepthStencilState = DepthStencilStates.Default, + BlendState = BlendStates.Opaque + }, + Vertex = vertexShader, + Pixel = pixelShader, + ResourceLayout = resourceLayout, + InputLayouts = [inputLayout], + PrimitiveTopology = PrimitiveTopology.TriangleList, + Output = FrameBuffer.Output + }); + } + + public override void Update(CameraHandler camera) + { + constantBuffer.Upload([new() + { + Model = Matrix4x4.Identity, + View = camera.View, + Projection = camera.Projection, + LightPos = new(278.0f, 548.0f, 280.0f), + LightColor = new(2.0f, 1.8f, 1.4f), + CameraPos = camera.Position + }], 0); + } + + public override void Render(CommandBuffer commandBuffer) + { + commandBuffer.BeginRenderPass(FrameBuffer, new() + { + ColorValues = [new(0.51f, 0.518f, 0.557f, 1.0f)], + Depth = 1.0f, + Stencil = 0, + Flags = ClearFlags.All + }, resourceTable); + + commandBuffer.SetPipeline(pipeline); + commandBuffer.SetResourceTable(resourceTable); + commandBuffer.SetVertexBuffer(vertexBuffer, 0, 0); + commandBuffer.SetIndexBuffer(indexBuffer, 0, IndexFormat.UInt32); + commandBuffer.DrawIndexed(indexCount, 1, 0, 0, 0); + + commandBuffer.EndRenderPass(); + } + + public override void Dispose() + { + base.Dispose(); + + pipeline.Dispose(); + resourceTable.Dispose(); + resourceLayout.Dispose(); + constantBuffer.Dispose(); + materialBuffer.Dispose(); + indexBuffer.Dispose(); + vertexBuffer.Dispose(); + } +} + +[StructLayout(LayoutKind.Explicit, Size = 240)] +file struct RasterConstants +{ + [FieldOffset(0)] + public Matrix4x4 Model; + + [FieldOffset(64)] + public Matrix4x4 View; + + [FieldOffset(128)] + public Matrix4x4 Projection; + + [FieldOffset(192)] + public Vector3 LightPos; + + [FieldOffset(208)] + public Vector3 LightColor; + + [FieldOffset(224)] + public Vector3 CameraPos; +} diff --git a/sources/Experiments/CornellBox/Renderers/Renderer.cs b/sources/Experiments/CornellBox/Renderers/Renderer.cs new file mode 100644 index 00000000..9558e16a --- /dev/null +++ b/sources/Experiments/CornellBox/Renderers/Renderer.cs @@ -0,0 +1,68 @@ +using CornellBox.Handlers; +using Zenith.NET; + +namespace CornellBox.Renderers; + +internal abstract class Renderer : IDisposable +{ + protected Renderer() + { + Resize(App.Width, App.Height); + } + + public Texture Color { get; private set; } = null!; + + public Texture DepthStencil { get; private set; } = null!; + + public FrameBuffer FrameBuffer { get; private set; } = null!; + + public abstract void Update(CameraHandler camera); + + public abstract void Render(CommandBuffer commandBuffer); + + public virtual void Resize(uint width, uint height) + { + FrameBuffer?.Dispose(); + DepthStencil?.Dispose(); + Color?.Dispose(); + + Color = App.Context.CreateTexture(new() + { + Type = TextureType.Texture2D, + Format = PixelFormat.B8G8R8A8UNorm, + Width = width, + Height = height, + Depth = 1, + MipLevels = 1, + ArrayLayers = 1, + SampleCount = SampleCount.Count1, + Flags = TextureUsageFlags.RenderTarget | TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess + }); + + DepthStencil = App.Context.CreateTexture(new() + { + Type = TextureType.Texture2D, + Format = PixelFormat.D32FloatS8UInt, + Width = width, + Height = height, + Depth = 1, + MipLevels = 1, + ArrayLayers = 1, + SampleCount = SampleCount.Count1, + Flags = TextureUsageFlags.DepthStencil + }); + + FrameBuffer = App.Context.CreateFrameBuffer(new() + { + ColorAttachments = [new() { Target = Color }], + DepthStencilAttachment = new() { Target = DepthStencil } + }); + } + + public virtual void Dispose() + { + FrameBuffer.Dispose(); + DepthStencil.Dispose(); + Color.Dispose(); + } +} diff --git a/sources/Experiments/Directory.Packages.props b/sources/Experiments/Directory.Packages.props index ad71e76c..6f64c1d7 100644 --- a/sources/Experiments/Directory.Packages.props +++ b/sources/Experiments/Directory.Packages.props @@ -3,7 +3,6 @@ - diff --git a/sources/Experiments/SponzaScene/App.cs b/sources/Experiments/SponzaScene/App.cs deleted file mode 100644 index 4656949b..00000000 --- a/sources/Experiments/SponzaScene/App.cs +++ /dev/null @@ -1,217 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using Silk.NET.Input; -using Silk.NET.Windowing; -using SponzaScene.Helpers; -using SponzaScene.Models; -using SponzaScene.Renderer; -using Zenith.NET; -using Zenith.NET.DirectX12; -using Zenith.NET.Extensions.ImGui; -using Zenith.NET.Vulkan; - -namespace SponzaScene; - -internal static class App -{ - private static readonly IWindow window; - private static readonly IInputContext inputContext; - private static readonly SwapChain swapChain; - private static readonly SilkImGuiController imGui; - private static readonly CameraController camera; - private static readonly DeferredRenderer renderer; - - static App() - { - if (OperatingSystem.IsWindows()) - { - Context = GraphicsContext.CreateDirectX12(true); - } - else - { - Context = GraphicsContext.CreateVulkan(true); - } - - Context.ValidationMessage += static (sender, args) => Console.WriteLine($"[{args.Source} - {args.Severity}] {args.Message}"); - - Sponza = new(); - - FallbackTexture = Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R8G8B8A8UNorm, - Width = 1, - Height = 1, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource - }); - FallbackTexture.Upload([unchecked((int)0xFFFF00FF)], default, default, new() { Width = 1, Height = 1, Depth = 1 }); - - PointSampler = Context.CreateSampler(new() - { - Filter = Filter.MinPointMagPointMipPoint, - MaxLod = uint.MaxValue - }); - - LinearSampler = Context.CreateSampler(new() - { - Filter = Filter.MinLinearMagLinearMipLinear, - MaxLod = uint.MaxValue - }); - - ShadowSampler = Context.CreateSampler(new() - { - Filter = Filter.MinLinearMagLinearMipLinear, - U = AddressMode.Border, - V = AddressMode.Border, - W = AddressMode.Border, - BorderColor = BorderColor.OpaqueWhite, - ComparisonFunc = ComparisonFunc.LessEqual, - MaxLod = uint.MaxValue - }); - - window = Window.Create(WindowOptions.Default with { API = GraphicsAPI.None }); - window.Size = new(1280, 720); - window.Initialize(); - window.Center(); - - inputContext = window.CreateInput(); - - Surface surface; - if (OperatingSystem.IsWindows()) - { - surface = Surface.Win32(window.Native!.Win32!.Value.Hwnd, (uint)window.Size.X, (uint)window.Size.Y); - } - else if (OperatingSystem.IsMacOS()) - { - surface = Surface.Apple(CocoaHelper.CreateLayer(window.Native!.Cocoa!.Value), (uint)window.Size.X, (uint)window.Size.Y); - } - else if (OperatingSystem.IsLinux()) - { - surface = Surface.Xlib(window.Native!.X11!.Value.Display, (nint)window.Native.X11.Value.Window, (uint)window.Size.X, (uint)window.Size.Y); - } - else - { - throw new PlatformNotSupportedException(); - } - - swapChain = Context.CreateSwapChain(new() { Surface = surface, ColorTargetFormat = PixelFormat.B8G8R8A8UNorm, DepthStencilTargetFormat = PixelFormat.D32FloatS8UInt }); - imGui = new(inputContext, swapChain.FrameBuffer.Output, ImGuiColorSpace.Legacy); - camera = new(inputContext, Matrix4x4.CreateRotationY(float.DegreesToRadians(90.0f)) * Matrix4x4.CreateTranslation(new(-67.8f, 7.5f, -1.6f))); - renderer = new(); - } - - public static GraphicsContext Context { get; } - - public static Sponza Sponza { get; } - - public static Texture FallbackTexture { get; } - - public static Sampler PointSampler { get; } - - public static Sampler LinearSampler { get; } - - public static Sampler ShadowSampler { get; } - - public static void Run() - { - window.Update += delta => - { - uint width = (uint)window.Size.X; - uint height = (uint)window.Size.Y; - - if (width is 0 || height is 0) - { - return; - } - - imGui.Update(delta, width, height); - camera.Update(delta, width, height); - renderer.Update(width, height, camera); - }; - - window.Render += _ => - { - if (window.Size.X is 0 || window.Size.Y is 0) - { - return; - } - - renderer.Render(); - - // ImGui Rendering - { - renderer.UI(); - - ImGuiHelper.Overlay("Info", () => - { - ImGui.Text($"Backend: {Context.Backend}"); - - ImGui.Separator(); - - ImGui.Text(Context.Capabilities.DeviceName); - - ImGui.Separator(); - - ImGui.Text($"Ray Tracing Supported: {Context.Capabilities.RayTracingSupported}"); - - ImGui.Separator(); - - ImGui.Text($"Mesh Shading Supported: {Context.Capabilities.MeshShadingSupported}"); - - ImGui.Separator(); - - ImGui.Text($"Current FPS: {ImGui.GetIO().Framerate:F1}"); - }); - - CommandBuffer commandBuffer = Context.Graphics.CommandBuffer(); - - imGui.Render(commandBuffer, swapChain.FrameBuffer, ClearValues.Default); - - commandBuffer.Submit(true); - } - - swapChain.Present(); - }; - - window.Resize += size => - { - if (size.X is 0 || size.Y is 0) - { - return; - } - - swapChain.Resize((uint)size.X, (uint)size.Y); - }; - - window.Run(); - - renderer.Dispose(); - imGui.Dispose(); - swapChain.Dispose(); - inputContext.Dispose(); - window.Dispose(); - - ShadowSampler.Dispose(); - PointSampler.Dispose(); - LinearSampler.Dispose(); - FallbackTexture.Dispose(); - Sponza.Dispose(); - Context.Dispose(); - - Console.WriteLine("Exited cleanly."); - } - - public static ImTextureRef Binding(Texture texture) - { - return imGui.Binding(texture); - } - - public static ImTextureRef Binding(TextureView textureView) - { - return imGui.Binding(textureView); - } -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/Bloom.slang b/sources/Experiments/SponzaScene/Assets/Shaders/Bloom.slang deleted file mode 100644 index 9666edd5..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/Bloom.slang +++ /dev/null @@ -1,35 +0,0 @@ -static const float weights[5] = { 0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216 }; - -struct BloomConstants -{ - float2 TexelSize; -}; - -ConstantBuffer constants; -Texture2D sourceTexture; -RWTexture2D outputTexture; -SamplerState linearSampler; - -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadID: SV_DispatchThreadID) -{ - uint width, height; - outputTexture.GetDimensions(width, height); - - if (dispatchThreadID.x >= width || dispatchThreadID.y >= height) - { - return; - } - - float2 uv = (float2(dispatchThreadID.xy) + 0.5) / float2(width, height); - - float3 result = sourceTexture.SampleLevel(linearSampler, uv, 0).rgb * weights[0]; - - for (int i = 1; i < 5; i++) - { - result += sourceTexture.SampleLevel(linearSampler, uv + constants.TexelSize * i, 0).rgb * weights[i]; - result += sourceTexture.SampleLevel(linearSampler, uv - constants.TexelSize * i, 0).rgb * weights[i]; - } - - outputTexture[dispatchThreadID.xy] = float4(result, 1.0); -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/CSM.slang b/sources/Experiments/SponzaScene/Assets/Shaders/CSM.slang deleted file mode 100644 index 3b23632b..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/CSM.slang +++ /dev/null @@ -1,30 +0,0 @@ -struct CSMData -{ - float4x4 View; - - float4x4 Projection; -} - -ConstantBuffer data; - -struct VSInput -{ - float3 Position : POSITION0; -}; - -struct PSInput -{ - float4 Position : SV_POSITION; -}; - -PSInput VSMain(VSInput input) -{ - PSInput output; - output.Position = mul(mul(float4(input.Position, 1.0), data.View), data.Projection); - - return output; -} - -void PSMain(PSInput input) -{ -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/Compose.slang b/sources/Experiments/SponzaScene/Assets/Shaders/Compose.slang deleted file mode 100644 index cce4f9de..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/Compose.slang +++ /dev/null @@ -1,82 +0,0 @@ -static const float EXPOSURE = 0.85; -static const float CONTRAST = 1.18; -static const float SATURATION = 1.25; -static const float MID_GRAY = 0.18; - -static const float3 LUMA_COEFFICIENTS = float3(0.2126, 0.7152, 0.0722); -static const float3 WARM_TINT = float3(1.08, 1.0, 0.9); - -struct ComposeConstants -{ - float AOStrength; - - float BloomIntensity; - - float VolumetricIntensity; -}; - -ConstantBuffer constants; -Texture2D litColorTexture; -Texture2D gtaoTexture; -Texture2D bloomTexture; -Texture2D volumetricTexture; -RWTexture2D outputTexture; -SamplerState pointSampler; - -// ============================================ -// Tone Mapping -// ============================================ - -float3 ACESFilm(float3 x) -{ - const float a = 2.51; - const float b = 0.03; - const float c = 2.43; - const float d = 0.59; - const float e = 0.14; - - return saturate((x * (a * x + b)) / (x * (c * x + d) + e)); -} - -// ============================================ -// Color Grading -// ============================================ - -float3 ColorGrade(float3 color) -{ - color = (color - MID_GRAY) * CONTRAST + MID_GRAY; - - float luma = dot(color, LUMA_COEFFICIENTS); - color = lerp(luma, color, SATURATION); - - color *= WARM_TINT; - - return max(color, 0.0); -} - -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadID: SV_DispatchThreadID) -{ - uint width, height; - outputTexture.GetDimensions(width, height); - - if (dispatchThreadID.x >= width || dispatchThreadID.y >= height) - { - return; - } - - float2 uv = (float2(dispatchThreadID.xy) + 0.5) / float2(width, height); - - float3 color = litColorTexture.SampleLevel(pointSampler, uv, 0).rgb; - float ao = gtaoTexture.SampleLevel(pointSampler, uv, 0).r; - float3 bloom = bloomTexture.SampleLevel(pointSampler, uv, 0).rgb; - float volumetric = volumetricTexture.SampleLevel(pointSampler, uv, 0).r; - - color *= 1.0 - (1.0 - ao) * constants.AOStrength; - color += bloom * constants.BloomIntensity + volumetric * constants.VolumetricIntensity; - - color = ACESFilm(color * EXPOSURE); - color = ColorGrade(color); - - outputTexture[dispatchThreadID.xy] = float4(color, 1.0); -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/GBuffer.slang b/sources/Experiments/SponzaScene/Assets/Shaders/GBuffer.slang deleted file mode 100644 index 5ac06328..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/GBuffer.slang +++ /dev/null @@ -1,166 +0,0 @@ -enum MaterialFlags : int -{ - None = 0, - - UseAlphaCutoff = 1 << 0, - - HasBaseColorTexture = 1 << 1, - - HasNormalTexture = 1 << 2, - - HasMetallicRoughnessTexture = 1 << 3 -}; - -struct CameraConstants -{ - float4x4 View; - - float4x4 Projection; - - float NearPlane; - - float FarPlane; -}; - -struct MaterialConstants -{ - float AlphaCutoff; - - float MetallicFactor; - - float RoughnessFactor; - - float EmissiveStrength; - - float4 BaseColorFactor; - - float4 EmissiveFactor; - - MaterialFlags Flags; -}; - -ConstantBuffer camera; -ConstantBuffer material; -Texture2D baseColorTexture; -Texture2D normalTexture; -Texture2D metallicRoughnessTexture; -SamplerState linearSampler; - -struct VSInput -{ - float3 Position : POSITION0; - - float3 Normal : NORMAL0; - - float2 TexCoord : TEXCOORD0; - - float4 Color : COLOR0; -}; - -struct PSInput -{ - float4 Position : SV_POSITION; - - float3 WorldPosition : TEXCOORD0; - - float3 WorldNormal : TEXCOORD1; - - float3 WorldTangent : TEXCOORD2; - - float3 WorldBitangent : TEXCOORD3; - - float2 TexCoord : TEXCOORD4; - - float4 Color : COLOR0; -}; - -struct PSOutput -{ - float4 Albedo : SV_Target0; - - float4 Normal : SV_Target1; - - float4 Position : SV_Target2; - - float4 NormalizedDepth : SV_Target3; - - float4 MetallicRoughness : SV_Target4; - - float4 Emissive : SV_Target5; -}; - -float LinearizeDepth(float depth, float nearPlane, float farPlane) -{ - float z = depth * 2.0 - 1.0; - - return (2.0 * nearPlane * farPlane) / (farPlane + nearPlane - z * (farPlane - nearPlane)); -} - -PSInput VSMain(VSInput input) -{ - PSInput output; - - output.Position = mul(mul(float4(input.Position, 1.0), camera.View), camera.Projection); - output.WorldPosition = input.Position.xyz; - output.WorldNormal = normalize(input.Normal); - - float3 N = output.WorldNormal; - float3 up = abs(N.y) < 0.999 ? float3(0.0, 1.0, 0.0) : float3(0.0, 0.0, 1.0); - output.WorldTangent = normalize(cross(up, N)); - output.WorldBitangent = normalize(cross(N, output.WorldTangent)); - - output.TexCoord = input.TexCoord; - output.Color = input.Color; - - return output; -} - -PSOutput PSMain(PSInput input) -{ - PSOutput output; - - float4 baseColor = material.BaseColorFactor; - if ((material.Flags & MaterialFlags.HasBaseColorTexture) != 0) - { - baseColor *= baseColorTexture.Sample(linearSampler, input.TexCoord); - } - baseColor *= input.Color; - - if ((material.Flags & MaterialFlags.UseAlphaCutoff) != 0) - { - clip(baseColor.a - material.AlphaCutoff); - } - - float3 normal = normalize(input.WorldNormal); - if ((material.Flags & MaterialFlags.HasNormalTexture) != 0) - { - float3 tangentNormal = normalTexture.Sample(linearSampler, input.TexCoord).xyz * 2.0 - 1.0; - tangentNormal = normalize(tangentNormal); - - float3 T = normalize(input.WorldTangent); - float3 B = normalize(input.WorldBitangent); - float3 N = normalize(input.WorldNormal); - - normal = normalize(mul(tangentNormal, float3x3(T, B, N))); - } - - float metallic = material.MetallicFactor; - float roughness = material.RoughnessFactor; - if ((material.Flags & MaterialFlags.HasMetallicRoughnessTexture) != 0) - { - float4 mr = metallicRoughnessTexture.Sample(linearSampler, input.TexCoord); - roughness *= mr.g; - metallic *= mr.b; - } - - float normalizedDepth = LinearizeDepth(input.Position.z, camera.NearPlane, camera.FarPlane) / camera.FarPlane; - - output.Albedo = float4(baseColor.rgb, 1.0); - output.Normal = float4(normal, 1.0); - output.Position = float4(input.WorldPosition, 1.0); - output.NormalizedDepth = float4(normalizedDepth, normalizedDepth, normalizedDepth, 1.0); - output.MetallicRoughness = float4(metallic, roughness, 0.0, 1.0); - output.Emissive = float4(material.EmissiveFactor.rgb, material.EmissiveStrength); - - return output; -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/GTAO.slang b/sources/Experiments/SponzaScene/Assets/Shaders/GTAO.slang deleted file mode 100644 index be2e8708..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/GTAO.slang +++ /dev/null @@ -1,262 +0,0 @@ -static const float PI = 3.14159265359; -static const float EPSILON = 0.0001; - -static const float MAX_VIEW_DISTANCE = 500.0; -static const float MIN_VIEW_DISTANCE = 0.1; -static const float MIN_SAMPLE_DISTANCE = 0.001; -static const float MIN_SCREEN_RADIUS = 2.0; -static const float MAX_SCREEN_RADIUS = 100.0; - -static const float GOLDEN_RATIO = 0.381966; - -static const float CURVATURE_NORMAL_THRESHOLD = 0.4; -static const float CURVATURE_NDOTS_MIN = 0.2; -static const float CURVATURE_NDOTS_MAX = 0.7; -static const float CURVATURE_ATTENUATION = 0.8; - -struct GTAOConstants -{ - float4x4 View; - - float4x4 Projection; - - float2 ViewportSize; - - float EffectRadius; - - float EffectFalloffRange; - - float RadiusMultiplier; - - float FinalValuePower; - - float SampleDistributionPower; - - int SliceCount; - - int StepsPerSlice; -}; - -ConstantBuffer constants; -Texture2D positionTexture; -Texture2D normalTexture; -RWTexture2D outputTexture; -SamplerState pointSampler; - -// ============================================ -// Utility -// ============================================ - -float3 SafeNormalize(float3 v) -{ - float len = dot(v, v); - - return len > EPSILON ? v * rsqrt(len) : float3(0.0, 0.0, -1.0); -} - -float InterleavedGradientNoise(float2 pos) -{ - const float3 magic = float3(0.06711056, 0.00583715, 52.9829189); - - return frac(magic.z * frac(dot(pos, magic.xy))); -} - -// ============================================ -// Sampling -// ============================================ - -float3 GetViewPosition(float2 uv) -{ - float4 worldPos = positionTexture.SampleLevel(pointSampler, uv, 0); - - if (worldPos.w < EPSILON) - { - return float3(0.0, 0.0, 1e10); - } - - return mul(float4(worldPos.xyz, 1.0), constants.View).xyz; -} - -float3 GetViewNormal(float2 uv) -{ - float3 worldNormal = normalTexture.SampleLevel(pointSampler, uv, 0).xyz; - - if (dot(worldNormal, worldNormal) < 0.5) - { - return float3(0.0, 0.0, -1.0); - } - - return SafeNormalize(mul(float4(SafeNormalize(worldNormal), 0.0), constants.View).xyz); -} - -void SampleViewData(float2 uv, out float3 position, out float3 normal) -{ - float4 worldPos = positionTexture.SampleLevel(pointSampler, uv, 0); - - if (worldPos.w < EPSILON) - { - position = float3(0.0, 0.0, 1e10); - normal = float3(0.0, 0.0, -1.0); - - return; - } - - position = mul(float4(worldPos.xyz, 1.0), constants.View).xyz; - - float3 worldNormal = normalTexture.SampleLevel(pointSampler, uv, 0).xyz; - normal = SafeNormalize(mul(float4(SafeNormalize(worldNormal), 0.0), constants.View).xyz); -} - -// ============================================ -// Occlusion Calculation -// ============================================ - -float ApplyCurvatureCompensation(float NdotS, float normalDot) -{ - if (normalDot <= CURVATURE_NORMAL_THRESHOLD) - { - return NdotS; - } - - float normalFactor = (normalDot - CURVATURE_NORMAL_THRESHOLD) / (1.0 - CURVATURE_NORMAL_THRESHOLD); - normalFactor = normalFactor * normalFactor; - - float threshold = lerp(CURVATURE_NDOTS_MIN, CURVATURE_NDOTS_MAX, normalFactor); - - if (NdotS < threshold) - { - return 0.0; - } - - float remapped = (NdotS - threshold) / (1.0 - threshold); - - return remapped * (1.0 - normalFactor * CURVATURE_ATTENUATION); -} - -float CalculateSampleOcclusion(float3 centerPos, float3 centerNormal, float2 sampleUV, float worldRadius, float falloffPower) -{ - float3 samplePos, sampleNormal; - SampleViewData(sampleUV, samplePos, sampleNormal); - - if (abs(samplePos.z) >= MAX_VIEW_DISTANCE) - { - return 0.0; - } - - float3 toSample = samplePos - centerPos; - float dist = length(toSample); - - if (dist < MIN_SAMPLE_DISTANCE || dist >= worldRadius) - { - return 0.0; - } - - float3 sampleDir = toSample / dist; - float NdotS = dot(centerNormal, sampleDir); - - if (NdotS <= 0.0) - { - return 0.0; - } - - float normalDot = dot(centerNormal, sampleNormal); - NdotS = ApplyCurvatureCompensation(NdotS, normalDot); - - float distRatio = dist / worldRadius; - float falloff = saturate(1.0 - distRatio * distRatio); - float distanceFalloff = pow(falloff, falloffPower); - - return NdotS * distanceFalloff; -} - -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadID: SV_DispatchThreadID) -{ - uint2 pixelCoord = dispatchThreadID.xy; - - uint width, height; - outputTexture.GetDimensions(width, height); - - if (pixelCoord.x >= width || pixelCoord.y >= height) - { - return; - } - - float2 uv = (float2(pixelCoord) + 0.5) / float2(width, height); - - float3 viewPos = GetViewPosition(uv); - float viewDepth = abs(viewPos.z); - - if (viewDepth > MAX_VIEW_DISTANCE || viewDepth < MIN_VIEW_DISTANCE) - { - outputTexture[pixelCoord] = 1.0; - - return; - } - - float3 viewNormal = GetViewNormal(uv); - - float noise1 = InterleavedGradientNoise(float2(pixelCoord)); - float noise2 = InterleavedGradientNoise(float2(pixelCoord) + float2(5.588238, 5.588238)); - - float worldRadius = constants.EffectRadius * constants.RadiusMultiplier; - float projScale = abs(constants.Projection[1][1]); - float screenRadius = (worldRadius * projScale * constants.ViewportSize.y * 0.5) / viewDepth; - screenRadius = clamp(screenRadius, MIN_SCREEN_RADIUS, MAX_SCREEN_RADIUS); - - int sliceCount = constants.SliceCount; - int stepsPerSlice = constants.StepsPerSlice; - float invStepsPerSlice = 1.0 / float(stepsPerSlice); - - float totalOcclusion = 0.0; - float sampleCount = 0.0; - - float angleStep = PI / float(sliceCount); - float startAngle = noise1 * PI; - - float2 invViewportSize = 1.0 / constants.ViewportSize; - - for (int slice = 0; slice < sliceCount; slice++) - { - float angle = startAngle + angleStep * (float(slice) + 0.5); - float2 direction; - sincos(angle, direction.y, direction.x); - - float2 scaledDirection = direction * invViewportSize; - - for (int step = 1; step <= stepsPerSlice; step++) - { - float jitter = frac(noise2 + float(step) * GOLDEN_RATIO); - float t = (float(step) - 0.5 + jitter * 0.5) * invStepsPerSlice; - - float sampleRadius = max(pow(t, constants.SampleDistributionPower) * screenRadius, 1.0); - float2 offset = scaledDirection * sampleRadius; - - float2 forwardUV = uv + offset; - float2 backwardUV = uv - offset; - - if (all(forwardUV > 0.0) && all(forwardUV < 1.0)) - { - totalOcclusion += CalculateSampleOcclusion(viewPos, viewNormal, forwardUV, worldRadius, constants.EffectFalloffRange); - sampleCount += 1.0; - } - - if (all(backwardUV > 0.0) && all(backwardUV < 1.0)) - { - totalOcclusion += CalculateSampleOcclusion(viewPos, viewNormal, backwardUV, worldRadius, constants.EffectFalloffRange); - sampleCount += 1.0; - } - } - } - - float ao = 1.0; - - if (sampleCount > 0.0) - { - ao = 1.0 - saturate(totalOcclusion / sampleCount); - } - - ao = pow(saturate(ao), constants.FinalValuePower); - - outputTexture[pixelCoord] = ao; -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/GTAOBlur.slang b/sources/Experiments/SponzaScene/Assets/Shaders/GTAOBlur.slang deleted file mode 100644 index fe9c90de..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/GTAOBlur.slang +++ /dev/null @@ -1,112 +0,0 @@ -static const float EPSILON = 0.0001; - -static const float SPATIAL_SIGMA_SCALE = 0.5; -static const float RANGE_SIGMA = 0.15; -static const float DEPTH_SIGMA = 0.5; - -struct BlurConstants -{ - float2 TexelSize; - - int BlurSize; -}; - -ConstantBuffer constants; -Texture2D positionTexture; -Texture2D gtaoTexture; -RWTexture2D outputTexture; -SamplerState pointSampler; - -// ============================================ -// Utility -// ============================================ - -float GetLinearDepth(float2 uv) -{ - return positionTexture.SampleLevel(pointSampler, uv, 0).w; -} - -float GaussianWeight(float offset, float sigma) -{ - float sigmaSq2 = 2.0 * sigma * sigma; - - return exp(-(offset * offset) / sigmaSq2); -} - -float DepthWeight(float centerDepth, float sampleDepth) -{ - if (centerDepth < EPSILON || sampleDepth < EPSILON) - { - return 0.0; - } - - float depthDiff = abs(centerDepth - sampleDepth) / max(centerDepth, EPSILON); - - return exp(-(depthDiff * depthDiff) / (2.0 * DEPTH_SIGMA * DEPTH_SIGMA)); -} - -float RangeWeight(float centerValue, float sampleValue) -{ - float diff = centerValue - sampleValue; - - return exp(-(diff * diff) / (2.0 * RANGE_SIGMA * RANGE_SIGMA)); -} - -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadID: SV_DispatchThreadID) -{ - uint width, height; - outputTexture.GetDimensions(width, height); - - if (dispatchThreadID.x >= width || dispatchThreadID.y >= height) - { - return; - } - - float2 uv = (float2(dispatchThreadID.xy) + 0.5) / float2(width, height); - - float centerValue = gtaoTexture.SampleLevel(pointSampler, uv, 0).r; - float centerDepth = GetLinearDepth(uv); - - float result = centerValue; - float totalWeight = 1.0; - - int blurSize = constants.BlurSize; - float spatialSigma = float(blurSize) * SPATIAL_SIGMA_SCALE; - - for (int y = -blurSize; y <= blurSize; y++) - { - for (int x = -blurSize; x <= blurSize; x++) - { - if (x == 0 && y == 0) - { - continue; - } - - float2 offset = float2(x, y) * constants.TexelSize; - float2 sampleUV = uv + offset; - - if (any(sampleUV < 0.0) || any(sampleUV > 1.0)) - { - continue; - } - - float sampleValue = gtaoTexture.SampleLevel(pointSampler, sampleUV, 0).r; - float sampleDepth = GetLinearDepth(sampleUV); - - float dist = length(float2(x, y)); - float wSpatial = GaussianWeight(dist, spatialSigma); - float wDepth = DepthWeight(centerDepth, sampleDepth); - float wRange = RangeWeight(centerValue, sampleValue); - - float weight = wSpatial * wDepth * wRange; - - result += sampleValue * weight; - totalWeight += weight; - } - } - - result /= max(totalWeight, EPSILON); - - outputTexture[dispatchThreadID.xy] = result; -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/Lighting.slang b/sources/Experiments/SponzaScene/Assets/Shaders/Lighting.slang deleted file mode 100644 index 48fbb7c2..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/Lighting.slang +++ /dev/null @@ -1,592 +0,0 @@ -static const float PI = 3.14159265359; -static const float INV_PI = 0.31830988618; -static const float EPSILON = 0.0001; - -static const float MIN_AMBIENT = 0.015; - -static const float SHADOW_BASE_OFFSET = 0.045; -static const float SHADOW_BASE_RADIUS = 3.5; -static const float SHADOW_NORMAL_SMOOTH = 0.5; -static const int SHADOW_SAMPLE_COUNT = 32; - -struct DirectionalLight -{ - float3 Direction; - - float Intensity; - - float3 Color; -}; - -struct PointLight -{ - float3 Position; - - float Radius; - - float3 Color; - - float Intensity; -}; - -struct LightingConstants -{ - float4 CameraPosition; - - float4x4 InverseViewProjection; - - DirectionalLight DirectionalLight; -}; - -struct CSMData -{ - float4x4 View; - - float4x4 Projection; - - float NearPlane; - - float FarPlane; -}; - -struct SkyParams -{ - float DayFactor; - - float SunsetFactor; - - float NightFactor; - - float SunVis; - - float3 SunDir; -}; - -ConstantBuffer constants; -StructuredBuffer pointLights; -StructuredBuffer csmDatas; -Texture2D albedoTexture; -Texture2D normalTexture; -Texture2D positionTexture; -Texture2D metallicRoughnessTexture; -Texture2D emissiveTexture; -Texture2DArray csmTextures; -Texture2D gtaoTexture; -Texture2D rtgiTexture; -RWTexture2D outputTexture; -SamplerState pointSampler; -SamplerComparisonState shadowSampler; - -// ============================================ -// Utility -// ============================================ - -float3 SafeNormalize(float3 v) -{ - float len = dot(v, v); - - return len > EPSILON ? v * rsqrt(len) : float3(0.0, 1.0, 0.0); -} - -float InterleavedGradientNoise(float2 pos) -{ - const float3 magic = float3(0.06711056, 0.00583715, 52.9829189); - - return frac(magic.z * frac(dot(pos, magic.xy))); -} - -float2 VogelDiskSample(int sampleIndex, int samplesCount, int phi) -{ - const float goldenAngle = 2.4; - - float r = sqrt(float(sampleIndex) + 0.5) / sqrt(float(samplesCount)); - float theta = float(sampleIndex) * goldenAngle + phi; - - return float2(r * cos(theta), r * sin(theta)); -} - -// ============================================ -// Sky -// ============================================ - -SkyParams CalculateSkyParams(float3 sunDirection) -{ - SkyParams params; - - params.SunDir = SafeNormalize(-sunDirection); - - float sunHeight = params.SunDir.y; - - params.DayFactor = saturate(sunHeight * 2.0); - params.SunsetFactor = (1.0 - params.DayFactor) * (1.0 - params.DayFactor); - params.NightFactor = saturate(-sunHeight * 3.0); - params.SunVis = smoothstep(-0.1, 0.15, sunHeight); - - return params; -} - -float3 BlendSkyColors(float3 dayColor, float3 sunsetColor, float3 nightColor, SkyParams params) -{ - return lerp(lerp(dayColor, sunsetColor, params.SunsetFactor), nightColor, params.NightFactor); -} - -float3 SampleSkyColor(float3 direction, float3 sunDirection, float3 sunColor, float sunIntensity) -{ - SkyParams params = CalculateSkyParams(sunDirection); - - float3 zenithColor = BlendSkyColors(float3(0.1, 0.4, 1.0), float3(0.38, 0.22, 0.58) + sunColor * 0.32, float3(0.005, 0.005, 0.015), params); - - float3 horizonColor = BlendSkyColors(float3(0.5, 0.7, 1.0), sunColor * float3(1.0, 0.8, 0.55), float3(0.015, 0.015, 0.04), params); - - float t = pow(saturate(direction.y * 0.5 + 0.5), 0.35); - - return lerp(horizonColor, zenithColor, t) * (0.6 + params.DayFactor * 0.4) * sunIntensity * 0.32; -} - -float3 CalculateSkybox(float3 viewDir, float3 sunDirection, float3 sunColor, float sunIntensity) -{ - viewDir = SafeNormalize(viewDir); - - SkyParams params = CalculateSkyParams(sunDirection); - float elevation = viewDir.y; - - float3 zenithColor = BlendSkyColors(float3(0.08, 0.35, 1.0), float3(0.35, 0.2, 0.55) + sunColor * 0.3, float3(0.005, 0.005, 0.02), params); - - float3 horizonColor = BlendSkyColors(float3(0.25, 0.48, 0.95), sunColor * float3(1.0, 0.85, 0.6), float3(0.015, 0.015, 0.04), params); - - float3 groundColor = BlendSkyColors(float3(0.18, 0.35, 0.7), sunColor * float3(0.7, 0.5, 0.35), float3(0.01, 0.01, 0.025), params); - - float skyBlend = pow(saturate(elevation + 0.1), 0.18); - float3 skyColor = lerp(horizonColor, zenithColor, skyBlend); - - float groundBlend = 1.0 - saturate((elevation + 0.3) / 0.5); - groundBlend = groundBlend * groundBlend * (3.0 - 2.0 * groundBlend); - skyColor = lerp(skyColor, groundColor, groundBlend); - - float sunDot = dot(viewDir, params.SunDir); - float glowIntensity = sunIntensity * 0.2; - - float glow1 = pow(max(sunDot * 0.5 + 0.5, 0.0), 8.0 + params.DayFactor * 4.0) * 0.05 * (1.0 + params.SunsetFactor * 0.5); - float glow2 = pow(max(sunDot, 0.0), 32.0 + params.DayFactor * 16.0) * 0.15 * glowIntensity; - float glow3 = pow(max(sunDot, 0.0), 128.0 + params.DayFactor * 64.0) * 0.3 * glowIntensity; - float glow4 = pow(max(sunDot, 0.0), 512.0 + params.DayFactor * 256.0) * 0.8 * glowIntensity; - - float discThreshold = 0.9998 + params.DayFactor * 0.0001; - float sunDisc = smoothstep(discThreshold, discThreshold + 0.0001, sunDot) * 2.0 * glowIntensity; - - float3 glowColor = lerp(sunColor * float3(1.0, 0.6, 0.3), sunColor, params.DayFactor) * params.SunVis; - float3 discColor = lerp(float3(1.0, 0.85, 0.6), float3(1.0, 0.98, 0.94), params.DayFactor) * params.SunVis; - - skyColor += glowColor * (glow1 + glow2) + sunColor * params.SunVis * (glow3 + glow4) + discColor * sunDisc; - - float horizonGlow = exp(-elevation * elevation * (30.0 + params.DayFactor * 20.0)); - float3 viewHoriz = SafeNormalize(float3(viewDir.x, 0.0, viewDir.z)); - float3 sunHoriz = SafeNormalize(float3(params.SunDir.x, 0.0, params.SunDir.z)); - float horizSunDot = max(dot(viewHoriz, sunHoriz), 0.0); - - float3 warmGlow = lerp(float3(0.15, 0.1, 0.15), sunColor * 0.5, horizSunDot * params.SunsetFactor); - skyColor += warmGlow * horizonGlow * (0.06 + params.SunsetFactor * 0.1) * (0.3 + horizSunDot * 0.5) * params.SunVis; - - if (params.NightFactor > 0.1 && elevation > 0.0) - { - float starNoise = frac(sin(dot(viewDir.xz * 100.0, float2(12.9898, 78.233))) * 43758.5453); - - skyColor += smoothstep(0.98, 1.0, starNoise) * params.NightFactor * elevation * 0.5; - } - - return skyColor; -} - -float3 GetViewDirection(float2 uv) -{ - float2 ndc = float2(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0); - float4 worldPos = mul(float4(ndc, 1.0, 1.0), constants.InverseViewProjection); - - return SafeNormalize(worldPos.xyz / worldPos.w - constants.CameraPosition.xyz); -} - -// ============================================ -// Shadow Mapping -// ============================================ - -int GetCascadeIndex(float distanceToCamera) -{ - uint cascadeCount = csmDatas.getCount(); - - for (uint i = 0; i < cascadeCount; i++) - { - if (distanceToCamera < csmDatas[i].FarPlane) - { - return int(i); - } - } - - return int(cascadeCount - 1); -} - -float3 WorldToShadowCoord(float3 worldPos, int cascadeIndex) -{ - float4 lightSpacePos = mul(mul(float4(worldPos, 1.0), csmDatas[cascadeIndex].View), csmDatas[cascadeIndex].Projection); - lightSpacePos.xyz /= lightSpacePos.w; - - return float3(lightSpacePos.x * 0.5 + 0.5, -lightSpacePos.y * 0.5 + 0.5, lightSpacePos.z); -} - -float SampleShadowPCF(float3 shadowCoord, int cascadeIndex, float2 texelSize, float2 screenPos, float filterRadius) -{ - int rotationAngle = int(InterleavedGradientNoise(screenPos) * PI * 2.0); - float shadow = 0.0; - - for (int i = 0; i < SHADOW_SAMPLE_COUNT; i++) - { - float2 offset = VogelDiskSample(i, SHADOW_SAMPLE_COUNT, rotationAngle) * filterRadius * texelSize; - - shadow += csmTextures.SampleCmpLevelZero(shadowSampler, - float3(shadowCoord.xy + offset, cascadeIndex), - shadowCoord.z); - } - - return shadow / float(SHADOW_SAMPLE_COUNT); -} - -float CalculateShadow(float3 worldPos, float3 cameraPos, float3 normal, float3 lightDir, float2 screenPos) -{ - uint cascadeCount = csmDatas.getCount(); - - if (cascadeCount == 0) - { - return 1.0; - } - - float3 L = SafeNormalize(-lightDir); - float3 V = SafeNormalize(cameraPos - worldPos); - - float3 shadowNormal = SafeNormalize(lerp(normal, SafeNormalize(normal + L * 0.3), SHADOW_NORMAL_SMOOTH)); - - float NdotL = dot(shadowNormal, L); - - if (NdotL <= 0.0) - { - return 0.0; - } - - float NdotV = abs(dot(shadowNormal, V)); - float grazingView = 1.0 - NdotV; - float grazingLight = 1.0 - NdotL; - float combinedGrazing = max(grazingView * grazingView, grazingLight * grazingLight); - - float distanceToCamera = length(worldPos - cameraPos); - int cascadeIndex = GetCascadeIndex(distanceToCamera); - float cascadeScale = 1.0 + cascadeIndex * 0.6; - - float3 biasNormal = SafeNormalize(lerp(shadowNormal, L, combinedGrazing * 0.7)); - float sinTheta = sqrt(1.0 - NdotL * NdotL); - float slopeBias = min(sinTheta / max(NdotL, 0.01), 8.0) * 0.005; - float grazingBias = combinedGrazing * combinedGrazing * 0.15; - - float totalBias = (SHADOW_BASE_OFFSET + slopeBias + grazingBias) * cascadeScale; - float3 biasedPos = worldPos + biasNormal * totalBias + L * totalBias * 0.5; - float3 shadowCoord = WorldToShadowCoord(biasedPos, cascadeIndex); - - const float margin = 0.01; - - if (any(shadowCoord.xy < margin) || any(shadowCoord.xy > 1.0 - margin) || shadowCoord.z < 0.0 || shadowCoord.z > 1.0) - { - return 1.0; - } - - uint width, height, elements; - csmTextures.GetDimensions(width, height, elements); - float2 texelSize = 1.0 / float2(width, height); - - float cascadeFar = csmDatas[cascadeIndex].FarPlane; - float cascadeNear = csmDatas[cascadeIndex].NearPlane; - float blendRegion = (cascadeFar - cascadeNear) * 0.25; - float blendStart = cascadeFar - blendRegion; - - float blendFactor = 0.0; - - if (distanceToCamera > blendStart && cascadeIndex < int(cascadeCount - 1)) - { - blendFactor = smoothstep(0.0, 1.0, (distanceToCamera - blendStart) / blendRegion); - } - - float grazingRadius = combinedGrazing * combinedGrazing * 3.5; - float baseRadius = SHADOW_BASE_RADIUS + cascadeIndex * 0.5 + grazingRadius; - float filterRadius = lerp(baseRadius, baseRadius + 0.5, blendFactor); - - float shadow = SampleShadowPCF(shadowCoord, cascadeIndex, texelSize, screenPos, filterRadius); - - if (blendFactor > 0.0) - { - int nextCascade = cascadeIndex + 1; - float nextCascadeScale = 1.0 + nextCascade * 0.6; - float nextTotalBias = (SHADOW_BASE_OFFSET + slopeBias + grazingBias) * nextCascadeScale; - - float3 nextBiasedPos = worldPos + biasNormal * nextTotalBias + L * nextTotalBias * 0.5; - float3 nextShadowCoord = WorldToShadowCoord(nextBiasedPos, nextCascade); - - if (all(nextShadowCoord.xy > margin) && all(nextShadowCoord.xy < 1.0 - margin) && nextShadowCoord.z > 0.0 && - nextShadowCoord.z < 1.0) - { - float nextFilterRadius = baseRadius + 0.5 + nextCascade * 0.5; - float nextShadow = SampleShadowPCF(nextShadowCoord, nextCascade, texelSize, screenPos, nextFilterRadius); - - shadow = lerp(shadow, nextShadow, blendFactor); - } - } - - return shadow; -} - -// ============================================ -// PBR -// ============================================ - -float DistributionGGX(float NdotH, float roughness) -{ - float a2 = roughness * roughness; - a2 *= a2; - - float denom = NdotH * NdotH * (a2 - 1.0) + 1.0; - - return a2 / (PI * denom * denom + EPSILON); -} - -float GeometrySmith(float NdotV, float NdotL, float roughness) -{ - float k = (roughness + 1.0) * (roughness + 1.0) * 0.125; - float ggxV = NdotV / (NdotV * (1.0 - k) + k); - float ggxL = NdotL / (NdotL * (1.0 - k) + k); - - return ggxV * ggxL; -} - -float3 FresnelSchlick(float cosTheta, float3 F0) -{ - float t = 1.0 - cosTheta; - float t2 = t * t; - - return F0 + (1.0 - F0) * (t2 * t2 * t); -} - -float3 FresnelSchlickRoughness(float cosTheta, float3 F0, float roughness) -{ - float t = 1.0 - cosTheta; - float t2 = t * t; - - return F0 + (max(1.0 - roughness, F0) - F0) * (t2 * t2 * t); -} - -float3 CalculatePBRLight(float3 L, float3 V, float3 N, float3 albedo, float metallic, float roughness, float3 radiance) -{ - float3 H = SafeNormalize(V + L); - float3 F0 = lerp(0.04, albedo, metallic); - - float NdotV = max(dot(N, V), EPSILON); - float NdotL = max(dot(N, L), 0.0); - float NdotH = max(dot(N, H), 0.0); - float HdotV = max(dot(H, V), 0.0); - - float D = DistributionGGX(NdotH, roughness); - float G = GeometrySmith(NdotV, NdotL, roughness); - float3 F = FresnelSchlick(HdotV, F0); - - float3 specular = (D * G * F) / (4.0 * NdotV * NdotL + EPSILON); - float3 kD = (1.0 - F) * (1.0 - metallic); - - return (kD * albedo * INV_PI + specular) * radiance * NdotL; -} - -// ============================================ -// Lighting -// ============================================ - -float3 CalculateMinimalAmbient(float3 N, float3 V, float3 albedo, float metallic, float roughness, float ao, - float3 sunDirection, float3 sunColor, float sunIntensity) -{ - float3 F0 = lerp(0.04, albedo, metallic); - float NdotV = max(dot(N, V), EPSILON); - - float3 F = FresnelSchlickRoughness(NdotV, F0, roughness); - float3 kD = (1.0 - F) * (1.0 - metallic); - - float3 skyColor = SampleSkyColor(N, sunDirection, sunColor, sunIntensity); - float3 ambient = kD * albedo * skyColor * 0.05; - - float3 R = reflect(-V, N); - float3 skyReflection = SampleSkyColor(R, sunDirection, sunColor, sunIntensity); - float horizonOcclusion = saturate(1.0 + dot(R, N)); - float roughnessAttenuation = 1.0 - roughness * 0.7; - float3 specularAmbient = skyReflection * F * horizonOcclusion * roughnessAttenuation * 0.2; - - return (ambient + specularAmbient) * ao; -} - -float3 CalculateDirectionalLight(DirectionalLight light, float3 V, float3 N, float3 albedo, float metallic, float roughness, float shadow) -{ - float shadowFactor = shadow * shadow * shadow; - float3 radiance = light.Color * light.Intensity * shadowFactor; - - return CalculatePBRLight(SafeNormalize(-light.Direction), V, N, albedo, metallic, roughness, radiance); -} - -float3 CalculatePointLight(PointLight light, float3 worldPos, float3 V, float3 N, float3 albedo, float metallic, float roughness) -{ - float3 toLight = light.Position - worldPos; - float distance = length(toLight); - - if (distance > light.Radius) - { - return 0.0; - } - - float3 L = toLight / distance; - - float distanceRatio = distance / light.Radius; - float distanceRatio2 = distanceRatio * distanceRatio; - float radiusAttenuation = saturate(1.0 - distanceRatio2 * distanceRatio2); - radiusAttenuation *= radiusAttenuation; - - float physicalFalloff = 1.0 / max(distance * distance, EPSILON); - float attenuation = radiusAttenuation * physicalFalloff; - - return CalculatePBRLight(L, V, N, albedo, metallic, roughness, light.Color * light.Intensity * attenuation); -} - -float3 CalculateGlobalIllumination(float3 N, float3 albedo, float3 giRadiance, float metallic, float ao, - float3 sunDirection, float3 sunColor, float sunIntensity, float shadow) -{ - float diffuseWeight = 1.0 - metallic; - float giLuminance = dot(giRadiance, float3(0.299, 0.587, 0.114)); - bool hasValidGI = giLuminance > 0.001; - - float3 sunDir = SafeNormalize(-sunDirection); - float sunHeight = max(sunDir.y, 0.0); - float NdotL = max(dot(N, sunDir), 0.0); - - float3 giContribution = float3(0.0); - - if (hasValidGI) - { - float directLightStrength = NdotL * shadow; - float giScale = lerp(1.8, 0.8, directLightStrength); - - giContribution = albedo * giRadiance * diffuseWeight * giScale; - } - else - { - float3 skyUp = float3(0.25, 0.4, 0.65) * sunIntensity * 0.06; - float3 skyHorizon = float3(0.35, 0.4, 0.45) * sunIntensity * 0.05; - float3 skyDown = float3(0.12, 0.11, 0.1) * sunIntensity * 0.03; - - float upWeight = max(N.y, 0.0); - float downWeight = max(-N.y, 0.0); - float sideWeight = 1.0 - abs(N.y); - - float3 ambient = skyUp * upWeight + skyDown * downWeight + skyHorizon * sideWeight; - - float shadowAmbientBoost = lerp(1.5, 1.0, shadow); - - giContribution = albedo * ambient * diffuseWeight * shadowAmbientBoost; - } - - float darknessLevel = 1.0 - max(NdotL * shadow, giLuminance * 6.0); - float3 minAmbient = albedo * MIN_AMBIENT * sunIntensity * (0.2 + sunHeight * 0.8); - giContribution += minAmbient * saturate(darknessLevel) * 0.3; - - if (!hasValidGI) - { - float3 fallbackAmbient = albedo * 0.015 * sunIntensity * (0.3 + sunHeight * 0.7); - giContribution += fallbackAmbient * diffuseWeight; - } - - float aoFactor = lerp(0.4, 1.0, ao); - - return giContribution * aoFactor; -} - -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadID: SV_DispatchThreadID) -{ - uint width, height; - outputTexture.GetDimensions(width, height); - - if (dispatchThreadID.x >= width || dispatchThreadID.y >= height) - { - return; - } - - float2 uv = (float2(dispatchThreadID.xy) + 0.5) / float2(width, height); - - float3 worldPos = positionTexture.SampleLevel(pointSampler, uv, 0).xyz; - float3 normalData = normalTexture.SampleLevel(pointSampler, uv, 0).xyz; - - if (dot(worldPos, worldPos) < EPSILON || dot(normalData, normalData) < EPSILON) - { - outputTexture[dispatchThreadID.xy] = float4(CalculateSkybox(GetViewDirection(uv), - constants.DirectionalLight.Direction, - constants.DirectionalLight.Color, - constants.DirectionalLight.Intensity), - 1.0); - return; - } - - float3 albedo = albedoTexture.SampleLevel(pointSampler, uv, 0).rgb; - float3 N = SafeNormalize(normalData); - float2 metallicRoughness = metallicRoughnessTexture.SampleLevel(pointSampler, uv, 0).xy; - metallicRoughness.y = max(metallicRoughness.y, 0.04); - - float4 emissiveData = emissiveTexture.SampleLevel(pointSampler, uv, 0); - float ao = max(gtaoTexture.SampleLevel(pointSampler, uv, 0).r, 0.1); - float3 giRadiance = rtgiTexture.SampleLevel(pointSampler, uv, 0).rgb; - float3 V = SafeNormalize(constants.CameraPosition.xyz - worldPos); - - float3 color; - - if (dot(emissiveData.rgb, float3(0.299, 0.587, 0.114)) > 0.01) - { - color = emissiveData.rgb * emissiveData.a; - } - else - { - float shadow = CalculateShadow(worldPos, constants.CameraPosition.xyz, N, constants.DirectionalLight.Direction, uv); - - color = CalculateMinimalAmbient(N, - V, - albedo, - metallicRoughness.x, - metallicRoughness.y, - ao, - constants.DirectionalLight.Direction, - constants.DirectionalLight.Color, - constants.DirectionalLight.Intensity); - - color += CalculateDirectionalLight(constants.DirectionalLight, - V, - N, - albedo, - metallicRoughness.x, - metallicRoughness.y, - shadow); - - uint pointLightCount = pointLights.getCount(); - - for (uint i = 0; i < pointLightCount; i++) - { - color += CalculatePointLight(pointLights[i], worldPos, V, N, albedo, metallicRoughness.x, metallicRoughness.y); - } - - color += CalculateGlobalIllumination(N, - albedo, - giRadiance, - metallicRoughness.x, - ao, - constants.DirectionalLight.Direction, - constants.DirectionalLight.Color, - constants.DirectionalLight.Intensity, - shadow); - } - - outputTexture[dispatchThreadID.xy] = float4(max(color, 0.0), 1.0); -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/RTGI.slang b/sources/Experiments/SponzaScene/Assets/Shaders/RTGI.slang deleted file mode 100644 index 71f7a434..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/RTGI.slang +++ /dev/null @@ -1,379 +0,0 @@ -static const float PI = 3.14159265359; -static const float INV_PI = 0.31830988618; -static const float EPSILON = 0.0001; - -static const float RAY_MAX_DISTANCE = 200.0; -static const float SHADOW_RAY_DISTANCE = 500.0; -static const float GBUFFER_DISTANCE_THRESHOLD = 3.0; - -static const float RAY_ORIGIN_NORMAL_OFFSET = 0.1; -static const float RAY_TMIN = 0.01; - -struct DirectionalLight -{ - float3 Direction; - - float Intensity; - - float3 Color; -}; - -struct PointLight -{ - float3 Position; - - float Radius; - - float3 Color; - - float Intensity; -}; - -struct RTGIConstants -{ - uint Width; - - uint Height; - - uint FrameIndex; - - float Intensity; - - float4x4 ViewProjection; - - DirectionalLight DirectionalLight; -}; - -ConstantBuffer constants; -RaytracingAccelerationStructure tlas; -StructuredBuffer pointLights; -Texture2D albedoTexture; -Texture2D normalTexture; -Texture2D positionTexture; -Texture2D depthTexture; -RWTexture2D outputTexture; -SamplerState linearSampler; - -// ============================================ -// Utility -// ============================================ - -float3 SafeNormalize(float3 v) -{ - float len = dot(v, v); - - return len > EPSILON ? v * rsqrt(len) : float3(0.0, 1.0, 0.0); -} - -uint WangHash(uint seed) -{ - seed = (seed ^ 61) ^ (seed >> 16); - seed *= 9; - seed = seed ^ (seed >> 4); - seed *= 0x27d4eb2d; - seed = seed ^ (seed >> 15); - - return seed; -} - -float RandomFloat(inout uint seed) -{ - seed = WangHash(seed); - - return float(seed) / 4294967295.0; -} - -float2 RandomFloat2(inout uint seed) -{ - return float2(RandomFloat(seed), RandomFloat(seed)); -} - -// ============================================ -// Sampling -// ============================================ - -float3 CosineSampleHemisphere(float3 normal, inout uint seed) -{ - float2 u = RandomFloat2(seed); - - float r = sqrt(u.x); - float phi = 2.0 * PI * u.y; - - float3 localDir = float3(r * cos(phi), r * sin(phi), sqrt(max(0.0, 1.0 - u.x))); - - float3 up = abs(normal.y) < 0.999 ? float3(0.0, 1.0, 0.0) : float3(1.0, 0.0, 0.0); - float3 tangent = normalize(cross(up, normal)); - float3 bitangent = cross(normal, tangent); - - return normalize(tangent * localDir.x + bitangent * localDir.y + normal * localDir.z); -} - -float3 OffsetRayOrigin(float3 position, float3 normal) -{ - return position + normal * RAY_ORIGIN_NORMAL_OFFSET; -} - -bool ReprojectToScreen(float3 worldPos, float4x4 viewProj, out float2 screenUV) -{ - float4 clipPos = mul(float4(worldPos, 1.0), viewProj); - - if (clipPos.w <= 0.0) - { - screenUV = float2(-1.0); - - return false; - } - - clipPos.xyz /= clipPos.w; - screenUV = float2(clipPos.x * 0.5 + 0.5, -clipPos.y * 0.5 + 0.5); - - return all(screenUV >= 0.0) && all(screenUV <= 1.0) && clipPos.z > 0.0 && clipPos.z < 1.0; -} - -// ============================================ -// Sky -// ============================================ - -float3 GetSkyRadiance(float3 direction) -{ - float3 sunDir = SafeNormalize(-constants.DirectionalLight.Direction); - float sunHeight = max(sunDir.y, 0.0); - float elevation = direction.y; - - float3 skyBlue = float3(0.4, 0.6, 1.0); - float3 horizonColor = float3(0.7, 0.78, 0.9); - float3 groundColor = float3(0.25, 0.22, 0.2); - - float t = pow(saturate(elevation * 0.5 + 0.5), 0.4); - float3 skyColor = lerp(horizonColor, skyBlue, t); - - if (elevation < 0.0) - { - float groundBlend = saturate(-elevation * 2.0); - - skyColor = lerp(skyColor, groundColor, groundBlend); - } - - float baseBrightness = 0.25 + sunHeight * 0.2; - - return skyColor * constants.DirectionalLight.Intensity * baseBrightness; -} - -float3 GetAmbientRadiance(float3 normal) -{ - float3 skyUp = GetSkyRadiance(float3(0.0, 1.0, 0.0)); - float3 skyHorizon = GetSkyRadiance(float3(1.0, 0.0, 0.0)); - float3 skyDown = GetSkyRadiance(float3(0.0, -1.0, 0.0)) * 0.5; - - float upWeight = max(normal.y, 0.0); - float downWeight = max(-normal.y, 0.0); - float sideWeight = 1.0 - abs(normal.y); - - float3 ambient = skyUp * upWeight + skyDown * downWeight + skyHorizon * sideWeight; - - return ambient * 0.8; -} - -// ============================================ -// Shadow Testing -// ============================================ - -bool TraceShadowRay(float3 origin, float3 direction, float maxDistance) -{ - RayDesc shadowRay; - shadowRay.Origin = origin; - shadowRay.Direction = direction; - shadowRay.TMin = RAY_TMIN; - shadowRay.TMax = maxDistance; - - RayQuery shadowQuery; - shadowQuery.TraceRayInline(tlas, RAY_FLAG_NONE, 0xFF, shadowRay); - - while (shadowQuery.Proceed()) - { - } - - return shadowQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT; -} - -// ============================================ -// Surface Lighting -// ============================================ - -float3 CalculateSurfaceRadiance(float3 hitPos, float3 hitNormal, float3 hitAlbedo) -{ - float3 Lo = float3(0.0); - - float3 sunDir = SafeNormalize(-constants.DirectionalLight.Direction); - float NdotL = max(dot(hitNormal, sunDir), 0.0); - - if (NdotL > 0.0) - { - float3 shadowOrigin = OffsetRayOrigin(hitPos, hitNormal); - - if (!TraceShadowRay(shadowOrigin, sunDir, SHADOW_RAY_DISTANCE)) - { - float3 sunRadiance = constants.DirectionalLight.Color * constants.DirectionalLight.Intensity; - - Lo += (hitAlbedo * INV_PI) * sunRadiance * NdotL; - } - } - - float3 ambient = GetAmbientRadiance(hitNormal); - Lo += hitAlbedo * ambient; - - uint pointLightCount = pointLights.getCount(); - - for (uint i = 0; i < pointLightCount; i++) - { - PointLight light = pointLights[i]; - - float3 toLight = light.Position - hitPos; - float distance = length(toLight); - - if (distance > light.Radius) - { - continue; - } - - float3 L = toLight / distance; - float lightNdotL = max(dot(hitNormal, L), 0.0); - - if (lightNdotL <= 0.0) - { - continue; - } - - float distanceRatio = distance / light.Radius; - float distanceRatio2 = distanceRatio * distanceRatio; - float radiusAttenuation = saturate(1.0 - distanceRatio2 * distanceRatio2); - radiusAttenuation *= radiusAttenuation; - - float physicalFalloff = 1.0 / max(distance * distance, EPSILON); - float attenuation = radiusAttenuation * physicalFalloff; - - float3 lightRadiance = light.Color * light.Intensity * attenuation; - - Lo += (hitAlbedo * INV_PI) * lightRadiance * lightNdotL; - } - - return Lo; -} - -float3 EstimateOffscreenRadiance(float3 hitPos, float3 rayDir, float hitDistance) -{ - float3 sunDir = SafeNormalize(-constants.DirectionalLight.Direction); - float3 estimatedAlbedo = float3(0.5, 0.5, 0.5); - float3 estimatedNormal = -rayDir; - - float NdotL = max(dot(estimatedNormal, sunDir), 0.0); - - float3 directLight = float3(0.0); - - if (NdotL > 0.0) - { - float3 shadowOrigin = OffsetRayOrigin(hitPos, estimatedNormal); - - if (!TraceShadowRay(shadowOrigin, sunDir, SHADOW_RAY_DISTANCE)) - { - float3 sunRadiance = constants.DirectionalLight.Color * constants.DirectionalLight.Intensity; - - directLight = (estimatedAlbedo * INV_PI) * sunRadiance * NdotL; - } - } - - float3 ambient = GetAmbientRadiance(estimatedNormal); - - float distanceFade = saturate(1.0 - hitDistance / RAY_MAX_DISTANCE * 0.3); - - return (directLight + estimatedAlbedo * ambient) * distanceFade; -} - -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadID: SV_DispatchThreadID) -{ - uint2 pixelCoord = dispatchThreadID.xy; - - if (pixelCoord.x >= constants.Width || pixelCoord.y >= constants.Height) - { - return; - } - - float2 uv = (float2(pixelCoord) + 0.5) / float2(constants.Width, constants.Height); - - float3 worldPos = positionTexture.SampleLevel(linearSampler, uv, 0).xyz; - float3 normal = normalTexture.SampleLevel(linearSampler, uv, 0).xyz; - float depth = depthTexture.SampleLevel(linearSampler, uv, 0).r; - - if (depth < EPSILON || dot(normal, normal) < EPSILON) - { - outputTexture[pixelCoord] = float4(0.0, 0.0, 0.0, 1.0); - - return; - } - - normal = SafeNormalize(normal); - - uint seed = pixelCoord.x + pixelCoord.y * constants.Width + constants.FrameIndex * 719393; - - float3 rayDir = CosineSampleHemisphere(normal, seed); - float3 rayOrigin = OffsetRayOrigin(worldPos, normal); - - RayDesc ray; - ray.Origin = rayOrigin; - ray.Direction = rayDir; - ray.TMin = RAY_TMIN; - ray.TMax = RAY_MAX_DISTANCE; - - RayQuery query; - query.TraceRayInline(tlas, RAY_FLAG_NONE, 0xFF, ray); - - while (query.Proceed()) - { - } - - float3 radiance = float3(0.0); - - if (query.CommittedStatus() == COMMITTED_TRIANGLE_HIT) - { - float3 hitPos = rayOrigin + rayDir * query.CommittedRayT(); - - float2 hitScreenUV; - - if (ReprojectToScreen(hitPos, constants.ViewProjection, hitScreenUV)) - { - float3 hitAlbedo = albedoTexture.SampleLevel(linearSampler, hitScreenUV, 0).rgb; - float3 hitNormal = normalTexture.SampleLevel(linearSampler, hitScreenUV, 0).xyz; - float hitDepth = depthTexture.SampleLevel(linearSampler, hitScreenUV, 0).r; - float3 gbufferPos = positionTexture.SampleLevel(linearSampler, hitScreenUV, 0).xyz; - - float distToGBuffer = length(hitPos - gbufferPos); - - if (hitDepth > EPSILON && distToGBuffer < GBUFFER_DISTANCE_THRESHOLD) - { - radiance = CalculateSurfaceRadiance(hitPos, SafeNormalize(hitNormal), hitAlbedo); - } - else if (hitDepth > EPSILON) - { - float blendFactor = saturate((distToGBuffer - GBUFFER_DISTANCE_THRESHOLD) / GBUFFER_DISTANCE_THRESHOLD); - float3 estimatedNormal = SafeNormalize(lerp(hitNormal, -rayDir, blendFactor * 0.4)); - - radiance = CalculateSurfaceRadiance(hitPos, estimatedNormal, hitAlbedo); - } - else - { - radiance = EstimateOffscreenRadiance(hitPos, rayDir, query.CommittedRayT()); - } - } - else - { - radiance = EstimateOffscreenRadiance(hitPos, rayDir, query.CommittedRayT()); - } - } - else - { - radiance = GetSkyRadiance(rayDir); - } - - outputTexture[pixelCoord] = float4(radiance * constants.Intensity, 1.0); -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/SVGFAtrous.slang b/sources/Experiments/SponzaScene/Assets/Shaders/SVGFAtrous.slang deleted file mode 100644 index 16176abd..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/SVGFAtrous.slang +++ /dev/null @@ -1,112 +0,0 @@ -static const float EPSILON = 1e-6; -static const float KERNEL[3] = { 1.0, 0.75, 0.25 }; - -struct AtrousConstants -{ - float2 ViewportSize; - - int StepWidth; - - float PhiColor; - - float PhiNormal; - - float PhiDepth; -}; - -ConstantBuffer constants; -Texture2D inputTexture; -Texture2D positionTexture; -Texture2D normalTexture; -RWTexture2D outputTexture; - -float Luminance(float3 c) -{ - return dot(c, float3(0.2126, 0.7152, 0.0722)); -} - -float3 SafeNormalize(float3 v) -{ - float lenSq = dot(v, v); - - return lenSq > EPSILON ? v * rsqrt(lenSq) : float3(0.0, 0.0, 1.0); -} - -[numthreads(16, 16, 1)] -void CSMain(uint3 id: SV_DispatchThreadID) -{ - uint2 coord = id.xy; - - if (any(coord >= uint2(constants.ViewportSize))) - { - return; - } - - float3 centerPos = positionTexture.Load(int3(coord, 0)).xyz; - - if (dot(centerPos, centerPos) < EPSILON) - { - outputTexture[coord] = float4(0.0); - - return; - } - - float4 centerData = inputTexture.Load(int3(coord, 0)); - float3 centerColor = centerData.rgb; - float centerVar = max(centerData.a, EPSILON); - float3 centerNormal = SafeNormalize(normalTexture.Load(int3(coord, 0)).xyz); - float centerLum = max(Luminance(centerColor), EPSILON); - float centerDepth = length(centerPos); - - float phiLum = constants.PhiColor * sqrt(centerVar * centerLum * centerLum) + 0.001; - float phiDepth = centerDepth * constants.PhiDepth + 0.01; - - float3 colorSum = centerColor; - float varSum = centerVar; - float wSum = 1.0; - - [unroll] - for (int dy = -2; dy <= 2; dy++) - { - [unroll] - for (int dx = -2; dx <= 2; dx++) - { - if (dx == 0 && dy == 0) - { - continue; - } - - int2 p = int2(coord) + int2(dx, dy) * constants.StepWidth; - - if (any(p < 0) || any(p >= int2(constants.ViewportSize))) - { - continue; - } - - float3 samplePos = positionTexture.Load(int3(p, 0)).xyz; - - if (dot(samplePos, samplePos) < EPSILON) - { - continue; - } - - float4 sampleData = inputTexture.Load(int3(p, 0)); - float3 sampleNormal = SafeNormalize(normalTexture.Load(int3(p, 0)).xyz); - - float wK = KERNEL[abs(dx)] * KERNEL[abs(dy)]; - float wL = exp(-abs(Luminance(sampleData.rgb) - centerLum) / phiLum); - float wN = pow(max(dot(centerNormal, sampleNormal), 0.0), constants.PhiNormal); - float wD = exp(-abs(dot(samplePos - centerPos, centerNormal)) / phiDepth); - - float w = wK * wL * wN * wD; - - colorSum += sampleData.rgb * w; - varSum += max(sampleData.a, EPSILON) * w; - wSum += w; - } - } - - float invW = 1.0 / wSum; - - outputTexture[coord] = float4(colorSum * invW, varSum * invW); -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/SVGFTemporal.slang b/sources/Experiments/SponzaScene/Assets/Shaders/SVGFTemporal.slang deleted file mode 100644 index 78228a13..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/SVGFTemporal.slang +++ /dev/null @@ -1,207 +0,0 @@ -static const float EPSILON = 1e-6; - -struct TemporalConstants -{ - float4x4 PrevViewProjection; - - float2 ViewportSize; - - float ColorBoxSigma; - - float NormalThreshold; - - float DepthThreshold; - - int MaxHistoryLength; -}; - -ConstantBuffer constants; -Texture2D colorTexture; -Texture2D positionTexture; -Texture2D normalTexture; -Texture2D historyPositionTexture; -Texture2D historyNormalTexture; -Texture2D historyAccumulatedTexture; -Texture2D historyMomentsTexture; -RWTexture2D accumulatedTexture; -RWTexture2D momentsTexture; -RWTexture2D outputTexture; -SamplerState linearSampler; - -float Luminance(float3 c) -{ - return dot(c, float3(0.2126, 0.7152, 0.0722)); -} - -float3 SafeNormalize(float3 v) -{ - float lenSq = dot(v, v); - - return lenSq > EPSILON ? v * rsqrt(lenSq) : float3(0.0, 0.0, 1.0); -} - -bool Reproject(float3 pos, float3 normal, out int2 histCoord) -{ - float4 clip = mul(float4(pos, 1.0), constants.PrevViewProjection); - - if (clip.w <= 0.0) - { - histCoord = int2(-1, -1); - - return false; - } - - float2 ndc = clip.xy / clip.w; - float2 uv = float2(ndc.x * 0.5 + 0.5, -ndc.y * 0.5 + 0.5); - - if (any(uv < 0.0) || any(uv > 1.0)) - { - histCoord = int2(-1, -1); - - return false; - } - - histCoord = int2(uv * constants.ViewportSize); - - float3 histPos = historyPositionTexture.SampleLevel(linearSampler, uv, 0).xyz; - - if (dot(histPos, histPos) < EPSILON) - { - return false; - } - - float3 n = SafeNormalize(normal); - float depth = length(pos); - float planeDist = abs(dot(pos - histPos, n)); - - if (planeDist > depth * constants.DepthThreshold) - { - return false; - } - - float3 histNormal = historyNormalTexture.SampleLevel(linearSampler, uv, 0).xyz; - - if (dot(n, SafeNormalize(histNormal)) < constants.NormalThreshold) - { - return false; - } - - return true; -} - -void ComputeNeighborhood(uint2 coord, out float3 mean, out float3 stdDev, out float variance) -{ - float3 m1 = float3(0.0); - float3 m2 = float3(0.0); - - [unroll] - for (int y = -1; y <= 1; y++) - { - [unroll] - for (int x = -1; x <= 1; x++) - { - int2 p = clamp(int2(coord) + int2(x, y), int2(0), int2(constants.ViewportSize) - 1); - float3 c = colorTexture.Load(int3(p, 0)).rgb; - - m1 += c; - m2 += c * c; - } - } - - m1 /= 9.0; - m2 /= 9.0; - - float3 var = max(m2 - m1 * m1, 0.0); - mean = m1; - stdDev = sqrt(var + EPSILON); - - float meanLum = max(Luminance(mean), EPSILON); - float varLum = Luminance(var); - - variance = varLum / (meanLum * meanLum) + EPSILON; -} - -[numthreads(16, 16, 1)] -void CSMain(uint3 id: SV_DispatchThreadID) -{ - uint2 coord = id.xy; - - if (any(coord >= uint2(constants.ViewportSize))) - { - return; - } - - float3 pos = positionTexture.Load(int3(coord, 0)).xyz; - - if (dot(pos, pos) < EPSILON) - { - accumulatedTexture[coord] = float4(0.0); - momentsTexture[coord] = float4(0.0); - outputTexture[coord] = float4(0.0); - - return; - } - - float3 normal = normalTexture.Load(int3(coord, 0)).xyz; - float3 color = colorTexture.Load(int3(coord, 0)).rgb; - - float3 mean, stdDev; - float spatialVar; - ComputeNeighborhood(coord, mean, stdDev, spatialVar); - - float3 boxMin = mean - stdDev * constants.ColorBoxSigma; - float3 boxMax = mean + stdDev * constants.ColorBoxSigma; - - int2 histCoord; - bool valid = Reproject(pos, normal, histCoord); - - float3 accumulated; - float2 moments; - float histLen; - - if (valid) - { - float3 histColor = historyAccumulatedTexture.Load(int3(histCoord, 0)).rgb; - float4 histMom = historyMomentsTexture.Load(int3(histCoord, 0)); - - histColor = clamp(histColor, boxMin, boxMax); - histLen = min(histMom.w + 1.0, float(constants.MaxHistoryLength)); - - float alpha = 1.0 / histLen; - accumulated = lerp(histColor, color, alpha); - - float lum = Luminance(color); - moments.x = lerp(histMom.x, lum, alpha); - moments.y = lerp(histMom.y, lum * lum, alpha); - } - else - { - accumulated = color; - histLen = 1.0; - - float lum = Luminance(color); - moments = float2(lum, lum * lum); - } - - float temporalVar = max(moments.y - moments.x * moments.x, 0.0); - float meanLum = max(moments.x, EPSILON); - float relativeVar = temporalVar / (meanLum * meanLum); - - float variance; - - if (histLen < 4.0) - { - float t = histLen / 4.0; - variance = lerp(spatialVar * 4.0, relativeVar, t * t); - } - else - { - variance = relativeVar; - } - - variance = max(variance, 0.01); - - accumulatedTexture[coord] = float4(accumulated, 1.0); - momentsTexture[coord] = float4(moments, 0.0, histLen); - outputTexture[coord] = float4(accumulated, variance); -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/VolumetricLight.slang b/sources/Experiments/SponzaScene/Assets/Shaders/VolumetricLight.slang deleted file mode 100644 index 708968f3..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/VolumetricLight.slang +++ /dev/null @@ -1,173 +0,0 @@ -static const float PI = 3.14159265359; -static const float EPSILON = 0.0001; - -static const float MAX_PHASE = 0.5; -static const float SUN_VIEW_ATTENUATION = 0.95; -static const float INTENSITY_SCALE = 0.005; - -struct VolumetricLightConstants -{ - float4 CameraPosition; - - float4 LightDirection; - - float4 LightColor; - - float4x4 InverseViewProjection; - - float2 ScreenSize; - - int SampleCount; - - float Intensity; - - float Scattering; - - float MaxDistance; -}; - -struct CSMData -{ - float4x4 View; - - float4x4 Projection; - - float NearPlane; - - float FarPlane; -}; - -ConstantBuffer constants; -StructuredBuffer csmDatas; -Texture2D positionTexture; -Texture2DArray csmTextures; -RWTexture2D outputTexture; -SamplerState pointSampler; -SamplerComparisonState shadowSampler; - -// ============================================ -// Utility -// ============================================ - -float InterleavedGradientNoise(float2 pos) -{ - const float3 magic = float3(0.06711056, 0.00583715, 52.9829189); - - return frac(magic.z * frac(dot(pos, magic.xy))); -} - -float HenyeyGreenstein(float cosTheta, float g) -{ - float g2 = g * g; - float denom = 1.0 + g2 - 2.0 * g * cosTheta; - float phase = (1.0 - g2) / (4.0 * PI * pow(max(denom, EPSILON), 1.5)); - - return min(phase, MAX_PHASE); -} - -// ============================================ -// Shadow Sampling -// ============================================ - -int GetCascadeIndex(float distanceToCamera) -{ - uint cascadeCount = csmDatas.getCount(); - - for (uint i = 0; i < cascadeCount; i++) - { - if (distanceToCamera < csmDatas[i].FarPlane) - { - return int(i); - } - } - - return int(cascadeCount - 1); -} - -float SampleShadow(float3 worldPos, int cascadeIndex) -{ - float4 lightSpacePos = mul(mul(float4(worldPos, 1.0), csmDatas[cascadeIndex].View), csmDatas[cascadeIndex].Projection); - lightSpacePos.xyz /= lightSpacePos.w; - - float3 shadowCoord = float3(lightSpacePos.x * 0.5 + 0.5, -lightSpacePos.y * 0.5 + 0.5, lightSpacePos.z); - - if (any(shadowCoord.xy < 0.0) || any(shadowCoord.xy > 1.0) || shadowCoord.z < 0.0 || shadowCoord.z > 1.0) - { - return 1.0; - } - - return csmTextures.SampleCmpLevelZero(shadowSampler, float3(shadowCoord.xy, cascadeIndex), shadowCoord.z); -} - -// ============================================ -// Ray Marching -// ============================================ - -float3 GetWorldPosition(float2 ndc) -{ - float4 worldPos = mul(float4(ndc, 1.0, 1.0), constants.InverseViewProjection); - - return worldPos.xyz / worldPos.w; -} - -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadID: SV_DispatchThreadID) -{ - uint width, height; - outputTexture.GetDimensions(width, height); - - if (dispatchThreadID.x >= width || dispatchThreadID.y >= height) - { - return; - } - - float2 uv = (float2(dispatchThreadID.xy) + 0.5) / float2(width, height); - float2 ndc = float2(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0); - - float3 cameraPos = constants.CameraPosition.xyz; - float3 farWorldPos = GetWorldPosition(ndc); - float3 rayDir = normalize(farWorldPos - cameraPos); - - float3 surfacePos = positionTexture.SampleLevel(pointSampler, uv, 0).xyz; - float surfaceDistSq = dot(surfacePos, surfacePos); - float maxRayDistance = surfaceDistSq > EPSILON ? length(surfacePos - cameraPos) : constants.MaxDistance; - maxRayDistance = min(maxRayDistance, constants.MaxDistance); - - float3 lightDir = normalize(constants.LightDirection.xyz); - float cosTheta = dot(rayDir, -lightDir); - - float sunAlignment = max(cosTheta, 0.0); - float sunViewFactor = saturate(1.0 - pow(sunAlignment, 2.0) * SUN_VIEW_ATTENUATION); - float phase = HenyeyGreenstein(cosTheta, constants.Scattering); - - float noise = InterleavedGradientNoise(float2(dispatchThreadID.xy)); - float stepSize = maxRayDistance / float(constants.SampleCount); - float3 rayStep = rayDir * stepSize; - - float accumulation = 0.0; - float3 samplePos = cameraPos + rayDir * noise * stepSize; - - int currentCascade = 0; - float currentCascadeFar = csmDatas[0].FarPlane; - - for (int i = 0; i < constants.SampleCount; i++) - { - float distanceToCamera = float(i + 1) * stepSize; - - while (distanceToCamera > currentCascadeFar && currentCascade < int(csmDatas.getCount()) - 1) - { - currentCascade++; - currentCascadeFar = csmDatas[currentCascade].FarPlane; - } - - float shadow = SampleShadow(samplePos, currentCascade); - - accumulation += shadow; - - samplePos += rayStep; - } - - float volumetric = accumulation * stepSize * phase * sunViewFactor * constants.LightColor.w * constants.Intensity * INTENSITY_SCALE; - - outputTexture[dispatchThreadID.xy] = volumetric; -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/VolumetricLightBlur.slang b/sources/Experiments/SponzaScene/Assets/Shaders/VolumetricLightBlur.slang deleted file mode 100644 index 133a452c..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/VolumetricLightBlur.slang +++ /dev/null @@ -1,68 +0,0 @@ -static const float EPSILON = 0.0001; -static const float DEPTH_FALLOFF = 0.25; - -static const int KERNEL_RADIUS = 4; -static const float KERNEL_WEIGHTS[9] = { 0.0093, 0.028, 0.0659, 0.1226, 0.1802, 0.1226, 0.0659, 0.028, 0.0093 }; - -struct BlurConstants -{ - float2 TexelSize; -}; - -ConstantBuffer constants; -Texture2D inputTexture; -Texture2D positionTexture; -RWTexture2D outputTexture; -SamplerState linearSampler; - -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadID: SV_DispatchThreadID) -{ - uint width, height; - outputTexture.GetDimensions(width, height); - - if (dispatchThreadID.x >= width || dispatchThreadID.y >= height) - { - return; - } - - float2 uv = (float2(dispatchThreadID.xy) + 0.5) / float2(width, height); - - float3 centerPos = positionTexture.SampleLevel(linearSampler, uv, 0).xyz; - float centerDepth = dot(centerPos, centerPos); - - float centerValue = inputTexture.SampleLevel(linearSampler, uv, 0).r; - float centerWeight = KERNEL_WEIGHTS[KERNEL_RADIUS]; - - float result = centerValue * centerWeight; - float totalWeight = centerWeight; - - [unroll] - for (int i = 1; i <= KERNEL_RADIUS; i++) - { - float2 offset = constants.TexelSize * float(i); - float kernelWeight = KERNEL_WEIGHTS[KERNEL_RADIUS + i]; - - float2 uvPos = uv + offset; - float2 uvNeg = uv - offset; - - float3 posPos = positionTexture.SampleLevel(linearSampler, uvPos, 0).xyz; - float3 posNeg = positionTexture.SampleLevel(linearSampler, uvNeg, 0).xyz; - - float depthPos = dot(posPos, posPos); - float depthNeg = dot(posNeg, posNeg); - - float diffPos = centerDepth - depthPos; - float diffNeg = centerDepth - depthNeg; - - float weightPos = kernelWeight * exp(-diffPos * diffPos * DEPTH_FALLOFF); - float weightNeg = kernelWeight * exp(-diffNeg * diffNeg * DEPTH_FALLOFF); - - result += inputTexture.SampleLevel(linearSampler, uvPos, 0).r * weightPos; - result += inputTexture.SampleLevel(linearSampler, uvNeg, 0).r * weightNeg; - - totalWeight += weightPos + weightNeg; - } - - outputTexture[dispatchThreadID.xy] = result / max(totalWeight, EPSILON); -} diff --git a/sources/Experiments/SponzaScene/Assets/Shaders/slangdconfig.json b/sources/Experiments/SponzaScene/Assets/Shaders/slangdconfig.json deleted file mode 100644 index ee23f4de..00000000 --- a/sources/Experiments/SponzaScene/Assets/Shaders/slangdconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "slang.enableCommitCharactersInAutoCompletion": "on" -} diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/10381718147657362067.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/10381718147657362067.jpg deleted file mode 100644 index e49b8b12..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/10381718147657362067.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/10388182081421875623.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/10388182081421875623.jpg deleted file mode 100644 index 254626b4..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/10388182081421875623.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/11474523244911310074.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/11474523244911310074.jpg deleted file mode 100644 index f2cf424e..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/11474523244911310074.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/11490520546946913238.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/11490520546946913238.jpg deleted file mode 100644 index 4174770a..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/11490520546946913238.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/11872827283454512094.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/11872827283454512094.jpg deleted file mode 100644 index fd4136f4..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/11872827283454512094.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/11968150294050148237.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/11968150294050148237.jpg deleted file mode 100644 index db25cc6c..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/11968150294050148237.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/1219024358953944284.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/1219024358953944284.jpg deleted file mode 100644 index 4f3fe654..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/1219024358953944284.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/12501374198249454378.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/12501374198249454378.jpg deleted file mode 100644 index 79276b20..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/12501374198249454378.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/13196865903111448057.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/13196865903111448057.jpg deleted file mode 100644 index cdf1eaee..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/13196865903111448057.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/13824894030729245199.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/13824894030729245199.jpg deleted file mode 100644 index 8410fd77..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/13824894030729245199.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/13982482287905699490.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/13982482287905699490.jpg deleted file mode 100644 index 2c938a4c..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/13982482287905699490.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/14118779221266351425.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/14118779221266351425.jpg deleted file mode 100644 index f385e6b4..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/14118779221266351425.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/14170708867020035030.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/14170708867020035030.jpg deleted file mode 100644 index 51f9d064..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/14170708867020035030.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/14267839433702832875.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/14267839433702832875.jpg deleted file mode 100644 index 5e7b1c37..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/14267839433702832875.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/14650633544276105767.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/14650633544276105767.jpg deleted file mode 100644 index 64e58dc2..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/14650633544276105767.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/15295713303328085182.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/15295713303328085182.jpg deleted file mode 100644 index 80c8b28b..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/15295713303328085182.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/15722799267630235092.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/15722799267630235092.jpg deleted file mode 100644 index 079c22c5..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/15722799267630235092.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/16275776544635328252.png b/sources/Experiments/SponzaScene/Assets/Sponza/16275776544635328252.png deleted file mode 100644 index 987e8d03..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/16275776544635328252.png and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/16299174074766089871.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/16299174074766089871.jpg deleted file mode 100644 index 578484f2..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/16299174074766089871.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/16885566240357350108.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/16885566240357350108.jpg deleted file mode 100644 index 82bd131e..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/16885566240357350108.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/17556969131407844942.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/17556969131407844942.jpg deleted file mode 100644 index 8b7b6ded..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/17556969131407844942.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/17876391417123941155.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/17876391417123941155.jpg deleted file mode 100644 index 662ac2e8..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/17876391417123941155.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/2051777328469649772.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/2051777328469649772.jpg deleted file mode 100644 index 16bdb11d..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/2051777328469649772.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/2185409758123873465.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/2185409758123873465.jpg deleted file mode 100644 index 6740aee7..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/2185409758123873465.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/2299742237651021498.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/2299742237651021498.jpg deleted file mode 100644 index 93e4c860..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/2299742237651021498.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/2374361008830720677.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/2374361008830720677.jpg deleted file mode 100644 index 393a0289..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/2374361008830720677.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/2411100444841994089.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/2411100444841994089.jpg deleted file mode 100644 index e0fe74c0..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/2411100444841994089.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/2775690330959970771.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/2775690330959970771.jpg deleted file mode 100644 index a715d92c..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/2775690330959970771.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/2969916736137545357.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/2969916736137545357.jpg deleted file mode 100644 index d4c22138..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/2969916736137545357.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/332936164838540657.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/332936164838540657.jpg deleted file mode 100644 index 393a0289..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/332936164838540657.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/3371964815757888145.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/3371964815757888145.jpg deleted file mode 100644 index 5d7e2588..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/3371964815757888145.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/3455394979645218238.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/3455394979645218238.jpg deleted file mode 100644 index c91c7956..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/3455394979645218238.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/3628158980083700836.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/3628158980083700836.jpg deleted file mode 100644 index 75884009..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/3628158980083700836.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/3827035219084910048.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/3827035219084910048.jpg deleted file mode 100644 index 0a7b892c..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/3827035219084910048.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/4477655471536070370.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/4477655471536070370.jpg deleted file mode 100644 index 3b463b27..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/4477655471536070370.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/4601176305987539675.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/4601176305987539675.jpg deleted file mode 100644 index 3fca97a4..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/4601176305987539675.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/466164707995436622.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/466164707995436622.jpg deleted file mode 100644 index d65b8f3c..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/466164707995436622.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/4675343432951571524.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/4675343432951571524.jpg deleted file mode 100644 index 14dd8f9e..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/4675343432951571524.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/4871783166746854860.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/4871783166746854860.jpg deleted file mode 100644 index dd777519..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/4871783166746854860.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/4910669866631290573.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/4910669866631290573.jpg deleted file mode 100644 index 3fca97a4..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/4910669866631290573.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/4975155472559461469.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/4975155472559461469.jpg deleted file mode 100644 index 43aee7b9..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/4975155472559461469.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/5061699253647017043.png b/sources/Experiments/SponzaScene/Assets/Sponza/5061699253647017043.png deleted file mode 100644 index 8b690c36..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/5061699253647017043.png and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/5792855332885324923.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/5792855332885324923.jpg deleted file mode 100644 index c965353a..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/5792855332885324923.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/5823059166183034438.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/5823059166183034438.jpg deleted file mode 100644 index 1873401f..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/5823059166183034438.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/6047387724914829168.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/6047387724914829168.jpg deleted file mode 100644 index d9b3ccaa..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/6047387724914829168.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/6151467286084645207.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/6151467286084645207.jpg deleted file mode 100644 index 1714a852..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/6151467286084645207.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/6593109234861095314.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/6593109234861095314.jpg deleted file mode 100644 index 3fca97a4..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/6593109234861095314.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/6667038893015345571.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/6667038893015345571.jpg deleted file mode 100644 index 2a79121d..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/6667038893015345571.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/6772804448157695701.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/6772804448157695701.jpg deleted file mode 100644 index d3619afe..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/6772804448157695701.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/7056944414013900257.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/7056944414013900257.jpg deleted file mode 100644 index 393a0289..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/7056944414013900257.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/715093869573992647.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/715093869573992647.jpg deleted file mode 100644 index e56a2822..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/715093869573992647.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/7268504077753552595.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/7268504077753552595.jpg deleted file mode 100644 index 15a6d7df..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/7268504077753552595.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/7441062115984513793.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/7441062115984513793.jpg deleted file mode 100644 index e571d401..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/7441062115984513793.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/755318871556304029.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/755318871556304029.jpg deleted file mode 100644 index f2afed3c..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/755318871556304029.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/759203620573749278.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/759203620573749278.jpg deleted file mode 100644 index 8a2170c9..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/759203620573749278.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/7645212358685992005.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/7645212358685992005.jpg deleted file mode 100644 index ee067215..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/7645212358685992005.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/7815564343179553343.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/7815564343179553343.jpg deleted file mode 100644 index 11948eee..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/7815564343179553343.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/8006627369776289000.png b/sources/Experiments/SponzaScene/Assets/Sponza/8006627369776289000.png deleted file mode 100644 index ba5f6551..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/8006627369776289000.png and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/8051790464816141987.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/8051790464816141987.jpg deleted file mode 100644 index 6e050152..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/8051790464816141987.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/8114461559286000061.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/8114461559286000061.jpg deleted file mode 100644 index 58be9bce..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/8114461559286000061.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/8481240838833932244.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/8481240838833932244.jpg deleted file mode 100644 index 207a7a6c..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/8481240838833932244.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/8503262930880235456.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/8503262930880235456.jpg deleted file mode 100644 index f3423ebe..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/8503262930880235456.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/8747919177698443163.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/8747919177698443163.jpg deleted file mode 100644 index 3c3d983f..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/8747919177698443163.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/8750083169368950601.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/8750083169368950601.jpg deleted file mode 100644 index 48a46dfc..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/8750083169368950601.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/8773302468495022225.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/8773302468495022225.jpg deleted file mode 100644 index 4647a44e..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/8773302468495022225.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/8783994986360286082.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/8783994986360286082.jpg deleted file mode 100644 index 6839be4a..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/8783994986360286082.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/9288698199695299068.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/9288698199695299068.jpg deleted file mode 100644 index dba904f1..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/9288698199695299068.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/9916269861720640319.jpg b/sources/Experiments/SponzaScene/Assets/Sponza/9916269861720640319.jpg deleted file mode 100644 index bfe9d287..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/9916269861720640319.jpg and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/Sponza.bin b/sources/Experiments/SponzaScene/Assets/Sponza/Sponza.bin deleted file mode 100644 index caa2a36d..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/Sponza.bin and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/Sponza.gltf b/sources/Experiments/SponzaScene/Assets/Sponza/Sponza.gltf deleted file mode 100644 index 02252eba..00000000 --- a/sources/Experiments/SponzaScene/Assets/Sponza/Sponza.gltf +++ /dev/null @@ -1,8573 +0,0 @@ -{ - "asset": { - "generator": "glTF-Transform v1.2.3", - "version": "2.0" - }, - "accessors": [ - { - "type": "SCALAR", - "componentType": 5123, - "count": 10920, - "bufferView": 0, - "byteOffset": 0 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 1404, - "bufferView": 0, - "byteOffset": 21840 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 6633, - "bufferView": 0, - "byteOffset": 24648 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 4086, - "bufferView": 0, - "byteOffset": 37916 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 324, - "bufferView": 0, - "byteOffset": 46088 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 840, - "bufferView": 0, - "byteOffset": 46736 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 6996, - "bufferView": 0, - "byteOffset": 48416 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 4368, - "bufferView": 0, - "byteOffset": 62408 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 8688, - "bufferView": 0, - "byteOffset": 71144 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 48, - "bufferView": 0, - "byteOffset": 88520 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 3288, - "bufferView": 0, - "byteOffset": 88616 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 11040, - "bufferView": 0, - "byteOffset": 95192 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 612, - "bufferView": 0, - "byteOffset": 117272 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 612, - "bufferView": 0, - "byteOffset": 118496 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 444, - "bufferView": 0, - "byteOffset": 119720 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 480, - "bufferView": 0, - "byteOffset": 120608 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 336, - "bufferView": 0, - "byteOffset": 121568 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 480, - "bufferView": 0, - "byteOffset": 122240 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 336, - "bufferView": 0, - "byteOffset": 123200 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 1320, - "bufferView": 0, - "byteOffset": 123872 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 96, - "bufferView": 0, - "byteOffset": 126512 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 162, - "bufferView": 0, - "byteOffset": 126704 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 726, - "bufferView": 0, - "byteOffset": 127028 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 72, - "bufferView": 0, - "byteOffset": 128480 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 246, - "bufferView": 0, - "byteOffset": 128624 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 1668, - "bufferView": 0, - "byteOffset": 129116 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 150, - "bufferView": 0, - "byteOffset": 132452 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 10224, - "bufferView": 0, - "byteOffset": 132752 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 150, - "bufferView": 0, - "byteOffset": 153200 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 15, - "bufferView": 0, - "byteOffset": 153500 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 4080, - "bufferView": 0, - "byteOffset": 153532 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 11208, - "bufferView": 0, - "byteOffset": 161692 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 69624, - "bufferView": 0, - "byteOffset": 184108 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 54, - "bufferView": 0, - "byteOffset": 323356 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 192, - "bufferView": 0, - "byteOffset": 323464 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 16368, - "bufferView": 0, - "byteOffset": 323848 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 83388, - "bufferView": 0, - "byteOffset": 356584 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 16512, - "bufferView": 0, - "byteOffset": 523360 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 33120, - "bufferView": 0, - "byteOffset": 556384 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 14592, - "bufferView": 0, - "byteOffset": 622624 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 13824, - "bufferView": 0, - "byteOffset": 651808 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 24, - "bufferView": 0, - "byteOffset": 679456 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 14871, - "bufferView": 0, - "byteOffset": 679504 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 14871, - "bufferView": 0, - "byteOffset": 709248 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 1200, - "bufferView": 0, - "byteOffset": 738992 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 27552, - "bufferView": 0, - "byteOffset": 741392 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 4563, - "bufferView": 0, - "byteOffset": 796496 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 84, - "bufferView": 0, - "byteOffset": 805624 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 43452, - "bufferView": 0, - "byteOffset": 805792 - }, - { - "type": "SCALAR", - "componentType": 5123, - "count": 30, - "bufferView": 0, - "byteOffset": 892696 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3175, - "max": [ - 540.9965209960938, - 210.9434051513672, - 244.8979949951172 - ], - "min": [ - 449.5628967285156, - 85.37139892578125, - 152.0906982421875 - ], - "bufferView": 1, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 3175, - "bufferView": 2, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3175, - "bufferView": 3, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3175, - "bufferView": 4, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 533, - "max": [ - -209.1302032470703, - 73.12359619140625, - -189.0428009033203 - ], - "min": [ - -277.3555908203125, - 46.08150100708008, - -252.99859619140625 - ], - "bufferView": 5, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 533, - "bufferView": 6, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 533, - "bufferView": 7, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 533, - "bufferView": 8, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "max": [ - -219.32369995117188, - 56.199501037597656, - -198.78799438476562 - ], - "min": [ - -271.2546081542969, - -0.14010000228881836, - -250.77699279785156 - ], - "bufferView": 9, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 1231, - "bufferView": 10, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "bufferView": 11, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1231, - "bufferView": 12, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 753, - "max": [ - -1401.679931640625, - 758.5531005859375, - 85.7051010131836 - ], - "min": [ - -1424.663818359375, - 493.0472106933594, - -163.38650512695312 - ], - "bufferView": 13, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 753, - "bufferView": 14, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 753, - "bufferView": 15, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 753, - "bufferView": 16, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 128, - "max": [ - 914.80078125, - 495.6896057128906, - 238.67950439453125 - ], - "min": [ - -1045.740966796875, - 221.48770141601562, - -310.1346130371094 - ], - "bufferView": 17, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 128, - "bufferView": 18, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 128, - "bufferView": 19, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 128, - "bufferView": 20, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 560, - "max": [ - 917.6837158203125, - 507.8031921386719, - 243.55810546875 - ], - "min": [ - -1048.3079833984375, - 492.9888000488281, - -318.1059875488281 - ], - "bufferView": 21, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 560, - "bufferView": 22, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 560, - "bufferView": 23, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 560, - "bufferView": 24, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1864, - "max": [ - 1302.20166015625, - 383.9880065917969, - 574.9027099609375 - ], - "min": [ - -1429.452392578125, - 215.80360412597656, - -645.1483154296875 - ], - "bufferView": 25, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 1864, - "bufferView": 26, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1864, - "bufferView": 27, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1864, - "bufferView": 28, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1708, - "max": [ - 528.9411010742188, - 220.99710083007812, - 244.57009887695312 - ], - "min": [ - -658.5947875976562, - -2.460700035095215, - -316.86920166015625 - ], - "bufferView": 29, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 1708, - "bufferView": 30, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1708, - "bufferView": 31, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1708, - "bufferView": 32, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3192, - "max": [ - 912.8480834960938, - 410.4053039550781, - 233.32640075683594 - ], - "min": [ - -1041.22900390625, - 211.39549255371094, - -305.53790283203125 - ], - "bufferView": 33, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 3192, - "bufferView": 34, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3192, - "bufferView": 35, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3192, - "bufferView": 36, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "max": [ - 1302.220947265625, - 415.5303039550781, - 574.1851806640625 - ], - "min": [ - -1432.224365234375, - 415.5303039550781, - -645.4310302734375 - ], - "bufferView": 37, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 16, - "bufferView": 38, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "bufferView": 39, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 16, - "bufferView": 40, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1864, - "max": [ - 1302.20166015625, - 862.651611328125, - 574.9027099609375 - ], - "min": [ - -1429.452392578125, - 694.46728515625, - -645.1483154296875 - ], - "bufferView": 41, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1864, - "bufferView": 42, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1864, - "bufferView": 43, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1172, - "max": [ - 897.2501220703125, - 820.1328125, - 171.45469665527344 - ], - "min": [ - -1029.183349609375, - 695.7373046875, - -241.11900329589844 - ], - "bufferView": 44, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 1172, - "bufferView": 45, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1172, - "bufferView": 46, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1172, - "bufferView": 47, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 6368, - "max": [ - 917.5026245117188, - 695.3228149414062, - 243.35009765625 - ], - "min": [ - -1046.2919921875, - 507.1398010253906, - -315.4476013183594 - ], - "bufferView": 48, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 6368, - "bufferView": 49, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 6368, - "bufferView": 50, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 6368, - "bufferView": 51, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 216, - "max": [ - 868.647216796875, - 921.728515625, - 185.96730041503906 - ], - "min": [ - -1002.363525390625, - 693.7667846679688, - -259.3258056640625 - ], - "bufferView": 52, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 216, - "bufferView": 53, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 216, - "bufferView": 54, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 216, - "bufferView": 55, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 212, - "max": [ - 892.6567993164062, - 921.728515625, - 225.29530334472656 - ], - "min": [ - -1022.56689453125, - 693.7667846679688, - -295.4941101074219 - ], - "bufferView": 56, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 212, - "bufferView": 57, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 212, - "bufferView": 58, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 212, - "bufferView": 59, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 138, - "max": [ - 868.5941772460938, - 1296.710693359375, - 181.2987060546875 - ], - "min": [ - -1002.3765258789062, - 921.728515625, - -253.54859924316406 - ], - "bufferView": 60, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 138, - "bufferView": 61, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 138, - "bufferView": 62, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 138, - "bufferView": 63, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "max": [ - 535.96142578125, - 1273.487548828125, - -243.13319396972656 - ], - "min": [ - 478.494384765625, - 1215.901611328125, - -263.6247863769531 - ], - "bufferView": 64, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 126, - "bufferView": 65, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "bufferView": 66, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 126, - "bufferView": 67, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "max": [ - 524.9011840820312, - 1262.404296875, - -255.96710205078125 - ], - "min": [ - 489.55450439453125, - 1226.984619140625, - -271.4642028808594 - ], - "bufferView": 68, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 122, - "bufferView": 69, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "bufferView": 70, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 122, - "bufferView": 71, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "max": [ - 165.83509826660156, - 1273.487548828125, - -243.13319396972656 - ], - "min": [ - 108.36810302734375, - 1215.901611328125, - -263.6247863769531 - ], - "bufferView": 72, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "bufferView": 73, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 126, - "bufferView": 74, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "max": [ - 154.77490234375, - 1262.404296875, - -255.96710205078125 - ], - "min": [ - 119.4281997680664, - 1226.984619140625, - -271.4642028808594 - ], - "bufferView": 75, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "bufferView": 76, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 122, - "bufferView": 77, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "max": [ - -235.86529541015625, - 1273.487548828125, - -243.13319396972656 - ], - "min": [ - -293.3323059082031, - 1215.901611328125, - -263.6247863769531 - ], - "bufferView": 78, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "bufferView": 79, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 126, - "bufferView": 80, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "max": [ - -246.92550659179688, - 1262.404296875, - -255.96710205078125 - ], - "min": [ - -282.2721862792969, - 1226.984619140625, - -271.4642028808594 - ], - "bufferView": 81, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "bufferView": 82, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 122, - "bufferView": 83, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "max": [ - -606.0911254882812, - 1273.487548828125, - -243.13319396972656 - ], - "min": [ - -663.55810546875, - 1215.901611328125, - -263.6247863769531 - ], - "bufferView": 84, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "bufferView": 85, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 126, - "bufferView": 86, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "max": [ - -617.1514282226562, - 1262.404296875, - -255.96710205078125 - ], - "min": [ - -652.4979248046875, - 1226.984619140625, - -271.4642028808594 - ], - "bufferView": 87, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "bufferView": 88, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 122, - "bufferView": 89, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "max": [ - -992.115478515625, - 1275.01123046875, - -6.238100051879883 - ], - "min": [ - -1012.607177734375, - 1217.42529296875, - -63.70500183105469 - ], - "bufferView": 90, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 126, - "bufferView": 91, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "bufferView": 92, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 126, - "bufferView": 93, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "max": [ - -1004.9495239257812, - 1263.927978515625, - -17.29829978942871 - ], - "min": [ - -1020.4464721679688, - 1228.50830078125, - -52.64500045776367 - ], - "bufferView": 94, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 122, - "bufferView": 95, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "bufferView": 96, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 122, - "bufferView": 97, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "max": [ - 535.96142578125, - 1273.487548828125, - 189.92849731445312 - ], - "min": [ - 478.494384765625, - 1215.901611328125, - 169.43699645996094 - ], - "bufferView": 98, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "bufferView": 99, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 126, - "bufferView": 100, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "max": [ - 524.9011840820312, - 1262.404296875, - 197.76800537109375 - ], - "min": [ - 489.55450439453125, - 1226.984619140625, - 182.27090454101562 - ], - "bufferView": 101, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "bufferView": 102, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 122, - "bufferView": 103, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "max": [ - 165.83509826660156, - 1273.487548828125, - 189.92849731445312 - ], - "min": [ - 108.36810302734375, - 1215.901611328125, - 169.43699645996094 - ], - "bufferView": 104, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "bufferView": 105, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 126, - "bufferView": 106, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "max": [ - 154.77490234375, - 1262.404296875, - 197.76800537109375 - ], - "min": [ - 119.4281997680664, - 1226.984619140625, - 182.27090454101562 - ], - "bufferView": 107, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "bufferView": 108, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 122, - "bufferView": 109, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "max": [ - -235.86529541015625, - 1273.487548828125, - 189.92849731445312 - ], - "min": [ - -293.3323059082031, - 1215.901611328125, - 169.43699645996094 - ], - "bufferView": 110, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "bufferView": 111, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 126, - "bufferView": 112, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "max": [ - -246.92550659179688, - 1262.404296875, - 197.7678985595703 - ], - "min": [ - -282.2721862792969, - 1226.984619140625, - 182.27090454101562 - ], - "bufferView": 113, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "bufferView": 114, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 122, - "bufferView": 115, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "max": [ - -606.0911254882812, - 1273.487548828125, - 189.92849731445312 - ], - "min": [ - -663.55810546875, - 1215.901611328125, - 169.43699645996094 - ], - "bufferView": 116, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 126, - "bufferView": 117, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 126, - "bufferView": 118, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "max": [ - -617.1514282226562, - 1262.404296875, - 197.7678985595703 - ], - "min": [ - -652.4979858398438, - 1226.984619140625, - 182.27090454101562 - ], - "bufferView": 119, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 122, - "bufferView": 120, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 122, - "bufferView": 121, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 880, - "max": [ - 721.81982421875, - 1014.4711303710938, - 202.78709411621094 - ], - "min": [ - -1030.053955078125, - 921.728515625, - -274.7777099609375 - ], - "bufferView": 122, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 880, - "bufferView": 123, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 880, - "bufferView": 124, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 880, - "bufferView": 125, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 56, - "max": [ - 997.59619140625, - 1314.490234375, - 318.9007873535156 - ], - "min": [ - -1086.4228515625, - 907.7440795898438, - -408.14678955078125 - ], - "bufferView": 126, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 56, - "bufferView": 127, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 56, - "bufferView": 128, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 56, - "bufferView": 129, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 560, - "max": [ - 917.6837158203125, - 930.2659301757812, - 243.55810546875 - ], - "min": [ - -1048.3079833984375, - 915.451416015625, - -318.1059875488281 - ], - "bufferView": 130, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 560, - "bufferView": 131, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 560, - "bufferView": 132, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 66, - "max": [ - 1302.2208251953125, - 867.3870849609375, - 574.7061767578125 - ], - "min": [ - -1431.199951171875, - -2.6201000213623047, - -644.3114013671875 - ], - "bufferView": 133, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 66, - "bufferView": 134, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 66, - "bufferView": 135, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 66, - "bufferView": 136, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 314, - "max": [ - 41.11109924316406, - 289.3175048828125, - 605.0136108398438 - ], - "min": [ - -509.68328857421875, - -2.1349000930786133, - 554.269775390625 - ], - "bufferView": 137, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 314, - "bufferView": 138, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 314, - "bufferView": 139, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 314, - "bufferView": 140, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 48, - "max": [ - -357.1275939941406, - 289.3175048828125, - 583.672119140625 - ], - "min": [ - -509.6835021972656, - 119.80509948730469, - 573.1038818359375 - ], - "bufferView": 141, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 48, - "bufferView": 142, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 48, - "bufferView": 143, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 48, - "bufferView": 144, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 98, - "max": [ - 384.1211853027344, - 289.3175964355469, - 589.7529296875 - ], - "min": [ - 231.56539916992188, - 119.80509948730469, - 573.10400390625 - ], - "bufferView": 145, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 98, - "bufferView": 146, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 98, - "bufferView": 147, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 98, - "bufferView": 148, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 48, - "max": [ - 384.1213073730469, - 289.3175964355469, - 583.6721801757812 - ], - "min": [ - 231.56539916992188, - 119.80509948730469, - 573.10400390625 - ], - "bufferView": 149, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 48, - "bufferView": 150, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 688, - "max": [ - 1315.5244140625, - 716.8505859375, - 42.59199905395508 - ], - "min": [ - -140.4468994140625, - -2.2155001163482666, - -651.5385131835938 - ], - "bufferView": 151, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 688, - "bufferView": 152, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 688, - "bufferView": 153, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 688, - "bufferView": 154, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 92, - "max": [ - 1302.190673828125, - 424.4659118652344, - 575.3004150390625 - ], - "min": [ - -1431.898681640625, - 415.4613952636719, - -641.6024169921875 - ], - "bufferView": 155, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 92, - "bufferView": 156, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 92, - "bufferView": 157, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 92, - "bufferView": 158, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 5904, - "max": [ - 1303.27197265625, - 695.3226928710938, - 575.7255249023438 - ], - "min": [ - -1430.30517578125, - 182.6522979736328, - -646.9678955078125 - ], - "bufferView": 159, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 5904, - "bufferView": 160, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 5904, - "bufferView": 161, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 5904, - "bufferView": 162, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 92, - "max": [ - 1302.1905517578125, - 5.625100135803223, - 574.0297241210938 - ], - "min": [ - -1428.519775390625, - -3.3794000148773193, - -644.3114013671875 - ], - "bufferView": 163, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 92, - "bufferView": 164, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 92, - "bufferView": 165, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 92, - "bufferView": 166, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 7, - "max": [ - 1302.1905517578125, - -2.506200075149536, - 574.0297241210938 - ], - "min": [ - -1428.519775390625, - -2.506200075149536, - -644.3114013671875 - ], - "bufferView": 167, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 7, - "bufferView": 168, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 7, - "bufferView": 169, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 7, - "bufferView": 170, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1824, - "max": [ - 925.6038208007812, - 220.99710083007812, - 246.61489868164062 - ], - "min": [ - -1057.22021484375, - -2.460700035095215, - -316.86920166015625 - ], - "bufferView": 171, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 1824, - "bufferView": 172, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1824, - "bufferView": 173, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1824, - "bufferView": 174, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3764, - "max": [ - 921.9354858398438, - 823.3441772460938, - 245.81419372558594 - ], - "min": [ - -1052.875732421875, - 413.9111022949219, - -317.269287109375 - ], - "bufferView": 175, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 3764, - "bufferView": 176, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3764, - "bufferView": 177, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3764, - "bufferView": 178, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 23038, - "max": [ - 907.4069213867188, - 699.61181640625, - 234.77340698242188 - ], - "min": [ - -1037.651611328125, - 506.6332092285156, - -309.70550537109375 - ], - "bufferView": 179, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 23038, - "bufferView": 180, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 23038, - "bufferView": 181, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 23038, - "bufferView": 182, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 36, - "max": [ - -8.262900352478027, - 348.1973876953125, - 575.5051879882812 - ], - "min": [ - -119.40730285644531, - 256.7309875488281, - 568.6583862304688 - ], - "bufferView": 183, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 36, - "bufferView": 184, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 36, - "bufferView": 185, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 120, - "max": [ - 997.59619140625, - 1330.769287109375, - 318.9007873535156 - ], - "min": [ - -1086.4228515625, - 907.7440795898438, - -408.14678955078125 - ], - "bufferView": 186, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 120, - "bufferView": 187, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 120, - "bufferView": 188, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 120, - "bufferView": 189, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3952, - "max": [ - 503.1986083984375, - 886.1389770507812, - 199.3907012939453 - ], - "min": [ - -628.6536254882812, - 828.8109130859375, - -270.8304138183594 - ], - "bufferView": 190, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 3952, - "bufferView": 191, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3952, - "bufferView": 192, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3952, - "bufferView": 193, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 20987, - "max": [ - 551.2263793945312, - 225.1020965576172, - 266.4422912597656 - ], - "min": [ - -680.2642211914062, - -28.04960060119629, - -341.1361999511719 - ], - "bufferView": 194, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 20987, - "bufferView": 195, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 20987, - "bufferView": 196, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 20987, - "bufferView": 197, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "max": [ - -453.8620910644531, - 520.5938720703125, - 252.28579711914062 - ], - "min": [ - -783.794189453125, - 339.4429931640625, - 157.164306640625 - ], - "bufferView": 198, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 3260, - "bufferView": 199, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "bufferView": 200, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3260, - "bufferView": 201, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "max": [ - -85.25599670410156, - 520.5938720703125, - 252.28570556640625 - ], - "min": [ - -415.18798828125, - 339.4429931640625, - 157.16419982910156 - ], - "bufferView": 202, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "bufferView": 203, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3260, - "bufferView": 204, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "max": [ - 283.3501892089844, - 520.5938720703125, - 252.2855987548828 - ], - "min": [ - -46.58190155029297, - 339.4429931640625, - 157.16419982910156 - ], - "bufferView": 205, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "bufferView": 206, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3260, - "bufferView": 207, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "max": [ - 651.9561767578125, - 520.5938720703125, - 252.2855987548828 - ], - "min": [ - 322.0242004394531, - 339.4429931640625, - 157.16409301757812 - ], - "bufferView": 208, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "bufferView": 209, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3260, - "bufferView": 210, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "max": [ - 648.8516845703125, - 520.5938720703125, - -229.40480041503906 - ], - "min": [ - 318.9197082519531, - 339.4429931640625, - -324.5262145996094 - ], - "bufferView": 211, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "bufferView": 212, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3260, - "bufferView": 213, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "max": [ - 280.24560546875, - 520.5938720703125, - -229.40480041503906 - ], - "min": [ - -49.6864013671875, - 339.4429931640625, - -324.5262145996094 - ], - "bufferView": 214, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "bufferView": 215, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3260, - "bufferView": 216, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "max": [ - -88.3604965209961, - 520.5938720703125, - -229.40480041503906 - ], - "min": [ - -418.2926025390625, - 339.4429931640625, - -324.5262145996094 - ], - "bufferView": 217, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "bufferView": 218, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3260, - "bufferView": 219, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "max": [ - -456.96661376953125, - 520.5938720703125, - -229.40480041503906 - ], - "min": [ - -786.898681640625, - 339.4429931640625, - -324.5262145996094 - ], - "bufferView": 220, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 3260, - "bufferView": 221, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 3260, - "bufferView": 222, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 8340, - "max": [ - 830.2938842773438, - 294.114013671875, - 209.11500549316406 - ], - "min": [ - -958.6978149414062, - 274.9595947265625, - -289.70361328125 - ], - "bufferView": 223, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 8340, - "bufferView": 224, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 8340, - "bufferView": 225, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 8340, - "bufferView": 226, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "max": [ - 82.35980224609375, - 283.0152893066406, - 213.4824981689453 - ], - "min": [ - -204.93739318847656, - 0.13050000369548798, - 188.90179443359375 - ], - "bufferView": 227, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 2615, - "bufferView": 228, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "bufferView": 229, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2615, - "bufferView": 230, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2509, - "max": [ - -290.5769958496094, - 283.6809997558594, - 208.21240234375 - ], - "min": [ - -577.6201782226562, - -0.30889999866485596, - 182.904296875 - ], - "bufferView": 231, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 2509, - "bufferView": 232, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2509, - "bufferView": 233, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2509, - "bufferView": 234, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "max": [ - -658.940673828125, - 283.0152893066406, - 213.4824981689453 - ], - "min": [ - -946.2379150390625, - 0.13050000369548798, - 188.90179443359375 - ], - "bufferView": 235, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "bufferView": 236, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2615, - "bufferView": 237, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "max": [ - -658.940673828125, - 283.0152893066406, - -264.67620849609375 - ], - "min": [ - -946.2379150390625, - 0.13050000369548798, - -289.25689697265625 - ], - "bufferView": 238, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "bufferView": 239, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2615, - "bufferView": 240, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2509, - "max": [ - 448.0338134765625, - 283.6809997558594, - 208.21240234375 - ], - "min": [ - 160.99049377441406, - -0.30889999866485596, - 182.904296875 - ], - "bufferView": 241, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2509, - "bufferView": 242, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2509, - "bufferView": 243, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "max": [ - 820.1740112304688, - 283.0152893066406, - 213.4824981689453 - ], - "min": [ - 532.8767700195312, - 0.13050000369548798, - 188.90179443359375 - ], - "bufferView": 244, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2615, - "bufferView": 245, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2509, - "max": [ - -290.5769958496094, - 283.6809997558594, - -269.9462890625 - ], - "min": [ - -577.6201782226562, - -0.30889999866485596, - -295.25439453125 - ], - "bufferView": 246, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2509, - "bufferView": 247, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2509, - "bufferView": 248, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "max": [ - 82.35980224609375, - 283.0152893066406, - -264.67620849609375 - ], - "min": [ - -204.93739318847656, - 0.13050000369548798, - -289.25689697265625 - ], - "bufferView": 249, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "bufferView": 250, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2615, - "bufferView": 251, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2509, - "max": [ - 448.0338134765625, - 283.6809997558594, - -269.9462890625 - ], - "min": [ - 160.99049377441406, - -0.30889999866485596, - -295.25439453125 - ], - "bufferView": 252, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2509, - "bufferView": 253, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2509, - "bufferView": 254, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2615, - "max": [ - 820.1740112304688, - 283.0152893066406, - -264.67620849609375 - ], - "min": [ - 532.8767700195312, - 0.13050000369548798, - -289.25689697265625 - ], - "bufferView": 255, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2615, - "bufferView": 256, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "max": [ - 513.3057250976562, - 214.3549041748047, - -217.91380310058594 - ], - "min": [ - 461.90301513671875, - 133.72129821777344, - -221.48719787597656 - ], - "bufferView": 257, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 16, - "bufferView": 258, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "bufferView": 259, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 16, - "bufferView": 260, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2957, - "max": [ - 522.6115112304688, - 216.9512939453125, - -194.3249969482422 - ], - "min": [ - 452.6521911621094, - 98.67289733886719, - -246.83450317382812 - ], - "bufferView": 261, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 2957, - "bufferView": 262, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2957, - "bufferView": 263, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2957, - "bufferView": 264, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "max": [ - -593.5302734375, - 214.3549041748047, - -217.91380310058594 - ], - "min": [ - -644.93310546875, - 133.72129821777344, - -221.48719787597656 - ], - "bufferView": 265, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "bufferView": 266, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 16, - "bufferView": 267, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2957, - "max": [ - -584.224609375, - 216.9512939453125, - -194.3249969482422 - ], - "min": [ - -654.1837768554688, - 98.67289733886719, - -246.83450317382812 - ], - "bufferView": 268, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 2957, - "bufferView": 269, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2957, - "bufferView": 270, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2957, - "bufferView": 271, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "max": [ - -593.4752807617188, - 214.3549041748047, - 145.12840270996094 - ], - "min": [ - -644.8781127929688, - 133.72129821777344, - 141.55499267578125 - ], - "bufferView": 272, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "bufferView": 273, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 16, - "bufferView": 274, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2957, - "max": [ - -584.2244262695312, - 216.9512939453125, - 170.47579956054688 - ], - "min": [ - -654.1837768554688, - 98.67289733886719, - 117.96620178222656 - ], - "bufferView": 275, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2957, - "bufferView": 276, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2957, - "bufferView": 277, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "max": [ - 513.3607788085938, - 214.3549041748047, - 145.1282958984375 - ], - "min": [ - 461.9580078125, - 133.72129821777344, - 141.55479431152344 - ], - "bufferView": 278, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 16, - "bufferView": 279, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 16, - "bufferView": 280, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2957, - "max": [ - 522.611572265625, - 216.9512939453125, - 170.47560119628906 - ], - "min": [ - 452.6523132324219, - 98.67289733886719, - 117.96600341796875 - ], - "bufferView": 281, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 2957, - "bufferView": 282, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 2957, - "bufferView": 283, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 533, - "max": [ - -929.0048217773438, - 73.12359619140625, - -193.6112060546875 - ], - "min": [ - -992.9603881835938, - 46.08150100708008, - -261.83648681640625 - ], - "bufferView": 284, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 533, - "bufferView": 285, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 533, - "bufferView": 286, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "max": [ - -938.7498779296875, - 56.199501037597656, - -199.7122039794922 - ], - "min": [ - -990.7388916015625, - -0.14010000228881836, - -251.64309692382812 - ], - "bufferView": 287, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "bufferView": 288, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1231, - "bufferView": 289, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 533, - "max": [ - -929.0048217773438, - 69.36119842529297, - 183.283203125 - ], - "min": [ - -992.9603881835938, - 42.31909942626953, - 115.05789947509766 - ], - "bufferView": 290, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 533, - "bufferView": 291, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 533, - "bufferView": 292, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "max": [ - -938.7498779296875, - 52.43709945678711, - 177.1822052001953 - ], - "min": [ - -990.7388916015625, - -3.9024999141693115, - 125.25129699707031 - ], - "bufferView": 293, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "bufferView": 294, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1231, - "bufferView": 295, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 533, - "max": [ - -209.1302032470703, - 69.36119842529297, - 187.85159301757812 - ], - "min": [ - -277.3555908203125, - 42.31909942626953, - 123.89579772949219 - ], - "bufferView": 296, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 533, - "bufferView": 297, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 533, - "bufferView": 298, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "max": [ - -219.32369995117188, - 52.43709945678711, - 178.1063995361328 - ], - "min": [ - -271.2546081542969, - -3.9024999141693115, - 126.11740112304688 - ], - "bufferView": 299, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "bufferView": 300, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1231, - "bufferView": 301, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 450, - "max": [ - 147.3343963623047, - 67.06770324707031, - 183.33749389648438 - ], - "min": [ - 91.80699920654297, - 43.87229919433594, - 126.15380096435547 - ], - "bufferView": 302, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 450, - "bufferView": 303, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 450, - "bufferView": 304, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 450, - "bufferView": 305, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "max": [ - 144.7440948486328, - 52.30889892578125, - 179.31080627441406 - ], - "min": [ - 92.75509643554688, - -4.030700206756592, - 127.37989807128906 - ], - "bufferView": 306, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "bufferView": 307, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1231, - "bufferView": 308, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 450, - "max": [ - 861.8858032226562, - 67.61940002441406, - 183.33749389648438 - ], - "min": [ - 806.3583984375, - 44.42399978637695, - 126.15380096435547 - ], - "bufferView": 309, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 450, - "bufferView": 310, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 450, - "bufferView": 311, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "max": [ - 859.2954711914062, - 52.860599517822266, - 179.31080627441406 - ], - "min": [ - 807.3065185546875, - -3.4790000915527344, - 127.37989807128906 - ], - "bufferView": 312, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "bufferView": 313, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1231, - "bufferView": 314, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 450, - "max": [ - 861.8858032226562, - 70.95819854736328, - -193.55690002441406 - ], - "min": [ - 806.3583984375, - 47.762901306152344, - -250.7406005859375 - ], - "bufferView": 315, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 450, - "bufferView": 316, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 450, - "bufferView": 317, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "max": [ - 859.2954711914062, - 56.199501037597656, - -197.58360290527344 - ], - "min": [ - 807.3065185546875, - -0.14010000228881836, - -249.51449584960938 - ], - "bufferView": 318, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "bufferView": 319, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1231, - "bufferView": 320, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 450, - "max": [ - 147.3343963623047, - 70.95819854736328, - -193.55690002441406 - ], - "min": [ - 91.80699920654297, - 47.762901306152344, - -250.7406005859375 - ], - "bufferView": 321, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 450, - "bufferView": 322, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 450, - "bufferView": 323, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "max": [ - 144.7440948486328, - 56.199501037597656, - -197.58360290527344 - ], - "min": [ - 92.75509643554688, - -0.14010000228881836, - -249.51449584960938 - ], - "bufferView": 324, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 1231, - "bufferView": 325, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 1231, - "bufferView": 326, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 5308, - "max": [ - 1194.1705322265625, - 133.0167999267578, - 478.2618103027344 - ], - "min": [ - -1276.67333984375, - -0.6934000253677368, - -523.4995727539062 - ], - "bufferView": 327, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 5308, - "bufferView": 328, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 5308, - "bufferView": 329, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 5308, - "bufferView": 330, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 866, - "max": [ - 1299.0263671875, - 264.7611999511719, - 41.46760177612305 - ], - "min": [ - 1224.04833984375, - 79.90480041503906, - -114.69149780273438 - ], - "bufferView": 331, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 866, - "bufferView": 332, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 866, - "bufferView": 333, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 866, - "bufferView": 334, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 753, - "max": [ - 1299.8668212890625, - 306.3245849609375, - 88.62660217285156 - ], - "min": [ - 1277.022705078125, - 40.818599700927734, - -160.46499633789062 - ], - "bufferView": 335, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 753, - "bufferView": 336, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 753, - "bufferView": 337, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 866, - "max": [ - -1352.456298828125, - 264.7611999511719, - 42.85340118408203 - ], - "min": [ - -1427.434326171875, - 79.90480041503906, - -113.30570220947266 - ], - "bufferView": 338, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 866, - "bufferView": 339, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 866, - "bufferView": 340, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 753, - "max": [ - -1405.4306640625, - 306.3245849609375, - 88.62689971923828 - ], - "min": [ - -1428.27490234375, - 40.818599700927734, - -160.464599609375 - ], - "bufferView": 341, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 753, - "bufferView": 342, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 753, - "bufferView": 343, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 50, - "max": [ - 1746.69287109375, - 1347.19580078125, - 1039.711181640625 - ], - "min": [ - -1866.98291015625, - -126.44249725341797, - -1139.030517578125 - ], - "bufferView": 344, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 50, - "bufferView": 345, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 50, - "bufferView": 346, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 50, - "bufferView": 347, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 11890, - "max": [ - 1799.9080810546875, - 1429.4332275390625, - 1105.426025390625 - ], - "min": [ - -1920.9459228515625, - 1280.513427734375, - -1182.80712890625 - ], - "bufferView": 348, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 11890, - "bufferView": 349, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 11890, - "bufferView": 350, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 11890, - "bufferView": 351, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 20, - "max": [ - 1380.6033935546875, - 1271.037109375, - 674.7567749023438 - ], - "min": [ - -1504.46826171875, - -115.9791030883789, - -782.5203247070312 - ], - "bufferView": 352, - "byteOffset": 0 - }, - { - "type": "VEC2", - "componentType": 5126, - "count": 20, - "bufferView": 353, - "byteOffset": 0 - }, - { - "type": "VEC3", - "componentType": 5126, - "count": 20, - "bufferView": 354, - "byteOffset": 0 - }, - { - "type": "VEC4", - "componentType": 5126, - "count": 20, - "bufferView": 355, - "byteOffset": 0 - } - ], - "bufferViews": [ - { - "buffer": 0, - "byteOffset": 0, - "byteLength": 892756, - "target": 34963 - }, - { - "buffer": 0, - "byteOffset": 892756, - "byteLength": 38100, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 930856, - "byteLength": 25400, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 956256, - "byteLength": 38100, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 994356, - "byteLength": 50800, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1045156, - "byteLength": 6396, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1051552, - "byteLength": 4264, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1055816, - "byteLength": 6396, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1062212, - "byteLength": 8528, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1070740, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1085512, - "byteLength": 9848, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1095360, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1110132, - "byteLength": 19696, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1129828, - "byteLength": 9036, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1138864, - "byteLength": 6024, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1144888, - "byteLength": 9036, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1153924, - "byteLength": 12048, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1165972, - "byteLength": 1536, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1167508, - "byteLength": 1024, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1168532, - "byteLength": 1536, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1170068, - "byteLength": 2048, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1172116, - "byteLength": 6720, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1178836, - "byteLength": 4480, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1183316, - "byteLength": 6720, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1190036, - "byteLength": 8960, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1198996, - "byteLength": 22368, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1221364, - "byteLength": 14912, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1236276, - "byteLength": 22368, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1258644, - "byteLength": 29824, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1288468, - "byteLength": 20496, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1308964, - "byteLength": 13664, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1322628, - "byteLength": 20496, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1343124, - "byteLength": 27328, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1370452, - "byteLength": 38304, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1408756, - "byteLength": 25536, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1434292, - "byteLength": 38304, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1472596, - "byteLength": 51072, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1523668, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1523860, - "byteLength": 128, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1523988, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1524180, - "byteLength": 256, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1524436, - "byteLength": 22368, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1546804, - "byteLength": 22368, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1569172, - "byteLength": 29824, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1598996, - "byteLength": 14064, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1613060, - "byteLength": 9376, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1622436, - "byteLength": 14064, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1636500, - "byteLength": 18752, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1655252, - "byteLength": 76416, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1731668, - "byteLength": 50944, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1782612, - "byteLength": 76416, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1859028, - "byteLength": 101888, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1960916, - "byteLength": 2592, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1963508, - "byteLength": 1728, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1965236, - "byteLength": 2592, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1967828, - "byteLength": 3456, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1971284, - "byteLength": 2544, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1973828, - "byteLength": 1696, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1975524, - "byteLength": 2544, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1978068, - "byteLength": 3392, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1981460, - "byteLength": 1656, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1983116, - "byteLength": 1104, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1984220, - "byteLength": 1656, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1985876, - "byteLength": 2208, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1988084, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1989596, - "byteLength": 1008, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1990604, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1992116, - "byteLength": 2016, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1994132, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1995596, - "byteLength": 976, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1996572, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1998036, - "byteLength": 1952, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 1999988, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2001500, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2003012, - "byteLength": 2016, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2005028, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2006492, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2007956, - "byteLength": 1952, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2009908, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2011420, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2012932, - "byteLength": 2016, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2014948, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2016412, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2017876, - "byteLength": 1952, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2019828, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2021340, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2022852, - "byteLength": 2016, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2024868, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2026332, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2027796, - "byteLength": 1952, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2029748, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2031260, - "byteLength": 1008, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2032268, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2033780, - "byteLength": 2016, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2035796, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2037260, - "byteLength": 976, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2038236, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2039700, - "byteLength": 1952, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2041652, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2043164, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2044676, - "byteLength": 2016, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2046692, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2048156, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2049620, - "byteLength": 1952, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2051572, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2053084, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2054596, - "byteLength": 2016, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2056612, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2058076, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2059540, - "byteLength": 1952, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2061492, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2063004, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2064516, - "byteLength": 2016, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2066532, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2067996, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2069460, - "byteLength": 1952, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2071412, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2072924, - "byteLength": 1512, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2074436, - "byteLength": 2016, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2076452, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2077916, - "byteLength": 1464, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2079380, - "byteLength": 1952, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2081332, - "byteLength": 10560, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2091892, - "byteLength": 7040, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2098932, - "byteLength": 10560, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2109492, - "byteLength": 14080, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2123572, - "byteLength": 672, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2124244, - "byteLength": 448, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2124692, - "byteLength": 672, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2125364, - "byteLength": 896, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2126260, - "byteLength": 6720, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2132980, - "byteLength": 6720, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2139700, - "byteLength": 8960, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2148660, - "byteLength": 792, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2149452, - "byteLength": 528, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2149980, - "byteLength": 792, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2150772, - "byteLength": 1056, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2151828, - "byteLength": 3768, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2155596, - "byteLength": 2512, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2158108, - "byteLength": 3768, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2161876, - "byteLength": 5024, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2166900, - "byteLength": 576, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2167476, - "byteLength": 384, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2167860, - "byteLength": 576, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2168436, - "byteLength": 768, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2169204, - "byteLength": 1176, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2170380, - "byteLength": 784, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2171164, - "byteLength": 1176, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2172340, - "byteLength": 1568, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2173908, - "byteLength": 576, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2174484, - "byteLength": 576, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2175060, - "byteLength": 8256, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2183316, - "byteLength": 5504, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2188820, - "byteLength": 8256, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2197076, - "byteLength": 11008, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2208084, - "byteLength": 1104, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2209188, - "byteLength": 736, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2209924, - "byteLength": 1104, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2211028, - "byteLength": 1472, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2212500, - "byteLength": 70848, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2283348, - "byteLength": 47232, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2330580, - "byteLength": 70848, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2401428, - "byteLength": 94464, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2495892, - "byteLength": 1104, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2496996, - "byteLength": 736, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2497732, - "byteLength": 1104, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2498836, - "byteLength": 1472, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2500308, - "byteLength": 84, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2500392, - "byteLength": 56, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2500448, - "byteLength": 84, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2500532, - "byteLength": 112, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2500644, - "byteLength": 21888, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2522532, - "byteLength": 14592, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2537124, - "byteLength": 21888, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2559012, - "byteLength": 29184, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2588196, - "byteLength": 45168, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2633364, - "byteLength": 30112, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2663476, - "byteLength": 45168, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2708644, - "byteLength": 60224, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 2768868, - "byteLength": 276456, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3045324, - "byteLength": 184304, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3229628, - "byteLength": 276456, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3506084, - "byteLength": 368608, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3874692, - "byteLength": 432, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3875124, - "byteLength": 288, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3875412, - "byteLength": 432, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3875844, - "byteLength": 1440, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3877284, - "byteLength": 960, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3878244, - "byteLength": 1440, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3879684, - "byteLength": 1920, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3881604, - "byteLength": 47424, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3929028, - "byteLength": 31616, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 3960644, - "byteLength": 47424, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 4008068, - "byteLength": 63232, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 4071300, - "byteLength": 251844, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 4323144, - "byteLength": 167896, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 4491040, - "byteLength": 251844, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 4742884, - "byteLength": 335792, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5078676, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5117796, - "byteLength": 26080, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5143876, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5182996, - "byteLength": 52160, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5235156, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5274276, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5313396, - "byteLength": 52160, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5365556, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5404676, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5443796, - "byteLength": 52160, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5495956, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5535076, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5574196, - "byteLength": 52160, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5626356, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5665476, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5704596, - "byteLength": 52160, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5756756, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5795876, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5834996, - "byteLength": 52160, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5887156, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5926276, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 5965396, - "byteLength": 52160, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6017556, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6056676, - "byteLength": 39120, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6095796, - "byteLength": 52160, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6147956, - "byteLength": 100080, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6248036, - "byteLength": 66720, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6314756, - "byteLength": 100080, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6414836, - "byteLength": 133440, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6548276, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6579656, - "byteLength": 20920, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6600576, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6631956, - "byteLength": 41840, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6673796, - "byteLength": 30108, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6703904, - "byteLength": 20072, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6723976, - "byteLength": 30108, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6754084, - "byteLength": 40144, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6794228, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6825608, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6856988, - "byteLength": 41840, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6898828, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6930208, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 6961588, - "byteLength": 41840, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7003428, - "byteLength": 30108, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7033536, - "byteLength": 30108, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7063644, - "byteLength": 40144, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7103788, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7135168, - "byteLength": 41840, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7177008, - "byteLength": 30108, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7207116, - "byteLength": 30108, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7237224, - "byteLength": 40144, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7277368, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7308748, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7340128, - "byteLength": 41840, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7381968, - "byteLength": 30108, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7412076, - "byteLength": 30108, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7442184, - "byteLength": 40144, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7482328, - "byteLength": 31380, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7513708, - "byteLength": 41840, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7555548, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7555740, - "byteLength": 128, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7555868, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7556060, - "byteLength": 256, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7556316, - "byteLength": 35484, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7591800, - "byteLength": 23656, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7615456, - "byteLength": 35484, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7650940, - "byteLength": 47312, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7698252, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7698444, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7698636, - "byteLength": 256, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7698892, - "byteLength": 35484, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7734376, - "byteLength": 23656, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7758032, - "byteLength": 35484, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7793516, - "byteLength": 47312, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7840828, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7841020, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7841212, - "byteLength": 256, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7841468, - "byteLength": 35484, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7876952, - "byteLength": 35484, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7912436, - "byteLength": 47312, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7959748, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7959940, - "byteLength": 192, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7960132, - "byteLength": 256, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7960388, - "byteLength": 35484, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 7995872, - "byteLength": 35484, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8031356, - "byteLength": 47312, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8078668, - "byteLength": 6396, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8085064, - "byteLength": 6396, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8091460, - "byteLength": 8528, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8099988, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8114760, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8129532, - "byteLength": 19696, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8149228, - "byteLength": 6396, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8155624, - "byteLength": 6396, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8162020, - "byteLength": 8528, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8170548, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8185320, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8200092, - "byteLength": 19696, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8219788, - "byteLength": 6396, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8226184, - "byteLength": 6396, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8232580, - "byteLength": 8528, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8241108, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8255880, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8270652, - "byteLength": 19696, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8290348, - "byteLength": 5400, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8295748, - "byteLength": 3600, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8299348, - "byteLength": 5400, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8304748, - "byteLength": 7200, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8311948, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8326720, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8341492, - "byteLength": 19696, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8361188, - "byteLength": 5400, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8366588, - "byteLength": 5400, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8371988, - "byteLength": 7200, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8379188, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8393960, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8408732, - "byteLength": 19696, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8428428, - "byteLength": 5400, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8433828, - "byteLength": 5400, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8439228, - "byteLength": 7200, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8446428, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8461200, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8475972, - "byteLength": 19696, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8495668, - "byteLength": 5400, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8501068, - "byteLength": 5400, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8506468, - "byteLength": 7200, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8513668, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8528440, - "byteLength": 14772, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8543212, - "byteLength": 19696, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8562908, - "byteLength": 63696, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8626604, - "byteLength": 42464, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8669068, - "byteLength": 63696, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8732764, - "byteLength": 84928, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8817692, - "byteLength": 10392, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8828084, - "byteLength": 6928, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8835012, - "byteLength": 10392, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8845404, - "byteLength": 13856, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8859260, - "byteLength": 9036, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8868296, - "byteLength": 9036, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8877332, - "byteLength": 12048, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8889380, - "byteLength": 10392, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8899772, - "byteLength": 10392, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8910164, - "byteLength": 13856, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8924020, - "byteLength": 9036, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8933056, - "byteLength": 9036, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8942092, - "byteLength": 12048, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8954140, - "byteLength": 600, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8954740, - "byteLength": 400, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8955140, - "byteLength": 600, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8955740, - "byteLength": 800, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 8956540, - "byteLength": 142680, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 9099220, - "byteLength": 95120, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 9194340, - "byteLength": 142680, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 9337020, - "byteLength": 190240, - "byteStride": 16, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 9527260, - "byteLength": 240, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 9527500, - "byteLength": 160, - "byteStride": 8, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 9527660, - "byteLength": 240, - "byteStride": 12, - "target": 34962 - }, - { - "buffer": 0, - "byteOffset": 9527900, - "byteLength": 320, - "byteStride": 16, - "target": 34962 - } - ], - "samplers": [ - { - "magFilter": 9729, - "minFilter": 9987, - "wrapS": 10497, - "wrapT": 10497 - } - ], - "textures": [ - { - "source": 1, - "sampler": 0 - }, - { - "source": 0, - "sampler": 0 - }, - { - "source": 2, - "sampler": 0 - }, - { - "source": 7, - "sampler": 0 - }, - { - "source": 6, - "sampler": 0 - }, - { - "source": 8, - "sampler": 0 - }, - { - "source": 68, - "sampler": 0 - }, - { - "source": 4, - "sampler": 0 - }, - { - "source": 3, - "sampler": 0 - }, - { - "source": 5, - "sampler": 0 - }, - { - "source": 10, - "sampler": 0 - }, - { - "source": 9, - "sampler": 0 - }, - { - "source": 11, - "sampler": 0 - }, - { - "source": 13, - "sampler": 0 - }, - { - "source": 12, - "sampler": 0 - }, - { - "source": 14, - "sampler": 0 - }, - { - "source": 16, - "sampler": 0 - }, - { - "source": 15, - "sampler": 0 - }, - { - "source": 17, - "sampler": 0 - }, - { - "source": 19, - "sampler": 0 - }, - { - "source": 18, - "sampler": 0 - }, - { - "source": 20, - "sampler": 0 - }, - { - "source": 22, - "sampler": 0 - }, - { - "source": 21, - "sampler": 0 - }, - { - "source": 23, - "sampler": 0 - }, - { - "source": 25, - "sampler": 0 - }, - { - "source": 24, - "sampler": 0 - }, - { - "source": 26, - "sampler": 0 - }, - { - "source": 28, - "sampler": 0 - }, - { - "source": 27, - "sampler": 0 - }, - { - "source": 29, - "sampler": 0 - }, - { - "source": 31, - "sampler": 0 - }, - { - "source": 30, - "sampler": 0 - }, - { - "source": 32, - "sampler": 0 - }, - { - "source": 34, - "sampler": 0 - }, - { - "source": 33, - "sampler": 0 - }, - { - "source": 35, - "sampler": 0 - }, - { - "source": 37, - "sampler": 0 - }, - { - "source": 36, - "sampler": 0 - }, - { - "source": 38, - "sampler": 0 - }, - { - "source": 40, - "sampler": 0 - }, - { - "source": 39, - "sampler": 0 - }, - { - "source": 41, - "sampler": 0 - }, - { - "source": 43, - "sampler": 0 - }, - { - "source": 42, - "sampler": 0 - }, - { - "source": 45, - "sampler": 0 - }, - { - "source": 44, - "sampler": 0 - }, - { - "source": 47, - "sampler": 0 - }, - { - "source": 46, - "sampler": 0 - }, - { - "source": 48, - "sampler": 0 - }, - { - "source": 50, - "sampler": 0 - }, - { - "source": 49, - "sampler": 0 - }, - { - "source": 52, - "sampler": 0 - }, - { - "source": 51, - "sampler": 0 - }, - { - "source": 54, - "sampler": 0 - }, - { - "source": 53, - "sampler": 0 - }, - { - "source": 55, - "sampler": 0 - }, - { - "source": 57, - "sampler": 0 - }, - { - "source": 56, - "sampler": 0 - }, - { - "source": 58, - "sampler": 0 - }, - { - "source": 60, - "sampler": 0 - }, - { - "source": 59, - "sampler": 0 - }, - { - "source": 61, - "sampler": 0 - }, - { - "source": 63, - "sampler": 0 - }, - { - "source": 62, - "sampler": 0 - }, - { - "source": 64, - "sampler": 0 - }, - { - "source": 66, - "sampler": 0 - }, - { - "source": 65, - "sampler": 0 - }, - { - "source": 67, - "sampler": 0 - } - ], - "images": [ - { - "mimeType": "image/jpeg", - "uri": "8773302468495022225.jpg" - }, - { - "mimeType": "image/png", - "uri": "5061699253647017043.png" - }, - { - "mimeType": "image/jpeg", - "uri": "11872827283454512094.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "12501374198249454378.jpg" - }, - { - "mimeType": "image/png", - "uri": "8006627369776289000.png" - }, - { - "mimeType": "image/jpeg", - "uri": "715093869573992647.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "4477655471536070370.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "7268504077753552595.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "8503262930880235456.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "13982482287905699490.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "8750083169368950601.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "16885566240357350108.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "16299174074766089871.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "5792855332885324923.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "11968150294050148237.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "2051777328469649772.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "14650633544276105767.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "4871783166746854860.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "10388182081421875623.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "15295713303328085182.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "9916269861720640319.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "15722799267630235092.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "6047387724914829168.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "8051790464816141987.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "14267839433702832875.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "5823059166183034438.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "13824894030729245199.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "6667038893015345571.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "7441062115984513793.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "8114461559286000061.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "3628158980083700836.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "11490520546946913238.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "3455394979645218238.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "7645212358685992005.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "6151467286084645207.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "8783994986360286082.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "2299742237651021498.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "4975155472559461469.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "3371964815757888145.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "7056944414013900257.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "4675343432951571524.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "7815564343179553343.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "2374361008830720677.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "2775690330959970771.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "332936164838540657.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "2185409758123873465.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "6593109234861095314.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "17876391417123941155.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "466164707995436622.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "4601176305987539675.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "11474523244911310074.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "4910669866631290573.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "9288698199695299068.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "14170708867020035030.jpg" - }, - { - "mimeType": "image/png", - "uri": "16275776544635328252.png" - }, - { - "mimeType": "image/jpeg", - "uri": "1219024358953944284.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "3827035219084910048.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "755318871556304029.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "2411100444841994089.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "10381718147657362067.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "8481240838833932244.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "17556969131407844942.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "759203620573749278.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "6772804448157695701.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "13196865903111448057.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "14118779221266351425.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "2969916736137545357.jpg" - }, - { - "mimeType": "image/jpeg", - "uri": "8747919177698443163.jpg" - }, - { - "mimeType": "image/png", - "uri": "white.png" - } - ], - "buffers": [ - { - "uri": "Sponza.bin", - "byteLength": 9528220 - } - ], - "materials": [ - { - "alphaMode": "MASK", - "alphaCutoff": 0.5, - "doubleSided": true, - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 0 - }, - "metallicRoughnessTexture": { - "index": 2 - } - }, - "normalTexture": { - "index": 1 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 3 - }, - "metallicRoughnessTexture": { - "index": 5 - } - }, - "normalTexture": { - "index": 4 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "metallicFactor": 0, - "baseColorTexture": { - "index": 6 - } - } - }, - { - "alphaMode": "MASK", - "alphaCutoff": 0.5, - "doubleSided": true, - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 7 - }, - "metallicRoughnessTexture": { - "index": 9 - } - }, - "normalTexture": { - "index": 8 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 10 - }, - "metallicRoughnessTexture": { - "index": 12 - } - }, - "normalTexture": { - "index": 11 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 13 - }, - "metallicRoughnessTexture": { - "index": 15 - } - }, - "normalTexture": { - "index": 14 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 16 - }, - "metallicRoughnessTexture": { - "index": 18 - } - }, - "normalTexture": { - "index": 17 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 19 - }, - "metallicRoughnessTexture": { - "index": 21 - } - }, - "normalTexture": { - "index": 20 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 22 - }, - "metallicRoughnessTexture": { - "index": 24 - } - }, - "normalTexture": { - "index": 23 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 25 - }, - "metallicRoughnessTexture": { - "index": 27 - } - }, - "normalTexture": { - "index": 26 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 28 - }, - "metallicRoughnessTexture": { - "index": 30 - } - }, - "normalTexture": { - "index": 29 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 31 - }, - "metallicRoughnessTexture": { - "index": 33 - } - }, - "normalTexture": { - "index": 32 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 34 - }, - "metallicRoughnessTexture": { - "index": 36 - } - }, - "normalTexture": { - "index": 35 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 37 - }, - "metallicRoughnessTexture": { - "index": 39 - } - }, - "normalTexture": { - "index": 38 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 40 - }, - "metallicRoughnessTexture": { - "index": 42 - } - }, - "normalTexture": { - "index": 41 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 43 - }, - "metallicRoughnessTexture": { - "index": 42 - } - }, - "normalTexture": { - "index": 44 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 45 - }, - "metallicRoughnessTexture": { - "index": 42 - } - }, - "normalTexture": { - "index": 46 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 47 - }, - "metallicRoughnessTexture": { - "index": 49 - } - }, - "normalTexture": { - "index": 48 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 50 - }, - "metallicRoughnessTexture": { - "index": 49 - } - }, - "normalTexture": { - "index": 51 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 52 - }, - "metallicRoughnessTexture": { - "index": 49 - } - }, - "normalTexture": { - "index": 53 - } - }, - { - "alphaMode": "MASK", - "alphaCutoff": 0.5, - "doubleSided": true, - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 54 - }, - "metallicRoughnessTexture": { - "index": 56 - } - }, - "normalTexture": { - "index": 55 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 57 - }, - "metallicRoughnessTexture": { - "index": 59 - } - }, - "normalTexture": { - "index": 58 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 60 - }, - "metallicRoughnessTexture": { - "index": 62 - } - }, - "normalTexture": { - "index": 61 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 63 - }, - "metallicRoughnessTexture": { - "index": 65 - } - }, - "normalTexture": { - "index": 64 - } - }, - { - "pbrMetallicRoughness": { - "baseColorFactor": [ - 0.5879999995231628, - 0.5879999995231628, - 0.5879999995231628, - 1 - ], - "baseColorTexture": { - "index": 66 - }, - "metallicRoughnessTexture": { - "index": 68 - } - }, - "normalTexture": { - "index": 67 - } - } - ], - "meshes": [ - { - "primitives": [ - { - "attributes": { - "POSITION": 50, - "TEXCOORD_0": 51, - "NORMAL": 52, - "TANGENT": 53 - }, - "mode": 4, - "material": 0, - "indices": 0 - }, - { - "attributes": { - "POSITION": 54, - "TEXCOORD_0": 55, - "NORMAL": 56, - "TANGENT": 57 - }, - "mode": 4, - "material": 3, - "indices": 1 - }, - { - "attributes": { - "POSITION": 58, - "TEXCOORD_0": 59, - "NORMAL": 60, - "TANGENT": 61 - }, - "mode": 4, - "material": 1, - "indices": 2 - }, - { - "attributes": { - "POSITION": 62, - "TEXCOORD_0": 63, - "NORMAL": 64, - "TANGENT": 65 - }, - "mode": 4, - "material": 4, - "indices": 3 - }, - { - "attributes": { - "POSITION": 66, - "TEXCOORD_0": 67, - "NORMAL": 68, - "TANGENT": 69 - }, - "mode": 4, - "material": 5, - "indices": 4 - }, - { - "attributes": { - "POSITION": 70, - "TEXCOORD_0": 71, - "NORMAL": 72, - "TANGENT": 73 - }, - "mode": 4, - "material": 6, - "indices": 5 - }, - { - "attributes": { - "POSITION": 74, - "TEXCOORD_0": 75, - "NORMAL": 76, - "TANGENT": 77 - }, - "mode": 4, - "material": 7, - "indices": 6 - }, - { - "attributes": { - "POSITION": 78, - "TEXCOORD_0": 79, - "NORMAL": 80, - "TANGENT": 81 - }, - "mode": 4, - "material": 8, - "indices": 7 - }, - { - "attributes": { - "POSITION": 82, - "TEXCOORD_0": 83, - "NORMAL": 84, - "TANGENT": 85 - }, - "mode": 4, - "material": 6, - "indices": 8 - }, - { - "attributes": { - "POSITION": 86, - "TEXCOORD_0": 87, - "NORMAL": 88, - "TANGENT": 89 - }, - "mode": 4, - "material": 9, - "indices": 9 - }, - { - "attributes": { - "POSITION": 90, - "TEXCOORD_0": 75, - "NORMAL": 91, - "TANGENT": 92 - }, - "mode": 4, - "material": 7, - "indices": 6 - }, - { - "attributes": { - "POSITION": 93, - "TEXCOORD_0": 94, - "NORMAL": 95, - "TANGENT": 96 - }, - "mode": 4, - "material": 6, - "indices": 10 - }, - { - "attributes": { - "POSITION": 97, - "TEXCOORD_0": 98, - "NORMAL": 99, - "TANGENT": 100 - }, - "mode": 4, - "material": 10, - "indices": 11 - }, - { - "attributes": { - "POSITION": 101, - "TEXCOORD_0": 102, - "NORMAL": 103, - "TANGENT": 104 - }, - "mode": 4, - "material": 5, - "indices": 12 - }, - { - "attributes": { - "POSITION": 105, - "TEXCOORD_0": 106, - "NORMAL": 107, - "TANGENT": 108 - }, - "mode": 4, - "material": 7, - "indices": 13 - }, - { - "attributes": { - "POSITION": 109, - "TEXCOORD_0": 110, - "NORMAL": 111, - "TANGENT": 112 - }, - "mode": 4, - "material": 5, - "indices": 14 - }, - { - "attributes": { - "POSITION": 113, - "TEXCOORD_0": 114, - "NORMAL": 115, - "TANGENT": 116 - }, - "mode": 4, - "material": 6, - "indices": 15 - }, - { - "attributes": { - "POSITION": 117, - "TEXCOORD_0": 118, - "NORMAL": 119, - "TANGENT": 120 - }, - "mode": 4, - "material": 7, - "indices": 16 - }, - { - "attributes": { - "POSITION": 121, - "TEXCOORD_0": 114, - "NORMAL": 122, - "TANGENT": 123 - }, - "mode": 4, - "material": 6, - "indices": 15 - }, - { - "attributes": { - "POSITION": 124, - "TEXCOORD_0": 118, - "NORMAL": 125, - "TANGENT": 126 - }, - "mode": 4, - "material": 7, - "indices": 16 - }, - { - "attributes": { - "POSITION": 127, - "TEXCOORD_0": 114, - "NORMAL": 128, - "TANGENT": 129 - }, - "mode": 4, - "material": 6, - "indices": 15 - }, - { - "attributes": { - "POSITION": 130, - "TEXCOORD_0": 118, - "NORMAL": 131, - "TANGENT": 132 - }, - "mode": 4, - "material": 7, - "indices": 16 - }, - { - "attributes": { - "POSITION": 133, - "TEXCOORD_0": 114, - "NORMAL": 134, - "TANGENT": 135 - }, - "mode": 4, - "material": 6, - "indices": 15 - }, - { - "attributes": { - "POSITION": 136, - "TEXCOORD_0": 118, - "NORMAL": 137, - "TANGENT": 138 - }, - "mode": 4, - "material": 7, - "indices": 16 - }, - { - "attributes": { - "POSITION": 139, - "TEXCOORD_0": 140, - "NORMAL": 141, - "TANGENT": 142 - }, - "mode": 4, - "material": 6, - "indices": 17 - }, - { - "attributes": { - "POSITION": 143, - "TEXCOORD_0": 144, - "NORMAL": 145, - "TANGENT": 146 - }, - "mode": 4, - "material": 7, - "indices": 18 - }, - { - "attributes": { - "POSITION": 147, - "TEXCOORD_0": 140, - "NORMAL": 148, - "TANGENT": 149 - }, - "mode": 4, - "material": 6, - "indices": 17 - }, - { - "attributes": { - "POSITION": 150, - "TEXCOORD_0": 144, - "NORMAL": 151, - "TANGENT": 152 - }, - "mode": 4, - "material": 7, - "indices": 18 - }, - { - "attributes": { - "POSITION": 153, - "TEXCOORD_0": 140, - "NORMAL": 154, - "TANGENT": 155 - }, - "mode": 4, - "material": 6, - "indices": 17 - }, - { - "attributes": { - "POSITION": 156, - "TEXCOORD_0": 144, - "NORMAL": 157, - "TANGENT": 158 - }, - "mode": 4, - "material": 7, - "indices": 18 - }, - { - "attributes": { - "POSITION": 159, - "TEXCOORD_0": 140, - "NORMAL": 160, - "TANGENT": 161 - }, - "mode": 4, - "material": 6, - "indices": 17 - }, - { - "attributes": { - "POSITION": 162, - "TEXCOORD_0": 144, - "NORMAL": 163, - "TANGENT": 164 - }, - "mode": 4, - "material": 7, - "indices": 18 - }, - { - "attributes": { - "POSITION": 165, - "TEXCOORD_0": 140, - "NORMAL": 166, - "TANGENT": 167 - }, - "mode": 4, - "material": 6, - "indices": 17 - }, - { - "attributes": { - "POSITION": 168, - "TEXCOORD_0": 144, - "NORMAL": 169, - "TANGENT": 170 - }, - "mode": 4, - "material": 7, - "indices": 18 - }, - { - "attributes": { - "POSITION": 171, - "TEXCOORD_0": 172, - "NORMAL": 173, - "TANGENT": 174 - }, - "mode": 4, - "material": 6, - "indices": 19 - }, - { - "attributes": { - "POSITION": 175, - "TEXCOORD_0": 176, - "NORMAL": 177, - "TANGENT": 178 - }, - "mode": 4, - "material": 5, - "indices": 20 - }, - { - "attributes": { - "POSITION": 179, - "TEXCOORD_0": 71, - "NORMAL": 180, - "TANGENT": 181 - }, - "mode": 4, - "material": 6, - "indices": 5 - }, - { - "attributes": { - "POSITION": 182, - "TEXCOORD_0": 183, - "NORMAL": 184, - "TANGENT": 185 - }, - "mode": 4, - "material": 5, - "indices": 21 - }, - { - "attributes": { - "POSITION": 186, - "TEXCOORD_0": 187, - "NORMAL": 188, - "TANGENT": 189 - }, - "mode": 4, - "material": 11, - "indices": 22 - }, - { - "attributes": { - "POSITION": 190, - "TEXCOORD_0": 191, - "NORMAL": 192, - "TANGENT": 193 - }, - "mode": 4, - "material": 5, - "indices": 23 - }, - { - "attributes": { - "POSITION": 194, - "TEXCOORD_0": 195, - "NORMAL": 196, - "TANGENT": 197 - }, - "mode": 4, - "material": 11, - "indices": 24 - }, - { - "attributes": { - "POSITION": 198, - "TEXCOORD_0": 191, - "NORMAL": 199, - "TANGENT": 193 - }, - "mode": 4, - "material": 5, - "indices": 23 - }, - { - "attributes": { - "POSITION": 200, - "TEXCOORD_0": 201, - "NORMAL": 202, - "TANGENT": 203 - }, - "mode": 4, - "material": 11, - "indices": 25 - }, - { - "attributes": { - "POSITION": 204, - "TEXCOORD_0": 205, - "NORMAL": 206, - "TANGENT": 207 - }, - "mode": 4, - "material": 5, - "indices": 26 - }, - { - "attributes": { - "POSITION": 208, - "TEXCOORD_0": 209, - "NORMAL": 210, - "TANGENT": 211 - }, - "mode": 4, - "material": 10, - "indices": 27 - }, - { - "attributes": { - "POSITION": 212, - "TEXCOORD_0": 213, - "NORMAL": 214, - "TANGENT": 215 - }, - "mode": 4, - "material": 5, - "indices": 28 - }, - { - "attributes": { - "POSITION": 216, - "TEXCOORD_0": 217, - "NORMAL": 218, - "TANGENT": 219 - }, - "mode": 4, - "material": 9, - "indices": 29 - }, - { - "attributes": { - "POSITION": 220, - "TEXCOORD_0": 221, - "NORMAL": 222, - "TANGENT": 223 - }, - "mode": 4, - "material": 8, - "indices": 30 - }, - { - "attributes": { - "POSITION": 224, - "TEXCOORD_0": 225, - "NORMAL": 226, - "TANGENT": 227 - }, - "mode": 4, - "material": 6, - "indices": 31 - }, - { - "attributes": { - "POSITION": 228, - "TEXCOORD_0": 229, - "NORMAL": 230, - "TANGENT": 231 - }, - "mode": 4, - "material": 12, - "indices": 32 - }, - { - "attributes": { - "POSITION": 232, - "TEXCOORD_0": 233, - "NORMAL": 234 - }, - "mode": 4, - "material": 2, - "indices": 33 - }, - { - "attributes": { - "POSITION": 235, - "TEXCOORD_0": 236, - "NORMAL": 237, - "TANGENT": 238 - }, - "mode": 4, - "material": 5, - "indices": 34 - }, - { - "attributes": { - "POSITION": 239, - "TEXCOORD_0": 240, - "NORMAL": 241, - "TANGENT": 242 - }, - "mode": 4, - "material": 13, - "indices": 35 - }, - { - "attributes": { - "POSITION": 243, - "TEXCOORD_0": 244, - "NORMAL": 245, - "TANGENT": 246 - }, - "mode": 4, - "material": 0, - "indices": 36 - }, - { - "attributes": { - "POSITION": 247, - "TEXCOORD_0": 248, - "NORMAL": 249, - "TANGENT": 250 - }, - "mode": 4, - "material": 14, - "indices": 37 - }, - { - "attributes": { - "POSITION": 251, - "TEXCOORD_0": 248, - "NORMAL": 252, - "TANGENT": 253 - }, - "mode": 4, - "material": 15, - "indices": 37 - }, - { - "attributes": { - "POSITION": 254, - "TEXCOORD_0": 248, - "NORMAL": 255, - "TANGENT": 256 - }, - "mode": 4, - "material": 16, - "indices": 37 - }, - { - "attributes": { - "POSITION": 257, - "TEXCOORD_0": 248, - "NORMAL": 258, - "TANGENT": 259 - }, - "mode": 4, - "material": 14, - "indices": 37 - }, - { - "attributes": { - "POSITION": 260, - "TEXCOORD_0": 248, - "NORMAL": 261, - "TANGENT": 262 - }, - "mode": 4, - "material": 15, - "indices": 37 - }, - { - "attributes": { - "POSITION": 263, - "TEXCOORD_0": 248, - "NORMAL": 264, - "TANGENT": 265 - }, - "mode": 4, - "material": 14, - "indices": 37 - }, - { - "attributes": { - "POSITION": 266, - "TEXCOORD_0": 248, - "NORMAL": 267, - "TANGENT": 268 - }, - "mode": 4, - "material": 16, - "indices": 37 - }, - { - "attributes": { - "POSITION": 269, - "TEXCOORD_0": 248, - "NORMAL": 270, - "TANGENT": 271 - }, - "mode": 4, - "material": 15, - "indices": 37 - }, - { - "attributes": { - "POSITION": 272, - "TEXCOORD_0": 273, - "NORMAL": 274, - "TANGENT": 275 - }, - "mode": 4, - "material": 13, - "indices": 38 - }, - { - "attributes": { - "POSITION": 276, - "TEXCOORD_0": 277, - "NORMAL": 278, - "TANGENT": 279 - }, - "mode": 4, - "material": 17, - "indices": 39 - }, - { - "attributes": { - "POSITION": 280, - "TEXCOORD_0": 281, - "NORMAL": 282, - "TANGENT": 283 - }, - "mode": 4, - "material": 18, - "indices": 40 - }, - { - "attributes": { - "POSITION": 284, - "TEXCOORD_0": 277, - "NORMAL": 285, - "TANGENT": 286 - }, - "mode": 4, - "material": 19, - "indices": 39 - }, - { - "attributes": { - "POSITION": 287, - "TEXCOORD_0": 277, - "NORMAL": 288, - "TANGENT": 289 - }, - "mode": 4, - "material": 18, - "indices": 39 - }, - { - "attributes": { - "POSITION": 290, - "TEXCOORD_0": 281, - "NORMAL": 291, - "TANGENT": 292 - }, - "mode": 4, - "material": 19, - "indices": 40 - }, - { - "attributes": { - "POSITION": 293, - "TEXCOORD_0": 277, - "NORMAL": 285, - "TANGENT": 294 - }, - "mode": 4, - "material": 18, - "indices": 39 - }, - { - "attributes": { - "POSITION": 295, - "TEXCOORD_0": 281, - "NORMAL": 296, - "TANGENT": 297 - }, - "mode": 4, - "material": 17, - "indices": 40 - }, - { - "attributes": { - "POSITION": 298, - "TEXCOORD_0": 277, - "NORMAL": 299, - "TANGENT": 300 - }, - "mode": 4, - "material": 19, - "indices": 39 - }, - { - "attributes": { - "POSITION": 301, - "TEXCOORD_0": 281, - "NORMAL": 302, - "TANGENT": 303 - }, - "mode": 4, - "material": 18, - "indices": 40 - }, - { - "attributes": { - "POSITION": 304, - "TEXCOORD_0": 277, - "NORMAL": 288, - "TANGENT": 305 - }, - "mode": 4, - "material": 17, - "indices": 39 - }, - { - "attributes": { - "POSITION": 306, - "TEXCOORD_0": 307, - "NORMAL": 308, - "TANGENT": 309 - }, - "mode": 4, - "material": 20, - "indices": 41 - }, - { - "attributes": { - "POSITION": 310, - "TEXCOORD_0": 311, - "NORMAL": 312, - "TANGENT": 313 - }, - "mode": 4, - "material": 21, - "indices": 42 - }, - { - "attributes": { - "POSITION": 314, - "TEXCOORD_0": 307, - "NORMAL": 315, - "TANGENT": 316 - }, - "mode": 4, - "material": 20, - "indices": 41 - }, - { - "attributes": { - "POSITION": 317, - "TEXCOORD_0": 318, - "NORMAL": 319, - "TANGENT": 320 - }, - "mode": 4, - "material": 21, - "indices": 43 - }, - { - "attributes": { - "POSITION": 321, - "TEXCOORD_0": 307, - "NORMAL": 322, - "TANGENT": 323 - }, - "mode": 4, - "material": 20, - "indices": 41 - }, - { - "attributes": { - "POSITION": 324, - "TEXCOORD_0": 311, - "NORMAL": 325, - "TANGENT": 326 - }, - "mode": 4, - "material": 21, - "indices": 42 - }, - { - "attributes": { - "POSITION": 327, - "TEXCOORD_0": 307, - "NORMAL": 328, - "TANGENT": 329 - }, - "mode": 4, - "material": 20, - "indices": 41 - }, - { - "attributes": { - "POSITION": 330, - "TEXCOORD_0": 318, - "NORMAL": 331, - "TANGENT": 332 - }, - "mode": 4, - "material": 21, - "indices": 43 - }, - { - "attributes": { - "POSITION": 333, - "TEXCOORD_0": 55, - "NORMAL": 334, - "TANGENT": 335 - }, - "mode": 4, - "material": 3, - "indices": 1 - }, - { - "attributes": { - "POSITION": 336, - "TEXCOORD_0": 59, - "NORMAL": 337, - "TANGENT": 338 - }, - "mode": 4, - "material": 1, - "indices": 2 - }, - { - "attributes": { - "POSITION": 339, - "TEXCOORD_0": 55, - "NORMAL": 340, - "TANGENT": 341 - }, - "mode": 4, - "material": 3, - "indices": 1 - }, - { - "attributes": { - "POSITION": 342, - "TEXCOORD_0": 59, - "NORMAL": 343, - "TANGENT": 344 - }, - "mode": 4, - "material": 1, - "indices": 2 - }, - { - "attributes": { - "POSITION": 345, - "TEXCOORD_0": 55, - "NORMAL": 346, - "TANGENT": 347 - }, - "mode": 4, - "material": 3, - "indices": 1 - }, - { - "attributes": { - "POSITION": 348, - "TEXCOORD_0": 59, - "NORMAL": 349, - "TANGENT": 350 - }, - "mode": 4, - "material": 1, - "indices": 2 - }, - { - "attributes": { - "POSITION": 351, - "TEXCOORD_0": 352, - "NORMAL": 353, - "TANGENT": 354 - }, - "mode": 4, - "material": 3, - "indices": 44 - }, - { - "attributes": { - "POSITION": 355, - "TEXCOORD_0": 59, - "NORMAL": 356, - "TANGENT": 357 - }, - "mode": 4, - "material": 1, - "indices": 2 - }, - { - "attributes": { - "POSITION": 358, - "TEXCOORD_0": 352, - "NORMAL": 359, - "TANGENT": 360 - }, - "mode": 4, - "material": 3, - "indices": 44 - }, - { - "attributes": { - "POSITION": 361, - "TEXCOORD_0": 59, - "NORMAL": 362, - "TANGENT": 363 - }, - "mode": 4, - "material": 1, - "indices": 2 - }, - { - "attributes": { - "POSITION": 364, - "TEXCOORD_0": 352, - "NORMAL": 365, - "TANGENT": 366 - }, - "mode": 4, - "material": 3, - "indices": 44 - }, - { - "attributes": { - "POSITION": 367, - "TEXCOORD_0": 59, - "NORMAL": 368, - "TANGENT": 369 - }, - "mode": 4, - "material": 1, - "indices": 2 - }, - { - "attributes": { - "POSITION": 370, - "TEXCOORD_0": 352, - "NORMAL": 371, - "TANGENT": 372 - }, - "mode": 4, - "material": 3, - "indices": 44 - }, - { - "attributes": { - "POSITION": 373, - "TEXCOORD_0": 59, - "NORMAL": 374, - "TANGENT": 375 - }, - "mode": 4, - "material": 1, - "indices": 2 - }, - { - "attributes": { - "POSITION": 376, - "TEXCOORD_0": 377, - "NORMAL": 378, - "TANGENT": 379 - }, - "mode": 4, - "material": 22, - "indices": 45 - }, - { - "attributes": { - "POSITION": 380, - "TEXCOORD_0": 381, - "NORMAL": 382, - "TANGENT": 383 - }, - "mode": 4, - "material": 23, - "indices": 46 - }, - { - "attributes": { - "POSITION": 384, - "TEXCOORD_0": 63, - "NORMAL": 385, - "TANGENT": 386 - }, - "mode": 4, - "material": 4, - "indices": 3 - }, - { - "attributes": { - "POSITION": 387, - "TEXCOORD_0": 381, - "NORMAL": 388, - "TANGENT": 389 - }, - "mode": 4, - "material": 23, - "indices": 46 - }, - { - "attributes": { - "POSITION": 390, - "TEXCOORD_0": 63, - "NORMAL": 391, - "TANGENT": 392 - }, - "mode": 4, - "material": 4, - "indices": 3 - }, - { - "attributes": { - "POSITION": 393, - "TEXCOORD_0": 394, - "NORMAL": 395, - "TANGENT": 396 - }, - "mode": 4, - "material": 5, - "indices": 47 - }, - { - "attributes": { - "POSITION": 397, - "TEXCOORD_0": 398, - "NORMAL": 399, - "TANGENT": 400 - }, - "mode": 4, - "material": 24, - "indices": 48 - }, - { - "attributes": { - "POSITION": 401, - "TEXCOORD_0": 402, - "NORMAL": 403, - "TANGENT": 404 - }, - "mode": 4, - "material": 5, - "indices": 49 - } - ] - } - ], - "nodes": [ - { - "scale": [ - 0.00800000037997961, - 0.00800000037997961, - 0.00800000037997961 - ], - "mesh": 0 - } - ], - "scenes": [ - { - "nodes": [ - 0 - ] - } - ], - "scene": 0 -} diff --git a/sources/Experiments/SponzaScene/Assets/Sponza/white.png b/sources/Experiments/SponzaScene/Assets/Sponza/white.png deleted file mode 100644 index 0851a35f..00000000 Binary files a/sources/Experiments/SponzaScene/Assets/Sponza/white.png and /dev/null differ diff --git a/sources/Experiments/SponzaScene/Helpers/ImGuiHelper.cs b/sources/Experiments/SponzaScene/Helpers/ImGuiHelper.cs deleted file mode 100644 index 4e3bdbe2..00000000 --- a/sources/Experiments/SponzaScene/Helpers/ImGuiHelper.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using Zenith.NET; - -namespace SponzaScene.Helpers; - -internal static class ImGuiHelper -{ - private const ImGuiWindowFlags OverlayFlags = ImGuiWindowFlags.NoDecoration - | ImGuiWindowFlags.AlwaysAutoResize - | ImGuiWindowFlags.NoSavedSettings - | ImGuiWindowFlags.NoFocusOnAppearing - | ImGuiWindowFlags.NoInputs - | ImGuiWindowFlags.NoMove; - - public static void Overlay(string name, Action action) - { - ImGui.SetNextWindowPos(new(10, 10), ImGuiCond.Always, new(0, 0)); - ImGui.SetNextWindowBgAlpha(0.35f); - - if (ImGui.Begin(name, OverlayFlags)) - { - action(); - - ImGui.End(); - } - } - - public static void Image(Texture texture, Vector2? maxSize = null) - { - float aspectRatio = (float)texture.Desc.Width / texture.Desc.Height; - - Vector2 size = maxSize ?? ImGui.GetContentRegionAvail(); - - if (size.X / size.Y > aspectRatio) - { - size.X = size.Y * aspectRatio; - } - else - { - size.Y = size.X / aspectRatio; - } - - Image(App.Binding(texture), size); - } - - public static void Image(TextureView textureView, Vector2? maxSize = null) - { - ZenithHelper.MipDimensions(textureView.Desc.Texture.Desc.Width, - textureView.Desc.Texture.Desc.Height, - 1, - textureView.Desc.FirstMipLevel, - out uint mipWidth, - out uint mipHeight, - out _); - - float aspectRatio = (float)mipWidth / mipHeight; - - Vector2 size = maxSize ?? ImGui.GetContentRegionAvail(); - - if (size.X / size.Y > aspectRatio) - { - size.X = size.Y * aspectRatio; - } - else - { - size.Y = size.X / aspectRatio; - } - - Image(App.Binding(textureView), size); - } - - private static void Image(ImTextureRef imTextureRef, Vector2 size) - { - Background(ImGui.GetCursorScreenPos(), size, 0xFF000000); - ImGui.Image(imTextureRef, size); - - if (ImGui.IsItemHovered() && ImGui.BeginTooltip()) - { - Vector2 displaySize = ImGui.GetIO().DisplaySize / 2.0f; - - size *= MathF.Min(displaySize.X / size.X, displaySize.Y / size.Y); - - Background(ImGui.GetCursorScreenPos(), size, 0xFF000000); - ImGui.Image(imTextureRef, size); - - ImGui.EndTooltip(); - } - } - - private static void Background(Vector2 position, Vector2 size, uint color) - { - ImGui.GetWindowDrawList().AddRectFilled(position, position + size, color); - } -} diff --git a/sources/Experiments/SponzaScene/Models/CSMData.cs b/sources/Experiments/SponzaScene/Models/CSMData.cs deleted file mode 100644 index 2df1488b..00000000 --- a/sources/Experiments/SponzaScene/Models/CSMData.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Numerics; - -namespace SponzaScene.Models; - -internal struct CSMData -{ - public Matrix4x4 View; - - public Matrix4x4 Projection; - - public float NearPlane; - - public float FarPlane; -} diff --git a/sources/Experiments/SponzaScene/Models/DirectionalLight.cs b/sources/Experiments/SponzaScene/Models/DirectionalLight.cs deleted file mode 100644 index fe9ebf2f..00000000 --- a/sources/Experiments/SponzaScene/Models/DirectionalLight.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Numerics; - -namespace SponzaScene.Models; - -internal struct DirectionalLight -{ - public Vector3 Direction; - - public float Intensity; - - public Vector3 Color; -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Models/Material.cs b/sources/Experiments/SponzaScene/Models/Material.cs deleted file mode 100644 index 2c227891..00000000 --- a/sources/Experiments/SponzaScene/Models/Material.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Numerics; -using SharpGLTF.Schema2; -using Zenith.NET; -using Zenith.NET.Extensions.ImageSharp; -using GMaterial = SharpGLTF.Schema2.Material; -using GTexture = SharpGLTF.Schema2.Texture; -using Texture = Zenith.NET.Texture; - -namespace SponzaScene.Models; - -internal class Material : DisposableObject -{ - public Material(GMaterial material) - { - Name = material.Name ?? "Unnamed Material"; - DoubleSided = material.DoubleSided; - AlphaCutoff = material.AlphaCutoff; - BaseColorFactor = material.GetDiffuseColor(Vector4.One); - - if (material.GetDiffuseTexture() is GTexture texture) - { - using MemoryStream stream = new(texture.PrimaryImage.Content.Content.ToArray()); - - BaseColorTexture = App.Context.LoadTextureFromStream(stream, true); - } - - if (material.FindChannel("Normal")?.Texture is GTexture normalTexture) - { - using MemoryStream stream = new(normalTexture.PrimaryImage.Content.Content.ToArray()); - - NormalTexture = App.Context.LoadTextureFromStream(stream); - } - - if (material.FindChannel("MetallicRoughness") is MaterialChannel mr) - { - MetallicFactor = mr.GetFactor("MetallicFactor"); - RoughnessFactor = mr.GetFactor("RoughnessFactor"); - - if (mr.Texture is GTexture metallicRoughnessTexture) - { - using MemoryStream stream = new(metallicRoughnessTexture.PrimaryImage.Content.Content.ToArray()); - - MetallicRoughnessTexture = App.Context.LoadTextureFromStream(stream); - } - } - - if (material.FindChannel("Emissive") is MaterialChannel e) - { - EmissiveFactor = e.Color; - EmissiveStrength = e.GetFactor("EmissiveStrength"); - } - } - - public Material(string name, - bool doubleSided = false, - float alphaCutoff = 0.5f, - Vector4? baseColorFactor = null, - float metallicFactor = 1.0f, - float roughnessFactor = 1.0f, - Vector4? emissiveFactor = null, - float emissiveStrength = 1.0f) - { - Name = name; - DoubleSided = doubleSided; - AlphaCutoff = alphaCutoff; - BaseColorFactor = baseColorFactor ?? Vector4.One; - MetallicFactor = metallicFactor; - RoughnessFactor = roughnessFactor; - EmissiveFactor = emissiveFactor ?? Vector4.Zero; - EmissiveStrength = emissiveStrength; - } - - public string Id { get; } = Guid.NewGuid().ToString(); - - public string Name { get; } - - public bool DoubleSided { get; } - - public float AlphaCutoff { get; } - - public Vector4 BaseColorFactor { get; } - - public Texture? BaseColorTexture { get; } - - public Texture? NormalTexture { get; } - - public float MetallicFactor { get; } - - public float RoughnessFactor { get; } - - public Texture? MetallicRoughnessTexture { get; } - - public Vector4 EmissiveFactor { get; } - - public float EmissiveStrength { get; } - - protected override void Destroy() - { - MetallicRoughnessTexture?.Dispose(); - NormalTexture?.Dispose(); - BaseColorTexture?.Dispose(); - } -} diff --git a/sources/Experiments/SponzaScene/Models/Node.cs b/sources/Experiments/SponzaScene/Models/Node.cs deleted file mode 100644 index 0072e41d..00000000 --- a/sources/Experiments/SponzaScene/Models/Node.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Zenith.NET; - -namespace SponzaScene.Models; - -internal readonly record struct Node(string Name, uint VertexCount, IndirectDrawIndexedArgs Args, uint Material); \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Models/PointLight.cs b/sources/Experiments/SponzaScene/Models/PointLight.cs deleted file mode 100644 index f6c84fb4..00000000 --- a/sources/Experiments/SponzaScene/Models/PointLight.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Numerics; - -namespace SponzaScene.Models; - -internal struct PointLight -{ - public Vector3 Position; - - public float Radius; - - public Vector3 Color; - - public float Intensity; -} diff --git a/sources/Experiments/SponzaScene/Models/Sponza.cs b/sources/Experiments/SponzaScene/Models/Sponza.cs deleted file mode 100644 index ac8802bb..00000000 --- a/sources/Experiments/SponzaScene/Models/Sponza.cs +++ /dev/null @@ -1,304 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SharpGLTF.Schema2; -using Zenith.NET; -using Buffer = Zenith.NET.Buffer; -using GNode = SharpGLTF.Schema2.Node; - -namespace SponzaScene.Models; - -internal unsafe class Sponza : DisposableObject -{ - private static readonly Vector3 HorizonColor = new(1.0f, 0.65f, 0.4f); - private static readonly Vector3 DayColor = new(1.0f, 0.9f, 0.75f); - - private float directionalLightProgress = 0.454f; - - public Sponza() - { - ModelRoot root = ModelRoot.Load(Path.Combine(AppContext.BaseDirectory, "Assets", "Sponza", "Sponza.gltf")); - - List nodes = []; - List vertices = []; - List indices = []; - foreach (GNode node in root.LogicalNodes) - { - ProcessNode(node, nodes, vertices, indices); - } - - uint baseMaterialIndex = (uint)root.LogicalMaterials.Count; - - AddSphere(new(-29.67882f, 6.9f, 6.88488f), 0.6f, baseMaterialIndex, nodes, vertices, indices); - AddSphere(new(-29.67882f, 6.9f, -10.55208f), 0.6f, baseMaterialIndex + 1, nodes, vertices, indices); - AddSphere(new(23.4f, 6.9f, 6.88488f), 0.6f, baseMaterialIndex + 2, nodes, vertices, indices); - AddSphere(new(23.4f, 6.9f, -10.55076f), 0.6f, baseMaterialIndex + 3, nodes, vertices, indices); - - Nodes = [.. nodes]; - - Materials = - [ - .. root.LogicalMaterials.Select(static material => new Material(material)), - new("Emissive_Cyan", emissiveFactor: new(0.3f, 0.9f, 1.0f, 1.0f), emissiveStrength: 20.0f), - new("Emissive_Magenta", emissiveFactor: new(1.0f, 0.3f, 0.8f, 1.0f), emissiveStrength: 20.0f), - new("Emissive_Yellow", emissiveFactor: new(1.0f, 0.9f, 0.2f, 1.0f), emissiveStrength: 20.0f), - new("Emissive_Green", emissiveFactor: new(0.3f, 1.0f, 0.4f, 1.0f), emissiveStrength: 20.0f) - ]; - - Vertices = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)(sizeof(Vertex) * vertices.Count), - StrideInBytes = (uint)sizeof(Vertex), - Flags = BufferUsageFlags.Vertex | (App.Context.Capabilities.RayTracingSupported ? BufferUsageFlags.AccelerationStructure : 0) - }); - Vertices.Upload([.. vertices], 0); - - Indices = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)(sizeof(uint) * indices.Count), - StrideInBytes = sizeof(uint), - Flags = BufferUsageFlags.Index | (App.Context.Capabilities.RayTracingSupported ? BufferUsageFlags.AccelerationStructure : 0) - }); - Indices.Upload([.. indices], 0); - - if (App.Context.Capabilities.RayTracingSupported) - { - RayTracingGeometry[] geometries = new RayTracingGeometry[Nodes.Length]; - for (int i = 0; i < Nodes.Length; i++) - { - Node node = Nodes[i]; - - geometries[i] = new() - { - Type = RayTracingGeometryType.Triangles, - Triangles = new() - { - VertexBuffer = Vertices, - VertexFormat = PixelFormat.R32G32B32Float, - VertexCount = node.VertexCount, - VertexStrideInBytes = (uint)sizeof(Vertex), - VertexOffsetInBytes = (uint)(sizeof(Vertex) * node.Args.VertexOffset), - IndexBuffer = Indices, - IndexFormat = IndexFormat.UInt32, - IndexCount = node.Args.IndexCount, - IndexOffsetInBytes = sizeof(uint) * node.Args.FirstIndex, - Transform = Matrix4x4.Identity - }, - Flags = RayTracingGeometryFlags.Opaque - }; - } - - CommandBuffer commandBuffer = App.Context.Graphics.CommandBuffer(); - - BLAS = commandBuffer.BuildAccelerationStructure(new BottomLevelAccelerationStructureDesc() - { - Geometries = geometries, - Flags = AccelerationStructureBuildFlags.PreferFastTrace - }); - - RayTracingInstance instance = new() - { - AccelerationStructure = BLAS, - InstanceMask = 0xFF, - Transform = Matrix4x4.Identity, - Flags = RayTracingInstanceFlags.TriangleCullDisable - }; - - TLAS = commandBuffer.BuildAccelerationStructure(new TopLevelAccelerationStructureDesc() - { - Instances = [instance], - Flags = AccelerationStructureBuildFlags.PreferFastTrace - }); - - commandBuffer.Submit(true); - } - } - - public DirectionalLight DirectionalLight - { - get - { - const float maxElevation = 75.0f; - const float degToRad = MathF.PI / 180.0f; - - float progressAngle = directionalLightProgress * MathF.PI; - float elevation = maxElevation * MathF.Sin(progressAngle); - float elevationRad = elevation * degToRad; - - Vector3 direction = Vector3.Normalize(new(0.0f, -MathF.Sin(elevationRad), -MathF.Cos(progressAngle))); - - float colorFactor = Math.Clamp(elevation / maxElevation, 0.0f, 1.0f); - float smoothColorFactor = colorFactor * colorFactor * (3.0f - (2.0f * colorFactor)); - float intensityFactor = MathF.Sin(colorFactor * MathF.PI * 0.5f); - - return new() - { - Direction = direction, - Color = Vector3.Lerp(HorizonColor, DayColor, smoothColorFactor), - Intensity = float.Lerp(2.0f, 5.0f, intensityFactor) - }; - } - } - - public PointLight[] PointLights { get; } = - [ - new() - { - Position = new(-29.67882f, 6.9f, 6.88488f), - Color = new(0.3f, 0.9f, 1.0f), - Intensity = 800.0f, - Radius = 30.0f - }, - new() - { - Position = new(-29.67882f, 6.9f, -10.55208f), - Color = new(1.0f, 0.3f, 0.8f), - Intensity = 800.0f, - Radius = 30.0f - }, - new() - { - Position = new(23.4f, 6.9f, 6.88488f), - Color = new(1.0f, 0.9f, 0.2f), - Intensity = 800.0f, - Radius = 30.0f - }, - new() - { - Position = new(23.4f, 6.9f, -10.55076f), - Color = new(0.3f, 1.0f, 0.4f), - Intensity = 800.0f, - Radius = 30.0f - } - ]; - - public Node[] Nodes { get; } - - public Material[] Materials { get; } - - public Buffer Vertices { get; } - - public Buffer Indices { get; } - - public BottomLevelAccelerationStructure? BLAS { get; } - - public TopLevelAccelerationStructure? TLAS { get; } - - public void UI() - { - ImGui.SliderFloat("Time of Day", ref directionalLightProgress, 0.0f, 1.0f); - } - - protected override void Destroy() - { - foreach (Material material in Materials) - { - material.Dispose(); - } - - TLAS?.Dispose(); - BLAS?.Dispose(); - Indices.Dispose(); - Vertices.Dispose(); - } - - private static void ProcessNode(GNode node, List nodes, List vertices, List indices) - { - Matrix4x4 worldMatrix = node.WorldMatrix * Matrix4x4.CreateScale(6.0f); - - foreach (GNode children in node.VisualChildren) - { - ProcessNode(children, nodes, vertices, indices); - } - - if (node.Mesh is null) - { - return; - } - - foreach (MeshPrimitive primitive in node.Mesh.Primitives) - { - IndirectDrawIndexedArgs args = new() - { - IndexCount = (uint)primitive.IndexAccessor.Count, - InstanceCount = 1, - FirstIndex = (uint)indices.Count, - VertexOffset = vertices.Count - }; - - primitive.VertexAccessors.TryGetValue("POSITION", out Accessor? positionAccessor); - primitive.VertexAccessors.TryGetValue("NORMAL", out Accessor? normalAccessor); - primitive.VertexAccessors.TryGetValue("TEXCOORD_0", out Accessor? texCoordAccessor); - primitive.VertexAccessors.TryGetValue("COLOR_0", out Accessor? colorAccessor); - - IList? positions = positionAccessor?.AsVector3Array(); - IList? normals = normalAccessor?.AsVector3Array(); - IList? texCoords = texCoordAccessor?.AsVector2Array(); - IList? colors = colorAccessor?.AsVector4Array(); - - uint vertexCount = (uint)(positionAccessor?.Count ?? 0); - - for (int i = 0; i < vertexCount; i++) - { - vertices.Add(new() - { - Position = Vector3.Transform(positions?[i] ?? Vector3.Zero, worldMatrix), - Normal = Vector3.Normalize(Vector3.TransformNormal(normals?[i] ?? Vector3.UnitY, worldMatrix)), - TexCoord = texCoords?[i] ?? Vector2.Zero, - Color = colors?[i] ?? Vector4.One - }); - } - - indices.AddRange(primitive.IndexAccessor.AsIndicesArray()); - nodes.Add(new(node.Name, vertexCount, args, (uint)primitive.Material.LogicalIndex)); - } - } - - private static void AddSphere(Vector3 center, float radius, uint material, List nodes, List vertices, List indices) - { - const uint segments = 16; - const uint rings = 16; - - uint baseIndex = (uint)vertices.Count; - uint firstIndex = (uint)indices.Count; - - for (uint ring = 0; ring <= rings; ring++) - { - float phi = MathF.PI * ring / rings; - float y = MathF.Cos(phi); - float ringRadius = MathF.Sin(phi); - - for (uint segment = 0; segment <= segments; segment++) - { - float theta = 2.0f * MathF.PI * segment / segments; - Vector3 normal = new(ringRadius * MathF.Cos(theta), y, ringRadius * MathF.Sin(theta)); - - vertices.Add(new() - { - Position = (normal * radius) + center, - Normal = normal, - TexCoord = new((float)segment / segments, (float)ring / rings), - Color = Vector4.One - }); - } - } - - for (uint ring = 0; ring < rings; ring++) - { - for (uint segment = 0; segment < segments; segment++) - { - uint current = (ring * (segments + 1)) + segment; - uint next = current + segments + 1; - - indices.AddRange([current, next, current + 1, current + 1, next, next + 1]); - } - } - - nodes.Add(new($"EmissiveSphere_{center}", (rings + 1) * (segments + 1), new() - { - IndexCount = rings * segments * 6, - InstanceCount = 1, - FirstIndex = firstIndex, - VertexOffset = (int)baseIndex - }, material)); - } -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Models/Vertex.cs b/sources/Experiments/SponzaScene/Models/Vertex.cs deleted file mode 100644 index 89e53117..00000000 --- a/sources/Experiments/SponzaScene/Models/Vertex.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Numerics; -using Zenith.NET; - -namespace SponzaScene.Models; - -internal struct Vertex -{ - public Vector3 Position; - - public Vector3 Normal; - - public Vector2 TexCoord; - - public Vector4 Color; - - public static InputLayout InputLayout() - { - InputLayout layout = new(); - layout.Add(new() { Format = ElementFormat.Float3, Semantic = ElementSemantic.Position }); - layout.Add(new() { Format = ElementFormat.Float3, Semantic = ElementSemantic.Normal }); - layout.Add(new() { Format = ElementFormat.Float2, Semantic = ElementSemantic.TexCoord }); - layout.Add(new() { Format = ElementFormat.Float4, Semantic = ElementSemantic.Color }); - - return layout; - } -} diff --git a/sources/Experiments/SponzaScene/Program.cs b/sources/Experiments/SponzaScene/Program.cs deleted file mode 100644 index 90ccf408..00000000 --- a/sources/Experiments/SponzaScene/Program.cs +++ /dev/null @@ -1,3 +0,0 @@ -using SponzaScene; - -App.Run(); \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Renderer/DeferredRenderer.cs b/sources/Experiments/SponzaScene/Renderer/DeferredRenderer.cs deleted file mode 100644 index cb883cb7..00000000 --- a/sources/Experiments/SponzaScene/Renderer/DeferredRenderer.cs +++ /dev/null @@ -1,123 +0,0 @@ -using Hexa.NET.ImGui; -using SponzaScene.Models; -using SponzaScene.Renderer.Passes; -using Zenith.NET; - -namespace SponzaScene.Renderer; - -internal class DeferredRenderer : DisposableObject -{ - private readonly RenderPass[] passes; - private readonly RenderContext context; - - public DeferredRenderer() - { - if (App.Context.Capabilities.RayTracingSupported) - { - passes = - [ - new GBufferPass(), - new CSMPass(), - new RTGIPass(), - new SVGFTemporalPass(), - new SVGFAtrousPass(), - new GTAOPass(), - new GTAOBlurPass(), - new VolumetricLightPass(), - new VolumetricLightBlurPass(), - new BloomPass(), - new LightingPass(), - new ComposePass() - ]; - } - else - { - passes = - [ - new GBufferPass(), - new CSMPass(), - new GTAOPass(), - new GTAOBlurPass(), - new VolumetricLightPass(), - new VolumetricLightBlurPass(), - new BloomPass(), - new LightingPass(), - new ComposePass() - ]; - } - - context = new(); - } - - public void Update(uint width, uint height, CameraController camera) - { - if (context.Width != width || context.Height != height) - { - context.Initialize(width, height); - - foreach (RenderPass pass in passes) - { - pass.Resize(width, height); - } - } - - context.FrameIndex++; - context.View = camera.View; - context.Projection = camera.Projection; - context.NearPlane = camera.NearPlane; - context.FarPlane = camera.FarPlane; - context.CameraPosition = camera.Position; - context.Fov = camera.Fov; - context.AspectRatio = camera.AspectRatio; - } - - public void Render() - { - CommandBuffer commandBuffer = App.Context.Graphics.CommandBuffer(); - - commandBuffer.BeginDebugEvent("Deferred Rendering"); - - foreach (RenderPass pass in passes) - { - pass.Execute(commandBuffer, context); - } - - commandBuffer.EndDebugEvent(); - - commandBuffer.Submit(true); - } - - public void UI() - { - ImGui.GetBackgroundDrawList().AddImage(App.Binding(context.FinalColor!), default, new(context.Width, context.Height)); - - if (ImGui.Begin("Deferred Renderer")) - { - App.Sponza.UI(); - - foreach (RenderPass pass in passes) - { - bool opened = ImGui.CollapsingHeader(pass.Name); - - ImGui.SameLine(ImGui.GetWindowWidth() - 80); - ImGui.Text($"{pass.GpuTime:F2} ms"); - - if (opened) - { - pass.DebugUI(context); - } - } - } - ImGui.End(); - } - - protected override void Destroy() - { - foreach (RenderPass pass in passes) - { - pass.Dispose(); - } - - context.Dispose(); - } -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/BloomPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/BloomPass.cs deleted file mode 100644 index a36973a1..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/BloomPass.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using Zenith.NET; -using Zenith.NET.Extensions.Slang; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class BloomPass : RenderPass -{ - private const uint ThreadGroupSize = 16; - - private readonly Buffer constantBuffer; - private readonly ResourceLayout resourceLayout; - private readonly ComputePipeline pipeline; - - private ResourceTable? horizontalResourceTable; - private ResourceTable? verticalResourceTable; - - private int iterations = 4; - - public BloomPass() : base("Bloom Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(BloomConstants), - StrideInBytes = (uint)sizeof(BloomConstants), - Flags = BufferUsageFlags.Constant - }); - - resourceLayout = App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - - using Shader cs = App.Context.LoadShaderFromFile(GetShaderPath("Bloom"), "CSMain", ShaderStageFlags.Compute); - - pipeline = App.Context.CreateComputePipeline(new() - { - Compute = cs, - ResourceLayout = resourceLayout, - ThreadGroupSizeX = ThreadGroupSize, - ThreadGroupSizeY = ThreadGroupSize, - ThreadGroupSizeZ = 1 - }); - } - - public override void Resize(uint width, uint height) - { - horizontalResourceTable?.Dispose(); - horizontalResourceTable = null; - - verticalResourceTable?.Dispose(); - verticalResourceTable = null; - } - - protected override void ExecuteImpl(CommandBuffer commandBuffer, RenderContext context) - { - EnsureResourceTables(context); - - commandBuffer.CopyTexture(context.Emissive!, - default, - default, - context.VerticalBloom!, - default, - default, - new() { Width = context.Width, Height = context.Height, Depth = 1 }); - - uint dispatchX = (context.Width + ThreadGroupSize - 1) / ThreadGroupSize; - uint dispatchY = (context.Height + ThreadGroupSize - 1) / ThreadGroupSize; - - commandBuffer.SetPipeline(pipeline); - - for (int i = 0; i < iterations; i++) - { - commandBuffer.Upload(constantBuffer, 0, [new BloomConstants() { TexelSize = new(1.0f / context.Width, 0) }]); - - commandBuffer.SetResourceTable(horizontalResourceTable!); - - commandBuffer.Dispatch(dispatchX, dispatchY, 1); - - commandBuffer.Upload(constantBuffer, 0, [new BloomConstants() { TexelSize = new(0, 1.0f / context.Height) }]); - - commandBuffer.SetResourceTable(verticalResourceTable!); - - commandBuffer.Dispatch(dispatchX, dispatchY, 1); - } - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGui.SliderInt("Blur Iterations", ref iterations, 1, 8); - - ImGuiHelper.Image(context.VerticalBloom!); - } - - protected override void Destroy() - { - verticalResourceTable?.Dispose(); - horizontalResourceTable?.Dispose(); - - pipeline.Dispose(); - resourceLayout.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } - - private void EnsureResourceTables(RenderContext context) - { - horizontalResourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = [constantBuffer, context.VerticalBloom!, context.HorizontalBloom!, App.LinearSampler] - }); - - verticalResourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = [constantBuffer, context.HorizontalBloom!, context.VerticalBloom!, App.LinearSampler] - }); - } -} - -file struct BloomConstants -{ - public Vector2 TexelSize; -} diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/CSMPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/CSMPass.cs deleted file mode 100644 index abacf34c..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/CSMPass.cs +++ /dev/null @@ -1,230 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using SponzaScene.Models; -using Zenith.NET; -using Zenith.NET.Extensions.Slang; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class CSMPass : RenderPass -{ - private readonly Buffer argsBuffer; - private readonly Buffer dataBuffer; - private readonly ResourceLayout resourceLayout; - private readonly ResourceTable resourceTable; - private readonly GraphicsPipeline pipeline; - - public CSMPass() : base("CSM Pass") - { - argsBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)(sizeof(IndirectDrawIndexedArgs) * App.Sponza.Nodes.Length), - StrideInBytes = (uint)sizeof(IndirectDrawIndexedArgs), - Flags = BufferUsageFlags.Indirect - }); - argsBuffer.Upload([.. App.Sponza.Nodes.Select(static item => item.Args)], 0); - - dataBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(CSMData), - StrideInBytes = (uint)sizeof(CSMData), - Flags = BufferUsageFlags.Constant - }); - - resourceLayout = App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new ResourceBinding() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Vertex | ShaderStageFlags.Pixel } - ) - }); - - resourceTable = App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = [dataBuffer] - }); - - using Shader vs = App.Context.LoadShaderFromFile(GetShaderPath("CSM"), "VSMain", ShaderStageFlags.Vertex); - using Shader ps = App.Context.LoadShaderFromFile(GetShaderPath("CSM"), "PSMain", ShaderStageFlags.Pixel); - - InputLayout inputLayout = new() - { - Elements = [new() { Format = ElementFormat.Float3, Semantic = ElementSemantic.Position }], - StrideInBytes = (uint)sizeof(Vertex) - }; - - pipeline = App.Context.CreateGraphicsPipeline(new() - { - RenderStates = new() - { - RasterizerState = RasterizerStates.CullFront with - { - DepthBias = 250, - SlopeScaledDepthBias = 3.0f, - DepthBiasClamp = 0.02f - }, - DepthStencilState = DepthStencilStates.Default, - BlendState = BlendStates.Opaque - }, - Vertex = vs, - Pixel = ps, - ResourceLayout = resourceLayout, - InputLayouts = [inputLayout], - PrimitiveTopology = PrimitiveTopology.TriangleList, - Output = RenderContext.CSMOutput - }); - } - - protected override void ExecuteImpl(CommandBuffer commandBuffer, RenderContext context) - { - UpdateCSMDatas(context); - - commandBuffer.SetPipeline(pipeline); - commandBuffer.SetVertexBuffer(App.Sponza.Vertices, 0, 0); - commandBuffer.SetIndexBuffer(App.Sponza.Indices, 0, IndexFormat.UInt32); - commandBuffer.SetResourceTable(resourceTable); - - for (int i = 0; i < RenderContext.CSMSplits.Length; i++) - { - commandBuffer.Upload(dataBuffer, 0, [context.CSMDatas[i]]); - - commandBuffer.BeginRenderPass(context.CSMFrameBuffers![i], ClearValues.Default); - commandBuffer.DrawIndexedIndirect(argsBuffer, 0, (uint)App.Sponza.Nodes.Length); - commandBuffer.EndRenderPass(); - } - } - - protected override void DebugUIImpl(RenderContext context) - { - int splitCount = RenderContext.CSMSplits.Length; - - float spacing = ImGui.GetStyle().ItemSpacing.X; - - Vector2 size = new((ImGui.GetContentRegionAvail().X - (spacing * (splitCount - 1))) / splitCount); - size = size with { Y = size.X }; - - for (int i = 0; i < splitCount; i++) - { - ImGui.BeginGroup(); - ImGui.Text($"Cascade {i}"); - ImGuiHelper.Image(context.CSMTextureViews![i], size); - ImGui.EndGroup(); - - if (i < splitCount - 1) - { - ImGui.SameLine(); - } - } - } - - public override void Resize(uint width, uint height) - { - } - - protected override void Destroy() - { - pipeline.Dispose(); - resourceTable.Dispose(); - resourceLayout.Dispose(); - dataBuffer.Dispose(); - argsBuffer.Dispose(); - - base.Destroy(); - } - - private static Vector4[] GetFrustumCornersWorldSpace(RenderContext context, float nearPlane, float farPlane) - { - Matrix4x4 projection = Matrix4x4.CreatePerspectiveFieldOfView(float.DegreesToRadians(context.Fov), - context.AspectRatio, - nearPlane, - farPlane); - - Matrix4x4.Invert(context.View * projection, out Matrix4x4 invVP); - - Vector4[] frustumCorners = - [ - new(-1, 1, 0, 1), - new( 1, 1, 0, 1), - new( 1, -1, 0, 1), - new(-1, -1, 0, 1), - new(-1, 1, 1, 1), - new( 1, 1, 1, 1), - new( 1, -1, 1, 1), - new(-1, -1, 1, 1) - ]; - - for (int i = 0; i < frustumCorners.Length; i++) - { - Vector4 corner = Vector4.Transform(frustumCorners[i], invVP); - frustumCorners[i] = corner / corner.W; - } - - return frustumCorners; - } - - private static void UpdateCSMDatas(RenderContext context) - { - float previousSplitDist = context.NearPlane; - - Vector3 lightDir = Vector3.Normalize(App.Sponza.DirectionalLight.Direction); - - for (int i = 0; i < RenderContext.CSMSplits.Length; i++) - { - float splitDist = context.FarPlane * RenderContext.CSMSplits[i]; - - Vector4[] frustumCorners = GetFrustumCornersWorldSpace(context, previousSplitDist, splitDist); - - Vector3 center = Vector3.Zero; - foreach (Vector4 corner in frustumCorners) - { - center += new Vector3(corner.X, corner.Y, corner.Z); - } - center /= frustumCorners.Length; - - float radius = 0.0f; - foreach (Vector4 corner in frustumCorners) - { - float distance = Vector3.Distance(new(corner.X, corner.Y, corner.Z), center); - radius = MathF.Max(radius, distance); - } - radius = MathF.Ceiling(radius * 16f) / 16f; - - Vector3 up = MathF.Abs(lightDir.Y) > 0.99f ? Vector3.UnitZ : Vector3.UnitY; - - float shadowDistance = radius * 4.0f; - - Vector3 lightPos = center - (lightDir * shadowDistance); - Matrix4x4 lightView = Matrix4x4.CreateLookAt(lightPos, center, up); - - float texelSize = radius * 2.0f / 4096.0f; - - Vector3 centerLS = Vector3.Transform(center, lightView); - centerLS.X = MathF.Floor(centerLS.X / texelSize) * texelSize; - centerLS.Y = MathF.Floor(centerLS.Y / texelSize) * texelSize; - - Matrix4x4.Invert(lightView, out Matrix4x4 invLightView); - - center = Vector3.Transform(centerLS, invLightView); - lightPos = center - (lightDir * shadowDistance); - lightView = Matrix4x4.CreateLookAt(lightPos, center, up); - - Matrix4x4 lightProjection = Matrix4x4.CreateOrthographic(radius * 2f, - radius * 2f, - 0.1f, - (shadowDistance * 2.0f) + radius); - - context.CSMDatas[i] = new() - { - View = lightView, - Projection = lightProjection, - NearPlane = previousSplitDist, - FarPlane = splitDist - }; - - previousSplitDist = splitDist; - } - } -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/ComposePass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/ComposePass.cs deleted file mode 100644 index f8bad4e5..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/ComposePass.cs +++ /dev/null @@ -1,106 +0,0 @@ -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using Zenith.NET; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class ComposePass : FullscreenPass -{ - private readonly Buffer constantBuffer; - - private ResourceTable? resourceTable; - - private float aoStrength = 1.0f; - private float bloomIntensity = 1.5f; - private float volumetricIntensity = 2.5f; - - public ComposePass() : base("Compose Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(ComposeConstants), - StrideInBytes = (uint)sizeof(ComposeConstants), - Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite - }); - } - - protected override string ShaderName => "Compose"; - - public override void Resize(uint width, uint height) - { - resourceTable?.Dispose(); - resourceTable = null; - } - - protected override ResourceLayout? CreateResourceLayout() - { - return App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - } - - protected override ResourceTable EnsureResourceTable(ResourceLayout resourceLayout, RenderContext context) - { - return resourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - context.LitColor!, - context.GTAOBlurred!, - context.VerticalBloom!, - context.VolumetricLightBlurred!, - context.FinalColor!, - App.PointSampler - ] - }); - } - - protected override void UpdateResources(RenderContext context) - { - constantBuffer.Upload([new ComposeConstants - { - AOStrength = aoStrength, - BloomIntensity = bloomIntensity, - VolumetricIntensity = volumetricIntensity - }], 0); - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGui.SliderFloat("AO Strength", ref aoStrength, 0.0f, 2.0f); - ImGui.SliderFloat("Bloom Intensity", ref bloomIntensity, 0.0f, 2.0f); - ImGui.SliderFloat("Volumetric Intensity", ref volumetricIntensity, 0.0f, 5.0f); - - ImGuiHelper.Image(context.FinalColor!); - } - - protected override void Destroy() - { - resourceTable?.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } -} - -file struct ComposeConstants -{ - public float AOStrength; - - public float BloomIntensity; - - public float VolumetricIntensity; -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/FullscreenPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/FullscreenPass.cs deleted file mode 100644 index 8259ca4f..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/FullscreenPass.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Zenith.NET; -using Zenith.NET.Extensions.Slang; - -namespace SponzaScene.Renderer.Passes; - -internal abstract class FullscreenPass : RenderPass -{ - private const uint ThreadGroupSize = 16; - - private readonly ResourceLayout? resourceLayout; - private readonly ComputePipeline pipeline; - - protected FullscreenPass(string name) : base(name) - { - using Shader cs = App.Context.LoadShaderFromFile(GetShaderPath(ShaderName), "CSMain", ShaderStageFlags.Compute); - - pipeline = App.Context.CreateComputePipeline(new() - { - Compute = cs, - ResourceLayout = resourceLayout = CreateResourceLayout(), - ThreadGroupSizeX = ThreadGroupSize, - ThreadGroupSizeY = ThreadGroupSize, - ThreadGroupSizeZ = 1 - }); - } - - protected abstract string ShaderName { get; } - - protected sealed override void ExecuteImpl(CommandBuffer commandBuffer, RenderContext context) - { - UpdateResources(context); - - ExecuteBefore(commandBuffer, context); - - commandBuffer.SetPipeline(pipeline); - - if (resourceLayout is not null) - { - commandBuffer.SetResourceTable(EnsureResourceTable(resourceLayout, context)); - } - - commandBuffer.Dispatch((context.Width + ThreadGroupSize - 1) / ThreadGroupSize, (context.Height + ThreadGroupSize - 1) / ThreadGroupSize, 1); - - ExecuteAfter(commandBuffer, context); - } - - protected override void Destroy() - { - pipeline.Dispose(); - resourceLayout?.Dispose(); - - base.Destroy(); - } - - protected abstract ResourceLayout? CreateResourceLayout(); - - protected abstract ResourceTable EnsureResourceTable(ResourceLayout resourceLayout, RenderContext context); - - protected abstract void UpdateResources(RenderContext context); - - protected virtual void ExecuteBefore(CommandBuffer commandBuffer, RenderContext context) { } - - protected virtual void ExecuteAfter(CommandBuffer commandBuffer, RenderContext context) { } -} diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/GBufferPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/GBufferPass.cs deleted file mode 100644 index a6bb968d..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/GBufferPass.cs +++ /dev/null @@ -1,308 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using SponzaScene.Models; -using Zenith.NET; -using Zenith.NET.Extensions.Slang; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class GBufferPass : RenderPass -{ - private readonly Buffer cameraBuffer; - private readonly Buffer materialBuffer; - private readonly BufferView[] materialBufferViews; - private readonly ResourceLayout resourceLayout; - private readonly ResourceTable[] resourceTables; - private readonly GraphicsPipeline cullBackPipeline; - private readonly GraphicsPipeline cullNonePipeline; - - public GBufferPass() : base("G-Buffer Pass") - { - cameraBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(CameraConstants), - StrideInBytes = (uint)sizeof(CameraConstants), - Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite - }); - - materialBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)(ZenithHelper.Align((uint)sizeof(MaterialConstants), GraphicsContext.ConstantBufferAlignment) * App.Sponza.Materials.Length), - StrideInBytes = (uint)sizeof(MaterialConstants), - Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite - }); - - materialBufferViews = new BufferView[App.Sponza.Materials.Length]; - - MappedMemory mappedMemory = materialBuffer.Map(); - - for (int i = 0; i < App.Sponza.Materials.Length; i++) - { - uint offsetInBytes = (uint)(ZenithHelper.Align((uint)sizeof(MaterialConstants), GraphicsContext.ConstantBufferAlignment) * i); - - Material material = App.Sponza.Materials[i]; - - *(MaterialConstants*)(mappedMemory.Pointer + offsetInBytes) = new() - { - AlphaCutoff = material.AlphaCutoff, - MetallicFactor = material.MetallicFactor, - RoughnessFactor = material.RoughnessFactor, - EmissiveStrength = material.EmissiveStrength, - BaseColorFactor = material.BaseColorFactor, - EmissiveFactor = material.EmissiveFactor, - Flags = (material.AlphaCutoff > 0 ? MaterialFlags.UseAlphaCutoff : 0) - | (material.BaseColorTexture is not null ? MaterialFlags.HasBaseColorTexture : 0) - | (material.NormalTexture is not null ? MaterialFlags.HasNormalTexture : 0) - | (material.MetallicRoughnessTexture is not null ? MaterialFlags.HasMetallicRoughnessTexture : 0) - }; - - materialBufferViews[i] = App.Context.CreateBufferView(new() - { - Buffer = materialBuffer, - OffsetInBytes = offsetInBytes, - SizeInBytes = (uint)sizeof(MaterialConstants), - StrideInBytes = (uint)sizeof(MaterialConstants) - }); - } - - materialBuffer.Unmap(); - - resourceLayout = App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Vertex | ShaderStageFlags.Pixel }, - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Pixel }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Pixel }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Pixel }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Pixel }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Pixel } - ) - }); - - resourceTables = new ResourceTable[App.Sponza.Materials.Length]; - for (int i = 0; i < App.Sponza.Materials.Length; i++) - { - Material material = App.Sponza.Materials[i]; - - resourceTables[i] = App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - cameraBuffer, - materialBufferViews[i], - material.BaseColorTexture ?? App.FallbackTexture, - material.NormalTexture ?? App.FallbackTexture, - material.MetallicRoughnessTexture ?? App.FallbackTexture, - App.LinearSampler - ] - }); - } - - using Shader vs = App.Context.LoadShaderFromFile(GetShaderPath("GBuffer"), "VSMain", ShaderStageFlags.Vertex); - using Shader ps = App.Context.LoadShaderFromFile(GetShaderPath("GBuffer"), "PSMain", ShaderStageFlags.Pixel); - - cullBackPipeline = App.Context.CreateGraphicsPipeline(new() - { - RenderStates = new() - { - RasterizerState = RasterizerStates.CullBack, - DepthStencilState = DepthStencilStates.Default, - BlendState = BlendStates.Opaque - }, - Vertex = vs, - Pixel = ps, - ResourceLayout = resourceLayout, - InputLayouts = [Vertex.InputLayout()], - PrimitiveTopology = PrimitiveTopology.TriangleList, - Output = RenderContext.GBufferOutput - }); - - cullNonePipeline = App.Context.CreateGraphicsPipeline(new() - { - RenderStates = new() - { - RasterizerState = RasterizerStates.CullNone, - DepthStencilState = DepthStencilStates.Default, - BlendState = BlendStates.Opaque - }, - Vertex = vs, - Pixel = ps, - ResourceLayout = resourceLayout, - InputLayouts = [Vertex.InputLayout()], - PrimitiveTopology = PrimitiveTopology.TriangleList, - Output = RenderContext.GBufferOutput - }); - } - - public override void Resize(uint width, uint height) - { - } - - protected override void ExecuteImpl(CommandBuffer commandBuffer, RenderContext context) - { - cameraBuffer.Upload([new CameraConstants() - { - View = context.View, - Projection = context.Projection, - NearPlane = context.NearPlane, - FarPlane = context.FarPlane - }], 0); - - commandBuffer.BeginRenderPass(context.GBufferFrameBuffer!, ClearValues.Default, resourceTables); - - commandBuffer.SetPipeline(cullBackPipeline); - commandBuffer.SetVertexBuffer(App.Sponza.Vertices, 0, 0); - commandBuffer.SetIndexBuffer(App.Sponza.Indices, 0, IndexFormat.UInt32); - - foreach (Node node in App.Sponza.Nodes) - { - if (App.Sponza.Materials[node.Material].DoubleSided) - { - continue; - } - - commandBuffer.SetResourceTable(resourceTables[node.Material]); - - commandBuffer.DrawIndexed(node.Args.IndexCount, - node.Args.InstanceCount, - node.Args.FirstIndex, - node.Args.VertexOffset, - node.Args.FirstInstance); - } - - commandBuffer.SetPipeline(cullNonePipeline); - commandBuffer.SetVertexBuffer(App.Sponza.Vertices, 0, 0); - commandBuffer.SetIndexBuffer(App.Sponza.Indices, 0, IndexFormat.UInt32); - - foreach (Node node in App.Sponza.Nodes) - { - if (!App.Sponza.Materials[node.Material].DoubleSided) - { - continue; - } - - commandBuffer.SetResourceTable(resourceTables[node.Material]); - - commandBuffer.DrawIndexed(node.Args.IndexCount, - node.Args.InstanceCount, - node.Args.FirstIndex, - node.Args.VertexOffset, - node.Args.FirstInstance); - } - - commandBuffer.EndRenderPass(); - } - - protected override void DebugUIImpl(RenderContext context) - { - Vector2 size = new((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X) / 3.0f); - size = size with { Y = size.X * context.Height / context.Width }; - - ImGui.BeginGroup(); - ImGui.Text("Albedo"); - ImGuiHelper.Image(context.Albedo!, size); - ImGui.EndGroup(); - - ImGui.SameLine(); - - ImGui.BeginGroup(); - ImGui.Text("Normal"); - ImGuiHelper.Image(context.Normal!, size); - ImGui.EndGroup(); - - ImGui.SameLine(); - - ImGui.BeginGroup(); - ImGui.Text("Position"); - ImGuiHelper.Image(context.Position!, size); - ImGui.EndGroup(); - - ImGui.BeginGroup(); - ImGui.Text("Depth"); - ImGuiHelper.Image(context.NormalizedDepth!, size); - ImGui.EndGroup(); - - ImGui.SameLine(); - - ImGui.BeginGroup(); - ImGui.Text("Metallic Roughness"); - ImGuiHelper.Image(context.MetallicRoughness!, size); - ImGui.EndGroup(); - - ImGui.SameLine(); - - ImGui.BeginGroup(); - ImGui.Text("Emissive"); - ImGuiHelper.Image(context.Emissive!, size); - ImGui.EndGroup(); - } - - protected override void Destroy() - { - cullNonePipeline.Dispose(); - cullBackPipeline.Dispose(); - - foreach (ResourceTable resourceTable in resourceTables) - { - resourceTable.Dispose(); - } - - resourceLayout.Dispose(); - - foreach (BufferView view in materialBufferViews) - { - view.Dispose(); - } - - materialBuffer.Dispose(); - cameraBuffer.Dispose(); - - base.Destroy(); - } -} - -[Flags] -file enum MaterialFlags -{ - None = 0, - - UseAlphaCutoff = 1 << 0, - - HasBaseColorTexture = 1 << 1, - - HasNormalTexture = 1 << 2, - - HasMetallicRoughnessTexture = 1 << 3 -} - -file struct CameraConstants -{ - public Matrix4x4 View; - - public Matrix4x4 Projection; - - public float NearPlane; - - public float FarPlane; -} - -file struct MaterialConstants -{ - public float AlphaCutoff; - - public float MetallicFactor; - - public float RoughnessFactor; - - public float EmissiveStrength; - - public Vector4 BaseColorFactor; - - public Vector4 EmissiveFactor; - - public MaterialFlags Flags; -} diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/GTAOBlurPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/GTAOBlurPass.cs deleted file mode 100644 index e44f5500..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/GTAOBlurPass.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using Zenith.NET; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class GTAOBlurPass : FullscreenPass -{ - private readonly Buffer constantBuffer; - - private ResourceTable? resourceTable; - - private int blurSize = 4; - - public GTAOBlurPass() : base("GTAO Blur Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(BlurConstants), - StrideInBytes = (uint)sizeof(BlurConstants), - Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite - }); - } - - protected override string ShaderName => "GTAOBlur"; - - public override void Resize(uint width, uint height) - { - resourceTable?.Dispose(); - resourceTable = null; - } - - protected override ResourceLayout? CreateResourceLayout() - { - return App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - } - - protected override ResourceTable EnsureResourceTable(ResourceLayout resourceLayout, RenderContext context) - { - return resourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - context.Position!, - context.GTAO!, - context.GTAOBlurred!, - App.PointSampler - ] - }); - } - - protected override void UpdateResources(RenderContext context) - { - constantBuffer.Upload([new BlurConstants - { - TexelSize = new(1.0f / context.Width, 1.0f / context.Height), - BlurSize = blurSize - }], 0); - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGui.SliderInt("Blur Size", ref blurSize, 1, 8); - - ImGuiHelper.Image(context.GTAOBlurred!); - } - - protected override void Destroy() - { - resourceTable?.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } -} - -file struct BlurConstants -{ - public Vector2 TexelSize; - - public int BlurSize; -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/GTAOPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/GTAOPass.cs deleted file mode 100644 index a2685f24..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/GTAOPass.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using Zenith.NET; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class GTAOPass : FullscreenPass -{ - private readonly Buffer constantBuffer; - - private ResourceTable? resourceTable; - - private float effectRadius = 1.5f; - private float effectFalloffRange = 2.0f; - private float radiusMultiplier = 1.2f; - private float finalValuePower = 1.5f; - private float sampleDistributionPower = 2.0f; - private int sliceCount = 3; - private int stepsPerSlice = 4; - - public GTAOPass() : base("GTAO Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(GTAOConstants), - StrideInBytes = (uint)sizeof(GTAOConstants), - Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite - }); - } - - protected override string ShaderName => "GTAO"; - - public override void Resize(uint width, uint height) - { - resourceTable?.Dispose(); - resourceTable = null; - } - - protected override ResourceLayout? CreateResourceLayout() - { - return App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - } - - protected override ResourceTable EnsureResourceTable(ResourceLayout resourceLayout, RenderContext context) - { - return resourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - context.Position!, - context.Normal!, - context.GTAO!, - App.PointSampler - ] - }); - } - - protected override void UpdateResources(RenderContext context) - { - constantBuffer.Upload([new GTAOConstants - { - View = context.View, - Projection = context.Projection, - ViewportSize = new(context.Width, context.Height), - EffectRadius = effectRadius, - EffectFalloffRange = effectFalloffRange, - RadiusMultiplier = radiusMultiplier, - FinalValuePower = finalValuePower, - SampleDistributionPower = sampleDistributionPower, - SliceCount = sliceCount, - StepsPerSlice = stepsPerSlice - }], 0); - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGui.SliderFloat("Effect Radius", ref effectRadius, 0.5f, 10.0f); - ImGui.SliderFloat("Falloff Range", ref effectFalloffRange, 0.5f, 4.0f); - ImGui.SliderFloat("Radius Multiplier", ref radiusMultiplier, 0.5f, 5.0f); - ImGui.SliderFloat("Final Value Power", ref finalValuePower, 0.5f, 3.0f); - ImGui.SliderFloat("Sample Distribution Power", ref sampleDistributionPower, 1.0f, 3.0f); - ImGui.SliderInt("Slice Count", ref sliceCount, 2, 12); - ImGui.SliderInt("Steps Per Slice", ref stepsPerSlice, 2, 16); - - ImGuiHelper.Image(context.GTAO!); - } - - protected override void Destroy() - { - resourceTable?.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } -} - -file struct GTAOConstants -{ - public Matrix4x4 View; - - public Matrix4x4 Projection; - - public Vector2 ViewportSize; - - public float EffectRadius; - - public float EffectFalloffRange; - - public float RadiusMultiplier; - - public float FinalValuePower; - - public float SampleDistributionPower; - - public int SliceCount; - - public int StepsPerSlice; -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/LightingPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/LightingPass.cs deleted file mode 100644 index e7e672af..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/LightingPass.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System.Numerics; -using SponzaScene.Helpers; -using SponzaScene.Models; -using Zenith.NET; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class LightingPass : FullscreenPass -{ - private readonly Buffer constantBuffer; - private readonly Buffer pointLightsBuffer; - private readonly Buffer csmDatasBuffer; - - private ResourceTable? resourceTable; - - public LightingPass() : base("Lighting Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(LightingConstants), - StrideInBytes = (uint)sizeof(LightingConstants), - Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite - }); - - pointLightsBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)(sizeof(PointLight) * App.Sponza.PointLights.Length), - StrideInBytes = (uint)sizeof(PointLight), - Flags = BufferUsageFlags.ShaderResource - }); - pointLightsBuffer.Upload(App.Sponza.PointLights, 0); - - csmDatasBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)(sizeof(CSMData) * RenderContext.CSMSplits.Length), - StrideInBytes = (uint)sizeof(CSMData), - Flags = BufferUsageFlags.ShaderResource - }); - } - - protected override string ShaderName => "Lighting"; - - public override void Resize(uint width, uint height) - { - resourceTable?.Dispose(); - resourceTable = null; - } - - protected override ResourceLayout? CreateResourceLayout() - { - return App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - } - - protected override ResourceTable EnsureResourceTable(ResourceLayout resourceLayout, RenderContext context) - { - return resourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - pointLightsBuffer, - csmDatasBuffer, - context.Albedo!, - context.Normal!, - context.Position!, - context.MetallicRoughness!, - context.Emissive!, - context.CSMDepths!, - context.GTAOBlurred!, - context.RTGI!, - context.LitColor!, - App.PointSampler, - App.ShadowSampler - ] - }); - } - - protected override void UpdateResources(RenderContext context) - { - Matrix4x4.Invert(context.View * context.Projection, out Matrix4x4 inverseViewProjection); - - constantBuffer.Upload([new LightingConstants - { - CameraPosition = new(context.CameraPosition, 1.0f), - InverseViewProjection = inverseViewProjection, - DirectionalLight = App.Sponza.DirectionalLight - }], 0); - - csmDatasBuffer.Upload(context.CSMDatas, 0); - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGuiHelper.Image(context.LitColor!); - } - - protected override void Destroy() - { - resourceTable?.Dispose(); - csmDatasBuffer.Dispose(); - pointLightsBuffer.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } -} - -file struct LightingConstants -{ - public Vector4 CameraPosition; - - public Matrix4x4 InverseViewProjection; - - public DirectionalLight DirectionalLight; -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/RTGIPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/RTGIPass.cs deleted file mode 100644 index b7c06bc8..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/RTGIPass.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using SponzaScene.Models; -using Zenith.NET; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class RTGIPass : FullscreenPass -{ - private readonly Buffer constantBuffer; - private readonly Buffer pointLightsBuffer; - - private ResourceTable? resourceTable; - - private float intensity = 1.0f; - - public RTGIPass() : base("RTGI Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(RTGIConstants), - StrideInBytes = (uint)sizeof(RTGIConstants), - Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite - }); - - pointLightsBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)(sizeof(PointLight) * App.Sponza.PointLights.Length), - StrideInBytes = (uint)sizeof(PointLight), - Flags = BufferUsageFlags.ShaderResource - }); - pointLightsBuffer.Upload(App.Sponza.PointLights, 0); - } - - protected override string ShaderName => "RTGI"; - - public override void Resize(uint width, uint height) - { - resourceTable?.Dispose(); - resourceTable = null; - } - - protected override ResourceLayout? CreateResourceLayout() - { - return App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.AccelerationStructure, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - } - - protected override ResourceTable EnsureResourceTable(ResourceLayout resourceLayout, RenderContext context) - { - return resourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - App.Sponza.TLAS!, - pointLightsBuffer, - context.Albedo!, - context.Normal!, - context.Position!, - context.NormalizedDepth!, - context.RTGI!, - App.LinearSampler - ] - }); - } - - protected override void UpdateResources(RenderContext context) - { - constantBuffer.Upload([new RTGIConstants - { - Width = context.Width, - Height = context.Height, - FrameIndex = context.FrameIndex, - Intensity = intensity, - ViewProjection = context.View * context.Projection, - DirectionalLight = App.Sponza.DirectionalLight - }], 0); - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGui.SliderFloat("Intensity", ref intensity, 0.0f, 3.0f); - - ImGuiHelper.Image(context.RTGI!); - } - - protected override void Destroy() - { - resourceTable?.Dispose(); - pointLightsBuffer.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } -} - -file struct RTGIConstants -{ - public uint Width; - - public uint Height; - - public uint FrameIndex; - - public float Intensity; - - public Matrix4x4 ViewProjection; - - public DirectionalLight DirectionalLight; -} diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/RenderPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/RenderPass.cs deleted file mode 100644 index 12b53fcd..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/RenderPass.cs +++ /dev/null @@ -1,121 +0,0 @@ -using Zenith.NET; - -namespace SponzaScene.Renderer.Passes; - -internal abstract class RenderPass : DisposableObject -{ - private readonly QueryHeap queryHeap; - - protected RenderPass(string name) - { - Name = name; - - queryHeap = App.Context.CreateQueryHeap(new() - { - Type = QueryType.Timestamp, - Count = 2 - }); - } - - public string Name { get; } - - public double GpuTime - { - get - { - ulong[] timestamps = new ulong[2]; - queryHeap.GetResults(timestamps, 0); - - return (timestamps[1] - timestamps[0]) / 1000000.0; - } - } - - public void Execute(CommandBuffer commandBuffer, RenderContext context) - { - commandBuffer.WriteTimestamp(queryHeap, 0); - - commandBuffer.BeginDebugEvent(Name); - - ExecuteImpl(commandBuffer, context); - - commandBuffer.EndDebugEvent(); - - commandBuffer.WriteTimestamp(queryHeap, 1); - } - - public void DebugUI(RenderContext context) - { - DebugUIImpl(context); - } - - public abstract void Resize(uint width, uint height); - - protected abstract void ExecuteImpl(CommandBuffer commandBuffer, RenderContext context); - - protected abstract void DebugUIImpl(RenderContext context); - - protected override void Destroy() - { - queryHeap.Dispose(); - } - - protected static string GetShaderPath(string shaderName) - { - return Path.Combine(AppContext.BaseDirectory, "Assets", "Shaders", $"{shaderName}.slang"); - } - - protected static ResourceBinding[] Bindings(params ResourceBinding[] bindings) - { - switch (App.Context.Backend) - { - case Backend.DirectX12: - { - uint cbvIndex = 0; - uint srvIndex = 0; - uint uavIndex = 0; - uint samplerIndex = 0; - - for (int i = 0; i < bindings.Length; i++) - { - ref ResourceBinding binding = ref bindings[i]; - - switch (binding.Type) - { - case ResourceType.ConstantBuffer: - binding = binding with { Index = cbvIndex++ }; - break; - - case ResourceType.StructuredBuffer: - case ResourceType.Texture: - case ResourceType.AccelerationStructure: - binding = binding with { Index = srvIndex++ }; - break; - - case ResourceType.StructuredBufferReadWrite: - case ResourceType.TextureReadWrite: - binding = binding with { Index = uavIndex++ }; - break; - - case ResourceType.Sampler: - binding = binding with { Index = samplerIndex++ }; - break; - } - } - } - break; - - case Backend.Vulkan: - { - for (int i = 0; i < bindings.Length; i++) - { - ref ResourceBinding binding = ref bindings[i]; - - binding = binding with { Index = (uint)i }; - } - } - break; - } - - return bindings; - } -} diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/SVGFAtrousPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/SVGFAtrousPass.cs deleted file mode 100644 index d8f1ceb4..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/SVGFAtrousPass.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using Zenith.NET; -using Zenith.NET.Extensions.Slang; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class SVGFAtrousPass : RenderPass -{ - private const uint ThreadGroupSize = 16; - - private readonly Buffer constantBuffer; - private readonly ResourceLayout resourceLayout; - private readonly ComputePipeline pipeline; - - private ResourceTable? readPingWritePong; - private ResourceTable? readPongWritePing; - - private int iterations = 6; - private float phiColor = 2.0f; - private float phiNormal = 32.0f; - private float phiDepth = 0.05f; - - public SVGFAtrousPass() : base("SVGF A-Trous Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(AtrousConstants), - StrideInBytes = (uint)sizeof(AtrousConstants), - Flags = BufferUsageFlags.Constant - }); - - resourceLayout = App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - - using Shader cs = App.Context.LoadShaderFromFile(GetShaderPath("SVGFAtrous"), "CSMain", ShaderStageFlags.Compute); - - pipeline = App.Context.CreateComputePipeline(new() - { - Compute = cs, - ResourceLayout = resourceLayout, - ThreadGroupSizeX = ThreadGroupSize, - ThreadGroupSizeY = ThreadGroupSize, - ThreadGroupSizeZ = 1 - }); - } - - public override void Resize(uint width, uint height) - { - readPingWritePong?.Dispose(); - readPingWritePong = null; - - readPongWritePing?.Dispose(); - readPongWritePing = null; - } - - protected override void ExecuteImpl(CommandBuffer commandBuffer, RenderContext context) - { - EnsureResourceTables(context); - - uint dispatchX = (context.Width + ThreadGroupSize - 1) / ThreadGroupSize; - uint dispatchY = (context.Height + ThreadGroupSize - 1) / ThreadGroupSize; - - commandBuffer.SetPipeline(pipeline); - - bool writeToPong = true; - - for (int i = 0; i < iterations; i++) - { - AtrousConstants constants = new() - { - ViewportSize = new Vector2(context.Width, context.Height), - StepWidth = 1 << i, - PhiColor = phiColor, - PhiNormal = phiNormal, - PhiDepth = phiDepth - }; - - commandBuffer.Upload(constantBuffer, 0, [constants]); - commandBuffer.SetResourceTable(writeToPong ? readPingWritePong! : readPongWritePing!); - commandBuffer.Dispatch(dispatchX, dispatchY, 1); - - writeToPong = !writeToPong; - } - - if (writeToPong) - { - commandBuffer.CopyTexture(context.SVGFPingPong!, - default, - default, - context.RTGI!, - default, - default, - new() { Width = context.Width, Height = context.Height, Depth = 1 }); - } - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGui.SliderInt("Iterations", ref iterations, 1, 7); - ImGui.SliderFloat("Phi Color", ref phiColor, 0.1f, 10.0f); - ImGui.SliderFloat("Phi Normal", ref phiNormal, 4.0f, 128.0f); - ImGui.SliderFloat("Phi Depth", ref phiDepth, 0.01f, 1.0f); - - ImGuiHelper.Image(context.RTGI!); - } - - protected override void Destroy() - { - readPongWritePing?.Dispose(); - readPingWritePong?.Dispose(); - - pipeline.Dispose(); - resourceLayout.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } - - private void EnsureResourceTables(RenderContext context) - { - readPingWritePong ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - context.SVGFPingPong!, - context.Position!, - context.Normal!, - context.RTGI! - ] - }); - - readPongWritePing ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - context.RTGI!, - context.Position!, - context.Normal!, - context.SVGFPingPong! - ] - }); - } -} - -file struct AtrousConstants -{ - public Vector2 ViewportSize; - - public int StepWidth; - - public float PhiColor; - - public float PhiNormal; - - public float PhiDepth; -} diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/SVGFTemporalPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/SVGFTemporalPass.cs deleted file mode 100644 index 36364f97..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/SVGFTemporalPass.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using Zenith.NET; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class SVGFTemporalPass : FullscreenPass -{ - private readonly Buffer constantBuffer; - - private ResourceTable? resourceTable; - private Matrix4x4 prevViewProjection; - - private float colorBoxSigma = 2.0f; - private float normalThreshold = 0.95f; - private float depthThreshold = 0.02f; - private int maxHistoryLength = 32; - - public SVGFTemporalPass() : base("SVGF Temporal Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(TemporalConstants), - StrideInBytes = (uint)sizeof(TemporalConstants), - Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite - }); - } - - protected override string ShaderName => "SVGFTemporal"; - - public override void Resize(uint width, uint height) - { - resourceTable?.Dispose(); - resourceTable = null; - } - - protected override ResourceLayout? CreateResourceLayout() - { - return App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - } - - protected override ResourceTable EnsureResourceTable(ResourceLayout resourceLayout, RenderContext context) - { - return resourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - context.RTGI!, - context.Position!, - context.Normal!, - context.HistoryPosition!, - context.HistoryNormal!, - context.RTGIHistoryAccumulated!, - context.RTGIHistoryMoments!, - context.RTGIAccumulated!, - context.RTGIMoments!, - context.SVGFPingPong!, - App.LinearSampler - ] - }); - } - - protected override void UpdateResources(RenderContext context) - { - constantBuffer.Upload([new TemporalConstants - { - PrevViewProjection = prevViewProjection, - ViewportSize = new Vector2(context.Width, context.Height), - ColorBoxSigma = colorBoxSigma, - NormalThreshold = normalThreshold, - DepthThreshold = depthThreshold, - MaxHistoryLength = maxHistoryLength - }], 0); - } - - protected override void ExecuteBefore(CommandBuffer commandBuffer, RenderContext context) - { - commandBuffer.CopyTexture(context.Position!, - default, - default, - context.HistoryPosition!, - default, - default, - new() { Width = context.Width, Height = context.Height, Depth = 1 }); - - commandBuffer.CopyTexture(context.Normal!, - default, - default, - context.HistoryNormal!, - default, - default, - new() { Width = context.Width, Height = context.Height, Depth = 1 }); - - commandBuffer.CopyTexture(context.RTGIAccumulated!, - default, - default, - context.RTGIHistoryAccumulated!, - default, - default, - new() { Width = context.Width, Height = context.Height, Depth = 1 }); - - commandBuffer.CopyTexture(context.RTGIMoments!, - default, - default, - context.RTGIHistoryMoments!, - default, - default, - new() { Width = context.Width, Height = context.Height, Depth = 1 }); - - prevViewProjection = context.View * context.Projection; - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGui.SliderFloat("Color Box Sigma", ref colorBoxSigma, 0.5f, 5.0f); - ImGui.SliderFloat("Normal Threshold", ref normalThreshold, 0.8f, 1.0f); - ImGui.SliderFloat("Depth Threshold", ref depthThreshold, 0.001f, 0.1f); - ImGui.SliderInt("Max History Length", ref maxHistoryLength, 4, 64); - - ImGuiHelper.Image(context.SVGFPingPong!); - } - - protected override void Destroy() - { - resourceTable?.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } -} - -file struct TemporalConstants -{ - public Matrix4x4 PrevViewProjection; - - public Vector2 ViewportSize; - - public float ColorBoxSigma; - - public float NormalThreshold; - - public float DepthThreshold; - - public int MaxHistoryLength; -} diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/VolumetricLightBlurPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/VolumetricLightBlurPass.cs deleted file mode 100644 index 6255237d..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/VolumetricLightBlurPass.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using Zenith.NET; -using Zenith.NET.Extensions.Slang; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class VolumetricLightBlurPass : RenderPass -{ - private const uint ThreadGroupSize = 16; - - private readonly Buffer constantBuffer; - private readonly ResourceLayout resourceLayout; - private readonly ComputePipeline pipeline; - - private ResourceTable? horizontalResourceTable; - private ResourceTable? verticalResourceTable; - - private int iterations = 2; - - public VolumetricLightBlurPass() : base("Volumetric Light Blur Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(BlurConstants), - StrideInBytes = (uint)sizeof(BlurConstants), - Flags = BufferUsageFlags.Constant - }); - - resourceLayout = App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - - using Shader cs = App.Context.LoadShaderFromFile(GetShaderPath("VolumetricLightBlur"), "CSMain", ShaderStageFlags.Compute); - - pipeline = App.Context.CreateComputePipeline(new() - { - Compute = cs, - ResourceLayout = resourceLayout, - ThreadGroupSizeX = ThreadGroupSize, - ThreadGroupSizeY = ThreadGroupSize, - ThreadGroupSizeZ = 1 - }); - } - - public override void Resize(uint width, uint height) - { - horizontalResourceTable?.Dispose(); - horizontalResourceTable = null; - - verticalResourceTable?.Dispose(); - verticalResourceTable = null; - } - - protected override void ExecuteImpl(CommandBuffer commandBuffer, RenderContext context) - { - EnsureResourceTables(context); - - uint dispatchX = (context.Width + ThreadGroupSize - 1) / ThreadGroupSize; - uint dispatchY = (context.Height + ThreadGroupSize - 1) / ThreadGroupSize; - - commandBuffer.SetPipeline(pipeline); - - for (int i = 0; i < iterations; i++) - { - commandBuffer.Upload(constantBuffer, 0, [new BlurConstants() { TexelSize = new(1.0f / context.Width, 0) }]); - commandBuffer.SetResourceTable(horizontalResourceTable!); - commandBuffer.Dispatch(dispatchX, dispatchY, 1); - - commandBuffer.Upload(constantBuffer, 0, [new BlurConstants() { TexelSize = new(0, 1.0f / context.Height) }]); - commandBuffer.SetResourceTable(verticalResourceTable!); - commandBuffer.Dispatch(dispatchX, dispatchY, 1); - } - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGui.SliderInt("Blur Iterations", ref iterations, 1, 4); - - ImGuiHelper.Image(context.VolumetricLightBlurred!); - } - - protected override void Destroy() - { - verticalResourceTable?.Dispose(); - horizontalResourceTable?.Dispose(); - - pipeline.Dispose(); - resourceLayout.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } - - private void EnsureResourceTables(RenderContext context) - { - horizontalResourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - context.VolumetricLight!, - context.Position!, - context.VolumetricLightBlurred!, - App.LinearSampler - ] - }); - - verticalResourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - context.VolumetricLightBlurred!, - context.Position!, - context.VolumetricLight!, - App.LinearSampler - ] - }); - } -} - -file struct BlurConstants -{ - public Vector2 TexelSize; -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Renderer/Passes/VolumetricLightPass.cs b/sources/Experiments/SponzaScene/Renderer/Passes/VolumetricLightPass.cs deleted file mode 100644 index 002ddeda..00000000 --- a/sources/Experiments/SponzaScene/Renderer/Passes/VolumetricLightPass.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Numerics; -using Hexa.NET.ImGui; -using SponzaScene.Helpers; -using SponzaScene.Models; -using Zenith.NET; -using Buffer = Zenith.NET.Buffer; - -namespace SponzaScene.Renderer.Passes; - -internal unsafe class VolumetricLightPass : FullscreenPass -{ - private readonly Buffer constantBuffer; - private readonly Buffer csmDatasBuffer; - - private ResourceTable? resourceTable; - - private int sampleCount = 64; - private float intensity = 1.0f; - private float scattering = 0.7f; - private float maxDistance = 100.0f; - - public VolumetricLightPass() : base("Volumetric Light Pass") - { - constantBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)sizeof(VolumetricLightConstants), - StrideInBytes = (uint)sizeof(VolumetricLightConstants), - Flags = BufferUsageFlags.Constant | BufferUsageFlags.MapWrite - }); - - csmDatasBuffer = App.Context.CreateBuffer(new() - { - SizeInBytes = (uint)(sizeof(CSMData) * RenderContext.CSMSplits.Length), - StrideInBytes = (uint)sizeof(CSMData), - Flags = BufferUsageFlags.ShaderResource - }); - } - - protected override string ShaderName => "VolumetricLight"; - - public override void Resize(uint width, uint height) - { - resourceTable?.Dispose(); - resourceTable = null; - } - - protected override ResourceLayout? CreateResourceLayout() - { - return App.Context.CreateResourceLayout(new() - { - Bindings = Bindings - ( - new() { Type = ResourceType.ConstantBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.StructuredBuffer, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Texture, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.TextureReadWrite, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute }, - new() { Type = ResourceType.Sampler, Count = 1, StageFlags = ShaderStageFlags.Compute } - ) - }); - } - - protected override ResourceTable EnsureResourceTable(ResourceLayout resourceLayout, RenderContext context) - { - return resourceTable ??= App.Context.CreateResourceTable(new() - { - Layout = resourceLayout, - Resources = - [ - constantBuffer, - csmDatasBuffer, - context.Position!, - context.CSMDepths!, - context.VolumetricLight!, - App.PointSampler, - App.ShadowSampler - ] - }); - } - - protected override void UpdateResources(RenderContext context) - { - Matrix4x4.Invert(context.View * context.Projection, out Matrix4x4 inverseViewProjection); - - constantBuffer.Upload([new VolumetricLightConstants - { - CameraPosition = new(context.CameraPosition, 1.0f), - LightDirection = new(App.Sponza.DirectionalLight.Direction, 0.0f), - LightColor = new(App.Sponza.DirectionalLight.Color, App.Sponza.DirectionalLight.Intensity), - InverseViewProjection = inverseViewProjection, - ScreenSize = new(context.Width, context.Height), - SampleCount = sampleCount, - Intensity = intensity, - Scattering = scattering, - MaxDistance = maxDistance - }], 0); - - csmDatasBuffer.Upload(context.CSMDatas, 0); - } - - protected override void DebugUIImpl(RenderContext context) - { - ImGui.SliderInt("Sample Count", ref sampleCount, 16, 128); - ImGui.SliderFloat("Intensity", ref intensity, 0.0f, 5.0f); - ImGui.SliderFloat("Scattering", ref scattering, 0.0f, 1.0f); - ImGui.SliderFloat("Max Distance", ref maxDistance, 10.0f, 500.0f); - - ImGuiHelper.Image(context.VolumetricLight!); - } - - protected override void Destroy() - { - resourceTable?.Dispose(); - csmDatasBuffer.Dispose(); - constantBuffer.Dispose(); - - base.Destroy(); - } -} - -file struct VolumetricLightConstants -{ - public Vector4 CameraPosition; - - public Vector4 LightDirection; - - public Vector4 LightColor; - - public Matrix4x4 InverseViewProjection; - - public Vector2 ScreenSize; - - public int SampleCount; - - public float Intensity; - - public float Scattering; - - public float MaxDistance; -} \ No newline at end of file diff --git a/sources/Experiments/SponzaScene/Renderer/RenderContext.cs b/sources/Experiments/SponzaScene/Renderer/RenderContext.cs deleted file mode 100644 index f1656978..00000000 --- a/sources/Experiments/SponzaScene/Renderer/RenderContext.cs +++ /dev/null @@ -1,521 +0,0 @@ -using System.Numerics; -using SponzaScene.Models; -using Zenith.NET; - -namespace SponzaScene.Renderer; - -internal class RenderContext : DisposableObject -{ - public static Output GBufferOutput { get; } = new() - { - ColorAttachments = - [ - PixelFormat.R8G8B8A8UNorm, - PixelFormat.R16G16B16A16Float, - PixelFormat.R16G16B16A16Float, - PixelFormat.R8G8B8A8UNorm, - PixelFormat.R8G8B8A8UNorm, - PixelFormat.R16G16B16A16Float - ], - DepthStencilAttachment = PixelFormat.D32FloatS8UInt, - SampleCount = SampleCount.Count1 - }; - - public static float[] CSMSplits { get; } = [0.1f, 0.3f, 0.6f, 1.0f]; - - public static Output CSMOutput { get; } = new() - { - ColorAttachments = [], - DepthStencilAttachment = PixelFormat.D32Float, - SampleCount = SampleCount.Count1 - }; - - #region Frame Information - public uint Width { get; private set; } - - public uint Height { get; private set; } - - public uint FrameIndex { get; set; } - - public Matrix4x4 View { get; set; } - - public Matrix4x4 Projection { get; set; } - - public float NearPlane { get; set; } - - public float FarPlane { get; set; } - - public Vector3 CameraPosition { get; set; } - - public float Fov { get; set; } - - public float AspectRatio { get; set; } - #endregion - - #region G-Buffer - public Texture? Albedo { get; private set; } - - public Texture? Normal { get; private set; } - - public Texture? Position { get; private set; } - - public Texture? Depth { get; private set; } - - public Texture? NormalizedDepth { get; private set; } - - public Texture? MetallicRoughness { get; private set; } - - public Texture? Emissive { get; private set; } - - public FrameBuffer? GBufferFrameBuffer { get; private set; } - #endregion - - #region Cascaded Shadow Maps - public CSMData[] CSMDatas { get; } = new CSMData[CSMSplits.Length]; - - public Texture? CSMDepths { get; private set; } - - public TextureView[]? CSMTextureViews { get; private set; } - - public FrameBuffer[]? CSMFrameBuffers { get; private set; } - #endregion - - #region SVGF Denoising - public Texture? HistoryPosition { get; private set; } - - public Texture? HistoryNormal { get; private set; } - - public Texture? SVGFPingPong { get; private set; } - - public Texture? RTGIAccumulated { get; private set; } - - public Texture? RTGIMoments { get; private set; } - - public Texture? RTGIHistoryAccumulated { get; private set; } - - public Texture? RTGIHistoryMoments { get; private set; } - #endregion - - #region Intermediate Textures - public Texture? RTGI { get; private set; } - - public Texture? GTAO { get; private set; } - - public Texture? GTAOBlurred { get; private set; } - - public Texture? VolumetricLight { get; private set; } - - public Texture? VolumetricLightBlurred { get; private set; } - - public Texture? HorizontalBloom { get; private set; } - - public Texture? VerticalBloom { get; private set; } - - public Texture? LitColor { get; private set; } - #endregion - - public Texture? FinalColor { get; private set; } - - public void Initialize(uint width, uint height) - { - Destroy(); - - Albedo = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R8G8B8A8UNorm, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.RenderTarget | TextureUsageFlags.ShaderResource - }); - - Normal = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.RenderTarget | TextureUsageFlags.ShaderResource - }); - - Position = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.RenderTarget | TextureUsageFlags.ShaderResource - }); - - Depth = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.D32FloatS8UInt, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.DepthStencil | TextureUsageFlags.ShaderResource - }); - - NormalizedDepth = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R8G8B8A8UNorm, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.RenderTarget | TextureUsageFlags.ShaderResource - }); - - MetallicRoughness = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R8G8B8A8UNorm, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.RenderTarget | TextureUsageFlags.ShaderResource - }); - - Emissive = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.RenderTarget | TextureUsageFlags.ShaderResource - }); - - GBufferFrameBuffer = App.Context.CreateFrameBuffer(new() - { - ColorAttachments = - [ - new() { Target = Albedo }, - new() { Target = Normal }, - new() { Target = Position }, - new() { Target = NormalizedDepth }, - new() { Target = MetallicRoughness }, - new() { Target = Emissive } - ], - DepthStencilAttachment = new() { Target = Depth } - }); - - CSMDepths = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2DArray, - Format = PixelFormat.D32Float, - Width = 4096, - Height = 4096, - Depth = 1, - MipLevels = 1, - ArrayLayers = (uint)CSMSplits.Length, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.DepthStencil | TextureUsageFlags.ShaderResource - }); - - CSMTextureViews = new TextureView[CSMSplits.Length]; - CSMFrameBuffers = new FrameBuffer[CSMSplits.Length]; - for (int i = 0; i < CSMSplits.Length; i++) - { - CSMTextureViews[i] = App.Context.CreateTextureView(new() - { - Texture = CSMDepths, - MipLevelCount = 1, - FirstArrayLayer = (uint)i, - ArrayLayerCount = 1 - }); - - CSMFrameBuffers[i] = App.Context.CreateFrameBuffer(new() - { - ColorAttachments = [], - DepthStencilAttachment = new() { Target = CSMDepths, Slice = new() { ArrayLayer = (uint)i } } - }); - } - - HistoryPosition = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - HistoryNormal = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - SVGFPingPong = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - RTGIAccumulated = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - RTGIMoments = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - RTGIHistoryAccumulated = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - RTGIHistoryMoments = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - RTGI = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - GTAO = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R8UNorm, - Width = width / 4, - Height = height / 4, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - GTAOBlurred = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R8UNorm, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - VolumetricLight = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16Float, - Width = width / 4, - Height = height / 4, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - VolumetricLightBlurred = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - HorizontalBloom = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - VerticalBloom = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - LitColor = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R16G16B16A16Float, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - FinalColor = App.Context.CreateTexture(new() - { - Type = TextureType.Texture2D, - Format = PixelFormat.R8G8B8A8UNorm, - Width = width, - Height = height, - Depth = 1, - MipLevels = 1, - ArrayLayers = 1, - SampleCount = SampleCount.Count1, - Flags = TextureUsageFlags.ShaderResource | TextureUsageFlags.UnorderedAccess - }); - - Width = width; - Height = height; - FrameIndex = 0; - } - - protected override void Destroy() - { - FinalColor?.Dispose(); - - LitColor?.Dispose(); - VerticalBloom?.Dispose(); - HorizontalBloom?.Dispose(); - VolumetricLightBlurred?.Dispose(); - VolumetricLight?.Dispose(); - GTAOBlurred?.Dispose(); - GTAO?.Dispose(); - RTGI?.Dispose(); - - RTGIHistoryMoments?.Dispose(); - RTGIHistoryAccumulated?.Dispose(); - RTGIMoments?.Dispose(); - RTGIAccumulated?.Dispose(); - SVGFPingPong?.Dispose(); - HistoryNormal?.Dispose(); - HistoryPosition?.Dispose(); - - if (CSMFrameBuffers is not null) - { - foreach (FrameBuffer frameBuffer in CSMFrameBuffers) - { - frameBuffer.Dispose(); - } - } - - if (CSMTextureViews is not null) - { - foreach (TextureView textureView in CSMTextureViews) - { - textureView.Dispose(); - } - } - - CSMDepths?.Dispose(); - - GBufferFrameBuffer?.Dispose(); - Emissive?.Dispose(); - MetallicRoughness?.Dispose(); - NormalizedDepth?.Dispose(); - Depth?.Dispose(); - Position?.Dispose(); - Normal?.Dispose(); - Albedo?.Dispose(); - } -} diff --git a/sources/Extensions/Zenith.NET.Extensions.ImGui/ImGuiRenderer.cs b/sources/Extensions/Zenith.NET.Extensions.ImGui/ImGuiRenderer.cs index dd447629..99b5f875 100644 --- a/sources/Extensions/Zenith.NET.Extensions.ImGui/ImGuiRenderer.cs +++ b/sources/Extensions/Zenith.NET.Extensions.ImGui/ImGuiRenderer.cs @@ -63,13 +63,13 @@ float4 PSMain(VSOutput input) : SV_TARGET private readonly string[] Dxil = [ // Vertex Shader - Legacy - "44584243B88166074E68703A034EB95DBF613956010000001C130000070000003C0000004C000000D40000006001000090020000FC090000180A0000534649300800000000000000000000004953473180000000030000000800000000000000680000000000000000000000030000000000000003030000000000000000000071000000000000000000000003000000010000000303000000000000000000007A000000000000000000000003000000020000000F0F000000000000504F534954494F4E00544558434F4F524400434F4C4F52004F5347318400000003000000080000000000000068000000000000000100000003000000000000000F00000000000000000000007400000000000000000000000300000001000000030C000000000000000000007D000000000000000000000003000000020000000F0000000000000053565F506F736974696F6E00544558434F4F524400434F4C4F5200005053563028010000340000000100000000000000000000000000000000000000FFFFFFFF010000000303000303000000000000000000000000000000280000000100000018000000020000000000000000000000000000000D000000000000003000000000504F534954494F4E00544558434F4F524400434F4C4F5200544558434F4F524400434F4C4F520056534D61696E0000010000000000000010000000010000000000000001004200030000000A000000000000000101420003000000130000000000000001024400030000000000000000000000010044030304000019000000000000000101420003020000220000000000000001024400030200000F0000000F00000000000000000000001000000020000000000000000000000000010000000200000004000000080000535441546407000066000100D90100004458494C06010000100000004C0700004243C0DE210C0000D00100000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000004000000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1090C11C0118640040C108400906226600E60890621800001C0021C5180000380C528E1A2E7FC21E42F2B98D2A5662F28BDB46846118061DF70C973F610F21F921D00C0B8182A6100CE000F494C2000CC3A0E8B6E1F227EC21247F2524878A04228D9C87882684909000008570006722EAA0E1F227EC21247F25A40D690644000070CC1104A570000BB8081B081846208C24D8CE121640927C069822E4F28BC501261FF7711470274953440993CF398D3401CD24FD340ABAABA429A284C9071727009614880046FA691478E7188B13004B0A440023FD340A3E02D3019823000500000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A600774A0F340021932520204E0210CC690870002000000000000000080210F0204400000000000000000431E0508000100000000000000863C0F100003000000000000000C79222000020000000000000018F2504000040000000000000030E4C180000800000000000000200B040016000000321E981819114C908C092647C60443024AA01846000A30A00C8AA010CAA124CAA3F80AA228682C414040043A4A6204A0080AA10CC89B01A06F0680C019000A6700481CCB6198E70100080C0000444008040310142818010079180000A00000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD91004130400992000C9066120260880B241300C0A76731B068420260861E0D139637B130B63830A930B6B9BFB82992000CB06C45016C318186043D06C2000C00126081FC765ECCD6D8E2ECC8D6EEE0B668200301B0822928C0D02334D10BC8D0C94DC9B5AD9185DDA9BDB17CC040168260880B361C0B06182003C130400DA8010D6954986B66D10186E820006DD068258246383C07C1B0E03A2AACE03830942116C00360CC6188CC186800C360C831894C104410CBE0DC119D0B09A6A0A4B732302F534954495F4E4344138AC09C2716D088C09C2816D102469C362A8C11AB0411BB0C1E006061BBC0111AA22ACA1A72729A20DCB10076BC0066DC006831B0C6CF0062C869E989EA4260847364100A20D8254071B966B0ED6800DDA800D063AB8D8C00E360C70200777C065CAEA0BEA6D2E8D2EEDCD6D8270681B16230FD6400FDA800E063A30D8C00E362C431CAC011BB4811B0C6E30B0C11B6C58AE3958033668033718E8E062033BD830EC011FF4C186010FFC0098208C41B54130406143210669F0074F28D030637B0BA39B6391E6364737374100241A7369675F6C64130460A2319776F63547374100A80DC82860A4500AA6700AA8900A55D8D8ECDA5CD2C8CADCE8A6044115323C17BB32B9B9B437B72901D1840CCFC52E8CCDAE4C6E4A60D421C37399430B232B936B7A232B639B122065C8F05CE4CAE6DEEAE4C6CAE6A6044E25323C17BA3CB8B22037B737BA30BAB437B7B929021894411D323C17BBB4B2BB24B229BA30BAB229C119D421C3732973A393CB837A4B73A39B9B12844217323C97B1B73A37BA32B9B929412A00000000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C38CC821077C70037210877370037B080779608770C88777A8077A98813CE4800F6E400FE5D00EF000000071200000220000001660BCAC09208D0130C3E537CE74208DE10366400D97EF3C3ED034CE044C440834C34218C1365CBEF3F84240150511950E3094840108985FDCB61D74C3E53B8F2F4404301121D00C0BF1450EB321CD803486094CC3E53B8FBF38C020360F35F9C56DDB40355CBEF3F8D2E444044A4D0F35F9C56D5B81345CBEF3F813114D0810617E71DB00000000000000004841534814000000000000006AAE23310BBC64551106088544F544414458494CFC080000660001003F0200004458494C0601000010000000E40800004243C0DE210C0000360200000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000004000000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1094C11C0118640040C108400906226600E60890621800001C0021C5180000380C528E1A2E7FC21E42F2B98D2A5662F28BDB46846118061DF70C973F610F21F921D00C0B8182A6100CE000F494C2000CC3A0E8B6E1F227EC21247F2524878A04228D9C87882684909000008570006722EAA0E1F227EC21247F25A40D690644000070CC1104A570000BB8081B081846208C24D8CE121640927C069822E4F28BC501261FF7711470274953440993CF398D3401CD24FD340ABAABA429A284C9071727009614880046FA691478E7188B13004B0A440023FD340A3E02D3019823000502000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A600774A0F340021932520204E0211B431E0200000000000000000000863C08100001000000000000000C79142000040000000000000018F23C40000C0000000000000030E4898000080000000000000060C84301011000000000000000C0900703022000000000000000802C10000012000000321E981419114C908C092647C60443024AA0188A6204A00003CAA008CA83C612040444A0A32446008AA010CA80C2190012C77218E679000002030000111002C10004050A4600000079180000650000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD91004130400992000C9066120260880B241180C0A76731B0684202608C0324108038BC00401603620CAC228CAD0001B02670301000F304110836B43104D108A8086D55453589A1B11A8A7A924AAA427A709C2114D100E6943A04C108E698200341B044DDBB028957561D79029D74684AA086BE8E9498A68C33274D6855D43365CDB040170580C3D313D494D100E6A82003C1B044D0C362C1F185817760D61F05D63B061E03C32E03265F505F536974697F6E6364138AA0D8B6206D6196061308481728DC18665E8AC0BCB866CB8B60DCB0706D6856543187CD7186C18D0200DD460C350066B004C10C600DA20286DB0A198283680DCA00A1B9B5D9B4B1A59991BDD9420A84286E76257263797F6E63625209A90E1B9D885B1D995C94D098C3A64782E7368616465724D6F64656C5302A40C199E8B5CD9DC5B9DDC58D9DC94E0A94386E76297567697443645174657362588EA90E1B994B9D1C9E541BDA5B9D1CD4D09DC00000000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C38CC821077C70037210877370037B080779608770C88777A8077A98813CE4800F6E400FE5D00EF000000071200000220000001660BCAC09208D0130C3E537CE74208DE10366400D97EF3C3ED034CE044C440834C34218C1365CBEF3F84240150511950E3094840108985FDCB61D74C3E53B8F2F4404301121D00C0BF1450EB321CD803486094CC3E53B8FBF38C020360F35F9C56DDB40355CBEF3F8D2E444044A4D0F35F9C56D5B81345CBEF3F813114D0810617E71DB0000000061200000A30000001304412C100000000E0000000414572914C20C40D995EC40C10E94065D2300749400196304200882F847D31C02183064CD412CCB3291310240E450472000C0022C0000002306080082608085813274C788C1018020185063A004C58841028020182068F0701FE68C1824000882019206500706C933629000200806881A445E1864D0884102802018206B207D62804523060900826080B0C1640663C04923060900826080B401750664D04C23060900826080B841550665E05123060900826080BC81650666F054230607008260F0B841959CC16842008C2608C168C2208C2610C388C1018020183C73A0396F309A1000A30942309A3008A309C4306270002008060F1E7C931B8C2604C06882108C260CC26802318C181C000882C1D3076480D1C16842008C2608C168C2208C26108359937C460C100004C120120537B09E60C4000140100CA25178033158821103040041308848010ECCE0084CB3E4336280002008069129C8812605230608008260109DC21C9881138C182000088241840A74A0064A605E269F1103040041308854C10EBC2A183140001004836815EE400DA260C4000140100C2256C00337680213034E3E23060800826010B9821E8801168C182000088241F40A7BE0065430628000200806112CF0811C4001BD0100080E00407100009203008C182400088281720BA0F00AAF800AD188410280201828B7000AAFF00A78D08C182400088281720BA0F00AAF700AC988410280201828B7000AAFF00AA5508C182400088281720BA0200BAF800A6C30629000200806CA2D80822CBC021EACC188410280201828B7000AACF00AA80007230609008260A0DC0228B0C22BE0C11B8C182400088281720BA0C00AAF700A6E30629000200806CA2D80022BBC4229B401CD0100100000000000", + "4458424322A36D6E02DEF08BE6B9959E5635FACE0100000038120000070000003C0000004C000000D40000006001000090020000DC090000F8090000534649300800000000000000000000004953473180000000030000000800000000000000680000000000000000000000030000000000000003030000000000000000000071000000000000000000000003000000010000000303000000000000000000007A000000000000000000000003000000020000000F0F000000000000504F534954494F4E00544558434F4F524400434F4C4F52004F5347318400000003000000080000000000000068000000000000000100000003000000000000000F00000000000000000000007400000000000000000000000300000001000000030C000000000000000000007D000000000000000000000003000000020000000F0000000000000053565F506F736974696F6E00544558434F4F524400434F4C4F5200005053563028010000340000000100000000000000000000000000000000000000FFFFFFFF010000000303000303000000000000000000000000000000280000000100000018000000020000000000000000000000000000000D000000000000003000000000504F534954494F4E00544558434F4F524400434F4C4F5200544558434F4F524400434F4C4F520056534D61696E0000010000000000000010000000010000000000000001004200030000000A000000000000000101420003000000130000000000000001024400030000000000000000000000010044030304000019000000000000000101420003020000220000000000000001024400030200000F0000000F00000000000000000000001000000020000000000000000000000000010000000200000004000000080000535441544407000066000100D10100004458494C06010000100000002C0700004243C0DE210C0000C80100000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000003F00000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1088C1084009000A6600E608C0608E0029C64010444190510C8020886220E4A8E1F227EC21249FDBA8622526BFB86D440CC3305071CF70F913F610921F02CDB01028580AA1100C414D29066218067A6E1B2E7FC21E42F2574272A84820D2C879886842080909045108866022920E1A2E7FC21E42F25742DA906640044110C51C41500A86A0888AAC81806104624882EC2C610124C9678029422EBF581C60F2711F4781769234459430F99CD34813D04CD24FA360BB4A9A224A987C7071026049810860A49F4601778EB13801B0A4400430D24FA3A0232F1D8839025000000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A60077430E4098000000000000000000060C86300011000000000000000C090070102400000000000000080214F0304C00000000000000000439E0708800000000000000000863C12100001000000000000000C792C20000200000000000000C802010016000000321E981419114C908C092647C60443224AA01846000A30A00C8AA010CAA124CAA3200AAC28A82889118022288432A0B000010111A89B01206F0680BE190002C77218E679000002030000111002C1000405E2660000000000791800009F0000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD910041304E2982010C8066120260844B241300C0A76731B06842026081F47E78CED4D2C8C0D2A4C2EAC6DEE0B668240281B1043590C6360800D41B3810000079820741A97B137B739BA3037BAB92F980902B16C208848323608CC3441E03C3250726F6A656374696F6E5F30130482992010CD8601C3860902E14C108867034258572619DAB64160B80982B76D208845323608CCB7E13020AAEA3C30982008C00660C3608CC1186C08C860C3308841194C10C0A0DB109C010DABA9A6B0343722504F534954494F4E1384829A2014D586C0982014D6064192362C861AAC011BB4011B0C6E60B0C11B10A12AC21A7A7A9222DAB00C71B0066CD0066C30B8C1C0066FC062E889E9496A82505C130402DA204875B061B9E6600DD8A00DD860A0838B0DEC60C300077270075CA6ACBEA0DEE6D2E8D2DEDC260805B66131F2600DF4A00DE860A003830DEC60C332C4C11AB0411BB8C1E006031BBCC186E59A83356083367083810E2E36B0830DC31EF0411F6C18F0C00F80094218641B04031436146290067FF084020D33B6B730BAB9090211B148739BA39B9B2010128DB9B4B32F36321A7369675F7374130462DA808C02299482299C0229A0422A546163B36B7349232B73A39B120455C8F05CECCAE4E6D2DEDCA6044413323C17BB3036BB32B9298151870CCF650E2D8CAC4CAEE98DAC8C6D4A809421C373912B9B7BAB931B2B9B9B123895C8F05CE8F2E0CA82DCDCDEE8C2E8D2DEDCE6A60860500675C8F05CECD2CAEE92C8A6E8C2E8CAA6046750870CCFA5CC8D4E2E0FEA2DCD8D6E6E4A100A5DC8F05CC6DEEADCE8CAE4E6A604A900791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C38CC821077C70037210877370037B080779608770C88777A8077A98813CE4800F6E400FE5D00EF0000000712000001F0000000660BCAC09208D1550C3E53B8F0F348D3301131102CDB01036B00D97EF3CBE1050454144A5030C25610002E617B76D06DD70F9CEE30B11014C440834C3427C91C36C4833208D6101D370F9CEE32F0E3088CD434D7E71DB26500D97EF3CBE3439118152D3434D7E71DB46200D97EF3CFE4444130244985FDC360000000000000048415348140000000000000082D156255E85851D3995C0A0E0DA81FE4458494C38080000660001000E0200004458494C0601000010000000200800004243C0DE210C0000050200000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000003F00000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1088C1084009000A6600E608C0608E0029C64010444190510C8020886220E4A8E1F227EC21249FDBA8622526BFB86D440CC3305071CF70F913F610921F02CDB01028580AA1100C414D29066218067A6E1B2E7FC21E42F2574272A84820D2C879886842080909045108866022920E1A2E7FC21E42F25742DA906640044110C51C41500A86A0888AAC81806104624882EC2C610124C9678029422EBF581C60F2711F4781769234459430F99CD34813D04CD24FA360BB4A9A224A987C7071026049810860A49F4601778EB13801B0A4400430D24FA3A0232F1D8839025000000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A60077430E4090000000000000000000060C86300011000000000000000C090070102400000000000000080214F0304C00000000000000000439E0708800000000000000000863C12100001000000000000000C792C20000200000000000000C802010011000000321E981419114C908C092647C60443224AA0188A6204A00003CAA008CA838A92180128824228030A0B10101081C0B11C86791E0080C000004004844030004181BE19000079180000650000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD910041304E2982010C8066120260844B241180C0A76731B0684202608843241F82C02130462D980280BA32843036C089C0D04003CC004010CAA0D41344110001A56534D61696E44A09EA692A8929E9C2608C5334128A00D81324128A20902C16C10346DC3A254D6855D43A65C1B11AA22ACA1A72729A20DCBD05917760DD9706D1304A26131F4C4F424354128A40902E16C103431D8B07C60605DD83584C1778DC18681F3C880CB94D517D4DB5C1A5DDA9BDB04A198362C8A1958678085C11006CA35061B96A1B32E2C1BB2E1DA362C1F185817960D61F05D63B06140833450830D4319AC01304108036A83A0B4C18662A2D80072832A6C6C766D2E6964656E745382A00A199E8B5D99DC5CDA9BDB9480684286E76217C6665726372530EA90E1B9CCA1859195C935BD9195B14D09903264782E7265736F75726365735382A70E199E8B5D5AD95D12D9145D185DD99420AA4386E752E646279707F596E646373725700300000000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C38CC821077C70037210877370037B080779608770C88777A8077A98813CE4800F6E400FE5D00EF0000000712000001F0000000660BCAC09208D1550C3E53B8F0F348D3301131102CDB01036B00D97EF3CBE1050454144A5030C25610002E617B76D06DD70F9CEE30B11014C440834C3427C91C36C4833208D6101D370F9CEE32F0E3088CD434D7E71DB26500D97EF3CBE3439118152D3434D7E71DB46200D97EF3CFE4444130244985FDC36000000612000007A0000001304412C100000000900000044944221CC001457D995EC40C10E9406152540D508005173108AA24414CD21780B000000230608008260607587900D230607008260207D47208C18240008828141060DB655CC8841028020181865E064DCD18C18240008828161068FD659CE8841028020181867006D5EF58C182400088281810691187C1934629000200806461A486300064B34629000200806861A4C6110069B34629000200806C61A50622006CD346270002008068D1A48C9188C2604C06882108C260CC26802318C181C00088241F30697B306A30901309A2004A30983309A400C230607008260D0D00137ADC16842008C2608C168C2208C26108339917C460C100004C1E0C983318894C08C003A0651F219314000100483870FCC8062020B10E89874C967C4000140100C9E3F4883CB092C50A06394269F1103040041307844810D3428B08081CE88410280201820A610077EE00778A08C182400088201620A71E0077E9006C788410280201820A610077EE00777408C182400088201620A71E0077E5007C188410280201820A61007A1E00778F08D182400088201620A71100A7E9006DE88410280201820A610077BE0077830062306090082608098421CEC811FA481188C182400088201620A71B0077E700761306290002008068829C4C11EF8411D80010200000000", // Vertex Shader - Linear - "44584243E58BC259F693FFB2661B317240B86DEA0100000090130000070000003C0000004C000000D40000006001000090020000040A0000200A0000534649300800000000000000000000004953473180000000030000000800000000000000680000000000000000000000030000000000000003030000000000000000000071000000000000000000000003000000010000000303000000000000000000007A000000000000000000000003000000020000000F0F000000000000504F534954494F4E00544558434F4F524400434F4C4F52004F5347318400000003000000080000000000000068000000000000000100000003000000000000000F00000000000000000000007400000000000000000000000300000001000000030C000000000000000000007D000000000000000000000003000000020000000F0000000000000053565F506F736974696F6E00544558434F4F524400434F4C4F5200005053563028010000340000000100000000000000000000000000000000000000FFFFFFFF010000000303000303000000000000000000000000000000280000000100000018000000020000000000000000000000000000000D000000000000003000000000504F534954494F4E00544558434F4F524400434F4C4F5200544558434F4F524400434F4C4F520056534D61696E0000010000000000000010000000010000000000000001004200030000000A000000000000000101420003000000130000000000000001024400030000000000000000000000010044030304000019000000000000000101420003020000220000000000000001024400030200000F0000000F00000000000000000000001000000020000000000000000000000000010000000200000004000000080000535441546C07000066000100DB0100004458494C0601000010000000540700004243C0DE210C0000D20100000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000004000000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1090C11C0118640040C108400906226600E60890621800001C0021C5180000380C528E1A2E7FC21E42F2B98D2A5662F28BDB46846118061DF70C973F610F21F921D00C0B8182A6100CE000F494C2000CC3A0E8B6E1F227EC21247F2524878A04228D9C87882684909000008570006722EAA0E1F227EC21247F25A40D690644000070CC1104A570000BB8081B081846208C24D8CE121640927C069822E4F28BC501261FF7711470274953440993CF398D3401CD24FD340ABAABA429A284C9071727009614880046FA691478E7188B13004B0A440023FD340A3E02D3019823000500000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A600774A0F340021932520204E0410CC690870002000000000000000080210F0204400000000000000000431E0508000100000000000000863C0F100003000000000000000C79222000020000000000000018F2504000040000000000000030E4C180000800000000000000200B040017000000321E981819114C908C092647C60443024AA01846000A30A00C8AA010CAA124CAA34C8A34A0208A82C612040444A0A32446008AA010CA80BC1900FA6600089C01A0700680C4B11C86791E0080C000004004844030004181821100000079180000A10000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD91004130400992000C9066120260880B241300C0A76731B068420260861F0D139637B130B63830A930B6B9BFB82992000CB06C45016C318186043D06C2000C00126085FC765ECCD6D8E2ECC8D6EEE0B668200301B0822928C0D02334D103C8E0C94DC9B5AD9185DDA9BDB17CC040168260880B361C0B06182003C130400DA8010D6954986B66D10186E820006DE068258246383C07C1B0E03A2AACE03830942116C00360CC6188CC186800C360C831894C104410CC06043700634ACA69AC2D2DC88403D4D2551253D394D108E6B8270601B02638270641B0449DAB0186AB0066CD0066C30B881C1066F4084AA086BE8E9498A68C332C4C11AB0411BB0C1E006031BBC018BA127A627A909C2A14D1080688320D5C186E59A83356083366083810E2E36B0830D031CC8C11D7099B2FA827A9B4BA34B7B739B201CDB86C5C88335D08336A083810E0C36B0830DCB10076BC0066DE006831B0C6CF0061B966B0ED6800DDAC00D063AB8D8C00E360C7BC0077DB061C0033F00260863606D100C50D85088411AFCC1130A34CCD8DEC2E8E6260880C422CD6D8E6E6E82004C34E6D2CEBED8C826080045632EEDEC6B8E6E8200541B905120855230855340855450852A6C6C766D2E6964656E745382A00A199E8B5D99DC5CDA9BDB9480684286E76217C6665726372530EA90E1B9CCA1859195C935BD9195B14D09903264782E7265736F75726365735302A712199E0B5D1E5C59909BDB1B5D185DDA9BDBDC14010CCAA00E199E8B5D5AD95D12D9145D185DD994E00CEA90E1B994B9D1C9E541BDA5B9D1CD4D0942A10B199ECBD85B9D1B5D99DCDC944015000000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC421077C70037A288776808719D1430EF8E006E4200EE7E006F6100EF2C00EE1900FEF500FF400000071200000220000001660BCAC09208D0130C3E537CE74208DE10366400D97EF3C3ED034CE044C440834C34218C1365CBEF3F84240150511950E3094840108985FDCB61D74C3E53B8F2F4404301121D00C0BF1450EB321CD803486094CC3E53B8FBF38C020360F35F9C56DDB40355CBEF3F8D2E444044A4D0F35F9C56D5B81345CBEF3F813114D0810617E71DB0000000000000000484153481400000000000000A6A82BB80A05DD02AE1B66751D5ACC794458494C68090000660001005A0200004458494C0601000010000000500900004243C0DE210C0000510200000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000004000000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1094C11C0118640040C108400906226600E60890621800001C0021C5180000380C528E1A2E7FC21E42F2B98D2A5662F28BDB46846118061DF70C973F610F21F921D00C0B8182A6100CE000F494C2000CC3A0E8B6E1F227EC21247F2524878A04228D9C87882684909000008570006722EAA0E1F227EC21247F25A40D690644000070CC1104A570000BB8081B081846208C24D8CE121640927C069822E4F28BC501261FF7711470274953440993CF398D3401CD24FD340ABAABA429A284C9071727009614880046FA691478E7188B13004B0A440023FD340A3E02D3019823000502000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A600774A0F340021932520204E0211B431E0200000000000000000000863C08100001000000000000000C79142000040000000000000018F23C40000C0000000000000030E4898000080000000000000060C84301011000000000000000C0900703022000000000000000802C10000012000000321E981419114C908C092647C60443024AA0188A6204A00003CAA008CA83C612040444A0A32446008AA010CA80C2190012C77218E679000002030000111002C10004050A4600000079180000650000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD91004130400992000C9066120260880B241180C0A76731B0684202608C0324108038BC00401603620CAC228CAD0001B02670301000F304110836B43104D108A8086D55453589A1B11A8A7A924AAA427A709C2114D100E6943A04C108E698200341B044DDBB028957561D79029D74684AA086BE8E9498A68C33274D6855D43365CDB040170580C3D313D494D100E6A82003C1B044D0C362C1F185817760D61F05D63B061E03C32E03265F505F536974697F6E6364138AA0D8B6206D6196061308481728DC18665E8AC0BCB866CB8B60DCB0706D6856543187CD7186C18D0200DD460C350066B004C10C600DA20286DB0A198283680DCA00A1B9B5D9B4B1A59991BDD9420A84286E76257263797F6E63625209A90E1B9D885B1D995C94D098C3A64782E7368616465724D6F64656C5302A40C199E8B5CD9DC5B9DDC58D9DC94E0A94386E76297567697443645174657362588EA90E1B994B9D1C9E541BDA5B9D1CD4D09DC00000000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC421077C70037A288776808719D1430EF8E006E4200EE7E006F6100EF2C00EE1900FEF500FF400000071200000220000001660BCAC09208D0130C3E537CE74208DE10366400D97EF3C3ED034CE044C440834C34218C1365CBEF3F84240150511950E3094840108985FDCB61D74C3E53B8F2F4404301121D00C0BF1450EB321CD803486094CC3E53B8FBF38C020360F35F9C56DDB40355CBEF3F8D2E444044A4D0F35F9C56D5B81345CBEF3F813114D0810617E71DB0000000061200000BE0000001304412C10000000130000000414572914C20C40D995EC40C10E94065D2300749400196304324AE3E9374640DA682F7F6304A2B9EAA43746008220887F34CD21800143D61CC4B22C13192300440E750402002CC002000000230608008260809141338081326270002008069419344131629000200806C81A489F186CD1884102802018206C3081C11830D2884102802018206D4085011970D3884102802018206E508941196CD4884102802018206F60A581197CD5884102802018207070A9C11940D6884102802018207180A1011A84C135629000200806881C6469900612366270002008064F1C60891A8C2604C06882108C260CC26802318C181C000882C163079D2307A30901309A2004A30983309A400C230607008260F0EC81184C71309A1000A30942309A3008A309C4306270002008060F289C017607A30901309A2004A30983309A400C664DF219314000100483A814E2C07A82110304004130884C410EC46009460C100004C1203A853930832330CD92CF88010280201844A950079A148C182000088241A40A7660064E30628000200806D12ADC811A288179997C460C100004C1206A853CF0AA60C4000140100C2257D003358882110304004130885E610FDCA0094C0C38F98C182000088241140B7D20065830628000200806912CF8811B50C188010280201844B3F007720005F4060020380000C50100480E006070A007F23138D803F9181CF0817C6CE003F8D8D007F0B1C10FE0637630C8C7EC60908FD9C1201F1B42013E3688027C6C1805F8181F0CF2313E18E4637C30C887440100340A0020520000950200C81400306290002008068A3BDC823998C32F94C188410280201828EE700BE6600EAF1006230609008260A0B8C32D988339F842376290002008068A3BDC823998032F64230609008260A0B8C32DA48339FC02288C182400088281E20EB7900EE6F00A7F306290002008068A3BDCC23898C32F20230609008260A0B8C32D8C8339BCC2316290002008068A3BDCC23898832F18230609008260A0B8C32D8C8339F04228D02900000100000000000000", + "44584243D753A620DDB4C72961AF9BB49563BC6A0100000094120000070000003C0000004C000000D40000006001000090020000E0090000FC090000534649300800000000000000000000004953473180000000030000000800000000000000680000000000000000000000030000000000000003030000000000000000000071000000000000000000000003000000010000000303000000000000000000007A000000000000000000000003000000020000000F0F000000000000504F534954494F4E00544558434F4F524400434F4C4F52004F5347318400000003000000080000000000000068000000000000000100000003000000000000000F00000000000000000000007400000000000000000000000300000001000000030C000000000000000000007D000000000000000000000003000000020000000F0000000000000053565F506F736974696F6E00544558434F4F524400434F4C4F5200005053563028010000340000000100000000000000000000000000000000000000FFFFFFFF010000000303000303000000000000000000000000000000280000000100000018000000020000000000000000000000000000000D000000000000003000000000504F534954494F4E00544558434F4F524400434F4C4F5200544558434F4F524400434F4C4F520056534D61696E0000010000000000000010000000010000000000000001004200030000000A000000000000000101420003000000130000000000000001024400030000000000000000000000010044030304000019000000000000000101420003020000220000000000000001024400030200000F0000000F00000000000000000000001000000020000000000000000000000000010000000200000004000000080000535441544807000066000100D20100004458494C0601000010000000300700004243C0DE210C0000C90100000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000003F00000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1088C1084009000A6600E608C0608E0029C64010444190510C8020886220E4A8E1F227EC21249FDBA8622526BFB86D440CC3305071CF70F913F610921F02CDB01028580AA1100C414D29066218067A6E1B2E7FC21E42F2574272A84820D2C879886842080909045108866022920E1A2E7FC21E42F25742DA906640044110C51C41500A86A0888AAC81806104624882EC2C610124C9678029422EBF581C60F2711F4781769234459430F99CD34813D04CD24FA360BB4A9A224A987C7071026049810860A49F4601778EB13801B0A4400430D24FA3A0232F1D8839025000000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A60077430E4098000000000000000000060C86300011000000000000000C090070102400000000000000080214F0304C00000000000000000439E0708800000000000000000863C12100001000000000000000C792C20000200000000000000C802010016000000321E981819114C908C092647C60443224AA01846000A30A00C8AA010CAA124CAA35CCAAF208A828A92180128824228030A0B10101081BA1900F26600E89B0120702C87619E070020300000100121100C4050206E0600000079180000A00000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD910041304E2982010C8066120260844B241300C0A76731B06842026085F47E78CED4D2C8C0D2A4C2EAC6DEE0B668240281B1043590C6360800D41B3810000079820741B97B137B739BA3037BAB92F980902B16C208848323608CC3441E03E3250726F6A656374696F6E5F30130482992010CD8601C3860902E14C108867034258572619DAB64160B80982C76D208845323608CCB7E13020AAEA3C30982008C00660C3608CC1186C08C860C3308841194C10C0C0DB109C010DABA9A6B0343722504F534954494F4E1384A29A2014D686C0982014D7064192362C861AAC011BB4011B0C6E60B0C11B10A12AC21A7A7A9222DAB00C71B0066CD0066C30B8C1C0066FC062E889E9496A825060130402DA204875B061B9E6600DD8A00DD860A0838B0DEC60C300077270075CA6ACBEA0DEE6D2E8D2DEDC260845B66131F2600DF4A00DE860A003830DEC60C332C4C11AB0411BB8C1E006031BBCC186E59A83356083367083810E2E36B0830DC31EF0411F6C18F0C00F80094218681B04031436146290067FF084020D33B6B730BAB9090211B148739BA39B9B2010128DB9B4B32F36B2090231D1984B3BFB9AA39B2010D406641448A1144CE11450211554A10A1B9B5D9B4B1A59991BDD9420A84286E76257263797F6E63625209A90E1B9D885B1D995C94D098C3A64782E7368616465724D6F64656C5302A40C199E8B5CD9DC5B9DDC58D9DC94C0A94486E74297075716E4E6F646174697F6E6363745008332A84386E76297567697443645174657362538833A64782E656E747279506F696E7473538250E84286E732F656E7465726373725500500791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC421077C70037A288776808719D1430EF8E006E4200EE7E006F6100EF2C00EE1900FEF500FF4000000712000001F0000000660BCAC09208D1550C3E53B8F0F348D3301131102CDB01036B00D97EF3CBE1050454144A5030C25610002E617B76D06DD70F9CEE30B11014C440834C3427C91C36C4833208D6101D370F9CEE32F0E3088CD434D7E71DB26500D97EF3CBE3439118152D3434D7E71DB46200D97EF3CFE4444130244985FDC3600000000000000484153481400000000000000F9DD1AE5250EB9E439EBECBF95D9943F4458494C9008000066000100240200004458494C0601000010000000780800004243C0DE210C00001B0200000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000003F00000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1088C1084009000A6600E608C0608E0029C64010444190510C8020886220E4A8E1F227EC21249FDBA8622526BFB86D440CC3305071CF70F913F610921F02CDB01028580AA1100C414D29066218067A6E1B2E7FC21E42F2574272A84820D2C879886842080909045108866022920E1A2E7FC21E42F25742DA906640044110C51C41500A86A0888AAC81806104624882EC2C610124C9678029422EBF581C60F2711F4781769234459430F99CD34813D04CD24FA360BB4A9A224A987C7071026049810860A49F4601778EB13801B0A4400430D24FA3A0232F1D8839025000000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A60077430E4090000000000000000000060C86300011000000000000000C090070102400000000000000080214F0304C00000000000000000439E0708800000000000000000863C12100001000000000000000C792C20000200000000000000C802010011000000321E981419114C908C092647C60443224AA0188A6204A00003CAA008CA838A92180128824228030A0B10101081C0B11C86791E0080C000004004844030004181BE19000079180000650000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD910041304E2982010C8066120260844B241180C0A76731B0684202608843241F82C02130462D980280BA32843036C089C0D04003CC004010CAA0D41344110001A56534D61696E44A09EA692A8929E9C2608C5334128A00D81324128A20902C16C10346DC3A254D6855D43A65C1B11AA22ACA1A72729A20DCBD05917760DD9706D1304A26131F4C4F424354128A40902E16C103431D8B07C60605DD83584C1778DC18681F3C880CB94D517D4DB5C1A5DDA9BDB04A198362C8A1958678085C11006CA35061B96A1B32E2C1BB2E1DA362C1F185817960D61F05D63B06140833450830D4319AC01304108036A83A0B4C18662A2D80072832A6C6C766D2E6964656E745382A00A199E8B5D99DC5CDA9BDB9480684286E76217C6665726372530EA90E1B9CCA1859195C935BD9195B14D09903264782E7265736F75726365735382A70E199E8B5D5AD95D12D9145D185DD99420AA4386E752E646279707F596E646373725700300000000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC421077C70037A288776808719D1430EF8E006E4200EE7E006F6100EF2C00EE1900FEF500FF4000000712000001F0000000660BCAC09208D1550C3E53B8F0F348D3301131102CDB01036B00D97EF3CBE1050454144A5030C25610002E617B76D06DD70F9CEE30B11014C440834C3427C91C36C4833208D6101D370F9CEE32F0E3088CD434D7E71DB26500D97EF3CBE3439118152D3434D7E71DB46200D97EF3CFE4444130244985FDC3600000061200000900000001304412C100000000E000000548D005051024494462914C20C4071955DC90E14EC000D6304A2B9EAA4374640DA682F7F14CD21640B5173108AA244348C11C8288DA71F002306080082606081C12170CF88C10180201848627004C48841028020181867D06C1EC68C18240008828181060EF745CD8841028020181869F07460903923060900826060A801E48501F68C182400088281B10651198801078D182400088281C10692198C41158D182400088281D10613199081278D182400088281E106541994C1358D181C00088241D306526206A30901309A2004A30983309A400C230607008260D0C8C1E5B8C16842008C2608C168C2208C2610C388C1018020183477C04D6E309A1000A30942309A3008A309C4604E249F11030400413078F8600C22253023808E41947C460C100004C1E0F90333A098C002043A265DF2193140001004834714D2E072020B14E818A5C967C4000140100C9E5260030D0A2C60A063636006F2B1313803F9D818A0817C6C6003F8D8D006F0B1C10DE063431AC8C78634908F0D69201F1BE6003E36D0017C6CA803F8D8F006F2B1E10DE463C31BC867C4200140100C105C000558800555C8460C120004C100C1055080055810056BC4200140100C105C00055880855498460C120004C100C10550800558380568C4200140100C105C00855980055570831183040041304070011466011644A10D460C120004C100C10550680558508561C4200140100C105C00855680055110460C120004C100C10550680558488560C4200140100C105C0085568085537803040000000000", // Pixel Shader - "44584243885543CA35880DBB02C0AE5493A85ECF0100000034110000070000003C0000004C000000D80000001401000024020000400900005C09000053464930080000000000000000000000495347318400000003000000080000000000000068000000000000000100000003000000000000000F000000000000000000000074000000000000000000000003000000010000000303000000000000000000007D000000000000000000000003000000020000000F0F00000000000053565F506F736974696F6E00544558434F4F524400434F4C4F5200004F5347313400000001000000080000000000000028000000000000004000000003000000000000000F0000000000000053565F5461726765740000005053563008010000340000000000000000000000000000000000000000000000FFFFFFFF000000000301000301000000000000000000000000000000100000000200000018000000010000000000000000000000000000000E000000000000000300000000000000000000000000000002000000000000001800000000544558434F4F524400434F4C4F520050534D61696E000001000000000000001000000000000000000000000100440303040000010000000000000001014200030200000A00000000000000010244000302000000000000000000000100441003000000000000000000000000000000000000000F0000000F000000000000000000000001000000020000000400000008000000535441541407000066000000C50100004458494C0601000010000000FC0600004243C0DE210C0000BC0100000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000005200000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1084C11C0118640040C108400906226600E60890621800001C0021C5180000380C526E1A2E7FC21E42F257425A89C92F6E1B15866118001DF70C973F610F21F921D00C0B8182A6300CE038866118000018F4DC365CFE843D84E4AF84E4509140A491F310D18410121200A0100EE044241D345CFE843D84E4AF84B421CD800800008E3982A0140E400115590301C3088431531B8C033B84C33CCC831BD04239E0033DD4833C94831C90021FD843398C033DBC833CF08139B0C33B84033DB00118D0811F80811FE8811EB4433AC0C33CFC023DE4033C94030A8099C4601CD8211CE6611EDC8016CA011FE8A11EE4A11CE48014F8C01ECA611CE8E11DE4810FCC811DDE211CE8810DC0800EFC000CFC00099946DB4DD21451C2E4B300F32C44C44EC044A000A02E1D8039025000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A600774A0F340021932520204E0611B431E0208000000000000000000863C08100001000000000000000C79142000040000000000000018F23C40000C0000000000000030E4918000080000000000000060C8630101100000000000000040160800000012000000321E981419114C908C092647C60443024AA01846008AA024CAA03C0AA164082C414040043A4AA20C0A6104A0080A84B81900F26600E81BCB6108000080E701804020100A4600000079180000870000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD910041304E0982000C8066120260840B241300C0A70731B0684202608DCC584AE0C8FAE4EAEEC0B66820028130460D92018CD86C45016C31818C3D9103C13040F633217D606C75626F705B3013122C9300603D8104C1B080800A80942116C00360CC6756D08B00DC3606513842FDB106C34A0A69AC2D2DCB84C597D41BDCDA5D1A5BDB94D108E688270481B026382704C138483DAB018DE0706612006831818630010A12AC21A7A7A92229A201CD504016036086770061B96A10CBE3108033318CC601803346031F4C4F4243541009A0DC219ACC1868551836F0CC2C00C063160C6800D360C6490066DC064CAEA8B2A4CEEAC8C6E8270581B16E30D3E3808833118C4C0180336D810C4C186C10DE40098208001B44130E8604361757350D5010D33B6B730BAB90902E0B048739BA39B9B20000F8DB9B4B32F36321A7369675F737444E8CAF0BEDCDEE4DA362877800779A0077B40F0011EF4C150858DCDAECD258DACCC8D6E4A105421C373B12B939B4B7B739B12104DC8F05CECC2D8ECCAE4A604461D323C9739B430B232B9A637B232B6290152860CCF45AE6CEEAD4E6EAC6C6E4A405522C373A1CB832B0B72737BA30BA34B7B739B9B126475C8F05CECD2CAEE92C8A6E8C2E8CAA6045B1D323C9732373AB93CA8B73437BAB929411D7421C373197BAB73A32B939B9B12F4010000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC421077C70037A288776808719D1430EF8E006E4200EE7E006F6100EF2C00EE1900FEF500FF4000000712000001C0000001660A4AC09208D0130C3E537CE74208DE10356400D97EF3C3ED034CE044C440834C3429841375CBEF3F8424400131102CDB0105FE4301BD20C486398C0345CBEF3F88B030C62F350935FDCB61140C3E53B8F2F01CCB3107E71DB36500D97EF3CBE3439118152D3434D7E71DB0000000000000000484153481400000000000000AE3AD3E904D723E35E117863FA49DDD14458494CD007000066000000F40100004458494C0601000010000000B80700004243C0DE210C0000EB0100000B82200002000000130000000781239141C80449061032399201840C250508191E048B628018450242920B42C41032143808184B0A32628848901420434688A500193242E4480E901123C4504151818CE183E58A0431460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000005300000032228809206485041323A484041323E384A19014124C8C8C0B84C44C1088C11C0118640040C108400906226600E60890621800001C0021C5180000380C526E1A2E7FC21E42F257425A89C92F6E1B15866118001DF70C973F610F21F921D00C0B8182A6300CE038866118000018F4DC365CFE843D84E4AF84E4509140A491F310D18410121200A0100EE044241D345CFE843D84E4AF84B421CD800800008E3982A0140E400115590301C3088431531B8C033B84C33CCC831BD04239E0033DD4833C94831C90021FD843398C033DBC833CF08139B0C33B84033DB00118D0811F80811FE8811EB4433AC0C33CFC023DE4033C94030A8099C4601CD8211CE6611EDC8016CA011FE8A11EE4A11CE48014F8C01ECA611CE8E11DE4810FCC811DDE211CE8810DC0800EFC000CFC00099946DB4DD21451C2E4B300F32C44C44EC044A000A02E1D803902502000000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A600774A0F340021932520204E0411B431E0200000000000000000000863C08100001000000000000000C79142000040000000000000018F23C40000C0000000000000030E4918000080000000000000060C8630101100000000000000040160800000012000000321E981419114C908C092647C60443024AA0188A6204A0084AA20CCA83C012040444A0A324CAA01046008AA040889B01206F0680BEB11C86000000781E00080402A160040000000079180000650000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD910041304E0982000C8066120260840B241180C0A70731B0684202608803241E02C02130460992000CC0641713624CAC228CAD028CF86009A2078D7064491184519146043306D202200A026081FB621B026084540036AAA292CCD8DCB94D517D4DB5C1A5DDA9BDB04E180260847B42150260887344138A60D8BA26D5CE70D9EF20144A88AB0869E9EA4882608073541009A0DC2188CC186650883EDEBC4601083E1230316434F4C4F521304C0D9208CC1196C581A33D8BE4E0C06AFF9D060C300066590064CA6ACBEA8C2E4CECAE8260847B56151D6606383EE1B3CE543830D411B6C18D4C00D800902183C1B04050E361458F606551C546163B36B7349232B73A39B120455C8F05CECCAE4E6D2DEDCA6044413323C17BB3036BB32B9298151870CCF650E2D8CAC4CAEE98DAC8C6D4A809421C373912B9B7BAB931B2B9B9B125075C8F05CECD2CAEE92C8A6E8C2E8CAA604561D323C9732373AB93CA8B73437BAB929411C000000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC421077C70037A288776808719D1430EF8E006E4200EE7E006F6100EF2C00EE1900FEF500FF4000000712000001C0000001660A4AC09208D0130C3E537CE74208DE10356400D97EF3C3ED034CE044C440834C3429841375CBEF3F8424400131102CDB0105FE4301BD20C486398C0345CBEF3F88B030C62F350935FDCB61140C3E53B8F2F01CCB3107E71DB36500D97EF3CBE3439118152D3434D7E71DB00000000612000004E0000001304412C100000000E00000004CC0014422994EC40C10E94244471141E552300749400457308CB378700060A51230073108AA24464CC005038D4110800A0000A000000002306080082606091414380013262800020080656193844182423060900826080A841140662904923060900826080AC81240663A04C23060900826080B0C1340664A05123060900826080B401450665E05523060900826080B841950666D05923060900826080BC81A50667E05C23060700826020B501853823060700826020B941853823060F008260F0C0C12404C4C0306AA0061A339A1000A30942309A3008A309C4600D211F6B08F95843C8C71A423E440160C4200140100C943D10033AA0833528460C120004C140D90331A0033AD88811830400413050F6400CE8800ED46018314800100403650FC4800EE8A00D0404000000000000" + "44584243EE63AC19F937568890164F4A4BFF155601000000D4100000070000003C0000004C000000D800000014010000240200001C0900003809000053464930080000000000000000000000495347318400000003000000080000000000000068000000000000000100000003000000000000000F000000000000000000000074000000000000000000000003000000010000000303000000000000000000007D000000000000000000000003000000020000000F0F00000000000053565F506F736974696F6E00544558434F4F524400434F4C4F5200004F5347313400000001000000080000000000000028000000000000004000000003000000000000000F0000000000000053565F5461726765740000005053563008010000340000000000000000000000000000000000000000000000FFFFFFFF000000000301000301000000000000000000000000000000100000000200000018000000010000000000000000000000000000000E000000000000000300000000000000000000000000000002000000000000001800000000544558434F4F524400434F4C4F520050534D61696E000001000000000000001000000000000000000000000100440303040000010000000000000001014200030200000A00000000000000010244000302000000000000000000000100441003000000000000000000000000000000000000000F0000000F00000000000000000000000100000002000000040000000800000053544154F006000066000000BC0100004458494C0601000010000000D80600004243C0DE210C0000B30100000B82200002000000130000000781239141C80449061032399201840C250508191E048B628014450242920B42A41032143808184B0A32528848901420434688A500193242E4480E909122C4504151818CE183E58A0429460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000005000000032224809206485049322A484049322E384A19014124C8A8C0B84A44C107C23002500146600E608C0608E0029C620841442A61880105206A19B86CB9FB08790FC95905662F28BDB46C51863102AF70C973F610F21F921D00C0B8182551845181B630C42C8A076DB70F913F61092BF12924345029146CE43441342484820A4108CB047F0A0E1F227EC21247F25A40D6906441042CA1C41500A46249944070286118861A636180776088779980737A08572C0077AA8077928073920053EB0877218077A780779E0037360877708077A600330A0033F00033FD0033D688774808779F8057AC807782807149099C4601CD8211CE6611EDC8016CA011FE8A11EE4A11CE48014F8C01ECA611CE8E11DE4810FCC811DDE211CE8810DC0800EFC000CFC00091753BE499A224A987C16609E8588D80998081410DAE940E608400100000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A60077430E4098000000000000000000060C86300011000000000000000C090070102400000000000000080214F0304C00000000000000000431E0808800000000000000000863C1410000100000000000000648100000011000000321E981419114C908C092647C604432225500C230045501265501E855030544AA20C0A6104A0080A847C01020222109F01A03E96C310000000CF0300814020A46700000079180000870000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD910041304C2982010C7066120260804B241300C0A70731B06842026081AC684AE0C8FAE4EAEEC0B66824024130442D92018CD86C45016C31818C3D9103C1304CE623217D606C75626F705B3013122C9300603D8104C1B080800A80982006C00360CC6756D08B00DC360651384EEDA106C34A0A69AC2D2DCB84C597D41BDCDA5D1A5BDB94D108A678250401B0263825044138442DAB018DE0706612006831818630010A12AC21A7A7A92229A2014D304815836086770061B96A10CBE3108033318CC601803346031F4C4F424354120980DC219ACC1868551836F0CC2C00C063160C6800D360C6490066DC064CAEA8B2A4CEEAC8C6E8250501B16E30D3E3808833118C4C0180336D810C4C186C10DE400982078D506C1A0830D85D5CD41550734CCD8DEC2E8E6260844C322CD6D8E6E6E82403834E6D2CEBED8C868CCA59D7DCDD111A12BC3FB727B936BDBA0DC011EE4811EEC01C10778D00743153636BB369734B23237BA294150850CCFC5AE4C6E2EEDCD6D4A403421C373B10B63B32B939B121875C8F05CE6D0C2C8CAE49ADEC8CAD8A6044819323C17B9B2B9B73AB9B1B2B9290155890CCF852E0FAE2CC8CDED8D2E8C2EEDCD6D6E4A90D521C373B14B2BBB4B229BA20BA32B9B126C75C8F05CCADCE8E4F2A0DED2DCE8E6A60475D0850CCF65ECADCE8DAE4C6E6E4AD007000000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC421077C70037A288776808719D1430EF8E006E4200EE7E006F6100EF2C00EE1900FEF500FF400000071200000190000000660A4AC09208D1150C3E53B8F0F348D3301131102CDB01056D00D97EF3CBE1011C0448440332CC41739CC863403D21816300D97EF3CFEE20083D83CD4E417B76D03D070F9CEE34B00F32C845FDCB60954C3E53B8F2F4D4E44A0D4F450935FDC36000000000000004841534814000000000000009F974238F30DDDF016CFF4F093C3E59C4458494C9407000066000000E50100004458494C06010000100000007C0700004243C0DE210C0000DC0100000B82200002000000130000000781239141C80449061032399201840C250508191E048B628014450242920B42A41032143808184B0A32528848901420434688A500193242E4480E909122C4504151818CE183E58A0429460651180000080000001B8CE0FFFFFFFF074002A80D84F0FFFFFFFF03206D3086FFFFFFFF1F0009A800491800000300000013826042204C080600000000892000005000000032224809206485049322A484049322E384A19014124C8A8C0B84A44C107C23002500146600E608C0608E0029C620841442A61880105206A19B86CB9FB08790FC95905662F28BDB46C51863102AF70C973F610F21F921D00C0B8182551845181B630C42C8A076DB70F913F61092BF12924345029146CE43441342484820A4108CB047F0A0E1F227EC21247F25A40D6906441042CA1C41500A46249944070286118861A636180776088779980737A08572C0077AA8077928073920053EB0877218077A780779E0037360877708077A600330A0033F00033FD0033D688774808779F8057AC807782807149099C4601CD8211CE6611EDC8016CA011FE8A11EE4A11CE48014F8C01ECA611CE8E11DE4810FCC811DDE211CE8810DC0800EFC000CFC00091753BE499A224A987C16609E8588D80998081410DAE940E608400100000000131472C08774608736688779680372C0870DAE500E6DD00E7A500E6D000F7A300772A0077320076D900E71A0077320076D900E78A00778D006E9100776A0077160076D900E7320077A300772D006E9600774A0077640076D600E7160077A100776D006E6300772A0077320076D600E7640077A600774D006EE80077A100776A0077320077A60077430E4090000000000000000000060C86300011000000000000000C090070102400000000000000080214F0304C00000000000000000431E0808800000000000000000863C1410000100000000000000648100000011000000321E981419114C908C092647C604432225500C4531025004255106E541A524CAA01046008AA040C81720202002F11900EA63390C010000F03C00100804427A060000000079180000650000001A034C90460213C43120C31B4381934BB30BA32B4B018971C1718171A989919901419931C3A991C9A919334BD910041304C2982010C7066120260804B241180C0A70731B0684202608443241D02E02130442992010CB0641713624CAC228CAD028CF86009A2070D5064491184519146043306D202200A026089DB521B026080240036AAA292CCD8DCB94D517D4DB5C1A5DDA9BDB04A1702608C5B32150260805344128A20D8BA26D5CE70D9EF20144A88AB0869E9EA488260885344120980DC2188CC186650883EDEBC4601083E1230316434F4C4F521304A2D9208CC1196C581A33D8BE4E0C06AFF9D060C300066590064CA6ACBEA8C2E4CECAE82608C5B46151D6606383EE1B3CE543830D411B6C18D4C00D800982476D101438D85060D91B547150858DCDAECD258DACCC8D6E4A105421C373B12B939B4B7B739B12104DC8F05CECC2D8ECCAE4A604461D323C9739B430B232B9A637B232B6290152860CCF45AE6CEEAD4E6EAC6C6E4A40D521C373B14B2BBB4B229BA20BA32B9B125875C8F05CCADCE8E4F2A0DED2DCE8E6A6047100000000791800004C0000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC421077C70037A288776808719D1430EF8E006E4200EE7E006F6100EF2C00EE1900FEF500FF400000071200000190000000660A4AC09208D1150C3E53B8F0F348D3301131102CDB01056D00D97EF3CBE1011C0448440332CC41739CC863403D21816300D97EF3CFEE20083D83CD4E417B76D03D070F9CEE34B00F32C845FDCB60954C3E53B8F2F4D4E44A0D4F450935FDC3600000061200000490000001304412C100000000B00000034470088CC0014422994EC40C10E94244471141E9512A03787A07873085F427204600E22499287C60C0000002306080082604089C13278CF8801028020185063C00C1F34629000200806061A3C1F1860D088410280201818690081411824D1884102802018186A1085811864D2884102802018186B2089C11874D3884102802018186C309D011970D4884102802018186D40A1411934D588C101802018406B2021CD88C101802018406C3021CD88C103802018346E100901312C0B1AA001B68C2604C06882108C260CC268023118D1C8C788463E4634F231A291CF8841028020182078F0C5411CA40131629000200806081E7C711007D930629000200806081E7C71100768208C18240008820182075F1CC4C11A0408000000000000" ]; private readonly ResourceLayoutDesc DxilDesc = new() @@ -85,13 +85,13 @@ float4 PSMain(VSOutput input) : SV_TARGET private readonly string[] Spirv = [ // Vertex Shader - Legacy - "030223070005010000002800650000000000000011000200010000000E00030000000000010000000F000C00000000001D00000056534D61696E00000400000007000000080000000A0000000B0000000D0000001B000000030003000B000000010000000500090007000000656E747279506F696E74506172616D5F56534D61696E2E555600000005000A0008000000656E747279506F696E74506172616D5F56534D61696E2E436F6C6F7200000000050006000A000000696E7075742E506F736974696F6E0000050005000B000000696E7075742E555600000000050005000D000000696E7075742E436F6C6F720005000400100000007465787475726500050004001300000073616D706C65720005000A00160000005F4D617472697853746F726167655F666C6F617434783464656661756C74000006000500160000000000000064617461000000000500070015000000436F6E7374616E74735F64656661756C7400000006000600150000000000000050726F6A656374696F6E00000500080014000000476C6F62616C506172616D735F64656661756C7400000000060006001400000000000000636F6E7374616E7473000000050006001B000000676C6F62616C506172616D7300000000050005002000000056534F757470757400000000060006002000000000000000506F736974696F6E0000000006000400200000000100000055560000060005002000000002000000436F6C6F7200000005000400220000006F7574707574000005000400220000006F7574707574000005000C00240000005F4D617472697853746F726167655F666C6F61743478345F6C6F676963616C64656661756C74000006000500240000000000000064617461000000000500090023000000436F6E7374616E74735F64656661756C745F6C6F676963616C00000006000600230000000000000050726F6A656374696F6E0000050004001D00000056534D61696E000047000400040000000B0000000000000047000400070000001E0000000000000047000400080000001E00000001000000470004000A0000001E00000000000000470004000B0000001E00000001000000470004000D0000001E000000020000004700040010000000210000000100000047000400100000002200000000000000470004001300000021000000020000004700040013000000220000000000000047000400170000000600000010000000480005001600000000000000230000000000000048000500150000000000000023000000000000004700030014000000020000004800050014000000000000002300000000000000470004001B0000002100000000000000470004001B00000022000000000000001600030001000000200000001700040002000000010000000400000020000400030000000300000002000000170004000500000001000000020000002000040006000000030000000500000020000400090000000100000005000000200004000C0000000100000002000000190009000E00000001000000010000000200000000000000000000000100000000000000200004000F000000000000000E0000001A0002001100000020000400120000000000000011000000150004001800000020000000010000002B0004001800000019000000040000001C0004001700000002000000190000001E00030016000000170000001E00030015000000160000001E0003001400000015000000200004001A0000000200000014000000130002001C000000210003001E0000001C0000001E00050020000000020000000500000002000000200004002100000007000000200000001C0004002500000002000000190000001E00030024000000250000001E0003002300000024000000200004002600000007000000230000002B000400180000002B00000000000000200004002C00000007000000020000002B000400010000002F000000000000002B00040001000000300000000000803F2000040031000000020000001500000020000400360000000700000024000000180004005200000002000000040000002B000400180000005600000001000000200004005700000007000000050000002B000400180000005A000000020000003B0004000300000004000000030000003B0004000600000007000000030000003B0004000300000008000000030000003B000400090000000A000000010000003B000400090000000B000000010000003B0004000C0000000D000000010000003B0004000F00000010000000000000003B0004001200000013000000000000003B0004001A0000001B00000002000000360005001C0000001D000000000000001E000000F80002001F0000003B0004002100000022000000070000003B0004002600000027000000070000003D00040005000000280000000A0000003D00040005000000290000000B0000003D000400020000002A0000000D000000410005002C0000002D000000220000002B00000050000600020000002E000000280000002F000000300000004100050031000000320000001B0000002B0000003D000400150000003300000032000000900104002300000034000000330000003E0003002700000034000000410005003600000037000000270000002B0000003D000400240000003800000037000000510005002500000039000000380000000000000051000500020000003A000000390000000000000051000500010000003B0000003A0000000000000051000500010000003C0000003A0000000100000051000500010000003D0000003A0000000200000051000500010000003E0000003A0000000300000051000500020000003F00000039000000010000005100050001000000400000003F000000000000005100050001000000410000003F000000010000005100050001000000420000003F000000020000005100050001000000430000003F0000000300000051000500020000004400000039000000020000005100050001000000450000004400000000000000510005000100000046000000440000000100000051000500010000004700000044000000020000005100050001000000480000004400000003000000510005000200000049000000390000000300000051000500010000004A000000490000000000000051000500010000004B000000490000000100000051000500010000004C000000490000000200000051000500010000004D000000490000000300000050000700020000004E0000003B0000003C0000003D0000003E00000050000700020000004F00000040000000410000004200000043000000500007000200000050000000450000004600000047000000480000005000070002000000510000004A0000004B0000004C0000004D0000005000070052000000530000004E0000004F0000005000000051000000910005000200000054000000530000002E0000003E0003002D0000005400000041000500570000005800000022000000560000003E0003005800000029000000410005002C0000005B000000220000005A0000003E0003005B0000002A0000003D000400200000005D0000002200000051000500020000005E0000005D000000000000003E000300040000005E0000005100050005000000600000005D000000010000003E00030007000000600000005100050002000000620000005D000000020000003E0003000800000062000000FD00010038000100", + "030223070006010000002800490000000000000011000200010000000E00030000000000010000000F000C00000000000200000056534D61696E0000360000003A0000003D000000150000002B000000310000001C000000030003000B00000001000000050009000B000000436F6E7374616E74735F7374643134305F6C6F676963616C00000000060006000B0000000000000050726F6A656374696F6E00000500060015000000696E7075742E506F736974696F6E0000050007001A000000436F6E7374616E74735F73746431343000000000060006001A0000000000000050726F6A656374696F6E00000500070019000000476C6F62616C506172616D735F73746431343000060006001900000000000000636F6E7374616E7473000000050006001C000000676C6F62616C506172616D7300000000050005002B000000696E7075742E5556000000000500050031000000696E7075742E436F6C6F7200050009003A000000656E747279506F696E74506172616D5F56534D61696E2E555600000005000A003D000000656E747279506F696E74506172616D5F56534D61696E2E436F6C6F7200000000050004000200000056534D61696E000047000400150000001E00000000000000480005001A000000000000002300000000000000480004001A0000000000000005000000480005001A0000000000000007000000100000004700030019000000020000004800050019000000000000002300000000000000470004001C0000002100000000000000470004001C0000002200000000000000470004002B0000001E0000000100000047000400310000001E0000000200000047000400360000000B00000000000000470004003A0000001E00000000000000470004003D0000001E0000000100000013000200010000002100030003000000010000001600030006000000200000001700040007000000060000000400000017000400080000000600000002000000180004000C00000007000000040000001E0003000B0000000C000000150004000F00000020000000010000002B0004000F0000001000000000000000200004001400000001000000080000002B0004000600000017000000000000002B00040006000000180000000000803F1E0003001A0000000C0000001E000300190000001A000000200004001B0000000200000019000000200004001D000000020000001A0000002000040030000000010000000700000020000400350000000300000007000000200004003900000003000000080000003B0004001400000015000000010000003B0004001B0000001C000000020000003B000400140000002B000000010000003B0004003000000031000000010000003B0004003500000036000000030000003B000400390000003A000000030000003B000400350000003D000000030000003600050001000000020000000000000003000000F8000200040000003D000400080000001300000015000000500006000700000016000000130000001700000018000000410005001D0000001E0000001C000000100000003D0004001A0000001F0000001E000000900104000B000000200000001F000000510005000C00000048000000200000000000000091000500070000002500000048000000160000003D000400080000002A0000002B0000003D000400070000002F000000310000003E00030036000000250000003E0003003A0000002A0000003E0003003D0000002F000000FD00010038000100", // Vertex Shader - Linear - "0302230700050100000028007F0000000000000011000200010000000E00030000000000010000000F000C00000000001D00000056534D61696E00000400000007000000080000000A0000000B0000000D0000001B000000030003000B000000010000000500090007000000656E747279506F696E74506172616D5F56534D61696E2E555600000005000A0008000000656E747279506F696E74506172616D5F56534D61696E2E436F6C6F7200000000050006000A000000696E7075742E506F736974696F6E0000050005000B000000696E7075742E555600000000050005000D000000696E7075742E436F6C6F720005000400100000007465787475726500050004001300000073616D706C65720005000A00160000005F4D617472697853746F726167655F666C6F617434783464656661756C74000006000500160000000000000064617461000000000500070015000000436F6E7374616E74735F64656661756C7400000006000600150000000000000050726F6A656374696F6E00000500080014000000476C6F62616C506172616D735F64656661756C7400000000060006001400000000000000636F6E7374616E7473000000050006001B000000676C6F62616C506172616D7300000000050005002000000056534F757470757400000000060006002000000000000000506F736974696F6E0000000006000400200000000100000055560000060005002000000002000000436F6C6F7200000005000400220000006F7574707574000005000400220000006F7574707574000005000C00240000005F4D617472697853746F726167655F666C6F61743478345F6C6F676963616C64656661756C74000006000500240000000000000064617461000000000500090023000000436F6E7374616E74735F64656661756C745F6C6F676963616C00000006000600230000000000000050726F6A656374696F6E000005000400620000007372676200000000050006006000000053726762546F4C696E65617200000000050004001D00000056534D61696E000047000400040000000B0000000000000047000400070000001E0000000000000047000400080000001E00000001000000470004000A0000001E00000000000000470004000B0000001E00000001000000470004000D0000001E000000020000004700040010000000210000000100000047000400100000002200000000000000470004001300000021000000020000004700040013000000220000000000000047000400170000000600000010000000480005001600000000000000230000000000000048000500150000000000000023000000000000004700030014000000020000004800050014000000000000002300000000000000470004001B0000002100000000000000470004001B00000022000000000000001600030001000000200000001700040002000000010000000400000020000400030000000300000002000000170004000500000001000000020000002000040006000000030000000500000020000400090000000100000005000000200004000C0000000100000002000000190009000E00000001000000010000000200000000000000000000000100000000000000200004000F000000000000000E0000001A0002001100000020000400120000000000000011000000150004001800000020000000010000002B0004001800000019000000040000001C0004001700000002000000190000001E00030016000000170000001E00030015000000160000001E0003001400000015000000200004001A0000000200000014000000130002001C000000210003001E0000001C0000001E00050020000000020000000500000002000000200004002100000007000000200000001C0004002500000002000000190000001E00030024000000250000001E0003002300000024000000200004002600000007000000230000002B000400180000002B00000000000000200004002C00000007000000020000002B000400010000002F000000000000002B00040001000000300000000000803F2000040031000000020000001500000020000400360000000700000024000000180004005200000002000000040000002B000400180000005600000001000000200004005700000007000000050000002B000400180000005A00000002000000170004005D000000010000000300000021000400610000005D0000005D0000002B000400010000006500000012519C3E2B0004000100000067000000C4A22E3F2B000400010000006B000000C22C4D3C200004006F00000007000000010000003B0004000300000004000000030000003B0004000600000007000000030000003B0004000300000008000000030000003B000400090000000A000000010000003B000400090000000B000000010000003B0004000C0000000D000000010000003B0004000F00000010000000000000003B0004001200000013000000000000003B0004001A0000001B00000002000000360005001C0000001D000000000000001E000000F80002001F0000003B0004002100000022000000070000003B0004002600000027000000070000003D00040005000000280000000A0000003D00040005000000290000000B0000003D000400020000002A0000000D000000410005002C0000002D000000220000002B00000050000600020000002E000000280000002F000000300000004100050031000000320000001B0000002B0000003D000400150000003300000032000000900104002300000034000000330000003E0003002700000034000000410005003600000037000000270000002B0000003D000400240000003800000037000000510005002500000039000000380000000000000051000500020000003A000000390000000000000051000500010000003B0000003A0000000000000051000500010000003C0000003A0000000100000051000500010000003D0000003A0000000200000051000500010000003E0000003A0000000300000051000500020000003F00000039000000010000005100050001000000400000003F000000000000005100050001000000410000003F000000010000005100050001000000420000003F000000020000005100050001000000430000003F0000000300000051000500020000004400000039000000020000005100050001000000450000004400000000000000510005000100000046000000440000000100000051000500010000004700000044000000020000005100050001000000480000004400000003000000510005000200000049000000390000000300000051000500010000004A000000490000000000000051000500010000004B000000490000000100000051000500010000004C000000490000000200000051000500010000004D000000490000000300000050000700020000004E0000003B0000003C0000003D0000003E00000050000700020000004F00000040000000410000004200000043000000500007000200000050000000450000004600000047000000480000005000070002000000510000004A0000004B0000004C0000004D0000005000070052000000530000004E0000004F0000005000000051000000910005000200000054000000530000002E0000003E0003002D0000005400000041000500570000005800000022000000560000003E0003005800000029000000410005002C0000005B000000220000005A0000003E0003005B0000002A0000004F0008005D0000005E0000002A0000002A000000000000000100000002000000390005005D0000005F000000600000005E000000410005006F000000700000005B0000002B0000005100050001000000710000005F000000000000003E0003007000000071000000410005006F000000720000005B000000560000005100050001000000730000005F000000010000003E0003007200000073000000410005006F000000740000005B0000005A0000005100050001000000750000005F000000020000003E00030074000000750000003D00040020000000770000002200000051000500020000007800000077000000000000003E000300040000007800000051000500050000007A00000077000000010000003E000300070000007A00000051000500020000007C00000077000000020000003E000300080000007C000000FD00010038000100360005005D000000600000000000000061000000370003005D00000062000000F8000200630000008E0005005D000000640000006200000065000000500006005D00000066000000670000006700000067000000810005005D000000680000006400000066000000850005005D000000690000006200000068000000500006005D0000006A0000006B0000006B0000006B000000810005005D0000006C000000690000006A000000850005005D0000006D000000620000006C000000FE0002006D00000038000100", + "030223070006010000002800750000000000000011000200010000000E00030000000000010000000F000C00000000000200000056534D61696E0000500000005400000057000000150000002B000000310000001C000000030003000B00000001000000050009000B000000436F6E7374616E74735F7374643134305F6C6F676963616C00000000060006000B0000000000000050726F6A656374696F6E00000500060015000000696E7075742E506F736974696F6E0000050007001A000000436F6E7374616E74735F73746431343000000000060006001A0000000000000050726F6A656374696F6E00000500070019000000476C6F62616C506172616D735F73746431343000060006001900000000000000636F6E7374616E7473000000050006001C000000676C6F62616C506172616D7300000000050005002B000000696E7075742E5556000000000500050031000000696E7075742E436F6C6F72000500090054000000656E747279506F696E74506172616D5F56534D61696E2E555600000005000A0057000000656E747279506F696E74506172616D5F56534D61696E2E436F6C6F7200000000050004000200000056534D61696E000047000400150000001E00000000000000480005001A000000000000002300000000000000480004001A0000000000000005000000480005001A0000000000000007000000100000004700030019000000020000004800050019000000000000002300000000000000470004001C0000002100000000000000470004001C0000002200000000000000470004002B0000001E0000000100000047000400310000001E0000000200000047000400500000000B0000000000000047000400540000001E0000000000000047000400570000001E0000000100000013000200010000002100030003000000010000001600030006000000200000001700040007000000060000000400000017000400080000000600000002000000180004000C00000007000000040000001E0003000B0000000C000000150004000F00000020000000010000002B0004000F0000001000000000000000200004001400000001000000080000002B0004000600000017000000000000002B00040006000000180000000000803F1E0003001A0000000C0000001E000300190000001A000000200004001B0000000200000019000000200004001D000000020000001A00000020000400300000000100000007000000170004003300000006000000030000002B000400060000003B00000012519C3E2B000400060000003D000000C4A22E3F2B0004000600000041000000C22C4D3C200004004F0000000300000007000000200004005300000003000000080000003B0004001400000015000000010000003B0004001B0000001C000000020000003B000400140000002B000000010000003B0004003000000031000000010000003B0004004F00000050000000030000003B0004005300000054000000030000003B0004004F00000057000000030000002C000600330000006D0000003D0000003D0000003D0000002C000600330000006E0000004100000041000000410000003600050001000000020000000000000003000000F8000200040000003D000400080000001300000015000000500006000700000016000000130000001700000018000000410005001D0000001E0000001C000000100000003D0004001A0000001F0000001E000000900104000B000000200000001F000000510005000C0000006C00000020000000000000009100050007000000250000006C000000160000003D000400080000002A0000002B0000003D000400070000002F000000310000004F00080033000000340000002F0000002F0000000000000001000000020000008E000500330000005D000000340000003B00000081000500330000005F0000005D0000006D000000850005003300000060000000340000005F000000810005003300000062000000600000006E00000085000500330000006300000034000000620000005100050006000000470000006300000000000000520006000700000070000000470000002F00000000000000510005000600000049000000630000000100000052000600070000007200000049000000700000000100000051000500060000004B00000063000000020000005200060007000000740000004B00000072000000020000003E00030050000000250000003E000300540000002A0000003E0003005700000074000000FD00010038000100", // Pixel Shader - "030223070005010000002800290000000000000011000200010000000E00030000000000010000000F000A00040000001A00000050534D61696E000004000000070000000A0000000F00000010000000100003001A00000007000000030003000B0000000100000005000400040000007465787475726500050004000700000073616D706C657200050008000A000000656E747279506F696E74506172616D5F50534D61696E0000050005000F000000696E7075742E5556000000000500050010000000696E7075742E436F6C6F720005000A00130000005F4D617472697853746F726167655F666C6F617434783464656661756C74000006000500130000000000000064617461000000000500070012000000436F6E7374616E74735F64656661756C7400000006000600120000000000000050726F6A656374696F6E00000500080011000000476C6F62616C506172616D735F64656661756C7400000000060006001100000000000000636F6E7374616E74730000000500060018000000676C6F62616C506172616D7300000000050006002300000073616D706C6564496D61676500000000050004002400000073616D706C656400050004001A00000050534D61696E000047000400040000002100000001000000470004000400000022000000000000004700040007000000210000000200000047000400070000002200000000000000470004000A0000001E00000000000000470004000C0000000B0000000F000000470004000F0000001E0000000000000047000400100000001E00000001000000470004001400000006000000100000004800050013000000000000002300000000000000480005001200000000000000230000000000000047000300110000000200000048000500110000000000000023000000000000004700040018000000210000000000000047000400180000002200000000000000160003000100000020000000190009000200000001000000010000000200000000000000000000000100000000000000200004000300000000000000020000001A00020005000000200004000600000000000000050000001700040008000000010000000400000020000400090000000300000008000000200004000B0000000100000008000000170004000D0000000100000002000000200004000E000000010000000D000000150004001500000020000000010000002B0004001500000016000000040000001C0004001400000008000000160000001E00030013000000140000001E00030012000000130000001E0003001100000012000000200004001700000002000000110000001300020019000000210003001B000000190000001B00030022000000020000003B0004000300000004000000000000003B0004000600000007000000000000003B000400090000000A000000030000003B0004000B0000000C000000010000003B0004000E0000000F000000010000003B0004000B00000010000000010000003B00040017000000180000000200000036000500190000001A000000000000001B000000F80002001C0000003D0004000D0000001D0000000F0000003D000400080000001E000000100000003D000400020000001F000000040000003D0004000500000020000000070000003D0004000200000021000000040000005600050022000000230000001F00000020000000570006000800000024000000230000001D00000000000000530004000800000025000000240000008500050008000000260000001E000000250000003E0003000A00000026000000FD00010038000100" + "0302230700060100000028001E0000000000000011000200010000000E00030000000000010000000F000A00040000000200000050534D61696E000011000000150000001D0000000D00000009000000100003000200000007000000030003000B000000010000000500050009000000696E7075742E436F6C6F7200050005000D000000696E7075742E55560000000005000400110000007465787475726500050004001500000073616D706C657200050006001800000073616D706C6564496D61676500000000050004001900000073616D706C656400050008001D000000656E747279506F696E74506172616D5F50534D61696E0000050004000200000050534D61696E000047000400090000001E00000001000000470004000D0000001E0000000000000047000400110000002100000001000000470004001100000022000000000000004700040015000000210000000200000047000400150000002200000000000000470004001D0000001E0000000000000013000200010000002100030003000000010000001600030005000000200000001700040006000000050000000400000020000400080000000100000006000000170004000A0000000500000002000000200004000C000000010000000A000000190009000E000000050000000100000002000000000000000000000001000000000000002000040010000000000000000E0000001A00020012000000200004001400000000000000120000001B000300170000000E000000200004001C00000003000000060000003B0004000800000009000000010000003B0004000C0000000D000000010000003B0004001000000011000000000000003B0004001400000015000000000000003B0004001C0000001D000000030000003600050001000000020000000000000003000000F8000200040000003D0004000600000007000000090000003D0004000A0000000B0000000D0000003D0004000E0000000F000000110000003D0004001200000013000000150000005600050017000000180000000F00000013000000570006000600000019000000180000000B0000000000000085000500060000001B00000007000000190000003E0003001D0000001B000000FD00010038000100" ]; private readonly ResourceLayoutDesc SpirvDesc = new() @@ -107,10 +107,13 @@ float4 PSMain(VSOutput input) : SV_TARGET private readonly string[] Metallib = [ // Vertex Shader - Legacy + "4D544C4201800200070000810E000000181300000000000058000000000000008A00000000000000160100000000000039000000000000004F0100000000000008000000000000005701000000000000300E000000000000010000008A0000004E414D45070056534D61696E00545950450100004841534820000EAC3941BE1430927847F5EEDB1D3E2EC5534205A80228D8C9BA1EB0FC38937B4F464654180000000000000000000000000000000000000000000000000056455253080002000600030001004D44535A0800300E00000000000052464C5408000400000000000000454E4454524C53541000870F000000000000910300000000000055554944100064EF3F7D1C4B30FF8EC74A1716027506454E4454390000005641545420000300506F736974696F6E5F3100008055565F31000180436F6C6F725F310002805641545905000300040406454E445408000000454E4454DEC0170B0000000014000000140E0000FFFFFFFF4243C0DE3514000003000000620C3024801005C814000000210C00004C0300000B02210002000000160000000781239141C80449061032399201840C250508191E048B628014450242920B42A41032143808184B0A3252884870C421234412878C1041920264C808B1142043468820C901325284182A282A90317CB05C9120C5C800000089200000250000003222480920624600212B249814212524981419270C85A4906052645C20246582209A0118462080610401B843104109C24CD43CD0833CD4C338D0831BB44339D04338B0831EE8413B84033DC8433AE0430A084AD21451C2E4734E234D4033493F9D82829534459430F9E0E204C0920211C0483F9D0233887008A6184204446920608E000CE608406110211086110866040000000051180000630000001BFA23F8FFFFFFFF013005C00F003800FE00908009A0803E20C2011EE0411EDE011FDAC01CEAC11DC6A10DCC011EDAA01DC2811ED001A00779A8877200087390877068877268037878877470077A28077900C2811DD80120DA211DDCA10DD8A11CCE211CD8A10DECA11CC6811EDE411EDAE01ED2811CE8011D803890033C00067778873610877A480776A08774708779000877788736480777308779680373808736688770A0077400E8411EEAA11C00C21DDEA10DDC211CDC611EDAC01CE0A10DDA211CE8011D007A90877A280780708777688379488773708772208736D0877290877798873630077868837608077A4007801EE4A11ECA0120DCE11DDA801EE4211CE0011ED2C11DCEA10DDA211CE8011D007A90877A28078098077A08877158873680077978077A288771A0877790873610877A30077328077968837948077D2807000F00A21EDC611EC2C11CCAA10DCC011EDAA01DC2811ED001A00779A8877200367402012C002900D5100EE9200F6D200EF5600EE6500EF2D006EEF00E6D100EEC900EE1300F00000049180000010000001384400013B870480779B0033AF8057B90033B688370800778608772688376088771788779C08738A0033780033780830DB7510E6D000F7A600774A0077640077A600774D006E910077A80077A80076D900E78A00778A00778D006E9100776A0077160077A100776D006E9300772A0077320077A300772D006E9600774A0077640077A600774D006E6300772A0077320077A300772D006E6600774A0077640077A600774D006F6100776A0077160077A100776D006F6200774A0077320077A300772D006F6300772A0077320077A300772D006F6400778A0077640077A600774D006F6600774A0077640077A600774D006F6900776A00771200778A00771200778D006F610077280077A10077280077A10077280076D600F71900772A00772500776A00772500776D006F620077560077A20077560077A20077560076D600F75100772A00775100772A00775100772D006F6100770200774A0077100077240077A100770200774D006EE80077A100776A0077320071A210C69BCAC0920CD900A30120000020000000100000000000390D82050D4690000200B0400000A000000321E981019114C908C092647C6044362255008E55004E5538002055120C530025006051800000000B1180000A50000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC7698770588772708374680778608774188774A08719CE530FEE000FF2500EE4900EE3400FE1200EEC500E3320281DDCC11EC2411ED2211CDC811EDCE01CE4E11DEA011E66185138B0433A9C833BCC50247660077B68073760877778077898514CF4900FF0500E331E6A1ECA611CE8211DDEC11D7E011EE4A11CCC211DF0610654858338CCC33BB0433DD04339FCC23CE4433B88C33BB0C38CC50A877998877718877408077A28077298815CE3100EECC00EE5500EF33023C1D2411EE4E117D8E11DDE011E6648193BB0833DB4831B84C3388C4339CCC33CB8C139C8C33BD4033CCC48B471080776600771088771588719DBC60EEC600FEDE006F0200FE5300FE5200FF6500E6E100EE3300EE5300FF3E006E9E00EE4500EF83023E2EC611CC2811DD8E117EC211DE6211DC4211DD8211DE8211F66209D3BBC433DB80339948339CC58BC7070077778077A08077A488777708719CE870EE5100EF0100EECC00EEF300EF3900EF4500E33283008877490073730877A708771A08774780777F88573908777A80778980700000000792000001D010000721E482043880C19097232482023818C9191D144A01028643C3132428E9021A398066400560000004A63611BB44171506C1C193091C128916310CB01490A7128484421CCB24497E30000000077636861725F73697A656672616D652D706F696E7465726169722E6D61785F6465766963655F627566666572736169722E6D61785F636F6E7374616E745F627566666572736169722E6D61785F74687265616467726F75705F627566666572736169722E6D61785F74657874757265736169722E6D61785F726561645F77726974655F74657874757265736169722E6D61785F73616D706C6572734170706C65206D6574616C2076657273696F6E2033323032332E38363420286D6574616C66652D33323032332E383634294D6574616C6169722E636F6D70696C652E64656E6F726D735F64697361626C656169722E636F6D70696C652E666173745F6D6174685F656E61626C656169722E636F6D70696C652E6672616D656275666665725F66657463685F656E61626C656169722E706F736974696F6E6169722E6172675F747970655F6E616D65666C6F6174346169722E6172675F6E616D65506F736974696F6E5F306169722E7665727465785F6F75747075747573657228544558434F4F524429666C6F61743255565F307573657228434F4C4F5229436F6C6F725F306169722E7665727465785F696E7075746169722E6C6F636174696F6E5F696E646578506F736974696F6E5F3155565F31436F6C6F725F316169722E6275666665726169722E726561646169722E616464726573735F73706163656169722E7374727563745F747970655F696E666F666C6F617434783450726F6A656374696F6E5F30436F6E7374616E74735F30636F6E7374616E74735F306169722E6172675F747970655F73697A656169722E6172675F747970655F616C69676E5F73697A65476C6F62616C506172616D735F30676C6F62616C506172616D735F3026760000000000003082C00423088C3082C00C23080C3182C01423088C3182C01C23080C3282C02423088C3282C02C23080A3082C030330C6A10ACC10C031B086D30C3C006831BCC30B001E106330C6C50B8C10C031B186F30C3C006071CCC30B00112073304C90C431BC8C11CCC402874A006733043B0CC10303304CD0C85F34091348331514F15593318D3F5401136C3500AA6700A332473906973A0064F156D33246A90696AA0064F157133246D90696DA0060F147533147360077320066330C31106AC3007763007645006334874E06973A0061F18B44118B48219D8C119C4C18306511ACC40A4822AAC822BCC30D4012ABCC29D01C0711CC7711CC7711CC7B9811BB8811BB8811BB8811B5874A0079665B9011DD0011DE0022EE0022B90836A80828C042628233636BB3697B637B23AB6321733B6B0B3B951103BB8033CC8033DD8033EE88354D8D8ECDA5CD2C8CADCE84609FC2097B0343917BB32B9B9B437B751823F482A2C4DCE852DCCEDAC2EECACECCBAE4C6E2EEDCD6D940014720A4B9373197B6B834B632BFB7A83A34B7B739B1B65080551188554C2D2E45CECCAE4E8CAF046095E01000000A9180000250000000B0A7228877780077A587098433DB8C338B04339D0C382E61CC6A10DE8411EC2C11DE6211DE8211DDEC11D1634E3600EE7500FE1200FE4400FE1200FE7500EF4B08081077928877060077678877108077A28077258709CC338B4013BA4833D94C3026B1CD8211CDCE11CDC201CE4611CDC201CE8811EC2611CD0A11CC8611CC2811DD861C1010FF4200FE1500FF4800E00000000D11000000600000007CC3CA4833B9C033B94033DA0833C94433890C30100000061200000360000001304412C1000000006000000D446004AA00CE88D008C45044110909801A0310300000000F1300000140000002247C890510A841C00000000980500006169722D616C6961732D73636F7065732856534D61696E296169722D616C6961732D73636F70652D61726728332900002B8459888515032DCC822C6C08680100FD18C8E138CE414128830C0D61A010887F3F06B34892A45010CA204384242804E28F4101FEFD1811745D974341283804E03FDBD004C06C437005B30DC1256C1010030000040000005B86E0A0852D4371D0C2964139680100000000007120000003000000320E1022840096060000000000000000650C00001F000000120394F0000000000300000006000000090000004C000000010000005800000000000000580000000100000070000000000000000F0000001C00000000000000060000000600000000000000700000000000000000000000010000000000000000000000060000000000000006000000FFFFFFFF00240000000000005D0C00000E0000001203946B0000000056534D61696E33323032332E38363461697236345F7632362D6170706C652D6D61636F737831342E302E3000000000000000000000000000010000008D030000524255467D03000000000000000000000018000000414952521000180004001000000000000000140010000000000000000400000000000000100000000400000001000000000000000A000000E00200009002000034020000F0010000AC0100007C0100004C010000D40000006800000004000000F4FDFFFF01000800040000009EFFFFFF04000000010000001400000010001000000000000400000008000C0010000000400000001C000000040000000C00000050726F6A656374696F6E5F300000000008000000666C6F617434783400000000B0FDFFFF010008000C0000000000060008000400060000000400000001000000140000001000140004000000080000000C00100010000000090000004000000018000000040000000B000000636F6E7374616E74735F30000B000000436F6E7374616E74735F3000BCFEFFFF00000400200000001C0024000000000008000C000600070010000000140018001C0020001C0000000000010200000000010000000800000040000000100000001C000000040000000E000000676C6F62616C506172616D735F3000000E000000476C6F62616C506172616D735F30000030FFFFFF0420040004000000A6FFFFFF0200000001000000500100000400000007000000436F6C6F725F31005CFFFFFF0420040004000000D2FFFFFF0100000001000000CC000000040000000400000055565F3100000000E4FEFFFF042004001400000000000E0014000000040008000C0010000E000000000000000100000090000000040000000A000000506F736974696F6E5F310000C8FFFFFF0400020004000000C0FFFFFF18000000BC0000000400000007000000436F6C6F725F30000B0000007573657228434F4C4F52290008000C000400080008000000040002001400000010001000000004000000000008000C00100000002400000014000000040000000400000055565F300000000006000000666C6F61743200000E0000007573657228544558434F4F5244290000BCFFFFFF020002001400000000000E000C00000000000000040008000E00000018000000040000000A000000506F736974696F6E5F30000006000000666C6F617434000008000E000400080008000000030000001000000000000A001000040008000C000A000000300000001C000000040000000400000004000000050000000600000007000000030000000100000002000000030000000600000056534D61696E0000454E4454", // Vertex Shader - Linear + "4D544C4201800200070000810E000000881300000000000058000000000000008A00000000000000160100000000000039000000000000004F0100000000000008000000000000005701000000000000A00E000000000000010000008A0000004E414D45070056534D61696E005459504501000048415348200018279E3BBD163C92118F96D26DD622BB504BD02519E79C64165EE9EDB89C0D444F464654180000000000000000000000000000000000000000000000000056455253080002000600030001004D44535A0800A00E00000000000052464C5408000400000000000000454E4454524C53541000F70F0000000000009103000000000000555549441000C24CC1BA27A533429FAEB8AF316BA7F7454E4454390000005641545420000300506F736974696F6E5F3100008055565F31000180436F6C6F725F310002805641545905000300040406454E445408000000454E4454DEC0170B0000000014000000840E0000FFFFFFFF4243C0DE3514000003000000620C3024801005C814000000210C0000680300000B02210002000000160000000781239141C80449061032399201840C250508191E048B628014450242920B42A41032143808184B0A3252884870C421234412878C1041920264C808B1142043468820C901325284182A282A90317CB05C9120C5C800000089200000270000003222480920624600212B249814212524981419270C85A4906052645C20246582609A0118462080610401B843104109C24CD43CD0833CD4C338D0831BB44339D04338B0831EE8413B84033DC8433AE0430A084AD21451C2E4734E234D4033493F9D82829534459430F9E0E204C0920211C0483F9D0233887008A6184204446920608E000CE6084061102110861108661861608611066004000000000051180000630000001BFA23F8FFFFFFFF013005C00F003800FE00908009A0803E20C2011EE0411EDE011FDAC01CEAC11DC6A10DCC011EDAA01DC2811ED001A00779A8877200087390877068877268037878877470077A28077900C2811DD80120DA211DDCA10DD8A11CCE211CD8A10DECA11CC6811EDE411EDAE01ED2811CE8011D803890033C00067778873610877A480776A08774708779000877788736480777308779680373808736688770A0077400E8411EEAA11C00C21DDEA10DDC211CDC611EDAC01CE0A10DDA211CE8011D007A90877A280780708777688379488773708772208736D0877290877798873630077868837608077A4007801EE4A11ECA0120DCE11DDA801EE4211CE0011ED2C11DCEA10DDA211CE8011D007A90877A28078098077A08877158873680077978077A288771A0877790873610877A30077328077968837948077D2807000F00A21EDC611EC2C11CCAA10DCC011EDAA01DC2811ED001A00779A8877200367402012C002900D5100EE9200F6D200EF5600EE6500EF2D006EEF00E6D100EEC900EE1300F00000049180000010000001384400013B870480779B0033AF8057B90033B688370800778608772688376088771788779C08738A0033780033780830DB7510E6D000F7A600774A0077640077A600774D006E910077A80077A80076D900E78A00778A00778D006E9100776A0077160077A100776D006E9300772A0077320077A300772D006E9600774A0077640077A600774D006E6300772A0077320077A300772D006E6600774A0077640077A600774D006F6100776A0077160077A100776D006F6200774A0077320077A300772D006F6300772A0077320077A300772D006F6400778A0077640077A600774D006F6600774A0077640077A600774D006F6900776A00771200778A00771200778D006F610077280077A10077280077A10077280076D600F71900772A00772500776A00772500776D006F620077560077A20077560077A20077560076D600F75100772A00775100772A00775100772D006F6100770200774A0077100077240077A100770200774D006EE80077A100776A0077320071A210C69BCAC0920CD900A30120000020000000100000000000390D82050546D0000200B0400000A000000321E981019114C908C092647C6044362255008E55004E5538002055120C530025006051800000000B1180000A50000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC7698770588772708374680778608774188774A08719CE530FEE000FF2500EE4900EE3400FE1200EEC500E3320281DDCC11EC2411ED2211CDC811EDCE01CE4E11DEA011E66185138B0433A9C833BCC50247660077B68073760877778077898514CF4900FF0500E331E6A1ECA611CE8211DDEC11D7E011EE4A11CCC211DF0610654858338CCC33BB0433DD04339FCC23CE4433B88C33BB0C38CC50A877998877718877408077A28077298815CE3100EECC00EE5500EF33023C1D2411EE4E117D8E11DDE011E6648193BB0833DB4831B84C3388C4339CCC33CB8C139C8C33BD4033CCC48B471080776600771088771588719DBC60EEC600FEDE006F0200FE5300FE5200FF6500E6E100EE3300EE5300FF3E006E9E00EE4500EF83023E2EC611CC2811DD8E117EC211DE6211DC4211DD8211DE8211F66209D3BBC433DB80339948339CC58BC7070077778077A08077A488777708719CE870EE5100EF0100EECC00EEF300EF3900EF4500E33283008877490073730877A708771A08774780777F88573908777A80778980700000000792000001D010000721E482043880C19097232482023818C9191D144A01028643C3132428E9021A398066400560000004A63611BB44171506C1C193091C128916310CB01490A7128484421CCB24497E30000000077636861725F73697A656672616D652D706F696E7465726169722E6D61785F6465766963655F627566666572736169722E6D61785F636F6E7374616E745F627566666572736169722E6D61785F74687265616467726F75705F627566666572736169722E6D61785F74657874757265736169722E6D61785F726561645F77726974655F74657874757265736169722E6D61785F73616D706C6572734170706C65206D6574616C2076657273696F6E2033323032332E38363420286D6574616C66652D33323032332E383634294D6574616C6169722E636F6D70696C652E64656E6F726D735F64697361626C656169722E636F6D70696C652E666173745F6D6174685F656E61626C656169722E636F6D70696C652E6672616D656275666665725F66657463685F656E61626C656169722E706F736974696F6E6169722E6172675F747970655F6E616D65666C6F6174346169722E6172675F6E616D65506F736974696F6E5F306169722E7665727465785F6F75747075747573657228544558434F4F524429666C6F61743255565F307573657228434F4C4F5229436F6C6F725F306169722E7665727465785F696E7075746169722E6C6F636174696F6E5F696E646578506F736974696F6E5F3155565F31436F6C6F725F316169722E6275666665726169722E726561646169722E616464726573735F73706163656169722E7374727563745F747970655F696E666F666C6F617434783450726F6A656374696F6E5F30436F6E7374616E74735F30636F6E7374616E74735F306169722E6172675F747970655F73697A656169722E6172675F747970655F616C69676E5F73697A65476C6F62616C506172616D735F30676C6F62616C506172616D735F3026760000000000003082C00423088C3082C00C23080C3182C01423088C3182C01C23080C3282C02423088C3282C02C23080A3082C030330C6A10ACC10C031B086D30C3C006831BCC30B001E106330C6C50B8C10C031B186F30C3C006071CCC30B00112073304C90C431BC8C11CCC402874A006733043B0CC10303304CD0C85F34091348331514F15593318D3F5401136C3500AA6700A332473906973A0064F156D33246A90696AA0064F157133246D90696DA0060F147533147360077320066330C31106AC3007763007645006334874E06973A0061F18B44118B48219D8C119C4C18306511ACC40A4822AAC822BCC30D4012ABCC29D01C0711CC7711CC7711CC7B9811BB8811BB8811BB8811B5874A0079665B9011DD0011DE0022EE0022B90836A80828C042628233636BB3697B637B23AB6321733B6B0B3B951103BB8033CC8033DD8033EE88354D8D8ECDA5CD2C8CADCE84609FC2097B0343917BB32B9B9B437B751823F482A2C4DCE852DCCEDAC2EECACECCBAE4C6E2EEDCD6D940014720A4B9373197B6B834B632BFB7A83A34B7B739B1B65080551188554C2D2E45CECCAE4E8CAF046095E01000000A9180000250000000B0A7228877780077A587098433DB8C338B04339D0C382E61CC6A10DE8411EC2C11DE6211DE8211DDEC11D1634E3600EE7500FE1200FE4400FE1200FE7500EF4B08081077928877060077678877108077A28077258709CC338B4013BA4833D94C3026B1CD8211CDCE11CDC201CE4611CDC201CE8811EC2611CD0A11CC8611CC2811DD861C1010FF4200FE1500FF4800E00000000D11000000600000007CC3CA4833B9C033B94033DA0833C94433890C30100000061200000500000001304412C1000000018000000C46600A88D00944019D01B01188B08822098835002221A8B0002E12038D600040285D100123300346600288E35C8288DA79F8CD278FAC9288DA7DF580369A3BDFC9136DACB1F69A3BDFC8D3588E6AA939E68AE3AE989E6AA93DE680000000000F1300000140000002247C890510A841C00000000980500006169722D616C6961732D73636F7065732856534D61696E296169722D616C6961732D73636F70652D61726728332900002B8459888515032DCC822C6C08680100FD18D1735DD7434128830C16E2A010887F3F46356DDB265110CA2083C6442804E28F4101FEFD181A06066000061605A1E01080FF208337511844E28F4104FE180CE28F8104FE1814E23FC8104CDC20435006DC6C439600B30D011A04B30DC1206C101003040000005B86E0A0852D4371D0C2964139680100000000007120000003000000320E1022840098060000000000000000650C00001F000000120394F0000000000300000006000000090000004C000000010000005800000000000000580000000100000070000000000000000F0000001C00000000000000060000000600000000000000700000000000000000000000010000000000000000000000060000000000000006000000FFFFFFFF00240000000000005D0C00000E0000001203946B0000000056534D61696E33323032332E38363461697236345F7632362D6170706C652D6D61636F737831342E302E3000000000000000000000000000010000008D030000524255467D03000000000000000000000018000000414952521000180004001000000000000000140010000000000000000400000000000000100000000400000001000000000000000A000000E00200009002000034020000F0010000AC0100007C0100004C010000D40000006800000004000000F4FDFFFF01000800040000009EFFFFFF04000000010000001400000010001000000000000400000008000C0010000000400000001C000000040000000C00000050726F6A656374696F6E5F300000000008000000666C6F617434783400000000B0FDFFFF010008000C0000000000060008000400060000000400000001000000140000001000140004000000080000000C00100010000000090000004000000018000000040000000B000000636F6E7374616E74735F30000B000000436F6E7374616E74735F3000BCFEFFFF00000400200000001C0024000000000008000C000600070010000000140018001C0020001C0000000000010200000000010000000800000040000000100000001C000000040000000E000000676C6F62616C506172616D735F3000000E000000476C6F62616C506172616D735F30000030FFFFFF0420040004000000A6FFFFFF0200000001000000500100000400000007000000436F6C6F725F31005CFFFFFF0420040004000000D2FFFFFF0100000001000000CC000000040000000400000055565F3100000000E4FEFFFF042004001400000000000E0014000000040008000C0010000E000000000000000100000090000000040000000A000000506F736974696F6E5F310000C8FFFFFF0400020004000000C0FFFFFF18000000BC0000000400000007000000436F6C6F725F30000B0000007573657228434F4C4F52290008000C000400080008000000040002001400000010001000000004000000000008000C00100000002400000014000000040000000400000055565F300000000006000000666C6F61743200000E0000007573657228544558434F4F5244290000BCFFFFFF020002001400000000000E000C00000000000000040008000E00000018000000040000000A000000506F736974696F6E5F30000006000000666C6F617434000008000E000400080008000000030000001000000000000A001000040008000C000A000000300000001C000000040000000400000004000000050000000600000007000000030000000100000002000000030000000600000056534D61696E0000454E4454", // Pixel Shader + "4D544C4201800200070000810E000000D81100000000000058000000000000008A00000000000000160100000000000008000000000000001E0100000000000008000000000000002601000000000000000E000000000000010000008A0000004E414D45070050534D61696E00545950450100014841534820008335EA1F82646DCCC623827DA6EBF0258B1E224AA4218D60D70CC077494E05494F464654180000000000000000000000000000000000000000000000000056455253080002000600030001004D44535A0800000E00000000000052464C5408000400000000000000454E4454524C53541000260F000000000000B202000000000000555549441000C710A16106E43B598CE29DE59990D629454E445408000000454E445408000000454E4454DEC0170B0000000014000000EC0D0000FFFFFFFF4243C0DE3514000003000000620C3024801005C814000000210C0000350300000B02210002000000160000000781239141C80449061032399201840C250508191E048B628014450242920B42A41032143808184B0A3252884870C421234412878C1041920264C808B1142043468820C901325284182A282A90317CB05C9120C5C8000000892000001F0000003222480920624600212B249814212524981419270C85A4906052645C20246582609A01184620801B84610401404A9A224A98FC7F22AE898A88DF1EFE698C00184420028CA429A284C9FF2580791622FAA731026010C1108C214608E5109A23408E10D41C4130470006C30842639455CE608E01D0E80D048C0000000051180000670000001BF623F8FFFFFFFF015803C014003F002460022AA00F8870800778908777C0873630877A708771680373808736688770A0077400E8411EEAA11C00C21CE4211CDAA11CDA001EDE211DDC811ECA411E807060077600887648077768037628877308077668037B288771A08777908736B8877420077A4007200EE4000F80C11DDEA10DC4A11ED2811DE8211DDC611E00C21DDEA10DD2C11DCC611EDAC01CE0A10DDA211CE8011D007A90877A28078070877768037708077798873630077868837608077A4007801EE4A11ECA0120DCE11DDA601ED2E11CDCA11CC8A10DF4A11CE4E11DE6A10DCC011EDAA01DC2811ED001A00779A88772000877788736A0077908077880877470877368837608077A4007801EE4A11ECA0120E6811EC2611CD6A10DE0411EDE811ECA611CE8E11DE4A10DC4A11ECCC11CCA411EDA601ED2411FCA01C00380A80777988770308772680373808736688770A0077400E8411EEAA11C800D843000A4B0011AFEFFFFFF7F00DA005803C014003F0024A002FA60834104C002541B8C420016A0DAC018FFFFFFFF3F006D00AC01200115D00700491800000300000013844098300C44316130880213B870480779B0033AF8057B90033B688370800778608772688376088771788779C08738A0033780033780830DB7510E6D000F7A600774A0077640077A600774D006E910077A80077A80076D900E78A00778A00778D006E9100776A0077160077A100776D006E9300772A0077320077A300772D006E9600774A0077640077A600774D006E6300772A0077320077A300772D006E6600774A0077640077A600774D006F6100776A0077160077A100776D006F6200774A0077320077A300772D006F6300772A0077320077A300772D006F6400778A0077640077A600774D006F6600774A0077640077A600774D006F6900776A00771200778A00771200778D006F610077280077A10077280077A10077280076D600F71900772A00772500776A00772500776D006F620077560077A20077560077A20077560076D600F75100772A00775100772A00775100772D006F6100770200774A0077100077240077A100770200774D006EE80077A100776A0077320071A210C69A4AC0920CD900A301000000200000001000000000003185219DB0304800000002000000000006000121B048ADE0C000064810009000000321E981019114C908C092647C604436A255008E55004E5538002055120C5300250060000B1180000A50000003308801CC4E11C6614013D88433884C38C4280077978077398710CE6000FED100EF4800E330C421EC2C11DCEA11C6630053D88433884831BCC033DC8433D8C033DCC788C7470077B08077948877070077A700376788770208719CC110EEC900EE1300F6E300FE3F00EF0500E3310C41DDE211CD8211DC2611E6630893BBC833BD04339B4033CBC833C84033BCCF0147660077B680737688772680737808770908770600776280776F8057678877780875F08877118877298877998812CEEF00EEEE00EF5C00EEC300362C8A11CE4A11CCCA11CE4A11CDC611CCA211CC4811DCA6106D6904339C84339984339C84339B8C33894433888033B94C32FBC833CFC823BD4033BB0C30CC7698770588772708374680778608774188774A08719CE530FEE000FF2500EE4900EE3400FE1200EEC500E3320281DDCC11EC2411ED2211CDC811EDCE01CE4E11DEA011E66185138B0433A9C833BCC50247660077B68073760877778077898514CF4900FF0500E331E6A1ECA611CE8211DDEC11D7E011EE4A11CCC211DF0610654858338CCC33BB0433DD04339FCC23CE4433B88C33BB0C38CC50A877998877718877408077A28077298815CE3100EECC00EE5500EF33023C1D2411EE4E117D8E11DDE011E6648193BB0833DB4831B84C3388C4339CCC33CB8C139C8C33BD4033CCC48B471080776600771088771588719DBC60EEC600FEDE006F0200FE5300FE5200FF6500E6E100EE3300EE5300FF3E006E9E00EE4500EF83023E2EC611CC2811DD8E117EC211DE6211DC4211DD8211DE8211F66209D3BBC433DB80339948339CC58BC7070077778077A08077A488777708719CE870EE5100EF0100EECC00EEF300EF3900EF4500E33283008877490073730877A708771A08774780777F88573908777A807789807000000007920000008010000721E482043880C19097232482023818C9191D144A01028643C3132428E9021A3680660604F0000004A63611BB44171506C1C194491C12092A33C06B11C8CA4388BA460C97224000077636861725F73697A656672616D652D706F696E7465726169722E6D61785F6465766963655F627566666572736169722E6D61785F636F6E7374616E745F627566666572736169722E6D61785F74687265616467726F75705F627566666572736169722E6D61785F74657874757265736169722E6D61785F726561645F77726974655F74657874757265736169722E6D61785F73616D706C6572734170706C65206D6574616C2076657273696F6E2033323032332E38363420286D6574616C66652D33323032332E383634294D6574616C6169722E636F6D70696C652E64656E6F726D735F64697361626C656169722E636F6D70696C652E666173745F6D6174685F656E61626C656169722E636F6D70696C652E6672616D656275666665725F66657463685F656E61626C656169722E72656E6465725F7461726765746169722E6172675F747970655F6E616D65666C6F6174346169722E6172675F6E616D656F75747075745F306169722E667261676D656E745F696E7075747573657228544558434F4F5244296169722E63656E7465726169722E7065727370656374697665666C6F61743255565F307573657228434F4C4F5229436F6C6F725F306169722E706F736974696F6E6169722E6E6F5F7065727370656374697665506F736974696F6E5F306169722E6172675F756E757365646169722E746578747572656169722E6C6F636174696F6E5F696E6465786169722E73616D706C657465787475726532643C666C6F61742C2073616D706C653E746578747572655F316169722E73616D706C657273616D706C657273616D706C65725F31000026630000000000003082D0082308CD3082D01023084D3182D0182308CD3182D02023084D3282D0282308CD3282D03023080930C37006011ACC30A481A006330C6930ACC10C431A106B30C39006C51ACC30A481C106330C6970B4C10C431A206E304390CC30A8C11BC0C10C8412076700073304CB0C013343D0CC70387000070F14493304A130430207135559CF1561332467306595F540913643A2065BC53D50D479332871F081011C9C41183C62108DC10C091A900118C0C1193C651099C10CC52890422998C229CC30C88128A0C28D01C0711CC7711CC7711CE7066EE0066EE0066EE0066E60D1811E5896650A1C2BB0022BD8033CB0828C042628233636BB3697B637B23AB6321733B6B0B3B951103998033AA8033BB8033CC88354D8D8ECDA5CD2C8CADCE84609F42097B0343917BB32B9B9B437B751823D482A2C4DCE852DCCEDAC2EECACECCBAE4C6E2EEDCD6D94800F720A4B9373197B6B834B632BFB7A83A34B7B739B1B65E8033FF88364C2D2E45CCCE4C2CEDACADCE84609500100A9180000250000000B0A7228877780077A587098433DB8C338B04339D0C382E61CC6A10DE8411EC2C11DE6211DE8211DDEC11D1634E3600EE7500FE1200FE4400FE1200FE7500EF4B08081077928877060077678877108077A28077258709CC338B4013BA4833D94C3026B1CD8211CDCE11CDC201CE4611CDC201CE8811EC2611CD0A11CC8611CC2811DD861C1010FF4200FE1500FF4800E00000000D11000000600000007CC3CA4833B9C033B94033DA0833C94433890C30100000061200000310000001304412C1000000004000000C46A600480DC08008111001233000000F13000001C0000002247C890510E042B00000000188601006169722D616C6961732D73636F7065732850534D61696E296169722D616C6961732D73636F70652D73616D706C6572736169722D616C6961732D73636F70652D74657874757265732B8456508515832BB4C22AAC185EA115586183F00AAE00002306CD108260F05887A114032108CC68420060B088FF6C0311001B04C4000000020000005B06E07805000000000000007120000003000000320E1022840084060000000000000000650C00002500000012039428010000000300000021000000090000004C000000010000005800000000000000580000000200000088000000000000002A0000001C00000000000000060000000600000000000000880000000000000000000000020000000000000000000000060000000000000006000000FFFFFFFF00240000060000001B000000060000001B000000FFFFFFFF08240000000000005D0C000015000000120394A60000000050534D61696E6169722E73616D706C655F746578747572655F32642E763466333233323032332E38363461697236345F7632362D6170706C652D6D61636F737831342E302E3000000000000001000000AE020000524255469E02000000000000000000000000140000004149525200000A0018000400100014000A000000000000000400000000000000100000000400000001000000000000000700000008020000AC0100004801000008010000C000000054000000040000001CFEFFFF010004001400000000000E0014000000040008000C0010000E000000000000000100000018000000040000000900000073616D706C65725F310000000700000073616D706C65720068FEFFFF0200040018000000000012001800000008000C00070000001000140012000000000000040000000001000000180000000400000009000000746578747572655F31000000180000007465787475726532643C666C6F61742C2073616D706C653E00000000C4FFFFFF02300400140000001000100000000000000008000C000700100000000000000100010000040000000A000000506F736974696F6E5F30000008000C0004000800080000000030040004000000C2FFFFFF0000010118000000C80000000400000007000000436F6C6F725F30000B0000007573657228434F4C4F52290050FFFFFF0030040018000000000012001400000008000000060007000C00100012000000000001012400000014000000040000000400000055565F300000000006000000666C6F61743200000E0000007573657228544558434F4F5244290000B0FFFFFF0010020018000000000012001400000004000800000000000C0010001200000000000000000000001800000004000000080000006F75747075745F300000000006000000666C6F617434000008000E000400080008000000010000001000000000000A001000040008000C000A0000002C000000200000000400000005000000020000000300000004000000050000000600000001000000010000000600000050534D61696E0000454E4454" ]; private readonly ResourceLayoutDesc MetallibDesc = new() @@ -129,8 +132,8 @@ float4 PSMain(VSOutput input) : SV_TARGET private readonly GraphicsPipeline graphicsPipeline; private readonly Dictionary textureBindings = []; private readonly Dictionary textureViewBindings = []; - private readonly Dictionary imTextures = []; - private readonly Dictionary imResourceTables = []; + private readonly Dictionary resourceTableBindings = []; + private readonly Dictionary drawDataTextures = []; private Buffer? vertexBuffer; private Buffer? indexBuffer; @@ -221,12 +224,12 @@ public ImTextureID Binding(Texture texture) if (!textureBindings.TryGetValue(texture, out ImTextureID textureID)) { ulong id = 0; - while (imResourceTables.ContainsKey(id)) + while (resourceTableBindings.ContainsKey(id)) { id++; } - imResourceTables[textureBindings[texture] = textureID = id] = Context.CreateResourceTable(new() + resourceTableBindings[textureBindings[texture] = textureID = id] = Context.CreateResourceTable(new() { Layout = resourceLayout, Resources = [constants, texture, sampler] @@ -241,12 +244,12 @@ public ImTextureID Binding(TextureView textureView) if (!textureViewBindings.TryGetValue(textureView, out ImTextureID textureID)) { ulong id = 0; - while (imResourceTables.ContainsKey(id)) + while (resourceTableBindings.ContainsKey(id)) { id++; } - imResourceTables[textureViewBindings[textureView] = textureID = id] = Context.CreateResourceTable(new() + resourceTableBindings[textureViewBindings[textureView] = textureID = id] = Context.CreateResourceTable(new() { Layout = resourceLayout, Resources = [constants, textureView, sampler] @@ -256,24 +259,6 @@ public ImTextureID Binding(TextureView textureView) return textureID; } - public void RemoveBinding(ImTextureID textureID) - { - if (imResourceTables.Remove(textureID, out ResourceTable? resourceTable)) - { - resourceTable.Dispose(); - } - - if (textureBindings.FirstOrDefault(kv => kv.Value == textureID).Key is Texture texture) - { - textureBindings.Remove(texture); - } - - if (textureViewBindings.FirstOrDefault(kv => kv.Value == textureID).Key is TextureView textureView) - { - textureViewBindings.Remove(textureView); - } - } - public void Render(CommandBuffer commandBuffer, FrameBuffer frameBuffer, ClearValue clearValue, ImDrawDataPtr drawData) { if (drawData.CmdListsCount is 0) @@ -281,6 +266,8 @@ public void Render(CommandBuffer commandBuffer, FrameBuffer frameBuffer, ClearVa return; } + drawData.ScaleClipRects(drawData.FramebufferScale); + for (int i = 0; i < drawData.Textures.Size; i++) { ImTextureDataPtr textureData = drawData.Textures[i]; @@ -320,13 +307,13 @@ public void Render(CommandBuffer commandBuffer, FrameBuffer frameBuffer, ClearVa textureData.SetTexID(Binding(texture)); textureData.SetStatus(ImTextureStatus.Ok); - imTextures[textureData.TexID] = texture; + drawDataTextures[textureData.TexID] = texture; } break; case ImTextureStatus.WantUpdates: { - if (imTextures.TryGetValue(textureData.TexID, out Texture? texture)) + if (drawDataTextures.TryGetValue(textureData.TexID, out Texture? texture)) { for (int j = 0; j < textureData.Updates.Size; j++) { @@ -368,9 +355,7 @@ public void Render(CommandBuffer commandBuffer, FrameBuffer frameBuffer, ClearVa case ImTextureStatus.WantDestroy: { - RemoveBinding(textureData.TexID); - - if (imTextures.Remove(textureData.TexID, out Texture? texture)) + if (drawDataTextures.Remove(textureData.TexID, out Texture? texture)) { texture.Dispose(); } @@ -382,26 +367,28 @@ public void Render(CommandBuffer commandBuffer, FrameBuffer frameBuffer, ClearVa } } - uint totalVertexSizeInBytes = (uint)(sizeof(ImDrawVert) * drawData.TotalVtxCount); + RemoveDestroyedBindings(); + + uint totalVertexSizeInBytes = (uint)(sizeof(ImDrawVert) * (int)(drawData.TotalVtxCount * 1.2)); if (vertexBuffer is null || vertexBuffer.Desc.SizeInBytes < totalVertexSizeInBytes) { vertexBuffer?.Dispose(); vertexBuffer = Context.CreateBuffer(new() { - SizeInBytes = totalVertexSizeInBytes + (totalVertexSizeInBytes / 2), + SizeInBytes = totalVertexSizeInBytes, StrideInBytes = (uint)sizeof(ImDrawVert), Flags = BufferUsageFlags.Vertex | BufferUsageFlags.MapWrite }); } - uint totalIndexSizeInBytes = (uint)(sizeof(ushort) * drawData.TotalIdxCount); + uint totalIndexSizeInBytes = (uint)(sizeof(ushort) * (int)(drawData.TotalIdxCount * 1.2)); if (indexBuffer is null || indexBuffer.Desc.SizeInBytes < totalIndexSizeInBytes) { indexBuffer?.Dispose(); indexBuffer = Context.CreateBuffer(new() { - SizeInBytes = totalIndexSizeInBytes + (totalIndexSizeInBytes / 2), + SizeInBytes = totalIndexSizeInBytes, StrideInBytes = sizeof(ushort), Flags = BufferUsageFlags.Index | BufferUsageFlags.MapWrite }); @@ -433,7 +420,7 @@ public void Render(CommandBuffer commandBuffer, FrameBuffer frameBuffer, ClearVa commandBuffer.BeginDebugEvent("ImGui"); - commandBuffer.BeginRenderPass(frameBuffer, clearValue, imResourceTables.Values); + commandBuffer.BeginRenderPass(frameBuffer, clearValue, resourceTableBindings.Values); commandBuffer.SetPipeline(graphicsPipeline); commandBuffer.SetVertexBuffer(vertexBuffer, 0, 0); @@ -469,7 +456,7 @@ public void Render(CommandBuffer commandBuffer, FrameBuffer frameBuffer, ClearVa } commandBuffer.SetScissors([scissor]); - commandBuffer.SetResourceTable(imResourceTables[drawCmd.TexRef.GetTexID()]); + commandBuffer.SetResourceTable(resourceTableBindings[drawCmd.TexRef.GetTexID()]); commandBuffer.DrawIndexed(drawCmd.ElemCount, 1, (uint)(drawCmd.IdxOffset + indexOffset), (int)(drawCmd.VtxOffset + vertexOffset), 0); } } @@ -488,17 +475,17 @@ protected override void Destroy() indexBuffer?.Dispose(); vertexBuffer?.Dispose(); - foreach (ResourceTable resourceTable in imResourceTables.Values) + foreach (Texture texture in drawDataTextures.Values) { - resourceTable.Dispose(); + texture.Dispose(); } - imResourceTables.Clear(); + drawDataTextures.Clear(); - foreach (Texture texture in imTextures.Values) + foreach (ResourceTable resourceTable in resourceTableBindings.Values) { - texture.Dispose(); + resourceTable.Dispose(); } - imTextures.Clear(); + resourceTableBindings.Clear(); textureViewBindings.Clear(); textureBindings.Clear(); @@ -507,9 +494,47 @@ protected override void Destroy() sampler.Dispose(); constants.Dispose(); } + + private void RemoveDestroyedBindings() + { + ImTextureID[] destroyedTextureIDs = [.. resourceTableBindings.Keys.Where(textureID => + { + if (textureBindings.FirstOrDefault(kv => kv.Value == textureID).Key is Texture texture) + { + return texture.IsDisposed; + } + + if (textureViewBindings.FirstOrDefault(kv => kv.Value == textureID).Key is TextureView textureView) + { + return textureView.IsDisposed; + } + + return false; + })]; + + foreach (ImTextureID textureID in destroyedTextureIDs) + { + if (resourceTableBindings.Remove(textureID, out ResourceTable? resourceTable)) + { + resourceTable.Dispose(); + } + + if (textureViewBindings.FirstOrDefault(kv => kv.Value == textureID).Key is TextureView textureView) + { + textureViewBindings.Remove(textureView); + } + + if (textureBindings.FirstOrDefault(kv => kv.Value == textureID).Key is Texture texture) + { + textureBindings.Remove(texture); + } + } + } } +[StructLayout(LayoutKind.Explicit, Size = 64)] file struct Constants { + [FieldOffset(0)] public Matrix4x4 Projection; } diff --git a/sources/Extensions/Zenith.NET.Extensions.ImageSharp/Extensions.cs b/sources/Extensions/Zenith.NET.Extensions.ImageSharp/Extensions.cs index ca7dcc3b..bfb4c7fe 100644 --- a/sources/Extensions/Zenith.NET.Extensions.ImageSharp/Extensions.cs +++ b/sources/Extensions/Zenith.NET.Extensions.ImageSharp/Extensions.cs @@ -8,7 +8,7 @@ public static class Extensions { extension(GraphicsContext context) { - public Texture LoadTextureFromStream(Stream stream, bool generateMipMaps = false) + public Texture LoadTextureFromStream(Stream stream, bool generateMipMaps = true) { using Image image = Image.Load(stream); diff --git a/sources/Extensions/Zenith.NET.Extensions.Slang/Extensions.cs b/sources/Extensions/Zenith.NET.Extensions.Slang/Extensions.cs index 05a7ed52..87749a66 100644 --- a/sources/Extensions/Zenith.NET.Extensions.Slang/Extensions.cs +++ b/sources/Extensions/Zenith.NET.Extensions.Slang/Extensions.cs @@ -24,18 +24,20 @@ public Shader LoadShaderFromFile(string file, string entryPoint, ShaderStageFlag } } + arguments.Add("-target"); + switch (context.Backend) { case Backend.DirectX12: - arguments.AddRange(["-profile", "sm_6_6", "-target", "dxil"]); + arguments.AddRange(["dxil", "-profile", "sm_6_6"]); break; case Backend.Metal: - arguments.AddRange(["-target", "metallib"]); + arguments.AddRange(["metallib", "-capability", "metallib_latest"]); break; case Backend.Vulkan: - arguments.AddRange(["-fvk-use-dx-layout", "-fvk-use-entrypoint-name", "-target", "spirv"]); + arguments.AddRange(["spirv", "-capability", "spirv_latest", "-fvk-use-entrypoint-name"]); break; } diff --git a/sources/Zenith.NET.DirectX12/DXCommandBuffer.cs b/sources/Zenith.NET.DirectX12/DXCommandBuffer.cs index aaca9b30..7f08263a 100644 --- a/sources/Zenith.NET.DirectX12/DXCommandBuffer.cs +++ b/sources/Zenith.NET.DirectX12/DXCommandBuffer.cs @@ -72,6 +72,13 @@ protected override void CopyBufferToTextureImpl(Buffer src, uint srcOffsetInByte dxSrc.TransitionStates(this, ResourceStates.CopySource); dxDest.TransitionStates(this, destSlice, ResourceStates.CopyDest); + (uint blockWidth, uint blockHeight, uint blocksWide, _) = ZenithHelper.BlockLayout(dxDest.Desc.Format, destExtent.Width, destExtent.Height); + + uint offsetX = ZenithHelper.Align(destOffset.X, blockWidth); + uint offsetY = ZenithHelper.Align(destOffset.Y, blockHeight); + uint extentWidth = ZenithHelper.Align(destExtent.Width, blockWidth); + uint extentHeight = ZenithHelper.Align(destExtent.Height, blockHeight); + TextureCopyLocation srcLocation = new() { PResource = dxSrc.Resource, @@ -82,15 +89,15 @@ protected override void CopyBufferToTextureImpl(Buffer src, uint srcOffsetInByte Footprint = new() { Format = DXFormats.DirectX12(dxDest.Desc.Format), - Width = destExtent.Width, - Height = destExtent.Height, + Width = extentWidth, + Height = extentHeight, Depth = destExtent.Depth, - RowPitch = ZenithHelper.Align(ZenithHelper.SizeInBytes(dxDest.Desc.Format) * destExtent.Width, GraphicsContext.TextureRowPitchAlignment) + RowPitch = ZenithHelper.Align(ZenithHelper.SizeInBytes(dxDest.Desc.Format) * blocksWide, GraphicsContext.TextureRowPitchAlignment) } } }; - Box srcBox = new(0, 0, 0, destExtent.Width, destExtent.Height, destExtent.Depth); + Box srcBox = new(0, 0, 0, extentWidth, extentHeight, destExtent.Depth); TextureCopyLocation destLocation = new() { @@ -99,7 +106,7 @@ protected override void CopyBufferToTextureImpl(Buffer src, uint srcOffsetInByte SubresourceIndex = ZenithHelper.SubresourceIndex(dxDest.Desc, destSlice) }; - GraphicsCommandList4.CopyTextureRegion(&destLocation, destOffset.X, destOffset.Y, destOffset.Z, &srcLocation, &srcBox); + GraphicsCommandList4.CopyTextureRegion(&destLocation, offsetX, offsetY, destOffset.Z, &srcLocation, &srcBox); dxSrc.TransitionStates(this, srcOldStates); dxDest.TransitionStates(this, destSlice, destOldStates); @@ -149,6 +156,13 @@ protected override void CopyTextureToBufferImpl(Texture src, TextureSlice srcSli dxSrc.TransitionStates(this, srcSlice, ResourceStates.CopySource); dxDest.TransitionStates(this, ResourceStates.CopyDest); + (uint blockWidth, uint blockHeight, uint blocksWide, _) = ZenithHelper.BlockLayout(dxSrc.Desc.Format, srcExtent.Width, srcExtent.Height); + + uint offsetX = ZenithHelper.Align(srcOffset.X, blockWidth); + uint offsetY = ZenithHelper.Align(srcOffset.Y, blockHeight); + uint extentWidth = ZenithHelper.Align(srcExtent.Width, blockWidth); + uint extentHeight = ZenithHelper.Align(srcExtent.Height, blockHeight); + TextureCopyLocation srcLocation = new() { PResource = dxSrc.Resource, @@ -156,7 +170,7 @@ protected override void CopyTextureToBufferImpl(Texture src, TextureSlice srcSli SubresourceIndex = ZenithHelper.SubresourceIndex(dxSrc.Desc, srcSlice) }; - Box srcBox = new(srcOffset.X, srcOffset.Y, srcOffset.Z, srcOffset.X + srcExtent.Width, srcOffset.Y + srcExtent.Height, srcOffset.Z + srcExtent.Depth); + Box srcBox = new(offsetX, offsetY, srcOffset.Z, offsetX + extentWidth, offsetY + extentHeight, srcOffset.Z + srcExtent.Depth); TextureCopyLocation destLocation = new() { @@ -168,10 +182,10 @@ protected override void CopyTextureToBufferImpl(Texture src, TextureSlice srcSli Footprint = new() { Format = DXFormats.DirectX12(dxSrc.Desc.Format), - Width = srcExtent.Width, - Height = srcExtent.Height, + Width = extentWidth, + Height = extentHeight, Depth = srcExtent.Depth, - RowPitch = ZenithHelper.Align(ZenithHelper.SizeInBytes(dxSrc.Desc.Format) * srcExtent.Width, GraphicsContext.TextureRowPitchAlignment) + RowPitch = ZenithHelper.Align(ZenithHelper.SizeInBytes(dxSrc.Desc.Format) * blocksWide, GraphicsContext.TextureRowPitchAlignment) } } }; @@ -218,7 +232,7 @@ protected override void BeginRenderPassImpl(FrameBuffer frameBuffer, ClearValue { DXFrameBuffer dxFrameBuffer = frameBuffer.DirectX12(); - dxFrameBuffer.PrepareAttachmentsForRendering(this); + dxFrameBuffer.PrepareAttachments(this); bool clearColor = clearValue.Flags.HasFlag(ClearFlags.Color); bool clearDepth = clearValue.Flags.HasFlag(ClearFlags.Depth); @@ -275,7 +289,7 @@ protected override void EndRenderPassImpl(FrameBuffer frameBuffer) { GraphicsCommandList4.EndRenderPass(); - frameBuffer.DirectX12().FinalizeColorAttachmentsForPresent(this); + frameBuffer.DirectX12().PresentColorAttachments(this); } protected override void SetScissorsImpl(Scissor[] scissors) diff --git a/sources/Zenith.NET.DirectX12/DXFormats.cs b/sources/Zenith.NET.DirectX12/DXFormats.cs index 066dda31..13a0c234 100644 --- a/sources/Zenith.NET.DirectX12/DXFormats.cs +++ b/sources/Zenith.NET.DirectX12/DXFormats.cs @@ -280,6 +280,34 @@ ResourceType.StructuredBufferReadWrite or }; } + public static (PrimitiveTopologyType PrimitiveTopologyType, D3DPrimitiveTopology PrimitiveTopology) DirectX12(PrimitiveTopology primitiveTopology) + { + return + ( + primitiveTopology switch + { + PrimitiveTopology.PointList => PrimitiveTopologyType.Point, + + PrimitiveTopology.LineList or + PrimitiveTopology.LineStrip => PrimitiveTopologyType.Line, + + PrimitiveTopology.TriangleList or + PrimitiveTopology.TriangleStrip => PrimitiveTopologyType.Triangle, + + _ => PrimitiveTopologyType.Undefined + }, + primitiveTopology switch + { + PrimitiveTopology.PointList => D3DPrimitiveTopology.D3DPrimitiveTopologyPointlist, + PrimitiveTopology.LineList => D3DPrimitiveTopology.D3DPrimitiveTopologyLinelist, + PrimitiveTopology.LineStrip => D3DPrimitiveTopology.D3DPrimitiveTopologyLinestrip, + PrimitiveTopology.TriangleList => D3DPrimitiveTopology.D3DPrimitiveTopologyTrianglelist, + PrimitiveTopology.TriangleStrip => D3DPrimitiveTopology.D3DPrimitiveTopologyTrianglestrip, + _ => D3DPrimitiveTopology.D3DPrimitiveTopologyUndefined + } + ); + } + public static ShaderVisibility DirectX12(ShaderStageFlags shaderStageFlags) { if (shaderStageFlags.HasFlag(ShaderStageFlags.Vertex)) @@ -461,34 +489,6 @@ public static Format DirectX12(ElementFormat elementFormat) }; } - public static (PrimitiveTopologyType PrimitiveTopologyType, D3DPrimitiveTopology PrimitiveTopology) DirectX12(PrimitiveTopology primitiveTopology) - { - return - ( - primitiveTopology switch - { - PrimitiveTopology.PointList => PrimitiveTopologyType.Point, - - PrimitiveTopology.LineList or - PrimitiveTopology.LineStrip => PrimitiveTopologyType.Line, - - PrimitiveTopology.TriangleList or - PrimitiveTopology.TriangleStrip => PrimitiveTopologyType.Triangle, - - _ => PrimitiveTopologyType.Undefined - }, - primitiveTopology switch - { - PrimitiveTopology.PointList => D3DPrimitiveTopology.D3DPrimitiveTopologyPointlist, - PrimitiveTopology.LineList => D3DPrimitiveTopology.D3DPrimitiveTopologyLinelist, - PrimitiveTopology.LineStrip => D3DPrimitiveTopology.D3DPrimitiveTopologyLinestrip, - PrimitiveTopology.TriangleList => D3DPrimitiveTopology.D3DPrimitiveTopologyTrianglelist, - PrimitiveTopology.TriangleStrip => D3DPrimitiveTopology.D3DPrimitiveTopologyTrianglestrip, - _ => D3DPrimitiveTopology.D3DPrimitiveTopologyUndefined - } - ); - } - public static CommandListType DirectX12(CommandQueueType commandQueueType) { return commandQueueType switch diff --git a/sources/Zenith.NET.DirectX12/DXFrameBuffer.cs b/sources/Zenith.NET.DirectX12/DXFrameBuffer.cs index f3032da1..7babe8dd 100644 --- a/sources/Zenith.NET.DirectX12/DXFrameBuffer.cs +++ b/sources/Zenith.NET.DirectX12/DXFrameBuffer.cs @@ -128,7 +128,7 @@ public DXFrameBuffer(DXGraphicsContext context, FrameBufferDesc desc) : base(con public DXDescriptorToken[] Tokens { get; } - public void PrepareAttachmentsForRendering(DXCommandBuffer commandBuffer) + public void PrepareAttachments(DXCommandBuffer commandBuffer) { foreach (FrameBufferAttachment attachment in Desc.ColorAttachments) { @@ -138,7 +138,7 @@ public void PrepareAttachmentsForRendering(DXCommandBuffer commandBuffer) Desc.DepthStencilAttachment?.Target.DirectX12().TransitionStates(commandBuffer, Desc.DepthStencilAttachment.Value.Slice, ResourceStates.DepthWrite); } - public void FinalizeColorAttachmentsForPresent(DXCommandBuffer commandBuffer) + public void PresentColorAttachments(DXCommandBuffer commandBuffer) { foreach (FrameBufferAttachment attachment in Desc.ColorAttachments) { diff --git a/sources/Zenith.NET.DirectX12/DXGraphicsPipeline.cs b/sources/Zenith.NET.DirectX12/DXGraphicsPipeline.cs index 475e0963..342ac305 100644 --- a/sources/Zenith.NET.DirectX12/DXGraphicsPipeline.cs +++ b/sources/Zenith.NET.DirectX12/DXGraphicsPipeline.cs @@ -18,7 +18,8 @@ public DXGraphicsPipeline(DXGraphicsContext context, GraphicsPipelineDesc desc) { SampleMask = uint.MaxValue, VS = desc.Vertex.DirectX12().GetShaderBytecode(scope), - PS = desc.Pixel.DirectX12().GetShaderBytecode(scope) + PS = desc.Pixel.DirectX12().GetShaderBytecode(scope), + PrimitiveTopologyType = DXFormats.DirectX12(desc.PrimitiveTopology).PrimitiveTopologyType }; // RenderStates - Output @@ -191,11 +192,6 @@ public DXGraphicsPipeline(DXGraphicsContext context, GraphicsPipelineDesc desc) }; } - // PrimitiveTopology - { - graphicsPipelineStateDesc.PrimitiveTopologyType = DXFormats.DirectX12(desc.PrimitiveTopology).PrimitiveTopologyType; - } - context.Device.CreateGraphicsPipelineState(&graphicsPipelineStateDesc, out PipelineState).Success(); } diff --git a/sources/Zenith.NET.DirectX12/DXTopLevelAccelerationStructure.cs b/sources/Zenith.NET.DirectX12/DXTopLevelAccelerationStructure.cs index 60de1d87..ba557aad 100644 --- a/sources/Zenith.NET.DirectX12/DXTopLevelAccelerationStructure.cs +++ b/sources/Zenith.NET.DirectX12/DXTopLevelAccelerationStructure.cs @@ -130,8 +130,8 @@ private void FillInstanceBuffer(TopLevelAccelerationStructureDesc desc, out Buil instances[i] = new() { - InstanceID = instance.InstanceID, - InstanceMask = instance.InstanceMask, + InstanceID = instance.ID, + InstanceMask = instance.Mask, Flags = (uint)DXFormats.DirectX12(instance.Flags), AccelerationStructure = instance.AccelerationStructure.DirectX12().AccelerationStructureBuffer.GPUVirtualAddress }; diff --git a/sources/Zenith.NET.Metal/Extensions.cs b/sources/Zenith.NET.Metal/Extensions.cs index 00e75089..33bbf9b5 100644 --- a/sources/Zenith.NET.Metal/Extensions.cs +++ b/sources/Zenith.NET.Metal/Extensions.cs @@ -1,4 +1,7 @@ -namespace Zenith.NET.Metal; +using System.Diagnostics; +using Metal.NET; + +namespace Zenith.NET.Metal; public static class Extensions { @@ -10,71 +13,152 @@ public static GraphicsContext CreateMetal(bool useValidationLayer) } } + extension(NSError error) + { + internal void Success() + { + if (!error.IsNull) + { + Debug.WriteLine($"Metal call failed with error: {error.LocalizedDescription}"); + + error.Dispose(); + } + } + } + extension(CommandBuffer commandBuffer) { + internal MTLCommandBuffer Metal() + { + return (MTLCommandBuffer)commandBuffer; + } } extension(SwapChain swapChain) { + internal MTLSwapChain Metal() + { + return (MTLSwapChain)swapChain; + } } extension(FrameBuffer frameBuffer) { + internal MTLFrameBuffer Metal() + { + return (MTLFrameBuffer)frameBuffer; + } } extension(Shader shader) { + internal MTLShader Metal() + { + return (MTLShader)shader; + } } extension(Buffer buffer) { + internal MTLBuffer Metal() + { + return (MTLBuffer)buffer; + } } extension(BufferView bufferView) { + internal MTLBufferView Metal() + { + return (MTLBufferView)bufferView; + } } extension(Texture texture) { + internal MTLTexture Metal() + { + return (MTLTexture)texture; + } } extension(TextureView textureView) { + internal MTLTextureView Metal() + { + return (MTLTextureView)textureView; + } } extension(Sampler sampler) { + internal MTLSampler Metal() + { + return (MTLSampler)sampler; + } } extension(BottomLevelAccelerationStructure bottomLevelAccelerationStructure) { + internal MTLBottomLevelAccelerationStructure Metal() + { + return (MTLBottomLevelAccelerationStructure)bottomLevelAccelerationStructure; + } } extension(TopLevelAccelerationStructure topLevelAccelerationStructure) { + internal MTLTopLevelAccelerationStructure Metal() + { + return (MTLTopLevelAccelerationStructure)topLevelAccelerationStructure; + } } extension(ResourceLayout resourceLayout) { + internal MTLResourceLayout Metal() + { + return (MTLResourceLayout)resourceLayout; + } } extension(ResourceTable resourceTable) { + internal MTLResourceTable Metal() + { + return (MTLResourceTable)resourceTable; + } } extension(GraphicsPipeline graphicsPipeline) { + internal MTLGraphicsPipeline Metal() + { + return (MTLGraphicsPipeline)graphicsPipeline; + } } extension(ComputePipeline computePipeline) { + internal MTLComputePipeline Metal() + { + return (MTLComputePipeline)computePipeline; + } } extension(MeshShadingPipeline meshShadingPipeline) { + internal MTLMeshShadingPipeline Metal() + { + return (MTLMeshShadingPipeline)meshShadingPipeline; + } } extension(QueryHeap queryHeap) { + internal MTLQueryHeap Metal() + { + return (MTLQueryHeap)queryHeap; + } } } \ No newline at end of file diff --git a/sources/Zenith.NET.Metal/MTLBottomLevelAccelerationStructure.cs b/sources/Zenith.NET.Metal/MTLBottomLevelAccelerationStructure.cs new file mode 100644 index 00000000..18b2ff2e --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLBottomLevelAccelerationStructure.cs @@ -0,0 +1,118 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLBottomLevelAccelerationStructure : BottomLevelAccelerationStructure +{ + public MTLAccelerationStructure AccelerationStructure; + + public unsafe MTLBottomLevelAccelerationStructure(MTLGraphicsContext context, BottomLevelAccelerationStructureDesc desc, MTLCommandBuffer commandBuffer) : base(context, desc) + { + uint geometryCount = (uint)desc.Geometries.Length; + + TransformBuffer = new(context, new() + { + SizeInBytes = (uint)(sizeof(MTLPackedFloat4x3) * geometryCount), + StrideInBytes = (uint)sizeof(MTLPackedFloat4x3), + Flags = BufferUsageFlags.AccelerationStructure | BufferUsageFlags.MapWrite + }); + + MappedMemory mappedMemory = TransformBuffer.Map(); + + desc.Geometries.Select(static item => *(MTLPackedFloat4x3*)&item.Triangles.Transform).ToArray().CopyTo(new Span((MTLPackedFloat4x3*)mappedMemory.Pointer, (int)geometryCount)); + + TransformBuffer.Unmap(); + + MTL4AccelerationStructureGeometryDescriptor[] geometryDescriptors = new MTL4AccelerationStructureGeometryDescriptor[geometryCount]; + for (uint i = 0; i < geometryCount; i++) + { + RayTracingGeometry geometry = desc.Geometries[i]; + + switch (geometry.Type) + { + case RayTracingGeometryType.Triangles: + geometryDescriptors[i] = new MTL4AccelerationStructureTriangleGeometryDescriptor() + { + VertexBuffer = new() + { + BufferAddress = geometry.Triangles.VertexBuffer.Metal().Buffer.GpuAddress + geometry.Triangles.VertexOffsetInBytes, + Length = geometry.Triangles.VertexStrideInBytes * geometry.Triangles.VertexCount + }, + VertexFormat = MTLFormats.Metal(geometry.Triangles.VertexFormat).AttributeFormat, + VertexStride = geometry.Triangles.VertexStrideInBytes, + IndexBuffer = geometry.Triangles.IndexBuffer is not null ? new() + { + BufferAddress = geometry.Triangles.IndexBuffer.Metal().Buffer.GpuAddress + geometry.Triangles.IndexOffsetInBytes, + Length = (uint)(geometry.Triangles.IndexFormat is IndexFormat.UInt16 ? sizeof(ushort) : sizeof(uint)) * geometry.Triangles.IndexCount + } : default, + IndexType = MTLFormats.Metal(geometry.Triangles.IndexFormat), + TriangleCount = geometry.Triangles.IndexBuffer is not null ? geometry.Triangles.IndexCount / 3 : geometry.Triangles.VertexCount / 3, + TransformationMatrixBuffer = new() + { + BufferAddress = TransformBuffer.GpuAddress + (uint)(sizeof(MTLPackedFloat4x3) * i), + Length = (uint)sizeof(MTLPackedFloat4x3) + }, + TransformationMatrixLayout = MTLMatrixLayout.RowMajor, + Opaque = geometry.Flags.HasFlag(RayTracingGeometryFlags.Opaque) + }; + break; + + case RayTracingGeometryType.AABBs: + geometryDescriptors[i] = new MTL4AccelerationStructureBoundingBoxGeometryDescriptor() + { + BoundingBoxBuffer = new() + { + BufferAddress = geometry.AABBs.Buffer.Metal().Buffer.GpuAddress + geometry.AABBs.OffsetInBytes, + Length = geometry.AABBs.StrideInBytes * geometry.AABBs.Count + }, + BoundingBoxStride = geometry.AABBs.StrideInBytes, + BoundingBoxCount = geometry.AABBs.Count, + Opaque = geometry.Flags.HasFlag(RayTracingGeometryFlags.Opaque) + }; + break; + } + } + + MTL4PrimitiveAccelerationStructureDescriptor descriptor = new() + { + GeometryDescriptors = geometryDescriptors, + Usage = MTLFormats.Metal(desc.Flags) + }; + + MTLAccelerationStructureSizes sizes = context.Device.AccelerationStructureSizes(descriptor); + + AccelerationStructure = context.Device.MakeAccelerationStructure(sizes.AccelerationStructureSize); + context.AddAllocation(AccelerationStructure); + + ScratchBuffer = new(context, new() + { + SizeInBytes = (uint)sizes.BuildScratchBufferSize, + StrideInBytes = (uint)sizes.BuildScratchBufferSize, + Flags = BufferUsageFlags.ShaderResource + }); + + commandBuffer.CommandEncoder.Compute?.Build(AccelerationStructure, descriptor, new(ScratchBuffer.Buffer.GpuAddress, ScratchBuffer.Desc.SizeInBytes)); + commandBuffer.CommandEncoder.Compute?.BarrierAfterEncoderStages(MTLStages.AccelerationStructure, MTLStages.AccelerationStructure, MTL4VisibilityOptions.Device); + } + + public new MTLGraphicsContext Context => (MTLGraphicsContext)base.Context; + + public MTLBuffer TransformBuffer { get; } + + public MTLBuffer ScratchBuffer { get; } + + protected override void SetResourceName(string name) + { + AccelerationStructure.Label = name; + } + + protected override void Destroy() + { + Context.RemoveAllocation(AccelerationStructure); + + AccelerationStructure.Dispose(); + + ScratchBuffer.Dispose(); + TransformBuffer.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLBuffer.cs b/sources/Zenith.NET.Metal/MTLBuffer.cs new file mode 100644 index 00000000..2dae0e98 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLBuffer.cs @@ -0,0 +1,38 @@ +namespace Zenith.NET.Metal; + +internal class MTLBuffer : Buffer +{ + public MtlBuffer Buffer; + + public nuint GpuAddress; + + public MTLBuffer(MTLGraphicsContext context, BufferDesc desc) : base(context, desc) + { + Heap = new(context, desc, out Buffer); + + GpuAddress = Buffer.GpuAddress; + } + + public MTLHeap Heap { get; } + + public override MappedMemory Map() + { + return new() { Pointer = Buffer.Contents(), SizeInBytes = Desc.SizeInBytes }; + } + + public override void Unmap() + { + } + + protected override void SetResourceName(string name) + { + Buffer.Label = name; + } + + protected override void Destroy() + { + Buffer.Dispose(); + + Heap.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLBufferView.cs b/sources/Zenith.NET.Metal/MTLBufferView.cs new file mode 100644 index 00000000..c32ee139 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLBufferView.cs @@ -0,0 +1,14 @@ +namespace Zenith.NET.Metal; + +internal class MTLBufferView(MTLGraphicsContext context, BufferViewDesc desc) : BufferView(context, desc) +{ + public nuint GpuAddress = desc.Buffer.Metal().GpuAddress + desc.OffsetInBytes; + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + } +} diff --git a/sources/Zenith.NET.Metal/MTLCapabilities.cs b/sources/Zenith.NET.Metal/MTLCapabilities.cs new file mode 100644 index 00000000..f46a5354 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLCapabilities.cs @@ -0,0 +1,12 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLCapabilities(MTLGraphicsContext context) : Capabilities +{ + public override string DeviceName { get; } = context.Device.Name; + + public override bool RayTracingSupported { get; } = context.Device.SupportsRaytracingFromRender; + + public override bool MeshShadingSupported { get; } = context.Device.SupportsFamily(MTLGPUFamily.Apple7) || context.Device.SupportsFamily(MTLGPUFamily.Mac2); +} diff --git a/sources/Zenith.NET.Metal/MTLCommandBuffer.cs b/sources/Zenith.NET.Metal/MTLCommandBuffer.cs new file mode 100644 index 00000000..8f8e8601 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLCommandBuffer.cs @@ -0,0 +1,397 @@ +using System.Numerics; +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal unsafe class MTLCommandBuffer : CommandBuffer +{ + public MTL4CommandAllocator CommandAllocator; + + public MTL4CommandBuffer CommandBuffer; + + public MTLCommandBuffer(MTLGraphicsContext context, CommandQueue queue) : base(context, queue) + { + CommandAllocator = context.Device.MakeCommandAllocator(); + CommandBuffer = NSAutorelease.Own(context.Device.MakeCommandBuffer); + + CommandEncoder = new(context, CommandBuffer); + } + + public new MTLGraphicsContext Context => (MTLGraphicsContext)base.Context; + + public MTLCommandEncoder CommandEncoder { get; } + + protected override void CopyBufferImpl(Buffer src, uint srcOffsetInBytes, Buffer dest, uint destOffsetInBytes, uint sizeInBytes) + { + MTLBuffer mtlSrc = src.Metal(); + MTLBuffer mtlDest = dest.Metal(); + + CommandEncoder.Compute?.Copy(mtlSrc.Buffer, srcOffsetInBytes, mtlDest.Buffer, destOffsetInBytes, sizeInBytes); + + CommandEncoder.Compute?.BarrierAfterEncoderStages(MTLStages.Blit, MTLStages.Blit | MTLStages.Dispatch, MTL4VisibilityOptions.Device); + } + + protected override void CopyBufferToTextureImpl(Buffer src, uint srcOffsetInBytes, Texture dest, TextureSlice destSlice, TextureOffset destOffset, TextureExtent destExtent) + { + MTLBuffer mtlSrc = src.Metal(); + MTLTexture mtlDest = dest.Metal(); + + (_, _, uint blocksWide, uint blocksHigh) = ZenithHelper.BlockLayout(mtlDest.Desc.Format, destExtent.Width, destExtent.Height); + + uint formatSizeInBytes = ZenithHelper.SizeInBytes(mtlDest.Desc.Format); + uint sliceRowPitchInBytes = ZenithHelper.Align(formatSizeInBytes * blocksWide, GraphicsContext.TextureRowPitchAlignment); + uint sliceDepthPitchInBytes = ZenithHelper.Align(sliceRowPitchInBytes * blocksHigh, GraphicsContext.TextureDepthPitchAlignment); + + CommandEncoder.Compute?.Copy(mtlSrc.Buffer, + srcOffsetInBytes, + sliceRowPitchInBytes, + sliceDepthPitchInBytes, + new(destExtent.Width, destExtent.Height, destExtent.Depth), + mtlDest.Texture, + ZenithHelper.FlattenArrayLayerIndex(mtlDest.Desc, destSlice), + destSlice.MipLevel, + new(destOffset.X, destOffset.Y, destOffset.Z)); + + CommandEncoder.Compute?.BarrierAfterEncoderStages(MTLStages.Blit, MTLStages.Blit | MTLStages.Dispatch, MTL4VisibilityOptions.Device); + } + + protected override void CopyTextureImpl(Texture src, TextureSlice srcSlice, TextureOffset srcOffset, Texture dest, TextureSlice destSlice, TextureOffset destOffset, TextureExtent extent) + { + MTLTexture mtlSrc = src.Metal(); + MTLTexture mtlDest = dest.Metal(); + + CommandEncoder.Compute?.Copy(mtlSrc.Texture, + ZenithHelper.FlattenArrayLayerIndex(mtlSrc.Desc, srcSlice), + srcSlice.MipLevel, + new(srcOffset.X, srcOffset.Y, srcOffset.Z), + new(extent.Width, extent.Height, extent.Depth), + mtlDest.Texture, + ZenithHelper.FlattenArrayLayerIndex(mtlDest.Desc, destSlice), + destSlice.MipLevel, + new(destOffset.X, destOffset.Y, destOffset.Z)); + + CommandEncoder.Compute?.BarrierAfterEncoderStages(MTLStages.Blit, MTLStages.Blit | MTLStages.Dispatch, MTL4VisibilityOptions.Device); + } + + protected override void CopyTextureToBufferImpl(Texture src, TextureSlice srcSlice, TextureOffset srcOffset, TextureExtent srcExtent, Buffer dest, uint destOffsetInBytes) + { + MTLTexture mtlSrc = src.Metal(); + MTLBuffer mtlDest = dest.Metal(); + + (_, _, uint blocksWide, uint blocksHigh) = ZenithHelper.BlockLayout(mtlSrc.Desc.Format, srcExtent.Width, srcExtent.Height); + + uint formatSizeInBytes = ZenithHelper.SizeInBytes(mtlSrc.Desc.Format); + uint sliceRowPitchInBytes = ZenithHelper.Align(formatSizeInBytes * blocksWide, GraphicsContext.TextureRowPitchAlignment); + uint sliceDepthPitchInBytes = ZenithHelper.Align(sliceRowPitchInBytes * blocksHigh, GraphicsContext.TextureDepthPitchAlignment); + + CommandEncoder.Compute?.Copy(mtlSrc.Texture, + ZenithHelper.FlattenArrayLayerIndex(mtlSrc.Desc, srcSlice), + srcSlice.MipLevel, + new(srcOffset.X, srcOffset.Y, srcOffset.Z), + new(srcExtent.Width, srcExtent.Height, srcExtent.Depth), + mtlDest.Buffer, + destOffsetInBytes, + sliceRowPitchInBytes, + sliceDepthPitchInBytes); + + CommandEncoder.Compute?.BarrierAfterEncoderStages(MTLStages.Blit, MTLStages.Blit | MTLStages.Dispatch, MTL4VisibilityOptions.Device); + } + + protected override void ResolveTextureImpl(Texture src, TextureSlice srcSlice, Texture dest, TextureSlice destSlice) + { + MTLTexture mtlSrc = src.Metal(); + MTLTexture mtlDest = dest.Metal(); + + CommandEncoder.Compute?.Copy(mtlSrc.Texture, + ZenithHelper.FlattenArrayLayerIndex(mtlSrc.Desc, srcSlice), + srcSlice.MipLevel, + mtlDest.Texture, + ZenithHelper.FlattenArrayLayerIndex(mtlDest.Desc, destSlice), + destSlice.MipLevel, + 1, + 1); + + CommandEncoder.Compute?.BarrierAfterEncoderStages(MTLStages.Blit, MTLStages.Blit | MTLStages.Dispatch, MTL4VisibilityOptions.Device); + } + + protected override BottomLevelAccelerationStructure BuildAccelerationStructureImpl(BottomLevelAccelerationStructureDesc desc) + { + return new MTLBottomLevelAccelerationStructure(Context, desc, this); + } + + protected override TopLevelAccelerationStructure BuildAccelerationStructureImpl(TopLevelAccelerationStructureDesc desc) + { + return new MTLTopLevelAccelerationStructure(Context, desc, this); + } + + protected override void UpdateAccelerationStructureImpl(TopLevelAccelerationStructure accelerationStructure, TopLevelAccelerationStructureDesc newDesc) + { + accelerationStructure.Metal().Update(this, newDesc); + } + + protected override void BeginRenderPassImpl(FrameBuffer frameBuffer, ClearValue clearValue) + { + MTLFrameBuffer mtlFrameBuffer = frameBuffer.Metal(); + + bool clearColor = clearValue.Flags.HasFlag(ClearFlags.Color); + bool clearDepth = clearValue.Flags.HasFlag(ClearFlags.Depth); + bool clearStencil = clearValue.Flags.HasFlag(ClearFlags.Stencil); + + for (uint i = 0; i < mtlFrameBuffer.ColorAttachmentCount; i++) + { + MTLRenderPassColorAttachmentDescriptor colorAttachment = mtlFrameBuffer.Descriptor.ColorAttachments[i]; + + colorAttachment.LoadAction = MTLLoadAction.Load; + + if (clearColor) + { + colorAttachment.LoadAction = MTLLoadAction.Clear; + + Vector4 color = clearValue.ColorValues[i]; + + colorAttachment.ClearColor = new() + { + Red = color.X, + Green = color.Y, + Blue = color.Z, + Alpha = color.W + }; + } + } + + if (mtlFrameBuffer.HasDepthStencilAttachment) + { + MTLRenderPassDepthAttachmentDescriptor depthAttachment = mtlFrameBuffer.Descriptor.DepthAttachment; + + if (!depthAttachment.Texture.IsNull) + { + depthAttachment.LoadAction = MTLLoadAction.Load; + + if (clearDepth) + { + depthAttachment.LoadAction = MTLLoadAction.Clear; + depthAttachment.ClearDepth = clearValue.Depth; + } + } + + MTLRenderPassStencilAttachmentDescriptor stencilAttachment = mtlFrameBuffer.Descriptor.StencilAttachment; + + if (!stencilAttachment.Texture.IsNull) + { + stencilAttachment.LoadAction = MTLLoadAction.Load; + + if (clearStencil) + { + stencilAttachment.LoadAction = MTLLoadAction.Clear; + stencilAttachment.ClearStencil = clearValue.Stencil; + } + } + } + + CommandEncoder.BeginRenderPass(mtlFrameBuffer.Descriptor); + } + + protected override void EndRenderPassImpl(FrameBuffer frameBuffer) + { + CommandEncoder.EndRenderPass(); + } + + protected override void SetScissorsImpl(Scissor[] scissors) + { + CommandEncoder.SetScissors(scissors); + } + + protected override void SetViewportsImpl(Viewport[] viewports) + { + CommandEncoder.SetViewports(viewports); + } + + protected override void SetPipelineImpl(GraphicsPipeline pipeline) + { + CommandEncoder.SetPipeline(pipeline); + } + + protected override void SetPipelineImpl(ComputePipeline pipeline) + { + CommandEncoder.SetPipeline(pipeline); + } + + protected override void SetPipelineImpl(MeshShadingPipeline pipeline) + { + CommandEncoder.SetPipeline(pipeline); + } + + protected override void SetVertexBufferImpl(GraphicsPipeline pipeline, Buffer buffer, uint offsetInBytes, uint index) + { + CommandEncoder.SetVertexBuffer(buffer, offsetInBytes, index); + } + + protected override void SetIndexBufferImpl(GraphicsPipeline pipeline, Buffer buffer, uint offsetInBytes, IndexFormat format) + { + CommandEncoder.SetIndexBuffer(buffer, offsetInBytes, format); + } + + protected override void SetResourceTableImpl(Pipeline pipeline, ResourceTable resourceTable) + { + CommandEncoder.SetResourceTable(resourceTable); + } + + protected override void DrawImpl(GraphicsPipeline pipeline, uint vertexCount, uint instanceCount, uint firstVertex, uint firstInstance) + { + CommandEncoder.Bind(); + + CommandEncoder.Render?.DrawPrimitives(CommandEncoder.PrimitiveType, firstVertex, vertexCount, instanceCount, firstInstance); + } + + protected override void DrawIndirectImpl(GraphicsPipeline pipeline, Buffer indirectBuffer, uint offsetInBytes, uint drawCount) + { + CommandEncoder.Bind(); + + nuint indirectGpuAddress = indirectBuffer.Metal().GpuAddress + offsetInBytes; + + for (uint i = 0; i < drawCount; i++) + { + CommandEncoder.Render?.DrawPrimitives(CommandEncoder.PrimitiveType, indirectGpuAddress + ((uint)sizeof(IndirectDrawArgs) * i)); + } + } + + protected override void DrawIndexedImpl(GraphicsPipeline pipeline, uint indexCount, uint instanceCount, uint firstIndex, int vertexOffset, uint firstInstance) + { + CommandEncoder.Bind(); + + CommandEncoder.Render?.DrawIndexedPrimitives(CommandEncoder.PrimitiveType, + indexCount, + CommandEncoder.IndexType, + CommandEncoder.IndexBuffer + (CommandEncoder.IndexStrideInBytes * firstIndex), + CommandEncoder.IndexSizeInBytes - (CommandEncoder.IndexStrideInBytes * firstIndex), + instanceCount, + vertexOffset, + firstInstance); + } + + protected override void DrawIndexedIndirectImpl(GraphicsPipeline pipeline, Buffer indirectBuffer, uint offsetInBytes, uint drawCount) + { + CommandEncoder.Bind(); + + nuint indirectGpuAddress = indirectBuffer.Metal().GpuAddress + offsetInBytes; + + for (uint i = 0; i < drawCount; i++) + { + CommandEncoder.Render?.DrawIndexedPrimitives(CommandEncoder.PrimitiveType, + CommandEncoder.IndexType, + CommandEncoder.IndexBuffer + (CommandEncoder.IndexStrideInBytes * i), + CommandEncoder.IndexSizeInBytes - (CommandEncoder.IndexStrideInBytes * i), + indirectGpuAddress + ((uint)sizeof(IndirectDrawIndexedArgs) * i)); + } + } + + protected override void DispatchImpl(ComputePipeline pipeline, uint groupCountX, uint groupCountY, uint groupCountZ) + { + CommandEncoder.Bind(); + + CommandEncoder.Compute?.DispatchThreadgroups(new MTLSize(groupCountX, groupCountY, groupCountZ), CommandEncoder.ThreadGroupSize); + + CommandEncoder.Compute?.BarrierAfterEncoderStages(MTLStages.Dispatch, MTLStages.Blit | MTLStages.Dispatch, MTL4VisibilityOptions.Device); + } + + protected override void DispatchIndirectImpl(ComputePipeline pipeline, Buffer indirectBuffer, uint offsetInBytes) + { + CommandEncoder.Bind(); + + CommandEncoder.Compute?.DispatchThreadgroups(indirectBuffer.Metal().GpuAddress + offsetInBytes, CommandEncoder.ThreadGroupSize); + + CommandEncoder.Compute?.BarrierAfterEncoderStages(MTLStages.Dispatch, MTLStages.Blit | MTLStages.Dispatch, MTL4VisibilityOptions.Device); + } + + protected override void DispatchMeshImpl(MeshShadingPipeline pipeline, uint groupCountX, uint groupCountY, uint groupCountZ) + { + CommandEncoder.Bind(); + + CommandEncoder.Render?.DrawMeshThreadgroups(new MTLSize(groupCountX, groupCountY, groupCountZ), + CommandEncoder.AmplificationThreadGroupSize, + CommandEncoder.MeshThreadGroupSize); + } + + protected override void DispatchMeshIndirectImpl(MeshShadingPipeline pipeline, Buffer indirectBuffer, uint offsetInBytes, uint dispatchCount) + { + CommandEncoder.Bind(); + + nuint indirectGpuAddress = indirectBuffer.Metal().GpuAddress + offsetInBytes; + + for (uint i = 0; i < dispatchCount; i++) + { + CommandEncoder.Render?.DrawMeshThreadgroups(indirectGpuAddress + ((uint)sizeof(IndirectDispatchMeshArgs) * i), + CommandEncoder.AmplificationThreadGroupSize, + CommandEncoder.MeshThreadGroupSize); + } + } + + protected override void BeginQueryImpl(QueryHeap queryHeap, uint index) + { + CommandEncoder.BeginQuery(queryHeap, index); + } + + protected override void EndQueryImpl(QueryHeap queryHeap, uint index) + { + CommandEncoder.EndQuery(queryHeap, index); + } + + protected override void WriteTimestampImpl(QueryHeap queryHeap, uint index) + { + MTLQueryHeap mtlQueryHeap = queryHeap.Metal(); + + CommandBuffer.WriteTimestamp(mtlQueryHeap.CounterHeap, index); + CommandBuffer.ResolveCounterHeap(mtlQueryHeap.CounterHeap, new(index, 1), new(mtlQueryHeap.Buffer.GpuAddress + (sizeof(ulong) * index), sizeof(ulong)), MtlFence.Null, MtlFence.Null); + } + + protected override void BeginDebugEventImpl(string label) + { + CommandEncoder.BeginDebugEvent(label); + } + + protected override void EndDebugEventImpl() + { + CommandEncoder.EndDebugEvent(); + } + + protected override void InsertDebugMarkerImpl(string label) + { + CommandEncoder.InsertDebugMarker(label); + } + + protected override void BeginImpl() + { + CommandBuffer.BeginCommandBuffer(CommandAllocator); + + CommandBuffer.UseResidencySet(Context.ResidencySet); + + CommandEncoder.Begin(); + } + + protected override void EndImpl() + { + CommandEncoder.End(); + + CommandBuffer.EndCommandBuffer(); + } + + protected override void ResetImpl() + { + CommandAllocator.Reset(); + } + + protected override void SetResourceName(string name) + { + CommandBuffer.Label = name; + } + + protected override void Destroy() + { + base.Destroy(); + + CommandEncoder.Dispose(); + + CommandBuffer.Dispose(); + CommandAllocator.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLCommandEncoder.cs b/sources/Zenith.NET.Metal/MTLCommandEncoder.cs new file mode 100644 index 00000000..d3e86628 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLCommandEncoder.cs @@ -0,0 +1,363 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLCommandEncoder : GraphicsResource +{ + private const MTLStages RenderStages = MTLStages.Vertex | MTLStages.Fragment | MTLStages.Object | MTLStages.Mesh; + private const MTLStages ComputeStages = MTLStages.Dispatch | MTLStages.Blit | MTLStages.AccelerationStructure; + + private readonly Dictionary todoBeginQueries = []; + private readonly Dictionary todoEndQueries = []; + private readonly Dictionary vertexBuffers = []; + + public MtlFence Fence; + + public MtlBuffer Buffer; + + public MTL4ArgumentTable ArgumentTable; + + private Scissor[]? todoScissors; + private Viewport[]? todoViewports; + private Pipeline? currentPipeline; + private ResourceTable? currentResourceTable; + private bool needsRebind; + + public MTLCommandEncoder(MTLGraphicsContext context, MTL4CommandBuffer commandBuffer) : base(context) + { + CommandBuffer = commandBuffer; + + Fence = context.Device.MakeFence(); + Buffer = context.Device.MakeBuffer(sizeof(ulong) * 128, MTLResourceOptions.StorageModePrivate); + + MTL4ArgumentTableDescriptor descriptor = new() + { + MaxBufferBindCount = 16, + MaxTextureBindCount = 16, + MaxSamplerStateBindCount = 16, + SupportAttributeStrides = true + }; + + ArgumentTable = context.Device.MakeArgumentTable(descriptor, out NSError error); + error.Success(); + } + + public MTL4CommandBuffer CommandBuffer { get; } + + public MTL4RenderCommandEncoder? Render { get; private set; } + + public MTL4ComputeCommandEncoder? Compute { get; private set; } + + public nuint IndexBuffer { get; private set; } + + public uint IndexSizeInBytes { get; private set; } + + public uint IndexStrideInBytes { get; private set; } + + public MTLIndexType IndexType { get; private set; } + + public MTLPrimitiveType PrimitiveType { get; private set; } + + public MTLSize ThreadGroupSize { get; private set; } + + public MTLSize AmplificationThreadGroupSize { get; private set; } + + public MTLSize MeshThreadGroupSize { get; private set; } + + public void Begin() + { + Compute = NSAutorelease.Own(CommandBuffer.MakeComputeCommandEncoder); + } + + public void End() + { + EndRender(); + EndCompute(); + + todoScissors = null; + todoViewports = null; + currentPipeline = null; + currentResourceTable = null; + needsRebind = false; + + todoBeginQueries.Clear(); + todoEndQueries.Clear(); + vertexBuffers.Clear(); + } + + public void BeginRenderPass(MTL4RenderPassDescriptor descriptor) + { + EndCompute(); + + descriptor.VisibilityResultBuffer = Buffer; + + Render = NSAutorelease.Own(CommandBuffer.MakeRenderCommandEncoder, descriptor); + Render.WaitForFence(Fence, RenderStages); + + foreach (KeyValuePair beginQuery in todoBeginQueries) + { + BeginQuery(beginQuery.Value, beginQuery.Key); + } + todoBeginQueries.Clear(); + + if (todoScissors is not null) + { + SetScissors(todoScissors); + + todoScissors = null; + } + + if (todoViewports is not null) + { + SetViewports(todoViewports); + + todoViewports = null; + } + } + + public void EndRenderPass() + { + EndRender(); + + Compute = NSAutorelease.Own(CommandBuffer.MakeComputeCommandEncoder); + Compute.WaitForFence(Fence, ComputeStages); + + foreach (KeyValuePair endQuery in todoEndQueries) + { + EndQuery(endQuery.Value, endQuery.Key); + } + todoEndQueries.Clear(); + } + + public void SetScissors(Scissor[] scissors) + { + if (Render is null) + { + todoScissors = [.. scissors]; + } + else + { + MTLScissorRect[] mtlScissors = [.. scissors.Select(static item => new MTLScissorRect((uint)item.X, (uint)item.Y, item.Width, item.Height))]; + + Render.SetScissorRects(mtlScissors); + } + } + + public void SetViewports(Viewport[] viewports) + { + if (Render is null) + { + todoViewports = [.. viewports]; + } + else + { + MTLViewport[] mtlViewports = [.. viewports.Select(static item => new MTLViewport(item.X, item.Y, item.Width, item.Height, item.MinDepth, item.MaxDepth))]; + + Render.SetViewports(mtlViewports); + } + } + + public void SetPipeline(GraphicsPipeline pipeline) + { + currentPipeline = pipeline; + + needsRebind = true; + + PrimitiveType = MTLFormats.Metal(pipeline.Desc.PrimitiveTopology).Type; + } + + public void SetPipeline(ComputePipeline pipeline) + { + currentPipeline = pipeline; + + needsRebind = true; + + ThreadGroupSize = new(pipeline.Desc.ThreadGroupSizeX, pipeline.Desc.ThreadGroupSizeY, pipeline.Desc.ThreadGroupSizeZ); + } + + public void SetPipeline(MeshShadingPipeline pipeline) + { + currentPipeline = pipeline; + + needsRebind = true; + + AmplificationThreadGroupSize = new(pipeline.Desc.AmplificationThreadGroupSizeX, pipeline.Desc.AmplificationThreadGroupSizeY, pipeline.Desc.AmplificationThreadGroupSizeZ); + MeshThreadGroupSize = new(pipeline.Desc.MeshThreadGroupSizeX, pipeline.Desc.MeshThreadGroupSizeY, pipeline.Desc.MeshThreadGroupSizeZ); + } + + public void SetVertexBuffer(Buffer buffer, uint offsetInBytes, uint index) + { + vertexBuffers[index] = buffer.Metal().GpuAddress + offsetInBytes; + + needsRebind = true; + } + + public void SetIndexBuffer(Buffer buffer, uint offsetInBytes, IndexFormat format) + { + IndexBuffer = buffer.Metal().GpuAddress + offsetInBytes; + IndexSizeInBytes = buffer.Desc.SizeInBytes - offsetInBytes; + IndexStrideInBytes = (uint)(format is IndexFormat.UInt16 ? sizeof(ushort) : sizeof(uint)); + IndexType = MTLFormats.Metal(format); + } + + public void SetResourceTable(ResourceTable resourceTable) + { + currentResourceTable = resourceTable; + + needsRebind = true; + } + + public void Bind() + { + if (!needsRebind) + { + return; + } + + switch (currentPipeline) + { + case MTLGraphicsPipeline graphicsPipeline: + { + BindRenderPipeline(graphicsPipeline.Desc.RenderStates, graphicsPipeline.RenderPipelineState, graphicsPipeline.DepthStencilState); + + if (currentResourceTable is MTLResourceTable resourceTable) + { + Render?.SetArgumentTable(resourceTable.ArgumentTable, MTLRenderStages.Fragment); + + resourceTable.Bind(ArgumentTable); + } + + foreach (KeyValuePair vertexBuffer in vertexBuffers) + { + ArgumentTable.SetAddress(vertexBuffer.Value, graphicsPipeline.VertexBufferStartIndex + vertexBuffer.Key); + } + + Render?.SetArgumentTable(ArgumentTable, MTLRenderStages.Vertex); + } + break; + + case MTLComputePipeline computePipeline: + { + Compute?.SetComputePipelineState(computePipeline.ComputePipelineState); + + if (currentResourceTable is MTLResourceTable resourceTable) + { + Compute?.SetArgumentTable(resourceTable.ArgumentTable); + } + } + break; + + case MTLMeshShadingPipeline meshShadingPipeline: + { + BindRenderPipeline(meshShadingPipeline.Desc.RenderStates, meshShadingPipeline.RenderPipelineState, meshShadingPipeline.DepthStencilState); + + if (currentResourceTable is MTLResourceTable resourceTable) + { + Render?.SetArgumentTable(resourceTable.ArgumentTable, MTLRenderStages.Object | MTLRenderStages.Mesh); + } + } + break; + } + + needsRebind = false; + } + + public void BeginQuery(QueryHeap queryHeap, uint index) + { + if (Render is null) + { + todoBeginQueries[index] = queryHeap; + } + else + { + Render.SetVisibilityResultMode(MTLFormats.Metal(queryHeap.Desc.Type), sizeof(ulong) * index); + } + } + + public void EndQuery(QueryHeap queryHeap, uint index) + { + Render?.SetVisibilityResultMode(MTLVisibilityResultMode.Disabled, sizeof(ulong) * index); + + if (Compute is null) + { + todoEndQueries[index] = queryHeap; + } + else + { + Compute.Copy(Buffer, sizeof(ulong) * index, queryHeap.Metal().Buffer.Buffer, sizeof(ulong) * index, sizeof(ulong)); + } + } + + public void BeginDebugEvent(string label) + { + Render?.PushDebugGroup(label); + Compute?.PushDebugGroup(label); + } + + public void EndDebugEvent() + { + Render?.PopDebugGroup(); + Compute?.PopDebugGroup(); + } + + public void InsertDebugMarker(string label) + { + Render?.InsertDebugSignpost(label); + Compute?.InsertDebugSignpost(label); + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + Render?.Dispose(); + Render = null; + + Compute?.Dispose(); + Compute = null; + + ArgumentTable.Dispose(); + Buffer.Dispose(); + Fence.Dispose(); + } + + private void EndRender() + { + Render?.UpdateFence(Fence, RenderStages); + Render?.EndEncoding(); + Render?.Dispose(); + Render = null; + } + + private void EndCompute() + { + Compute?.UpdateFence(Fence, ComputeStages); + Compute?.EndEncoding(); + Compute?.Dispose(); + Compute = null; + } + + private void BindRenderPipeline(RenderStates renderStates, MTLRenderPipelineState renderPipelineState, MTLDepthStencilState depthStencilState) + { + Render?.SetRenderPipelineState(renderPipelineState); + + Render?.SetCullMode(MTLFormats.Metal(renderStates.RasterizerState.CullMode)); + + Render?.SetDepthClipMode(renderStates.RasterizerState.DepthClipEnable ? MTLDepthClipMode.Clip : MTLDepthClipMode.Clamp); + Render?.SetDepthBias(renderStates.RasterizerState.DepthBias, renderStates.RasterizerState.SlopeScaledDepthBias, renderStates.RasterizerState.DepthBiasClamp); + + Render?.SetTriangleFillMode(MTLFormats.Metal(renderStates.RasterizerState.FillMode)); + + if (renderStates.BlendFactor.HasValue) + { + Render?.SetBlendColor(renderStates.BlendFactor.Value.X, renderStates.BlendFactor.Value.Y, renderStates.BlendFactor.Value.Z, renderStates.BlendFactor.Value.W); + } + + Render?.SetDepthStencilState(depthStencilState); + Render?.SetStencilReferenceValue(renderStates.StencilReference); + + Render?.SetFrontFacing(MTLFormats.Metal(renderStates.RasterizerState.FrontFace)); + } +} diff --git a/sources/Zenith.NET.Metal/MTLCommandQueue.cs b/sources/Zenith.NET.Metal/MTLCommandQueue.cs new file mode 100644 index 00000000..b7b7f853 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLCommandQueue.cs @@ -0,0 +1,34 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLCommandQueue(MTLGraphicsContext context, CommandQueueType type, MTL4CommandQueue queue) : CommandQueue(context, type) +{ + private readonly MTLFence fence = new(context); + + protected override CommandBuffer CreateCommandBuffer() + { + return new MTLCommandBuffer(context, this); + } + + protected override void WaitIdleImpl() + { + fence.Wait(queue); + } + + protected override void SubmitImpl(CommandBuffer commandBuffer) + { + queue.Commit([commandBuffer.Metal().CommandBuffer]); + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + base.Destroy(); + + fence.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLComputePipeline.cs b/sources/Zenith.NET.Metal/MTLComputePipeline.cs new file mode 100644 index 00000000..516d2627 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLComputePipeline.cs @@ -0,0 +1,29 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLComputePipeline : ComputePipeline +{ + public MTLComputePipelineState ComputePipelineState; + + public MTLComputePipeline(MTLGraphicsContext context, ComputePipelineDesc desc) : base(context, desc) + { + MTL4ComputePipelineDescriptor descriptor = new() + { + ComputeFunctionDescriptor = desc.Compute.Metal().Descriptor, + RequiredThreadsPerThreadgroup = new(desc.ThreadGroupSizeX, desc.ThreadGroupSizeY, desc.ThreadGroupSizeZ) + }; + + ComputePipelineState = context.Compiler.MakeComputePipelineState(descriptor, MTL4CompilerTaskOptions.Null, out NSError error); + error.Success(); + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + ComputePipelineState.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLFence.cs b/sources/Zenith.NET.Metal/MTLFence.cs new file mode 100644 index 00000000..a05d4250 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLFence.cs @@ -0,0 +1,31 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLFence(MTLGraphicsContext context) : GraphicsResource(context) +{ + private readonly MTLSharedEvent @event = context.Device.MakeSharedEvent(); + + private ulong currentFenceValue; + + public void Wait(MTL4CommandQueue queue) + { + currentFenceValue++; + + queue.SignalEvent(@event, currentFenceValue); + + if (@event.SignaledValue < currentFenceValue) + { + @event.Wait(currentFenceValue, ulong.MaxValue); + } + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + @event.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLFormats.cs b/sources/Zenith.NET.Metal/MTLFormats.cs new file mode 100644 index 00000000..aff8fa59 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLFormats.cs @@ -0,0 +1,508 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal static class MTLFormats +{ + public static MTLResourceOptions Metal(BufferUsageFlags bufferUsageFlags) + { + MTLResourceOptions result = MTLResourceOptions.HazardTrackingModeUntracked; + + if (bufferUsageFlags.HasFlag(BufferUsageFlags.MapRead) || bufferUsageFlags.HasFlag(BufferUsageFlags.MapWrite)) + { + result |= MTLResourceOptions.StorageModeShared; + + if (bufferUsageFlags.HasFlag(BufferUsageFlags.MapWrite)) + { + result |= MTLResourceOptions.CPUCacheModeWriteCombined; + } + } + else + { + result |= MTLResourceOptions.StorageModePrivate; + } + + return result; + } + + public static MTLTextureType Metal(TextureType textureType) + { + return textureType switch + { + TextureType.Texture1D => MTLTextureType.MTL1D, + TextureType.Texture1DArray => MTLTextureType.MTL1DArray, + TextureType.Texture2D => MTLTextureType.MTL2D, + TextureType.Texture2DArray => MTLTextureType.MTL2DArray, + TextureType.Texture3D => MTLTextureType.MTL3D, + TextureType.TextureCube => MTLTextureType.MTLCube, + TextureType.TextureCubeArray => MTLTextureType.MTLCubeArray, + _ => MTLTextureType.MTL1D + }; + } + + public static (MTLPixelFormat PixelFormat, MTLAttributeFormat AttributeFormat) Metal(PixelFormat pixelFormat) + { + return pixelFormat switch + { + PixelFormat.R8UNorm => (MTLPixelFormat.R8Unorm, MTLAttributeFormat.UCharNormalized), + PixelFormat.R8SNorm => (MTLPixelFormat.R8Snorm, MTLAttributeFormat.CharNormalized), + PixelFormat.R8UInt => (MTLPixelFormat.R8Uint, MTLAttributeFormat.UChar), + PixelFormat.R8SInt => (MTLPixelFormat.R8Sint, MTLAttributeFormat.Char), + + PixelFormat.R16UNorm => (MTLPixelFormat.R16Unorm, MTLAttributeFormat.UShortNormalized), + PixelFormat.R16SNorm => (MTLPixelFormat.R16Snorm, MTLAttributeFormat.ShortNormalized), + PixelFormat.R16UInt => (MTLPixelFormat.R16Uint, MTLAttributeFormat.UShort), + PixelFormat.R16SInt => (MTLPixelFormat.R16Sint, MTLAttributeFormat.Short), + PixelFormat.R16Float => (MTLPixelFormat.R16Float, MTLAttributeFormat.Half), + + PixelFormat.R32UInt => (MTLPixelFormat.R32Uint, MTLAttributeFormat.UInt), + PixelFormat.R32SInt => (MTLPixelFormat.R32Sint, MTLAttributeFormat.Int), + PixelFormat.R32Float => (MTLPixelFormat.R32Float, MTLAttributeFormat.Float), + + PixelFormat.R8G8UNorm => (MTLPixelFormat.RG8Unorm, MTLAttributeFormat.UChar2Normalized), + PixelFormat.R8G8SNorm => (MTLPixelFormat.RG8Snorm, MTLAttributeFormat.Char2Normalized), + PixelFormat.R8G8UInt => (MTLPixelFormat.RG8Uint, MTLAttributeFormat.UChar2), + PixelFormat.R8G8SInt => (MTLPixelFormat.RG8Sint, MTLAttributeFormat.Char2), + + PixelFormat.R16G16UNorm => (MTLPixelFormat.RG16Unorm, MTLAttributeFormat.UShort2Normalized), + PixelFormat.R16G16SNorm => (MTLPixelFormat.RG16Snorm, MTLAttributeFormat.Short2Normalized), + PixelFormat.R16G16UInt => (MTLPixelFormat.RG16Uint, MTLAttributeFormat.UShort2), + PixelFormat.R16G16SInt => (MTLPixelFormat.RG16Sint, MTLAttributeFormat.Short2), + PixelFormat.R16G16Float => (MTLPixelFormat.RG16Float, MTLAttributeFormat.Half2), + + PixelFormat.R32G32UInt => (MTLPixelFormat.RG32Uint, MTLAttributeFormat.UInt2), + PixelFormat.R32G32SInt => (MTLPixelFormat.RG32Sint, MTLAttributeFormat.Int2), + PixelFormat.R32G32Float => (MTLPixelFormat.RG32Float, MTLAttributeFormat.Float2), + + PixelFormat.R32G32B32UInt => (MTLPixelFormat.Invalid, MTLAttributeFormat.UInt3), + PixelFormat.R32G32B32SInt => (MTLPixelFormat.Invalid, MTLAttributeFormat.Int3), + PixelFormat.R32G32B32Float => (MTLPixelFormat.Invalid, MTLAttributeFormat.Float3), + + PixelFormat.R8G8B8A8UNorm => (MTLPixelFormat.RGBA8Unorm, MTLAttributeFormat.UChar4Normalized), + PixelFormat.R8G8B8A8SNorm => (MTLPixelFormat.RGBA8Snorm, MTLAttributeFormat.Char4Normalized), + PixelFormat.R8G8B8A8UInt => (MTLPixelFormat.RGBA8Uint, MTLAttributeFormat.UChar4), + PixelFormat.R8G8B8A8SInt => (MTLPixelFormat.RGBA8Sint, MTLAttributeFormat.Char4), + PixelFormat.R8G8B8A8SRgb => (MTLPixelFormat.RGBA8Unorm_sRGB, MTLAttributeFormat.UChar4Normalized), + + PixelFormat.R16G16B16A16UNorm => (MTLPixelFormat.RGBA16Unorm, MTLAttributeFormat.UShort4Normalized), + PixelFormat.R16G16B16A16SNorm => (MTLPixelFormat.RGBA16Snorm, MTLAttributeFormat.Short4Normalized), + PixelFormat.R16G16B16A16UInt => (MTLPixelFormat.RGBA16Uint, MTLAttributeFormat.UShort4), + PixelFormat.R16G16B16A16SInt => (MTLPixelFormat.RGBA16Sint, MTLAttributeFormat.Short4), + PixelFormat.R16G16B16A16Float => (MTLPixelFormat.RGBA16Float, MTLAttributeFormat.Half4), + + PixelFormat.R32G32B32A32UInt => (MTLPixelFormat.RGBA32Uint, MTLAttributeFormat.UInt4), + PixelFormat.R32G32B32A32SInt => (MTLPixelFormat.RGBA32Sint, MTLAttributeFormat.Int4), + PixelFormat.R32G32B32A32Float => (MTLPixelFormat.RGBA32Float, MTLAttributeFormat.Float4), + + PixelFormat.B8G8R8A8UNorm => (MTLPixelFormat.BGRA8Unorm, MTLAttributeFormat.UChar4Normalized_BGRA), + PixelFormat.B8G8R8A8SRgb => (MTLPixelFormat.BGRA8Unorm_sRGB, MTLAttributeFormat.UChar4Normalized_BGRA), + + PixelFormat.D16UNorm => (MTLPixelFormat.Depth16Unorm, MTLAttributeFormat.Invalid), + PixelFormat.D24UNormS8UInt => (MTLPixelFormat.Depth24Unorm_Stencil8, MTLAttributeFormat.Invalid), + PixelFormat.D32Float => (MTLPixelFormat.Depth32Float, MTLAttributeFormat.Invalid), + PixelFormat.D32FloatS8UInt => (MTLPixelFormat.Depth32Float_Stencil8, MTLAttributeFormat.Invalid), + + PixelFormat.BC4UNorm => (MTLPixelFormat.BC4_RUnorm, MTLAttributeFormat.Invalid), + PixelFormat.BC4SNorm => (MTLPixelFormat.BC4_RSnorm, MTLAttributeFormat.Invalid), + + PixelFormat.BC5UNorm => (MTLPixelFormat.BC5_RGUnorm, MTLAttributeFormat.Invalid), + PixelFormat.BC5SNorm => (MTLPixelFormat.BC5_RGSnorm, MTLAttributeFormat.Invalid), + + PixelFormat.BC6HUFloat => (MTLPixelFormat.BC6H_RGBUfloat, MTLAttributeFormat.Invalid), + PixelFormat.BC6HSFloat => (MTLPixelFormat.BC6H_RGBFloat, MTLAttributeFormat.Invalid), + + PixelFormat.BC7UNorm => (MTLPixelFormat.BC7_RGBAUnorm, MTLAttributeFormat.Invalid), + PixelFormat.BC7SRgb => (MTLPixelFormat.BC7_RGBAUnorm_sRGB, MTLAttributeFormat.Invalid), + + PixelFormat.ETC2UNorm => (MTLPixelFormat.ETC2_RGB8, MTLAttributeFormat.Invalid), + PixelFormat.ETC2SRgb => (MTLPixelFormat.ETC2_RGB8_sRGB, MTLAttributeFormat.Invalid), + + PixelFormat.ETC2A1UNorm => (MTLPixelFormat.ETC2_RGB8A1, MTLAttributeFormat.Invalid), + PixelFormat.ETC2A1SRgb => (MTLPixelFormat.ETC2_RGB8A1_sRGB, MTLAttributeFormat.Invalid), + + PixelFormat.ETC2A8UNorm => (MTLPixelFormat.EAC_RGBA8, MTLAttributeFormat.Invalid), + PixelFormat.ETC2A8SRgb => (MTLPixelFormat.EAC_RGBA8_sRGB, MTLAttributeFormat.Invalid), + + PixelFormat.ASTC4x4UNorm => (MTLPixelFormat.ASTC_4x4_LDR, MTLAttributeFormat.Invalid), + PixelFormat.ASTC4x4SRgb => (MTLPixelFormat.ASTC_4x4_sRGB, MTLAttributeFormat.Invalid), + PixelFormat.ASTC4x4Float => (MTLPixelFormat.ASTC_4x4_HDR, MTLAttributeFormat.Invalid), + + PixelFormat.ASTC5x5UNorm => (MTLPixelFormat.ASTC_5x5_LDR, MTLAttributeFormat.Invalid), + PixelFormat.ASTC5x5SRgb => (MTLPixelFormat.ASTC_5x5_sRGB, MTLAttributeFormat.Invalid), + PixelFormat.ASTC5x5Float => (MTLPixelFormat.ASTC_5x5_HDR, MTLAttributeFormat.Invalid), + + PixelFormat.ASTC6x6UNorm => (MTLPixelFormat.ASTC_6x6_LDR, MTLAttributeFormat.Invalid), + PixelFormat.ASTC6x6SRgb => (MTLPixelFormat.ASTC_6x6_sRGB, MTLAttributeFormat.Invalid), + PixelFormat.ASTC6x6Float => (MTLPixelFormat.ASTC_6x6_HDR, MTLAttributeFormat.Invalid), + + PixelFormat.ASTC8x8UNorm => (MTLPixelFormat.ASTC_8x8_LDR, MTLAttributeFormat.Invalid), + PixelFormat.ASTC8x8SRgb => (MTLPixelFormat.ASTC_8x8_sRGB, MTLAttributeFormat.Invalid), + PixelFormat.ASTC8x8Float => (MTLPixelFormat.ASTC_8x8_HDR, MTLAttributeFormat.Invalid), + + PixelFormat.ASTC10x10UNorm => (MTLPixelFormat.ASTC_10x10_LDR, MTLAttributeFormat.Invalid), + PixelFormat.ASTC10x10SRgb => (MTLPixelFormat.ASTC_10x10_sRGB, MTLAttributeFormat.Invalid), + PixelFormat.ASTC10x10Float => (MTLPixelFormat.ASTC_10x10_HDR, MTLAttributeFormat.Invalid), + + PixelFormat.ASTC12x12UNorm => (MTLPixelFormat.ASTC_12x12_LDR, MTLAttributeFormat.Invalid), + PixelFormat.ASTC12x12SRgb => (MTLPixelFormat.ASTC_12x12_sRGB, MTLAttributeFormat.Invalid), + PixelFormat.ASTC12x12Float => (MTLPixelFormat.ASTC_12x12_HDR, MTLAttributeFormat.Invalid), + + _ => (MTLPixelFormat.Invalid, MTLAttributeFormat.Invalid) + }; + } + + public static uint Metal(SampleCount sampleCount) + { + return sampleCount switch + { + SampleCount.Count1 => 1, + SampleCount.Count2 => 2, + SampleCount.Count4 => 4, + SampleCount.Count8 => 8, + SampleCount.Count16 => 16, + SampleCount.Count32 => 32, + _ => 1 + }; + } + + public static MTLTextureUsage Metal(TextureUsageFlags textureUsageFlags) + { + MTLTextureUsage result = MTLTextureUsage.Unknown; + + if (textureUsageFlags.HasFlag(TextureUsageFlags.RenderTarget) || textureUsageFlags.HasFlag(TextureUsageFlags.DepthStencil)) + { + result |= MTLTextureUsage.RenderTarget; + } + + if (textureUsageFlags.HasFlag(TextureUsageFlags.ShaderResource)) + { + result |= MTLTextureUsage.ShaderRead; + } + + if (textureUsageFlags.HasFlag(TextureUsageFlags.UnorderedAccess)) + { + result |= MTLTextureUsage.ShaderWrite; + } + + return result; + } + + public static (MTLSamplerMinMagFilter MinFilter, MTLSamplerMinMagFilter MagFilter, MTLSamplerMipFilter MipFilter) Metal(Filter filter) + { + return filter switch + { + Filter.MinPointMagPointMipPoint => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Nearest), + Filter.MinPointMagPointMipLinear => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Linear), + Filter.MinPointMagLinearMipPoint => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Nearest), + Filter.MinPointMagLinearMipLinear => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Linear), + Filter.MinLinearMagPointMipPoint => (MTLSamplerMinMagFilter.Linear, MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Nearest), + Filter.MinLinearMagPointMipLinear => (MTLSamplerMinMagFilter.Linear, MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Linear), + Filter.MinLinearMagLinearMipPoint => (MTLSamplerMinMagFilter.Linear, MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Nearest), + Filter.MinLinearMagLinearMipLinear => (MTLSamplerMinMagFilter.Linear, MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Linear), + Filter.Anisotropic => (MTLSamplerMinMagFilter.Linear, MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Linear), + _ => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.NotMipmapped) + }; + } + + public static MTLSamplerAddressMode Metal(AddressMode addressMode) + { + return addressMode switch + { + AddressMode.Wrap => MTLSamplerAddressMode.Repeat, + AddressMode.Mirror => MTLSamplerAddressMode.MirrorRepeat, + AddressMode.Clamp => MTLSamplerAddressMode.ClampToEdge, + AddressMode.Border => MTLSamplerAddressMode.ClampToBorderColor, + _ => MTLSamplerAddressMode.ClampToEdge + }; + } + + public static MTLCompareFunction Metal(ComparisonFunc comparisonFunc) + { + return comparisonFunc switch + { + ComparisonFunc.Never => MTLCompareFunction.Never, + ComparisonFunc.Less => MTLCompareFunction.Less, + ComparisonFunc.Equal => MTLCompareFunction.Equal, + ComparisonFunc.LessEqual => MTLCompareFunction.LessEqual, + ComparisonFunc.Greater => MTLCompareFunction.Greater, + ComparisonFunc.NotEqual => MTLCompareFunction.NotEqual, + ComparisonFunc.GreaterEqual => MTLCompareFunction.GreaterEqual, + ComparisonFunc.Always => MTLCompareFunction.Always, + _ => MTLCompareFunction.Never + }; + } + + public static MTLSamplerBorderColor Metal(BorderColor borderColor) + { + return borderColor switch + { + BorderColor.TransparentBlack => MTLSamplerBorderColor.TransparentBlack, + BorderColor.OpaqueBlack => MTLSamplerBorderColor.OpaqueBlack, + BorderColor.OpaqueWhite => MTLSamplerBorderColor.OpaqueWhite, + _ => MTLSamplerBorderColor.TransparentBlack + }; + } + + public static (MTLPrimitiveTopologyClass TopologyClass, MTLPrimitiveType Type) Metal(PrimitiveTopology primitiveTopology) + { + return + ( + primitiveTopology switch + { + PrimitiveTopology.PointList => MTLPrimitiveTopologyClass.Point, + + PrimitiveTopology.LineList or + PrimitiveTopology.LineStrip => MTLPrimitiveTopologyClass.Line, + + PrimitiveTopology.TriangleList or + PrimitiveTopology.TriangleStrip => MTLPrimitiveTopologyClass.Triangle, + + _ => MTLPrimitiveTopologyClass.Unspecified + }, + primitiveTopology switch + { + PrimitiveTopology.PointList => MTLPrimitiveType.Point, + PrimitiveTopology.LineList => MTLPrimitiveType.Line, + PrimitiveTopology.LineStrip => MTLPrimitiveType.LineStrip, + PrimitiveTopology.TriangleList => MTLPrimitiveType.Triangle, + PrimitiveTopology.TriangleStrip => MTLPrimitiveType.TriangleStrip, + _ => MTLPrimitiveType.Point + } + ); + } + + public static MTLStencilOperation Metal(StencilOp stencilOp) + { + return stencilOp switch + { + StencilOp.Keep => MTLStencilOperation.Keep, + StencilOp.Zero => MTLStencilOperation.Zero, + StencilOp.Replace => MTLStencilOperation.Replace, + StencilOp.IncrementAndClamp => MTLStencilOperation.IncrementClamp, + StencilOp.DecrementAndClamp => MTLStencilOperation.DecrementClamp, + StencilOp.Invert => MTLStencilOperation.Invert, + StencilOp.IncrementAndWrap => MTLStencilOperation.IncrementWrap, + StencilOp.DecrementAndWrap => MTLStencilOperation.DecrementWrap, + _ => MTLStencilOperation.Keep + }; + } + + public static MTLBlendFactor Metal(Blend blend) + { + return blend switch + { + Blend.Zero => MTLBlendFactor.Zero, + Blend.One => MTLBlendFactor.One, + Blend.SrcAlpha => MTLBlendFactor.SourceAlpha, + Blend.InverseSrcAlpha => MTLBlendFactor.OneMinusSourceAlpha, + Blend.DestAlpha => MTLBlendFactor.DestinationAlpha, + Blend.InverseDestAlpha => MTLBlendFactor.OneMinusDestinationAlpha, + Blend.SrcColor => MTLBlendFactor.SourceColor, + Blend.InverseSrcColor => MTLBlendFactor.OneMinusSourceColor, + Blend.DestColor => MTLBlendFactor.DestinationColor, + Blend.InverseDestColor => MTLBlendFactor.OneMinusDestinationColor, + Blend.BlendFactor => MTLBlendFactor.BlendColor, + Blend.InverseBlendFactor => MTLBlendFactor.OneMinusBlendColor, + _ => MTLBlendFactor.Zero + }; + } + + public static MTLBlendOperation Metal(BlendOp blendOp) + { + return blendOp switch + { + BlendOp.Add => MTLBlendOperation.Add, + BlendOp.Subtract => MTLBlendOperation.Subtract, + BlendOp.ReverseSubtract => MTLBlendOperation.ReverseSubtract, + BlendOp.Min => MTLBlendOperation.Min, + BlendOp.Max => MTLBlendOperation.Max, + _ => MTLBlendOperation.Add + }; + } + + public static MTLColorWriteMask Metal(ColorComponentFlags colorComponentFlags) + { + MTLColorWriteMask result = MTLColorWriteMask.None; + + if (colorComponentFlags.HasFlag(ColorComponentFlags.Red)) + { + result |= MTLColorWriteMask.Red; + } + + if (colorComponentFlags.HasFlag(ColorComponentFlags.Green)) + { + result |= MTLColorWriteMask.Green; + } + + if (colorComponentFlags.HasFlag(ColorComponentFlags.Blue)) + { + result |= MTLColorWriteMask.Blue; + } + + if (colorComponentFlags.HasFlag(ColorComponentFlags.Alpha)) + { + result |= MTLColorWriteMask.Alpha; + } + + return result; + } + + public static MTLVertexFormat Metal(ElementFormat elementFormat) + { + return elementFormat switch + { + ElementFormat.UByte1 => MTLVertexFormat.UChar, + ElementFormat.UByte2 => MTLVertexFormat.UChar2, + ElementFormat.UByte4 => MTLVertexFormat.UChar4, + ElementFormat.Byte1 => MTLVertexFormat.Char, + ElementFormat.Byte2 => MTLVertexFormat.Char2, + ElementFormat.Byte4 => MTLVertexFormat.Char4, + + ElementFormat.UByte1Normalized => MTLVertexFormat.UCharNormalized, + ElementFormat.UByte2Normalized => MTLVertexFormat.UChar2Normalized, + ElementFormat.UByte4Normalized => MTLVertexFormat.UChar4Normalized, + ElementFormat.Byte1Normalized => MTLVertexFormat.CharNormalized, + ElementFormat.Byte2Normalized => MTLVertexFormat.Char2Normalized, + ElementFormat.Byte4Normalized => MTLVertexFormat.Char4Normalized, + + ElementFormat.UShort1 => MTLVertexFormat.UShort, + ElementFormat.UShort2 => MTLVertexFormat.UShort2, + ElementFormat.UShort4 => MTLVertexFormat.UShort4, + ElementFormat.Short1 => MTLVertexFormat.Short, + ElementFormat.Short2 => MTLVertexFormat.Short2, + ElementFormat.Short4 => MTLVertexFormat.Short4, + + ElementFormat.UShort1Normalized => MTLVertexFormat.UShortNormalized, + ElementFormat.UShort2Normalized => MTLVertexFormat.UShort2Normalized, + ElementFormat.UShort4Normalized => MTLVertexFormat.UShort4Normalized, + ElementFormat.Short1Normalized => MTLVertexFormat.ShortNormalized, + ElementFormat.Short2Normalized => MTLVertexFormat.Short2Normalized, + ElementFormat.Short4Normalized => MTLVertexFormat.Short4Normalized, + + ElementFormat.Half1 => MTLVertexFormat.Half, + ElementFormat.Half2 => MTLVertexFormat.Half2, + ElementFormat.Half4 => MTLVertexFormat.Half4, + + ElementFormat.Float1 => MTLVertexFormat.Float, + ElementFormat.Float2 => MTLVertexFormat.Float2, + ElementFormat.Float3 => MTLVertexFormat.Float3, + ElementFormat.Float4 => MTLVertexFormat.Float4, + + ElementFormat.UInt1 => MTLVertexFormat.UInt, + ElementFormat.UInt2 => MTLVertexFormat.UInt2, + ElementFormat.UInt3 => MTLVertexFormat.UInt3, + ElementFormat.UInt4 => MTLVertexFormat.UInt4, + ElementFormat.Int1 => MTLVertexFormat.Int, + ElementFormat.Int2 => MTLVertexFormat.Int2, + ElementFormat.Int3 => MTLVertexFormat.Int3, + ElementFormat.Int4 => MTLVertexFormat.Int4, + + _ => MTLVertexFormat.Invalid + }; + } + + public static MTLCullMode Metal(CullMode cullMode) + { + return cullMode switch + { + CullMode.None => MTLCullMode.None, + CullMode.Front => MTLCullMode.Front, + CullMode.Back => MTLCullMode.Back, + _ => MTLCullMode.None + }; + } + + public static MTLTriangleFillMode Metal(FillMode fillMode) + { + return fillMode switch + { + FillMode.Solid => MTLTriangleFillMode.Fill, + FillMode.Wireframe => MTLTriangleFillMode.Lines, + _ => MTLTriangleFillMode.Fill + }; + } + + public static MTLWinding Metal(FrontFace frontFace) + { + return frontFace switch + { + FrontFace.CounterClockwise => MTLWinding.CounterClockwise, + FrontFace.Clockwise => MTLWinding.Clockwise, + _ => MTLWinding.Clockwise + }; + } + + public static MTLIndexType Metal(IndexFormat indexFormat) + { + return indexFormat switch + { + IndexFormat.UInt16 => MTLIndexType.UInt16, + IndexFormat.UInt32 => MTLIndexType.UInt32, + _ => MTLIndexType.UInt16 + }; + } + + public static MTLVisibilityResultMode Metal(QueryType queryType) + { + return queryType switch + { + QueryType.Occlusion => MTLVisibilityResultMode.Counting, + QueryType.BinaryOcclusion => MTLVisibilityResultMode.Boolean, + _ => MTLVisibilityResultMode.Disabled + }; + } + + public static MTLAccelerationStructureUsage Metal(AccelerationStructureBuildFlags accelerationStructureBuildFlags) + { + MTLAccelerationStructureUsage result = MTLAccelerationStructureUsage.None; + + if (accelerationStructureBuildFlags.HasFlag(AccelerationStructureBuildFlags.AllowUpdate) || accelerationStructureBuildFlags.HasFlag(AccelerationStructureBuildFlags.PerformUpdate)) + { + result |= MTLAccelerationStructureUsage.Refit; + } + + if (accelerationStructureBuildFlags.HasFlag(AccelerationStructureBuildFlags.PreferFastTrace)) + { + result |= MTLAccelerationStructureUsage.PreferFastIntersection; + } + + if (accelerationStructureBuildFlags.HasFlag(AccelerationStructureBuildFlags.PreferFastBuild)) + { + result |= MTLAccelerationStructureUsage.PreferFastBuild; + } + + if (accelerationStructureBuildFlags.HasFlag(AccelerationStructureBuildFlags.MinimizeMemory)) + { + result |= MTLAccelerationStructureUsage.MinimizeMemory; + } + + return result; + } + + public static MTLAccelerationStructureInstanceOptions Metal(RayTracingInstanceFlags rayTracingInstanceFlags) + { + MTLAccelerationStructureInstanceOptions result = MTLAccelerationStructureInstanceOptions.None; + + if (rayTracingInstanceFlags.HasFlag(RayTracingInstanceFlags.TriangleCullDisable)) + { + result |= MTLAccelerationStructureInstanceOptions.DisableTriangleCulling; + } + + if (rayTracingInstanceFlags.HasFlag(RayTracingInstanceFlags.TriangleFrontCounterClockwise)) + { + result |= MTLAccelerationStructureInstanceOptions.TriangleFrontFacingWindingCounterClockwise; + } + + if (rayTracingInstanceFlags.HasFlag(RayTracingInstanceFlags.ForceOpaque)) + { + result |= MTLAccelerationStructureInstanceOptions.Opaque; + } + + if (rayTracingInstanceFlags.HasFlag(RayTracingInstanceFlags.ForceNoOpaque)) + { + result |= MTLAccelerationStructureInstanceOptions.NonOpaque; + } + + return result; + } +} diff --git a/sources/Zenith.NET.Metal/MTLFrameBuffer.cs b/sources/Zenith.NET.Metal/MTLFrameBuffer.cs new file mode 100644 index 00000000..547642f1 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLFrameBuffer.cs @@ -0,0 +1,108 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLFrameBuffer : FrameBuffer +{ + public MTL4RenderPassDescriptor Descriptor; + + public MTLFrameBuffer(MTLGraphicsContext context, FrameBufferDesc desc) : base(context, desc) + { + ColorAttachmentCount = (uint)desc.ColorAttachments.Length; + HasDepthStencilAttachment = desc.DepthStencilAttachment is not null; + + Descriptor = new(); + + uint width = 0; + uint height = 0; + SampleCount sampleCount = SampleCount.Count1; + + for (uint i = 0; i < ColorAttachmentCount; i++) + { + FrameBufferAttachment attachment = desc.ColorAttachments[i]; + + if (i is 0) + { + ZenithHelper.MipDimensions(attachment.Target.Desc.Width, attachment.Target.Desc.Height, 0, attachment.Slice.MipLevel, out width, out height, out _); + + sampleCount = attachment.Target.Desc.SampleCount; + } + + Descriptor.ColorAttachments[i] = new() + { + Texture = attachment.Target.Metal().Texture, + Level = attachment.Slice.MipLevel, + Slice = ZenithHelper.FlattenArrayLayerIndex(attachment.Target.Desc, attachment.Slice), + LoadAction = MTLLoadAction.Load, + StoreAction = MTLStoreAction.Store + }; + } + + if (HasDepthStencilAttachment) + { + FrameBufferAttachment attachment = desc.DepthStencilAttachment!.Value; + + if (ColorAttachmentCount is 0) + { + ZenithHelper.MipDimensions(attachment.Target.Desc.Width, attachment.Target.Desc.Height, 0, attachment.Slice.MipLevel, out width, out height, out _); + + sampleCount = attachment.Target.Desc.SampleCount; + } + + if (ZenithHelper.HasDepth(attachment.Target.Desc.Format)) + { + Descriptor.DepthAttachment = new() + { + Texture = attachment.Target.Metal().Texture, + Level = attachment.Slice.MipLevel, + Slice = ZenithHelper.FlattenArrayLayerIndex(attachment.Target.Desc, attachment.Slice), + LoadAction = MTLLoadAction.Load, + StoreAction = MTLStoreAction.Store + }; + } + + if (ZenithHelper.HasStencil(attachment.Target.Desc.Format)) + { + Descriptor.StencilAttachment = new() + { + Texture = attachment.Target.Metal().Texture, + Level = attachment.Slice.MipLevel, + Slice = ZenithHelper.FlattenArrayLayerIndex(attachment.Target.Desc, attachment.Slice), + LoadAction = MTLLoadAction.Load, + StoreAction = MTLStoreAction.Store + }; + } + } + + Descriptor.RenderTargetWidth = width; + Descriptor.RenderTargetHeight = height; + + Width = width; + Height = height; + Output = new() + { + ColorAttachments = [.. desc.ColorAttachments.Select(static item => item.Target.Desc.Format)], + DepthStencilAttachment = desc.DepthStencilAttachment?.Target.Desc.Format, + SampleCount = sampleCount + }; + } + + public override uint ColorAttachmentCount { get; } + + public override bool HasDepthStencilAttachment { get; } + + public override uint Width { get; } + + public override uint Height { get; } + + public override Output Output { get; } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + Descriptor.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLGraphicsContext.cs b/sources/Zenith.NET.Metal/MTLGraphicsContext.cs index 63343e00..bdd25114 100644 --- a/sources/Zenith.NET.Metal/MTLGraphicsContext.cs +++ b/sources/Zenith.NET.Metal/MTLGraphicsContext.cs @@ -1,7 +1,33 @@ -namespace Zenith.NET.Metal; +using Metal.NET; + +namespace Zenith.NET.Metal; internal class MTLGraphicsContext(bool useValidationLayer) : GraphicsContext(Backend.Metal, useValidationLayer) { + public MTLDevice Device = MTLDevice.Null; + + public MTL4Compiler Compiler = MTL4Compiler.Null; + + public MTLResidencySet ResidencySet = MTLResidencySet.Null; + + public MTL4CommandQueue GraphicsQueue = MTL4CommandQueue.Null; + + public MTL4CommandQueue ComputeQueue = MTL4CommandQueue.Null; + + public MTL4CommandQueue CopyQueue = MTL4CommandQueue.Null; + + public void AddAllocation(MTLAllocation allocation) + { + ResidencySet.AddAllocation(allocation); + ResidencySet.Commit(); + } + + public void RemoveAllocation(MTLAllocation allocation) + { + ResidencySet.RemoveAllocation(allocation); + ResidencySet.Commit(); + } + protected override void Initialize(bool useValidationLayer, out Capabilities capabilities, out CommandQueue graphics, @@ -9,76 +35,119 @@ protected override void Initialize(bool useValidationLayer, out CommandQueue copy, out ValidationLayer? validationLayer) { - throw new NotImplementedException(); + Device = MTLDevice.CreateSystemDefaultDevice(); + + if (!Device.SupportsFamily(MTLGPUFamily.Metal4)) + { + throw new NotSupportedException("Metal 4 is not supported on system default device."); + } + + Compiler = Device.MakeCompiler(new(), out NSError error); + error.Success(); + + ResidencySet = Device.MakeResidencySet(new(), out error); + error.Success(); + + GraphicsQueue = Device.MakeMTL4CommandQueue(); + ComputeQueue = Device.MakeMTL4CommandQueue(); + CopyQueue = Device.MakeMTL4CommandQueue(); + + GraphicsQueue.AddResidencySet(ResidencySet); + ComputeQueue.AddResidencySet(ResidencySet); + CopyQueue.AddResidencySet(ResidencySet); + + capabilities = new MTLCapabilities(this); + graphics = new MTLCommandQueue(this, CommandQueueType.Graphics, GraphicsQueue); + compute = new MTLCommandQueue(this, CommandQueueType.Compute, ComputeQueue); + copy = new MTLCommandQueue(this, CommandQueueType.Copy, CopyQueue); + validationLayer = null; } protected override SwapChain CreateSwapChainImpl(SwapChainDesc desc) { - throw new NotImplementedException(); + return new MTLSwapChain(this, desc); } protected override FrameBuffer CreateFrameBufferImpl(FrameBufferDesc desc) { - throw new NotImplementedException(); + return new MTLFrameBuffer(this, desc); } protected override Shader CreateShaderImpl(ShaderDesc desc) { - throw new NotImplementedException(); + return new MTLShader(this, desc); } protected override Buffer CreateBufferImpl(BufferDesc desc) { - throw new NotImplementedException(); + return new MTLBuffer(this, desc); } protected override BufferView CreateBufferViewImpl(BufferViewDesc desc) { - throw new NotImplementedException(); + return new MTLBufferView(this, desc); } protected override Texture CreateTextureImpl(TextureDesc desc) { - throw new NotImplementedException(); + return new MTLTexture(this, desc); } protected override TextureView CreateTextureViewImpl(TextureViewDesc desc) { - throw new NotImplementedException(); + return new MTLTextureView(this, desc); } protected override Sampler CreateSamplerImpl(SamplerDesc desc) { - throw new NotImplementedException(); + return new MTLSampler(this, desc); } protected override ResourceLayout CreateResourceLayoutImpl(ResourceLayoutDesc desc) { - throw new NotImplementedException(); + return new MTLResourceLayout(this, desc); } protected override ResourceTable CreateResourceTableImpl(ResourceTableDesc desc) { - throw new NotImplementedException(); + return new MTLResourceTable(this, desc); } protected override GraphicsPipeline CreateGraphicsPipelineImpl(GraphicsPipelineDesc desc) { - throw new NotImplementedException(); + return new MTLGraphicsPipeline(this, desc); } protected override ComputePipeline CreateComputePipelineImpl(ComputePipelineDesc desc) { - throw new NotImplementedException(); + return new MTLComputePipeline(this, desc); } protected override MeshShadingPipeline CreateMeshShadingPipelineImpl(MeshShadingPipelineDesc desc) { - throw new NotImplementedException(); + return new MTLMeshShadingPipeline(this, desc); } protected override QueryHeap CreateQueryHeapImpl(QueryHeapDesc desc) { - throw new NotImplementedException(); + return new MTLQueryHeap(this, desc); + } + + protected override void Destroy() + { + base.Destroy(); + + CopyQueue.RemoveResidencySet(ResidencySet); + ComputeQueue.RemoveResidencySet(ResidencySet); + GraphicsQueue.RemoveResidencySet(ResidencySet); + + CopyQueue.Dispose(); + ComputeQueue.Dispose(); + GraphicsQueue.Dispose(); + + ResidencySet.Dispose(); + Compiler.Dispose(); + + Device.Dispose(); } } diff --git a/sources/Zenith.NET.Metal/MTLGraphicsPipeline.cs b/sources/Zenith.NET.Metal/MTLGraphicsPipeline.cs new file mode 100644 index 00000000..86fa35ca --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLGraphicsPipeline.cs @@ -0,0 +1,122 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLGraphicsPipeline : GraphicsPipeline +{ + public MTLRenderPipelineState RenderPipelineState; + + public MTLDepthStencilState DepthStencilState; + + public MTLGraphicsPipeline(MTLGraphicsContext context, GraphicsPipelineDesc desc) : base(context, desc) + { + VertexBufferStartIndex = desc.ResourceLayout is not null ? desc.ResourceLayout.Metal().BufferCount : 0; + + MTL4RenderPipelineDescriptor descriptor = new() + { + VertexFunctionDescriptor = desc.Vertex.Metal().Descriptor, + FragmentFunctionDescriptor = desc.Pixel.Metal().Descriptor, + InputPrimitiveTopology = MTLFormats.Metal(desc.PrimitiveTopology).TopologyClass + }; + + // RenderStates - Output + { + descriptor.AlphaToCoverageState = desc.RenderStates.BlendState.AlphaToCoverageEnable ? MTL4AlphaToCoverageState.Enabled : MTL4AlphaToCoverageState.Disabled; + + BlendStateRenderTarget[] blendStateRenderTargets = + [ + desc.RenderStates.BlendState.RenderTarget0, + desc.RenderStates.BlendState.RenderTarget1, + desc.RenderStates.BlendState.RenderTarget2, + desc.RenderStates.BlendState.RenderTarget3, + desc.RenderStates.BlendState.RenderTarget4, + desc.RenderStates.BlendState.RenderTarget5, + desc.RenderStates.BlendState.RenderTarget6, + desc.RenderStates.BlendState.RenderTarget7 + ]; + + for (int i = 0; i < blendStateRenderTargets.Length; i++) + { + BlendStateRenderTarget target = desc.RenderStates.BlendState.IndependentBlendEnable ? blendStateRenderTargets[i] : blendStateRenderTargets[0]; + + descriptor.ColorAttachments[(uint)i] = new() + { + PixelFormat = i < desc.Output.ColorAttachments.Length ? MTLFormats.Metal(desc.Output.ColorAttachments[i]).PixelFormat : MTLPixelFormat.Invalid, + BlendingState = target.BlendEnable ? MTL4BlendState.Enabled : MTL4BlendState.Disabled, + SourceRGBBlendFactor = MTLFormats.Metal(target.SrcBlend), + DestinationRGBBlendFactor = MTLFormats.Metal(target.DestBlend), + RgbBlendOperation = MTLFormats.Metal(target.BlendOp), + SourceAlphaBlendFactor = MTLFormats.Metal(target.SrcBlendAlpha), + DestinationAlphaBlendFactor = MTLFormats.Metal(target.DestBlendAlpha), + AlphaBlendOperation = MTLFormats.Metal(target.BlendOpAlpha), + WriteMask = MTLFormats.Metal(target.Flags) + }; + } + + descriptor.RasterSampleCount = MTLFormats.Metal(desc.Output.SampleCount); + + DepthStencilState = context.Device.MakeDepthStencilState(new() + { + DepthCompareFunction = desc.RenderStates.DepthStencilState.DepthEnable ? MTLFormats.Metal(desc.RenderStates.DepthStencilState.DepthFunc) : MTLCompareFunction.Always, + IsDepthWriteEnabled = desc.RenderStates.DepthStencilState.DepthWriteEnable, + FrontFaceStencil = desc.RenderStates.DepthStencilState.StencilEnable ? new() + { + StencilCompareFunction = MTLFormats.Metal(desc.RenderStates.DepthStencilState.FrontFace.StencilFunc), + StencilFailureOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.FrontFace.StencilFailOp), + DepthFailureOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.FrontFace.StencilDepthFailOp), + DepthStencilPassOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.FrontFace.StencilPassOp), + ReadMask = desc.RenderStates.DepthStencilState.StencilReadMask, + WriteMask = desc.RenderStates.DepthStencilState.StencilWriteMask + } : MTLStencilDescriptor.Null, + BackFaceStencil = desc.RenderStates.DepthStencilState.StencilEnable ? new() + { + StencilCompareFunction = MTLFormats.Metal(desc.RenderStates.DepthStencilState.BackFace.StencilFunc), + StencilFailureOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.BackFace.StencilFailOp), + DepthFailureOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.BackFace.StencilDepthFailOp), + DepthStencilPassOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.BackFace.StencilPassOp), + ReadMask = desc.RenderStates.DepthStencilState.StencilReadMask, + WriteMask = desc.RenderStates.DepthStencilState.StencilWriteMask + } : MTLStencilDescriptor.Null + }); + } + + // InputLayouts + { + uint binding = VertexBufferStartIndex; + uint attribute = 0; + for (int i = 0; i < desc.InputLayouts.Length; i++) + { + InputLayout inputLayout = desc.InputLayouts[i]; + + descriptor.VertexDescriptor.Layouts[binding].Stride = inputLayout.StrideInBytes; + + foreach (InputElement element in inputLayout.Elements) + { + descriptor.VertexDescriptor.Attributes[attribute++] = new() + { + Format = MTLFormats.Metal(element.Format), + Offset = element.OffsetInBytes, + BufferIndex = binding + }; + } + + binding++; + } + } + + RenderPipelineState = context.Compiler.MakeRenderPipelineState(descriptor, MTL4CompilerTaskOptions.Null, out NSError error); + error.Success(); + } + + public uint VertexBufferStartIndex { get; } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + DepthStencilState.Dispose(); + RenderPipelineState.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLHeap.cs b/sources/Zenith.NET.Metal/MTLHeap.cs new file mode 100644 index 00000000..fc3caa19 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLHeap.cs @@ -0,0 +1,60 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLHeap : GraphicsResource +{ + public MtlHeap Heap; + + public MTLHeap(MTLGraphicsContext context, BufferDesc desc, out MtlBuffer buffer) : base(context) + { + context.AddAllocation(Heap = context.Device.MakeHeap(new() + { + Size = context.Device.HeapBufferSizeAndAlign(desc.SizeInBytes, MTLFormats.Metal(desc.Flags)).Size, + ResourceOptions = MTLFormats.Metal(desc.Flags), + Type = MTLHeapType.Automatic + })); + + buffer = Heap.MakeBuffer(desc.SizeInBytes, MTLFormats.Metal(desc.Flags)); + } + + public MTLHeap(MTLGraphicsContext context, TextureDesc desc, out MtlTexture texture) : base(context) + { + MTLTextureDescriptor descriptor = new() + { + TextureType = MTLFormats.Metal(desc.Type), + PixelFormat = MTLFormats.Metal(desc.Format).PixelFormat, + Width = desc.Width, + Height = desc.Height, + Depth = desc.Depth, + MipmapLevelCount = desc.MipLevels, + SampleCount = MTLFormats.Metal(desc.SampleCount), + ArrayLength = desc.ArrayLayers, + ResourceOptions = MTLResourceOptions.StorageModePrivate | MTLResourceOptions.HazardTrackingModeUntracked, + Usage = MTLFormats.Metal(desc.Flags), + AllowGPUOptimizedContents = true + }; + + context.AddAllocation(Heap = context.Device.MakeHeap(new() + { + Size = context.Device.HeapTextureSizeAndAlign(descriptor).Size, + ResourceOptions = descriptor.ResourceOptions, + Type = MTLHeapType.Automatic + })); + + texture = Heap.MakeTexture(descriptor); + } + + public new MTLGraphicsContext Context => (MTLGraphicsContext)base.Context; + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + Context.RemoveAllocation(Heap); + + Heap.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLMeshShadingPipeline.cs b/sources/Zenith.NET.Metal/MTLMeshShadingPipeline.cs new file mode 100644 index 00000000..cc84af40 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLMeshShadingPipeline.cs @@ -0,0 +1,100 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLMeshShadingPipeline : MeshShadingPipeline +{ + public MTLRenderPipelineState RenderPipelineState; + + public MTLDepthStencilState DepthStencilState; + + public MTLMeshShadingPipeline(MTLGraphicsContext context, MeshShadingPipelineDesc desc) : base(context, desc) + { + MTL4MeshRenderPipelineDescriptor descriptor = new() + { + MeshFunctionDescriptor = desc.Mesh.Metal().Descriptor, + FragmentFunctionDescriptor = desc.Pixel.Metal().Descriptor, + RequiredThreadsPerMeshThreadgroup = new(desc.MeshThreadGroupSizeX, desc.MeshThreadGroupSizeY, desc.MeshThreadGroupSizeZ) + }; + + if (desc.Amplification is not null) + { + descriptor.ObjectFunctionDescriptor = desc.Amplification.Metal().Descriptor; + descriptor.RequiredThreadsPerObjectThreadgroup = new(desc.AmplificationThreadGroupSizeX, desc.AmplificationThreadGroupSizeY, desc.AmplificationThreadGroupSizeZ); + } + + // RenderStates - Output + { + descriptor.AlphaToCoverageState = desc.RenderStates.BlendState.AlphaToCoverageEnable ? MTL4AlphaToCoverageState.Enabled : MTL4AlphaToCoverageState.Disabled; + + BlendStateRenderTarget[] blendStateRenderTargets = + [ + desc.RenderStates.BlendState.RenderTarget0, + desc.RenderStates.BlendState.RenderTarget1, + desc.RenderStates.BlendState.RenderTarget2, + desc.RenderStates.BlendState.RenderTarget3, + desc.RenderStates.BlendState.RenderTarget4, + desc.RenderStates.BlendState.RenderTarget5, + desc.RenderStates.BlendState.RenderTarget6, + desc.RenderStates.BlendState.RenderTarget7 + ]; + + for (int i = 0; i < blendStateRenderTargets.Length; i++) + { + BlendStateRenderTarget target = desc.RenderStates.BlendState.IndependentBlendEnable ? blendStateRenderTargets[i] : blendStateRenderTargets[0]; + + descriptor.ColorAttachments[(uint)i] = new() + { + PixelFormat = i < desc.Output.ColorAttachments.Length ? MTLFormats.Metal(desc.Output.ColorAttachments[i]).PixelFormat : MTLPixelFormat.Invalid, + BlendingState = target.BlendEnable ? MTL4BlendState.Enabled : MTL4BlendState.Disabled, + SourceRGBBlendFactor = MTLFormats.Metal(target.SrcBlend), + DestinationRGBBlendFactor = MTLFormats.Metal(target.DestBlend), + RgbBlendOperation = MTLFormats.Metal(target.BlendOp), + SourceAlphaBlendFactor = MTLFormats.Metal(target.SrcBlendAlpha), + DestinationAlphaBlendFactor = MTLFormats.Metal(target.DestBlendAlpha), + AlphaBlendOperation = MTLFormats.Metal(target.BlendOpAlpha), + WriteMask = MTLFormats.Metal(target.Flags) + }; + } + + descriptor.RasterSampleCount = MTLFormats.Metal(desc.Output.SampleCount); + + DepthStencilState = context.Device.MakeDepthStencilState(new() + { + DepthCompareFunction = desc.RenderStates.DepthStencilState.DepthEnable ? MTLFormats.Metal(desc.RenderStates.DepthStencilState.DepthFunc) : MTLCompareFunction.Always, + IsDepthWriteEnabled = desc.RenderStates.DepthStencilState.DepthWriteEnable, + FrontFaceStencil = desc.RenderStates.DepthStencilState.StencilEnable ? new() + { + StencilCompareFunction = MTLFormats.Metal(desc.RenderStates.DepthStencilState.FrontFace.StencilFunc), + StencilFailureOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.FrontFace.StencilFailOp), + DepthFailureOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.FrontFace.StencilDepthFailOp), + DepthStencilPassOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.FrontFace.StencilPassOp), + ReadMask = desc.RenderStates.DepthStencilState.StencilReadMask, + WriteMask = desc.RenderStates.DepthStencilState.StencilWriteMask + } : MTLStencilDescriptor.Null, + BackFaceStencil = desc.RenderStates.DepthStencilState.StencilEnable ? new() + { + StencilCompareFunction = MTLFormats.Metal(desc.RenderStates.DepthStencilState.BackFace.StencilFunc), + StencilFailureOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.BackFace.StencilFailOp), + DepthFailureOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.BackFace.StencilDepthFailOp), + DepthStencilPassOperation = MTLFormats.Metal(desc.RenderStates.DepthStencilState.BackFace.StencilPassOp), + ReadMask = desc.RenderStates.DepthStencilState.StencilReadMask, + WriteMask = desc.RenderStates.DepthStencilState.StencilWriteMask + } : MTLStencilDescriptor.Null + }); + } + + RenderPipelineState = context.Compiler.MakeRenderPipelineState(descriptor, MTL4CompilerTaskOptions.Null, out NSError error); + error.Success(); + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + DepthStencilState.Dispose(); + RenderPipelineState.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLQueryHeap.cs b/sources/Zenith.NET.Metal/MTLQueryHeap.cs new file mode 100644 index 00000000..99edbc27 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLQueryHeap.cs @@ -0,0 +1,50 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal unsafe class MTLQueryHeap : QueryHeap +{ + public MTL4CounterHeap CounterHeap; + + public MTLQueryHeap(MTLGraphicsContext context, QueryHeapDesc desc) : base(context, desc) + { + MTL4CounterHeapDescriptor descriptor = new() + { + Type = MTL4CounterHeapType.Timestamp, + Count = desc.Count + }; + + CounterHeap = context.Device.MakeCounterHeap(descriptor, out NSError error); + error.Success(); + + Buffer = new(context, new() + { + SizeInBytes = sizeof(ulong) * desc.Count, + StrideInBytes = sizeof(ulong), + Flags = BufferUsageFlags.MapRead + }); + } + + public MTLBuffer Buffer { get; } + + protected override void GetResultsImpl(Span results, uint startIndex) + { + MappedMemory mappedMemory = Buffer.Map(); + + new Span((void*)(mappedMemory.Pointer + (sizeof(ulong) * startIndex)), results.Length).CopyTo(results); + + Buffer.Unmap(); + } + + protected override void SetResourceName(string name) + { + CounterHeap.Label = name; + } + + protected override void Destroy() + { + Buffer.Dispose(); + + CounterHeap.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLResourceLayout.cs b/sources/Zenith.NET.Metal/MTLResourceLayout.cs new file mode 100644 index 00000000..34b60f3a --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLResourceLayout.cs @@ -0,0 +1,45 @@ +namespace Zenith.NET.Metal; + +internal class MTLResourceLayout : ResourceLayout +{ + public MTLResourceLayout(MTLGraphicsContext context, ResourceLayoutDesc desc) : base(context, desc) + { + for (int i = 0; i < desc.Bindings.Length; i++) + { + ResourceBinding binding = desc.Bindings[i]; + + switch (binding.Type) + { + case ResourceType.ConstantBuffer: + case ResourceType.StructuredBuffer: + case ResourceType.StructuredBufferReadWrite: + case ResourceType.AccelerationStructure: + BufferCount += binding.Count; + break; + + case ResourceType.Texture: + case ResourceType.TextureReadWrite: + TextureCount += binding.Count; + break; + + case ResourceType.Sampler: + SamplerCount += binding.Count; + break; + } + } + } + + public uint BufferCount { get; } + + public uint TextureCount { get; } + + public uint SamplerCount { get; } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + } +} diff --git a/sources/Zenith.NET.Metal/MTLResourceTable.cs b/sources/Zenith.NET.Metal/MTLResourceTable.cs new file mode 100644 index 00000000..50885767 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLResourceTable.cs @@ -0,0 +1,155 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLResourceTable : ResourceTable +{ + private readonly Binding[] bufferBindings; + private readonly Binding[] textureBindings; + private readonly Binding[] samplerBindings; + private readonly Binding[] accelerationStructureBindings; + + public MTL4ArgumentTable ArgumentTable; + + public MTLResourceTable(MTLGraphicsContext context, ResourceTableDesc desc) : base(context, desc) + { + MTLResourceLayout layout = desc.Layout.Metal(); + + MTL4ArgumentTableDescriptor descriptor = new() + { + MaxBufferBindCount = layout.BufferCount, + MaxTextureBindCount = layout.TextureCount, + MaxSamplerStateBindCount = layout.SamplerCount + }; + + ArgumentTable = context.Device.MakeArgumentTable(descriptor, out NSError error); + error.Success(); + + List bufferBindingList = []; + List textureBindingList = []; + List samplerBindingList = []; + List accelerationStructureBindingList = []; + + uint resourceStartIndex = 0; + + for (int i = 0; i < layout.Desc.Bindings.Length; i++) + { + ResourceBinding binding = layout.Desc.Bindings[i]; + + for (uint j = 0; j < binding.Count; j++) + { + IBindableResource resource = desc.Resources[(int)(resourceStartIndex + j)]; + + switch (binding.Type) + { + case ResourceType.ConstantBuffer: + case ResourceType.StructuredBuffer: + case ResourceType.StructuredBufferReadWrite: + if (resource is Buffer buffer) + { + bufferBindingList.Add(new(buffer.Metal().GpuAddress, default, binding.Index + j)); + } + else if (resource is BufferView bufferView) + { + bufferBindingList.Add(new(bufferView.Metal().GpuAddress, default, binding.Index + j)); + } + break; + + case ResourceType.Texture: + case ResourceType.TextureReadWrite: + if (resource is Texture texture) + { + textureBindingList.Add(new(default, texture.Metal().Texture.GpuResourceID, binding.Index + j)); + } + else if (resource is TextureView textureView) + { + textureBindingList.Add(new(default, textureView.Metal().Texture.GpuResourceID, binding.Index + j)); + } + break; + + case ResourceType.Sampler: + if (resource is Sampler sampler) + { + samplerBindingList.Add(new(default, sampler.Metal().SamplerState.GpuResourceID, binding.Index + j)); + } + break; + + case ResourceType.AccelerationStructure: + if (resource is TopLevelAccelerationStructure topLevelAccelerationStructure) + { + accelerationStructureBindingList.Add(new(default, topLevelAccelerationStructure.Metal().AccelerationStructure.GpuResourceID, binding.Index + j)); + } + break; + } + } + + resourceStartIndex += binding.Count; + } + + bufferBindings = [.. bufferBindingList]; + textureBindings = [.. textureBindingList]; + samplerBindings = [.. samplerBindingList]; + accelerationStructureBindings = [.. accelerationStructureBindingList]; + + Bind(ArgumentTable); + } + + public void Bind(MTL4ArgumentTable argumentTable) + { + foreach (Binding binding in bufferBindings) + { + binding.Buffer(argumentTable); + } + + foreach (Binding binding in textureBindings) + { + binding.Texture(argumentTable); + } + + foreach (Binding binding in samplerBindings) + { + binding.Sampler(argumentTable); + } + + foreach (Binding binding in accelerationStructureBindings) + { + binding.AccelerationStructure(argumentTable); + } + } + + protected override void PreprocessImpl(CommandBuffer commandBuffer) + { + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + ArgumentTable.Dispose(); + } + + private readonly struct Binding(nuint gpuAddress, MTLResourceID resourceID, uint index) + { + public void Buffer(MTL4ArgumentTable argumentTable) + { + argumentTable.SetAddress(gpuAddress, index); + } + + public void Texture(MTL4ArgumentTable argumentTable) + { + argumentTable.SetTexture(resourceID, index); + } + + public void Sampler(MTL4ArgumentTable argumentTable) + { + argumentTable.SetSamplerState(resourceID, index); + } + + public void AccelerationStructure(MTL4ArgumentTable argumentTable) + { + argumentTable.SetResource(resourceID, index); + } + } +} diff --git a/sources/Zenith.NET.Metal/MTLSampler.cs b/sources/Zenith.NET.Metal/MTLSampler.cs new file mode 100644 index 00000000..2acdba25 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLSampler.cs @@ -0,0 +1,39 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLSampler : Sampler +{ + public MTLSamplerState SamplerState; + + public MTLSampler(MTLGraphicsContext context, SamplerDesc desc) : base(context, desc) + { + MTLSamplerDescriptor descriptor = new() + { + MinFilter = MTLFormats.Metal(desc.Filter).MinFilter, + MagFilter = MTLFormats.Metal(desc.Filter).MagFilter, + MipFilter = MTLFormats.Metal(desc.Filter).MipFilter, + MaxAnisotropy = desc.Filter is Filter.Anisotropic ? desc.MaxAnisotropy : 1, + SAddressMode = MTLFormats.Metal(desc.U), + TAddressMode = MTLFormats.Metal(desc.V), + RAddressMode = MTLFormats.Metal(desc.W), + BorderColor = MTLFormats.Metal(desc.BorderColor), + LodMinClamp = desc.MinLod, + LodMaxClamp = desc.MaxLod, + LodBias = desc.LodBias, + CompareFunction = MTLFormats.Metal(desc.ComparisonFunc), + SupportArgumentBuffers = true + }; + + SamplerState = context.Device.MakeSamplerState(descriptor); + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + SamplerState.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLShader.cs b/sources/Zenith.NET.Metal/MTLShader.cs new file mode 100644 index 00000000..f5a419a3 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLShader.cs @@ -0,0 +1,32 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLShader : Shader +{ + public MTLLibrary Library; + + public MTL4LibraryFunctionDescriptor Descriptor; + + public MTLShader(MTLGraphicsContext context, ShaderDesc desc) : base(context, desc) + { + Library = context.Device.MakeLibrary(DispatchData.Create(desc.ShaderBytes), out NSError error); + error.Success(); + + Descriptor = new() + { + Name = desc.EntryPoint, + Library = Library + }; + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + Descriptor.Dispose(); + Library.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLSwapChain.cs b/sources/Zenith.NET.Metal/MTLSwapChain.cs new file mode 100644 index 00000000..34e067ba --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLSwapChain.cs @@ -0,0 +1,77 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLSwapChain : SwapChain +{ + private readonly MTLSwapChainFrameBuffer swapChainFrameBuffer; + + public CAMetalLayer Layer = CAMetalLayer.Null; + + public CAMetalDrawable Drawable = CAMetalDrawable.Null; + + public MTLSwapChain(MTLGraphicsContext context, SwapChainDesc desc) : base(context, desc) + { + swapChainFrameBuffer = new(context, this); + + CreateSwapChain(); + } + + public new MTLGraphicsContext Context => (MTLGraphicsContext)base.Context; + + public override FrameBuffer FrameBuffer => swapChainFrameBuffer.Get(Desc.Surface.Width, Desc.Surface.Height, Drawable); + + public override void Present() + { + Drawable.Present(); + Drawable.Dispose(); + + Drawable = NSAutorelease.Own(Layer.NextDrawable); + } + + protected override void ResizeImpl() + { + Drawable.Dispose(); + + Layer.DrawableSize = new(Desc.Surface.Width, Desc.Surface.Height); + + Drawable = NSAutorelease.Own(Layer.NextDrawable); + } + + protected override void RefreshImpl() + { + CreateSwapChain(); + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + DestroySwapChain(); + + swapChainFrameBuffer.Dispose(); + } + + private void CreateSwapChain() + { + DestroySwapChain(); + + Layer = new(Desc.Surface.Handles[0], NativeObjectOwnership.Borrowed) + { + Device = Context.Device, + PixelFormat = MTLFormats.Metal(Desc.ColorTargetFormat).PixelFormat, + FramebufferOnly = false, + DrawableSize = new(Desc.Surface.Width, Desc.Surface.Height) + }; + + Drawable = NSAutorelease.Own(Layer.NextDrawable); + } + + private void DestroySwapChain() + { + Drawable.Dispose(); + Layer.Dispose(); + } +} diff --git a/sources/Zenith.NET.Metal/MTLSwapChainFrameBuffer.cs b/sources/Zenith.NET.Metal/MTLSwapChainFrameBuffer.cs new file mode 100644 index 00000000..2a2cf920 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLSwapChainFrameBuffer.cs @@ -0,0 +1,77 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLSwapChainFrameBuffer(MTLGraphicsContext context, MTLSwapChain swapChain) : GraphicsResource(context) +{ + private MTLTexture? colorTarget; + private MTLTexture? depthStencilTarget; + private MTLFrameBuffer? frameBuffer; + + public MTLFrameBuffer Get(uint width, uint height, CAMetalDrawable drawable) + { + colorTarget ??= new(context, new() + { + Type = TextureType.Texture2D, + Format = swapChain.Desc.ColorTargetFormat, + Width = width, + Height = height, + Depth = 1, + MipLevels = 1, + ArrayLayers = 1, + SampleCount = SampleCount.Count1, + Flags = TextureUsageFlags.RenderTarget + }, drawable.Texture); + + depthStencilTarget ??= swapChain.Desc.DepthStencilTargetFormat is not null ? new(context, new() + { + Type = TextureType.Texture2D, + Format = swapChain.Desc.DepthStencilTargetFormat.Value, + Width = width, + Height = height, + Depth = 1, + MipLevels = 1, + ArrayLayers = 1, + SampleCount = SampleCount.Count1, + Flags = TextureUsageFlags.DepthStencil + }) : null; + + frameBuffer ??= new(context, new() + { + ColorAttachments = [new() { Target = colorTarget }], + DepthStencilAttachment = depthStencilTarget is not null ? new() { Target = depthStencilTarget } : null + }); + + if (frameBuffer.Width != width || frameBuffer.Height != height) + { + DestroyFrameBuffer(); + + return Get(width, height, drawable); + } + + frameBuffer.Descriptor.ColorAttachments[0].Texture = colorTarget.Texture = drawable.Texture; + + return frameBuffer; + } + + protected override void SetResourceName(string name) + { + } + + protected override void Destroy() + { + DestroyFrameBuffer(); + } + + private void DestroyFrameBuffer() + { + frameBuffer?.Dispose(); + frameBuffer = null; + + depthStencilTarget?.Dispose(); + depthStencilTarget = null; + + colorTarget?.Dispose(); + colorTarget = null; + } +} diff --git a/sources/Zenith.NET.Metal/MTLTexture.cs b/sources/Zenith.NET.Metal/MTLTexture.cs new file mode 100644 index 00000000..34609036 --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLTexture.cs @@ -0,0 +1,33 @@ +namespace Zenith.NET.Metal; + +internal class MTLTexture : Texture +{ + public MtlTexture Texture; + + public MTLTexture(MTLGraphicsContext context, TextureDesc desc) : base(context, desc) + { + Heap = new(context, desc, out Texture); + } + + public MTLTexture(MTLGraphicsContext context, TextureDesc desc, MtlTexture texture) : base(context, desc) + { + Texture = texture; + } + + public MTLHeap? Heap { get; } + + protected override void SetResourceName(string name) + { + Texture.Label = name; + } + + protected override void Destroy() + { + if (Heap is not null) + { + Texture.Dispose(); + + Heap.Dispose(); + } + } +} diff --git a/sources/Zenith.NET.Metal/MTLTextureView.cs b/sources/Zenith.NET.Metal/MTLTextureView.cs new file mode 100644 index 00000000..8a6c578c --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLTextureView.cs @@ -0,0 +1,42 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal class MTLTextureView : TextureView +{ + public MtlTexture Texture; + + public MTLTextureView(MTLGraphicsContext context, TextureViewDesc desc) : base(context, desc) + { + MTLTextureViewDescriptor descriptor = new() + { + PixelFormat = MTLFormats.Metal(desc.Texture.Desc.Format).PixelFormat, + TextureType = Resolve(desc), + LevelRange = new(desc.FirstMipLevel, desc.MipLevelCount), + SliceRange = new(ZenithHelper.FlattenArrayLayerRange(desc).FlattenArrayLayerIndex, ZenithHelper.FlattenArrayLayerRange(desc).FlattenArrayLayerCount) + }; + + Texture = desc.Texture.Metal().Texture.MakeTextureView(descriptor); + } + + protected override void SetResourceName(string name) + { + Texture.Label = name; + } + + protected override void Destroy() + { + Texture.Dispose(); + } + + private static MTLTextureType Resolve(TextureViewDesc desc) + { + return MTLFormats.Metal(desc.Texture.Desc.Type switch + { + TextureType.Texture1DArray when desc.ArrayLayerCount is 1 => TextureType.Texture1D, + TextureType.Texture2DArray when desc.ArrayLayerCount is 1 => TextureType.Texture2D, + TextureType.TextureCubeArray when desc.ArrayLayerCount is 1 => TextureType.TextureCube, + _ => desc.Texture.Desc.Type + }); + } +} diff --git a/sources/Zenith.NET.Metal/MTLTopLevelAccelerationStructure.cs b/sources/Zenith.NET.Metal/MTLTopLevelAccelerationStructure.cs new file mode 100644 index 00000000..4707a81a --- /dev/null +++ b/sources/Zenith.NET.Metal/MTLTopLevelAccelerationStructure.cs @@ -0,0 +1,108 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal unsafe class MTLTopLevelAccelerationStructure : TopLevelAccelerationStructure +{ + public MTLAccelerationStructure AccelerationStructure; + + public MTLTopLevelAccelerationStructure(MTLGraphicsContext context, TopLevelAccelerationStructureDesc desc, MTLCommandBuffer commandBuffer) : base(context, desc) + { + uint instanceCount = (uint)desc.Instances.Length; + + InstanceBuffer = new(context, new() + { + SizeInBytes = (uint)(sizeof(MTLIndirectAccelerationStructureInstanceDescriptor) * instanceCount), + StrideInBytes = (uint)sizeof(MTLIndirectAccelerationStructureInstanceDescriptor), + Flags = BufferUsageFlags.MapWrite + }); + + FillInstanceBuffer(desc); + + MTL4InstanceAccelerationStructureDescriptor descriptor = new() + { + InstanceDescriptorBuffer = new(InstanceBuffer.Metal().GpuAddress, InstanceBuffer.Desc.SizeInBytes), + InstanceDescriptorStride = (uint)sizeof(MTLIndirectAccelerationStructureInstanceDescriptor), + InstanceCount = instanceCount, + InstanceDescriptorType = MTLAccelerationStructureInstanceDescriptorType.Indirect, + InstanceTransformationMatrixLayout = MTLMatrixLayout.RowMajor, + Usage = MTLFormats.Metal(desc.Flags) + }; + + MTLAccelerationStructureSizes sizes = context.Device.AccelerationStructureSizes(descriptor); + + AccelerationStructure = context.Device.MakeAccelerationStructure(sizes.AccelerationStructureSize); + context.AddAllocation(AccelerationStructure); + + ScratchBuffer = new(context, new() + { + SizeInBytes = (uint)sizes.BuildScratchBufferSize, + StrideInBytes = (uint)sizes.BuildScratchBufferSize, + Flags = BufferUsageFlags.ShaderResource + }); + + commandBuffer.CommandEncoder.Compute?.Build(AccelerationStructure, descriptor, new(ScratchBuffer.Buffer.GpuAddress, ScratchBuffer.Desc.SizeInBytes)); + } + + public new MTLGraphicsContext Context => (MTLGraphicsContext)base.Context; + + public MTLBuffer InstanceBuffer { get; } + + public MTLBuffer ScratchBuffer { get; } + + public void Update(MTLCommandBuffer commandBuffer, TopLevelAccelerationStructureDesc newDesc) + { + FillInstanceBuffer(newDesc); + + MTL4InstanceAccelerationStructureDescriptor descriptor = new() + { + InstanceDescriptorBuffer = new(InstanceBuffer.Metal().GpuAddress, InstanceBuffer.Desc.SizeInBytes), + InstanceDescriptorStride = (uint)sizeof(MTLIndirectAccelerationStructureInstanceDescriptor), + InstanceCount = (uint)newDesc.Instances.Length, + InstanceDescriptorType = MTLAccelerationStructureInstanceDescriptorType.Indirect, + InstanceTransformationMatrixLayout = MTLMatrixLayout.RowMajor, + Usage = MTLFormats.Metal(newDesc.Flags) + }; + + commandBuffer.CommandEncoder.Compute?.Refit(AccelerationStructure, descriptor, AccelerationStructure, new(ScratchBuffer.Buffer.GpuAddress, ScratchBuffer.Desc.SizeInBytes)); + } + + protected override void SetResourceName(string name) + { + AccelerationStructure.Label = name; + } + + protected override void Destroy() + { + Context.RemoveAllocation(AccelerationStructure); + + AccelerationStructure.Dispose(); + + ScratchBuffer.Dispose(); + InstanceBuffer.Dispose(); + } + + private void FillInstanceBuffer(TopLevelAccelerationStructureDesc desc) + { + uint instanceCount = (uint)desc.Instances.Length; + + MappedMemory mappedMemory = InstanceBuffer.Map(); + + MTLIndirectAccelerationStructureInstanceDescriptor* instances = (MTLIndirectAccelerationStructureInstanceDescriptor*)mappedMemory.Pointer; + for (uint i = 0; i < instanceCount; i++) + { + RayTracingInstance instance = desc.Instances[i]; + + instances[i] = new() + { + TransformationMatrix = *(MTLPackedFloat4x3*)&instance.Transform, + Options = MTLFormats.Metal(instance.Flags), + Mask = instance.Mask, + UserID = instance.ID, + AccelerationStructureID = instance.AccelerationStructure.Metal().AccelerationStructure.GpuResourceID + }; + } + + InstanceBuffer.Unmap(); + } +} diff --git a/sources/Zenith.NET.Metal/NSAutorelease.cs b/sources/Zenith.NET.Metal/NSAutorelease.cs new file mode 100644 index 00000000..8033430c --- /dev/null +++ b/sources/Zenith.NET.Metal/NSAutorelease.cs @@ -0,0 +1,34 @@ +using Metal.NET; + +namespace Zenith.NET.Metal; + +internal static class NSAutorelease +{ + public static T Own(Func func) where T : NSObject, INativeObject + { + using NSAutoreleasePool _ = new(); + + return func().Retain(); + } + + public static T Own(Func func, T1 arg1) where T : NSObject, INativeObject + { + using NSAutoreleasePool _ = new(); + + return func(arg1).Retain(); + } + + public static T Own(Func func, T1 arg1, T2 arg2) where T : NSObject, INativeObject + { + using NSAutoreleasePool _ = new(); + + return func(arg1, arg2).Retain(); + } + + public static T Own(Func func, T1 arg1, T2 arg2, T3 arg3) where T : NSObject, INativeObject + { + using NSAutoreleasePool _ = new(); + + return func(arg1, arg2, arg3).Retain(); + } +} diff --git a/sources/Zenith.NET.Metal/Usings.cs b/sources/Zenith.NET.Metal/Usings.cs new file mode 100644 index 00000000..6bc1dc32 --- /dev/null +++ b/sources/Zenith.NET.Metal/Usings.cs @@ -0,0 +1,4 @@ +global using MtlBuffer = Metal.NET.MTLBuffer; +global using MtlFence = Metal.NET.MTLFence; +global using MtlHeap = Metal.NET.MTLHeap; +global using MtlTexture = Metal.NET.MTLTexture; diff --git a/sources/Zenith.NET.Metal/Zenith.NET.Metal.csproj b/sources/Zenith.NET.Metal/Zenith.NET.Metal.csproj index 002a1a85..ecf99eae 100644 --- a/sources/Zenith.NET.Metal/Zenith.NET.Metal.csproj +++ b/sources/Zenith.NET.Metal/Zenith.NET.Metal.csproj @@ -8,6 +8,10 @@ + + + + diff --git a/sources/Zenith.NET.Vulkan/VKCommandBuffer.cs b/sources/Zenith.NET.Vulkan/VKCommandBuffer.cs index c673b9aa..01001e66 100644 --- a/sources/Zenith.NET.Vulkan/VKCommandBuffer.cs +++ b/sources/Zenith.NET.Vulkan/VKCommandBuffer.cs @@ -66,15 +66,17 @@ protected override void CopyBufferToTextureImpl(Buffer src, uint srcOffsetInByte vkDest.TransitionLayout(this, destSlice, ImageLayout.TransferDstOptimal); + (uint blockWidth, uint blockHeight, uint blocksWide, uint blocksHigh) = ZenithHelper.BlockLayout(vkDest.Desc.Format, destExtent.Width, destExtent.Height); + uint formatSizeInBytes = ZenithHelper.SizeInBytes(vkDest.Desc.Format); - uint sliceRowPitchInBytes = ZenithHelper.Align(formatSizeInBytes * destExtent.Width, GraphicsContext.TextureRowPitchAlignment); - uint sliceDepthPitchInBytes = ZenithHelper.Align(sliceRowPitchInBytes * destExtent.Height, GraphicsContext.TextureDepthPitchAlignment); + uint sliceRowPitchInBytes = ZenithHelper.Align(formatSizeInBytes * blocksWide, GraphicsContext.TextureRowPitchAlignment); + uint sliceDepthPitchInBytes = ZenithHelper.Align(sliceRowPitchInBytes * blocksHigh, GraphicsContext.TextureDepthPitchAlignment); BufferImageCopy bufferImageCopy = new() { BufferOffset = srcOffsetInBytes, - BufferRowLength = sliceRowPitchInBytes / formatSizeInBytes, - BufferImageHeight = sliceDepthPitchInBytes / sliceRowPitchInBytes, + BufferRowLength = sliceRowPitchInBytes / formatSizeInBytes * blockWidth, + BufferImageHeight = sliceDepthPitchInBytes / sliceRowPitchInBytes * blockHeight, ImageSubresource = new() { AspectMask = VKFormats.Vulkan(vkDest.Desc.Format, vkDest.Desc.Flags).AspectFlags, @@ -162,15 +164,17 @@ protected override void CopyTextureToBufferImpl(Texture src, TextureSlice srcSli vkSrc.TransitionLayout(this, srcSlice, ImageLayout.TransferSrcOptimal); + (uint blockWidth, uint blockHeight, uint blocksWide, uint blocksHigh) = ZenithHelper.BlockLayout(vkSrc.Desc.Format, srcExtent.Width, srcExtent.Height); + uint formatSizeInBytes = ZenithHelper.SizeInBytes(vkSrc.Desc.Format); - uint sliceRowPitchInBytes = ZenithHelper.Align(formatSizeInBytes * srcExtent.Width, GraphicsContext.TextureRowPitchAlignment); - uint sliceDepthPitchInBytes = ZenithHelper.Align(sliceRowPitchInBytes * srcExtent.Height, GraphicsContext.TextureDepthPitchAlignment); + uint sliceRowPitchInBytes = ZenithHelper.Align(formatSizeInBytes * blocksWide, GraphicsContext.TextureRowPitchAlignment); + uint sliceDepthPitchInBytes = ZenithHelper.Align(sliceRowPitchInBytes * blocksHigh, GraphicsContext.TextureDepthPitchAlignment); BufferImageCopy bufferImageCopy = new() { BufferOffset = destOffsetInBytes, - BufferRowLength = sliceRowPitchInBytes / formatSizeInBytes, - BufferImageHeight = sliceDepthPitchInBytes / sliceRowPitchInBytes, + BufferRowLength = sliceRowPitchInBytes / formatSizeInBytes * blockWidth, + BufferImageHeight = sliceDepthPitchInBytes / sliceRowPitchInBytes * blockHeight, ImageSubresource = new() { AspectMask = VKFormats.Vulkan(vkSrc.Desc.Format, vkSrc.Desc.Flags).AspectFlags, @@ -259,7 +263,7 @@ protected override void BeginRenderPassImpl(FrameBuffer frameBuffer, ClearValue { VKFrameBuffer vkFrameBuffer = frameBuffer.Vulkan(); - vkFrameBuffer.PrepareAttachmentsForRendering(this); + vkFrameBuffer.PrepareAttachments(this); bool clearColor = clearValue.Flags.HasFlag(ClearFlags.Color); bool clearDepth = clearValue.Flags.HasFlag(ClearFlags.Depth); @@ -323,7 +327,7 @@ protected override void EndRenderPassImpl(FrameBuffer frameBuffer) { Context.Vk.CmdEndRendering(CommandBuffer); - frameBuffer.Vulkan().FinalizeColorAttachmentsForPresent(this); + frameBuffer.Vulkan().PresentColorAttachments(this); } protected override void SetScissorsImpl(Scissor[] scissors) diff --git a/sources/Zenith.NET.Vulkan/VKFrameBuffer.cs b/sources/Zenith.NET.Vulkan/VKFrameBuffer.cs index 14eea2c7..e904c56d 100644 --- a/sources/Zenith.NET.Vulkan/VKFrameBuffer.cs +++ b/sources/Zenith.NET.Vulkan/VKFrameBuffer.cs @@ -121,7 +121,7 @@ public VKFrameBuffer(VKGraphicsContext context, FrameBufferDesc desc) : base(con public ImageView[] ImageViews { get; } - public void PrepareAttachmentsForRendering(VKCommandBuffer commandBuffer) + public void PrepareAttachments(VKCommandBuffer commandBuffer) { foreach (FrameBufferAttachment attachment in Desc.ColorAttachments) { @@ -131,7 +131,7 @@ public void PrepareAttachmentsForRendering(VKCommandBuffer commandBuffer) Desc.DepthStencilAttachment?.Target.Vulkan().TransitionLayout(commandBuffer, Desc.DepthStencilAttachment.Value.Slice, ImageLayout.DepthStencilAttachmentOptimal); } - public void FinalizeColorAttachmentsForPresent(VKCommandBuffer commandBuffer) + public void PresentColorAttachments(VKCommandBuffer commandBuffer) { foreach (FrameBufferAttachment attachment in Desc.ColorAttachments) { diff --git a/sources/Zenith.NET.Vulkan/VKGraphicsContext.cs b/sources/Zenith.NET.Vulkan/VKGraphicsContext.cs index 399ada30..5fd94b41 100644 --- a/sources/Zenith.NET.Vulkan/VKGraphicsContext.cs +++ b/sources/Zenith.NET.Vulkan/VKGraphicsContext.cs @@ -164,7 +164,7 @@ protected override void Initialize(bool useValidationLayer, Vk.CreateInstance(&createInfo, null, out Instance).Success(); - LamdaNativeContext context = new((proc) => Vk.GetInstanceProcAddr(Instance, (byte*)ZenithMarshal.StringToPointer(scope, proc, StringEncoding.UTF8))); + LamdaNativeContext context = new(proc => Vk.GetInstanceProcAddr(Instance, (byte*)ZenithMarshal.StringToPointer(scope, proc, StringEncoding.UTF8))); DebugUtils = enabledExtensions.Contains(ExtDebugUtils.ExtensionName) ? new(context) : null; Surface = enabledExtensions.Contains(KhrSurface.ExtensionName) ? new(context) : null; diff --git a/sources/Zenith.NET.Vulkan/VKGraphicsPipeline.cs b/sources/Zenith.NET.Vulkan/VKGraphicsPipeline.cs index 6eeb6c21..536f9d1a 100644 --- a/sources/Zenith.NET.Vulkan/VKGraphicsPipeline.cs +++ b/sources/Zenith.NET.Vulkan/VKGraphicsPipeline.cs @@ -180,14 +180,14 @@ public VKGraphicsPipeline(VKGraphicsContext context, GraphicsPipelineDesc desc) Stride = inputLayout.StrideInBytes }; - foreach (InputElement inputElement in inputLayout.Elements) + foreach (InputElement element in inputLayout.Elements) { vertexAttributeDescriptions[attribute] = new() { Location = attribute, Binding = binding, - Format = VKFormats.Vulkan(inputElement.Format), - Offset = inputElement.OffsetInBytes + Format = VKFormats.Vulkan(element.Format), + Offset = element.OffsetInBytes }; attribute++; diff --git a/sources/Zenith.NET.Vulkan/VKTopLevelAccelerationStructure.cs b/sources/Zenith.NET.Vulkan/VKTopLevelAccelerationStructure.cs index 3ea04bb5..04994252 100644 --- a/sources/Zenith.NET.Vulkan/VKTopLevelAccelerationStructure.cs +++ b/sources/Zenith.NET.Vulkan/VKTopLevelAccelerationStructure.cs @@ -180,8 +180,8 @@ private void FillInstanceBuffer(TopLevelAccelerationStructureDesc desc, out Acce instances[i] = new() { Transform = *(TransformMatrixKHR*)&instance.Transform, - InstanceCustomIndex = instance.InstanceID, - Mask = instance.InstanceMask, + InstanceCustomIndex = instance.ID, + Mask = instance.Mask, Flags = VKFormats.Vulkan(instance.Flags), AccelerationStructureReference = instance.AccelerationStructure.Vulkan().DeviceAddress }; diff --git a/sources/Zenith.NET.Vulkan/Zenith.NET.Vulkan.csproj b/sources/Zenith.NET.Vulkan/Zenith.NET.Vulkan.csproj index 39132514..56ad22a6 100644 --- a/sources/Zenith.NET.Vulkan/Zenith.NET.Vulkan.csproj +++ b/sources/Zenith.NET.Vulkan/Zenith.NET.Vulkan.csproj @@ -9,7 +9,6 @@ - diff --git a/sources/Zenith.NET/CommandBuffer.cs b/sources/Zenith.NET/CommandBuffer.cs index 3f7a9e21..443a9877 100644 --- a/sources/Zenith.NET/CommandBuffer.cs +++ b/sources/Zenith.NET/CommandBuffer.cs @@ -1,4 +1,4 @@ -using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Zenith.NET; @@ -24,41 +24,45 @@ public void Upload(Buffer buffer, uint offsetInBytes, ReadOnlySpan data) w return; } - uint sizeInBytes = (uint)(Unsafe.SizeOf() * data.Length); + ReadOnlySpan byteData = MemoryMarshal.AsBytes(data); - Buffer temporary = Context.Uploader.Buffer(this, sizeInBytes); - temporary.Upload(data, 0); + Buffer temporary = Context.Uploader.Buffer(this, (uint)byteData.Length); + temporary.Upload(byteData, 0); - CopyBuffer(temporary, 0, buffer, offsetInBytes, sizeInBytes); + CopyBuffer(temporary, 0, buffer, offsetInBytes, (uint)byteData.Length); } - public void Upload(Texture texture, TextureSlice slice, TextureOffset offset, TextureExtent extent, ReadOnlySpan pixels) where T : unmanaged + public void Upload(Texture texture, TextureSlice slice, TextureOffset offset, TextureExtent extent, ReadOnlySpan data) where T : unmanaged { - uint formatSizeInBytes = ZenithHelper.SizeInBytes(texture.Desc.Format); - - if (Unsafe.SizeOf() != formatSizeInBytes || pixels.Length is 0 || pixels.Length != extent.Width * extent.Height * extent.Depth) + if (data.Length is 0) { return; } - uint sliceSizeInTexels = extent.Width * extent.Height; + ReadOnlySpan byteData = MemoryMarshal.AsBytes(data); + + uint formatSizeInBytes = ZenithHelper.SizeInBytes(texture.Desc.Format); + (_, _, uint blocksWide, uint blocksHigh) = ZenithHelper.BlockLayout(texture.Desc.Format, extent.Width, extent.Height); + + uint sliceRowPitchInBytes = formatSizeInBytes * blocksWide; + uint sliceDepthPitchInBytes = sliceRowPitchInBytes * blocksHigh; - uint sliceRowPitchInBytes = ZenithHelper.Align(formatSizeInBytes * extent.Width, GraphicsContext.TextureRowPitchAlignment); - uint sliceDepthPitchInBytes = ZenithHelper.Align(sliceRowPitchInBytes * extent.Height, GraphicsContext.TextureDepthPitchAlignment); + uint sliceRowPitchAlignInBytes = ZenithHelper.Align(sliceRowPitchInBytes, GraphicsContext.TextureRowPitchAlignment); + uint sliceDepthPitchAlignInBytes = ZenithHelper.Align(sliceRowPitchAlignInBytes * blocksHigh, GraphicsContext.TextureDepthPitchAlignment); TextureExtent sliceExtent = extent with { Depth = 1 }; for (uint i = 0; i < extent.Depth; i++) { - Buffer temporary = Context.Uploader.Buffer(this, sliceDepthPitchInBytes); + Buffer temporary = Context.Uploader.Buffer(this, sliceDepthPitchAlignInBytes); MappedMemory mappedMemory = temporary.Map(); unsafe { - for (int j = 0; j < extent.Height; j++) + for (uint j = 0; j < blocksHigh; j++) { - pixels.Slice((int)((sliceSizeInTexels * i) + (extent.Width * j)), (int)extent.Width).CopyTo(new((void*)(mappedMemory.Pointer + (sliceRowPitchInBytes * j)), (int)extent.Width)); + byteData.Slice((int)((sliceDepthPitchInBytes * i) + (sliceRowPitchInBytes * j)), (int)sliceRowPitchInBytes).CopyTo(new((void*)(mappedMemory.Pointer + (sliceRowPitchAlignInBytes * j)), (int)sliceRowPitchInBytes)); } } diff --git a/sources/Zenith.NET/Structs/MeshShadingPipelineDesc.cs b/sources/Zenith.NET/Structs/MeshShadingPipelineDesc.cs index 2f95a192..d7af84d6 100644 --- a/sources/Zenith.NET/Structs/MeshShadingPipelineDesc.cs +++ b/sources/Zenith.NET/Structs/MeshShadingPipelineDesc.cs @@ -16,11 +16,11 @@ public record struct MeshShadingPipelineDesc public Output Output; - public uint ObjectThreadGroupSizeX; + public uint AmplificationThreadGroupSizeX; - public uint ObjectThreadGroupSizeY; + public uint AmplificationThreadGroupSizeY; - public uint ObjectThreadGroupSizeZ; + public uint AmplificationThreadGroupSizeZ; public uint MeshThreadGroupSizeX; diff --git a/sources/Zenith.NET/Structs/RayTracingInstance.cs b/sources/Zenith.NET/Structs/RayTracingInstance.cs index 50145959..599c7ead 100644 --- a/sources/Zenith.NET/Structs/RayTracingInstance.cs +++ b/sources/Zenith.NET/Structs/RayTracingInstance.cs @@ -6,9 +6,9 @@ public record struct RayTracingInstance { public BottomLevelAccelerationStructure AccelerationStructure; - public uint InstanceID; + public uint ID; - public byte InstanceMask; + public byte Mask; public Matrix4x4 Transform; diff --git a/sources/Zenith.NET/Texture.cs b/sources/Zenith.NET/Texture.cs index f7934f0a..b0debb5e 100644 --- a/sources/Zenith.NET/Texture.cs +++ b/sources/Zenith.NET/Texture.cs @@ -8,7 +8,7 @@ public abstract class Texture(GraphicsContext context, TextureDesc desc) : Graph public void Upload(ReadOnlySpan data, TextureSlice slice, TextureOffset offset, TextureExtent extent) where T : unmanaged { - if (data.Length is 0 || data.Length != extent.Width * extent.Height * extent.Depth) + if (data.Length is 0) { return; } diff --git a/sources/Zenith.NET/Uploader.cs b/sources/Zenith.NET/Uploader.cs index 875d2e87..30f3b454 100644 --- a/sources/Zenith.NET/Uploader.cs +++ b/sources/Zenith.NET/Uploader.cs @@ -15,7 +15,7 @@ public Buffer Buffer(CommandBuffer commandBuffer, uint sizeInBytes) borrowed[commandBuffer] = leases = []; } - if (!(available.Where(item => item.HasCapacityFor(sizeInBytes)).MinBy(item => item.Buffer.Desc.SizeInBytes) is Lease lease && available.Remove(lease))) + if (!(available.Where(item => item.HasCapacityFor(sizeInBytes)).MinBy(static item => item.Buffer.Desc.SizeInBytes) is Lease lease && available.Remove(lease))) { lease = new(context.CreateBuffer(new() { diff --git a/sources/Zenith.NET/ValidationLayer.cs b/sources/Zenith.NET/ValidationLayer.cs index 72743485..9a4e6aca 100644 --- a/sources/Zenith.NET/ValidationLayer.cs +++ b/sources/Zenith.NET/ValidationLayer.cs @@ -589,9 +589,9 @@ internal void ValidateDesc(MeshShadingPipelineDesc desc) CheckOutput("MeshShadingPipelineDesc.Output", desc.Output); - if (desc.Amplification is not null && (desc.ObjectThreadGroupSizeX is 0 || desc.ObjectThreadGroupSizeY is 0 || desc.ObjectThreadGroupSizeZ is 0)) + if (desc.Amplification is not null && (desc.AmplificationThreadGroupSizeX is 0 || desc.AmplificationThreadGroupSizeY is 0 || desc.AmplificationThreadGroupSizeZ is 0)) { - ReportFrameworkMessage(MessageSeverity.Error, string.Format(ValidationMessages.MustBeGreaterThanZero, "MeshShadingPipelineDesc object thread group sizes (ObjectThreadGroupSizeX, ObjectThreadGroupSizeY, ObjectThreadGroupSizeZ)")); + ReportFrameworkMessage(MessageSeverity.Error, string.Format(ValidationMessages.MustBeGreaterThanZero, "MeshShadingPipelineDesc amplification thread group sizes (AmplificationThreadGroupSizeX, AmplificationThreadGroupSizeY, AmplificationThreadGroupSizeZ)")); } if (desc.MeshThreadGroupSizeX is 0 || desc.MeshThreadGroupSizeY is 0 || desc.MeshThreadGroupSizeZ is 0) @@ -777,9 +777,9 @@ void CheckRayTracingInstance(string name, RayTracingInstance rayTracingInstance) return; } - if (rayTracingInstance.InstanceID > ValidationConstants.MaxInstanceId) + if (rayTracingInstance.ID > ValidationConstants.MaxRayTracingInstanceID) { - ReportFrameworkMessage(MessageSeverity.Error, string.Format(ValidationMessages.MustBeLessThanOrEqualTo, $"{name}.InstanceID", ValidationConstants.MaxInstanceId)); + ReportFrameworkMessage(MessageSeverity.Error, string.Format(ValidationMessages.MustBeLessThanOrEqualTo, $"{name}.ID", ValidationConstants.MaxRayTracingInstanceID)); } } } @@ -934,7 +934,7 @@ file static class ValidationConstants public const int IndexSizeUInt32 = 4; - public const int MaxInstanceId = 16777215; + public const int MaxRayTracingInstanceID = 16777215; } file static class ValidationMessages diff --git a/sources/Zenith.NET/ZenithHelper.cs b/sources/Zenith.NET/ZenithHelper.cs index a758d24c..892b940c 100644 --- a/sources/Zenith.NET/ZenithHelper.cs +++ b/sources/Zenith.NET/ZenithHelper.cs @@ -21,9 +21,19 @@ public static void MipDimensions(uint width, uint height, uint depth, uint mipLe mipDepth = Math.Max(1, depth >> (int)mipLevel); } - public static (uint BlockWidth, uint BlockHeight) BlockSize(PixelFormat format) + public static bool HasDepth(PixelFormat pixelFormat) { - return format switch + return pixelFormat is PixelFormat.D16UNorm or PixelFormat.D24UNormS8UInt or PixelFormat.D32Float or PixelFormat.D32FloatS8UInt; + } + + public static bool HasStencil(PixelFormat pixelFormat) + { + return pixelFormat is PixelFormat.D24UNormS8UInt or PixelFormat.D32FloatS8UInt; + } + + public static (uint BlockWidth, uint BlockHeight, uint BlocksWide, uint BlocksHigh) BlockLayout(PixelFormat format, uint width, uint height) + { + (uint blockWidth, uint blockHeight) = format switch { PixelFormat.BC4UNorm or PixelFormat.BC4SNorm or @@ -32,51 +42,43 @@ PixelFormat.BC5SNorm or PixelFormat.BC6HUFloat or PixelFormat.BC6HSFloat or PixelFormat.BC7UNorm or - PixelFormat.BC7SRgb => (4, 4), + PixelFormat.BC7SRgb => (4u, 4u), PixelFormat.ETC2UNorm or PixelFormat.ETC2SRgb or PixelFormat.ETC2A1UNorm or PixelFormat.ETC2A1SRgb or PixelFormat.ETC2A8UNorm or - PixelFormat.ETC2A8SRgb => (4, 4), + PixelFormat.ETC2A8SRgb => (4u, 4u), PixelFormat.ASTC4x4UNorm or PixelFormat.ASTC4x4SRgb or - PixelFormat.ASTC4x4Float => (4, 4), + PixelFormat.ASTC4x4Float => (4u, 4u), PixelFormat.ASTC5x5UNorm or PixelFormat.ASTC5x5SRgb or - PixelFormat.ASTC5x5Float => (5, 5), + PixelFormat.ASTC5x5Float => (5u, 5u), PixelFormat.ASTC6x6UNorm or PixelFormat.ASTC6x6SRgb or - PixelFormat.ASTC6x6Float => (6, 6), + PixelFormat.ASTC6x6Float => (6u, 6u), PixelFormat.ASTC8x8UNorm or PixelFormat.ASTC8x8SRgb or - PixelFormat.ASTC8x8Float => (8, 8), + PixelFormat.ASTC8x8Float => (8u, 8u), PixelFormat.ASTC10x10UNorm or PixelFormat.ASTC10x10SRgb or - PixelFormat.ASTC10x10Float => (10, 10), + PixelFormat.ASTC10x10Float => (10u, 10u), PixelFormat.ASTC12x12UNorm or PixelFormat.ASTC12x12SRgb or - PixelFormat.ASTC12x12Float => (12, 12), + PixelFormat.ASTC12x12Float => (12u, 12u), - _ => (1, 1) + _ => (1u, 1u) }; - } - - public static bool HasDepth(PixelFormat pixelFormat) - { - return pixelFormat is PixelFormat.D16UNorm or PixelFormat.D24UNormS8UInt or PixelFormat.D32Float or PixelFormat.D32FloatS8UInt; - } - public static bool HasStencil(PixelFormat pixelFormat) - { - return pixelFormat is PixelFormat.D24UNormS8UInt or PixelFormat.D32FloatS8UInt; + return (blockWidth, blockHeight, (width + blockWidth - 1) / blockWidth, (height + blockHeight - 1) / blockHeight); } public static uint SizeInBytes(PixelFormat format) @@ -186,10 +188,7 @@ PixelFormat.ASTC12x12SRgb or public static uint SizeInBytes(PixelFormat format, uint width, uint height) { - (uint blockWidth, uint blockHeight) = BlockSize(format); - - uint blocksWide = (width + blockWidth - 1) / blockWidth; - uint blocksHigh = (height + blockHeight - 1) / blockHeight; + (_, _, uint blocksWide, uint blocksHigh) = BlockLayout(format, width, height); return blocksWide * blocksHigh * SizeInBytes(format); }