diff --git a/.git-branches.toml b/.git-branches.toml new file mode 100644 index 00000000..09f89f7a --- /dev/null +++ b/.git-branches.toml @@ -0,0 +1,95 @@ +# Git Town configuration file +# +# Run "git town config setup" to add additional entries +# to this file after updating Git Town. +# +# The "push-hook" setting determines whether Git Town +# permits or prevents Git hooks while pushing branches. +# Hooks are enabled by default. If your Git hooks are slow, +# you can disable them to speed up branch syncing. +# +# When disabled, Git Town pushes using the "--no-verify" switch. +# More info at https://www.git-town.com/preferences/push-hook. +push-hook = true + +# Should Git Town push the new branches it creates +# immediately to origin even if they are empty? +# +# When enabled, you can run "git push" right away +# but creating new branches is slower and +# it triggers an unnecessary CI run on the empty branch. +# +# When disabled, many Git Town commands execute faster +# and Git Town will create the missing tracking branch +# on the first run of "git sync". +push-new-branches = false + +# Should "git ship" delete the tracking branch? +# You want to disable this if your code hosting platform +# (GitHub, GitLab, etc) deletes head branches when +# merging pull requests through its UI. +ship-delete-tracking-branch = true + +# Should "git ship" sync branches before shipping them? +# +# Guidance: enable when shipping branches locally on your machine +# and disable when shipping feature branches via the code hosting +# API or web UI. +# +# When enabled, branches are always fully up to date when shipped +# and you get a chance to resolve merge conflicts +# between the feature branch to ship and the main development branch +# on the feature branch. This helps keep the main branch green. +# But this also triggers another CI run and delays shipping. +sync-before-ship = true + +# Should "git sync" also fetch updates from the upstream remote? +# +# If an "upstream" remote exists, and this setting is enabled, +# "git sync" will also update the local main branch +# with commits from the main branch at the upstream remote. +# +# This is useful if the repository you work on is a fork, +# and you want to keep it in sync with the repo it was forked from. +sync-upstream = false + +[branches] + +# The main branch is the branch from which you cut new feature branches, +# and into which you ship feature branches when they are done. +# This branch is often called "main", "master", or "development". +main = "dev" + +# Perennial branches are long-lived branches. +# They are never shipped and have no ancestors. +# Typically, perennial branches have names like +# "development", "staging", "qa", "production", etc. +perennials = ["main"] + +[hosting] + +# Knowing the type of code hosting platform allows Git Town +# to open browser URLs and talk to the code hosting API. +# Most people can leave this on "auto-detect". +# Only change this if your code hosting server uses as custom URL. +platform = "github" + +# When using SSH identities, define the hostname +# of your source code repository. Only change this +# if the auto-detection does not work for you. +# origin-hostname = "" + +[sync-strategy] + +# How should Git Town synchronize feature branches? +# Feature branches are short-lived branches cut from +# the main branch and shipped back into the main branch. +# Typically you develop features and bug fixes on them, +# hence their name. +feature-branches = "rebase" + +# How should Git Town synchronize perennial branches? +# Perennial branches have no parent branch. +# The only updates they receive are additional commits +# made to their tracking branch somewhere else. +perennial-branches = "merge" diff --git a/.github/workflows/build-listing.yml b/.github/workflows/build-listing.yml index 811ea5c5..d732b6ac 100644 --- a/.github/workflows/build-listing.yml +++ b/.github/workflows/build-listing.yml @@ -28,15 +28,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 # check out this repo - - uses: actions/checkout@v3 # check out automation repo + - uses: actions/checkout@v4 # check out this repo + - uses: actions/checkout@v4 # check out automation repo with: repository: vrchat-community/package-list-action path: ${{env.pathToCi}} clean: false # otherwise the local repo will no longer be checked out - name: Restore Cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: | ${{env.pathToCi}}/.nuke/temp @@ -49,13 +49,13 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Setup Pages - uses: actions/configure-pages@v2 + uses: actions/configure-pages@v5 - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v3 with: path: ${{env.listPublishDirectory}} - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v1 + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 98d8c943..b900375b --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,8 @@ Assets/Develop Assets/Develop.meta Assets/Bakery Assets/Bakery.meta +Assets/Decalery +Assets/Decalery.meta Assets/BakeryLightmaps Assets/BakeryLightmaps.meta Assets/Editor.meta @@ -97,4 +99,39 @@ Packages/sh.orels.shaders.inspector/Editor/MaterialLibraries/Resources/**/*.json /Assets/Gizmos /Assets/Gizmos.meta /Assets/LTCGI-Generated -/Assets/LTCGI-Generated.meta \ No newline at end of file +/Assets/LTCGI-Generated.meta +/Assets/csc.rsp +/Assets/csc.rsp.meta +/Assets/_PoiyomiShaders +/Assets/_PoiyomiShaders.meta +/Thry +/Exports + +/Assets/Samples +/Assets/Samples.meta + +/UserSettings/**/* +UserSettings/Layouts/default-2022.dwlt +UserSettings/EditorUserSettings.asset +UserSettings/Search.settings +Assets/TextMesh Pro +Assets/TextMesh Pro.meta +Assets/XR +Assets/XR.meta +Assets/AmplifyShaderEditor +Assets/AmplifyShaderEditor.meta +/bakery-* +Assets/XSToon3 +Assets/XSToon3.meta +Assets/AreaLit +Assets/AreaLit.meta +Assets/VRSL Addons +Assets/VRSL Addons.meta +Assets/Umodeler-Hub +Assets/Umodeler-Hub.meta +Assets/UniversalRenderPipelineGlobalSettings.asset +Assets/UniversalRenderPipelineGlobalSettings.asset.meta +ProjectSettings/UModeler-Hub.json + +Assets/Mochie +Assets/Mochie.meta \ No newline at end of file diff --git a/Assets/Tools/Editor/ReleaseExporter.cs b/Assets/Tools/Editor/ReleaseExporter.cs old mode 100644 new mode 100755 index dabbd36c..e13be90a --- a/Assets/Tools/Editor/ReleaseExporter.cs +++ b/Assets/Tools/Editor/ReleaseExporter.cs @@ -1,7 +1,12 @@ -using System.IO; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Linq; using UnityEditor; using UnityEngine; -using VRC.PackageManagement.Core.Types.Packages; +using Debug = UnityEngine.Debug; namespace ORL.Tools { @@ -14,46 +19,114 @@ public static class ReleaseExporter "Packages/sh.orels.shaders.generator", }; + [Serializable] + public class PackageInfo + { + public string name; + public string displayName; + public string version; + } + [MenuItem("Tools/orels1/Export Release")] - private static void ExportAsUnityPackage () + private static void ExportAsUnityPackage() { - var manifestPath = Path.Combine(_exportFolders[0], VRCPackageManifest.Filename); - var manifest = VRCPackageManifest.GetManifestAtPath(manifestPath); + var manifestPath = Path.Combine(_exportFolders[0], "package.json"); + var manifest = JsonUtility.FromJson(File.ReadAllText(manifestPath)); if (manifest == null) { Debug.LogError("Failed to load main package manifest to extract version, aborting"); return; } + // Get a list of new files from git + var processInfo = new ProcessStartInfo("git", "status -s") + { + WorkingDirectory = new FileInfo(".").FullName, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true + }; + var gitProc = Process.Start(processInfo); + gitProc.WaitForExit(); + if (gitProc.ExitCode != 0) + { + Debug.LogError("Failed to get git status, aborting"); + return; + } + var ignored = new List(); + while (!gitProc.StandardOutput.EndOfStream) + { + var line = gitProc.StandardOutput.ReadLine(); + if (line.StartsWith("??")) + { + ignored.Add(line.Substring(2).Trim().Replace('/', '\\')); + } + } + + Debug.Log($"Exporting version {manifest.version}"); + var exportDir = Path.Combine(Directory.GetCurrentDirectory(), "Exports"); Directory.CreateDirectory(exportDir); - AssetDatabase.ExportPackage - ( - _exportFolders, - Path.Combine(exportDir, $"orl-shaders-combined-{manifest.Version}.unitypackage"), - ExportPackageOptions.Recurse | ExportPackageOptions.Interactive - ); - - AssetDatabase.ExportPackage - ( - _exportFolders[0], - Path.Combine(exportDir, $"sh.orels.shaders-standalone-{manifest.Version}.unitypackage"), - ExportPackageOptions.Recurse | ExportPackageOptions.Interactive - ); - - AssetDatabase.ExportPackage - ( - _exportFolders[1], - Path.Combine(exportDir, $"sh.orels.shaders.inspector-standalone-{manifest.Version}.unitypackage"), - ExportPackageOptions.Recurse | ExportPackageOptions.Interactive - ); - - AssetDatabase.ExportPackage - ( - _exportFolders[2], - Path.Combine(exportDir, $"sh.orels.shaders.generator-standalone-{manifest.Version}.unitypackage"), - ExportPackageOptions.Recurse | ExportPackageOptions.Interactive - ); + + // Export .unitypackage files + ExportAsUnityPackage(_exportFolders, ignored, Path.Combine(exportDir, $"sh.orels.shaders-combined-{manifest.version}.unitypackage")); + ExportAsUnityPackage(_exportFolders[0], ignored, Path.Combine(exportDir, $"sh.orels.shaders-standalone-{manifest.version}.unitypackage")); + ExportAsUnityPackage(_exportFolders[1], ignored, Path.Combine(exportDir, $"sh.orels.shaders.inspector-standalone-{manifest.version}.unitypackage")); + ExportAsUnityPackage(_exportFolders[2], ignored, Path.Combine(exportDir, $"sh.orels.shaders.generator-standalone-{manifest.version}.unitypackage")); + + // Export .zip files + ExportAsZip(_exportFolders[0], ignored, Path.Combine(exportDir, $"sh.orels.shaders-{manifest.version}.zip")); + ExportAsZip(_exportFolders[1], ignored, Path.Combine(exportDir, $"sh.orels.shaders.inspector-{manifest.version}.zip")); + ExportAsZip(_exportFolders[2], ignored, Path.Combine(exportDir, $"sh.orels.shaders.generator-{manifest.version}.zip")); + + // Open the export folder + var exportedPath = new FileInfo("Exports").FullName; + Process.Start(exportedPath); + } + + private static void ExportAsUnityPackage(string[] baseFolders, List ingored, string exportPath) + { + var list = baseFolders.SelectMany(f => Directory.GetFiles(f, "*", SearchOption.AllDirectories)) + .Select(f => f.Replace('/', '\\')) + .Where(f => !ingored.Any(i => f.Contains(i, StringComparison.InvariantCultureIgnoreCase))) + .ToArray(); + + Debug.Log("Packages\\sh.orels.shaders\\Editor\\Dependencies\\ORLLayoutToolkit.cs".Contains("Packages\\sh.orels.shaders\\Editor\\Dependencies\\")); + AssetDatabase.ExportPackage(list, exportPath, ExportPackageOptions.Recurse); + } + + private static void ExportAsUnityPackage(string baseFolder, List ingored, string exportPath) + { + var list = Directory.GetFiles(baseFolder, "*", SearchOption.AllDirectories) + .Select(f => f.Replace('/', '\\')) + .Where(f => !ingored.Any(i => f.Contains(i, StringComparison.InvariantCultureIgnoreCase))) + .ToArray(); + AssetDatabase.ExportPackage(list, exportPath, ExportPackageOptions.Recurse); + } + + private static void ExportAsZip(string baseFolder, List ingored, string exportPath) + { + var list = Directory.GetFiles(baseFolder, "*", SearchOption.AllDirectories) + .Select(f => f.Replace('/', '\\')) + .Where(f => !ingored.Any(i => f.Contains(i, StringComparison.InvariantCultureIgnoreCase))) + .ToArray(); + + if (File.Exists(exportPath)) File.Delete(exportPath); + var basePath = baseFolder.Replace('/', '\\') + '\\'; + using (var zip = new ZipArchive(File.OpenWrite(exportPath), ZipArchiveMode.Create)) + { + foreach (var file in list) + { + var entry = zip.CreateEntry(file.Replace(basePath, "").Replace('\\', '/')); + using (var stream = File.OpenRead(file)) + { + using (var entryStream = entry.Open()) + { + stream.CopyTo(entryStream); + } + } + } + } } } } \ No newline at end of file diff --git a/Packages/.gitignore b/Packages/.gitignore index a49b7524..e26d92b4 100644 --- a/Packages/.gitignore +++ b/Packages/.gitignore @@ -1,6 +1,7 @@ /*/ -!com.vrchat.core.* +!com.vrchat.core.vpm-resolver !sh.orels.shaders.generator !sh.orels.shaders.inspector -!sh.orels.shaders \ No newline at end of file +!sh.orels.shaders +!com.vrchat.core.*/ diff --git a/Packages/com.vrchat.core.bootstrap/Editor/Bootstrap.cs b/Packages/com.vrchat.core.bootstrap/Editor/Bootstrap.cs deleted file mode 100644 index 6b9b4312..00000000 --- a/Packages/com.vrchat.core.bootstrap/Editor/Bootstrap.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.IO; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using UnityEditor; -using UnityEngine; - -namespace VRC.PackageManagement.Core -{ - public class Bootstrap - { - // JSON property names in Project Manifest - public const string UNITY_PACKAGES_FOLDER = "Packages"; - public const string UNITY_MANIFEST_FILENAME = "manifest.json"; - - // VRC Values - public const string VRC_CONFIG = "https://api.vrchat.cloud/api/1/config"; - public const string VRCAgent = "VCCBootstrap/1.0"; - public const string VRC_RESOLVER_PACKAGE = "com.vrchat.core.vpm-resolver"; - - // Finds url for bootstrap package without using JSON - private static Regex _bootstrapRegex = new Regex("\"bootstrap\"\\s*:\\s*\"(.+?(?=\"))\""); - public static string ManifestPath => Path.Combine(Directory.GetCurrentDirectory(), UNITY_PACKAGES_FOLDER, UNITY_MANIFEST_FILENAME); - - // Path where we expect the target package to exist - public static string ResolverPath => - Path.Combine(Directory.GetCurrentDirectory(), UNITY_PACKAGES_FOLDER, VRC_RESOLVER_PACKAGE); - - [InitializeOnLoadMethod] - public static async void CheckForRestore() - { - if (!new DirectoryInfo(ResolverPath).Exists) - { - try - { - await AddResolver(); - } - catch (Exception e) - { - Debug.LogError($"Could not download and install the VPM Package Resolver - you may be missing packages. Exception: {e.Message}"); - } - } - } - - public static async Task AddResolver() - { - var configData = await GetRemoteString(VRC_CONFIG); - if (string.IsNullOrWhiteSpace(configData)) - { - Debug.LogWarning($"Could not get VPM libraries, try again later"); - return; - } - var bootstrapMatch = _bootstrapRegex.Match(configData); - if (!bootstrapMatch.Success || bootstrapMatch.Groups.Count < 2) - { - Debug.LogError($"Could not find bootstrap in config, try again later"); - return; - } - - var url = $"{bootstrapMatch.Groups[1].Value}"; - - var targetFile = Path.Combine(Path.GetTempPath(), $"resolver-{DateTime.Now.ToString("yyyyMMddTHHmmss")}.unitypackage"); - - // Download to dir - var bytes = await Http.GetByteArrayAsync(url); - if (bytes == null || bytes.Length == 0) - { - Debug.LogError($"Could not download Resolver, try again later."); - return; - } - - File.WriteAllBytes(targetFile, bytes); - - if (File.Exists(targetFile)) - { - AssetDatabase.ImportPackage(targetFile, false); - } - else - { - Debug.LogError($"Could not save Resolver, do you have access to write into the Temp folder?"); - } - } - - static HttpClient _http; - - public static HttpClient Http - { - get - { - if (_http != null) - { - return _http; - } - - _http = new HttpClient(); - _http.DefaultRequestHeaders.UserAgent.ParseAdd(VRCAgent); - _http.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue() - { MaxAge = TimeSpan.FromHours(1) }; - return _http; - } - } - - public static async Task GetRemoteString(string url) - { - return await Http.GetStringAsync(url); - } - } -} \ No newline at end of file diff --git a/Packages/com.vrchat.core.bootstrap/Editor/VRChat.Bootstrapper.Editor.asmdef.meta b/Packages/com.vrchat.core.bootstrap/Editor/VRChat.Bootstrapper.Editor.asmdef.meta deleted file mode 100644 index 1d60f490..00000000 --- a/Packages/com.vrchat.core.bootstrap/Editor/VRChat.Bootstrapper.Editor.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e0d8a3ed977bd0948b99f4bce8e56a07 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.bootstrap/License.md b/Packages/com.vrchat.core.bootstrap/License.md deleted file mode 100644 index 275530cd..00000000 --- a/Packages/com.vrchat.core.bootstrap/License.md +++ /dev/null @@ -1,11 +0,0 @@ -# VRCHAT INC. -### VRCHAT DISTRO LICENSE FILE -Version: February 24, 2022 - -**SUMMARY OF TERMS:** Any materials subject to this Distro Asset License may be distributed by you, with or without modifications, on a non-commercial basis (i.e., at no charge), in accordance with the full terms of the Materials License Agreement. - -This Distro License File is a "License File" as defined in the VRChat Materials License Agreement, found at https://hello.vrchat.com/legal/sdk (or any successor link designated by VRChat) (as may be revised from time to time, the "Materials License Agreement"). - -This Distro License File applies to all the files in the Folder containing this Distro License File and those in all Child Folders within that Folder (except with respect to files in any Child Folder that contains a different License File) (such files, other than this Distro License File, the "Covered Files"). All capitalized terms used but not otherwise defined in this Distro License File have the meanings provided in the Materials License Agreement. - -This Distro License File only provides a summary of the terms applicable to the Covered Files. To understand your rights and obligations and the full set of terms that apply to use of the Covered Files, please see the relevant sections of the Materials License Agreement, including terms applicable to Distro Materials. \ No newline at end of file diff --git a/Packages/com.vrchat.core.bootstrap/License.md.meta b/Packages/com.vrchat.core.bootstrap/License.md.meta deleted file mode 100644 index 3a508bc3..00000000 --- a/Packages/com.vrchat.core.bootstrap/License.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: a84f4a071b4a7fa49985f447a0ce2fe2 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.bootstrap/package.json b/Packages/com.vrchat.core.bootstrap/package.json deleted file mode 100644 index d0b50804..00000000 --- a/Packages/com.vrchat.core.bootstrap/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name" : "com.vrchat.core.bootstrap", - "displayName" : "VRChat Package Bootstrapper", - "version" : "0.1.15", - "unity" : "2019.4", - "description" : "Tool to Download VPM Packages", - "vrchatVersion" : "2022.1.1", - "author" : { - "name" : "VRChat", - "email" : "developer@vrchat.com", - "url" : "https://github.com/vrchat/packages" - }, - "url" : "", - "dependencies" : { - "com.unity.nuget.newtonsoft-json" : "2.0.2" - } -} diff --git a/Packages/com.vrchat.core.bootstrap/package.json.meta b/Packages/com.vrchat.core.bootstrap/package.json.meta deleted file mode 100644 index 9aea5881..00000000 --- a/Packages/com.vrchat.core.bootstrap/package.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6c5fffb4815ba9046ad0a2e878396439 -PackageManifestImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.License.txt b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.License.txt deleted file mode 100644 index 66437210..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.License.txt +++ /dev/null @@ -1,7 +0,0 @@ -Copyright (c) 2016 Adam Reeve - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.dll b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.dll deleted file mode 100644 index e0216727..00000000 Binary files a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.dll and /dev/null differ diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.dll.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.dll.meta deleted file mode 100644 index cc2ba32c..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.dll.meta +++ /dev/null @@ -1,33 +0,0 @@ -fileFormatVersion: 2 -guid: 65d82c6541a90644390df2caa29c2209 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.License.txt b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.License.txt deleted file mode 100644 index 37ec93a1..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.License.txt +++ /dev/null @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.dll b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.dll deleted file mode 100644 index 1600c057..00000000 Binary files a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.dll and /dev/null differ diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.dll.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.dll.meta deleted file mode 100644 index 53d8dd73..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.dll.meta +++ /dev/null @@ -1,33 +0,0 @@ -fileFormatVersion: 2 -guid: 0c56563958a156145b708466db0e35cc -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.txt b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.txt deleted file mode 100644 index 8dada3ed..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.License.md b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.License.md deleted file mode 100644 index d9f6ecd2..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.License.md +++ /dev/null @@ -1,23 +0,0 @@ - -The MIT License (MIT) - -Copyright (c) 2020 Kurai András -Copyright (c) 2022-Present VRChat Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.License.md.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.License.md.meta deleted file mode 100644 index 597bf25a..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.License.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 598e678340a8c6e4e9a3debcdc6a9579 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.dll b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.dll deleted file mode 100644 index eb78a0fe..00000000 Binary files a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.dll and /dev/null differ diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.dll.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.dll.meta deleted file mode 100644 index 932224a5..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.Unity3D.dll.meta +++ /dev/null @@ -1,33 +0,0 @@ -fileFormatVersion: 2 -guid: cfc1421f162f0354d8a64d569417d9c9 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 1 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - DefaultValueInitialized: true - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.dll b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.dll deleted file mode 100644 index dab49d2c..00000000 Binary files a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.dll and /dev/null differ diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.dll.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.dll.meta deleted file mode 100644 index 2ef53f97..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.dll.meta +++ /dev/null @@ -1,33 +0,0 @@ -fileFormatVersion: 2 -guid: 702a5a2579f8edf43b5e7bfb2f52e2c6 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.License.txt b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.License.txt deleted file mode 100644 index d4f29245..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.License.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Antoine Aubry and contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.License.txt.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.License.txt.meta deleted file mode 100644 index a8bc0bc1..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.License.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3547422b181c5af49901e93c1122bbdd -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.dll b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.dll deleted file mode 100644 index d0bbb751..00000000 Binary files a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.dll and /dev/null differ diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.dll.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.dll.meta deleted file mode 100644 index 4b5ebc37..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/YamlDotNet.dll.meta +++ /dev/null @@ -1,33 +0,0 @@ -fileFormatVersion: 2 -guid: 9fd667e0ec0d1d84c9e17dad407f2272 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/vpm-core-lib.dll b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/vpm-core-lib.dll deleted file mode 100644 index 3cbc8f9d..00000000 Binary files a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/vpm-core-lib.dll and /dev/null differ diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/vpm-core-lib.dll.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/vpm-core-lib.dll.meta deleted file mode 100644 index 71e73f6c..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/vpm-core-lib.dll.meta +++ /dev/null @@ -1,33 +0,0 @@ -fileFormatVersion: 2 -guid: 140aba2a5b760e94cb3ed9f39a52610a -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 1 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - DefaultValueInitialized: true - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindow.cs b/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindow.cs deleted file mode 100644 index 9bd83652..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindow.cs +++ /dev/null @@ -1,412 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text.RegularExpressions; -using UnityEditor; -using UnityEditor.UIElements; -using UnityEditor.VersionControl; -using UnityEngine; -using UnityEngine.UIElements; -using VRC.PackageManagement.Core.Types.Packages; -using YamlDotNet.Serialization.NodeTypeResolvers; - -namespace VRC.PackageManagement.PackageMaker -{ - public class PackageMakerWindow : EditorWindow - { - // VisualElements - private VisualElement _rootView; - private TextField _targetAssetFolderField; - private TextField _packageIDField; - private Button _actionButton; - private EnumField _targetVRCPackageField; - private static string _projectDir; - private PackageMakerWindowData _windowData; - - private void LoadDataFromSave() - { - if (!string.IsNullOrWhiteSpace(_windowData.targetAssetFolder)) - { - _targetAssetFolderField.SetValueWithoutNotify(_windowData.targetAssetFolder); - } - _packageIDField.SetValueWithoutNotify(_windowData.packageID); - _targetVRCPackageField.SetValueWithoutNotify(_windowData.relatedPackage); - - RefreshActionButtonState(); - } - - private void OnEnable() - { - _projectDir = Directory.GetParent(Application.dataPath).FullName; - Refresh(); - } - - [MenuItem("VRChat SDK/Utilities/Package Maker")] - public static void ShowWindow() - { - PackageMakerWindow wnd = GetWindow(); - wnd.titleContent = new GUIContent("Package Maker"); - } - - [MenuItem("Assets/Export VPM as UnityPackage")] - private static void ExportAsUnityPackage () - { - if (Selection.assetGUIDs.Length != 1) - { - Debug.LogWarning($"Cannot export selection, must be a single Folder."); - return; - } - - string selectedFolder = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]); - var manifestPath = Path.Combine(selectedFolder, VRCPackageManifest.Filename); - var manifest = VRCPackageManifest.GetManifestAtPath(manifestPath); - if (manifest == null) - { - Debug.LogWarning($"Could not read valid Package Manifest at {manifestPath}. You need to create this first."); - return; - } - - var exportDir = Path.Combine(Directory.GetCurrentDirectory(), "Exports"); - Directory.CreateDirectory(exportDir); - AssetDatabase.ExportPackage - ( - selectedFolder, - Path.Combine(exportDir, $"{manifest.Id}-{manifest.Version}.unitypackage"), - ExportPackageOptions.Recurse | ExportPackageOptions.Interactive - ); - } - - private void Refresh() - { - if (_windowData == null) - { - _windowData = PackageMakerWindowData.GetOrCreate(); - } - - if (_rootView == null) return; - - if (_windowData != null) - { - LoadDataFromSave(); - } - } - - private void RefreshActionButtonState() - { - _actionButton.SetEnabled( - StringIsValidAssetFolder(_windowData.targetAssetFolder) && - !string.IsNullOrWhiteSpace(_windowData.packageID) - ); - } - - /// - /// Unity calls the CreateGUI method automatically when the window needs to display - /// - private void CreateGUI() - { - if (_windowData == null) - { - _windowData = PackageMakerWindowData.GetOrCreate(); - } - - _rootView = rootVisualElement; - _rootView.name = "root-view"; - _rootView.styleSheets.Add((StyleSheet) Resources.Load("PackageMakerWindowStyle")); - - // Create Target Asset folder and register for drag and drop events - _rootView.Add(CreateTargetFolderElement()); - _rootView.Add(CreatePackageIDElement()); - _rootView.Add(CreateTargetVRCPackageElement()); - _rootView.Add(CreateActionButton()); - - Refresh(); - } - - public enum VRCPackageEnum - { - None = 0, - Worlds = 1, - Avatars = 2, - Base = 3, - UdonSharp = 4, - } - - private VisualElement CreateTargetVRCPackageElement() - { - _targetVRCPackageField = new EnumField("Related VRChat Package", VRCPackageEnum.None); - _targetVRCPackageField.RegisterValueChangedCallback(OnTargetVRCPackageChanged); - var box = new Box(); - box.Add(_targetVRCPackageField); - return box; - } - - private void OnTargetVRCPackageChanged(ChangeEvent evt) - { - _windowData.relatedPackage = (VRCPackageEnum)evt.newValue; - _windowData.Save(); - } - - private VisualElement CreateActionButton() - { - _actionButton = new Button(OnActionButtonPressed) - { - text = "Convert Assets to Package", - name = "action-button" - }; - return _actionButton; - } - - private void OnActionButtonPressed() - { - bool result = EditorUtility.DisplayDialog("One-Way Conversion", - $"This process will move the assets from {_windowData.targetAssetFolder} into a new Package with the id {_windowData.packageID} and give it references to {_windowData.relatedPackage}.", - "Ok", "Wait, not yet."); - if (result) - { - string newPackageFolderPath = Path.Combine(_projectDir, "Packages", _windowData.packageID); - Directory.CreateDirectory(newPackageFolderPath); - var fullTargetAssetFolder = Path.Combine(_projectDir, _windowData.targetAssetFolder); - DoMigration(fullTargetAssetFolder, newPackageFolderPath); - ForceRefresh(); - } - } - - public static void ForceRefresh () - { - MethodInfo method = typeof( UnityEditor.PackageManager.Client ).GetMethod( "Resolve", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.DeclaredOnly ); - if( method != null ) - method.Invoke( null, null ); - - AssetDatabase.Refresh(); - } - - private VisualElement CreatePackageIDElement() - { - var box = new Box() - { - name = "package-name-box" - }; - - _packageIDField = new TextField("Package ID", 255, false, false, '*'); - _packageIDField.RegisterValueChangedCallback(OnPackageIDChanged); - box.Add(_packageIDField); - - box.Add(new Label("Lowercase letters, numbers and dots only.") - { - name="description", - tooltip = "Standard practice is reverse domain notation like com.vrchat.packagename. Needs to be unique across VRChat, so if you don't own a domain you can try your username.", - }); - - return box; - } - - private Regex packageIdRegex = new Regex("[^a-z0-9.]"); - private void OnPackageIDChanged(ChangeEvent evt) - { - if (evt.newValue != null) - { - string newId = packageIdRegex.Replace(evt.newValue, "-"); - _packageIDField.SetValueWithoutNotify(newId); - _windowData.packageID = newId; - _windowData.Save(); - } - RefreshActionButtonState(); - } - - private VisualElement CreateTargetFolderElement() - { - var targetFolderBox = new Box() - { - name = "editor-target-box" - }; - - _targetAssetFolderField = new TextField("Target Folder"); - _targetAssetFolderField.RegisterCallback(OnTargetAssetFolderDragEnter, TrickleDown.TrickleDown); - _targetAssetFolderField.RegisterCallback(OnTargetAssetFolderDragLeave, TrickleDown.TrickleDown); - _targetAssetFolderField.RegisterCallback(OnTargetAssetFolderDragUpdated, TrickleDown.TrickleDown); - _targetAssetFolderField.RegisterCallback(OnTargetAssetFolderDragPerform, TrickleDown.TrickleDown); - _targetAssetFolderField.RegisterCallback(OnTargetAssetFolderDragExited, TrickleDown.TrickleDown); - _targetAssetFolderField.RegisterValueChangedCallback(OnTargetAssetFolderValueChanged); - targetFolderBox.Add(_targetAssetFolderField); - - targetFolderBox.Add(new Label("Drag and Drop an Assets Folder to Convert Above"){name="description"}); - return targetFolderBox; - } - - #region TargetAssetFolder Field Events - - private bool StringIsValidAssetFolder(string targetFolder) - { - return !string.IsNullOrWhiteSpace(targetFolder) && AssetDatabase.IsValidFolder(targetFolder); - } - - private void OnTargetAssetFolderValueChanged(ChangeEvent evt) - { - string targetFolder = evt.newValue; - - if (StringIsValidAssetFolder(targetFolder)) - { - _windowData.targetAssetFolder = evt.newValue; - _windowData.Save(); - RefreshActionButtonState(); - } - else - { - _targetAssetFolderField.SetValueWithoutNotify(evt.previousValue); - } - } - - private void OnTargetAssetFolderDragExited(DragExitedEvent evt) - { - DragAndDrop.visualMode = DragAndDropVisualMode.None; - } - - private void OnTargetAssetFolderDragPerform(DragPerformEvent evt) - { - var targetFolder = DragAndDrop.paths[0]; - if (!string.IsNullOrWhiteSpace(targetFolder) && AssetDatabase.IsValidFolder(targetFolder)) - { - _targetAssetFolderField.value = targetFolder; - } - else - { - Debug.LogError($"Could not accept {targetFolder}. Needs to be a folder within the project"); - } - } - - private void OnTargetAssetFolderDragUpdated(DragUpdatedEvent evt) - { - if (DragAndDrop.paths.Length == 1) - { - DragAndDrop.visualMode = DragAndDropVisualMode.Copy; - DragAndDrop.AcceptDrag(); - } - else - { - DragAndDrop.visualMode = DragAndDropVisualMode.Rejected; - } - } - - private void OnTargetAssetFolderDragLeave(DragLeaveEvent evt) - { - DragAndDrop.visualMode = DragAndDropVisualMode.None; - } - - private void OnTargetAssetFolderDragEnter(DragEnterEvent evt) - { - if (DragAndDrop.paths.Length == 1) - { - DragAndDrop.visualMode = DragAndDropVisualMode.Copy; - DragAndDrop.AcceptDrag(); - } - } - - #endregion - - #region Migration Logic - - private void DoMigration(string corePath, string targetDir) - { - - EditorUtility.DisplayProgressBar("Migrating Package", "Creating Starter Package", 0.1f); - - // Convert PackageType enum to VRC Package ID string - string packageType = null; - switch (_windowData.relatedPackage) - { - case VRCPackageEnum.Avatars: - packageType = "com.vrchat.avatars"; - break; - case VRCPackageEnum.Base: - packageType = "com.vrchat.base"; - break; - case VRCPackageEnum.Worlds: - packageType = "com.vrchat.clientsim"; // we want ClientSim too, need to specify that for now - break; - case VRCPackageEnum.UdonSharp: - packageType = "com.vrchat.udonsharp"; - break; - } - - string parentDir = new DirectoryInfo(targetDir)?.Parent.FullName; - Core.Utilities.CreateStarterPackage(_windowData.packageID, parentDir, packageType); - var allFiles = GetAllFiles(corePath).ToList(); - MoveFilesToPackageDir(allFiles, corePath, targetDir); - - // Clear target asset folder since it should no longer exist - _windowData.targetAssetFolder = ""; - - } - - private static IEnumerable GetAllFiles(string path) - { - var excludedPaths = new List() - { - "Editor.meta" - }; - return Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories) - .Where( - s => excludedPaths.All(entry => !s.Contains(entry)) - ); - } - - public static void MoveFilesToPackageDir(List files, string pathBase, string targetDir) - { - EditorUtility.DisplayProgressBar("Migrating Package", "Moving Package Files", 0f); - float totalFiles = files.Count; - - for (int i = 0; i < files.Count; i++) - { - try - { - EditorUtility.DisplayProgressBar("Migrating Package", "Moving Package Files", i / totalFiles); - var file = files[i]; - string simplifiedPath = file.Replace($"{pathBase}\\", ""); - - string dest = null; - if (simplifiedPath.Contains("Editor\\")) - { - // Remove extra 'Editor' subfolders - dest = simplifiedPath.Replace("Editor\\", ""); - dest = Path.Combine(targetDir, "Editor", dest); - } - else - { - // Make complete path to Runtime folder - dest = Path.Combine(targetDir, "Runtime", simplifiedPath); - } - - string targetEnclosingDir = Path.GetDirectoryName(dest); - Directory.CreateDirectory(targetEnclosingDir); - var sourceFile = Path.Combine(pathBase, simplifiedPath); - File.Move(sourceFile, dest); - } - catch (Exception e) - { - Debug.LogError($"Error moving {files[i]}: {e.Message}"); - continue; - } - } - - Directory.Delete(pathBase, true); // cleans up leftover folders since only files are moved - EditorUtility.ClearProgressBar(); - } - - // Important while we're doing copy-and-rename in order to rename paths with "Assets" without renaming paths with "Sample Assets" - public static string ReplaceFirst(string text, string search, string replace) - { - int pos = text.IndexOf(search); - if (pos < 0) - { - return text; - } - - return text.Substring(0, pos) + replace + text.Substring(pos + search.Length); - } - - #endregion - } - -} \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindowData.cs b/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindowData.cs deleted file mode 100644 index ee580b7c..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindowData.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.IO; -using UnityEditor; -using UnityEngine; -using VRC.PackageManagement.PackageMaker; - -public class PackageMakerWindowData : ScriptableObject -{ - public static string defaultAssetPath = Path.Combine("Assets", "PackageMakerWindowData.asset"); - public string targetAssetFolder; - public string packageID; - public PackageMakerWindow.VRCPackageEnum relatedPackage; - - public static PackageMakerWindowData GetOrCreate() - { - var existingData = AssetDatabase.AssetPathToGUID(defaultAssetPath); - if (string.IsNullOrWhiteSpace(existingData)) - { - return Create(); - } - else - { - var saveData = AssetDatabase.LoadAssetAtPath(defaultAssetPath); - if (saveData == null) - { - Debug.LogError($"Could not load saved data but the save file exists. Resetting."); - return Create(); - } - return saveData; - } - } - - public static PackageMakerWindowData Create() - { - var saveData = CreateInstance(); - AssetDatabase.CreateAsset(saveData, defaultAssetPath); - AssetDatabase.SaveAssets(); - return saveData; - } - - public void Save() - { - AssetDatabase.SaveAssets(); - } -} diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/Resolver.cs b/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/Resolver.cs deleted file mode 100644 index cb1822e7..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/Resolver.cs +++ /dev/null @@ -1,199 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using Serilog; -using Serilog.Sinks.Unity3D; -using UnityEditor; -using UnityEngine; -using VRC.PackageManagement.Core; -using VRC.PackageManagement.Core.Types; -using VRC.PackageManagement.Core.Types.Packages; - -namespace VRC.PackageManagement.Resolver -{ - - [InitializeOnLoad] - public class Resolver - { - private const string _projectLoadedKey = "PROJECT_LOADED"; - - private static string _projectDir; - public static string ProjectDir - { - get - { - if (_projectDir != null) - { - return _projectDir; - } - - try - { - _projectDir = new DirectoryInfo(Assembly.GetExecutingAssembly().Location).Parent.Parent.Parent - .FullName; - return _projectDir; - } - catch (Exception) - { - return ""; - } - } - } - - static Resolver() - { - SetupLogging(); - if (!SessionState.GetBool(_projectLoadedKey, false)) - { -#pragma warning disable 4014 - CheckResolveNeeded(); -#pragma warning restore 4014 - } - } - - private static void SetupLogging() - { - VRCLibLogger.SetLoggerDirectly( - new LoggerConfiguration() - .MinimumLevel.Information() - .WriteTo.Unity3D() - .CreateLogger() - ); - } - - private static async Task CheckResolveNeeded() - { - SessionState.SetBool(_projectLoadedKey, true); - - //Wait for project to finish compiling - while (EditorApplication.isCompiling || EditorApplication.isUpdating) - { - await Task.Delay(250); - } - - try - { - - if (string.IsNullOrWhiteSpace(ProjectDir)) - { - return; - } - - if (VPMProjectManifest.ResolveIsNeeded(ProjectDir)) - { - Debug.Log($"Resolve needed."); - var result = EditorUtility.DisplayDialog("VRChat Package Management", - $"This project requires some VRChat Packages which are not in the project yet.\n\nPress OK to download and install them.", - "OK", "Show Me What's Missing"); - if (result) - { - ResolveStatic(ProjectDir); - } - else - { - ResolverWindow.ShowWindow(); - } - } - } - catch (Exception) - { - // Unity says we can't open windows from this function so it throws an exception but also works fine. - } - } - - public static bool VPMManifestExists() - { - return VPMProjectManifest.Exists(ProjectDir, out _); - } - - public static void CreateManifest() - { - VPMProjectManifest.Load(ProjectDir); - ResolverWindow.Refresh(); - } - - public static void ResolveManifest() - { - ResolveStatic(ProjectDir); - } - - public static void ResolveStatic(string dir) - { - // Todo: calculate and show actual progress - EditorUtility.DisplayProgressBar($"Getting all VRChat Packages", "Downloading and Installing...", 0.5f); - VPMProjectManifest.Resolve(ProjectDir); - EditorUtility.ClearProgressBar(); - ForceRefresh(); - } - - public static List GetAllVersionsOf(string id) - { - var project = new UnityProject(ProjectDir); - - var versions = new List(); - foreach (var provider in Repos.GetAll) - { - var packagesWithVersions = provider.GetAllWithVersions(); - - foreach (var packageVersionList in packagesWithVersions) - { - foreach (var package in packageVersionList.Value.VersionsDescending) - { - if (package.Id != id) - continue; - if (Version.TryParse(package.Version, out var result)) - { - if (!versions.Contains(package.Version)) - versions.Add(package.Version); - } - } - } - } - - // Sort packages in project to the top - var sorted = from entry in versions orderby project.VPMProvider.HasPackage(entry) descending select entry; - - return sorted.ToList(); - } - - public static List GetAffectedPackageList(IVRCPackage package) - { - List list = new List(); - - var project = new UnityProject(ProjectDir); - - if (Repos.GetAllDependencies(package, out Dictionary dependencies, null)) - { - foreach (KeyValuePair item in dependencies) - { - project.VPMProvider.Refresh(); - if (project.VPMProvider.GetPackage(item.Key, item.Value) == null) - { - IVRCPackage d = Repos.GetPackageWithVersionMatch(item.Key, item.Value); - if (d != null) - { - list.Add(d.Id + " " + d.Version + "\n"); - } - } - } - - return list; - } - - return null; - } - - public static void ForceRefresh () - { - MethodInfo method = typeof( UnityEditor.PackageManager.Client ).GetMethod( "Resolve", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.DeclaredOnly ); - if( method != null ) - method.Invoke( null, null ); - - AssetDatabase.Refresh(); - } - - } -} \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/Resolver.cs.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/Resolver.cs.meta deleted file mode 100644 index a5403403..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/Resolver.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: f872e3586f8b4f06bab3c9facd14f6e6 -timeCreated: 1659048476 \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/ResolverWindow.cs b/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/ResolverWindow.cs deleted file mode 100644 index fad3f543..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/ResolverWindow.cs +++ /dev/null @@ -1,292 +0,0 @@ -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using UnityEditor; -using UnityEditor.UIElements; -using UnityEngine; -using UnityEngine.UIElements; -using VRC.PackageManagement.Core; -using VRC.PackageManagement.Core.Types; -using VRC.PackageManagement.Core.Types.Packages; -using Version = VRC.PackageManagement.Core.Types.VPMVersion.Version; - -namespace VRC.PackageManagement.Resolver -{ - public class ResolverWindow : EditorWindow - { - // VisualElements - private static VisualElement _rootView; - private static Button _refreshButton; - private static Button _createButton; - private static Button _resolveButton; - private static Box _manifestInfo; - private static Label _manifestLabel; - private static bool _isUpdating; - private static Color _colorPositive = Color.green; - private static Color _colorNegative = new Color(1, 0.3f, 0.3f); - - - [MenuItem("VRChat SDK/Utilities/Package Resolver")] - public static void ShowWindow() - { - ResolverWindow wnd = GetWindow(); - wnd.titleContent = new GUIContent("Package Resolver"); - } - - public static void Refresh() - { - if (_rootView == null || string.IsNullOrWhiteSpace(Resolver.ProjectDir)) return; - - _manifestInfo.SetEnabled(!_isUpdating); - _refreshButton.SetEnabled(!_isUpdating); - _manifestLabel.text = (_isUpdating ? "Working ..." : "Required Packages"); - _manifestInfo.Clear(); - _manifestInfo.Add(_manifestLabel); - - bool needsResolve = VPMProjectManifest.ResolveIsNeeded(Resolver.ProjectDir); - string resolveStatus = needsResolve ? "Please press \"Resolve\" to Download them." : "All of them are in the project."; - - // check for vpm dependencies - if (!Resolver.VPMManifestExists()) - { - TextElement noManifestText = new TextElement(); - noManifestText.text = "No VPM Manifest"; - noManifestText.style.color = _colorNegative; - _manifestInfo.Add(noManifestText); - } - else - { - var manifest = VPMProjectManifest.Load(Resolver.ProjectDir); - var project = new UnityProject(Resolver.ProjectDir); - - // Here is where we detect if all dependencies are installed - var allDependencies = (manifest.locked != null && manifest.locked.Count > 0) - ? manifest.locked - : manifest.dependencies; - - foreach (var pair in allDependencies) - { - var id = pair.Key; - var version = pair.Value.version; - IVRCPackage package = project.VPMProvider.GetPackage(id, version); - _manifestInfo.Add(CreateDependencyRow(id, version, project, (package != null))); - } - - } - _resolveButton.SetEnabled(needsResolve); - Resolver.ForceRefresh(); - } - - /// - /// Unity calls the CreateGUI method automatically when the window needs to display - /// - private void CreateGUI() - { - _rootView = rootVisualElement; - _rootView.name = "root-view"; - _rootView.styleSheets.Add((StyleSheet)Resources.Load("ResolverWindowStyle")); - - // Main Container - var container = new Box() - { - name = "buttons" - }; - _rootView.Add(container); - - // Create Button - if (!Resolver.VPMManifestExists()) - { - _createButton = new Button(Resolver.CreateManifest) - { - text = "Create", - name = "create-button-base" - }; - container.Add(_createButton); - } - else - { - _resolveButton = new Button(Resolver.ResolveManifest) - { - text = "Resolve All", - name = "resolve-button-base" - }; - container.Add(_resolveButton); - } - - // Manifest Info - _manifestInfo = new Box() - { - name = "manifest-info", - }; - _manifestLabel = (new Label("Required Packages") { name = "manifest-header" }); - - _rootView.Add(_manifestInfo); - - // Refresh Button - var refreshBox = new Box(); - _refreshButton = new Button(Refresh) - { - text = "Refresh", - name = "refresh-button-base" - }; - refreshBox.Add(_refreshButton); - _rootView.Add(refreshBox); - - Refresh(); - } - - private static VisualElement CreateDependencyRow(string id, string version, UnityProject project, bool havePackage) - { - // Table - - VisualElement row = new Box() { name = "package-box" }; - VisualElement column1 = new Box() { name = "package-box" }; - VisualElement column2 = new Box() { name = "package-box" }; - VisualElement column3 = new Box() { name = "package-box" }; - VisualElement column4 = new Box() { name = "package-box" }; - - column1.style.minWidth = 200; - column2.style.minWidth = 100; - column3.style.minWidth = 100; - column4.style.minWidth = 100; - - row.Add(column1); - row.Add(column2); - row.Add(column3); - row.Add(column4); - - // Package Name + Status - - TextElement text = new TextElement { text = $"{id} {version} " }; - - column1.Add(text); - - if (!havePackage) - { - TextElement missingText = new TextElement { text = "MISSING" }; - missingText.style.color = _colorNegative; - missingText.style.display = (_isUpdating ? DisplayStyle.None : DisplayStyle.Flex); - column2.Add(missingText); - } - - // Version Popup - - var choices = new List(); - foreach (string n in Resolver.GetAllVersionsOf(id)) - { - choices.Add(n); - } - - var popupField = new PopupField(choices, 0); - popupField.value = choices[0]; - popupField.style.display = (_isUpdating ? DisplayStyle.None : DisplayStyle.Flex); - - column3.Add(popupField); - - // Button - - Button updateButton = new Button() { text = "Update" }; - if (havePackage) - RefreshUpdateButton(updateButton, version, choices[0]); - else - RefreshMissingButton(updateButton); - - updateButton.clicked += (() => - { - IVRCPackage package = Repos.GetPackageWithVersionMatch(id, popupField.value); - - // Check and warn on Dependencies if Updating or Downgrading - if (Version.TryParse(version, out var currentVersion) && - Version.TryParse(popupField.value, out var newVersion)) - { - Dictionary dependencies = new Dictionary(); - StringBuilder dialogMsg = new StringBuilder(); - List affectedPackages = Resolver.GetAffectedPackageList(package); - for (int v = 0; v < affectedPackages.Count; v++) - { - dialogMsg.Append(affectedPackages[v]); - } - - if (affectedPackages.Count > 1) - { - dialogMsg.Insert(0, "This will update multiple packages:\n\n"); - dialogMsg.AppendLine("\nAre you sure?"); - if (EditorUtility.DisplayDialog("Package Has Dependencies", dialogMsg.ToString(), "OK", "Cancel")) - OnUpdatePackageClicked(project, package); - } - else - { - OnUpdatePackageClicked(project, package); - } - } - - }); - column4.Add(updateButton); - - popupField.RegisterCallback>((evt) => - { - if (havePackage) - RefreshUpdateButton(updateButton, version, evt.newValue); - else - RefreshMissingButton(updateButton); - }); - - return row; - } - - private static void RefreshUpdateButton(Button button, string currentVersion, string highestAvailableVersion) - { - if (currentVersion == highestAvailableVersion) - { - button.style.display = DisplayStyle.None; - } - else - { - button.style.display = (_isUpdating ? DisplayStyle.None : DisplayStyle.Flex); - if (Version.TryParse(currentVersion, out var currentVersionObject) && - Version.TryParse(highestAvailableVersion, out var highestAvailableVersionObject)) - { - if (currentVersionObject < highestAvailableVersionObject) - { - SetButtonColor(button, _colorPositive); - button.text = "Update"; - } - else - { - SetButtonColor(button, _colorNegative); - button.text = "Downgrade"; - } - } - } - } - - private static void RefreshMissingButton(Button button) - { - button.text = "Resolve"; - SetButtonColor(button, Color.white); - button.style.display = (_isUpdating ? DisplayStyle.None : DisplayStyle.Flex); - } - - private static void SetButtonColor(Button button, Color color) - { - button.style.color = color; - color.a = 0.25f; - button.style.borderRightColor = - button.style.borderLeftColor = - button.style.borderTopColor = - button.style.borderBottomColor = - color; - } - - private static async void OnUpdatePackageClicked(UnityProject project, IVRCPackage package) - { - _isUpdating = true; - Refresh(); - await Task.Delay(500); - await Task.Run(() => project.UpdateVPMPackage(package)); - _isUpdating = false; - Refresh(); - } - - } -} \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources.meta b/Packages/com.vrchat.core.vpm-resolver/Editor/Resources.meta deleted file mode 100644 index 44742999..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 8700b619eebc09545b4aaf4f69a2bf79 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/PackageMakerWindowStyle.uss b/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/PackageMakerWindowStyle.uss deleted file mode 100644 index 14ce0e79..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/PackageMakerWindowStyle.uss +++ /dev/null @@ -1,16 +0,0 @@ -.unity-box { - margin: 10px; - padding:10px; -} - -.unity-box #description { - margin: 10px 0 10px 0; - white-space: normal; -} - -#action-button { - font-size: 20px; - -unity-font-style: bold; - padding: 10px; - margin:10px; -} \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/ResolverWindowStyle.uss b/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/ResolverWindowStyle.uss deleted file mode 100644 index 443e2e96..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/ResolverWindowStyle.uss +++ /dev/null @@ -1,25 +0,0 @@ -.unity-box { - margin:2px; - padding:10px; - border-width:0px; -} - -#package-box { - margin:2px; - padding:10px; - border-width:0px; - flex-direction:row; - max-height:20px; - min-height:20px; - height:20px; - padding-top:0px; - padding-bottom:0px; - margin-top:0px; - margin-bottom:0px; - align-items:center; -} - -#manifest-header { - font-size: 20px; - margin-bottom: 10px; -} \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/com.vrchat.core.vpm-resolver.Editor.asmdef b/Packages/com.vrchat.core.vpm-resolver/Editor/com.vrchat.core.vpm-resolver.Editor.asmdef deleted file mode 100644 index 2dd9d946..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/com.vrchat.core.vpm-resolver.Editor.asmdef +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "com.vrchat.core.vpm-resolver.Editor", - "references": [], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/License.md b/Packages/com.vrchat.core.vpm-resolver/License.md deleted file mode 100644 index 275530cd..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/License.md +++ /dev/null @@ -1,11 +0,0 @@ -# VRCHAT INC. -### VRCHAT DISTRO LICENSE FILE -Version: February 24, 2022 - -**SUMMARY OF TERMS:** Any materials subject to this Distro Asset License may be distributed by you, with or without modifications, on a non-commercial basis (i.e., at no charge), in accordance with the full terms of the Materials License Agreement. - -This Distro License File is a "License File" as defined in the VRChat Materials License Agreement, found at https://hello.vrchat.com/legal/sdk (or any successor link designated by VRChat) (as may be revised from time to time, the "Materials License Agreement"). - -This Distro License File applies to all the files in the Folder containing this Distro License File and those in all Child Folders within that Folder (except with respect to files in any Child Folder that contains a different License File) (such files, other than this Distro License File, the "Covered Files"). All capitalized terms used but not otherwise defined in this Distro License File have the meanings provided in the Materials License Agreement. - -This Distro License File only provides a summary of the terms applicable to the Covered Files. To understand your rights and obligations and the full set of terms that apply to use of the Covered Files, please see the relevant sections of the Materials License Agreement, including terms applicable to Distro Materials. \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/License.md.meta b/Packages/com.vrchat.core.vpm-resolver/License.md.meta deleted file mode 100644 index 20b97519..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/License.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 7727f888edf4714448d5a0287deec6dd -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/package.json b/Packages/com.vrchat.core.vpm-resolver/package.json deleted file mode 100644 index 19f862e8..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name" : "com.vrchat.core.vpm-resolver", - "displayName" : "VRChat Package Resolver Tool", - "version" : "0.1.17", - "unity" : "2019.4", - "description" : "Tool to Download VPM Packages", - "vrchatVersion" : "2022.1.1", - "author" : { - "name" : "VRChat", - "email" : "developer@vrchat.com", - "url" : "https://github.com/vrchat/packages" - }, - "url" : "", - "dependencies" : { - "com.unity.nuget.newtonsoft-json" : "2.0.2" - } -} diff --git a/Packages/com.vrchat.core.vpm-resolver/package.json.meta b/Packages/com.vrchat.core.vpm-resolver/package.json.meta deleted file mode 100644 index b3235851..00000000 --- a/Packages/com.vrchat.core.vpm-resolver/package.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6b02e2915ebf04e4ea94e503d73e7411 -PackageManifestImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/manifest.json b/Packages/manifest.json old mode 100644 new mode 100755 index f207657a..7e838b83 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -2,16 +2,20 @@ "dependencies": { "at.pimaker.ltcgi": "https://github.com/PiMaker/ltcgi.git", "com.singularitygroup.hotreload": "git+https://gitlab.hotreload.net/root/hot-reload-releases.git#1.12.8", - "com.unity.ide.rider": "3.0.24", - "com.unity.ide.visualstudio": "2.0.20", - "com.unity.ide.vscode": "1.2.4", - "com.unity.postprocessing": "3.1.1", - "com.unity.test-framework": "1.1.29", - "com.unity.textmeshpro": "2.1.6", - "com.unity.timeline": "1.2.18", + "com.unity.2d.psdimporter": "8.0.5", + "com.unity.ai.navigation": "1.1.5", + "com.unity.ide.rider": "3.0.28", + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.ide.vscode": "1.2.5", + "com.unity.postprocessing": "3.4.0", + "com.unity.render-pipelines.core": "14.0.10", + "com.unity.render-pipelines.universal": "14.0.10", + "com.unity.test-framework": "1.1.33", + "com.unity.textmeshpro": "3.0.6", + "com.unity.timeline": "1.7.6", "com.unity.ugui": "1.0.0", - "com.unity.xr.oculus.standalone": "2.38.4", - "com.unity.xr.openvr.standalone": "2.0.5", + "com.unity.xr.management": "4.4.1", + "com.unity.xr.mock-hmd": "1.4.0-preview.2", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json old mode 100644 new mode 100755 index 112d1891..c03593eb --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -23,6 +23,78 @@ }, "hash": "ff60e352632357969bf3ff54ce63c8c4ba171566" }, + "com.unity.2d.animation": { + "version": "9.1.1", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.2d.common": "8.0.2", + "com.unity.2d.sprite": "1.0.0", + "com.unity.collections": "1.1.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.uielements": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.2d.common": { + "version": "8.0.2", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.7.3", + "com.unity.2d.sprite": "1.0.0", + "com.unity.mathematics": "1.1.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.uielements": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.2d.psdimporter": { + "version": "8.0.5", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.2d.common": "8.0.2", + "com.unity.2d.sprite": "1.0.0", + "com.unity.2d.animation": "9.1.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.2d.sprite": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.ai.navigation": { + "version": "1.1.5", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.ai": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.burst": { + "version": "1.8.12", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.mathematics": "1.2.1", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.collections": { + "version": "1.2.4", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.6.6", + "com.unity.test-framework": "1.1.31" + }, + "url": "https://packages.unity.com" + }, "com.unity.ext.nunit": { "version": "1.0.6", "depth": 1, @@ -31,7 +103,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.rider": { - "version": "3.0.24", + "version": "3.0.28", "depth": 0, "source": "registry", "dependencies": { @@ -40,7 +112,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.20", + "version": "2.0.22", "depth": 0, "source": "registry", "dependencies": { @@ -49,21 +121,28 @@ "url": "https://packages.unity.com" }, "com.unity.ide.vscode": { - "version": "1.2.4", + "version": "1.2.5", "depth": 0, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, + "com.unity.mathematics": { + "version": "1.2.6", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, "com.unity.nuget.newtonsoft-json": { - "version": "2.0.2", + "version": "3.2.1", "depth": 1, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.postprocessing": { - "version": "3.1.1", + "version": "3.4.0", "depth": 0, "source": "registry", "dependencies": { @@ -71,8 +150,55 @@ }, "url": "https://packages.unity.com" }, + "com.unity.render-pipelines.core": { + "version": "14.0.10", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.render-pipelines.universal": { + "version": "14.0.10", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.mathematics": "1.2.1", + "com.unity.burst": "1.8.9", + "com.unity.render-pipelines.core": "14.0.10", + "com.unity.shadergraph": "14.0.10", + "com.unity.render-pipelines.universal-config": "14.0.9" + } + }, + "com.unity.render-pipelines.universal-config": { + "version": "14.0.9", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "14.0.9" + } + }, + "com.unity.searcher": { + "version": "4.9.2", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.shadergraph": { + "version": "14.0.10", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "14.0.10", + "com.unity.searcher": "4.9.2" + } + }, "com.unity.test-framework": { - "version": "1.1.29", + "version": "1.1.33", "depth": 0, "source": "registry", "dependencies": { @@ -83,7 +209,7 @@ "url": "https://packages.unity.com" }, "com.unity.textmeshpro": { - "version": "2.1.6", + "version": "3.0.6", "depth": 0, "source": "registry", "dependencies": { @@ -92,13 +218,13 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.2.18", + "version": "1.7.6", "depth": 0, "source": "registry", "dependencies": { + "com.unity.modules.audio": "1.0.0", "com.unity.modules.director": "1.0.0", "com.unity.modules.animation": "1.0.0", - "com.unity.modules.audio": "1.0.0", "com.unity.modules.particlesystem": "1.0.0" }, "url": "https://packages.unity.com" @@ -112,35 +238,36 @@ "com.unity.modules.imgui": "1.0.0" } }, - "com.unity.xr.oculus.standalone": { - "version": "2.38.4", - "depth": 0, + "com.unity.xr.legacyinputhelpers": { + "version": "2.1.10", + "depth": 1, "source": "registry", - "dependencies": {}, + "dependencies": { + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.xr": "1.0.0" + }, "url": "https://packages.unity.com" }, - "com.unity.xr.openvr.standalone": { - "version": "2.0.5", + "com.unity.xr.management": { + "version": "4.4.1", "depth": 0, "source": "registry", - "dependencies": {}, - "url": "https://packages.unity.com" - }, - "com.vrchat.core.bootstrap": { - "version": "file:com.vrchat.core.bootstrap", - "depth": 0, - "source": "embedded", "dependencies": { - "com.unity.nuget.newtonsoft-json": "2.0.2" - } + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.xr": "1.0.0", + "com.unity.modules.subsystems": "1.0.0", + "com.unity.xr.legacyinputhelpers": "2.1.7" + }, + "url": "https://packages.unity.com" }, - "com.vrchat.core.vpm-resolver": { - "version": "file:com.vrchat.core.vpm-resolver", + "com.unity.xr.mock-hmd": { + "version": "1.4.0-preview.2", "depth": 0, - "source": "embedded", + "source": "registry", "dependencies": { - "com.unity.nuget.newtonsoft-json": "2.0.2" - } + "com.unity.xr.management": "4.0.1" + }, + "url": "https://packages.unity.com" }, "sh.orels.shaders": { "version": "file:sh.orels.shaders", @@ -295,6 +422,7 @@ "depth": 0, "source": "builtin", "dependencies": { + "com.unity.modules.ui": "1.0.0", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" } diff --git a/Packages/sh.orels.shaders.generator/Editor/ConfiguredShaderDefinitionImporter.cs b/Packages/sh.orels.shaders.generator/Editor/ConfiguredShaderDefinitionImporter.cs index 219a3fed..7557adb4 100644 --- a/Packages/sh.orels.shaders.generator/Editor/ConfiguredShaderDefinitionImporter.cs +++ b/Packages/sh.orels.shaders.generator/Editor/ConfiguredShaderDefinitionImporter.cs @@ -2,6 +2,9 @@ using System.Collections.Generic; using System.IO; using System.Text; +using UnityEditor; +using UnityEngine; + #if UNITY_2022_3_OR_NEWER using UnityEditor.AssetImporters; #else @@ -11,7 +14,7 @@ namespace ORL.ShaderGenerator { [ScriptedImporter(1, "orlconfshader")] - public class ConfiguredShaderDefinitionImporter: ShaderDefinitionImporter + public class ConfiguredShaderDefinitionImporter : ShaderDefinitionImporter { public string shaderName = "Configurable/NewShader"; public string lightingModel; @@ -20,25 +23,62 @@ public class ConfiguredShaderDefinitionImporter: ShaderDefinitionImporter { "@/Modules/BaseColor" }; - + + public List customModuleFlags = new List + { + false + }; + + public string lastGeneratedContent; + public long lastGeneratedTime; + public bool skipGeneration; + public override void OnImportAsset(AssetImportContext ctx) + { + var finalCode = GetGeneratedContents(this); + + var currentFileContent = File.ReadAllText(ctx.assetPath); + + // Shader wasn't generated by us, flag it as modified + var lastUpdated = File.GetLastWriteTime(ctx.assetPath); + // check if explicitly skipping or if the shader was modified with more than 1 second difference + if (skipGeneration || ((lastUpdated.Ticks - lastGeneratedTime) > TimeSpan.FromSeconds(1).Ticks)) + { + base.OnImportAsset(ctx); + return; + } + + // Otherwise - overwrite the file if it was modified + if (!finalCode.Equals(currentFileContent, StringComparison.InvariantCulture)) + { + File.WriteAllText(ctx.assetPath, finalCode); + } + + base.OnImportAsset(ctx); + } + + public static string GetGeneratedContents(ConfiguredShaderDefinitionImporter importer) { var generated = new StringBuilder(); - generated.AppendLine($@"%ShaderName(""{shaderName}"")"); - if (!string.IsNullOrWhiteSpace(lightingModel) && string.IsNullOrWhiteSpace(baseShader)) + generated.AppendLine(@"// This file is automatically generated from the configuration defined in the UI"); + generated.AppendLine(@"// It is not recommended to edit this file manually"); + generated.AppendLine(@"// If a manual edit is detected - it will no longer be adjustable via the UI"); + generated.AppendLine(@"// You can use a force reset button in the UI to reset the file to the original state"); + generated.AppendLine($@"%ShaderName(""{importer.shaderName}"")"); + if (!string.IsNullOrWhiteSpace(importer.lightingModel) && string.IsNullOrWhiteSpace(importer.baseShader)) { - generated.AppendLine($@"%LightingModel(""{lightingModel}"")"); + generated.AppendLine($@"%LightingModel(""{importer.lightingModel}"")"); } generated.AppendLine(@"%CustomEditor(""ORL.ShaderInspector.InspectorGUI"")"); generated.AppendLine(); generated.AppendLine("%Includes()"); generated.AppendLine("{"); - if (!string.IsNullOrWhiteSpace(baseShader)) + if (!string.IsNullOrWhiteSpace(importer.baseShader)) { - generated.AppendLine($@" ""{baseShader}"","); + generated.AppendLine($@" ""{importer.baseShader}"","); } - foreach (var module in modules) + foreach (var module in importer.modules) { generated.AppendLine($@" ""{module}"","); } @@ -46,12 +86,7 @@ public override void OnImportAsset(AssetImportContext ctx) generated.AppendLine(@" ""self"""); generated.AppendLine("}"); - var finalCode = generated.ToString(); - if (!finalCode.Equals(File.ReadAllText(ctx.assetPath), StringComparison.InvariantCulture)) - { - File.WriteAllText(ctx.assetPath, finalCode); - } - base.OnImportAsset(ctx); + return generated.ToString(); } } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Editor/ConfiguredShaderDefinitionImporterEditor.cs b/Packages/sh.orels.shaders.generator/Editor/ConfiguredShaderDefinitionImporterEditor.cs index b36db218..66d0ade1 100644 --- a/Packages/sh.orels.shaders.generator/Editor/ConfiguredShaderDefinitionImporterEditor.cs +++ b/Packages/sh.orels.shaders.generator/Editor/ConfiguredShaderDefinitionImporterEditor.cs @@ -1,11 +1,15 @@ using System.Collections.Generic; using System.IO; -using System.Text; -using NUnit.Framework; using UnityEditor; using UnityEditorInternal; -using UnityEditor.Experimental.AssetImporters; using UnityEngine; +using System; +using System.Reflection; +#if UNITY_2022_3_OR_NEWER +using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif namespace ORL.ShaderGenerator { @@ -17,114 +21,169 @@ public class ConfiguredShaderDefinitionImporterEditor : ShaderDefinitionImporter private List _builtInModules = new List(); private Dictionary reorderableLists; + private MethodInfo _assetHasIssuesCall; + public override void OnEnable() { reorderableLists = new Dictionary(10); ScanForBuiltInAssets(); + _firstPass = true; + _assetHasIssuesCall = typeof(AssetImporterEditor).GetMethod("AssetHasIssues", BindingFlags.Instance | BindingFlags.NonPublic); base.OnEnable(); } + private bool _firstPass; + public override void OnInspectorGUI() { - EditorGUILayout.PropertyField(serializedObject.FindProperty("shaderName")); - - EditorGUILayout.Space(2); - + var t = (ConfiguredShaderDefinitionImporter)target; + var assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(target)).Replace("\\", "/"); + + var assetHasIssues = (bool)_assetHasIssuesCall.Invoke(this, null); + + var generatedContent = assetHasIssues ? "" : ConfiguredShaderDefinitionImporter.GetGeneratedContents(t); + var actualContent = File.ReadAllText(AssetDatabase.GetAssetPath(target)); + var hasContentDiverged = !assetHasIssues && !generatedContent.Equals(actualContent, StringComparison.InvariantCultureIgnoreCase) && !HasModified(); + var baseShaderValue = serializedObject.FindProperty("baseShader").stringValue.Replace("@/Shaders/", string.Empty); var hasBaseShader = !string.IsNullOrWhiteSpace(baseShaderValue) && baseShaderValue != "None"; - var lmValue = serializedObject.FindProperty("lightingModel").stringValue - .Replace("@/LightingModels/", string.Empty); - - if (!hasBaseShader) + // If there are no active modifications waiting to apply (which would cause a desyng) + // And the content of the file doesn't match the supposed generated content + // Show a warning with a reset button + if (hasContentDiverged) { - var currLMIndex = _builtInLMs.IndexOf(lmValue); - if (currLMIndex == -1) + EditorGUILayout.HelpBox("The shader definition file contains manual edits. You can use the force reset button to reset the shader to the state defined by the configuration below.", MessageType.Warning); + if (GUILayout.Button("Force Reset")) { - currLMIndex = 0; + File.WriteAllText(AssetDatabase.GetAssetPath(target), generatedContent); + serializedObject.FindProperty("skipGeneration").boolValue = false; + serializedObject.FindProperty("lastGeneratedTime").longValue = DateTime.Now.Ticks; + serializedObject.FindProperty("lastGeneratedContent").stringValue = generatedContent; + t.SaveAndReimport(); } - - serializedObject.FindProperty("lightingModel").stringValue = - $"@/LightingModels/{_builtInLMs[EditorGUILayout.Popup("Lighting Model", currLMIndex, _builtInLMs.ToArray())]}"; + EditorGUILayout.Space(10); } - var currShaderIndex = _builtInShaders.IndexOf(baseShaderValue); - if (currShaderIndex == -1) + using (new EditorGUI.DisabledScope(hasContentDiverged)) { - currShaderIndex = 0; - } + EditorGUILayout.PropertyField(serializedObject.FindProperty("shaderName")); + EditorGUILayout.Space(2); - var newBaseShader = - _builtInShaders[EditorGUILayout.Popup("Base Shader", currShaderIndex, _builtInShaders.ToArray())]; - if (newBaseShader.Equals("None")) - { - serializedObject.FindProperty("baseShader").stringValue = null; - } - else - { - serializedObject.FindProperty("baseShader").stringValue = $"@/Shaders/{newBaseShader}"; - } + var lmValue = serializedObject.FindProperty("lightingModel").stringValue + .Replace("@/LightingModels/", string.Empty); - EditorGUILayout.Space(5); - - var modulesProp = serializedObject.FindProperty("modules"); - var modulesListData = GetReorderableList(modulesProp); - modulesListData.modules = _builtInModules; - modulesListData.List.DoLayoutList(); + if (!hasBaseShader) + { + var currLMIndex = _builtInLMs.IndexOf(lmValue); + if (currLMIndex == -1) + { + currLMIndex = 0; + } - serializedObject.ApplyModifiedProperties(); + serializedObject.FindProperty("lightingModel").stringValue = + $"@/LightingModels/{_builtInLMs[EditorGUILayout.Popup("Lighting Model", currLMIndex, _builtInLMs.ToArray())]}"; + } - if (GUILayout.Button("Modules/Features List")) - { - Application.OpenURL("https://shaders.orels.sh/docs/shaders-list"); - } + var currShaderIndex = _builtInShaders.IndexOf(baseShaderValue); + if (currShaderIndex == -1) + { + currShaderIndex = 0; + } - var hasDupes = false; - var allModules = new List(); - var hasToon = false; - for (int i = 0; i < modulesProp.arraySize; i++) - { - var module = modulesProp.GetArrayElementAtIndex(i).stringValue; - if (allModules.Contains(module)) + var newBaseShader = + _builtInShaders[EditorGUILayout.Popup("Base Shader", currShaderIndex, _builtInShaders.ToArray())]; + if (newBaseShader.Equals("None")) { - hasDupes = true; + serializedObject.FindProperty("baseShader").stringValue = null; } + else + { + serializedObject.FindProperty("baseShader").stringValue = $"@/Shaders/{newBaseShader}"; + } + + EditorGUILayout.Space(5); + + var modulesProp = serializedObject.FindProperty("modules"); + var customModuleFlagsProp = serializedObject.FindProperty("customModuleFlags"); + var modulesListData = GetReorderableList(modulesProp, customModuleFlagsProp, assetPath); + modulesListData.modules = _builtInModules; + modulesListData.List.DoLayoutList(); + + serializedObject.ApplyModifiedProperties(); - if (module.Contains("Toon")) + if (GUILayout.Button("Modules/Features List")) { - hasToon = true; + Application.OpenURL("https://shaders.orels.sh/docs/shaders-list"); } - allModules.Add(module); - } - if (hasBaseShader && allModules.Contains("@/Modules/BaseColor")) - { - EditorGUILayout.HelpBox("Usage of BaseColor module with any of the Base Shaders will often lead to compile issues, it is recommended to remove it", MessageType.Warning); - } - - if (hasBaseShader && allModules.Contains("@/Modules/Toon/Main")) - { - EditorGUILayout.HelpBox("Usage of Toon/Main module with any of the Base Shaders will often lead to compile issues, it is recommended to remove it", MessageType.Warning); - } + var hasDupes = false; + var allModules = new List(); + var hasToon = false; + for (int i = 0; i < modulesProp.arraySize; i++) + { + var module = modulesProp.GetArrayElementAtIndex(i).stringValue; + if (allModules.Contains(module)) + { + hasDupes = true; + } - if (hasDupes) - { - EditorGUILayout.HelpBox("There are duplicate modules in your modules list, make sure you do not have repeat modules", MessageType.Error); - } + if (module.Contains("Toon")) + { + hasToon = true; + } + allModules.Add(module); + } - if (hasToon && (lmValue != "Toon" || (hasBaseShader && !baseShaderValue.Contains("Toon")))) - { - EditorGUILayout.HelpBox("Toon modules on non-toon shaders might not work as expected. Use of a Toon module or Toon Lighting Model is recommended", MessageType.Warning); - } + if (hasBaseShader && allModules.Contains("@/Modules/BaseColor")) + { + EditorGUILayout.HelpBox("Usage of BaseColor module with any of the Base Shaders will often lead to compile issues, it is recommended to remove it", MessageType.Warning); + } - if (modulesProp.arraySize > 0) - { - EditorGUILayout.HelpBox("Not every module is guaranteed to work with the rest. Try different combinations in different order and see what works!", MessageType.Info); + if (hasBaseShader && allModules.Contains("@/Modules/Toon/Main")) + { + EditorGUILayout.HelpBox("Usage of Toon/Main module with any of the Base Shaders will often lead to compile issues, it is recommended to remove it", MessageType.Warning); + } + + if (hasDupes) + { + EditorGUILayout.HelpBox("There are duplicate modules in your modules list, make sure you do not have repeat modules", MessageType.Error); + } + + if (hasToon && (lmValue != "Toon" || (hasBaseShader && !baseShaderValue.Contains("Toon")))) + { + EditorGUILayout.HelpBox("Toon modules on non-toon shaders might not work as expected. Use of a Toon module or Toon Lighting Model is recommended", MessageType.Warning); + } + + if (modulesProp.arraySize > 0) + { + EditorGUILayout.HelpBox("Not every module is guaranteed to work with the rest. Try different combinations in different order and see what works!", MessageType.Info); + } + + EditorGUILayout.Space(5); + + base.OnInspectorGUI(); + if (assetHasIssues) + { + EditorGUILayout.HelpBox("Fix the issues in the configuration above and use the Force Reimport button to apply the changes", MessageType.Error); + if (GUILayout.Button("Force Reimport")) + { + serializedObject.FindProperty("lastGeneratedTime").longValue = DateTime.Now.Ticks; + t.SaveAndReimport(); + } + } } - - EditorGUILayout.Space(5); - base.OnInspectorGUI(); + } + + protected override void Apply() + { + var generatedContent = ConfiguredShaderDefinitionImporter.GetGeneratedContents(target as ConfiguredShaderDefinitionImporter); + serializedObject.FindProperty("lastGeneratedContent").stringValue = generatedContent; + + serializedObject.FindProperty("lastGeneratedTime").longValue = DateTime.Now.Ticks; + + base.Apply(); } private const string LMS_PATH = "Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels"; @@ -138,6 +197,8 @@ private void ScanForBuiltInAssets() foreach (var file in allLMs) { if (file.EndsWith(".meta")) continue; + // MapBaker LM is excluded + if (file.Contains("MapBaker.orlsource")) continue; _builtInLMs.Add(file.Replace(LMS_PATH, string.Empty).Substring(1) .Replace(".orlsource", string.Empty).Replace('\\', '/')); } @@ -176,7 +237,7 @@ private ReorderableListProperty GetReorderableList(SerializedProperty prop) return ret; } - private ReorderableListProperty GetReorderableList(SerializedProperty prop, SerializedProperty otherProp) + private ReorderableListProperty GetReorderableList(SerializedProperty prop, SerializedProperty otherProp, string assetPath) { ReorderableListProperty ret = null; if (reorderableLists.TryGetValue(prop.name, out ret)) @@ -185,7 +246,7 @@ private ReorderableListProperty GetReorderableList(SerializedProperty prop, Seri return ret; } - ret = new ReorderableListProperty(prop, otherProp); + ret = new ReorderableListProperty(prop, otherProp, assetPath); reorderableLists.Add(prop.name, ret); return ret; } @@ -198,6 +259,7 @@ private class ReorderableListProperty private SerializedProperty prop; private SerializedProperty otherProp; + private string assetPath; private bool doubleList; public SerializedProperty Property @@ -223,24 +285,37 @@ public ReorderableListProperty() List = null; } - public ReorderableListProperty(SerializedProperty property, SerializedProperty otherProperty) + public ReorderableListProperty(SerializedProperty property, SerializedProperty otherProperty, string assetPath) { IsExpanded = property.isExpanded; prop = property; otherProp = otherProperty; doubleList = true; + this.assetPath = assetPath; CreateList(); } private void CreateList() { List = new ReorderableList(Property.serializedObject, Property, true, true, true, true); - List.drawHeaderCallback += rect => EditorGUI.LabelField(rect, prop.displayName); + List.drawHeaderCallback += rect => + { + var customRect = new Rect(rect); + var customRectWidth = Mathf.Min(rect.width / 2f, 100f); + rect.xMax -= customRectWidth; + customRect.xMin = rect.xMax + 10f; + EditorGUI.LabelField(rect, prop.displayName); + EditorGUI.LabelField(customRect, "Custom Module"); + }; List.onCanRemoveCallback += list => List.count > 0; List.drawElementCallback += DrawElement; List.elementHeightCallback += idx => Mathf.Max(EditorGUIUtility.singleLineHeight, EditorGUI.GetPropertyHeight(prop.GetArrayElementAtIndex(idx), GUIContent.none, true)) + 4f; + List.onReorderCallbackWithDetails += (list, oldIndex, newIndex) => + { + otherProp.MoveArrayElement(oldIndex, newIndex); + }; } private void DrawElement(Rect rect, int index, bool active, bool focused) @@ -252,6 +327,10 @@ private void DrawElement(Rect rect, int index, bool active, bool focused) rect.height = EditorGUI.GetPropertyHeight(prop.GetArrayElementAtIndex(index), GUIContent.none, true); rect.y += 1; + if (otherProp.arraySize != prop.arraySize) + { + otherProp.arraySize = prop.arraySize; + } if (!doubleList) { var currIndex = modules.IndexOf(prop.GetArrayElementAtIndex(index).stringValue @@ -263,14 +342,67 @@ private void DrawElement(Rect rect, int index, bool active, bool focused) prop.GetArrayElementAtIndex(index).stringValue = $"@/Modules/{modules[EditorGUI.Popup(rect, currIndex, modules.ToArray())]}"; - // EditorGUI.PropertyField(rect, prop.GetArrayElementAtIndex(index), GUIContent.none, true); } else { + var currIndex = modules.IndexOf(prop.GetArrayElementAtIndex(index).stringValue + .Replace("@/Modules/", string.Empty)); + if (currIndex == -1) + { + currIndex = 0; + } + var secondRect = EditorGUI.IndentedRect(rect); - secondRect.xMin = rect.xMax / 2f + 2f; - rect.xMax = rect.xMax / 2f - 2f; - EditorGUI.PropertyField(rect, prop.GetArrayElementAtIndex(index), GUIContent.none, true); + secondRect.xMin = rect.xMax - 20f; + rect.xMax -= 30f; + secondRect.width = 20f; + + if (!otherProp.GetArrayElementAtIndex(index).boolValue) + { + prop.GetArrayElementAtIndex(index).stringValue = + $"@/Modules/{modules[EditorGUI.Popup(rect, currIndex, modules.ToArray())]}"; + } + else + { + try + { + var savedPath = prop.GetArrayElementAtIndex(index).stringValue; + if (savedPath.StartsWith("Assets")) + { + savedPath = "/" + savedPath.Replace("\\", "/"); + } + var sourcePath = string.Empty; + try + { + sourcePath = Utils.ResolveORLAsset(savedPath, savedPath.StartsWith("@/"), assetPath); + } + catch (SourceAssetNotFoundException e) + { + Debug.LogWarning($"Could not find source {e.AssetPath} at {string.Join("\n", e.AttemptedPaths[0])}\n"); + sourcePath = savedPath; + } + var sourceObject = AssetDatabase.LoadAssetAtPath(sourcePath); + if (sourceObject == null) + { + EditorGUI.PropertyField(rect, prop.GetArrayElementAtIndex(index), GUIContent.none, true); + } + else + { + using (var c = new EditorGUI.ChangeCheckScope()) + { + var newObject = EditorGUI.ObjectField(rect, sourceObject, typeof(TextAsset), false); + if (c.changed) + { + prop.GetArrayElementAtIndex(index).stringValue = "/" + AssetDatabase.GetAssetPath(newObject).Replace("\\", "/"); + } + } + } + } + catch (Exception e) + { + Debug.LogError($"Failed to draw asset field for custom module {prop.GetArrayElementAtIndex(index).stringValue}: " + e.Message); + } + } EditorGUI.PropertyField(secondRect, otherProp.GetArrayElementAtIndex(index), GUIContent.none, true); } diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies.meta b/Packages/sh.orels.shaders.generator/Editor/Dependencies.meta old mode 100644 new mode 100755 similarity index 77% rename from Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies.meta rename to Packages/sh.orels.shaders.generator/Editor/Dependencies.meta index 72fd76ec..99c58207 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies.meta +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f4e8a9c940ed84943bb0433246ec42bb +guid: bfe32de17e5f07e4c989828a04143e73 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/com.vrchat.core.bootstrap/Editor.meta b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser.meta old mode 100644 new mode 100755 similarity index 77% rename from Packages/com.vrchat.core.bootstrap/Editor.meta rename to Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser.meta index d8de3836..53a68bb9 --- a/Packages/com.vrchat.core.bootstrap/Editor.meta +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5ee5eebf1b35bbd49ae7983db316180a +guid: b19322b9fe20f134f88845816b59a54b folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/LICENSE.txt b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/LICENSE.txt new file mode 100755 index 00000000..7799b114 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/LICENSE.txt @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2024, Pema Malling + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.License.txt.meta b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/LICENSE.txt.meta old mode 100644 new mode 100755 similarity index 75% rename from Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.License.txt.meta rename to Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/LICENSE.txt.meta index a0fc49d8..839bd37f --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/SemanticVersioning.License.txt.meta +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/LICENSE.txt.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1417544c34d9a4f4aacebf76247940a9 +guid: 4cae7c6900f6fdc40ad3ab0cdc01c2ee TextScriptImporter: externalObjects: {} userData: diff --git a/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/README.md b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/README.md new file mode 100755 index 00000000..77e28020 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/README.md @@ -0,0 +1,17 @@ +# UnityShaderParser +A library for parsing Unity shaders. Consists of a few distinct components: +- A parser for ShaderLab, Unity's own Shader DSL. +- A parser for HLSL, the shading language embedded in ShaderLab. +- A preprocessor for dealing with macros before parsing. +- A framework for analyzing syntax trees using the visitor pattern, and for making edits to the corresponding source code. + +Check [the tests](https://github.com/pema99/UnityShaderParser/tree/master/UnityShaderParser.Tests) for some examples. + +# Acknowledgements +- http://code.google.com/p/fxdis-d3d1x/ for test data +- https://github.com/James-Jones/HLSLCrossCompiler for test data +- http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html for test data +- https://github.com/pema99/UnityShaderParser/tree/master/UnityShaderParser.Tests/TestShaders/Sdk for test data +- https://github.com/microsoft/DirectX-Graphics-Samples/ for test data +- Unity Builtin Shaders used as ShaderLab test data, available on the Unity download page +- https://github.com/tgjones/HlslTools was used as inspiration and reference for some of the HLSL parsing techniques diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.License.txt.meta b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/README.md.meta old mode 100644 new mode 100755 similarity index 75% rename from Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.License.txt.meta rename to Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/README.md.meta index 649b3193..a3b7ba0e --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.License.txt.meta +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/README.md.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1a7454bc513adb84d9ae85ed7e7268ba +guid: acffccb86f91d824c8bc8e0030a0ac2e TextScriptImporter: externalObjects: {} userData: diff --git a/Packages/com.vrchat.core.bootstrap/Editor/VRChat.Bootstrapper.Editor.asmdef b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.asmdef old mode 100644 new mode 100755 similarity index 80% rename from Packages/com.vrchat.core.bootstrap/Editor/VRChat.Bootstrapper.Editor.asmdef rename to Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.asmdef index 115b3e2d..a465b028 --- a/Packages/com.vrchat.core.bootstrap/Editor/VRChat.Bootstrapper.Editor.asmdef +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.asmdef @@ -1,10 +1,9 @@ { - "name": "VRChat.Bootstrapper.Editor", + "name": "UnityShaderParser", "references": [], "includePlatforms": [ "Editor" ], - "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/com.vrchat.core.vpm-resolver.Editor.asmdef.meta b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.asmdef.meta old mode 100644 new mode 100755 similarity index 76% rename from Packages/com.vrchat.core.vpm-resolver/Editor/com.vrchat.core.vpm-resolver.Editor.asmdef.meta rename to Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.asmdef.meta index 73456806..b37f60d2 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/com.vrchat.core.vpm-resolver.Editor.asmdef.meta +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d1e8c2ba944807d4a9213e2de6930a0b +guid: a5857e7d50658ab468a75fe6fb42fda9 AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.cs b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.cs new file mode 100755 index 00000000..bb5dde7e --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.cs @@ -0,0 +1,11817 @@ +// File generated by dotnet-combine at 2024-04-01__03_55_20 + + +using System.Collections.Generic; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using UnityShaderParser.Common; +using UnityShaderParser.HLSL; +using UnityShaderParser.HLSL.PreProcessor; +using UnityShaderParser.ShaderLab; + + + +// HLSL/HLSLEditor.cs +namespace UnityShaderParser.HLSL +{ + public abstract class HLSLEditor : HLSLSyntaxVisitor + { + public string Source { get; private set; } + public List> Tokens { get; private set; } + + public HLSLEditor(string source, List> tokens) + { + Source = source; + Tokens = tokens; + } + + protected HashSet<(SourceSpan span, string newText)> Edits = new HashSet<(SourceSpan, string)>(); + + protected void Edit(SourceSpan span, string newText) => Edits.Add((span, newText)); + protected void Edit(Token token, string newText) => Edit(token.Span, newText); + protected void Edit(HLSLSyntaxNode node, string newText) => Edit(node.Span, newText); + protected void AddBefore(SourceSpan span, string newText) => Edit(new SourceSpan(span.BasePath, span.FileName, span.Start, span.Start), newText); + protected void AddBefore(Token token, string newText) => Edit(new SourceSpan(token.Span.BasePath, token.Span.FileName, token.Span.Start, token.Span.Start), newText); + protected void AddBefore(HLSLSyntaxNode node, string newText) => Edit(new SourceSpan(node.Span.BasePath, node.Span.FileName, node.Span.Start, node.Span.Start), newText); + protected void AddAfter(SourceSpan span, string newText) => Edit(new SourceSpan(span.BasePath, span.FileName, span.End, span.End), newText); + protected void AddAfter(Token token, string newText) => Edit(new SourceSpan(token.Span.BasePath, token.Span.FileName, token.Span.End, token.Span.End), newText); + protected void AddAfter(HLSLSyntaxNode node, string newText) => Edit(new SourceSpan(node.Span.BasePath, node.Span.FileName, node.Span.End, node.Span.End), newText); + + public string ApplyCurrentEdits() => PrintingUtil.ApplyEditsToSourceText(Edits, Source); + + public string ApplyEdits(HLSLSyntaxNode node) + { + Visit(node); + return ApplyCurrentEdits(); + } + + public string ApplyEdits(IEnumerable nodes) + { + VisitMany(nodes); + return ApplyCurrentEdits(); + } + + public static string RunEditor(string source, HLSLSyntaxNode node) + where T : HLSLEditor + { + var editor = (HLSLEditor)Activator.CreateInstance(typeof(T), source, node.Tokens); + return editor.ApplyEdits(node); + } + + public static string RunEditor(string source, IEnumerable node) + where T : HLSLEditor + { + var editor = (HLSLEditor)Activator.CreateInstance(typeof(T), source, node.SelectMany(x => x.Tokens).ToList()); + return editor.ApplyEdits(node); + } + } +} + + +// HLSL/HLSLLexer.cs +namespace UnityShaderParser.HLSL +{ + using HLSLToken = Token; + + public class HLSLLexer : BaseLexer + { + protected override ParserStage Stage => ParserStage.HLSLLexing; + + public HLSLLexer(string source, string basePath, string fileName, bool throwExceptionOnError, SourceLocation offset) + : base(source, basePath, fileName, throwExceptionOnError, offset) { } + + public static List Lex(string source, string basePath, string fileName, bool throwExceptionOnError, out List diagnostics) + { + return Lex(source, basePath, fileName, throwExceptionOnError, new SourceLocation(1, 1, 0), out diagnostics); + } + + public static List Lex(string source, string basePath, string fileName, bool throwExceptionOnError, SourceLocation offset, out List diagnostics) + { + HLSLLexer lexer = new HLSLLexer(source, basePath, fileName, throwExceptionOnError, offset); + + lexer.Lex(); + + diagnostics = lexer.diagnostics; + return lexer.tokens; + } + + protected override void ProcessChar(char nextChar) + { + switch (nextChar) + { + case char c when char.IsLetter(c) || c == '_': + LexIdentifier(); + break; + + case '0' when LookAhead('x'): + Advance(1); + string hexNum = EatIdentifier().Substring(1); + string origHexNum = hexNum; + if (hexNum.EndsWith("u") || hexNum.EndsWith("U")) + hexNum = hexNum.Substring(0, hexNum.Length - 1); + if (!uint.TryParse(hexNum, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out uint hexVal)) + Error(DiagnosticFlags.SyntaxError, $"Invalid hex literal 0x{hexNum}"); + Add($"0x{origHexNum}", TokenKind.IntegerLiteralToken); + break; + + case char c when char.IsDigit(c) || (c == '.' && char.IsDigit(LookAhead())): + string num = EatNumber(out bool isFloat); + TokenKind kind = isFloat ? TokenKind.FloatLiteralToken : TokenKind.IntegerLiteralToken; + Add(num, kind); + break; + + case '\'': + Add(EatStringLiteral('\'', '\''), TokenKind.CharacterLiteralToken); + break; + + case '"': + Add(EatStringLiteral('"', '"'), TokenKind.StringLiteralToken); + break; + + case ' ': + case '\t': + case '\r': + case '\n': + case '\\': + Advance(); // Only consume 1 (preprocessor might care about the newlines) + break; + + case '/' when LookAhead('/'): + Advance(2); + while (!Match('\n')) + { + Advance(); + if (IsAtEnd()) + break; + } + break; + + case '/' when LookAhead('*'): + Advance(2); + while (!(Match('*') && LookAhead('/'))) + { + Advance(); + if (IsAtEnd()) + { + Error(DiagnosticFlags.SyntaxError, $"Unterminated comment."); + break; + } + } + Advance(2); + break; + + case '(': Advance(); Add(TokenKind.OpenParenToken); break; + case ')': Advance(); Add(TokenKind.CloseParenToken); break; + case '[': Advance(); Add(TokenKind.OpenBracketToken); break; + case ']': Advance(); Add(TokenKind.CloseBracketToken); break; + case '{': Advance(); Add(TokenKind.OpenBraceToken); break; + case '}': Advance(); Add(TokenKind.CloseBraceToken); break; + case ';': Advance(); Add(TokenKind.SemiToken); break; + case ',': Advance(); Add(TokenKind.CommaToken); break; + case '.': Advance(); Add(TokenKind.DotToken); break; + case '~': Advance(); Add(TokenKind.TildeToken); break; + case '?': Advance(); Add(TokenKind.QuestionToken); break; + + case '<' when LookAhead('='): Advance(2); Add(TokenKind.LessThanEqualsToken); break; + case '<' when LookAhead('<') && LookAhead('=', 2): Advance(3); Add(TokenKind.LessThanLessThanEqualsToken); break; + case '<' when LookAhead('<'): Advance(2); Add(TokenKind.LessThanLessThanToken); break; + case '<': Advance(); Add(TokenKind.LessThanToken); break; + + case '>' when LookAhead('='): Advance(2); Add(TokenKind.GreaterThanEqualsToken); break; + case '>' when LookAhead('>') && LookAhead('=', 2): Advance(3); Add(TokenKind.GreaterThanGreaterThanEqualsToken); break; + case '>' when LookAhead('>'): Advance(2); Add(TokenKind.GreaterThanGreaterThanToken); break; + case '>': Advance(); Add(TokenKind.GreaterThanToken); break; + + case '+' when LookAhead('+'): Advance(2); Add(TokenKind.PlusPlusToken); break; + case '+' when LookAhead('='): Advance(2); Add(TokenKind.PlusEqualsToken); break; + case '+': Advance(); Add(TokenKind.PlusToken); break; + + case '-' when LookAhead('-'): Advance(2); Add(TokenKind.MinusMinusToken); break; + case '-' when LookAhead('='): Advance(2); Add(TokenKind.MinusEqualsToken); break; + case '-': Advance(); Add(TokenKind.MinusToken); break; + + case '*' when LookAhead('='): Advance(2); Add(TokenKind.AsteriskEqualsToken); break; + case '*': Advance(); Add(TokenKind.AsteriskToken); break; + + case '/' when LookAhead('='): Advance(2); Add(TokenKind.SlashEqualsToken); break; + case '/': Advance(); Add(TokenKind.SlashToken); break; + + case '%' when LookAhead('='): Advance(2); Add(TokenKind.PercentEqualsToken); break; + case '%': Advance(); Add(TokenKind.PercentToken); break; + + case '&' when LookAhead('&'): Advance(2); Add(TokenKind.AmpersandAmpersandToken); break; + case '&' when LookAhead('='): Advance(2); Add(TokenKind.AmpersandEqualsToken); break; + case '&': Advance(); Add(TokenKind.AmpersandToken); break; + + case '|' when LookAhead('|'): Advance(2); Add(TokenKind.BarBarToken); break; + case '|' when LookAhead('='): Advance(2); Add(TokenKind.BarEqualsToken); break; + case '|': Advance(); Add(TokenKind.BarToken); break; + + case '^' when LookAhead('='): Advance(2); Add(TokenKind.CaretEqualsToken); break; + case '^': Advance(); Add(TokenKind.CaretToken); break; + + case ':' when LookAhead(':'): Advance(2); Add(TokenKind.ColonColonToken); break; + case ':': Advance(); Add(TokenKind.ColonToken); break; + + case '=' when LookAhead('='): Advance(2); Add(TokenKind.EqualsEqualsToken); break; + case '=': Advance(); Add(TokenKind.EqualsToken); break; + + case '!' when LookAhead('='): Advance(2); Add(TokenKind.ExclamationEqualsToken); break; + case '!': Advance(); Add(TokenKind.NotToken); break; + + case '#' when LookAhead('#'): Advance(2); Add(TokenKind.HashHashToken); break; + + case '#': + LexPreProcessorDirective(); + break; + + case char c: + Advance(); + Error(DiagnosticFlags.SyntaxError, $"Unexpected token '{c}'."); + break; + } + } + + private void LexIdentifier() + { + string identifier = EatIdentifier(); + if (HLSLSyntaxFacts.TryParseHLSLKeyword(identifier, out TokenKind token)) + { + Add(token); + } + else + { + Add(identifier, TokenKind.IdentifierToken); + } + } + + private void LexPreProcessorDirective() + { + Eat('#'); + SkipWhitespace(); + string keyword = EatIdentifier(); + switch (keyword) + { + case "define": + Add(TokenKind.DefineDirectiveKeyword); + SkipWhitespace(); + Add(EatIdentifier(), TokenKind.IdentifierToken); + if (Match('(')) // No whitespace + { + // In order to distinguish function like macros and regular macros, one must inspect whitespace + Advance(); + Add(TokenKind.OpenFunctionLikeMacroParenToken); + } + break; + + case "line": Add(TokenKind.LineDirectiveKeyword); break; + case "undef": Add(TokenKind.UndefDirectiveKeyword); break; + case "error": Add(TokenKind.ErrorDirectiveKeyword); break; + case "pragma": Add(TokenKind.PragmaDirectiveKeyword); break; + case "include": + Add(TokenKind.IncludeDirectiveKeyword); + SkipWhitespace(); + // Handle system includes + if (Match('<')) + { + Eat('<'); + var sb = new StringBuilder(); + while (!IsAtEnd() && !Match('>')) + { + sb.Append(Advance()); + } + Eat('>'); + Add(sb.ToString(), TokenKind.SystemIncludeLiteralToken); + } + break; + + case "if": Add(TokenKind.IfDirectiveKeyword); break; + case "ifdef": Add(TokenKind.IfdefDirectiveKeyword); break; + case "ifndef": Add(TokenKind.IfndefDirectiveKeyword); break; + case "elif": Add(TokenKind.ElifDirectiveKeyword); break; + case "else": Add(TokenKind.ElseDirectiveKeyword); break; + case "endif": Add(TokenKind.EndifDirectiveKeyword); break; + + default: + Add(TokenKind.HashToken); + Add(keyword, TokenKind.IdentifierToken); + break; + } + + // Go to end of line + while (!IsAtEnd() && !Match('\n')) + { + // Skip multiline macro line breaks + if (Match('\\')) + { + Advance(); + SkipWhitespace(); + if (Match('\n')) + { + Advance(); + } + } + + // Process char + StartCurrentSpan(); + ProcessChar(Peek()); + } + Add(TokenKind.EndDirectiveToken); + } + } +} + + +// HLSL/HLSLParser.cs +namespace UnityShaderParser.HLSL +{ + using HLSLToken = Token; + + public class HLSLParserConfig + { + public PreProcessorMode PreProcessorMode { get; set; } + public string BasePath { get; set; } + public string FileName { get; set; } + public IPreProcessorIncludeResolver IncludeResolver { get; set; } + public Dictionary Defines { get; set; } + public bool ThrowExceptionOnError { get; set; } + public DiagnosticFlags DiagnosticFilter { get; set; } + + public HLSLParserConfig() + { + PreProcessorMode = PreProcessorMode.ExpandAll; + BasePath = Directory.GetCurrentDirectory(); + FileName = null; + IncludeResolver = new DefaultPreProcessorIncludeResolver(); + Defines = new Dictionary(); + ThrowExceptionOnError = false; + DiagnosticFilter = DiagnosticFlags.All; + } + + public HLSLParserConfig(HLSLParserConfig config) + { + PreProcessorMode = config.PreProcessorMode; + BasePath = config.BasePath; + FileName = config.FileName; + IncludeResolver = config.IncludeResolver; + Defines = config.Defines; + ThrowExceptionOnError = config.ThrowExceptionOnError; + DiagnosticFilter = config.DiagnosticFilter; + } + } + + public class HLSLParser : BaseParser + { + public HLSLParser(List tokens, bool throwExceptionOnError, DiagnosticFlags diagnosticFilter) + : base(tokens, throwExceptionOnError, diagnosticFilter) + { + InitOperatorGroups(); + } + + protected override TokenKind StringLiteralTokenKind => TokenKind.StringLiteralToken; + protected override TokenKind IntegerLiteralTokenKind => TokenKind.IntegerLiteralToken; + protected override TokenKind FloatLiteralTokenKind => TokenKind.FloatLiteralToken; + protected override TokenKind IdentifierTokenKind => TokenKind.IdentifierToken; + protected override TokenKind InvalidTokenKind => TokenKind.InvalidToken; + protected override ParserStage Stage => ParserStage.HLSLParsing; + + public static List ParseTopLevelDeclarations(List tokens, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + HLSLParser parser = new HLSLParser(tokens, config.ThrowExceptionOnError, config.DiagnosticFilter); + parser.RunPreProcessor(config, out pragmas); + var result = parser.ParseTopLevelDeclarations(); + foreach (var decl in result) + { + decl.ComputeParents(); + } + diagnostics = parser.diagnostics; + return result; + } + + public static HLSLSyntaxNode ParseTopLevelDeclaration(List tokens, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + HLSLParser parser = new HLSLParser(tokens, config.ThrowExceptionOnError, config.DiagnosticFilter); + parser.RunPreProcessor(config, out pragmas); + var result = parser.ParseTopLevelDeclaration(); + result.ComputeParents(); + diagnostics = parser.diagnostics; + return result; + } + + public static List ParseStatements(List tokens, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + HLSLParser parser = new HLSLParser(tokens, config.ThrowExceptionOnError, config.DiagnosticFilter); + parser.RunPreProcessor(config, out pragmas); + var result = parser.ParseMany0(() => !parser.LoopShouldContinue(), () => parser.ParseStatement()); + foreach (var stmt in result) + { + stmt.ComputeParents(); + } + diagnostics = parser.diagnostics; + return result; + } + + public static StatementNode ParseStatement(List tokens, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + HLSLParser parser = new HLSLParser(tokens, config.ThrowExceptionOnError, config.DiagnosticFilter); + parser.RunPreProcessor(config, out pragmas); + var result = parser.ParseStatement(); + result.ComputeParents(); + diagnostics = parser.diagnostics; + return result; + } + + public static ExpressionNode ParseExpression(List tokens, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + HLSLParser parser = new HLSLParser(tokens, config.ThrowExceptionOnError, config.DiagnosticFilter); + parser.RunPreProcessor(config, out pragmas); + var result = parser.ParseExpression(); + result.ComputeParents(); + diagnostics = parser.diagnostics; + return result; + } + + public void RunPreProcessor(HLSLParserConfig config, out List pragmas) + { + if (config.PreProcessorMode == PreProcessorMode.DoNothing) + { + pragmas = new List(); + return; + } + + tokens = HLSLPreProcessor.PreProcess( + tokens, + config.ThrowExceptionOnError, + config.DiagnosticFilter, + config.PreProcessorMode, + config.BasePath, + config.IncludeResolver, + config.Defines, + out pragmas, + out var ppDiags); + diagnostics.AddRange(ppDiags); + } + + public List ParseTopLevelDeclarations() + { + List result = new List(); + + while (LoopShouldContinue()) + { + result.Add(ParseTopLevelDeclaration()); + } + + return result; + } + + public HLSLSyntaxNode ParseTopLevelDeclaration() + { + switch (Peek().Kind) + { + case TokenKind.NamespaceKeyword: + return ParseNamespace(); + + case TokenKind.CBufferKeyword: + case TokenKind.TBufferKeyword: + return ParseConstantBuffer(); + + case TokenKind.StructKeyword: + case TokenKind.ClassKeyword: + return ParseStructDefinitionOrDeclaration(new List()); + + case TokenKind.InterfaceKeyword: + return ParseInterfaceDefinition(new List()); + + case TokenKind.TypedefKeyword: + return ParseTypedef(new List()); + + case TokenKind.Technique10Keyword: + case TokenKind.Technique11Keyword: + case TokenKind.TechniqueKeyword: + return ParseTechnique(); + + case TokenKind.SemiToken: + var semiTok = Advance(); + return new EmptyStatementNode(Range(semiTok, semiTok)) { Attributes = new List() }; + + default: + if (IsNextPreProcessorDirective()) + { + return ParsePreProcessorDirective(ParseTopLevelDeclaration); + } + else if (IsNextPossiblyFunctionDeclaration()) + { + return ParseFunction(); + } + else + { + return ParseVariableDeclarationStatement(new List()); + } + } + } + + private bool IsNextCast() + { + int offset = 0; + + // Must have initial paren + if (LookAhead(offset).Kind != TokenKind.OpenParenToken) + return false; + offset++; + + // If we mention a builtin or user defined type - it might be a cast + if (HLSLSyntaxFacts.IsBuiltinType(LookAhead(offset).Kind) || + LookAhead(offset).Kind == TokenKind.ClassKeyword || + LookAhead(offset).Kind == TokenKind.StructKeyword || + LookAhead(offset).Kind == TokenKind.InterfaceKeyword) + { + offset++; + } + // If there is an identifier + else if (LookAhead(offset).Kind == TokenKind.IdentifierToken) + { + // Take as many qualifier sections as possible + offset++; + while (LookAhead(offset).Kind == TokenKind.ColonColonToken) + { + offset++; + if (LookAhead(offset).Kind != TokenKind.IdentifierToken) + { + return false; + } + offset++; + } + } + // If none of the above are true, can't be a cast + else + { + return false; + } + + // If we had an identifier, check if it is followed by an array type + while (LookAhead(offset).Kind == TokenKind.OpenBracketToken) + { + // All arguments must be constants or identifiers + offset++; + if (LookAhead(offset).Kind != TokenKind.IntegerLiteralToken && LookAhead(offset).Kind != TokenKind.IdentifierToken) + { + return false; + } + offset++; + if (LookAhead(offset).Kind != TokenKind.CloseBracketToken) + { + return false; + } + offset++; + } + + // If we've reached this point, make sure the cast is closed + if (LookAhead(offset).Kind != TokenKind.CloseParenToken) + return false; + + // It might still be ambiguous, so check if the next token is allowed to follow a cast + offset++; + return HLSLSyntaxFacts.CanTokenComeAfterCast(LookAhead(offset).Kind); + } + + private bool IsNextPossiblyFunctionDeclaration() + { + return Speculate(() => + { + ParseMany0(TokenKind.OpenBracketToken, ParseAttribute); + ParseDeclarationModifiers(); + ParseType(true); + ParseUserDefinedNamedType(); + return Match(TokenKind.OpenParenToken); + }); + } + + public StatePropertyNode ParseStateProperty() + { + var firstTok = Peek(); + + UserDefinedNamedTypeNode name; + if (Match(TokenKind.TextureKeyword)) + { + var nameTok = Advance(); + name = new NamedTypeNode(Range(nameTok, nameTok)) { Name = "texture" }; + } + else + { + name = ParseUserDefinedNamedType(); + } + ArrayRankNode rank = null; + if (Match(TokenKind.OpenBracketToken)) + { + rank = ParseArrayRank(); + } + + ExpressionNode expr; + Eat(TokenKind.EqualsToken); + bool isReference = Match(TokenKind.LessThanToken); + if (isReference) + { + Eat(TokenKind.LessThanToken); + expr = ParseNamedExpression(); + if (Match(TokenKind.OpenBracketToken)) + { + Eat(TokenKind.OpenBracketToken); + var indexExpr = ParseExpression(); + Eat(TokenKind.CloseBracketToken); + expr = new ElementAccessExpressionNode(Range(firstTok, Previous())) + { + Target = expr, + Index = indexExpr + }; + } + Eat(TokenKind.GreaterThanToken); + } + else + { + expr = ParseExpression(); + } + Eat(TokenKind.SemiToken); + + return new StatePropertyNode(Range(firstTok, Previous())) + { + Name = name, + ArrayRank = rank, + Value = expr, + IsReference = isReference, + }; + } + + public SamplerStateLiteralExpressionNode ParseSamplerStateLiteral() + { + var keywordTok = Eat(TokenKind.SamplerStateLegacyKeyword); + Eat(TokenKind.OpenBraceToken); + + List states = new List(); + while (Match(TokenKind.IdentifierToken, TokenKind.TextureKeyword)) + { + states.Add(ParseStateProperty()); + } + + Eat(TokenKind.CloseBraceToken); + + return new SamplerStateLiteralExpressionNode(Range(keywordTok, Previous())) + { + States = states + }; + } + + public CompileExpressionNode ParseCompileExpression() + { + var keywordTok = Eat(TokenKind.CompileKeyword); + string target = ParseIdentifier(); + + var name = ParseNamedExpression(); + var param = ParseParameterList(); + var expr = new FunctionCallExpressionNode(Range(keywordTok, Previous())) { Name = name, Arguments = param }; + + return new CompileExpressionNode(Range(keywordTok, Previous())) + { + Target = target, + Invocation = expr + }; + } + + internal ExpressionNode ParseExpression(int level = 0) + { + if (Match(TokenKind.SamplerStateLegacyKeyword)) + { + return ParseSamplerStateLiteral(); + } + + return ParseBinaryExpression(level); + } + + // https://en.cppreference.com/w/c/language/operator_precedence + private List<( + HashSet operators, + bool rightAssociative, + Func ctor + )> operatorGroups; + + private void InitOperatorGroups() + { + operatorGroups = new List<(HashSet operators, bool rightAssociative, Func ctor)> + { + // Compound expression + (new HashSet() { TokenKind.CommaToken }, + false, + (l, op, r) => new CompoundExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Right = r }), + + // Assignment + (new HashSet() { + TokenKind.EqualsToken, TokenKind.PlusEqualsToken, TokenKind.MinusEqualsToken, + TokenKind.AsteriskEqualsToken, TokenKind.SlashEqualsToken, TokenKind.PercentEqualsToken, + TokenKind.LessThanLessThanEqualsToken, TokenKind.GreaterThanGreaterThanEqualsToken, + TokenKind.AmpersandEqualsToken, TokenKind.CaretEqualsToken, TokenKind.BarEqualsToken }, + true, + (l, op, r) => new AssignmentExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // Ternary + (new HashSet() { TokenKind.QuestionToken }, + true, + (l, op, r) => throw new Exception("This should never happen. Please file a bug report.")), + + // LogicalOr + (new HashSet() { TokenKind.BarBarToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // LogicalAnd + (new HashSet() { TokenKind.AmpersandAmpersandToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // BitwiseOr + (new HashSet() { TokenKind.BarToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // BitwiseXor + (new HashSet() { TokenKind.CaretToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // BitwiseAnd + (new HashSet() { TokenKind.AmpersandToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // Equality + (new HashSet() { TokenKind.EqualsEqualsToken, TokenKind.ExclamationEqualsToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.First(), r.Tokens.Last())) { Left = l, Operator = op, Right = r }), + + // Comparison + (new HashSet() { TokenKind.LessThanToken, TokenKind.LessThanEqualsToken, TokenKind.GreaterThanToken, TokenKind.GreaterThanEqualsToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // BitShift + (new HashSet() { TokenKind.LessThanLessThanToken, TokenKind.GreaterThanGreaterThanToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // AddSub + (new HashSet() { TokenKind.PlusToken, TokenKind.MinusToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // MulDivMod + (new HashSet() { TokenKind.AsteriskToken, TokenKind.SlashToken, TokenKind.PercentToken }, + false, + (l, op, r) => new BinaryExpressionNode(Range(l.Tokens.FirstOrDefault(), r.Tokens.LastOrDefault())) { Left = l, Operator = op, Right = r }), + + // Binds most tightly + }; + } + + public ExpressionNode ParseBinaryExpression(int level = 0) + { + if (level >= operatorGroups.Count) + { + return ParsePrefixOrPostFixExpression(); + } + + ExpressionNode higher = ParseBinaryExpression(level + 1); + + // Ternary is a special case + if (level == (int)OperatorPrecedence.Ternary) + { + if (Match(TokenKind.QuestionToken)) + { + Eat(TokenKind.QuestionToken); + var left = ParseExpression(); + Eat(TokenKind.ColonToken); + var right = ParseExpression(); + return new TernaryExpressionNode(Range(higher.Tokens.First(), right.Tokens.Last())) { Condition = higher, TrueCase = left, FalseCase = right }; + } + } + + var group = operatorGroups[level]; + while (Match(tok => group.operators.Contains(tok.Kind))) + { + HLSLToken next = Advance(); + if (!HLSLSyntaxFacts.TryConvertToOperator(next.Kind, out OperatorKind op)) + { + Error("a valid operator", next); + } + + higher = group.ctor( + higher, + op, + ParseBinaryExpression(group.rightAssociative ? level : level + 1)); + + if (IsAtEnd()) + { + return higher; + } + } + + return higher; + } + + public ExpressionNode ParsePrefixOrPostFixExpression() + { + var firstTok = Peek(); + ExpressionNode higher; + switch (firstTok.Kind) + { + case TokenKind.PlusPlusToken: + case TokenKind.MinusMinusToken: + case TokenKind.PlusToken: + case TokenKind.MinusToken: + case TokenKind.NotToken: + case TokenKind.TildeToken: + TokenKind opKind = Eat(HLSLSyntaxFacts.IsPrefixUnaryToken).Kind; + HLSLSyntaxFacts.TryConvertToOperator(opKind, out var op); + var unExpr = ParsePrefixOrPostFixExpression(); + higher = new PrefixUnaryExpressionNode(Range(firstTok, Previous())) { Operator = op, Expression = unExpr }; + break; + + case TokenKind.OpenParenToken when IsNextCast(): + Eat(TokenKind.OpenParenToken); + var type = ParseType(); + List arrayRanks = new List(); + while (Match(TokenKind.OpenBracketToken)) + { + arrayRanks.Add(ParseArrayRank()); + } + Eat(TokenKind.CloseParenToken); + var castExpr = ParsePrefixOrPostFixExpression(); + higher = new CastExpressionNode(Range(firstTok, Previous())) { Kind = type, Expression = castExpr, ArrayRanks = arrayRanks, IsFunctionLike = false }; + break; + + case TokenKind.OpenParenToken: + Eat(TokenKind.OpenParenToken); + higher = ParseExpression(); + Eat(TokenKind.CloseParenToken); + break; + + default: + // Special case for constructors of built-in types. Their target is not an expression, but a keyword. + if (Match(HLSLSyntaxFacts.IsMultiArityNumericConstructor)) + { + var kind = ParseNumericType(); + var ctorArgs = ParseParameterList(); + higher = new NumericConstructorCallExpressionNode(Range(firstTok, Previous())) { Kind = kind, Arguments = ctorArgs }; + } + // Special case for function style C-casts + else if (Match(HLSLSyntaxFacts.IsSingleArityNumericConstructor)) + { + var kind = ParseNumericType(); + Eat(TokenKind.OpenParenToken); + var castFrom = ParseExpression(); + Eat(TokenKind.CloseParenToken); + higher = new CastExpressionNode(Range(firstTok, Previous())) { Kind = kind, Expression = castFrom, ArrayRanks = new List(), IsFunctionLike = true }; + } + else + { + higher = ParseTerminalExpression(); + } + break; + } + + while (LoopShouldContinue()) + { + switch (Peek().Kind) + { + case TokenKind.PlusPlusToken: + case TokenKind.MinusMinusToken: + HLSLSyntaxFacts.TryConvertToOperator(Advance().Kind, out var incrOp); + higher = new PostfixUnaryExpressionNode(Range(firstTok, Previous())) { Expression = higher, Operator = incrOp }; + break; + + case TokenKind.OpenParenToken when higher is NamedExpressionNode target: + var funcArgs = ParseParameterList(); + higher = new FunctionCallExpressionNode(Range(firstTok, Previous())) { Name = target, Arguments = funcArgs }; + break; + + case TokenKind.OpenBracketToken: + Eat(TokenKind.OpenBracketToken); + var indexArg = ParseExpression(); + Eat(TokenKind.CloseBracketToken); + higher = new ElementAccessExpressionNode(Range(firstTok, Previous())) { Target = higher, Index = indexArg }; + break; + + case TokenKind.DotToken: + Eat(TokenKind.DotToken); + string identifier = ParseIdentifier(); + + if (Match(TokenKind.OpenParenToken)) + { + var methodArgs = ParseParameterList(); + higher = new MethodCallExpressionNode(Range(firstTok, Previous())) { Target = higher, Name = identifier, Arguments = methodArgs }; + } + else + { + higher = new FieldAccessExpressionNode(Range(firstTok, Previous())) { Target = higher, Name = identifier }; + } + break; + + default: + return higher; + } + } + + return higher; + } + + public NamedExpressionNode ParseNamedExpression() + { + var firstTok = Peek(); + string identifier = ParseIdentifier(); + + var name = new IdentifierExpressionNode(Range(firstTok, firstTok)) { Name = identifier }; + + if (Match(TokenKind.ColonColonToken)) + { + Eat(TokenKind.ColonColonToken); + + var nextNameExpr = ParseNamedExpression(); + return new QualifiedIdentifierExpressionNode(Range(firstTok, Previous())) { Left = name, Right = nextNameExpr }; + } + else + { + return name; + } + } + + public ArrayInitializerExpressionNode ParseArrayInitializer() + { + var openTok = Eat(TokenKind.OpenBraceToken); + var exprs = ParseSeparatedList0( + TokenKind.CloseBraceToken, + TokenKind.CommaToken, + () => ParseExpression((int)OperatorPrecedence.Compound + 1), + true); + var closeTok = Eat(TokenKind.CloseBraceToken); + return new ArrayInitializerExpressionNode(Range(openTok, closeTok)) { Elements = exprs }; + } + + public LiteralExpressionNode ParseLiteralExpression() + { + HLSLToken next = Peek(); + string lexeme = HLSLSyntaxFacts.IdentifierOrKeywordToString(next); + + if (!HLSLSyntaxFacts.TryConvertLiteralKind(next.Kind, out var literalKind)) + { + Error("a valid literal expression", next); + } + Advance(); + + return new LiteralExpressionNode(Range(next, next)) { Lexeme = lexeme, Kind = literalKind }; + } + + public ExpressionNode ParseTerminalExpression() + { + if (Match(TokenKind.IdentifierToken)) + { + return ParseNamedExpression(); + } + + else if (Match(TokenKind.CompileKeyword)) + { + return ParseCompileExpression(); + } + + else if (Match(TokenKind.OpenBraceToken)) + { + return ParseArrayInitializer(); + } + + return ParseLiteralExpression(); + } + + public List ParseParameterList() + { + Eat(TokenKind.OpenParenToken); + List exprs = ParseSeparatedList0( + TokenKind.CloseParenToken, + TokenKind.CommaToken, + () => ParseExpression((int)OperatorPrecedence.Compound + 1)); + Eat(TokenKind.CloseParenToken); + return exprs; + } + + public AttributeNode ParseAttribute() + { + var openTok = Eat(TokenKind.OpenBracketToken); + + string identifier = ParseIdentifier(); + + List args = new List(); + if (Match(TokenKind.OpenParenToken)) + { + Eat(TokenKind.OpenParenToken); + + args = ParseSeparatedList1(TokenKind.CommaToken, ParseLiteralExpression); + + Eat(TokenKind.CloseParenToken); + } + + var closeTok = Eat(TokenKind.CloseBracketToken); + + return new AttributeNode(Range(openTok, closeTok)) + { + Name = identifier, + Arguments = args + }; + } + + public FunctionNode ParseFunction() + { + var firstTok = Peek(); + List attributes = ParseMany0(TokenKind.OpenBracketToken, ParseAttribute); + + var modifiers = ParseDeclarationModifiers(); + TypeNode returnType = ParseType(true); + + UserDefinedNamedTypeNode name = ParseUserDefinedNamedType(); + + Eat(TokenKind.OpenParenToken); + List parameters = ParseSeparatedList0(TokenKind.CloseParenToken, TokenKind.CommaToken, ParseFormalParameter); + Eat(TokenKind.CloseParenToken); + + SemanticNode semantic = ParseOptional(TokenKind.ColonToken, ParseSemantic); + + // Function prototype + if (Match(TokenKind.SemiToken)) + { + var semiTok = Eat(TokenKind.SemiToken); + return new FunctionDeclarationNode(Range(firstTok, semiTok)) + { + Attributes = attributes, + Modifiers = modifiers, + ReturnType = returnType, + Name = name, + Parameters = parameters, + Semantic = semantic + }; + } + RecoverTo(TokenKind.SemiToken, TokenKind.CloseBraceToken); + + // Otherwise, full function + BlockNode body = ParseBlock(new List()); + return new FunctionDefinitionNode(Range(firstTok, Previous())) + { + Attributes = attributes, + Modifiers = modifiers, + ReturnType = returnType, + Name = name, + Parameters = parameters, + Semantic = semantic, + Body = body + }; + } + + public StatementNode ParseStructDefinitionOrDeclaration(List attributes) + { + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? Peek(); + var modifiers = ParseDeclarationModifiers(); + StructTypeNode structType = ParseStructType(); + + // This is a definition - no instance + if (Match(TokenKind.SemiToken)) + { + if (modifiers.Count > 0) + { + Error(DiagnosticFlags.SyntaxError, $"Struct definitions cannot have modifiers, found '{string.Join(", ", modifiers)}'."); + } + + var semiTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + return new StructDefinitionNode(Range(firstTok, semiTok)) + { + Attributes = attributes, + StructType = structType, + }; + } + // This is a declaration - making a type and an instance + else + { + List variables = ParseSeparatedList1(TokenKind.CommaToken, () => ParseVariableDeclarator()); + var semiTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + return new VariableDeclarationStatementNode(Range(firstTok, semiTok)) + { + Modifiers = modifiers, + Kind = structType, + Declarators = variables, + Attributes = attributes, + }; + } + } + + public InterfaceDefinitionNode ParseInterfaceDefinition(List attributes) + { + var keywordTok = Eat(TokenKind.InterfaceKeyword); + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? keywordTok; + var name = ParseUserDefinedNamedType(); + + Eat(TokenKind.OpenBraceToken); + + List funs = ParseMany0( + () => !Match(TokenKind.CloseBraceToken), + ParseFunction); + + List decls = new List(); + foreach (var function in funs) + { + if (function is FunctionDeclarationNode decl) + { + decls.Add(decl); + } + else + { + Error(DiagnosticFlags.SemanticError, "Expected only function declarations/prototypes in interface type, but found a function body."); + } + } + + Eat(TokenKind.CloseBraceToken); + var semiTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + + return new InterfaceDefinitionNode(Range(keywordTok, semiTok)) + { + Attributes = attributes, + Name = name, + Functions = decls, + }; + } + + public NamespaceNode ParseNamespace() + { + var keywordTok = Eat(TokenKind.NamespaceKeyword); + var name = ParseUserDefinedNamedType(); + Eat(TokenKind.OpenBraceToken); + var decls = ParseMany0(() => !Match(TokenKind.CloseBraceToken), ParseTopLevelDeclaration); + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new NamespaceNode(Range(keywordTok, closeTok)) + { + Name = name, + Declarations = decls, + }; + } + + public ConstantBufferNode ParseConstantBuffer() + { + var buffer = Eat(TokenKind.CBufferKeyword, TokenKind.TBufferKeyword); + var name = ParseUserDefinedNamedType(); + + RegisterLocationNode reg = null; + if (Match(TokenKind.ColonToken)) + { + reg = ParseRegisterLocation(); + } + + Eat(TokenKind.OpenBraceToken); + + List decls = ParseMany0( + () => !Match(TokenKind.CloseBraceToken), + () => ParseVariableDeclarationStatement(new List())); + + Eat(TokenKind.CloseBraceToken); + if (Match(TokenKind.SemiToken)) + { + Eat(TokenKind.SemiToken); + } + RecoverTo(TokenKind.SemiToken, TokenKind.CloseBraceToken); + + return new ConstantBufferNode(Range(buffer, Previous())) + { + Name = name, + RegisterLocation = reg, + Declarations = decls, + IsTextureBuffer = buffer.Kind == TokenKind.TBufferKeyword + }; + } + + public TypedefNode ParseTypedef(List attributes) + { + var keywordTok = Eat(TokenKind.TypedefKeyword); + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? keywordTok; + + bool isConst = false; + if (Match(TokenKind.ConstKeyword)) + { + Eat(TokenKind.ConstKeyword); + isConst = true; + } + + var type = ParseType(); + + var names = ParseSeparatedList1(TokenKind.CommaToken, ParseUserDefinedNamedType); + + var semiTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + + return new TypedefNode(Range(firstTok, semiTok)) + { + Attributes = attributes, + FromType = type, + ToNames = names, + IsConst = isConst, + }; + } + + public TypeNode ParseType(bool allowVoid = false) + { + if (HLSLSyntaxFacts.TryConvertToPredefinedObjectType(Peek(), out PredefinedObjectType predefinedType)) + { + var firstTok = Advance(); + + List args = new List(); + if (Match(TokenKind.LessThanToken)) + { + Eat(TokenKind.LessThanToken); + args = ParseSeparatedList0( + TokenKind.GreaterThanToken, + TokenKind.CommaToken, + ParseTemplateArgumentType); + Eat(TokenKind.GreaterThanToken); + } + + return new PredefinedObjectTypeNode(Range(firstTok, Previous())) + { + Kind = predefinedType, + TemplateArguments = args, + }; + } + + if (Match(TokenKind.IdentifierToken)) + { + return ParseUserDefinedNamedType(); + } + + if (Match(TokenKind.StructKeyword, TokenKind.ClassKeyword)) + { + return ParseStructType(); + } + + return ParseNumericType(allowVoid); + } + + public StructTypeNode ParseStructType() + { + var keywordTok = Eat(TokenKind.StructKeyword, TokenKind.ClassKeyword); + bool isClass = keywordTok.Kind == TokenKind.ClassKeyword; + var name = ParseOptional(TokenKind.IdentifierToken, ParseUserDefinedNamedType); + + // base list + List baseList = new List(); + if (Match(TokenKind.ColonToken)) + { + Eat(TokenKind.ColonToken); + + baseList = ParseSeparatedList1(TokenKind.CommaToken, ParseUserDefinedNamedType); + } + + Eat(TokenKind.OpenBraceToken); + + List decls = new List(); + List methods = new List(); + while (LoopShouldContinue() && !Match(TokenKind.CloseBraceToken)) + { + if (IsNextPossiblyFunctionDeclaration()) + { + methods.Add(ParseFunction()); + } + else + { + decls.Add(ParseVariableDeclarationStatement(new List())); + } + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + + return new StructTypeNode(Range(keywordTok, closeTok)) + { + Name = name, + Inherits = baseList, + Fields = decls, + Methods = methods, + IsClass = isClass, + }; + } + + public NumericTypeNode ParseNumericType(bool allowVoid = false) + { + HLSLToken typeToken = Advance(); + if (HLSLSyntaxFacts.TryConvertToScalarType(typeToken.Kind, out ScalarType scalarType)) + { + if (scalarType == ScalarType.Void && !allowVoid) + Error("a type that isn't 'void'", typeToken); + return new ScalarTypeNode(Range(typeToken, typeToken)) { Kind = scalarType }; + } + + if (HLSLSyntaxFacts.TryConvertToMonomorphicVectorType(typeToken.Kind, out ScalarType vectorType, out int dimension)) + { + if (typeToken.Kind == TokenKind.VectorKeyword && Match(TokenKind.LessThanToken)) + { + Eat(TokenKind.LessThanToken); + var genVectorType = ParseNumericType().Kind; + Eat(TokenKind.CommaToken); + int genDim = ParseIntegerLiteral(); + var closeTok = Eat(TokenKind.GreaterThanToken); + return new VectorTypeNode(Range(typeToken, closeTok)) { Kind = genVectorType, Dimension = genDim }; + } + + return new VectorTypeNode(Range(typeToken, typeToken)) { Kind = vectorType, Dimension = dimension }; + } + + if (HLSLSyntaxFacts.TryConvertToMonomorphicMatrixType(typeToken.Kind, out ScalarType matrixType, out int dimX, out int dimY)) + { + if (typeToken.Kind == TokenKind.MatrixKeyword && Match(TokenKind.LessThanToken)) + { + Eat(TokenKind.LessThanToken); + var genMatrixType = ParseNumericType().Kind; + Eat(TokenKind.CommaToken); + int genDimX = ParseIntegerLiteral(); + Eat(TokenKind.CommaToken); + int genDimY = ParseIntegerLiteral(); + var closeTok = Eat(TokenKind.GreaterThanToken); + return new MatrixTypeNode(Range(typeToken, closeTok)) { Kind = genMatrixType, FirstDimension = genDimX, SecondDimension = genDimY }; + } + + return new MatrixTypeNode(Range(typeToken, typeToken)) { Kind = matrixType, FirstDimension = dimX, SecondDimension = dimY }; + } + + if (typeToken.Kind == TokenKind.UnsignedKeyword) + { + var type = ParseNumericType(); + type.Kind = HLSLSyntaxFacts.MakeUnsigned(type.Kind); + return type; + } + + if (typeToken.Kind == TokenKind.UNormKeyword || typeToken.Kind == TokenKind.SNormKeyword) + { + var type = ParseNumericType(); + type.Kind = HLSLSyntaxFacts.MakeNormed(type.Kind, typeToken.Kind); + return type; + } + + Error("a valid type", typeToken); + return new ScalarTypeNode(Range(typeToken, typeToken)) { Kind = ScalarType.Void }; + } + + public UserDefinedNamedTypeNode ParseUserDefinedNamedType() + { + var firstTok = Peek(); + string identifier = ParseIdentifier(); + var name = new NamedTypeNode(Range(firstTok, firstTok)) { Name = identifier }; + + if (Match(TokenKind.ColonColonToken)) + { + Eat(TokenKind.ColonColonToken); + var right = ParseUserDefinedNamedType(); + return new QualifiedNamedTypeNode(Range(firstTok, Previous())) { Left = name, Right = right }; + } + else + { + return name; + } + } + + public TypeNode ParseTemplateArgumentType() + { + if (Match(TokenKind.CharacterLiteralToken, TokenKind.FloatLiteralToken, TokenKind.IntegerLiteralToken, TokenKind.StringLiteralToken)) + { + var expression = ParseLiteralExpression(); + return new LiteralTemplateArgumentType(Range(Previous(), Previous())) { Literal = expression }; + } + + return ParseType(); + } + + public FormalParameterNode ParseFormalParameter() + { + var firstTok = Peek(); + List attributes = ParseMany0(TokenKind.OpenBracketToken, ParseAttribute); + var modifiers = ParseParameterModifiers(); + TypeNode type = ParseType(); + VariableDeclaratorNode declarator = ParseVariableDeclarator(false); + + return new FormalParameterNode(Range(firstTok, Previous())) + { + Attributes = attributes, + Modifiers = modifiers, + ParamType = type, + Declarator = declarator + }; + } + + public ArrayRankNode ParseArrayRank() + { + var openTok = Eat(TokenKind.OpenBracketToken); + ExpressionNode expr = null; + if (!Match(TokenKind.CloseBracketToken)) + { + expr = ParseExpression(); + } + var closeTok = Eat(TokenKind.CloseBracketToken); + return new ArrayRankNode(Range(openTok, closeTok)) { Dimension = expr }; + } + + public VariableDeclaratorNode ParseVariableDeclarator(bool allowCompoundInitializer = true) + { + var firstTok = Peek(); + string identifier = ParseIdentifier(); + + List arrayRanks = new List(); + while (Match(TokenKind.OpenBracketToken)) + { + arrayRanks.Add(ParseArrayRank()); + } + + List qualifiers = ParseMany0(TokenKind.ColonToken, ParseVariableDeclaratorQualifierNode); + + List annotations = new List(); + if (Match(TokenKind.LessThanToken)) + { + Eat(TokenKind.LessThanToken); + annotations = ParseMany0(() => !Match(TokenKind.GreaterThanToken), () => ParseVariableDeclarationStatement(new List())); + Eat(TokenKind.GreaterThanToken); + } + + InitializerNode initializer = null; + if (Match(TokenKind.EqualsToken)) + { + initializer = ParseValueInitializer(allowCompoundInitializer); + } + else if (Match(TokenKind.OpenBraceToken)) + { + initializer = ParseStateInitializerOrArray(); + } + + return new VariableDeclaratorNode(Range(firstTok, Previous())) + { + Name = identifier, + ArrayRanks = arrayRanks, + Qualifiers = qualifiers, + Annotations = annotations, + Initializer = initializer, + }; + } + + public ValueInitializerNode ParseValueInitializer(bool allowCompoundInitializer = true) + { + var eqTok = Eat(TokenKind.EqualsToken); + var expr = ParseExpression(allowCompoundInitializer ? 0 : (int)OperatorPrecedence.Compound + 1); + return new ValueInitializerNode(Range(eqTok, Previous())) { Expression = expr }; + } + + public StateInitializerNode ParseStateInitializer() + { + var openTok = Eat(TokenKind.OpenBraceToken); + List states = new List(); + while (Match(TokenKind.IdentifierToken)) + { + states.Add(ParseStateProperty()); + } + var closeTok = Eat(TokenKind.CloseBraceToken); + return new StateInitializerNode(Range(openTok, closeTok)) { States = states }; + } + + public InitializerNode ParseStateInitializerOrArray() + { + if (LookAhead().Kind == TokenKind.OpenBraceToken) + { + var openTok = Eat(TokenKind.OpenBraceToken); + List initializers = ParseSeparatedList0(TokenKind.CloseBraceToken, TokenKind.CommaToken, ParseStateInitializer); + var closeTok = Eat(TokenKind.CloseBraceToken); + return new StateArrayInitializerNode(Range(openTok, closeTok)) { Initializers = initializers }; + } + else + { + return ParseStateInitializer(); + } + } + + public VariableDeclaratorQualifierNode ParseVariableDeclaratorQualifierNode() + { + switch (LookAhead().Kind) + { + case TokenKind.IdentifierToken: return ParseSemantic(); + case TokenKind.RegisterKeyword: return ParseRegisterLocation(); + case TokenKind.PackoffsetKeyword: return ParsePackoffsetNode(); + default: return ParseSemantic(); + } + } + + public SemanticNode ParseSemantic() + { + var colTok = Eat(TokenKind.ColonToken); + string identifier = ParseIdentifier(); + return new SemanticNode(Range(colTok, Previous())) { Name = identifier }; + } + + public RegisterLocationNode ParseRegisterLocation() + { + var colTok = Eat(TokenKind.ColonToken); + Eat(TokenKind.RegisterKeyword); + Eat(TokenKind.OpenParenToken); + + string location = ParseIdentifier(); + RegisterKind kind = default; + int index = 0; + switch (location.ToLower().FirstOrDefault()) + { + case 't': kind = RegisterKind.Texture; break; + case 'b': kind = RegisterKind.Buffer; break; + case 'u': kind = RegisterKind.UAV; break; + case 's': kind = RegisterKind.Sampler; break; + default: break; + } + string indexLexeme = string.Concat(location.SkipWhile(x => !char.IsNumber(x))); + if (!int.TryParse(indexLexeme, out index)) + { + Error(DiagnosticFlags.SemanticError, $"Expected a valid register location, but got '{location}'."); + } + + int? spaceIndex = null; + if (Match(TokenKind.CommaToken)) + { + Eat(TokenKind.CommaToken); + + string space = ParseIdentifier(); + string spaceLexeme = string.Concat(space.SkipWhile(x => !char.IsNumber(x))); + if (int.TryParse(spaceLexeme, out int parsedIndex)) + { + spaceIndex = parsedIndex; + } + else + { + Error(DiagnosticFlags.SemanticError, $"Expected a valid space, but got '{location}'."); + } + } + + var closeTok = Eat(TokenKind.CloseParenToken); + + return new RegisterLocationNode(Range(colTok, closeTok)) + { + Kind = kind, + Location = index, + Space = spaceIndex, + }; + } + + public PackoffsetNode ParsePackoffsetNode() + { + var colTok = Eat(TokenKind.ColonToken); + Eat(TokenKind.PackoffsetKeyword); + Eat(TokenKind.OpenParenToken); + + string location = ParseIdentifier(); + int index = 0; + string indexLexeme = string.Concat(location.SkipWhile(x => !char.IsNumber(x))); + if (!int.TryParse(indexLexeme, out index)) + { + Error(DiagnosticFlags.SemanticError, $"Expected a valid packoffset location, but got '{location}'."); + } + + string swizzle = null; + if (Match(TokenKind.DotToken)) + { + Eat(TokenKind.DotToken); + swizzle = ParseIdentifier(); + } + + var closeTok = Eat(TokenKind.CloseParenToken); + + return new PackoffsetNode(Range(colTok, closeTok)) + { + Location = index, + Swizzle = swizzle, + }; + } + + public BlockNode ParseBlock(List attributes) + { + var openTok = Eat(TokenKind.OpenBraceToken); + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? openTok; + List statements = ParseMany0(() => !Match(TokenKind.CloseBraceToken), ParseStatement); + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new BlockNode(Range(firstTok, closeTok)) + { + Attributes = attributes, + Statements = statements, + }; + } + + private bool IsVariableDeclarationStatement(TokenKind nextKind) + { + if (HLSLSyntaxFacts.IsModifier(nextKind)) + return true; + if ((HLSLSyntaxFacts.IsBuiltinType(nextKind) || nextKind == TokenKind.IdentifierToken)) + { + return Speculate(() => + { + ParseType(); + return Match(TokenKind.IdentifierToken); + }); + } + return false; + } + + public StatementNode ParseStatement() + { + var firstTok = Peek(); + List attributes = ParseMany0(TokenKind.OpenBracketToken, ParseAttribute); + + HLSLToken next = Peek(); + switch (next.Kind) + { + case TokenKind.SemiToken: + var emptySemiTok = Advance(); + return new EmptyStatementNode(Range(firstTok, emptySemiTok)) { Attributes = attributes }; + + case TokenKind.OpenBraceToken: + return ParseBlock(attributes); + + case TokenKind.ReturnKeyword: + Advance(); + ExpressionNode returnExpr = null; + if (!Match(TokenKind.SemiToken)) + { + returnExpr = ParseExpression(); + } + var returnSemiTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + return new ReturnStatementNode(Range(firstTok, returnSemiTok)) { Attributes = attributes, Expression = returnExpr }; + + case TokenKind.ForKeyword: + return ParseForStatement(attributes); + + case TokenKind.WhileKeyword: + return ParseWhileStatement(attributes); + + case TokenKind.DoKeyword: + return ParseDoWhileStatement(attributes); + + case TokenKind.IfKeyword: + return ParseIfStatement(attributes); + + case TokenKind.SwitchKeyword: + return ParseSwitchStatement(attributes); + + case TokenKind.TypedefKeyword: + return ParseTypedef(attributes); + + case TokenKind.BreakKeyword: + Advance(); + var breakTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + return new BreakStatementNode(Range(firstTok, breakTok)) { Attributes = attributes }; + + case TokenKind.ContinueKeyword: + Advance(); + var continueTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + return new ContinueStatementNode(Range(firstTok, continueTok)) { Attributes = attributes }; + + case TokenKind.DiscardKeyword: + Advance(); + var discardTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + return new DiscardStatementNode(Range(firstTok, discardTok)) { Attributes = attributes }; + + case TokenKind.InterfaceKeyword: + return ParseInterfaceDefinition(attributes); + + case TokenKind.StructKeyword: + case TokenKind.ClassKeyword: + return ParseStructDefinitionOrDeclaration(attributes); + + case TokenKind kind when IsVariableDeclarationStatement(kind): + return ParseVariableDeclarationStatement(attributes); + + case var _ when IsNextPreProcessorDirective(): + return ParsePreProcessorDirective(ParseStatement); + + default: + ExpressionNode expr = ParseExpression(); + var exprSemiTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + return new ExpressionStatementNode(Range(firstTok, exprSemiTok)) { Attributes = attributes, Expression = expr }; + } + } + + public List ParseParameterModifiers() + { + List modifiers = new List(); + while (HLSLSyntaxFacts.TryConvertToParameterModifier(Peek(), out var modifier)) + { + Advance(); + modifiers.Add(modifier); + } + return modifiers; + } + + public List ParseDeclarationModifiers() + { + List modifiers = new List(); + while (HLSLSyntaxFacts.TryConvertToDeclarationModifier(Peek(), out var modifier)) + { + Advance(); + modifiers.Add(modifier); + } + return modifiers; + } + + public VariableDeclarationStatementNode ParseVariableDeclarationStatement(List attributes) + { + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? Peek(); + var modifiers = ParseDeclarationModifiers(); + TypeNode kind = ParseType(); + List variables = ParseSeparatedList1(TokenKind.CommaToken, () => ParseVariableDeclarator()); + var semiTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + + return new VariableDeclarationStatementNode(Range(firstTok, semiTok)) + { + Modifiers = modifiers, + Kind = kind, + Declarators = variables, + Attributes = attributes, + }; + } + + public ForStatementNode ParseForStatement(List attributes) + { + var keywordTok = Eat(TokenKind.ForKeyword); + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? keywordTok; + Eat(TokenKind.OpenParenToken); + + VariableDeclarationStatementNode decl = null; + ExpressionNode initializer = null; + if (!Match(TokenKind.SemiToken)) + { + if (!TryParse(() => ParseVariableDeclarationStatement(new List()), out decl)) + { + if (TryParse(() => ParseExpression(), out initializer)) + { + Eat(TokenKind.SemiToken); + } + else + { + Error("an expression or declaration in first section of for loop", Peek()); + } + } + } + else + { + Eat(TokenKind.SemiToken); + } + + ExpressionNode cond = null; + if (!Match(TokenKind.SemiToken)) + { + cond = ParseExpression(); + } + Eat(TokenKind.SemiToken); + + ExpressionNode incrementor = null; + if (!Match(TokenKind.SemiToken)) + { + incrementor = ParseExpression(); + } + Eat(TokenKind.CloseParenToken); + + var body = ParseStatement(); + RecoverTo(TokenKind.SemiToken, TokenKind.CloseBraceToken); + + return new ForStatementNode(Range(firstTok, Previous())) + { + Declaration = decl, + Condition = cond, + Increment = incrementor, + Body = body, + Attributes = attributes, + }; + } + + public WhileStatementNode ParseWhileStatement(List attributes) + { + var keywordTok = Eat(TokenKind.WhileKeyword); + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? keywordTok; + Eat(TokenKind.OpenParenToken); + + var cond = ParseExpression(); + + Eat(TokenKind.CloseParenToken); + + var body = ParseStatement(); + RecoverTo(TokenKind.SemiToken, TokenKind.CloseBraceToken); + + return new WhileStatementNode(Range(firstTok, Previous())) + { + Attributes = attributes, + Condition = cond, + Body = body, + }; + } + + public DoWhileStatementNode ParseDoWhileStatement(List attributes) + { + var keywordTok = Eat(TokenKind.DoKeyword); + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? keywordTok; + var body = ParseStatement(); + + Eat(TokenKind.WhileKeyword); + Eat(TokenKind.OpenParenToken); + + var cond = ParseExpression(); + + Eat(TokenKind.CloseParenToken); + var semiTok = Eat(TokenKind.SemiToken); + RecoverTo(TokenKind.SemiToken); + + return new DoWhileStatementNode(Range(firstTok, semiTok)) + { + Attributes = attributes, + Body = body, + Condition = cond, + }; + } + + public IfStatementNode ParseIfStatement(List attributes) + { + var keywordTok = Eat(TokenKind.IfKeyword); + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? keywordTok; + Eat(TokenKind.OpenParenToken); + + var cond = ParseExpression(); + + Eat(TokenKind.CloseParenToken); + + var body = ParseStatement(); + + StatementNode elseClause = null; + if (Match(TokenKind.ElseKeyword)) + { + Eat(TokenKind.ElseKeyword); + elseClause = ParseStatement(); + } + RecoverTo(TokenKind.SemiToken, TokenKind.CloseBraceToken); + + return new IfStatementNode(Range(firstTok, Previous())) + { + Attributes = attributes, + Condition = cond, + Body = body, + ElseClause = elseClause, + }; + } + + public SwitchStatementNode ParseSwitchStatement(List attributes) + { + var keywordTok = Eat(TokenKind.SwitchKeyword); + var firstTok = attributes.FirstOrDefault()?.Tokens.FirstOrDefault() ?? keywordTok; + Eat(TokenKind.OpenParenToken); + var expr = ParseExpression(); + Eat(TokenKind.CloseParenToken); + Eat(TokenKind.OpenBraceToken); + + List switchClauses = new List(); + while (Match(TokenKind.CaseKeyword, TokenKind.DefaultKeyword)) + { + var clauseStartTok = Peek(); + List switchLabels = new List(); + while (Match(TokenKind.CaseKeyword, TokenKind.DefaultKeyword)) + { + if (Match(TokenKind.CaseKeyword)) + { + var caseTok = Eat(TokenKind.CaseKeyword); + var caseExpr = ParseExpression(); + Eat(TokenKind.ColonToken); + switchLabels.Add(new SwitchCaseLabelNode(Range(caseTok, Previous())) { Value = caseExpr }); + } + else + { + var defaultTok = Eat(TokenKind.DefaultKeyword); + Eat(TokenKind.ColonToken); + switchLabels.Add(new SwitchDefaultLabelNode(Range(defaultTok, Previous())) { }); + } + } + + List statements = ParseMany0( + () => !Match(TokenKind.CloseBraceToken, TokenKind.CaseKeyword, TokenKind.DefaultKeyword), + ParseStatement); + switchClauses.Add(new SwitchClauseNode(Range(clauseStartTok, Previous())) { Labels = switchLabels, Statements = statements }); + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new SwitchStatementNode(Range(firstTok, closeTok)) + { + Attributes = attributes, + Expression = expr, + Clauses = switchClauses, + }; + } + + public TechniqueNode ParseTechnique() + { + var keywordTok = Eat(TokenKind.TechniqueKeyword, TokenKind.Technique10Keyword, TokenKind.Technique11Keyword); + int version = keywordTok.Kind == TokenKind.Technique10Keyword ? 10 : 11; + + UserDefinedNamedTypeNode name = null; + if (Match(TokenKind.IdentifierToken)) + { + name = ParseUserDefinedNamedType(); + } + + List annotations = new List(); + if (Match(TokenKind.LessThanToken)) + { + Eat(TokenKind.LessThanToken); + annotations = ParseMany0(() => !Match(TokenKind.GreaterThanToken), () => ParseVariableDeclarationStatement(new List())); + Eat(TokenKind.GreaterThanToken); + } + + Eat(TokenKind.OpenBraceToken); + var passes = ParseMany0(TokenKind.PassKeyword, ParsePass); + Eat(TokenKind.CloseBraceToken); + + if (Match(TokenKind.SemiToken)) + { + Eat(TokenKind.SemiToken); + } + RecoverTo(TokenKind.SemiToken, TokenKind.CloseBraceToken); + + return new TechniqueNode(Range(keywordTok, Previous())) + { + Name = name, + Annotations = annotations, + Version = version, + Passes = passes + }; + } + + public PassNode ParsePass() + { + var keywordTok = Eat(TokenKind.PassKeyword); + UserDefinedNamedTypeNode name = null; + if (Match(TokenKind.IdentifierToken)) + { + name = ParseUserDefinedNamedType(); + } + + List annotations = new List(); + if (Match(TokenKind.LessThanToken)) + { + Eat(TokenKind.LessThanToken); + annotations = ParseMany0(() => !Match(TokenKind.GreaterThanToken), () => ParseVariableDeclarationStatement(new List())); + Eat(TokenKind.GreaterThanToken); + } + + Eat(TokenKind.OpenBraceToken); + var statements = ParseMany0(() => !Match(TokenKind.CloseBraceToken), () => + { + if (TryParse(ParseStatement, out var stmt)) + { + return stmt; + } + // Assume state property + else + { + return ParseStateProperty(); + } + }); + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new PassNode(Range(keywordTok, closeTok)) + { + Name = name, + Annotations = annotations, + Statements = statements + }; + } + + private bool IsNextPreProcessorDirective() + { + switch (Peek().Kind) + { + case TokenKind.DefineDirectiveKeyword: + case TokenKind.IncludeDirectiveKeyword: + case TokenKind.LineDirectiveKeyword: + case TokenKind.UndefDirectiveKeyword: + case TokenKind.ErrorDirectiveKeyword: + case TokenKind.PragmaDirectiveKeyword: + case TokenKind.IfDirectiveKeyword: + case TokenKind.IfdefDirectiveKeyword: + case TokenKind.IfndefDirectiveKeyword: + return true; + default: + return false; + } + } + + public PreProcessorDirectiveNode ParsePreProcessorDirective(Func recurse) + { + var next = Peek(); + switch (next.Kind) + { + case TokenKind.DefineDirectiveKeyword: + return ParseDefineDirective(); + case TokenKind.IncludeDirectiveKeyword: + return ParseIncludeDirective(); + case TokenKind.LineDirectiveKeyword: + return ParseLineDirective(); + case TokenKind.UndefDirectiveKeyword: + return ParseUndefDirective(); + case TokenKind.ErrorDirectiveKeyword: + return ParseErrorDirective(); + case TokenKind.PragmaDirectiveKeyword: + return ParsePragmaDirective(); + case TokenKind.IfDirectiveKeyword: + return ParseIfDirective(recurse, false); + case TokenKind.IfdefDirectiveKeyword: + return ParseIfDefDirective(recurse); + case TokenKind.IfndefDirectiveKeyword: + return ParseIfNotDefDirective(recurse); + default: + Error("a valid preprocessor directive", next); + return null; + } + } + + public PreProcessorDirectiveNode ParseDefineDirective() + { + var keywordTok = Eat(TokenKind.DefineDirectiveKeyword); + string ident = ParseIdentifier(); + + // Function like + if (Match(TokenKind.OpenFunctionLikeMacroParenToken)) + { + Eat(TokenKind.OpenFunctionLikeMacroParenToken); + var args = ParseSeparatedList0(TokenKind.CloseParenToken, TokenKind.CommaToken, ParseIdentifier); + Eat(TokenKind.CloseParenToken); + var tokens = ParseMany0(() => !Match(TokenKind.EndDirectiveToken), () => Advance()); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + return new FunctionLikeMacroNode(Range(keywordTok, endTok)) + { + Name = ident, + Arguments = args, + Value = tokens, + }; + } + else + { + var tokens = ParseMany0(() => !Match(TokenKind.EndDirectiveToken), () => Advance()); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + return new ObjectLikeMacroNode(Range(keywordTok, endTok)) + { + Name = ident, + Value = tokens, + }; + } + } + + public IncludeDirectiveNode ParseIncludeDirective() + { + var keywordTok = Eat(TokenKind.IncludeDirectiveKeyword); + string ident = Eat(TokenKind.StringLiteralToken, TokenKind.SystemIncludeLiteralToken).Identifier; + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + return new IncludeDirectiveNode(Range(keywordTok, endTok)) { Path = ident }; + } + + public LineDirectiveNode ParseLineDirective() + { + var keywordTok = Eat(TokenKind.LineDirectiveKeyword); + int line = ParseIntegerLiteral(); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + return new LineDirectiveNode(Range(keywordTok, endTok)) { Line = line }; + } + + public UndefDirectiveNode ParseUndefDirective() + { + var keywordTok = Eat(TokenKind.UndefDirectiveKeyword); + string ident = ParseIdentifier(); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + return new UndefDirectiveNode(Range(keywordTok, endTok)) { Name = ident }; + } + + public ErrorDirectiveNode ParseErrorDirective() + { + var keywordTok = Eat(TokenKind.ErrorDirectiveKeyword); + var tokens = ParseMany0(() => !Match(TokenKind.EndDirectiveToken), () => Advance()); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + return new ErrorDirectiveNode(Range(keywordTok, endTok)) { Value = tokens }; + } + + public PragmaDirectiveNode ParsePragmaDirective() + { + var keywordTok = Eat(TokenKind.PragmaDirectiveKeyword); + var tokens = ParseMany0(() => !Match(TokenKind.EndDirectiveToken), () => Advance()); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + return new PragmaDirectiveNode(Range(keywordTok, endTok)) { Value = tokens }; + } + + public IfDirectiveNode ParseIfDirective(Func recurse, bool elif) + { + var keywordTok = elif ? Eat(TokenKind.ElifDirectiveKeyword) : Eat(TokenKind.IfDirectiveKeyword); + var expr = ParseExpression(); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + var body = ParseMany0(() => !Match(TokenKind.ElseDirectiveKeyword, TokenKind.ElifDirectiveKeyword, TokenKind.EndifDirectiveKeyword), recurse); + var elseClause = ParseDirectiveConditionalRemainder(recurse); + return new IfDirectiveNode(Range(keywordTok, Previous())) + { + Condition = expr, + Body = body, + ElseClause = elseClause, + }; + } + + public IfDefDirectiveNode ParseIfDefDirective(Func recurse) + { + var keywordTok = Eat(TokenKind.IfdefDirectiveKeyword); + string ident = ParseIdentifier(); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + var body = ParseMany0(() => !Match(TokenKind.ElseDirectiveKeyword, TokenKind.ElifDirectiveKeyword, TokenKind.EndifDirectiveKeyword), recurse); + var elseClause = ParseDirectiveConditionalRemainder(recurse); + return new IfDefDirectiveNode(Range(keywordTok, Previous())) + { + Condition = ident, + Body = body, + ElseClause = elseClause, + }; + } + + public IfNotDefDirectiveNode ParseIfNotDefDirective(Func recurse) + { + var keywordTok = Eat(TokenKind.IfndefDirectiveKeyword); + string ident = ParseIdentifier(); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + var body = ParseMany0(() => !Match(TokenKind.ElseDirectiveKeyword, TokenKind.ElifDirectiveKeyword, TokenKind.EndifDirectiveKeyword), recurse); + var elseClause = ParseDirectiveConditionalRemainder(recurse); + return new IfNotDefDirectiveNode(Range(keywordTok, Previous())) + { + Condition = ident, + Body = body, + ElseClause = elseClause, + }; + } + + public PreProcessorDirectiveNode ParseDirectiveConditionalRemainder(Func recurse) + { + PreProcessorDirectiveNode elseClause = null; + var next = Peek(); + switch (next.Kind) + { + case TokenKind.ElseDirectiveKeyword: + var keywordTok = Eat(TokenKind.ElseDirectiveKeyword); + Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + var body = ParseMany0(() => !Match(TokenKind.EndifDirectiveKeyword), recurse); + Eat(TokenKind.EndifDirectiveKeyword); + var endTokElse = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + elseClause = new ElseDirectiveNode(Range(keywordTok, endTokElse)) { Body = body }; + break; + case TokenKind.ElifDirectiveKeyword: + elseClause = ParseIfDirective(recurse, true); + break; + case TokenKind.EndifDirectiveKeyword: + Eat(TokenKind.EndifDirectiveKeyword); + var endTok = Eat(TokenKind.EndDirectiveToken); + RecoverTo(TokenKind.EndDirectiveToken); + break; + default: + Error("a valid preprocessor directive", next); + break; + } + return elseClause; + } + } +} + + +// HLSL/HLSLPrinter.cs +namespace UnityShaderParser.HLSL +{ + public class HLSLPrinter : HLSLSyntaxVisitor + { + // Settings + public int MaxParametersUntilLineBreak { get; set; } = 4; + public bool IndentBlockLikeSwitchClauses { get; set; } = false; + + // State and helpers + private StringBuilder sb = new StringBuilder(); + public string Text => sb.ToString(); + + private int indentLevel = 0; + private void PushIndent() => indentLevel++; + private void PopIndent() => indentLevel--; + private string Indent() => new string(' ', indentLevel * 4); + + private void Emit(string text) => sb.Append(text); + private void EmitLine(string text = "") => sb.AppendLine(text); + private void EmitIndented(string text = "") + { + sb.Append(Indent()); + sb.Append(text); + } + private void EmitIndentedLine(string text) + { + sb.Append(Indent()); + sb.AppendLine(text); + } + + private Stack expressionPrecedences = new Stack(); + + protected void VisitManySeparated(IList nodes, string separator, bool trailing = false, bool leading = false) + where T : HLSLSyntaxNode + { + if (leading && nodes.Count > 0) + { + Emit(separator); + } + VisitMany(nodes, () => Emit(separator)); + if (trailing && nodes.Count > 0) + { + Emit(separator); + } + } + + protected void EmitExpression(OperatorPrecedence prec, Action expressionEmitter) + { + int precedence = (int)prec; + bool needsParen = false; + if (expressionPrecedences.Count > 0 && expressionPrecedences.Peek() >= precedence) + { + needsParen = true; + } + + expressionPrecedences.Push(precedence); + if (needsParen) Emit("("); + expressionEmitter(); + if (needsParen) Emit(")"); + expressionPrecedences.Pop(); + } + + // Visitor implementation + public override void VisitFormalParameterNode(FormalParameterNode node) + { + VisitManySeparated(node.Attributes, " ", true); + string modifiers = string.Join("", node.Modifiers.Select(PrintingUtil.GetEnumName).Select(x => x + " ")); + Emit(modifiers); + Visit(node.ParamType); + Emit(" "); + Visit(node.Declarator); + } + public override void VisitVariableDeclaratorNode(VariableDeclaratorNode node) + { + Emit(node.Name); + VisitMany(node.ArrayRanks); + VisitMany(node.Qualifiers); + if (node.Annotations?.Count > 0) + { + EmitLine(); + EmitIndentedLine("<"); + PushIndent(); + VisitMany(node.Annotations); + PopIndent(); + EmitIndented(">"); + } + Visit(node.Initializer); + } + public override void VisitArrayRankNode(ArrayRankNode node) + { + Emit("["); + Visit(node.Dimension); + Emit("]"); + } + public override void VisitValueInitializerNode(ValueInitializerNode node) + { + Emit(" = "); + Visit(node.Expression); + } + public override void VisitStateInitializerNode(StateInitializerNode node) + { + EmitLine(); + EmitIndentedLine("{"); + PushIndent(); + VisitMany(node.States); + PopIndent(); + EmitIndented("}"); + } + public override void VisitStateArrayInitializerNode(StateArrayInitializerNode node) + { + EmitLine(); + EmitIndentedLine("{"); + PushIndent(); + VisitManySeparated(node.Initializers, ","); + PopIndent(); + EmitLine(); + EmitIndented("}"); + } + private void VisitFunctionNode(FunctionNode node) + { + EmitIndented(); + string modifiers = string.Join("", node.Modifiers.Select(PrintingUtil.GetEnumName).Select(x => x + " ")); + Emit(modifiers); + VisitManySeparated(node.Attributes, " ", true); + if (node.Attributes.Count > 0) EmitLine(); + Visit(node.ReturnType); + Emit(" "); + Visit(node.Name); + Emit("("); + if (node.Parameters?.Count > MaxParametersUntilLineBreak) + { + EmitLine(); + PushIndent(); + for (int i = 0; i < node.Parameters.Count; i++) + { + EmitIndented(); + Visit(node.Parameters[i]); + if (i < node.Parameters.Count - 1) + EmitLine(","); + } + PopIndent(); + } + else + { + VisitManySeparated(node.Parameters, ", "); + } + Emit(")"); + Visit(node.Semantic); + } + public override void VisitFunctionDeclarationNode(FunctionDeclarationNode node) + { + VisitFunctionNode(node); + EmitLine(";"); + } + public override void VisitFunctionDefinitionNode(FunctionDefinitionNode node) + { + VisitFunctionNode(node); + EmitLine(); + if (node.BodyIsSingleStatement) + { + EmitIndented(); + } + Visit(node.Body); + } + public override void VisitStructDefinitionNode(StructDefinitionNode node) + { + EmitIndented(); + VisitManySeparated(node.Attributes, " ", true); + Visit(node.StructType); + EmitLine(";"); + } + public override void VisitInterfaceDefinitionNode(InterfaceDefinitionNode node) + { + EmitIndented(); + VisitManySeparated(node.Attributes, " ", true); + Emit("interface "); + Visit(node.Name); + EmitLine(); + EmitIndentedLine("{"); + PushIndent(); + VisitMany(node.Functions); + PopIndent(); + EmitIndentedLine("};"); + } + public override void VisitConstantBufferNode(ConstantBufferNode node) + { + if (node.IsTextureBuffer) + { + Emit("tbuffer "); + } + else + { + Emit("cbuffer "); + } + Visit(node.Name); + Visit(node.RegisterLocation); + EmitLine(); + EmitIndentedLine("{"); + PushIndent(); + VisitMany(node.Declarations); + PopIndent(); + EmitIndentedLine("}"); + } + public override void VisitNamespaceNode(NamespaceNode node) + { + EmitIndented("namespace "); + Visit(node.Name); + EmitLine(); + EmitIndentedLine("{"); + PushIndent(); + VisitMany(node.Declarations); + PopIndent(); + EmitIndentedLine("}"); + } + public override void VisitTypedefNode(TypedefNode node) + { + EmitIndented(); + VisitManySeparated(node.Attributes, " ", true); + Emit("typedef "); + if (node.IsConst) + { + Emit("const "); + } + Visit(node.FromType); + Emit(" "); + VisitManySeparated(node.ToNames, ", "); + EmitLine(";"); + } + public override void VisitSemanticNode(SemanticNode node) + { + Emit($" : {node.Name}"); + } + public override void VisitRegisterLocationNode(RegisterLocationNode node) + { + Emit($" : register({PrintingUtil.GetEnumName(node.Kind)}{node.Location}"); + if (node.Space != null) + { + Emit($", space{node.Space})"); + } + else + { + Emit(")"); + } + } + public override void VisitPackoffsetNode(PackoffsetNode node) + { + Emit($" : packoffset(c{node.Location}"); + if (string.IsNullOrEmpty(node.Swizzle)) + { + Emit(")"); + } + else + { + Emit($".{node.Swizzle})"); + } + } + public override void VisitBlockNode(BlockNode node) + { + EmitIndented(); + VisitManySeparated(node.Attributes, " ", true); + EmitLine("{"); + PushIndent(); + VisitMany(node.Statements); + PopIndent(); + EmitIndentedLine("}"); + } + public override void VisitVariableDeclarationStatementNode(VariableDeclarationStatementNode node) + { + bool partOfFor = node.Parent is ForStatementNode forStatement && forStatement.Declaration == node; + + if (!partOfFor) EmitIndented(); + VisitManySeparated(node.Attributes, " ", true); + string modifiers = string.Join("", node.Modifiers.Select(PrintingUtil.GetEnumName).Select(x => x + " ")); + Emit(modifiers); + Visit(node.Kind); + Emit(" "); + VisitManySeparated(node.Declarators, ", "); + Emit(";"); + if (!partOfFor) EmitLine(); + } + public override void VisitReturnStatementNode(ReturnStatementNode node) + { + if (node.Expression != null) + { + EmitIndented("return "); + Visit(node.Expression); + EmitLine(";"); + } + else + { + EmitIndentedLine("return;"); + } + } + + public override void VisitBreakStatementNode(BreakStatementNode node) + { + EmitIndentedLine("break;"); + } + public override void VisitContinueStatementNode(ContinueStatementNode node) + { + EmitIndentedLine("continue;"); + } + public override void VisitDiscardStatementNode(DiscardStatementNode node) + { + EmitIndentedLine("discard;"); + } + public override void VisitEmptyStatementNode(EmptyStatementNode node) + { + EmitIndentedLine(";"); + } + public override void VisitForStatementNode(ForStatementNode node) + { + EmitIndented(); + VisitManySeparated(node.Attributes, " ", true); + Emit("for ("); + if (node.FirstIsDeclaration) + { + Visit(node.Declaration); + Emit(" "); + } + else + { + Visit(node.Initializer); + Emit("; "); + } + + Visit(node.Condition); + Emit("; "); + + Visit(node.Increment); + EmitLine(")"); + if (node.BodyIsSingleStatement) + { + EmitIndented(); + } + Visit(node.Body); + } + public override void VisitWhileStatementNode(WhileStatementNode node) + { + EmitIndented(); + VisitManySeparated(node.Attributes, " ", true); + Emit("while ("); + Visit(node.Condition); + EmitLine(")"); + if (node.BodyIsSingleStatement) + { + EmitIndented(); + } + Visit(node.Body); + } + public override void VisitDoWhileStatementNode(DoWhileStatementNode node) + { + EmitIndented(); + VisitManySeparated(node.Attributes, " ", true); + EmitLine("do"); + if (node.BodyIsSingleStatement) + { + EmitIndented(); + } + Visit(node.Body); + EmitIndented("while ("); + Visit(node.Condition); + EmitLine(");"); + } + public override void VisitIfStatementNode(IfStatementNode node) + { + if (!node.BodyIsElseIfClause) + { + EmitIndented(); + } + VisitManySeparated(node.Attributes, " ", true); + Emit("if ("); + Visit(node.Condition); + EmitLine(")"); + if (node.BodyIsSingleStatement) + { + EmitIndented(); + } + Visit(node.Body); + if (node.ElseClause != null) + { + EmitIndented("else "); + if (node.ElseClauseIsSingleStatement && !node.ElseClauseIsElseIfClause) + { + EmitLine(); + EmitIndented(); + } + else if (!node.ElseClauseIsElseIfClause) + { + EmitLine(); + } + + Visit(node.ElseClause); + } + } + public override void VisitSwitchStatementNode(SwitchStatementNode node) + { + EmitIndented(); + VisitManySeparated(node.Attributes, " ", true); + Emit("switch ("); + Visit(node.Expression); + EmitLine(")"); + EmitIndentedLine("{"); + PushIndent(); + VisitMany(node.Clauses); + PopIndent(); + EmitIndentedLine("}"); + } + public override void VisitSwitchClauseNode(SwitchClauseNode node) + { + VisitMany(node.Labels); + bool isSingleBlock = node.Statements.Count == 1 && node.Statements[0] is BlockNode; + if (!isSingleBlock && !IndentBlockLikeSwitchClauses) PushIndent(); + VisitMany(node.Statements); + if (!isSingleBlock && !IndentBlockLikeSwitchClauses) PopIndent(); + } + public override void VisitSwitchCaseLabelNode(SwitchCaseLabelNode node) + { + EmitIndented("case "); + Visit(node.Value); + EmitLine(":"); + } + public override void VisitSwitchDefaultLabelNode(SwitchDefaultLabelNode node) + { + EmitIndentedLine("default:"); + } + public override void VisitExpressionStatementNode(ExpressionStatementNode node) + { + EmitIndented(); + Visit(node.Expression); + EmitLine(";"); + } + public override void VisitAttributeNode(AttributeNode node) + { + Emit("["); + Emit(node.Name); + if (node.Arguments?.Count > 0) + { + Emit("("); + VisitManySeparated(node.Arguments, ", "); + Emit(")"); + } + Emit("]"); + } + public override void VisitQualifiedIdentifierExpressionNode(QualifiedIdentifierExpressionNode node) + { + Emit(node.GetName()); + } + public override void VisitIdentifierExpressionNode(IdentifierExpressionNode node) + { + Emit(node.GetName()); + } + public override void VisitLiteralExpressionNode(LiteralExpressionNode node) + { + if (node.Kind == LiteralKind.String) + { + Emit($"\"{node.Lexeme}\""); + } + else if (node.Kind == LiteralKind.Character) + { + Emit($"'{node.Lexeme}'"); + } + else + { + Emit(node.Lexeme); + } + } + public override void VisitAssignmentExpressionNode(AssignmentExpressionNode node) + { + EmitExpression(OperatorPrecedence.Assignment, () => + { + Visit(node.Left); + Emit($" {PrintingUtil.GetEnumName(node.Operator)} "); + Visit(node.Right); + }); + } + public override void VisitBinaryExpressionNode(BinaryExpressionNode node) + { + EmitExpression(HLSLSyntaxFacts.GetPrecedence(node.Operator, OperatorFixity.Infix), () => + { + Visit(node.Left); + Emit($" {PrintingUtil.GetEnumName(node.Operator)} "); + Visit(node.Right); + }); + } + public override void VisitCompoundExpressionNode(CompoundExpressionNode node) + { + EmitExpression(OperatorPrecedence.Compound, () => + { + Visit(node.Left); + Emit(", "); + Visit(node.Right); + }); + } + public override void VisitPrefixUnaryExpressionNode(PrefixUnaryExpressionNode node) + { + EmitExpression(OperatorPrecedence.PrefixUnary, () => + { + Emit($"{PrintingUtil.GetEnumName(node.Operator)}"); + Visit(node.Expression); + }); + } + public override void VisitPostfixUnaryExpressionNode(PostfixUnaryExpressionNode node) + { + EmitExpression(OperatorPrecedence.PostFixUnary, () => + { + Visit(node.Expression); + Emit($"{PrintingUtil.GetEnumName(node.Operator)}"); + }); + } + public override void VisitFieldAccessExpressionNode(FieldAccessExpressionNode node) + { + EmitExpression(OperatorPrecedence.PostFixUnary, () => + { + bool needsExtraParen = node.Target is LiteralExpressionNode; // Can't directly swizzle a literal + if (needsExtraParen) Emit("("); + Visit(node.Target); + if (needsExtraParen) Emit(")"); + Emit($".{node.Name}"); + }); + } + public override void VisitMethodCallExpressionNode(MethodCallExpressionNode node) + { + EmitExpression(OperatorPrecedence.PostFixUnary, () => + { + Visit(node.Target); + Emit($".{node.Name}("); + VisitManySeparated(node.Arguments, ", "); + Emit(")"); + }); + } + public override void VisitFunctionCallExpressionNode(FunctionCallExpressionNode node) + { + EmitExpression(OperatorPrecedence.PostFixUnary, () => + { + Visit(node.Name); + Emit("("); + VisitManySeparated(node.Arguments, ", "); + Emit(")"); + }); + } + public override void VisitNumericConstructorCallExpressionNode(NumericConstructorCallExpressionNode node) + { + EmitExpression(OperatorPrecedence.PostFixUnary, () => + { + Visit(node.Kind); + Emit("("); + VisitManySeparated(node.Arguments, ", "); + Emit(")"); + }); + } + public override void VisitElementAccessExpressionNode(ElementAccessExpressionNode node) + { + EmitExpression(OperatorPrecedence.PostFixUnary, () => + { + Visit(node.Target); + Emit("["); + Visit(node.Index); + Emit("]"); + }); + } + public override void VisitCastExpressionNode(CastExpressionNode node) + { + if (node.IsFunctionLike) + { + EmitExpression(OperatorPrecedence.PostFixUnary, () => + { + Visit(node.Kind); + Emit("("); + Visit(node.Expression); + Emit(")"); + }); + } + else + { + EmitExpression(OperatorPrecedence.PrefixUnary, () => + { + Emit("("); + Visit(node.Kind); + VisitMany(node.ArrayRanks); + Emit(")"); + Visit(node.Expression); + }); + } + } + public override void VisitArrayInitializerExpressionNode(ArrayInitializerExpressionNode node) + { + EmitLine(); + EmitIndentedLine("{"); + PushIndent(); + foreach (var element in node.Elements) + { + EmitIndented(); + Visit(element); + EmitLine(","); + } + PopIndent(); + EmitIndented("}"); + } + public override void VisitTernaryExpressionNode(TernaryExpressionNode node) + { + EmitExpression(OperatorPrecedence.Ternary, () => + { + Visit(node.Condition); + Emit(" ? "); + Visit(node.TrueCase); + Emit(" : "); + Visit(node.FalseCase); + }); + } + public override void VisitSamplerStateLiteralExpressionNode(SamplerStateLiteralExpressionNode node) + { + EmitLine("sampler_state"); + EmitIndentedLine("{"); + PushIndent(); + VisitMany(node.States); + PopIndent(); + EmitIndented("}"); + } + public override void VisitCompileExpressionNode(CompileExpressionNode node) + { + Emit($"compile {node.Target} "); + Visit(node.Invocation); + } + public override void VisitQualifiedNamedTypeNode(QualifiedNamedTypeNode node) + { + Emit(node.GetName()); + } + public override void VisitNamedTypeNode(NamedTypeNode node) + { + Emit(node.GetName()); + } + public override void VisitPredefinedObjectTypeNode(PredefinedObjectTypeNode node) + { + Emit(PrintingUtil.GetEnumName(node.Kind)); + if (node.TemplateArguments?.Count > 0) + { + Emit("<"); + VisitManySeparated(node.TemplateArguments, ", "); + Emit(">"); + } + } + public override void VisitStructTypeNode(StructTypeNode node) + { + if (node.IsClass) + { + Emit("class "); + } + else + { + Emit("struct "); + } + + Visit(node.Name); + if (node.Inherits.Count > 0) + { + Emit(" : "); + VisitManySeparated(node.Inherits, ", "); + } + EmitLine(); + EmitIndentedLine("{"); + PushIndent(); + VisitMany(node.Fields); + VisitMany(node.Methods); + PopIndent(); + EmitIndented("}"); + } + public override void VisitScalarTypeNode(ScalarTypeNode node) + { + Emit(PrintingUtil.GetEnumName(node.Kind)); + } + public override void VisitMatrixTypeNode(MatrixTypeNode node) + { + Emit($"{PrintingUtil.GetEnumName(node.Kind)}{node.FirstDimension}x{node.SecondDimension}"); + } + public override void VisitVectorTypeNode(VectorTypeNode node) + { + Emit($"{PrintingUtil.GetEnumName(node.Kind)}{node.Dimension}"); + } + public override void VisitTechniqueNode(TechniqueNode node) + { + Emit(node.Version == 11 ? "technique " : $"technique{node.Version} "); + Visit(node.Name); + EmitLine(); + if (node.Annotations?.Count > 0) + { + EmitIndentedLine("<"); + PushIndent(); + VisitMany(node.Annotations); + PopIndent(); + EmitIndentedLine(">"); + } + EmitIndentedLine("{"); + PushIndent(); + VisitMany(node.Passes); + PopIndent(); + EmitIndentedLine("}"); + } + public override void VisitStatePropertyNode(StatePropertyNode node) + { + EmitIndented(); + Visit(node.Name); + Visit(node.ArrayRank); + Emit(" = "); + if (node.IsReference) Emit("<"); + Visit(node.Value); + if (node.IsReference) Emit(">"); + EmitLine(";"); + } + public override void VisitPassNode(PassNode node) + { + EmitIndented("pass "); + Visit(node.Name); + EmitLine(); + if (node.Annotations?.Count > 0) + { + EmitIndentedLine("<"); + PushIndent(); + VisitMany(node.Annotations); + PopIndent(); + EmitIndentedLine(">"); + } + EmitIndentedLine("{"); + PushIndent(); + VisitMany(node.Statements); + PopIndent(); + EmitIndentedLine("}"); + } + + private string TokensToString(IEnumerable> tokens) + { + return string.Join(" ", tokens.Select(x => HLSLSyntaxFacts.TokenToString(x))); + } + + public override void VisitObjectLikeMacroNode(ObjectLikeMacroNode node) + { + EmitIndentedLine($"#define {node.Name} {TokensToString(node.Value)}"); + } + + public override void VisitFunctionLikeMacroNode(FunctionLikeMacroNode node) + { + EmitIndentedLine($"#define {node.Name}({string.Join(", ", node.Arguments)}) {TokensToString(node.Value)}"); + } + + public override void VisitErrorDirectiveNode(ErrorDirectiveNode node) + { + EmitIndentedLine($"#error {TokensToString(node.Value)}"); + } + + public override void VisitIncludeDirectiveNode(IncludeDirectiveNode node) + { + EmitIndentedLine($"#include \"{node.Path}\""); + } + + public override void VisitLineDirectiveNode(LineDirectiveNode node) + { + EmitIndentedLine($"#line {node.Line}"); + } + + public override void VisitPragmaDirectiveNode(PragmaDirectiveNode node) + { + EmitIndentedLine($"#pragma {TokensToString(node.Value)}"); + } + + public override void VisitUndefDirectiveNode(UndefDirectiveNode node) + { + EmitIndentedLine($"#undef {node.Name}"); + } + + public override void VisitIfDirectiveNode(IfDirectiveNode node) + { + if (node.IsElif) + { + EmitIndented($"#elif "); + } + else + { + EmitIndented($"#if "); + } + Visit(node.Condition); + EmitLine(); + VisitMany(node.Body); + if (node.ElseClause == null) + { + EmitIndentedLine("#endif"); + } + else + { + Visit(node.ElseClause); + } + } + + public override void VisitIfDefDirectiveNode(IfDefDirectiveNode node) + { + EmitIndentedLine($"#ifdef {node.Condition}"); + VisitMany(node.Body); + if (node.ElseClause == null) + { + EmitIndentedLine("#endif"); + } + else + { + Visit(node.ElseClause); + } + } + + public override void VisitIfNotDefDirectiveNode(IfNotDefDirectiveNode node) + { + EmitIndentedLine($"#ifndef {node.Condition}"); + VisitMany(node.Body); + if (node.ElseClause == null) + { + EmitIndentedLine("#endif"); + } + else + { + Visit(node.ElseClause); + } + } + + public override void VisitElseDirectiveNode(ElseDirectiveNode node) + { + EmitIndentedLine("#else"); + VisitMany(node.Body); + EmitIndentedLine("#endif"); + } + } +} + + +// HLSL/HLSLSyntaxElements.cs +namespace UnityShaderParser.HLSL +{ + using HLSLToken = Token; + + #region Common types + public enum TokenKind + { + InvalidToken, + + AppendStructuredBufferKeyword, + BlendStateKeyword, + BoolKeyword, + Bool1Keyword, + Bool2Keyword, + Bool3Keyword, + Bool4Keyword, + Bool1x1Keyword, + Bool1x2Keyword, + Bool1x3Keyword, + Bool1x4Keyword, + Bool2x1Keyword, + Bool2x2Keyword, + Bool2x3Keyword, + Bool2x4Keyword, + Bool3x1Keyword, + Bool3x2Keyword, + Bool3x3Keyword, + Bool3x4Keyword, + Bool4x1Keyword, + Bool4x2Keyword, + Bool4x3Keyword, + Bool4x4Keyword, + BufferKeyword, + ByteAddressBufferKeyword, + BreakKeyword, + CaseKeyword, + CBufferKeyword, + CentroidKeyword, + ClassKeyword, + ColumnMajorKeyword, + CompileKeyword, + ConstKeyword, + ConsumeStructuredBufferKeyword, + ContinueKeyword, + DefaultKeyword, + DefKeyword, + DepthStencilStateKeyword, + DiscardKeyword, + DoKeyword, + DoubleKeyword, + Double1Keyword, + Double2Keyword, + Double3Keyword, + Double4Keyword, + Double1x1Keyword, + Double1x2Keyword, + Double1x3Keyword, + Double1x4Keyword, + Double2x1Keyword, + Double2x2Keyword, + Double2x3Keyword, + Double2x4Keyword, + Double3x1Keyword, + Double3x2Keyword, + Double3x3Keyword, + Double3x4Keyword, + Double4x1Keyword, + Double4x2Keyword, + Double4x3Keyword, + Double4x4Keyword, + ElseKeyword, + ErrorKeyword, + ExportKeyword, + ExternKeyword, + FloatKeyword, + Float1Keyword, + Float2Keyword, + Float3Keyword, + Float4Keyword, + Float1x1Keyword, + Float1x2Keyword, + Float1x3Keyword, + Float1x4Keyword, + Float2x1Keyword, + Float2x2Keyword, + Float2x3Keyword, + Float2x4Keyword, + Float3x1Keyword, + Float3x2Keyword, + Float3x3Keyword, + Float3x4Keyword, + Float4x1Keyword, + Float4x2Keyword, + Float4x3Keyword, + Float4x4Keyword, + ForKeyword, + GloballycoherentKeyword, + GroupsharedKeyword, + HalfKeyword, + Half1Keyword, + Half2Keyword, + Half3Keyword, + Half4Keyword, + Half1x1Keyword, + Half1x2Keyword, + Half1x3Keyword, + Half1x4Keyword, + Half2x1Keyword, + Half2x2Keyword, + Half2x3Keyword, + Half2x4Keyword, + Half3x1Keyword, + Half3x2Keyword, + Half3x3Keyword, + Half3x4Keyword, + Half4x1Keyword, + Half4x2Keyword, + Half4x3Keyword, + Half4x4Keyword, + IfKeyword, + IndicesKeyword, + InKeyword, + InlineKeyword, + InoutKeyword, + InputPatchKeyword, + IntKeyword, + Int1Keyword, + Int2Keyword, + Int3Keyword, + Int4Keyword, + Int1x1Keyword, + Int1x2Keyword, + Int1x3Keyword, + Int1x4Keyword, + Int2x1Keyword, + Int2x2Keyword, + Int2x3Keyword, + Int2x4Keyword, + Int3x1Keyword, + Int3x2Keyword, + Int3x3Keyword, + Int3x4Keyword, + Int4x1Keyword, + Int4x2Keyword, + Int4x3Keyword, + Int4x4Keyword, + InterfaceKeyword, + LineKeyword, + LineAdjKeyword, + LinearKeyword, + LineStreamKeyword, + MatrixKeyword, + MessageKeyword, + Min10FloatKeyword, + Min10Float1Keyword, + Min10Float2Keyword, + Min10Float3Keyword, + Min10Float4Keyword, + Min10Float1x1Keyword, + Min10Float1x2Keyword, + Min10Float1x3Keyword, + Min10Float1x4Keyword, + Min10Float2x1Keyword, + Min10Float2x2Keyword, + Min10Float2x3Keyword, + Min10Float2x4Keyword, + Min10Float3x1Keyword, + Min10Float3x2Keyword, + Min10Float3x3Keyword, + Min10Float3x4Keyword, + Min10Float4x1Keyword, + Min10Float4x2Keyword, + Min10Float4x3Keyword, + Min10Float4x4Keyword, + Min12IntKeyword, + Min12Int1Keyword, + Min12Int2Keyword, + Min12Int3Keyword, + Min12Int4Keyword, + Min12Int1x1Keyword, + Min12Int1x2Keyword, + Min12Int1x3Keyword, + Min12Int1x4Keyword, + Min12Int2x1Keyword, + Min12Int2x2Keyword, + Min12Int2x3Keyword, + Min12Int2x4Keyword, + Min12Int3x1Keyword, + Min12Int3x2Keyword, + Min12Int3x3Keyword, + Min12Int3x4Keyword, + Min12Int4x1Keyword, + Min12Int4x2Keyword, + Min12Int4x3Keyword, + Min12Int4x4Keyword, + Min12UintKeyword, + Min12Uint1Keyword, + Min12Uint2Keyword, + Min12Uint3Keyword, + Min12Uint4Keyword, + Min12Uint1x1Keyword, + Min12Uint1x2Keyword, + Min12Uint1x3Keyword, + Min12Uint1x4Keyword, + Min12Uint2x1Keyword, + Min12Uint2x2Keyword, + Min12Uint2x3Keyword, + Min12Uint2x4Keyword, + Min12Uint3x1Keyword, + Min12Uint3x2Keyword, + Min12Uint3x3Keyword, + Min12Uint3x4Keyword, + Min12Uint4x1Keyword, + Min12Uint4x2Keyword, + Min12Uint4x3Keyword, + Min12Uint4x4Keyword, + Min16FloatKeyword, + Min16Float1Keyword, + Min16Float2Keyword, + Min16Float3Keyword, + Min16Float4Keyword, + Min16Float1x1Keyword, + Min16Float1x2Keyword, + Min16Float1x3Keyword, + Min16Float1x4Keyword, + Min16Float2x1Keyword, + Min16Float2x2Keyword, + Min16Float2x3Keyword, + Min16Float2x4Keyword, + Min16Float3x1Keyword, + Min16Float3x2Keyword, + Min16Float3x3Keyword, + Min16Float3x4Keyword, + Min16Float4x1Keyword, + Min16Float4x2Keyword, + Min16Float4x3Keyword, + Min16Float4x4Keyword, + Min16IntKeyword, + Min16Int1Keyword, + Min16Int2Keyword, + Min16Int3Keyword, + Min16Int4Keyword, + Min16Int1x1Keyword, + Min16Int1x2Keyword, + Min16Int1x3Keyword, + Min16Int1x4Keyword, + Min16Int2x1Keyword, + Min16Int2x2Keyword, + Min16Int2x3Keyword, + Min16Int2x4Keyword, + Min16Int3x1Keyword, + Min16Int3x2Keyword, + Min16Int3x3Keyword, + Min16Int3x4Keyword, + Min16Int4x1Keyword, + Min16Int4x2Keyword, + Min16Int4x3Keyword, + Min16Int4x4Keyword, + Min16UintKeyword, + Min16Uint1Keyword, + Min16Uint2Keyword, + Min16Uint3Keyword, + Min16Uint4Keyword, + Min16Uint1x1Keyword, + Min16Uint1x2Keyword, + Min16Uint1x3Keyword, + Min16Uint1x4Keyword, + Min16Uint2x1Keyword, + Min16Uint2x2Keyword, + Min16Uint2x3Keyword, + Min16Uint2x4Keyword, + Min16Uint3x1Keyword, + Min16Uint3x2Keyword, + Min16Uint3x3Keyword, + Min16Uint3x4Keyword, + Min16Uint4x1Keyword, + Min16Uint4x2Keyword, + Min16Uint4x3Keyword, + Min16Uint4x4Keyword, + NamespaceKeyword, + NointerpolationKeyword, + NoperspectiveKeyword, + NullKeyword, + OutKeyword, + OutputPatchKeyword, + PackMatrixKeyword, + PackoffsetKeyword, + PassKeyword, + PayloadKeyword, + PointKeyword, + PointStreamKeyword, + PragmaKeyword, + PreciseKeyword, + PrimitivesKeyword, + RasterizerOrderedBufferKeyword, + RasterizerOrderedByteAddressBufferKeyword, + RasterizerOrderedStructuredBufferKeyword, + RasterizerOrderedTexture1DKeyword, + RasterizerOrderedTexture1DArrayKeyword, + RasterizerOrderedTexture2DKeyword, + RasterizerOrderedTexture2DArrayKeyword, + RasterizerOrderedTexture3DKeyword, + RasterizerStateKeyword, + RegisterKeyword, + ReturnKeyword, + RowMajorKeyword, + RWBufferKeyword, + RWByteAddressBufferKeyword, + RWStructuredBufferKeyword, + RWTexture1DKeyword, + RWTexture1DArrayKeyword, + RWTexture2DKeyword, + RWTexture2DArrayKeyword, + RWTexture3DKeyword, + SamplerKeyword, + Sampler1DKeyword, + Sampler2DKeyword, + Sampler3DKeyword, + SamplerCubeKeyword, + SamplerComparisonStateKeyword, + SamplerStateKeyword, + SamplerStateLegacyKeyword, + SharedKeyword, + SNormKeyword, + StaticKeyword, + StringKeyword, + StructKeyword, + StructuredBufferKeyword, + SwitchKeyword, + TBufferKeyword, + TechniqueKeyword, + Technique10Keyword, + Technique11Keyword, + TextureKeyword, + Texture2DLegacyKeyword, + TextureCubeLegacyKeyword, + Texture1DKeyword, + Texture1DArrayKeyword, + Texture2DKeyword, + Texture2DArrayKeyword, + Texture2DMSKeyword, + Texture2DMSArrayKeyword, + Texture3DKeyword, + TextureCubeKeyword, + TextureCubeArrayKeyword, + TriangleKeyword, + TriangleAdjKeyword, + TriangleStreamKeyword, + TypedefKeyword, + UniformKeyword, + UNormKeyword, + UintKeyword, + Uint1Keyword, + Uint2Keyword, + Uint3Keyword, + Uint4Keyword, + Uint1x1Keyword, + Uint1x2Keyword, + Uint1x3Keyword, + Uint1x4Keyword, + Uint2x1Keyword, + Uint2x2Keyword, + Uint2x3Keyword, + Uint2x4Keyword, + Uint3x1Keyword, + Uint3x2Keyword, + Uint3x3Keyword, + Uint3x4Keyword, + Uint4x1Keyword, + Uint4x2Keyword, + Uint4x3Keyword, + Uint4x4Keyword, + VectorKeyword, + VerticesKeyword, + VolatileKeyword, + VoidKeyword, + WarningKeyword, + WhileKeyword, + TrueKeyword, + FalseKeyword, + UnsignedKeyword, + DwordKeyword, + CompileFragmentKeyword, + DepthStencilViewKeyword, + PixelfragmentKeyword, + RenderTargetViewKeyword, + StateblockStateKeyword, + StateblockKeyword, + + OpenParenToken, + CloseParenToken, + OpenBracketToken, + CloseBracketToken, + OpenBraceToken, + CloseBraceToken, + SemiToken, + CommaToken, + LessThanToken, + LessThanEqualsToken, + GreaterThanToken, + GreaterThanEqualsToken, + LessThanLessThanToken, + GreaterThanGreaterThanToken, + PlusToken, + PlusPlusToken, + MinusToken, + MinusMinusToken, + AsteriskToken, + SlashToken, + PercentToken, + AmpersandToken, + BarToken, + AmpersandAmpersandToken, + BarBarToken, + CaretToken, + NotToken, + TildeToken, + QuestionToken, + ColonToken, + ColonColonToken, + EqualsToken, + AsteriskEqualsToken, + SlashEqualsToken, + PercentEqualsToken, + PlusEqualsToken, + MinusEqualsToken, + LessThanLessThanEqualsToken, + GreaterThanGreaterThanEqualsToken, + AmpersandEqualsToken, + CaretEqualsToken, + BarEqualsToken, + EqualsEqualsToken, + ExclamationEqualsToken, + DotToken, + HashToken, + HashHashToken, + + IdentifierToken, + IntegerLiteralToken, + FloatLiteralToken, + CharacterLiteralToken, + StringLiteralToken, + + DefineDirectiveKeyword, + IncludeDirectiveKeyword, + LineDirectiveKeyword, + UndefDirectiveKeyword, + ErrorDirectiveKeyword, + PragmaDirectiveKeyword, + IfDirectiveKeyword, + IfdefDirectiveKeyword, + IfndefDirectiveKeyword, + ElifDirectiveKeyword, + ElseDirectiveKeyword, + EndifDirectiveKeyword, + SystemIncludeLiteralToken, + EndDirectiveToken, + OpenFunctionLikeMacroParenToken, + } + + [PrettyEnum(PrettyEnumStyle.AllLowerCase)] + public enum ScalarType + { + Void, + Bool, + Int, + Uint, + Half, + Float, + Double, + Min16Float, + Min10Float, + Min16Int, + Min12Int, + Min16Uint, + Min12Uint, + String, + [PrettyName("unorm float")] UNormFloat, + [PrettyName("snorm float")] SNormFloat, + } + + [PrettyEnum(PrettyEnumStyle.AllLowerCase)] + public enum LiteralKind + { + String, + Float, + [PrettyName("int")] Integer, + [PrettyName("char")] Character, + [PrettyName("bool")] Boolean, + [PrettyName("NULL")] Null, + } + + [PrettyEnum(PrettyEnumStyle.AllLowerCase)] + public enum RegisterKind + { + [PrettyName("t")] Texture, + [PrettyName("s")] Sampler, + [PrettyName("u")] UAV, + [PrettyName("b")] Buffer, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum PredefinedObjectType + { + [PrettyName("texture")] Texture, + Texture1D, + Texture1DArray, + Texture2D, + Texture2DArray, + Texture3D, + TextureCube, + TextureCubeArray, + Texture2DMS, + Texture2DMSArray, + RWTexture1D, + RWTexture1DArray, + RWTexture2D, + RWTexture2DArray, + RWTexture3D, + AppendStructuredBuffer, + Buffer, + ByteAddressBuffer, + ConsumeStructuredBuffer, + StructuredBuffer, + ConstantBuffer, + RasterizerOrderedBuffer, + RasterizerOrderedByteAddressBuffer, + RasterizerOrderedStructuredBuffer, + RasterizerOrderedTexture1D, + RasterizerOrderedTexture1DArray, + RasterizerOrderedTexture2D, + RasterizerOrderedTexture2DArray, + RasterizerOrderedTexture3D, + RWBuffer, + RWByteAddressBuffer, + RWStructuredBuffer, + InputPatch, + OutputPatch, + PointStream, + LineStream, + TriangleStream, + BlendState, + DepthStencilState, + RasterizerState, + [PrettyName("sampler")] Sampler, + [PrettyName("sampler1D")] Sampler1D, + [PrettyName("sampler2D")] Sampler2D, + [PrettyName("sampler3D")] Sampler3D, + [PrettyName("samplerCUBE")] SamplerCube, + SamplerState, + SamplerComparisonState, + BuiltInTriangleIntersectionAttributes, + RayDesc, + RaytracingAccelerationStructure + } + + [PrettyEnum(PrettyEnumStyle.AllLowerCase)] + public enum BindingModifier + { + Const, + [PrettyName("row_major")] RowMajor, + [PrettyName("column_major")] ColumnMajor, + Export, + Extern, + Inline, + Precise, + Shared, + Globallycoherent, + Groupshared, + Static, + Uniform, + Volatile, + SNorm, + UNorm, + Linear, + Centroid, + Nointerpolation, + Noperspective, + Sample, + + In, + Out, + Inout, + Point, + Triangle, + TriangleAdj, + Line, + LineAdj, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum StateKind + { + SamplerState, + SamplerComparisonState, + BlendState, + } + + [PrettyEnum(PrettyEnumStyle.AllLowerCase)] + public enum OperatorKind + { + [PrettyName("=")] Assignment, + [PrettyName("+=")] PlusAssignment, + [PrettyName("-=")] MinusAssignment, + [PrettyName("*=")] MulAssignment, + [PrettyName("/=")] DivAssignment, + [PrettyName("%=")] ModAssignment, + [PrettyName("<<=")] ShiftLeftAssignment, + [PrettyName(">>=")] ShiftRightAssignment, + [PrettyName("&=")] BitwiseAndAssignment, + [PrettyName("^=")] BitwiseXorAssignment, + [PrettyName("|=")] BitwiseOrAssignment, + + [PrettyName("||")] LogicalOr, + [PrettyName("&&")] LogicalAnd, + [PrettyName("|")] BitwiseOr, + [PrettyName("&")] BitwiseAnd, + [PrettyName("^")] BitwiseXor, + + [PrettyName(",")] Compound, + [PrettyName("?")] Ternary, + + [PrettyName("==")] Equals, + [PrettyName("!=")] NotEquals, + [PrettyName("<")] LessThan, + [PrettyName("<=")] LessThanOrEquals, + [PrettyName(">")] GreaterThan, + [PrettyName(">=")] GreaterThanOrEquals, + + [PrettyName("<<")] ShiftLeft, + [PrettyName(">>")] ShiftRight, + + [PrettyName("+")] Plus, + [PrettyName("-")] Minus, + [PrettyName("*")] Mul, + [PrettyName("/")] Div, + [PrettyName("%")] Mod, + + [PrettyName("++")] Increment, + [PrettyName("--")] Decrement, + + [PrettyName("!")] Not, + [PrettyName("~")] BitFlip, + } + + public enum OperatorFixity + { + Prefix, + Postfix, + Infix, + } + + public enum OperatorPrecedence + { // Associativity: + Compound, // left + Assignment, // right + Ternary, // right + LogicalOr, // left + LogicalAnd, // left + BitwiseOr, // left + BitwiseXor, // left + BitwiseAnd, // left + Equality, // left + Comparison, // left + BitShift, // left + AddSub, // left + MulDivMod, // left + PrefixUnary, // right + PostFixUnary, // left + } + #endregion + + #region Syntax tree + public abstract class HLSLSyntaxNode : SyntaxNode + { + public abstract void Accept(HLSLSyntaxVisitor visitor); + public abstract T Accept(HLSLSyntaxVisitor visitor); + + public override SourceSpan Span => span; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private SourceSpan span; + + public override SourceSpan OriginalSpan => originalSpan; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private SourceSpan originalSpan; + + public List Tokens => tokens; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private List tokens; + + public string GetCodeInSourceText(string sourceText) => Span.GetCodeInSourceText(sourceText); + public string GetPrettyPrintedCode() + { + HLSLPrinter printer = new HLSLPrinter(); + printer.Visit(this); + return printer.Text; + } + + public HLSLSyntaxNode(List tokens) + { + if (tokens.Count > 0) + { + this.span = SourceSpan.Between(tokens.First().Span, tokens.Last().Span); + this.originalSpan = SourceSpan.Between(tokens.First().OriginalSpan, tokens.Last().OriginalSpan); + } + this.tokens = tokens; + } + } + + public abstract class FunctionNode : HLSLSyntaxNode + { + public List Attributes { get; set; } + public List Modifiers { get; set; } + public TypeNode ReturnType { get; set; } + public UserDefinedNamedTypeNode Name { get; set; } + public List Parameters { get; set; } + public SemanticNode Semantic { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Attributes, Child(ReturnType), Child(Name), Parameters, OptionalChild(Semantic)); + + public FunctionNode(List tokens) : base(tokens) { } + } + + public class FormalParameterNode : HLSLSyntaxNode + { + public List Attributes { get; set; } + public List Modifiers { get; set; } + public TypeNode ParamType { get; set; } + public VariableDeclaratorNode Declarator { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Attributes, Child(ParamType), Child(Declarator)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFormalParameterNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFormalParameterNode(this); + + public FormalParameterNode(List tokens) : base(tokens) { } + } + + public class VariableDeclaratorNode : HLSLSyntaxNode + { + public string Name { get; set; } + public List ArrayRanks { get; set; } + public List Qualifiers { get; set; } + public List Annotations { get; set; } + public InitializerNode Initializer { get; set; } // Optional + + protected override IEnumerable GetChildren => + MergeChildren(ArrayRanks, Qualifiers, Annotations, OptionalChild(Initializer)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitVariableDeclaratorNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitVariableDeclaratorNode(this); + + public VariableDeclaratorNode(List tokens) : base(tokens) { } + } + + public class ArrayRankNode : HLSLSyntaxNode + { + public ExpressionNode Dimension { get; set; } // Optional + + protected override IEnumerable GetChildren => + OptionalChild(Dimension); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitArrayRankNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitArrayRankNode(this); + + public ArrayRankNode(List tokens) : base(tokens) { } + } + + public abstract class InitializerNode : HLSLSyntaxNode + { + public InitializerNode(List tokens) : base(tokens) { } + } + + public class ValueInitializerNode : InitializerNode + { + public ExpressionNode Expression { get; set; } + + protected override IEnumerable GetChildren => + Child(Expression); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitValueInitializerNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitValueInitializerNode(this); + + public ValueInitializerNode(List tokens) : base(tokens) { } + } + + // BlendState, SamplerState, etc. + public class StateInitializerNode : InitializerNode + { + public List States { get; set; } + + protected override IEnumerable GetChildren => + States; + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStateInitializerNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStateInitializerNode(this); + + public StateInitializerNode(List tokens) : base(tokens) { } + } + + public class StateArrayInitializerNode : InitializerNode + { + public List Initializers { get; set; } + + protected override IEnumerable GetChildren => + Initializers; + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStateArrayInitializerNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStateArrayInitializerNode(this); + + public StateArrayInitializerNode(List tokens) : base(tokens) { } + } + + public class FunctionDeclarationNode : FunctionNode + { + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFunctionDeclarationNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFunctionDeclarationNode(this); + + public FunctionDeclarationNode(List tokens) : base(tokens) { } + } + + public class FunctionDefinitionNode : FunctionNode + { + public BlockNode Body { get; set; } + + public bool BodyIsSingleStatement => !(Body is BlockNode); + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(Body)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFunctionDefinitionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFunctionDefinitionNode(this); + + public FunctionDefinitionNode(List tokens) : base(tokens) { } + } + + public class StructDefinitionNode : StatementNode + { + public StructTypeNode StructType { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(StructType)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStructDefinitionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStructDefinitionNode(this); + + public StructDefinitionNode(List tokens) : base(tokens) { } + } + + public class InterfaceDefinitionNode : StatementNode + { + public UserDefinedNamedTypeNode Name { get; set; } + public List Functions { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(Name), Functions); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitInterfaceDefinitionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitInterfaceDefinitionNode(this); + + public InterfaceDefinitionNode(List tokens) : base(tokens) { } + } + + public class ConstantBufferNode : HLSLSyntaxNode + { + public UserDefinedNamedTypeNode Name { get; set; } + public RegisterLocationNode RegisterLocation { get; set; } // Optional + public List Declarations { get; set; } + public bool IsTextureBuffer { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Name), OptionalChild(RegisterLocation), Declarations); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitConstantBufferNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitConstantBufferNode(this); + + public ConstantBufferNode(List tokens) : base(tokens) { } + } + + public class NamespaceNode : HLSLSyntaxNode + { + public UserDefinedNamedTypeNode Name { get; set; } + public List Declarations { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Name), Declarations); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitNamespaceNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitNamespaceNode(this); + + public NamespaceNode(List tokens) : base(tokens) { } + } + + public class TypedefNode : StatementNode + { + public TypeNode FromType { get; set; } + public List ToNames { get; set; } + public bool IsConst { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(FromType), ToNames); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitTypedefNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitTypedefNode(this); + + public TypedefNode(List tokens) : base(tokens) { } + } + + public abstract class VariableDeclaratorQualifierNode : HLSLSyntaxNode + { + public VariableDeclaratorQualifierNode(List tokens) : base(tokens) { } + } + + public class SemanticNode : VariableDeclaratorQualifierNode + { + public string Name { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSemanticNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSemanticNode(this); + + public SemanticNode(List tokens) : base(tokens) { } + } + + public class RegisterLocationNode : VariableDeclaratorQualifierNode + { + public RegisterKind Kind { get; set; } + public int Location { get; set; } + public int? Space { get; set; } // Optional + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitRegisterLocationNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitRegisterLocationNode(this); + + public RegisterLocationNode(List tokens) : base(tokens) { } + } + + public class PackoffsetNode : VariableDeclaratorQualifierNode + { + public int Location { get; set; } + public string Swizzle { get; set; } // Optional + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPackoffsetNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPackoffsetNode(this); + + public PackoffsetNode(List tokens) : base(tokens) { } + } + + public abstract class StatementNode : HLSLSyntaxNode + { + public List Attributes { get; set; } + + protected override IEnumerable GetChildren => + Attributes; + + public StatementNode(List tokens) : base(tokens) { } + } + + public class BlockNode : StatementNode + { + public List Statements { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Statements); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitBlockNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitBlockNode(this); + + public BlockNode(List tokens) : base(tokens) { } + } + + public class VariableDeclarationStatementNode : StatementNode + { + public List Modifiers { get; set; } + public TypeNode Kind { get; set; } + public List Declarators { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(Kind), Declarators); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitVariableDeclarationStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitVariableDeclarationStatementNode(this); + + public VariableDeclarationStatementNode(List tokens) : base(tokens) { } + } + + public class ReturnStatementNode : StatementNode + { + public ExpressionNode Expression { get; set; } // Optional + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, OptionalChild(Expression)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitReturnStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitReturnStatementNode(this); + + public ReturnStatementNode(List tokens) : base(tokens) { } + } + + public class BreakStatementNode : StatementNode + { + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitBreakStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitBreakStatementNode(this); + + public BreakStatementNode(List tokens) : base(tokens) { } + } + + public class ContinueStatementNode : StatementNode + { + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitContinueStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitContinueStatementNode(this); + + public ContinueStatementNode(List tokens) : base(tokens) { } + } + + public class DiscardStatementNode : StatementNode + { + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitDiscardStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitDiscardStatementNode(this); + + public DiscardStatementNode(List tokens) : base(tokens) { } + } + + public class EmptyStatementNode : StatementNode + { + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitEmptyStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitEmptyStatementNode(this); + + public EmptyStatementNode(List tokens) : base(tokens) { } + } + + public class ForStatementNode : StatementNode + { + public VariableDeclarationStatementNode Declaration { get; set; } // This is mutually exclusive with Initializer + public ExpressionNode Initializer { get; set; } + + public ExpressionNode Condition { get; set; } // Optional + public ExpressionNode Increment { get; set; } // Optional + public StatementNode Body { get; set; } + + public bool FirstIsDeclaration => Declaration != null; + public bool FirstIsExpression => Initializer != null; + public bool BodyIsSingleStatement => !(Body is BlockNode); + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, OptionalChild(Declaration), OptionalChild(Initializer), OptionalChild(Condition), OptionalChild(Increment), Child(Body)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitForStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitForStatementNode(this); + + public ForStatementNode(List tokens) : base(tokens) { } + } + + public class WhileStatementNode : StatementNode + { + public ExpressionNode Condition { get; set; } + public StatementNode Body { get; set; } + + public bool BodyIsSingleStatement => !(Body is BlockNode); + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(Condition), Child(Body)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitWhileStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitWhileStatementNode(this); + + public WhileStatementNode(List tokens) : base(tokens) { } + } + + public class DoWhileStatementNode : StatementNode + { + public StatementNode Body { get; set; } + public ExpressionNode Condition { get; set; } + + public bool BodyIsSingleStatement => !(Body is BlockNode); + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(Body), Child(Condition)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitDoWhileStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitDoWhileStatementNode(this); + + public DoWhileStatementNode(List tokens) : base(tokens) { } + } + + public class IfStatementNode : StatementNode + { + public ExpressionNode Condition { get; set; } + public StatementNode Body { get; set; } + public StatementNode ElseClause { get; set; } // Optional + + public bool BodyIsSingleStatement => !(Body is BlockNode); + public bool BodyIsElseIfClause => Parent is IfStatementNode; + public bool ElseClauseIsSingleStatement => !(ElseClause is BlockNode); + public bool ElseClauseIsElseIfClause => ElseClause is IfStatementNode; + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(Condition), Child(Body), OptionalChild(ElseClause)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIfStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIfStatementNode(this); + + public IfStatementNode(List tokens) : base(tokens) { } + } + + public class SwitchStatementNode : StatementNode + { + public ExpressionNode Expression { get; set; } + public List Clauses { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(Expression), Clauses); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSwitchStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSwitchStatementNode(this); + + public SwitchStatementNode(List tokens) : base(tokens) { } + } + + public class SwitchClauseNode : HLSLSyntaxNode + { + public List Labels { get; set; } + public List Statements { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Labels, Statements); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSwitchClauseNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSwitchClauseNode(this); + + public SwitchClauseNode(List tokens) : base(tokens) { } + } + + public abstract class SwitchLabelNode : HLSLSyntaxNode + { + public SwitchLabelNode(List tokens) : base(tokens) { } + } + + public class SwitchCaseLabelNode : SwitchLabelNode + { + public ExpressionNode Value { get; set; } + + protected override IEnumerable GetChildren => + Child(Value); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSwitchCaseLabelNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSwitchCaseLabelNode(this); + + public SwitchCaseLabelNode(List tokens) : base(tokens) { } + } + + public class SwitchDefaultLabelNode : SwitchLabelNode + { + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSwitchDefaultLabelNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSwitchDefaultLabelNode(this); + + public SwitchDefaultLabelNode(List tokens) : base(tokens) { } + } + + public class ExpressionStatementNode : StatementNode + { + public ExpressionNode Expression { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(base.GetChildren, Child(Expression)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitExpressionStatementNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitExpressionStatementNode(this); + + public ExpressionStatementNode(List tokens) : base(tokens) { } + } + + public class AttributeNode : HLSLSyntaxNode + { + public string Name { get; set; } + public List Arguments { get; set; } + + protected override IEnumerable GetChildren => + Arguments; + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitAttributeNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitAttributeNode(this); + + public AttributeNode(List tokens) : base(tokens) { } + } + + public abstract class ExpressionNode : HLSLSyntaxNode + { + public ExpressionNode(List tokens) : base(tokens) { } + } + + public abstract class NamedExpressionNode : ExpressionNode + { + public abstract string GetName(); + public abstract string GetUnqualifiedName(); + + public NamedExpressionNode(List tokens) : base(tokens) { } + } + + public class QualifiedIdentifierExpressionNode : NamedExpressionNode + { + public IdentifierExpressionNode Left { get; set; } + public NamedExpressionNode Right { get; set; } + + public override string GetName() => $"{Left.GetName()}::{Right.GetName()}"; + public override string GetUnqualifiedName() => Right.GetUnqualifiedName(); + + protected override IEnumerable GetChildren => + MergeChildren(Child(Left), Child(Right)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitQualifiedIdentifierExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitQualifiedIdentifierExpressionNode(this); + + public QualifiedIdentifierExpressionNode(List tokens) : base(tokens) { } + } + + public class IdentifierExpressionNode : NamedExpressionNode + { + public string Name { get; set; } + + public override string GetName() => Name; + public override string GetUnqualifiedName() => Name; + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIdentifierExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIdentifierExpressionNode(this); + + public IdentifierExpressionNode(List tokens) : base(tokens) { } + } + + public class LiteralExpressionNode : ExpressionNode + { + public string Lexeme { get; set; } + public LiteralKind Kind { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitLiteralExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitLiteralExpressionNode(this); + + public LiteralExpressionNode(List tokens) : base(tokens) { } + } + + public class AssignmentExpressionNode : ExpressionNode + { + public ExpressionNode Left { get; set; } + public OperatorKind Operator { get; set; } + public ExpressionNode Right { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Left), Child(Right)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitAssignmentExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitAssignmentExpressionNode(this); + + public AssignmentExpressionNode(List tokens) : base(tokens) { } + } + + public class BinaryExpressionNode : ExpressionNode + { + public ExpressionNode Left { get; set; } + public OperatorKind Operator { get; set; } + public ExpressionNode Right { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Left), Child(Right)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitBinaryExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitBinaryExpressionNode(this); + + public BinaryExpressionNode(List tokens) : base(tokens) { } + } + + public class CompoundExpressionNode : ExpressionNode + { + public ExpressionNode Left { get; set; } + public ExpressionNode Right { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Left), Child(Right)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitCompoundExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitCompoundExpressionNode(this); + + public CompoundExpressionNode(List tokens) : base(tokens) { } + } + + public class PrefixUnaryExpressionNode : ExpressionNode + { + public OperatorKind Operator { get; set; } + public ExpressionNode Expression { get; set; } + + protected override IEnumerable GetChildren => + Child(Expression); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPrefixUnaryExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPrefixUnaryExpressionNode(this); + + public PrefixUnaryExpressionNode(List tokens) : base(tokens) { } + } + + public class PostfixUnaryExpressionNode : ExpressionNode + { + public ExpressionNode Expression { get; set; } + public OperatorKind Operator { get; set; } + + protected override IEnumerable GetChildren => + Child(Expression); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPostfixUnaryExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPostfixUnaryExpressionNode(this); + + public PostfixUnaryExpressionNode(List tokens) : base(tokens) { } + } + + public class FieldAccessExpressionNode : ExpressionNode + { + public ExpressionNode Target { get; set; } + public string Name { get; set; } + + protected override IEnumerable GetChildren => + Child(Target); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFieldAccessExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFieldAccessExpressionNode(this); + + public FieldAccessExpressionNode(List tokens) : base(tokens) { } + } + + public class MethodCallExpressionNode : ExpressionNode + { + public ExpressionNode Target { get; set; } + public string Name { get; set; } + public List Arguments { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Target), Arguments); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitMethodCallExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitMethodCallExpressionNode(this); + + public MethodCallExpressionNode(List tokens) : base(tokens) { } + } + + public class FunctionCallExpressionNode : ExpressionNode + { + public NamedExpressionNode Name { get; set; } + public List Arguments { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Name), Arguments); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFunctionCallExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFunctionCallExpressionNode(this); + + public FunctionCallExpressionNode(List tokens) : base(tokens) { } + } + + public class NumericConstructorCallExpressionNode : ExpressionNode + { + public NumericTypeNode Kind { get; set; } + public List Arguments { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Kind), Arguments); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitNumericConstructorCallExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitNumericConstructorCallExpressionNode(this); + + public NumericConstructorCallExpressionNode(List tokens) : base(tokens) { } + } + + public class ElementAccessExpressionNode : ExpressionNode + { + public ExpressionNode Target { get; set; } + public ExpressionNode Index { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Target), Child(Index)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitElementAccessExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitElementAccessExpressionNode(this); + + public ElementAccessExpressionNode(List tokens) : base(tokens) { } + } + + public class CastExpressionNode : ExpressionNode + { + public TypeNode Kind { get; set; } + public ExpressionNode Expression { get; set; } + public List ArrayRanks { get; set; } + public bool IsFunctionLike { get; set; } + protected override IEnumerable GetChildren => + MergeChildren(Child(Kind), Child(Expression), ArrayRanks); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitCastExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitCastExpressionNode(this); + + public CastExpressionNode(List tokens) : base(tokens) { } + } + + public class ArrayInitializerExpressionNode : ExpressionNode + { + public List Elements { get; set; } + + protected override IEnumerable GetChildren => + Elements; + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitArrayInitializerExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitArrayInitializerExpressionNode(this); + + public ArrayInitializerExpressionNode(List tokens) : base(tokens) { } + } + + public class TernaryExpressionNode : ExpressionNode + { + public ExpressionNode Condition { get; set; } + public ExpressionNode TrueCase { get; set; } + public ExpressionNode FalseCase { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Condition), Child(TrueCase), Child(FalseCase)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitTernaryExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitTernaryExpressionNode(this); + + public TernaryExpressionNode(List tokens) : base(tokens) { } + } + + // Part of legacy sampler syntax (d3d9) + public class SamplerStateLiteralExpressionNode : ExpressionNode + { + public List States { get; set; } + + protected override IEnumerable GetChildren => + States; + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSamplerStateLiteralExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitSamplerStateLiteralExpressionNode(this); + + public SamplerStateLiteralExpressionNode(List tokens) : base(tokens) { } + } + + // From FX framework + public class CompileExpressionNode : ExpressionNode + { + public string Target { get; set; } + public FunctionCallExpressionNode Invocation { get; set; } + + protected override IEnumerable GetChildren => + Child(Invocation); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitCompileExpressionNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitCompileExpressionNode(this); + + public CompileExpressionNode(List tokens) : base(tokens) { } + } + + public abstract class TypeNode : HLSLSyntaxNode + { + public TypeNode(List tokens) : base(tokens) { } + } + public abstract class UserDefinedTypeNode : TypeNode + { + public UserDefinedTypeNode(List tokens) : base(tokens) { } + } + public abstract class UserDefinedNamedTypeNode : UserDefinedTypeNode + { + public abstract string GetName(); + public abstract string GetUnqualifiedName(); + + public UserDefinedNamedTypeNode(List tokens) : base(tokens) { } + } + public abstract class PredefinedTypeNode : TypeNode + { + public PredefinedTypeNode(List tokens) : base(tokens) { } + } + + public class QualifiedNamedTypeNode : UserDefinedNamedTypeNode + { + public NamedTypeNode Left { get; set; } + public UserDefinedNamedTypeNode Right { get; set; } + + public override string GetName() => $"{Left.GetName()}::{Right.GetName()}"; + public override string GetUnqualifiedName() => Right.GetUnqualifiedName(); + + protected override IEnumerable GetChildren => + MergeChildren(Child(Left), Child(Right)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitQualifiedNamedTypeNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitQualifiedNamedTypeNode(this); + + public QualifiedNamedTypeNode(List tokens) : base(tokens) { } + } + + public class NamedTypeNode : UserDefinedNamedTypeNode + { + public string Name { get; set; } + + public override string GetName() => Name; + public override string GetUnqualifiedName() => Name; + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitNamedTypeNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitNamedTypeNode(this); + + public NamedTypeNode(List tokens) : base(tokens) { } + } + + public class PredefinedObjectTypeNode : PredefinedTypeNode + { + public PredefinedObjectType Kind { get; set; } + public List TemplateArguments { get; set; } + + protected override IEnumerable GetChildren => + TemplateArguments; + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPredefinedObjectTypeNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPredefinedObjectTypeNode(this); + + public PredefinedObjectTypeNode(List tokens) : base(tokens) { } + } + + public class StructTypeNode : UserDefinedTypeNode + { + public UserDefinedNamedTypeNode Name { get; set; } + public List Inherits { get; set; } + public List Fields { get; set; } + public List Methods { get; set; } + public bool IsClass { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(OptionalChild(Name), Inherits, Fields, Methods); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStructTypeNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStructTypeNode(this); + + public StructTypeNode(List tokens) : base(tokens) { } + } + + public abstract class NumericTypeNode : PredefinedTypeNode + { + public ScalarType Kind { get; set; } + + public NumericTypeNode(List tokens) : base(tokens) { } + } + + public class ScalarTypeNode : NumericTypeNode + { + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitScalarTypeNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitScalarTypeNode(this); + + public ScalarTypeNode(List tokens) : base(tokens) { } + } + + public class MatrixTypeNode : NumericTypeNode + { + public int FirstDimension { get; set; } + public int SecondDimension { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitMatrixTypeNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitMatrixTypeNode(this); + + public MatrixTypeNode(List tokens) : base(tokens) { } + } + + public class VectorTypeNode : NumericTypeNode + { + public int Dimension { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitVectorTypeNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitVectorTypeNode(this); + + public VectorTypeNode(List tokens) : base(tokens) { } + } + + // This type mostly exists such that template can receive literal arguments. + // It's basically constexpr. + public class LiteralTemplateArgumentType : TypeNode + { + public LiteralExpressionNode Literal { get; set; } + + protected override IEnumerable GetChildren => + Child(Literal); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitLiteralTemplateArgumentType(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitLiteralTemplateArgumentType(this); + + public LiteralTemplateArgumentType(List tokens) : base(tokens) { } + } + + // Part of an object literal (SamplerState, BlendState, etc) + public class StatePropertyNode : StatementNode + { + public UserDefinedNamedTypeNode Name { get; set; } + public ArrayRankNode ArrayRank { get; set; } // Optional + public ExpressionNode Value { get; set; } + public bool IsReference { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(OptionalChild(ArrayRank), Child(Value)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStatePropertyNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitStatePropertyNode(this); + + public StatePropertyNode(List tokens) : base(tokens) { } + } + + // Old FX pipeline syntax + public class TechniqueNode : HLSLSyntaxNode + { + public int Version { get; set; } + public UserDefinedNamedTypeNode Name { get; set; } // Optional + public List Annotations { get; set; } + public List Passes { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(OptionalChild(Name), Annotations, Passes); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitTechniqueNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitTechniqueNode(this); + + public TechniqueNode(List tokens) : base(tokens) { } + } + + // Old FX pipeline syntax + public class PassNode : HLSLSyntaxNode + { + public UserDefinedNamedTypeNode Name { get; set; } // Optional + public List Annotations { get; set; } + public List Statements { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(OptionalChild(Name), Annotations, Statements); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPassNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPassNode(this); + + public PassNode(List tokens) : base(tokens) { } + } + + public abstract class PreProcessorDirectiveNode : StatementNode + { + protected PreProcessorDirectiveNode(List tokens) : base(tokens) { } + } + + public class ObjectLikeMacroNode : PreProcessorDirectiveNode + { + public string Name { get; set; } + public List Value { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitObjectLikeMacroNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitObjectLikeMacroNode(this); + + public ObjectLikeMacroNode(List tokens) : base(tokens) { } + } + + public class FunctionLikeMacroNode : PreProcessorDirectiveNode + { + public string Name { get; set; } + public List Arguments { get; set; } + public List Value { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFunctionLikeMacroNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitFunctionLikeMacroNode(this); + + public FunctionLikeMacroNode(List tokens) : base(tokens) { } + } + + public class IncludeDirectiveNode : PreProcessorDirectiveNode + { + public string Path { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIncludeDirectiveNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIncludeDirectiveNode(this); + + public IncludeDirectiveNode(List tokens) : base(tokens) { } + } + + public class LineDirectiveNode : PreProcessorDirectiveNode + { + public int Line { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitLineDirectiveNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitLineDirectiveNode(this); + + public LineDirectiveNode(List tokens) : base(tokens) { } + } + + public class UndefDirectiveNode : PreProcessorDirectiveNode + { + public string Name { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitUndefDirectiveNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitUndefDirectiveNode(this); + + public UndefDirectiveNode(List tokens) : base(tokens) { } + } + + public class ErrorDirectiveNode : PreProcessorDirectiveNode + { + public List Value { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitErrorDirectiveNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitErrorDirectiveNode(this); + + public ErrorDirectiveNode(List tokens) : base(tokens) { } + } + + public class PragmaDirectiveNode : PreProcessorDirectiveNode + { + public List Value { get; set; } + + protected override IEnumerable GetChildren => + Enumerable.Empty(); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPragmaDirectiveNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitPragmaDirectiveNode(this); + + public PragmaDirectiveNode(List tokens) : base(tokens) { } + } + + public class IfDefDirectiveNode : PreProcessorDirectiveNode + { + public string Condition { get; set; } + public List Body { get; set; } + public PreProcessorDirectiveNode ElseClause { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Body, OptionalChild(ElseClause)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIfDefDirectiveNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIfDefDirectiveNode(this); + + public IfDefDirectiveNode(List tokens) : base(tokens) { } + } + + public class IfNotDefDirectiveNode : PreProcessorDirectiveNode + { + public string Condition { get; set; } + public List Body { get; set; } + public PreProcessorDirectiveNode ElseClause { get; set; } + + protected override IEnumerable GetChildren => + MergeChildren(Body, OptionalChild(ElseClause)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIfNotDefDirectiveNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIfNotDefDirectiveNode(this); + + public IfNotDefDirectiveNode(List tokens) : base(tokens) { } + } + + public class IfDirectiveNode : PreProcessorDirectiveNode + { + public ExpressionNode Condition { get; set; } + public List Body { get; set; } + public PreProcessorDirectiveNode ElseClause { get; set; } + + public bool IsElif + { + get + { + switch (Parent) + { + case IfDefDirectiveNode p: return p.ElseClause == this; + case IfNotDefDirectiveNode p: return p.ElseClause == this; + case IfDirectiveNode p: return p.ElseClause == this; + default: return false; + } + } + } + + protected override IEnumerable GetChildren => + MergeChildren(Child(Condition), Body, OptionalChild(ElseClause)); + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIfDirectiveNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitIfDirectiveNode(this); + + public IfDirectiveNode(List tokens) : base(tokens) { } + } + + // The remainder of an if-directive + public class ElseDirectiveNode : PreProcessorDirectiveNode + { + public List Body { get; set; } + + protected override IEnumerable GetChildren => + Body; + + public override void Accept(HLSLSyntaxVisitor visitor) => visitor.VisitElseDirectiveNode(this); + public override T Accept(HLSLSyntaxVisitor visitor) => visitor.VisitElseDirectiveNode(this); + + public ElseDirectiveNode(List tokens) : base(tokens) { } + } + #endregion +} + + +// HLSL/HLSLSyntaxFacts.cs +namespace UnityShaderParser.HLSL +{ + public static class HLSLSyntaxFacts + { + public static bool TryParseHLSLKeyword(string keyword, out TokenKind token) + { + token = default; + + switch (keyword) + { + case "AppendStructuredBuffer": token = TokenKind.AppendStructuredBufferKeyword; return true; + case "BlendState": token = TokenKind.BlendStateKeyword; return true; + case "bool": token = TokenKind.BoolKeyword; return true; + case "bool1": token = TokenKind.Bool1Keyword; return true; + case "bool2": token = TokenKind.Bool2Keyword; return true; + case "bool3": token = TokenKind.Bool3Keyword; return true; + case "bool4": token = TokenKind.Bool4Keyword; return true; + case "bool1x1": token = TokenKind.Bool1x1Keyword; return true; + case "bool1x2": token = TokenKind.Bool1x2Keyword; return true; + case "bool1x3": token = TokenKind.Bool1x3Keyword; return true; + case "bool1x4": token = TokenKind.Bool1x4Keyword; return true; + case "bool2x1": token = TokenKind.Bool2x1Keyword; return true; + case "bool2x2": token = TokenKind.Bool2x2Keyword; return true; + case "bool2x3": token = TokenKind.Bool2x3Keyword; return true; + case "bool2x4": token = TokenKind.Bool2x4Keyword; return true; + case "bool3x1": token = TokenKind.Bool3x1Keyword; return true; + case "bool3x2": token = TokenKind.Bool3x2Keyword; return true; + case "bool3x3": token = TokenKind.Bool3x3Keyword; return true; + case "bool3x4": token = TokenKind.Bool3x4Keyword; return true; + case "bool4x1": token = TokenKind.Bool4x1Keyword; return true; + case "bool4x2": token = TokenKind.Bool4x2Keyword; return true; + case "bool4x3": token = TokenKind.Bool4x3Keyword; return true; + case "bool4x4": token = TokenKind.Bool4x4Keyword; return true; + case "Buffer": token = TokenKind.BufferKeyword; return true; + case "ByteAddressBuffer": token = TokenKind.ByteAddressBufferKeyword; return true; + case "break": token = TokenKind.BreakKeyword; return true; + case "case": token = TokenKind.CaseKeyword; return true; + case "cbuffer": token = TokenKind.CBufferKeyword; return true; + case "centroid": token = TokenKind.CentroidKeyword; return true; + case "class": token = TokenKind.ClassKeyword; return true; + case "column_major": token = TokenKind.ColumnMajorKeyword; return true; + case "compile": token = TokenKind.CompileKeyword; return true; + case "const": token = TokenKind.ConstKeyword; return true; + case "ConsumeStructuredBuffer": token = TokenKind.ConsumeStructuredBufferKeyword; return true; + case "continue": token = TokenKind.ContinueKeyword; return true; + case "default": token = TokenKind.DefaultKeyword; return true; + case "def": token = TokenKind.DefKeyword; return true; + case "DepthStencilState": token = TokenKind.DepthStencilStateKeyword; return true; + case "discard": token = TokenKind.DiscardKeyword; return true; + case "do": token = TokenKind.DoKeyword; return true; + case "double": token = TokenKind.DoubleKeyword; return true; + case "double1": token = TokenKind.Double1Keyword; return true; + case "double2": token = TokenKind.Double2Keyword; return true; + case "double3": token = TokenKind.Double3Keyword; return true; + case "double4": token = TokenKind.Double4Keyword; return true; + case "double1x1": token = TokenKind.Double1x1Keyword; return true; + case "double1x2": token = TokenKind.Double1x2Keyword; return true; + case "double1x3": token = TokenKind.Double1x3Keyword; return true; + case "double1x4": token = TokenKind.Double1x4Keyword; return true; + case "double2x1": token = TokenKind.Double2x1Keyword; return true; + case "double2x2": token = TokenKind.Double2x2Keyword; return true; + case "double2x3": token = TokenKind.Double2x3Keyword; return true; + case "double2x4": token = TokenKind.Double2x4Keyword; return true; + case "double3x1": token = TokenKind.Double3x1Keyword; return true; + case "double3x2": token = TokenKind.Double3x2Keyword; return true; + case "double3x3": token = TokenKind.Double3x3Keyword; return true; + case "double3x4": token = TokenKind.Double3x4Keyword; return true; + case "double4x1": token = TokenKind.Double4x1Keyword; return true; + case "double4x2": token = TokenKind.Double4x2Keyword; return true; + case "double4x3": token = TokenKind.Double4x3Keyword; return true; + case "double4x4": token = TokenKind.Double4x4Keyword; return true; + case "else": token = TokenKind.ElseKeyword; return true; + case "export": token = TokenKind.ExportKeyword; return true; + case "extern": token = TokenKind.ExternKeyword; return true; + case "float": token = TokenKind.FloatKeyword; return true; + case "float1": token = TokenKind.Float1Keyword; return true; + case "float2": token = TokenKind.Float2Keyword; return true; + case "float3": token = TokenKind.Float3Keyword; return true; + case "float4": token = TokenKind.Float4Keyword; return true; + case "float1x1": token = TokenKind.Float1x1Keyword; return true; + case "float1x2": token = TokenKind.Float1x2Keyword; return true; + case "float1x3": token = TokenKind.Float1x3Keyword; return true; + case "float1x4": token = TokenKind.Float1x4Keyword; return true; + case "float2x1": token = TokenKind.Float2x1Keyword; return true; + case "float2x2": token = TokenKind.Float2x2Keyword; return true; + case "float2x3": token = TokenKind.Float2x3Keyword; return true; + case "float2x4": token = TokenKind.Float2x4Keyword; return true; + case "float3x1": token = TokenKind.Float3x1Keyword; return true; + case "float3x2": token = TokenKind.Float3x2Keyword; return true; + case "float3x3": token = TokenKind.Float3x3Keyword; return true; + case "float3x4": token = TokenKind.Float3x4Keyword; return true; + case "float4x1": token = TokenKind.Float4x1Keyword; return true; + case "float4x2": token = TokenKind.Float4x2Keyword; return true; + case "float4x3": token = TokenKind.Float4x3Keyword; return true; + case "float4x4": token = TokenKind.Float4x4Keyword; return true; + case "for": token = TokenKind.ForKeyword; return true; + case "globallycoherent": token = TokenKind.GloballycoherentKeyword; return true; + case "groupshared": token = TokenKind.GroupsharedKeyword; return true; + case "half": token = TokenKind.HalfKeyword; return true; + case "half1": token = TokenKind.Half1Keyword; return true; + case "half2": token = TokenKind.Half2Keyword; return true; + case "half3": token = TokenKind.Half3Keyword; return true; + case "half4": token = TokenKind.Half4Keyword; return true; + case "half1x1": token = TokenKind.Half1x1Keyword; return true; + case "half1x2": token = TokenKind.Half1x2Keyword; return true; + case "half1x3": token = TokenKind.Half1x3Keyword; return true; + case "half1x4": token = TokenKind.Half1x4Keyword; return true; + case "half2x1": token = TokenKind.Half2x1Keyword; return true; + case "half2x2": token = TokenKind.Half2x2Keyword; return true; + case "half2x3": token = TokenKind.Half2x3Keyword; return true; + case "half2x4": token = TokenKind.Half2x4Keyword; return true; + case "half3x1": token = TokenKind.Half3x1Keyword; return true; + case "half3x2": token = TokenKind.Half3x2Keyword; return true; + case "half3x3": token = TokenKind.Half3x3Keyword; return true; + case "half3x4": token = TokenKind.Half3x4Keyword; return true; + case "half4x1": token = TokenKind.Half4x1Keyword; return true; + case "half4x2": token = TokenKind.Half4x2Keyword; return true; + case "half4x3": token = TokenKind.Half4x3Keyword; return true; + case "half4x4": token = TokenKind.Half4x4Keyword; return true; + case "if": token = TokenKind.IfKeyword; return true; + case "indices": token = TokenKind.IndicesKeyword; return true; + case "in": token = TokenKind.InKeyword; return true; + case "inline": token = TokenKind.InlineKeyword; return true; + case "inout": token = TokenKind.InoutKeyword; return true; + case "InputPatch": token = TokenKind.InputPatchKeyword; return true; + case "int": token = TokenKind.IntKeyword; return true; + case "int1": token = TokenKind.Int1Keyword; return true; + case "int2": token = TokenKind.Int2Keyword; return true; + case "int3": token = TokenKind.Int3Keyword; return true; + case "int4": token = TokenKind.Int4Keyword; return true; + case "int1x1": token = TokenKind.Int1x1Keyword; return true; + case "int1x2": token = TokenKind.Int1x2Keyword; return true; + case "int1x3": token = TokenKind.Int1x3Keyword; return true; + case "int1x4": token = TokenKind.Int1x4Keyword; return true; + case "int2x1": token = TokenKind.Int2x1Keyword; return true; + case "int2x2": token = TokenKind.Int2x2Keyword; return true; + case "int2x3": token = TokenKind.Int2x3Keyword; return true; + case "int2x4": token = TokenKind.Int2x4Keyword; return true; + case "int3x1": token = TokenKind.Int3x1Keyword; return true; + case "int3x2": token = TokenKind.Int3x2Keyword; return true; + case "int3x3": token = TokenKind.Int3x3Keyword; return true; + case "int3x4": token = TokenKind.Int3x4Keyword; return true; + case "int4x1": token = TokenKind.Int4x1Keyword; return true; + case "int4x2": token = TokenKind.Int4x2Keyword; return true; + case "int4x3": token = TokenKind.Int4x3Keyword; return true; + case "int4x4": token = TokenKind.Int4x4Keyword; return true; + case "interface": token = TokenKind.InterfaceKeyword; return true; + case "line": token = TokenKind.LineKeyword; return true; + case "lineadj": token = TokenKind.LineAdjKeyword; return true; + case "linear": token = TokenKind.LinearKeyword; return true; + case "LineStream": token = TokenKind.LineStreamKeyword; return true; + case "matrix": token = TokenKind.MatrixKeyword; return true; + case "message": token = TokenKind.MessageKeyword; return true; + case "min10float": token = TokenKind.Min10FloatKeyword; return true; + case "min10float1": token = TokenKind.Min10Float1Keyword; return true; + case "min10float2": token = TokenKind.Min10Float2Keyword; return true; + case "min10float3": token = TokenKind.Min10Float3Keyword; return true; + case "min10float4": token = TokenKind.Min10Float4Keyword; return true; + case "min10float1x1": token = TokenKind.Min10Float1x1Keyword; return true; + case "min10float1x2": token = TokenKind.Min10Float1x2Keyword; return true; + case "min10float1x3": token = TokenKind.Min10Float1x3Keyword; return true; + case "min10float1x4": token = TokenKind.Min10Float1x4Keyword; return true; + case "min10float2x1": token = TokenKind.Min10Float2x1Keyword; return true; + case "min10float2x2": token = TokenKind.Min10Float2x2Keyword; return true; + case "min10float2x3": token = TokenKind.Min10Float2x3Keyword; return true; + case "min10float2x4": token = TokenKind.Min10Float2x4Keyword; return true; + case "min10float3x1": token = TokenKind.Min10Float3x1Keyword; return true; + case "min10float3x2": token = TokenKind.Min10Float3x2Keyword; return true; + case "min10float3x3": token = TokenKind.Min10Float3x3Keyword; return true; + case "min10float3x4": token = TokenKind.Min10Float3x4Keyword; return true; + case "min10float4x1": token = TokenKind.Min10Float4x1Keyword; return true; + case "min10float4x2": token = TokenKind.Min10Float4x2Keyword; return true; + case "min10float4x3": token = TokenKind.Min10Float4x3Keyword; return true; + case "min10float4x4": token = TokenKind.Min10Float4x4Keyword; return true; + case "min12int": token = TokenKind.Min12IntKeyword; return true; + case "min12int1": token = TokenKind.Min12Int1Keyword; return true; + case "min12int2": token = TokenKind.Min12Int2Keyword; return true; + case "min12int3": token = TokenKind.Min12Int3Keyword; return true; + case "min12int4": token = TokenKind.Min12Int4Keyword; return true; + case "min12int1x1": token = TokenKind.Min12Int1x1Keyword; return true; + case "min12int1x2": token = TokenKind.Min12Int1x2Keyword; return true; + case "min12int1x3": token = TokenKind.Min12Int1x3Keyword; return true; + case "min12int1x4": token = TokenKind.Min12Int1x4Keyword; return true; + case "min12int2x1": token = TokenKind.Min12Int2x1Keyword; return true; + case "min12int2x2": token = TokenKind.Min12Int2x2Keyword; return true; + case "min12int2x3": token = TokenKind.Min12Int2x3Keyword; return true; + case "min12int2x4": token = TokenKind.Min12Int2x4Keyword; return true; + case "min12int3x1": token = TokenKind.Min12Int3x1Keyword; return true; + case "min12int3x2": token = TokenKind.Min12Int3x2Keyword; return true; + case "min12int3x3": token = TokenKind.Min12Int3x3Keyword; return true; + case "min12int3x4": token = TokenKind.Min12Int3x4Keyword; return true; + case "min12int4x1": token = TokenKind.Min12Int4x1Keyword; return true; + case "min12int4x2": token = TokenKind.Min12Int4x2Keyword; return true; + case "min12int4x3": token = TokenKind.Min12Int4x3Keyword; return true; + case "min12int4x4": token = TokenKind.Min12Int4x4Keyword; return true; + case "min12uint": token = TokenKind.Min12UintKeyword; return true; + case "min12uint1": token = TokenKind.Min12Uint1Keyword; return true; + case "min12uint2": token = TokenKind.Min12Uint2Keyword; return true; + case "min12uint3": token = TokenKind.Min12Uint3Keyword; return true; + case "min12uint4": token = TokenKind.Min12Uint4Keyword; return true; + case "min12uint1x1": token = TokenKind.Min12Uint1x1Keyword; return true; + case "min12uint1x2": token = TokenKind.Min12Uint1x2Keyword; return true; + case "min12uint1x3": token = TokenKind.Min12Uint1x3Keyword; return true; + case "min12uint1x4": token = TokenKind.Min12Uint1x4Keyword; return true; + case "min12uint2x1": token = TokenKind.Min12Uint2x1Keyword; return true; + case "min12uint2x2": token = TokenKind.Min12Uint2x2Keyword; return true; + case "min12uint2x3": token = TokenKind.Min12Uint2x3Keyword; return true; + case "min12uint2x4": token = TokenKind.Min12Uint2x4Keyword; return true; + case "min12uint3x1": token = TokenKind.Min12Uint3x1Keyword; return true; + case "min12uint3x2": token = TokenKind.Min12Uint3x2Keyword; return true; + case "min12uint3x3": token = TokenKind.Min12Uint3x3Keyword; return true; + case "min12uint3x4": token = TokenKind.Min12Uint3x4Keyword; return true; + case "min12uint4x1": token = TokenKind.Min12Uint4x1Keyword; return true; + case "min12uint4x2": token = TokenKind.Min12Uint4x2Keyword; return true; + case "min12uint4x3": token = TokenKind.Min12Uint4x3Keyword; return true; + case "min12uint4x4": token = TokenKind.Min12Uint4x4Keyword; return true; + case "min16float": token = TokenKind.Min16FloatKeyword; return true; + case "min16float1": token = TokenKind.Min16Float1Keyword; return true; + case "min16float2": token = TokenKind.Min16Float2Keyword; return true; + case "min16float3": token = TokenKind.Min16Float3Keyword; return true; + case "min16float4": token = TokenKind.Min16Float4Keyword; return true; + case "min16float1x1": token = TokenKind.Min16Float1x1Keyword; return true; + case "min16float1x2": token = TokenKind.Min16Float1x2Keyword; return true; + case "min16float1x3": token = TokenKind.Min16Float1x3Keyword; return true; + case "min16float1x4": token = TokenKind.Min16Float1x4Keyword; return true; + case "min16float2x1": token = TokenKind.Min16Float2x1Keyword; return true; + case "min16float2x2": token = TokenKind.Min16Float2x2Keyword; return true; + case "min16float2x3": token = TokenKind.Min16Float2x3Keyword; return true; + case "min16float2x4": token = TokenKind.Min16Float2x4Keyword; return true; + case "min16float3x1": token = TokenKind.Min16Float3x1Keyword; return true; + case "min16float3x2": token = TokenKind.Min16Float3x2Keyword; return true; + case "min16float3x3": token = TokenKind.Min16Float3x3Keyword; return true; + case "min16float3x4": token = TokenKind.Min16Float3x4Keyword; return true; + case "min16float4x1": token = TokenKind.Min16Float4x1Keyword; return true; + case "min16float4x2": token = TokenKind.Min16Float4x2Keyword; return true; + case "min16float4x3": token = TokenKind.Min16Float4x3Keyword; return true; + case "min16float4x4": token = TokenKind.Min16Float4x4Keyword; return true; + case "min16int": token = TokenKind.Min16IntKeyword; return true; + case "min16int1": token = TokenKind.Min16Int1Keyword; return true; + case "min16int2": token = TokenKind.Min16Int2Keyword; return true; + case "min16int3": token = TokenKind.Min16Int3Keyword; return true; + case "min16int4": token = TokenKind.Min16Int4Keyword; return true; + case "min16int1x1": token = TokenKind.Min16Int1x1Keyword; return true; + case "min16int1x2": token = TokenKind.Min16Int1x2Keyword; return true; + case "min16int1x3": token = TokenKind.Min16Int1x3Keyword; return true; + case "min16int1x4": token = TokenKind.Min16Int1x4Keyword; return true; + case "min16int2x1": token = TokenKind.Min16Int2x1Keyword; return true; + case "min16int2x2": token = TokenKind.Min16Int2x2Keyword; return true; + case "min16int2x3": token = TokenKind.Min16Int2x3Keyword; return true; + case "min16int2x4": token = TokenKind.Min16Int2x4Keyword; return true; + case "min16int3x1": token = TokenKind.Min16Int3x1Keyword; return true; + case "min16int3x2": token = TokenKind.Min16Int3x2Keyword; return true; + case "min16int3x3": token = TokenKind.Min16Int3x3Keyword; return true; + case "min16int3x4": token = TokenKind.Min16Int3x4Keyword; return true; + case "min16int4x1": token = TokenKind.Min16Int4x1Keyword; return true; + case "min16int4x2": token = TokenKind.Min16Int4x2Keyword; return true; + case "min16int4x3": token = TokenKind.Min16Int4x3Keyword; return true; + case "min16int4x4": token = TokenKind.Min16Int4x4Keyword; return true; + case "min16uint": token = TokenKind.Min16UintKeyword; return true; + case "min16uint1": token = TokenKind.Min16Uint1Keyword; return true; + case "min16uint2": token = TokenKind.Min16Uint2Keyword; return true; + case "min16uint3": token = TokenKind.Min16Uint3Keyword; return true; + case "min16uint4": token = TokenKind.Min16Uint4Keyword; return true; + case "min16uint1x1": token = TokenKind.Min16Uint1x1Keyword; return true; + case "min16uint1x2": token = TokenKind.Min16Uint1x2Keyword; return true; + case "min16uint1x3": token = TokenKind.Min16Uint1x3Keyword; return true; + case "min16uint1x4": token = TokenKind.Min16Uint1x4Keyword; return true; + case "min16uint2x1": token = TokenKind.Min16Uint2x1Keyword; return true; + case "min16uint2x2": token = TokenKind.Min16Uint2x2Keyword; return true; + case "min16uint2x3": token = TokenKind.Min16Uint2x3Keyword; return true; + case "min16uint2x4": token = TokenKind.Min16Uint2x4Keyword; return true; + case "min16uint3x1": token = TokenKind.Min16Uint3x1Keyword; return true; + case "min16uint3x2": token = TokenKind.Min16Uint3x2Keyword; return true; + case "min16uint3x3": token = TokenKind.Min16Uint3x3Keyword; return true; + case "min16uint3x4": token = TokenKind.Min16Uint3x4Keyword; return true; + case "min16uint4x1": token = TokenKind.Min16Uint4x1Keyword; return true; + case "min16uint4x2": token = TokenKind.Min16Uint4x2Keyword; return true; + case "min16uint4x3": token = TokenKind.Min16Uint4x3Keyword; return true; + case "min16uint4x4": token = TokenKind.Min16Uint4x4Keyword; return true; + case "namespace": token = TokenKind.NamespaceKeyword; return true; + case "nointerpolation": token = TokenKind.NointerpolationKeyword; return true; + case "noperspective": token = TokenKind.NoperspectiveKeyword; return true; + case "NULL": token = TokenKind.NullKeyword; return true; + case "out": token = TokenKind.OutKeyword; return true; + case "OutputPatch": token = TokenKind.OutputPatchKeyword; return true; + case "packmatrix": token = TokenKind.PackMatrixKeyword; return true; + case "packoffset": token = TokenKind.PackoffsetKeyword; return true; + case "Pass": token = TokenKind.PassKeyword; return true; + case "pass": token = TokenKind.PassKeyword; return true; + case "payload": token = TokenKind.PayloadKeyword; return true; + case "point": token = TokenKind.PointKeyword; return true; + case "PointStream": token = TokenKind.PointStreamKeyword; return true; + case "pragma": token = TokenKind.PragmaKeyword; return true; + case "precise": token = TokenKind.PreciseKeyword; return true; + case "primitives": token = TokenKind.PrimitivesKeyword; return true; + case "rasterizerorderedbuffer": token = TokenKind.RasterizerOrderedBufferKeyword; return true; + case "rasterizerorderedbyteaddressbuffer": token = TokenKind.RasterizerOrderedByteAddressBufferKeyword; return true; + case "rasterizerorderedstructuredbuffer": token = TokenKind.RasterizerOrderedStructuredBufferKeyword; return true; + case "rasterizerorderedtexture1d": token = TokenKind.RasterizerOrderedTexture1DKeyword; return true; + case "rasterizerorderedtexture1darray": token = TokenKind.RasterizerOrderedTexture1DArrayKeyword; return true; + case "rasterizerorderedtexture2d": token = TokenKind.RasterizerOrderedTexture2DKeyword; return true; + case "rasterizerorderedtexture2darray": token = TokenKind.RasterizerOrderedTexture2DArrayKeyword; return true; + case "rasterizerorderedtexture3d": token = TokenKind.RasterizerOrderedTexture3DKeyword; return true; + case "RasterizerState": token = TokenKind.RasterizerStateKeyword; return true; + case "register": token = TokenKind.RegisterKeyword; return true; + case "return": token = TokenKind.ReturnKeyword; return true; + case "row_major": token = TokenKind.RowMajorKeyword; return true; + case "RWBuffer": token = TokenKind.RWBufferKeyword; return true; + case "RWByteAddressBuffer": token = TokenKind.RWByteAddressBufferKeyword; return true; + case "RWStructuredBuffer": token = TokenKind.RWStructuredBufferKeyword; return true; + case "RWTexture1D": token = TokenKind.RWTexture1DKeyword; return true; + case "RWTexture1DArray": token = TokenKind.RWTexture1DArrayKeyword; return true; + case "RWTexture2D": token = TokenKind.RWTexture2DKeyword; return true; + case "RWTexture2DArray": token = TokenKind.RWTexture2DArrayKeyword; return true; + case "RWTexture3D": token = TokenKind.RWTexture3DKeyword; return true; + case "sampler": token = TokenKind.SamplerKeyword; return true; + case "sampler1d": token = TokenKind.Sampler1DKeyword; return true; + case "sampler2d": token = TokenKind.Sampler2DKeyword; return true; + case "sampler3d": token = TokenKind.Sampler3DKeyword; return true; + case "samplercube": token = TokenKind.SamplerCubeKeyword; return true; + case "SamplerComparisonState": token = TokenKind.SamplerComparisonStateKeyword; return true; + case "SamplerState": token = TokenKind.SamplerStateKeyword; return true; + case "sampler_state": token = TokenKind.SamplerStateLegacyKeyword; return true; + case "shared": token = TokenKind.SharedKeyword; return true; + case "snorm": token = TokenKind.SNormKeyword; return true; + case "static": token = TokenKind.StaticKeyword; return true; + case "string": token = TokenKind.StringKeyword; return true; + case "struct": token = TokenKind.StructKeyword; return true; + case "StructuredBuffer": token = TokenKind.StructuredBufferKeyword; return true; + case "switch": token = TokenKind.SwitchKeyword; return true; + case "tbuffer": token = TokenKind.TBufferKeyword; return true; + case "Technique": token = TokenKind.TechniqueKeyword; return true; + case "technique": token = TokenKind.TechniqueKeyword; return true; + case "technique10": token = TokenKind.Technique10Keyword; return true; + case "technique11": token = TokenKind.Technique11Keyword; return true; + case "texture": token = TokenKind.TextureKeyword; return true; + case "Texture2DLegacy": token = TokenKind.Texture2DLegacyKeyword; return true; + case "TextureCubeLegacy": token = TokenKind.TextureCubeLegacyKeyword; return true; + case "Texture1D": token = TokenKind.Texture1DKeyword; return true; + case "Texture1DArray": token = TokenKind.Texture1DArrayKeyword; return true; + case "Texture2D": token = TokenKind.Texture2DKeyword; return true; + case "Texture2DArray": token = TokenKind.Texture2DArrayKeyword; return true; + case "Texture2DMS": token = TokenKind.Texture2DMSKeyword; return true; + case "Texture2DMSArray": token = TokenKind.Texture2DMSArrayKeyword; return true; + case "Texture3D": token = TokenKind.Texture3DKeyword; return true; + case "TextureCube": token = TokenKind.TextureCubeKeyword; return true; + case "TextureCubeArray": token = TokenKind.TextureCubeArrayKeyword; return true; + case "triangle": token = TokenKind.TriangleKeyword; return true; + case "triangleadj": token = TokenKind.TriangleAdjKeyword; return true; + case "TriangleStream": token = TokenKind.TriangleStreamKeyword; return true; + case "typedef": token = TokenKind.TypedefKeyword; return true; + case "uniform": token = TokenKind.UniformKeyword; return true; + case "unorm": token = TokenKind.UNormKeyword; return true; + case "uint": token = TokenKind.UintKeyword; return true; + case "uint1": token = TokenKind.Uint1Keyword; return true; + case "uint2": token = TokenKind.Uint2Keyword; return true; + case "uint3": token = TokenKind.Uint3Keyword; return true; + case "uint4": token = TokenKind.Uint4Keyword; return true; + case "uint1x1": token = TokenKind.Uint1x1Keyword; return true; + case "uint1x2": token = TokenKind.Uint1x2Keyword; return true; + case "uint1x3": token = TokenKind.Uint1x3Keyword; return true; + case "uint1x4": token = TokenKind.Uint1x4Keyword; return true; + case "uint2x1": token = TokenKind.Uint2x1Keyword; return true; + case "uint2x2": token = TokenKind.Uint2x2Keyword; return true; + case "uint2x3": token = TokenKind.Uint2x3Keyword; return true; + case "uint2x4": token = TokenKind.Uint2x4Keyword; return true; + case "uint3x1": token = TokenKind.Uint3x1Keyword; return true; + case "uint3x2": token = TokenKind.Uint3x2Keyword; return true; + case "uint3x3": token = TokenKind.Uint3x3Keyword; return true; + case "uint3x4": token = TokenKind.Uint3x4Keyword; return true; + case "uint4x1": token = TokenKind.Uint4x1Keyword; return true; + case "uint4x2": token = TokenKind.Uint4x2Keyword; return true; + case "uint4x3": token = TokenKind.Uint4x3Keyword; return true; + case "uint4x4": token = TokenKind.Uint4x4Keyword; return true; + case "vector": token = TokenKind.VectorKeyword; return true; + case "vertices": token = TokenKind.VerticesKeyword; return true; + case "volatile": token = TokenKind.VolatileKeyword; return true; + case "void": token = TokenKind.VoidKeyword; return true; + case "warning": token = TokenKind.WarningKeyword; return true; + case "while": token = TokenKind.WhileKeyword; return true; + case "true": token = TokenKind.TrueKeyword; return true; + case "false": token = TokenKind.FalseKeyword; return true; + case "unsigned": token = TokenKind.UnsignedKeyword; return true; + case "dword": token = TokenKind.DwordKeyword; return true; + case "compile_fragment": token = TokenKind.CompileFragmentKeyword; return true; + case "DepthStencilView": token = TokenKind.DepthStencilViewKeyword; return true; + case "pixelfragment": token = TokenKind.PixelfragmentKeyword; return true; + case "RenderTargetView": token = TokenKind.RenderTargetViewKeyword; return true; + case "stateblock_state": token = TokenKind.StateblockStateKeyword; return true; + case "stateblock": token = TokenKind.StateblockKeyword; return true; + default: token = TokenKind.InvalidToken; return false; + } + } + + public static bool TryConvertToScalarType(TokenKind kind, out ScalarType type) + { + switch (kind) + { + case TokenKind.VoidKeyword: type = ScalarType.Void; return true; + case TokenKind.BoolKeyword: type = ScalarType.Bool; return true; + case TokenKind.IntKeyword: type = ScalarType.Int; return true; + case TokenKind.UintKeyword: type = ScalarType.Uint; return true; + case TokenKind.HalfKeyword: type = ScalarType.Half; return true; + case TokenKind.FloatKeyword: type = ScalarType.Float; return true; + case TokenKind.DoubleKeyword: type = ScalarType.Double; return true; + case TokenKind.Min16FloatKeyword: type = ScalarType.Min16Float; return true; + case TokenKind.Min10FloatKeyword: type = ScalarType.Min10Float; return true; + case TokenKind.Min16IntKeyword: type = ScalarType.Min16Int; return true; + case TokenKind.Min12IntKeyword: type = ScalarType.Min12Int; return true; + case TokenKind.Min16UintKeyword: type = ScalarType.Min16Uint; return true; + case TokenKind.Min12UintKeyword: type = ScalarType.Min12Uint; return true; + case TokenKind.StringKeyword: type = ScalarType.String; return true; + default: type = ScalarType.Void; return false; + } + } + + public static bool TryConvertToMonomorphicVectorType(TokenKind kind, out ScalarType type, out int dimension) + { + switch (kind) + { + case TokenKind.Bool1Keyword: type = ScalarType.Bool; dimension = 1; return true; + case TokenKind.Bool2Keyword: type = ScalarType.Bool; dimension = 2; return true; + case TokenKind.Bool3Keyword: type = ScalarType.Bool; dimension = 3; return true; + case TokenKind.Bool4Keyword: type = ScalarType.Bool; dimension = 4; return true; + case TokenKind.Half1Keyword: type = ScalarType.Half; dimension = 1; return true; + case TokenKind.Half2Keyword: type = ScalarType.Half; dimension = 2; return true; + case TokenKind.Half3Keyword: type = ScalarType.Half; dimension = 3; return true; + case TokenKind.Half4Keyword: type = ScalarType.Half; dimension = 4; return true; + case TokenKind.Int1Keyword: type = ScalarType.Int; dimension = 1; return true; + case TokenKind.Int2Keyword: type = ScalarType.Int; dimension = 2; return true; + case TokenKind.Int3Keyword: type = ScalarType.Int; dimension = 3; return true; + case TokenKind.Int4Keyword: type = ScalarType.Int; dimension = 4; return true; + case TokenKind.Uint1Keyword: type = ScalarType.Uint; dimension = 1; return true; + case TokenKind.Uint2Keyword: type = ScalarType.Uint; dimension = 2; return true; + case TokenKind.Uint3Keyword: type = ScalarType.Uint; dimension = 3; return true; + case TokenKind.Uint4Keyword: type = ScalarType.Uint; dimension = 4; return true; + case TokenKind.Float1Keyword: type = ScalarType.Float; dimension = 1; return true; + case TokenKind.Float2Keyword: type = ScalarType.Float; dimension = 2; return true; + case TokenKind.Float3Keyword: type = ScalarType.Float; dimension = 3; return true; + case TokenKind.Float4Keyword: type = ScalarType.Float; dimension = 4; return true; + case TokenKind.Double1Keyword: type = ScalarType.Double; dimension = 1; return true; + case TokenKind.Double2Keyword: type = ScalarType.Double; dimension = 2; return true; + case TokenKind.Double3Keyword: type = ScalarType.Double; dimension = 3; return true; + case TokenKind.Double4Keyword: type = ScalarType.Double; dimension = 4; return true; + case TokenKind.Min16Float1Keyword: type = ScalarType.Min16Float; dimension = 1; return true; + case TokenKind.Min16Float2Keyword: type = ScalarType.Min16Float; dimension = 2; return true; + case TokenKind.Min16Float3Keyword: type = ScalarType.Min16Float; dimension = 3; return true; + case TokenKind.Min16Float4Keyword: type = ScalarType.Min16Float; dimension = 4; return true; + case TokenKind.Min10Float1Keyword: type = ScalarType.Min10Float; dimension = 1; return true; + case TokenKind.Min10Float2Keyword: type = ScalarType.Min10Float; dimension = 2; return true; + case TokenKind.Min10Float3Keyword: type = ScalarType.Min10Float; dimension = 3; return true; + case TokenKind.Min10Float4Keyword: type = ScalarType.Min10Float; dimension = 4; return true; + case TokenKind.Min16Int1Keyword: type = ScalarType.Min16Int; dimension = 1; return true; + case TokenKind.Min16Int2Keyword: type = ScalarType.Min16Int; dimension = 2; return true; + case TokenKind.Min16Int3Keyword: type = ScalarType.Min16Int; dimension = 3; return true; + case TokenKind.Min16Int4Keyword: type = ScalarType.Min16Int; dimension = 4; return true; + case TokenKind.Min12Int1Keyword: type = ScalarType.Min12Int; dimension = 1; return true; + case TokenKind.Min12Int2Keyword: type = ScalarType.Min12Int; dimension = 2; return true; + case TokenKind.Min12Int3Keyword: type = ScalarType.Min12Int; dimension = 3; return true; + case TokenKind.Min12Int4Keyword: type = ScalarType.Min12Int; dimension = 4; return true; + case TokenKind.Min16Uint1Keyword: type = ScalarType.Min16Uint; dimension = 1; return true; + case TokenKind.Min16Uint2Keyword: type = ScalarType.Min16Uint; dimension = 2; return true; + case TokenKind.Min16Uint3Keyword: type = ScalarType.Min16Uint; dimension = 3; return true; + case TokenKind.Min16Uint4Keyword: type = ScalarType.Min16Uint; dimension = 4; return true; + case TokenKind.Min12Uint1Keyword: type = ScalarType.Min12Uint; dimension = 1; return true; + case TokenKind.Min12Uint2Keyword: type = ScalarType.Min12Uint; dimension = 2; return true; + case TokenKind.Min12Uint3Keyword: type = ScalarType.Min12Uint; dimension = 3; return true; + case TokenKind.Min12Uint4Keyword: type = ScalarType.Min12Uint; dimension = 4; return true; + case TokenKind.VectorKeyword: type = ScalarType.Float; dimension = 4; return true; + default: type = default; dimension = 0; return false; + } + } + + public static bool TryConvertToPredefinedObjectType(Token token, out PredefinedObjectType type) + { + switch (token.Kind) + { + case TokenKind.AppendStructuredBufferKeyword: type = PredefinedObjectType.AppendStructuredBuffer; return true; + case TokenKind.BlendStateKeyword: type = PredefinedObjectType.BlendState; return true; + case TokenKind.BufferKeyword: type = PredefinedObjectType.Buffer; return true; + case TokenKind.ByteAddressBufferKeyword: type = PredefinedObjectType.ByteAddressBuffer; return true; + case TokenKind.ConsumeStructuredBufferKeyword: type = PredefinedObjectType.ConsumeStructuredBuffer; return true; + case TokenKind.DepthStencilStateKeyword: type = PredefinedObjectType.DepthStencilState; return true; + case TokenKind.InputPatchKeyword: type = PredefinedObjectType.InputPatch; return true; + case TokenKind.LineStreamKeyword: type = PredefinedObjectType.LineStream; return true; + case TokenKind.OutputPatchKeyword: type = PredefinedObjectType.OutputPatch; return true; + case TokenKind.PointStreamKeyword: type = PredefinedObjectType.PointStream; return true; + case TokenKind.RasterizerStateKeyword: type = PredefinedObjectType.RasterizerState; return true; + case TokenKind.RWBufferKeyword: type = PredefinedObjectType.RWBuffer; return true; + case TokenKind.RWByteAddressBufferKeyword: type = PredefinedObjectType.RWByteAddressBuffer; return true; + case TokenKind.RWStructuredBufferKeyword: type = PredefinedObjectType.RWStructuredBuffer; return true; + case TokenKind.RWTexture1DKeyword: type = PredefinedObjectType.RWTexture1D; return true; + case TokenKind.RWTexture1DArrayKeyword: type = PredefinedObjectType.RWTexture1DArray; return true; + case TokenKind.RWTexture2DKeyword: type = PredefinedObjectType.RWTexture2D; return true; + case TokenKind.RWTexture2DArrayKeyword: type = PredefinedObjectType.RWTexture2DArray; return true; + case TokenKind.RWTexture3DKeyword: type = PredefinedObjectType.RWTexture3D; return true; + case TokenKind.Sampler1DKeyword: type = PredefinedObjectType.Sampler1D; return true; + case TokenKind.SamplerKeyword: type = PredefinedObjectType.Sampler; return true; + case TokenKind.Sampler2DKeyword: type = PredefinedObjectType.Sampler2D; return true; + case TokenKind.Sampler3DKeyword: type = PredefinedObjectType.Sampler3D; return true; + case TokenKind.SamplerCubeKeyword: type = PredefinedObjectType.SamplerCube; return true; + case TokenKind.SamplerStateKeyword: type = PredefinedObjectType.SamplerState; return true; + case TokenKind.SamplerComparisonStateKeyword: type = PredefinedObjectType.SamplerComparisonState; return true; + case TokenKind.StructuredBufferKeyword: type = PredefinedObjectType.StructuredBuffer; return true; + case TokenKind.TextureKeyword: type = PredefinedObjectType.Texture; return true; + case TokenKind.Texture2DLegacyKeyword: type = PredefinedObjectType.Texture; return true; + case TokenKind.TextureCubeLegacyKeyword: type = PredefinedObjectType.Texture; return true; + case TokenKind.Texture1DKeyword: type = PredefinedObjectType.Texture1D; return true; + case TokenKind.Texture1DArrayKeyword: type = PredefinedObjectType.Texture1DArray; return true; + case TokenKind.Texture2DKeyword: type = PredefinedObjectType.Texture2D; return true; + case TokenKind.Texture2DArrayKeyword: type = PredefinedObjectType.Texture2DArray; return true; + case TokenKind.Texture2DMSKeyword: type = PredefinedObjectType.Texture2DMS; return true; + case TokenKind.Texture2DMSArrayKeyword: type = PredefinedObjectType.Texture2DMSArray; return true; + case TokenKind.Texture3DKeyword: type = PredefinedObjectType.Texture3D; return true; + case TokenKind.TextureCubeKeyword: type = PredefinedObjectType.TextureCube; return true; + case TokenKind.TextureCubeArrayKeyword: type = PredefinedObjectType.TextureCubeArray; return true; + case TokenKind.TriangleStreamKeyword: type = PredefinedObjectType.TriangleStream; return true; + case TokenKind.RasterizerOrderedBufferKeyword: type = PredefinedObjectType.RasterizerOrderedBuffer; return true; + case TokenKind.RasterizerOrderedByteAddressBufferKeyword: type = PredefinedObjectType.RasterizerOrderedByteAddressBuffer; return true; + case TokenKind.RasterizerOrderedStructuredBufferKeyword: type = PredefinedObjectType.RasterizerOrderedStructuredBuffer; return true; + case TokenKind.RasterizerOrderedTexture1DArrayKeyword: type = PredefinedObjectType.RasterizerOrderedTexture1DArray; return true; + case TokenKind.RasterizerOrderedTexture1DKeyword: type = PredefinedObjectType.RasterizerOrderedTexture1D; return true; + case TokenKind.RasterizerOrderedTexture2DArrayKeyword: type = PredefinedObjectType.RasterizerOrderedTexture2DArray; return true; + case TokenKind.RasterizerOrderedTexture2DKeyword: type = PredefinedObjectType.RasterizerOrderedTexture2D; return true; + case TokenKind.RasterizerOrderedTexture3DKeyword: type = PredefinedObjectType.RasterizerOrderedTexture3D; return true; + // Weird edge case of HLSL grammar - 'ConstantBuffer' is not a real keyword, but is allowed as a generic type. + case TokenKind.IdentifierToken when token.Identifier == "ConstantBuffer": type = PredefinedObjectType.ConstantBuffer; return true; + default: type = default; return false; + } + } + + public static bool TryConvertToMonomorphicMatrixType(TokenKind kind, out ScalarType type, out int dimensionX, out int dimensionY) + { + switch (kind) + { + case TokenKind.Bool1x1Keyword: type = ScalarType.Bool; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Bool1x2Keyword: type = ScalarType.Bool; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Bool1x3Keyword: type = ScalarType.Bool; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Bool1x4Keyword: type = ScalarType.Bool; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Bool2x1Keyword: type = ScalarType.Bool; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Bool2x2Keyword: type = ScalarType.Bool; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Bool2x3Keyword: type = ScalarType.Bool; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Bool2x4Keyword: type = ScalarType.Bool; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Bool3x1Keyword: type = ScalarType.Bool; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Bool3x2Keyword: type = ScalarType.Bool; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Bool3x3Keyword: type = ScalarType.Bool; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Bool3x4Keyword: type = ScalarType.Bool; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Bool4x1Keyword: type = ScalarType.Bool; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Bool4x2Keyword: type = ScalarType.Bool; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Bool4x3Keyword: type = ScalarType.Bool; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Bool4x4Keyword: type = ScalarType.Bool; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Double1x1Keyword: type = ScalarType.Double; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Double1x2Keyword: type = ScalarType.Double; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Double1x3Keyword: type = ScalarType.Double; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Double1x4Keyword: type = ScalarType.Double; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Double2x1Keyword: type = ScalarType.Double; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Double2x2Keyword: type = ScalarType.Double; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Double2x3Keyword: type = ScalarType.Double; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Double2x4Keyword: type = ScalarType.Double; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Double3x1Keyword: type = ScalarType.Double; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Double3x2Keyword: type = ScalarType.Double; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Double3x3Keyword: type = ScalarType.Double; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Double3x4Keyword: type = ScalarType.Double; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Double4x1Keyword: type = ScalarType.Double; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Double4x2Keyword: type = ScalarType.Double; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Double4x3Keyword: type = ScalarType.Double; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Double4x4Keyword: type = ScalarType.Double; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Float1x1Keyword: type = ScalarType.Float; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Float1x2Keyword: type = ScalarType.Float; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Float1x3Keyword: type = ScalarType.Float; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Float1x4Keyword: type = ScalarType.Float; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Float2x1Keyword: type = ScalarType.Float; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Float2x2Keyword: type = ScalarType.Float; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Float2x3Keyword: type = ScalarType.Float; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Float2x4Keyword: type = ScalarType.Float; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Float3x1Keyword: type = ScalarType.Float; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Float3x2Keyword: type = ScalarType.Float; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Float3x3Keyword: type = ScalarType.Float; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Float3x4Keyword: type = ScalarType.Float; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Float4x1Keyword: type = ScalarType.Float; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Float4x2Keyword: type = ScalarType.Float; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Float4x3Keyword: type = ScalarType.Float; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Float4x4Keyword: type = ScalarType.Float; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Half1x1Keyword: type = ScalarType.Half; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Half1x2Keyword: type = ScalarType.Half; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Half1x3Keyword: type = ScalarType.Half; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Half1x4Keyword: type = ScalarType.Half; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Half2x1Keyword: type = ScalarType.Half; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Half2x2Keyword: type = ScalarType.Half; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Half2x3Keyword: type = ScalarType.Half; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Half2x4Keyword: type = ScalarType.Half; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Half3x1Keyword: type = ScalarType.Half; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Half3x2Keyword: type = ScalarType.Half; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Half3x3Keyword: type = ScalarType.Half; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Half3x4Keyword: type = ScalarType.Half; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Half4x1Keyword: type = ScalarType.Half; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Half4x2Keyword: type = ScalarType.Half; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Half4x3Keyword: type = ScalarType.Half; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Half4x4Keyword: type = ScalarType.Half; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Int1x1Keyword: type = ScalarType.Int; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Int1x2Keyword: type = ScalarType.Int; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Int1x3Keyword: type = ScalarType.Int; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Int1x4Keyword: type = ScalarType.Int; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Int2x1Keyword: type = ScalarType.Int; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Int2x2Keyword: type = ScalarType.Int; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Int2x3Keyword: type = ScalarType.Int; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Int2x4Keyword: type = ScalarType.Int; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Int3x1Keyword: type = ScalarType.Int; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Int3x2Keyword: type = ScalarType.Int; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Int3x3Keyword: type = ScalarType.Int; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Int3x4Keyword: type = ScalarType.Int; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Int4x1Keyword: type = ScalarType.Int; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Int4x2Keyword: type = ScalarType.Int; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Int4x3Keyword: type = ScalarType.Int; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Int4x4Keyword: type = ScalarType.Int; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Min10Float1x1Keyword: type = ScalarType.Min10Float; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Min10Float1x2Keyword: type = ScalarType.Min10Float; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Min10Float1x3Keyword: type = ScalarType.Min10Float; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Min10Float1x4Keyword: type = ScalarType.Min10Float; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Min10Float2x1Keyword: type = ScalarType.Min10Float; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Min10Float2x2Keyword: type = ScalarType.Min10Float; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Min10Float2x3Keyword: type = ScalarType.Min10Float; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Min10Float2x4Keyword: type = ScalarType.Min10Float; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Min10Float3x1Keyword: type = ScalarType.Min10Float; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Min10Float3x2Keyword: type = ScalarType.Min10Float; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Min10Float3x3Keyword: type = ScalarType.Min10Float; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Min10Float3x4Keyword: type = ScalarType.Min10Float; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Min10Float4x1Keyword: type = ScalarType.Min10Float; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Min10Float4x2Keyword: type = ScalarType.Min10Float; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Min10Float4x3Keyword: type = ScalarType.Min10Float; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Min10Float4x4Keyword: type = ScalarType.Min10Float; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Min12Int1x1Keyword: type = ScalarType.Min12Int; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Min12Int1x2Keyword: type = ScalarType.Min12Int; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Min12Int1x3Keyword: type = ScalarType.Min12Int; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Min12Int1x4Keyword: type = ScalarType.Min12Int; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Min12Int2x1Keyword: type = ScalarType.Min12Int; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Min12Int2x2Keyword: type = ScalarType.Min12Int; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Min12Int2x3Keyword: type = ScalarType.Min12Int; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Min12Int2x4Keyword: type = ScalarType.Min12Int; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Min12Int3x1Keyword: type = ScalarType.Min12Int; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Min12Int3x2Keyword: type = ScalarType.Min12Int; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Min12Int3x3Keyword: type = ScalarType.Min12Int; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Min12Int3x4Keyword: type = ScalarType.Min12Int; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Min12Int4x1Keyword: type = ScalarType.Min12Int; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Min12Int4x2Keyword: type = ScalarType.Min12Int; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Min12Int4x3Keyword: type = ScalarType.Min12Int; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Min12Int4x4Keyword: type = ScalarType.Min12Int; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Min16Float1x1Keyword: type = ScalarType.Min16Float; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Min16Float1x2Keyword: type = ScalarType.Min16Float; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Min16Float1x3Keyword: type = ScalarType.Min16Float; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Min16Float1x4Keyword: type = ScalarType.Min16Float; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Min16Float2x1Keyword: type = ScalarType.Min16Float; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Min16Float2x2Keyword: type = ScalarType.Min16Float; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Min16Float2x3Keyword: type = ScalarType.Min16Float; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Min16Float2x4Keyword: type = ScalarType.Min16Float; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Min16Float3x1Keyword: type = ScalarType.Min16Float; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Min16Float3x2Keyword: type = ScalarType.Min16Float; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Min16Float3x3Keyword: type = ScalarType.Min16Float; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Min16Float3x4Keyword: type = ScalarType.Min16Float; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Min16Float4x1Keyword: type = ScalarType.Min16Float; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Min16Float4x2Keyword: type = ScalarType.Min16Float; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Min16Float4x3Keyword: type = ScalarType.Min16Float; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Min16Float4x4Keyword: type = ScalarType.Min16Float; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Min16Int1x1Keyword: type = ScalarType.Min16Int; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Min16Int1x2Keyword: type = ScalarType.Min16Int; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Min16Int1x3Keyword: type = ScalarType.Min16Int; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Min16Int1x4Keyword: type = ScalarType.Min16Int; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Min16Int2x1Keyword: type = ScalarType.Min16Int; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Min16Int2x2Keyword: type = ScalarType.Min16Int; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Min16Int2x3Keyword: type = ScalarType.Min16Int; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Min16Int2x4Keyword: type = ScalarType.Min16Int; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Min16Int3x1Keyword: type = ScalarType.Min16Int; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Min16Int3x2Keyword: type = ScalarType.Min16Int; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Min16Int3x3Keyword: type = ScalarType.Min16Int; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Min16Int3x4Keyword: type = ScalarType.Min16Int; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Min16Int4x1Keyword: type = ScalarType.Min16Int; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Min16Int4x2Keyword: type = ScalarType.Min16Int; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Min16Int4x3Keyword: type = ScalarType.Min16Int; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Min16Int4x4Keyword: type = ScalarType.Min16Int; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Min16Uint1x1Keyword: type = ScalarType.Min16Uint; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Min16Uint1x2Keyword: type = ScalarType.Min16Uint; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Min16Uint1x3Keyword: type = ScalarType.Min16Uint; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Min16Uint1x4Keyword: type = ScalarType.Min16Uint; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Min16Uint2x1Keyword: type = ScalarType.Min16Uint; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Min16Uint2x2Keyword: type = ScalarType.Min16Uint; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Min16Uint2x3Keyword: type = ScalarType.Min16Uint; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Min16Uint2x4Keyword: type = ScalarType.Min16Uint; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Min16Uint3x1Keyword: type = ScalarType.Min16Uint; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Min16Uint3x2Keyword: type = ScalarType.Min16Uint; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Min16Uint3x3Keyword: type = ScalarType.Min16Uint; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Min16Uint3x4Keyword: type = ScalarType.Min16Uint; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Min16Uint4x1Keyword: type = ScalarType.Min16Uint; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Min16Uint4x2Keyword: type = ScalarType.Min16Uint; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Min16Uint4x3Keyword: type = ScalarType.Min16Uint; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Min16Uint4x4Keyword: type = ScalarType.Min16Uint; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Uint1x1Keyword: type = ScalarType.Uint; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Uint1x2Keyword: type = ScalarType.Uint; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Uint1x3Keyword: type = ScalarType.Uint; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Uint1x4Keyword: type = ScalarType.Uint; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Uint2x1Keyword: type = ScalarType.Uint; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Uint2x2Keyword: type = ScalarType.Uint; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Uint2x3Keyword: type = ScalarType.Uint; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Uint2x4Keyword: type = ScalarType.Uint; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Uint3x1Keyword: type = ScalarType.Uint; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Uint3x2Keyword: type = ScalarType.Uint; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Uint3x3Keyword: type = ScalarType.Uint; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Uint3x4Keyword: type = ScalarType.Uint; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Uint4x1Keyword: type = ScalarType.Uint; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Uint4x2Keyword: type = ScalarType.Uint; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Uint4x3Keyword: type = ScalarType.Uint; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Uint4x4Keyword: type = ScalarType.Uint; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.MatrixKeyword: type = ScalarType.Float; dimensionX = 4; dimensionY = 4; return true; + case TokenKind.Min12Uint1x1Keyword: type = ScalarType.Min12Uint; dimensionX = 1; dimensionY = 1; return true; + case TokenKind.Min12Uint1x2Keyword: type = ScalarType.Min12Uint; dimensionX = 1; dimensionY = 2; return true; + case TokenKind.Min12Uint1x3Keyword: type = ScalarType.Min12Uint; dimensionX = 1; dimensionY = 3; return true; + case TokenKind.Min12Uint1x4Keyword: type = ScalarType.Min12Uint; dimensionX = 1; dimensionY = 4; return true; + case TokenKind.Min12Uint2x1Keyword: type = ScalarType.Min12Uint; dimensionX = 2; dimensionY = 1; return true; + case TokenKind.Min12Uint2x2Keyword: type = ScalarType.Min12Uint; dimensionX = 2; dimensionY = 2; return true; + case TokenKind.Min12Uint2x3Keyword: type = ScalarType.Min12Uint; dimensionX = 2; dimensionY = 3; return true; + case TokenKind.Min12Uint2x4Keyword: type = ScalarType.Min12Uint; dimensionX = 2; dimensionY = 4; return true; + case TokenKind.Min12Uint3x1Keyword: type = ScalarType.Min12Uint; dimensionX = 3; dimensionY = 1; return true; + case TokenKind.Min12Uint3x2Keyword: type = ScalarType.Min12Uint; dimensionX = 3; dimensionY = 2; return true; + case TokenKind.Min12Uint3x3Keyword: type = ScalarType.Min12Uint; dimensionX = 3; dimensionY = 3; return true; + case TokenKind.Min12Uint3x4Keyword: type = ScalarType.Min12Uint; dimensionX = 3; dimensionY = 4; return true; + case TokenKind.Min12Uint4x1Keyword: type = ScalarType.Min12Uint; dimensionX = 4; dimensionY = 1; return true; + case TokenKind.Min12Uint4x2Keyword: type = ScalarType.Min12Uint; dimensionX = 4; dimensionY = 2; return true; + case TokenKind.Min12Uint4x3Keyword: type = ScalarType.Min12Uint; dimensionX = 4; dimensionY = 3; return true; + case TokenKind.Min12Uint4x4Keyword: type = ScalarType.Min12Uint; dimensionX = 4; dimensionY = 4; return true; + default: type = default; dimensionX = 0; dimensionY = 0; return false; + } + } + + public static bool IsMultiArityNumericConstructor(TokenKind kind) + { + switch (kind) + { + case TokenKind.VectorKeyword: + case TokenKind.Bool1Keyword: + case TokenKind.Bool2Keyword: + case TokenKind.Bool3Keyword: + case TokenKind.Bool4Keyword: + case TokenKind.Half1Keyword: + case TokenKind.Half2Keyword: + case TokenKind.Half3Keyword: + case TokenKind.Half4Keyword: + case TokenKind.Int1Keyword: + case TokenKind.Int2Keyword: + case TokenKind.Int3Keyword: + case TokenKind.Int4Keyword: + case TokenKind.Uint1Keyword: + case TokenKind.Uint2Keyword: + case TokenKind.Uint3Keyword: + case TokenKind.Uint4Keyword: + case TokenKind.Float1Keyword: + case TokenKind.Float2Keyword: + case TokenKind.Float3Keyword: + case TokenKind.Float4Keyword: + case TokenKind.Double1Keyword: + case TokenKind.Double2Keyword: + case TokenKind.Double3Keyword: + case TokenKind.Double4Keyword: + case TokenKind.Min16Float1Keyword: + case TokenKind.Min16Float2Keyword: + case TokenKind.Min16Float3Keyword: + case TokenKind.Min16Float4Keyword: + case TokenKind.Min10Float1Keyword: + case TokenKind.Min10Float2Keyword: + case TokenKind.Min10Float3Keyword: + case TokenKind.Min10Float4Keyword: + case TokenKind.Min16Int1Keyword: + case TokenKind.Min16Int2Keyword: + case TokenKind.Min16Int3Keyword: + case TokenKind.Min16Int4Keyword: + case TokenKind.Min12Int1Keyword: + case TokenKind.Min12Int2Keyword: + case TokenKind.Min12Int3Keyword: + case TokenKind.Min12Int4Keyword: + case TokenKind.Min16Uint1Keyword: + case TokenKind.Min16Uint2Keyword: + case TokenKind.Min16Uint3Keyword: + case TokenKind.Min16Uint4Keyword: + case TokenKind.Min12Uint1Keyword: + case TokenKind.Min12Uint2Keyword: + case TokenKind.Min12Uint3Keyword: + case TokenKind.Min12Uint4Keyword: + case TokenKind.SNormKeyword: + case TokenKind.UNormKeyword: + + case TokenKind.MatrixKeyword: + case TokenKind.Bool1x1Keyword: + case TokenKind.Bool1x2Keyword: + case TokenKind.Bool1x3Keyword: + case TokenKind.Bool1x4Keyword: + case TokenKind.Bool2x1Keyword: + case TokenKind.Bool2x2Keyword: + case TokenKind.Bool2x3Keyword: + case TokenKind.Bool2x4Keyword: + case TokenKind.Bool3x1Keyword: + case TokenKind.Bool3x2Keyword: + case TokenKind.Bool3x3Keyword: + case TokenKind.Bool3x4Keyword: + case TokenKind.Bool4x1Keyword: + case TokenKind.Bool4x2Keyword: + case TokenKind.Bool4x3Keyword: + case TokenKind.Bool4x4Keyword: + case TokenKind.Double1x1Keyword: + case TokenKind.Double1x2Keyword: + case TokenKind.Double1x3Keyword: + case TokenKind.Double1x4Keyword: + case TokenKind.Double2x1Keyword: + case TokenKind.Double2x2Keyword: + case TokenKind.Double2x3Keyword: + case TokenKind.Double2x4Keyword: + case TokenKind.Double3x1Keyword: + case TokenKind.Double3x2Keyword: + case TokenKind.Double3x3Keyword: + case TokenKind.Double3x4Keyword: + case TokenKind.Double4x1Keyword: + case TokenKind.Double4x2Keyword: + case TokenKind.Double4x3Keyword: + case TokenKind.Double4x4Keyword: + case TokenKind.Float1x1Keyword: + case TokenKind.Float1x2Keyword: + case TokenKind.Float1x3Keyword: + case TokenKind.Float1x4Keyword: + case TokenKind.Float2x1Keyword: + case TokenKind.Float2x2Keyword: + case TokenKind.Float2x3Keyword: + case TokenKind.Float2x4Keyword: + case TokenKind.Float3x1Keyword: + case TokenKind.Float3x2Keyword: + case TokenKind.Float3x3Keyword: + case TokenKind.Float3x4Keyword: + case TokenKind.Float4x1Keyword: + case TokenKind.Float4x2Keyword: + case TokenKind.Float4x3Keyword: + case TokenKind.Float4x4Keyword: + case TokenKind.Half1x1Keyword: + case TokenKind.Half1x2Keyword: + case TokenKind.Half1x3Keyword: + case TokenKind.Half1x4Keyword: + case TokenKind.Half2x1Keyword: + case TokenKind.Half2x2Keyword: + case TokenKind.Half2x3Keyword: + case TokenKind.Half2x4Keyword: + case TokenKind.Half3x1Keyword: + case TokenKind.Half3x2Keyword: + case TokenKind.Half3x3Keyword: + case TokenKind.Half3x4Keyword: + case TokenKind.Half4x1Keyword: + case TokenKind.Half4x2Keyword: + case TokenKind.Half4x3Keyword: + case TokenKind.Half4x4Keyword: + case TokenKind.Int1x1Keyword: + case TokenKind.Int1x2Keyword: + case TokenKind.Int1x3Keyword: + case TokenKind.Int1x4Keyword: + case TokenKind.Int2x1Keyword: + case TokenKind.Int2x2Keyword: + case TokenKind.Int2x3Keyword: + case TokenKind.Int2x4Keyword: + case TokenKind.Int3x1Keyword: + case TokenKind.Int3x2Keyword: + case TokenKind.Int3x3Keyword: + case TokenKind.Int3x4Keyword: + case TokenKind.Int4x1Keyword: + case TokenKind.Int4x2Keyword: + case TokenKind.Int4x3Keyword: + case TokenKind.Int4x4Keyword: + case TokenKind.Min10Float1x1Keyword: + case TokenKind.Min10Float1x2Keyword: + case TokenKind.Min10Float1x3Keyword: + case TokenKind.Min10Float1x4Keyword: + case TokenKind.Min10Float2x1Keyword: + case TokenKind.Min10Float2x2Keyword: + case TokenKind.Min10Float2x3Keyword: + case TokenKind.Min10Float2x4Keyword: + case TokenKind.Min10Float3x1Keyword: + case TokenKind.Min10Float3x2Keyword: + case TokenKind.Min10Float3x3Keyword: + case TokenKind.Min10Float3x4Keyword: + case TokenKind.Min10Float4x1Keyword: + case TokenKind.Min10Float4x2Keyword: + case TokenKind.Min10Float4x3Keyword: + case TokenKind.Min10Float4x4Keyword: + case TokenKind.Min12Int1x1Keyword: + case TokenKind.Min12Int1x2Keyword: + case TokenKind.Min12Int1x3Keyword: + case TokenKind.Min12Int1x4Keyword: + case TokenKind.Min12Int2x1Keyword: + case TokenKind.Min12Int2x2Keyword: + case TokenKind.Min12Int2x3Keyword: + case TokenKind.Min12Int2x4Keyword: + case TokenKind.Min12Int3x1Keyword: + case TokenKind.Min12Int3x2Keyword: + case TokenKind.Min12Int3x3Keyword: + case TokenKind.Min12Int3x4Keyword: + case TokenKind.Min12Int4x1Keyword: + case TokenKind.Min12Int4x2Keyword: + case TokenKind.Min12Int4x3Keyword: + case TokenKind.Min12Int4x4Keyword: + case TokenKind.Min16Float1x1Keyword: + case TokenKind.Min16Float1x2Keyword: + case TokenKind.Min16Float1x3Keyword: + case TokenKind.Min16Float1x4Keyword: + case TokenKind.Min16Float2x1Keyword: + case TokenKind.Min16Float2x2Keyword: + case TokenKind.Min16Float2x3Keyword: + case TokenKind.Min16Float2x4Keyword: + case TokenKind.Min16Float3x1Keyword: + case TokenKind.Min16Float3x2Keyword: + case TokenKind.Min16Float3x3Keyword: + case TokenKind.Min16Float3x4Keyword: + case TokenKind.Min16Float4x1Keyword: + case TokenKind.Min16Float4x2Keyword: + case TokenKind.Min16Float4x3Keyword: + case TokenKind.Min16Float4x4Keyword: + case TokenKind.Min12Uint1x1Keyword: + case TokenKind.Min12Uint1x2Keyword: + case TokenKind.Min12Uint1x3Keyword: + case TokenKind.Min12Uint1x4Keyword: + case TokenKind.Min12Uint2x1Keyword: + case TokenKind.Min12Uint2x2Keyword: + case TokenKind.Min12Uint2x3Keyword: + case TokenKind.Min12Uint2x4Keyword: + case TokenKind.Min12Uint3x1Keyword: + case TokenKind.Min12Uint3x2Keyword: + case TokenKind.Min12Uint3x3Keyword: + case TokenKind.Min12Uint3x4Keyword: + case TokenKind.Min12Uint4x1Keyword: + case TokenKind.Min12Uint4x2Keyword: + case TokenKind.Min12Uint4x3Keyword: + case TokenKind.Min12Uint4x4Keyword: + case TokenKind.Min16Int1x1Keyword: + case TokenKind.Min16Int1x2Keyword: + case TokenKind.Min16Int1x3Keyword: + case TokenKind.Min16Int1x4Keyword: + case TokenKind.Min16Int2x1Keyword: + case TokenKind.Min16Int2x2Keyword: + case TokenKind.Min16Int2x3Keyword: + case TokenKind.Min16Int2x4Keyword: + case TokenKind.Min16Int3x1Keyword: + case TokenKind.Min16Int3x2Keyword: + case TokenKind.Min16Int3x3Keyword: + case TokenKind.Min16Int3x4Keyword: + case TokenKind.Min16Int4x1Keyword: + case TokenKind.Min16Int4x2Keyword: + case TokenKind.Min16Int4x3Keyword: + case TokenKind.Min16Int4x4Keyword: + case TokenKind.Min16Uint1x1Keyword: + case TokenKind.Min16Uint1x2Keyword: + case TokenKind.Min16Uint1x3Keyword: + case TokenKind.Min16Uint1x4Keyword: + case TokenKind.Min16Uint2x1Keyword: + case TokenKind.Min16Uint2x2Keyword: + case TokenKind.Min16Uint2x3Keyword: + case TokenKind.Min16Uint2x4Keyword: + case TokenKind.Min16Uint3x1Keyword: + case TokenKind.Min16Uint3x2Keyword: + case TokenKind.Min16Uint3x3Keyword: + case TokenKind.Min16Uint3x4Keyword: + case TokenKind.Min16Uint4x1Keyword: + case TokenKind.Min16Uint4x2Keyword: + case TokenKind.Min16Uint4x3Keyword: + case TokenKind.Min16Uint4x4Keyword: + case TokenKind.Uint1x1Keyword: + case TokenKind.Uint1x2Keyword: + case TokenKind.Uint1x3Keyword: + case TokenKind.Uint1x4Keyword: + case TokenKind.Uint2x1Keyword: + case TokenKind.Uint2x2Keyword: + case TokenKind.Uint2x3Keyword: + case TokenKind.Uint2x4Keyword: + case TokenKind.Uint3x1Keyword: + case TokenKind.Uint3x2Keyword: + case TokenKind.Uint3x3Keyword: + case TokenKind.Uint3x4Keyword: + case TokenKind.Uint4x1Keyword: + case TokenKind.Uint4x2Keyword: + case TokenKind.Uint4x3Keyword: + case TokenKind.Uint4x4Keyword: + //case TokenKind.SNormKeyword: + //case TokenKind.UNormKeyword: + return true; + + default: + return false; + } + } + + public static bool IsSingleArityNumericConstructor(TokenKind kind) + { + switch (kind) + { + case TokenKind.BoolKeyword: + case TokenKind.HalfKeyword: + case TokenKind.IntKeyword: + case TokenKind.UintKeyword: + case TokenKind.FloatKeyword: + case TokenKind.DoubleKeyword: + case TokenKind.Min16FloatKeyword: + case TokenKind.Min16IntKeyword: + case TokenKind.Min16UintKeyword: + case TokenKind.StringKeyword: + return true; + + default: + return false; + } + } + + public static bool IsBuiltinType(TokenKind kind) + { + switch (kind) + { + case TokenKind.BoolKeyword: + case TokenKind.IntKeyword: + case TokenKind.UnsignedKeyword: + case TokenKind.DwordKeyword: + case TokenKind.UintKeyword: + case TokenKind.HalfKeyword: + case TokenKind.FloatKeyword: + case TokenKind.DoubleKeyword: + case TokenKind.Min16FloatKeyword: + case TokenKind.Min10FloatKeyword: + case TokenKind.Min16IntKeyword: + case TokenKind.Min12IntKeyword: + case TokenKind.Min16UintKeyword: + case TokenKind.Min12UintKeyword: + case TokenKind.VoidKeyword: + case TokenKind.StringKeyword: + case TokenKind.SNormKeyword: + case TokenKind.UNormKeyword: + + case TokenKind.AppendStructuredBufferKeyword: + case TokenKind.BlendStateKeyword: + case TokenKind.BufferKeyword: + case TokenKind.ByteAddressBufferKeyword: + case TokenKind.ConsumeStructuredBufferKeyword: + case TokenKind.DepthStencilStateKeyword: + case TokenKind.InputPatchKeyword: + case TokenKind.LineStreamKeyword: + case TokenKind.OutputPatchKeyword: + case TokenKind.PointStreamKeyword: + case TokenKind.RasterizerOrderedBufferKeyword: + case TokenKind.RasterizerOrderedByteAddressBufferKeyword: + case TokenKind.RasterizerOrderedStructuredBufferKeyword: + case TokenKind.RasterizerOrderedTexture1DKeyword: + case TokenKind.RasterizerOrderedTexture1DArrayKeyword: + case TokenKind.RasterizerOrderedTexture2DKeyword: + case TokenKind.RasterizerOrderedTexture2DArrayKeyword: + case TokenKind.RasterizerOrderedTexture3DKeyword: + case TokenKind.RasterizerStateKeyword: + case TokenKind.RWBufferKeyword: + case TokenKind.RWByteAddressBufferKeyword: + case TokenKind.RWStructuredBufferKeyword: + case TokenKind.RWTexture1DKeyword: + case TokenKind.RWTexture1DArrayKeyword: + case TokenKind.RWTexture2DKeyword: + case TokenKind.RWTexture2DArrayKeyword: + case TokenKind.RWTexture3DKeyword: + case TokenKind.SamplerKeyword: + case TokenKind.Sampler1DKeyword: + case TokenKind.Sampler2DKeyword: + case TokenKind.Sampler3DKeyword: + case TokenKind.SamplerCubeKeyword: + case TokenKind.SamplerStateKeyword: + case TokenKind.SamplerComparisonStateKeyword: + case TokenKind.StructuredBufferKeyword: + case TokenKind.Texture2DLegacyKeyword: + case TokenKind.TextureCubeLegacyKeyword: + case TokenKind.Texture1DKeyword: + case TokenKind.Texture1DArrayKeyword: + case TokenKind.Texture2DKeyword: + case TokenKind.Texture2DArrayKeyword: + case TokenKind.Texture2DMSKeyword: + case TokenKind.Texture2DMSArrayKeyword: + case TokenKind.Texture3DKeyword: + case TokenKind.TextureCubeKeyword: + case TokenKind.TextureCubeArrayKeyword: + case TokenKind.TriangleStreamKeyword: + return true; + + default: + return IsMultiArityNumericConstructor(kind); + } + } + + public static bool IsModifier(TokenKind kind) + { + switch (kind) + { + case TokenKind.ConstKeyword: + case TokenKind.RowMajorKeyword: + case TokenKind.ColumnMajorKeyword: + return true; + + case TokenKind.ExportKeyword: + case TokenKind.ExternKeyword: + case TokenKind.InlineKeyword: + case TokenKind.PreciseKeyword: + case TokenKind.SharedKeyword: + case TokenKind.GloballycoherentKeyword: + case TokenKind.GroupsharedKeyword: + case TokenKind.StaticKeyword: + case TokenKind.UniformKeyword: + case TokenKind.VolatileKeyword: + return true; + + case TokenKind.SNormKeyword: + case TokenKind.UNormKeyword: + return true; + + case TokenKind.LinearKeyword: + case TokenKind.CentroidKeyword: + case TokenKind.NointerpolationKeyword: + case TokenKind.NoperspectiveKeyword: + return true; + + default: + return false; + } + } + + public static bool IsPrefixUnaryToken(TokenKind kind) + { + switch (kind) + { + case TokenKind.PlusPlusToken: + case TokenKind.MinusMinusToken: + case TokenKind.PlusToken: + case TokenKind.MinusToken: + case TokenKind.NotToken: + case TokenKind.TildeToken: + return true; + + default: + return false; + } + } + + public static bool TryConvertLiteralKind(TokenKind kind, out LiteralKind outKind) + { + switch (kind) + { + case TokenKind.StringLiteralToken: outKind = LiteralKind.String; return true; + case TokenKind.FloatLiteralToken: outKind = LiteralKind.Float; return true; + case TokenKind.IntegerLiteralToken: outKind = LiteralKind.Integer; return true; + case TokenKind.CharacterLiteralToken: outKind = LiteralKind.Character; return true; + case TokenKind.TrueKeyword: outKind = LiteralKind.Boolean; return true; + case TokenKind.FalseKeyword: outKind = LiteralKind.Boolean; return true; + case TokenKind.NullKeyword: outKind = LiteralKind.Null; return true; + default: outKind = default; return false; + } + } + + public static bool CanTokenComeAfterCast(TokenKind kind) + { + switch (kind) + { + case TokenKind.SemiToken: + case TokenKind.CloseParenToken: + case TokenKind.CloseBracketToken: + case TokenKind.OpenBraceToken: + case TokenKind.CloseBraceToken: + case TokenKind.CommaToken: + case TokenKind.EqualsToken: + case TokenKind.PlusEqualsToken: + case TokenKind.MinusEqualsToken: + case TokenKind.AsteriskEqualsToken: + case TokenKind.SlashEqualsToken: + case TokenKind.PercentEqualsToken: + case TokenKind.AmpersandEqualsToken: + case TokenKind.CaretEqualsToken: + case TokenKind.BarEqualsToken: + case TokenKind.LessThanLessThanEqualsToken: + case TokenKind.GreaterThanGreaterThanEqualsToken: + case TokenKind.QuestionToken: + case TokenKind.ColonToken: + case TokenKind.BarBarToken: + case TokenKind.AmpersandAmpersandToken: + case TokenKind.BarToken: + case TokenKind.CaretToken: + case TokenKind.AmpersandToken: + case TokenKind.EqualsEqualsToken: + case TokenKind.ExclamationEqualsToken: + case TokenKind.LessThanToken: + case TokenKind.LessThanEqualsToken: + case TokenKind.GreaterThanToken: + case TokenKind.GreaterThanEqualsToken: + case TokenKind.LessThanLessThanToken: + case TokenKind.GreaterThanGreaterThanToken: + case TokenKind.PlusToken: + case TokenKind.MinusToken: + case TokenKind.AsteriskToken: + case TokenKind.SlashToken: + case TokenKind.PercentToken: + case TokenKind.PlusPlusToken: + case TokenKind.MinusMinusToken: + case TokenKind.OpenBracketToken: + case TokenKind.DotToken: + return false; + + default: + return true; + } + } + + public static bool TryConvertToDeclarationModifier(Token token, out BindingModifier modifier) + { + switch (token.Kind) + { + case TokenKind.ConstKeyword: modifier = BindingModifier.Const; return true; + case TokenKind.RowMajorKeyword: modifier = BindingModifier.RowMajor; return true; + case TokenKind.ColumnMajorKeyword: modifier = BindingModifier.ColumnMajor; return true; + case TokenKind.ExportKeyword: modifier = BindingModifier.Export; return true; + case TokenKind.ExternKeyword: modifier = BindingModifier.Extern; return true; + case TokenKind.InlineKeyword: modifier = BindingModifier.Inline; return true; + case TokenKind.PreciseKeyword: modifier = BindingModifier.Precise; return true; + case TokenKind.SharedKeyword: modifier = BindingModifier.Shared; return true; + case TokenKind.GloballycoherentKeyword: modifier = BindingModifier.Globallycoherent; return true; + case TokenKind.GroupsharedKeyword: modifier = BindingModifier.Groupshared; return true; + case TokenKind.StaticKeyword: modifier = BindingModifier.Static; return true; + case TokenKind.UniformKeyword: modifier = BindingModifier.Uniform; return true; + case TokenKind.VolatileKeyword: modifier = BindingModifier.Volatile; return true; + case TokenKind.SNormKeyword: modifier = BindingModifier.SNorm; return true; + case TokenKind.UNormKeyword: modifier = BindingModifier.UNorm; return true; + case TokenKind.LinearKeyword: modifier = BindingModifier.Linear; return true; + case TokenKind.CentroidKeyword: modifier = BindingModifier.Centroid; return true; + case TokenKind.NointerpolationKeyword: modifier = BindingModifier.Nointerpolation; return true; + case TokenKind.NoperspectiveKeyword: modifier = BindingModifier.Noperspective; return true; + // Weird edge case of HLSL grammar - 'sample' is not a real keyword. + case TokenKind.IdentifierToken when token.Identifier == "sample": modifier = BindingModifier.Sample; return true; + default: modifier = default; return false; + } + } + + public static bool TryConvertToParameterModifier(Token token, out BindingModifier modifier) + { + if (TryConvertToDeclarationModifier(token, out modifier)) + return true; + + switch (token.Kind) + { + case TokenKind.InKeyword: modifier = BindingModifier.In; return true; + case TokenKind.OutKeyword: modifier = BindingModifier.Out; return true; + case TokenKind.InoutKeyword: modifier = BindingModifier.Inout; return true; + case TokenKind.PointKeyword: modifier = BindingModifier.Point; return true; + case TokenKind.TriangleKeyword: modifier = BindingModifier.Triangle; return true; + case TokenKind.TriangleAdjKeyword: modifier = BindingModifier.TriangleAdj; return true; + case TokenKind.LineKeyword: modifier = BindingModifier.Line; return true; + case TokenKind.LineAdjKeyword: modifier = BindingModifier.LineAdj; return true; + default: modifier = default; return false; + } + } + + public static ScalarType MakeUnsigned(ScalarType type) + { + switch (type) + { + case ScalarType.Int: return ScalarType.Uint; + case ScalarType.Min12Int: return ScalarType.Min12Uint; + case ScalarType.Min16Int: return ScalarType.Min16Uint; + default: return type; + } + } + + public static ScalarType MakeNormed(ScalarType type, TokenKind norm) + { + if (type == ScalarType.Float) + { + if (norm == TokenKind.UNormKeyword) + return ScalarType.UNormFloat; + else if (norm == TokenKind.SNormKeyword) + return ScalarType.SNormFloat; + else + return type; + } + else + { + return type; + } + } + + public static bool TryConvertToOperator(TokenKind kind, out OperatorKind op) + { + switch (kind) + { + case TokenKind.EqualsToken: op = OperatorKind.Assignment; return true; + case TokenKind.PlusEqualsToken: op = OperatorKind.PlusAssignment; return true; + case TokenKind.MinusEqualsToken: op = OperatorKind.MinusAssignment; return true; + case TokenKind.AsteriskEqualsToken: op = OperatorKind.MulAssignment; return true; + case TokenKind.SlashEqualsToken: op = OperatorKind.DivAssignment; return true; + case TokenKind.PercentEqualsToken: op = OperatorKind.ModAssignment; return true; + case TokenKind.LessThanLessThanEqualsToken: op = OperatorKind.ShiftLeftAssignment; return true; + case TokenKind.GreaterThanGreaterThanEqualsToken: op = OperatorKind.ShiftRightAssignment; return true; + case TokenKind.AmpersandEqualsToken: op = OperatorKind.BitwiseAndAssignment; return true; + case TokenKind.CaretEqualsToken: op = OperatorKind.BitwiseXorAssignment; return true; + case TokenKind.BarEqualsToken: op = OperatorKind.BitwiseOrAssignment; return true; + case TokenKind.BarBarToken: op = OperatorKind.LogicalOr; return true; + case TokenKind.AmpersandAmpersandToken: op = OperatorKind.LogicalAnd; return true; + case TokenKind.BarToken: op = OperatorKind.BitwiseOr; return true; + case TokenKind.AmpersandToken: op = OperatorKind.BitwiseAnd; return true; + case TokenKind.CaretToken: op = OperatorKind.BitwiseXor; return true; + case TokenKind.CommaToken: op = OperatorKind.Compound; return true; + case TokenKind.QuestionToken: op = OperatorKind.Ternary; return true; + case TokenKind.EqualsEqualsToken: op = OperatorKind.Equals; return true; + case TokenKind.ExclamationEqualsToken: op = OperatorKind.NotEquals; return true; + case TokenKind.LessThanToken: op = OperatorKind.LessThan; return true; + case TokenKind.LessThanEqualsToken: op = OperatorKind.LessThanOrEquals; return true; + case TokenKind.GreaterThanToken: op = OperatorKind.GreaterThan; return true; + case TokenKind.GreaterThanEqualsToken: op = OperatorKind.GreaterThanOrEquals; return true; + case TokenKind.LessThanLessThanToken: op = OperatorKind.ShiftLeft; return true; + case TokenKind.GreaterThanGreaterThanToken: op = OperatorKind.ShiftRight; return true; + case TokenKind.PlusToken: op = OperatorKind.Plus; return true; + case TokenKind.MinusToken: op = OperatorKind.Minus; return true; + case TokenKind.AsteriskToken: op = OperatorKind.Mul; return true; + case TokenKind.SlashToken: op = OperatorKind.Div; return true; + case TokenKind.PercentToken: op = OperatorKind.Mod; return true; + case TokenKind.PlusPlusToken: op = OperatorKind.Increment; return true; + case TokenKind.MinusMinusToken: op = OperatorKind.Decrement; return true; + case TokenKind.NotToken: op = OperatorKind.Not; return true; + case TokenKind.TildeToken: op = OperatorKind.BitFlip; return true; + default: + op = default; + return false; + } + } + + public static OperatorPrecedence GetPrecedence(OperatorKind op, OperatorFixity fixity) + { + switch (op) + { + case OperatorKind.Compound: + return OperatorPrecedence.Compound; + case OperatorKind.Assignment: + case OperatorKind.PlusAssignment: + case OperatorKind.MinusAssignment: + case OperatorKind.MulAssignment: + case OperatorKind.DivAssignment: + case OperatorKind.ModAssignment: + case OperatorKind.ShiftLeftAssignment: + case OperatorKind.ShiftRightAssignment: + case OperatorKind.BitwiseAndAssignment: + case OperatorKind.BitwiseXorAssignment: + case OperatorKind.BitwiseOrAssignment: + return OperatorPrecedence.Assignment; + case OperatorKind.Ternary: + return OperatorPrecedence.Ternary; + case OperatorKind.LogicalOr: + return OperatorPrecedence.LogicalOr; + case OperatorKind.LogicalAnd: + return OperatorPrecedence.LogicalAnd; + case OperatorKind.BitwiseOr: + return OperatorPrecedence.BitwiseOr; + case OperatorKind.BitwiseXor: + return OperatorPrecedence.BitwiseXor; + case OperatorKind.BitwiseAnd: + return OperatorPrecedence.BitwiseAnd; + case OperatorKind.Equals: + case OperatorKind.NotEquals: + return OperatorPrecedence.Equality; + case OperatorKind.LessThan: + case OperatorKind.LessThanOrEquals: + case OperatorKind.GreaterThan: + case OperatorKind.GreaterThanOrEquals: + return OperatorPrecedence.Comparison; + case OperatorKind.ShiftLeft: + case OperatorKind.ShiftRight: + return OperatorPrecedence.BitShift; + case OperatorKind.Plus when fixity == OperatorFixity.Infix: + case OperatorKind.Minus when fixity == OperatorFixity.Infix: + return OperatorPrecedence.AddSub; + case OperatorKind.Mul: + case OperatorKind.Div: + case OperatorKind.Mod: + return OperatorPrecedence.MulDivMod; + case OperatorKind.Plus: + case OperatorKind.Minus: + case OperatorKind.Not: + case OperatorKind.BitFlip: + case OperatorKind.Increment when fixity == OperatorFixity.Prefix: + case OperatorKind.Decrement when fixity == OperatorFixity.Prefix: + return OperatorPrecedence.PrefixUnary; + case OperatorKind.Increment: + case OperatorKind.Decrement: + return OperatorPrecedence.PostFixUnary; + default: + return OperatorPrecedence.Compound; + } + } + + public static bool TryConvertKeywordToString(TokenKind kind, out string result) + { + switch (kind) + { + case TokenKind.AppendStructuredBufferKeyword: result = "AppendStructuredBuffer"; return true; + case TokenKind.BlendStateKeyword: result = "BlendState"; return true; + case TokenKind.BoolKeyword: result = "bool"; return true; + case TokenKind.Bool1Keyword: result = "bool1"; return true; + case TokenKind.Bool2Keyword: result = "bool2"; return true; + case TokenKind.Bool3Keyword: result = "bool3"; return true; + case TokenKind.Bool4Keyword: result = "bool4"; return true; + case TokenKind.Bool1x1Keyword: result = "bool1x1"; return true; + case TokenKind.Bool1x2Keyword: result = "bool1x2"; return true; + case TokenKind.Bool1x3Keyword: result = "bool1x3"; return true; + case TokenKind.Bool1x4Keyword: result = "bool1x4"; return true; + case TokenKind.Bool2x1Keyword: result = "bool2x1"; return true; + case TokenKind.Bool2x2Keyword: result = "bool2x2"; return true; + case TokenKind.Bool2x3Keyword: result = "bool2x3"; return true; + case TokenKind.Bool2x4Keyword: result = "bool2x4"; return true; + case TokenKind.Bool3x1Keyword: result = "bool3x1"; return true; + case TokenKind.Bool3x2Keyword: result = "bool3x2"; return true; + case TokenKind.Bool3x3Keyword: result = "bool3x3"; return true; + case TokenKind.Bool3x4Keyword: result = "bool3x4"; return true; + case TokenKind.Bool4x1Keyword: result = "bool4x1"; return true; + case TokenKind.Bool4x2Keyword: result = "bool4x2"; return true; + case TokenKind.Bool4x3Keyword: result = "bool4x3"; return true; + case TokenKind.Bool4x4Keyword: result = "bool4x4"; return true; + case TokenKind.BufferKeyword: result = "Buffer"; return true; + case TokenKind.ByteAddressBufferKeyword: result = "ByteAddressBuffer"; return true; + case TokenKind.BreakKeyword: result = "break"; return true; + case TokenKind.CaseKeyword: result = "case"; return true; + case TokenKind.CBufferKeyword: result = "cbuffer"; return true; + case TokenKind.CentroidKeyword: result = "centroid"; return true; + case TokenKind.ClassKeyword: result = "class"; return true; + case TokenKind.ColumnMajorKeyword: result = "column_major"; return true; + case TokenKind.CompileKeyword: result = "compile"; return true; + case TokenKind.ConstKeyword: result = "const"; return true; + case TokenKind.ConsumeStructuredBufferKeyword: result = "ConsumeStructuredBuffer"; return true; + case TokenKind.ContinueKeyword: result = "continue"; return true; + case TokenKind.DefaultKeyword: result = "default"; return true; + case TokenKind.DefKeyword: result = "def"; return true; + case TokenKind.DepthStencilStateKeyword: result = "DepthStencilState"; return true; + case TokenKind.DiscardKeyword: result = "discard"; return true; + case TokenKind.DoKeyword: result = "do"; return true; + case TokenKind.DoubleKeyword: result = "double"; return true; + case TokenKind.Double1Keyword: result = "double1"; return true; + case TokenKind.Double2Keyword: result = "double2"; return true; + case TokenKind.Double3Keyword: result = "double3"; return true; + case TokenKind.Double4Keyword: result = "double4"; return true; + case TokenKind.Double1x1Keyword: result = "double1x1"; return true; + case TokenKind.Double1x2Keyword: result = "double1x2"; return true; + case TokenKind.Double1x3Keyword: result = "double1x3"; return true; + case TokenKind.Double1x4Keyword: result = "double1x4"; return true; + case TokenKind.Double2x1Keyword: result = "double2x1"; return true; + case TokenKind.Double2x2Keyword: result = "double2x2"; return true; + case TokenKind.Double2x3Keyword: result = "double2x3"; return true; + case TokenKind.Double2x4Keyword: result = "double2x4"; return true; + case TokenKind.Double3x1Keyword: result = "double3x1"; return true; + case TokenKind.Double3x2Keyword: result = "double3x2"; return true; + case TokenKind.Double3x3Keyword: result = "double3x3"; return true; + case TokenKind.Double3x4Keyword: result = "double3x4"; return true; + case TokenKind.Double4x1Keyword: result = "double4x1"; return true; + case TokenKind.Double4x2Keyword: result = "double4x2"; return true; + case TokenKind.Double4x3Keyword: result = "double4x3"; return true; + case TokenKind.Double4x4Keyword: result = "double4x4"; return true; + case TokenKind.ElseKeyword: result = "else"; return true; + case TokenKind.ErrorKeyword: result = "error"; return true; + case TokenKind.ExportKeyword: result = "export"; return true; + case TokenKind.ExternKeyword: result = "extern"; return true; + case TokenKind.FloatKeyword: result = "float"; return true; + case TokenKind.Float1Keyword: result = "float1"; return true; + case TokenKind.Float2Keyword: result = "float2"; return true; + case TokenKind.Float3Keyword: result = "float3"; return true; + case TokenKind.Float4Keyword: result = "float4"; return true; + case TokenKind.Float1x1Keyword: result = "float1x1"; return true; + case TokenKind.Float1x2Keyword: result = "float1x2"; return true; + case TokenKind.Float1x3Keyword: result = "float1x3"; return true; + case TokenKind.Float1x4Keyword: result = "float1x4"; return true; + case TokenKind.Float2x1Keyword: result = "float2x1"; return true; + case TokenKind.Float2x2Keyword: result = "float2x2"; return true; + case TokenKind.Float2x3Keyword: result = "float2x3"; return true; + case TokenKind.Float2x4Keyword: result = "float2x4"; return true; + case TokenKind.Float3x1Keyword: result = "float3x1"; return true; + case TokenKind.Float3x2Keyword: result = "float3x2"; return true; + case TokenKind.Float3x3Keyword: result = "float3x3"; return true; + case TokenKind.Float3x4Keyword: result = "float3x4"; return true; + case TokenKind.Float4x1Keyword: result = "float4x1"; return true; + case TokenKind.Float4x2Keyword: result = "float4x2"; return true; + case TokenKind.Float4x3Keyword: result = "float4x3"; return true; + case TokenKind.Float4x4Keyword: result = "float4x4"; return true; + case TokenKind.ForKeyword: result = "for"; return true; + case TokenKind.GloballycoherentKeyword: result = "globallycoherent"; return true; + case TokenKind.GroupsharedKeyword: result = "groupshared"; return true; + case TokenKind.HalfKeyword: result = "half"; return true; + case TokenKind.Half1Keyword: result = "half1"; return true; + case TokenKind.Half2Keyword: result = "half2"; return true; + case TokenKind.Half3Keyword: result = "half3"; return true; + case TokenKind.Half4Keyword: result = "half4"; return true; + case TokenKind.Half1x1Keyword: result = "half1x1"; return true; + case TokenKind.Half1x2Keyword: result = "half1x2"; return true; + case TokenKind.Half1x3Keyword: result = "half1x3"; return true; + case TokenKind.Half1x4Keyword: result = "half1x4"; return true; + case TokenKind.Half2x1Keyword: result = "half2x1"; return true; + case TokenKind.Half2x2Keyword: result = "half2x2"; return true; + case TokenKind.Half2x3Keyword: result = "half2x3"; return true; + case TokenKind.Half2x4Keyword: result = "half2x4"; return true; + case TokenKind.Half3x1Keyword: result = "half3x1"; return true; + case TokenKind.Half3x2Keyword: result = "half3x2"; return true; + case TokenKind.Half3x3Keyword: result = "half3x3"; return true; + case TokenKind.Half3x4Keyword: result = "half3x4"; return true; + case TokenKind.Half4x1Keyword: result = "half4x1"; return true; + case TokenKind.Half4x2Keyword: result = "half4x2"; return true; + case TokenKind.Half4x3Keyword: result = "half4x3"; return true; + case TokenKind.Half4x4Keyword: result = "half4x4"; return true; + case TokenKind.IfKeyword: result = "if"; return true; + case TokenKind.IndicesKeyword: result = "indices"; return true; + case TokenKind.InKeyword: result = "in"; return true; + case TokenKind.InlineKeyword: result = "inline"; return true; + case TokenKind.InoutKeyword: result = "inout"; return true; + case TokenKind.InputPatchKeyword: result = "InputPatch"; return true; + case TokenKind.IntKeyword: result = "int"; return true; + case TokenKind.Int1Keyword: result = "int1"; return true; + case TokenKind.Int2Keyword: result = "int2"; return true; + case TokenKind.Int3Keyword: result = "int3"; return true; + case TokenKind.Int4Keyword: result = "int4"; return true; + case TokenKind.Int1x1Keyword: result = "int1x1"; return true; + case TokenKind.Int1x2Keyword: result = "int1x2"; return true; + case TokenKind.Int1x3Keyword: result = "int1x3"; return true; + case TokenKind.Int1x4Keyword: result = "int1x4"; return true; + case TokenKind.Int2x1Keyword: result = "int2x1"; return true; + case TokenKind.Int2x2Keyword: result = "int2x2"; return true; + case TokenKind.Int2x3Keyword: result = "int2x3"; return true; + case TokenKind.Int2x4Keyword: result = "int2x4"; return true; + case TokenKind.Int3x1Keyword: result = "int3x1"; return true; + case TokenKind.Int3x2Keyword: result = "int3x2"; return true; + case TokenKind.Int3x3Keyword: result = "int3x3"; return true; + case TokenKind.Int3x4Keyword: result = "int3x4"; return true; + case TokenKind.Int4x1Keyword: result = "int4x1"; return true; + case TokenKind.Int4x2Keyword: result = "int4x2"; return true; + case TokenKind.Int4x3Keyword: result = "int4x3"; return true; + case TokenKind.Int4x4Keyword: result = "int4x4"; return true; + case TokenKind.InterfaceKeyword: result = "interface"; return true; + case TokenKind.LineKeyword: result = "line"; return true; + case TokenKind.LineAdjKeyword: result = "lineadj"; return true; + case TokenKind.LinearKeyword: result = "linear"; return true; + case TokenKind.LineStreamKeyword: result = "LineStream"; return true; + case TokenKind.MatrixKeyword: result = "matrix"; return true; + case TokenKind.MessageKeyword: result = "message"; return true; + case TokenKind.Min10FloatKeyword: result = "min10float"; return true; + case TokenKind.Min10Float1Keyword: result = "min10float1"; return true; + case TokenKind.Min10Float2Keyword: result = "min10float2"; return true; + case TokenKind.Min10Float3Keyword: result = "min10float3"; return true; + case TokenKind.Min10Float4Keyword: result = "min10float4"; return true; + case TokenKind.Min10Float1x1Keyword: result = "min10float1x1"; return true; + case TokenKind.Min10Float1x2Keyword: result = "min10float1x2"; return true; + case TokenKind.Min10Float1x3Keyword: result = "min10float1x3"; return true; + case TokenKind.Min10Float1x4Keyword: result = "min10float1x4"; return true; + case TokenKind.Min10Float2x1Keyword: result = "min10float2x1"; return true; + case TokenKind.Min10Float2x2Keyword: result = "min10float2x2"; return true; + case TokenKind.Min10Float2x3Keyword: result = "min10float2x3"; return true; + case TokenKind.Min10Float2x4Keyword: result = "min10float2x4"; return true; + case TokenKind.Min10Float3x1Keyword: result = "min10float3x1"; return true; + case TokenKind.Min10Float3x2Keyword: result = "min10float3x2"; return true; + case TokenKind.Min10Float3x3Keyword: result = "min10float3x3"; return true; + case TokenKind.Min10Float3x4Keyword: result = "min10float3x4"; return true; + case TokenKind.Min10Float4x1Keyword: result = "min10float4x1"; return true; + case TokenKind.Min10Float4x2Keyword: result = "min10float4x2"; return true; + case TokenKind.Min10Float4x3Keyword: result = "min10float4x3"; return true; + case TokenKind.Min10Float4x4Keyword: result = "min10float4x4"; return true; + case TokenKind.Min12IntKeyword: result = "min12int"; return true; + case TokenKind.Min12Int1Keyword: result = "min12int1"; return true; + case TokenKind.Min12Int2Keyword: result = "min12int2"; return true; + case TokenKind.Min12Int3Keyword: result = "min12int3"; return true; + case TokenKind.Min12Int4Keyword: result = "min12int4"; return true; + case TokenKind.Min12Int1x1Keyword: result = "min12int1x1"; return true; + case TokenKind.Min12Int1x2Keyword: result = "min12int1x2"; return true; + case TokenKind.Min12Int1x3Keyword: result = "min12int1x3"; return true; + case TokenKind.Min12Int1x4Keyword: result = "min12int1x4"; return true; + case TokenKind.Min12Int2x1Keyword: result = "min12int2x1"; return true; + case TokenKind.Min12Int2x2Keyword: result = "min12int2x2"; return true; + case TokenKind.Min12Int2x3Keyword: result = "min12int2x3"; return true; + case TokenKind.Min12Int2x4Keyword: result = "min12int2x4"; return true; + case TokenKind.Min12Int3x1Keyword: result = "min12int3x1"; return true; + case TokenKind.Min12Int3x2Keyword: result = "min12int3x2"; return true; + case TokenKind.Min12Int3x3Keyword: result = "min12int3x3"; return true; + case TokenKind.Min12Int3x4Keyword: result = "min12int3x4"; return true; + case TokenKind.Min12Int4x1Keyword: result = "min12int4x1"; return true; + case TokenKind.Min12Int4x2Keyword: result = "min12int4x2"; return true; + case TokenKind.Min12Int4x3Keyword: result = "min12int4x3"; return true; + case TokenKind.Min12Int4x4Keyword: result = "min12int4x4"; return true; + case TokenKind.Min12UintKeyword: result = "min12uint"; return true; + case TokenKind.Min12Uint1Keyword: result = "min12uint1"; return true; + case TokenKind.Min12Uint2Keyword: result = "min12uint2"; return true; + case TokenKind.Min12Uint3Keyword: result = "min12uint3"; return true; + case TokenKind.Min12Uint4Keyword: result = "min12uint4"; return true; + case TokenKind.Min12Uint1x1Keyword: result = "min12uint1x1"; return true; + case TokenKind.Min12Uint1x2Keyword: result = "min12uint1x2"; return true; + case TokenKind.Min12Uint1x3Keyword: result = "min12uint1x3"; return true; + case TokenKind.Min12Uint1x4Keyword: result = "min12uint1x4"; return true; + case TokenKind.Min12Uint2x1Keyword: result = "min12uint2x1"; return true; + case TokenKind.Min12Uint2x2Keyword: result = "min12uint2x2"; return true; + case TokenKind.Min12Uint2x3Keyword: result = "min12uint2x3"; return true; + case TokenKind.Min12Uint2x4Keyword: result = "min12uint2x4"; return true; + case TokenKind.Min12Uint3x1Keyword: result = "min12uint3x1"; return true; + case TokenKind.Min12Uint3x2Keyword: result = "min12uint3x2"; return true; + case TokenKind.Min12Uint3x3Keyword: result = "min12uint3x3"; return true; + case TokenKind.Min12Uint3x4Keyword: result = "min12uint3x4"; return true; + case TokenKind.Min12Uint4x1Keyword: result = "min12uint4x1"; return true; + case TokenKind.Min12Uint4x2Keyword: result = "min12uint4x2"; return true; + case TokenKind.Min12Uint4x3Keyword: result = "min12uint4x3"; return true; + case TokenKind.Min12Uint4x4Keyword: result = "min12uint4x4"; return true; + case TokenKind.Min16FloatKeyword: result = "min16float"; return true; + case TokenKind.Min16Float1Keyword: result = "min16float1"; return true; + case TokenKind.Min16Float2Keyword: result = "min16float2"; return true; + case TokenKind.Min16Float3Keyword: result = "min16float3"; return true; + case TokenKind.Min16Float4Keyword: result = "min16float4"; return true; + case TokenKind.Min16Float1x1Keyword: result = "min16float1x1"; return true; + case TokenKind.Min16Float1x2Keyword: result = "min16float1x2"; return true; + case TokenKind.Min16Float1x3Keyword: result = "min16float1x3"; return true; + case TokenKind.Min16Float1x4Keyword: result = "min16float1x4"; return true; + case TokenKind.Min16Float2x1Keyword: result = "min16float2x1"; return true; + case TokenKind.Min16Float2x2Keyword: result = "min16float2x2"; return true; + case TokenKind.Min16Float2x3Keyword: result = "min16float2x3"; return true; + case TokenKind.Min16Float2x4Keyword: result = "min16float2x4"; return true; + case TokenKind.Min16Float3x1Keyword: result = "min16float3x1"; return true; + case TokenKind.Min16Float3x2Keyword: result = "min16float3x2"; return true; + case TokenKind.Min16Float3x3Keyword: result = "min16float3x3"; return true; + case TokenKind.Min16Float3x4Keyword: result = "min16float3x4"; return true; + case TokenKind.Min16Float4x1Keyword: result = "min16float4x1"; return true; + case TokenKind.Min16Float4x2Keyword: result = "min16float4x2"; return true; + case TokenKind.Min16Float4x3Keyword: result = "min16float4x3"; return true; + case TokenKind.Min16Float4x4Keyword: result = "min16float4x4"; return true; + case TokenKind.Min16IntKeyword: result = "min16int"; return true; + case TokenKind.Min16Int1Keyword: result = "min16int1"; return true; + case TokenKind.Min16Int2Keyword: result = "min16int2"; return true; + case TokenKind.Min16Int3Keyword: result = "min16int3"; return true; + case TokenKind.Min16Int4Keyword: result = "min16int4"; return true; + case TokenKind.Min16Int1x1Keyword: result = "min16int1x1"; return true; + case TokenKind.Min16Int1x2Keyword: result = "min16int1x2"; return true; + case TokenKind.Min16Int1x3Keyword: result = "min16int1x3"; return true; + case TokenKind.Min16Int1x4Keyword: result = "min16int1x4"; return true; + case TokenKind.Min16Int2x1Keyword: result = "min16int2x1"; return true; + case TokenKind.Min16Int2x2Keyword: result = "min16int2x2"; return true; + case TokenKind.Min16Int2x3Keyword: result = "min16int2x3"; return true; + case TokenKind.Min16Int2x4Keyword: result = "min16int2x4"; return true; + case TokenKind.Min16Int3x1Keyword: result = "min16int3x1"; return true; + case TokenKind.Min16Int3x2Keyword: result = "min16int3x2"; return true; + case TokenKind.Min16Int3x3Keyword: result = "min16int3x3"; return true; + case TokenKind.Min16Int3x4Keyword: result = "min16int3x4"; return true; + case TokenKind.Min16Int4x1Keyword: result = "min16int4x1"; return true; + case TokenKind.Min16Int4x2Keyword: result = "min16int4x2"; return true; + case TokenKind.Min16Int4x3Keyword: result = "min16int4x3"; return true; + case TokenKind.Min16Int4x4Keyword: result = "min16int4x4"; return true; + case TokenKind.Min16UintKeyword: result = "min16uint"; return true; + case TokenKind.Min16Uint1Keyword: result = "min16uint1"; return true; + case TokenKind.Min16Uint2Keyword: result = "min16uint2"; return true; + case TokenKind.Min16Uint3Keyword: result = "min16uint3"; return true; + case TokenKind.Min16Uint4Keyword: result = "min16uint4"; return true; + case TokenKind.Min16Uint1x1Keyword: result = "min16uint1x1"; return true; + case TokenKind.Min16Uint1x2Keyword: result = "min16uint1x2"; return true; + case TokenKind.Min16Uint1x3Keyword: result = "min16uint1x3"; return true; + case TokenKind.Min16Uint1x4Keyword: result = "min16uint1x4"; return true; + case TokenKind.Min16Uint2x1Keyword: result = "min16uint2x1"; return true; + case TokenKind.Min16Uint2x2Keyword: result = "min16uint2x2"; return true; + case TokenKind.Min16Uint2x3Keyword: result = "min16uint2x3"; return true; + case TokenKind.Min16Uint2x4Keyword: result = "min16uint2x4"; return true; + case TokenKind.Min16Uint3x1Keyword: result = "min16uint3x1"; return true; + case TokenKind.Min16Uint3x2Keyword: result = "min16uint3x2"; return true; + case TokenKind.Min16Uint3x3Keyword: result = "min16uint3x3"; return true; + case TokenKind.Min16Uint3x4Keyword: result = "min16uint3x4"; return true; + case TokenKind.Min16Uint4x1Keyword: result = "min16uint4x1"; return true; + case TokenKind.Min16Uint4x2Keyword: result = "min16uint4x2"; return true; + case TokenKind.Min16Uint4x3Keyword: result = "min16uint4x3"; return true; + case TokenKind.Min16Uint4x4Keyword: result = "min16uint4x4"; return true; + case TokenKind.NamespaceKeyword: result = "namespace"; return true; + case TokenKind.NointerpolationKeyword: result = "nointerpolation"; return true; + case TokenKind.NoperspectiveKeyword: result = "noperspective"; return true; + case TokenKind.NullKeyword: result = "NULL"; return true; + case TokenKind.OutKeyword: result = "out"; return true; + case TokenKind.OutputPatchKeyword: result = "OutputPatch"; return true; + case TokenKind.PackMatrixKeyword: result = "packmatrix"; return true; + case TokenKind.PackoffsetKeyword: result = "packoffset"; return true; + case TokenKind.PassKeyword: result = "pass"; return true; + case TokenKind.PayloadKeyword: result = "payload"; return true; + case TokenKind.PointKeyword: result = "point"; return true; + case TokenKind.PointStreamKeyword: result = "PointStream"; return true; + case TokenKind.PragmaKeyword: result = "pragma"; return true; + case TokenKind.PreciseKeyword: result = "precise"; return true; + case TokenKind.PrimitivesKeyword: result = "primitives"; return true; + case TokenKind.RasterizerOrderedBufferKeyword: result = "rasterizerorderedbuffer"; return true; + case TokenKind.RasterizerOrderedByteAddressBufferKeyword: result = "rasterizerorderedbyteaddressbuffer"; return true; + case TokenKind.RasterizerOrderedStructuredBufferKeyword: result = "rasterizerorderedstructuredbuffer"; return true; + case TokenKind.RasterizerOrderedTexture1DKeyword: result = "rasterizerorderedtexture1d"; return true; + case TokenKind.RasterizerOrderedTexture1DArrayKeyword: result = "rasterizerorderedtexture1darray"; return true; + case TokenKind.RasterizerOrderedTexture2DKeyword: result = "rasterizerorderedtexture2d"; return true; + case TokenKind.RasterizerOrderedTexture2DArrayKeyword: result = "rasterizerorderedtexture2darray"; return true; + case TokenKind.RasterizerOrderedTexture3DKeyword: result = "rasterizerorderedtexture3d"; return true; + case TokenKind.RasterizerStateKeyword: result = "RasterizerState"; return true; + case TokenKind.RegisterKeyword: result = "register"; return true; + case TokenKind.ReturnKeyword: result = "return"; return true; + case TokenKind.RowMajorKeyword: result = "row_major"; return true; + case TokenKind.RWBufferKeyword: result = "RWBuffer"; return true; + case TokenKind.RWByteAddressBufferKeyword: result = "RWByteAddressBuffer"; return true; + case TokenKind.RWStructuredBufferKeyword: result = "RWStructuredBuffer"; return true; + case TokenKind.RWTexture1DKeyword: result = "RWTexture1D"; return true; + case TokenKind.RWTexture1DArrayKeyword: result = "RWTexture1DArray"; return true; + case TokenKind.RWTexture2DKeyword: result = "RWTexture2D"; return true; + case TokenKind.RWTexture2DArrayKeyword: result = "RWTexture2DArray"; return true; + case TokenKind.RWTexture3DKeyword: result = "RWTexture3D"; return true; + case TokenKind.SamplerKeyword: result = "sampler"; return true; + case TokenKind.Sampler1DKeyword: result = "sampler1d"; return true; + case TokenKind.Sampler2DKeyword: result = "sampler2d"; return true; + case TokenKind.Sampler3DKeyword: result = "sampler3d"; return true; + case TokenKind.SamplerCubeKeyword: result = "samplercube"; return true; + case TokenKind.SamplerComparisonStateKeyword: result = "SamplerComparisonState"; return true; + case TokenKind.SamplerStateKeyword: result = "SamplerState"; return true; + case TokenKind.SamplerStateLegacyKeyword: result = "sampler_state"; return true; + case TokenKind.SharedKeyword: result = "shared"; return true; + case TokenKind.SNormKeyword: result = "snorm"; return true; + case TokenKind.StaticKeyword: result = "static"; return true; + case TokenKind.StringKeyword: result = "string"; return true; + case TokenKind.StructKeyword: result = "struct"; return true; + case TokenKind.StructuredBufferKeyword: result = "StructuredBuffer"; return true; + case TokenKind.SwitchKeyword: result = "switch"; return true; + case TokenKind.TBufferKeyword: result = "tbuffer"; return true; + case TokenKind.TechniqueKeyword: result = "technique"; return true; + case TokenKind.Technique10Keyword: result = "technique10"; return true; + case TokenKind.Technique11Keyword: result = "technique11"; return true; + case TokenKind.TextureKeyword: result = "texture"; return true; + case TokenKind.Texture2DLegacyKeyword: result = "Texture2DLegacy"; return true; + case TokenKind.TextureCubeLegacyKeyword: result = "TextureCubeLegacy"; return true; + case TokenKind.Texture1DKeyword: result = "Texture1D"; return true; + case TokenKind.Texture1DArrayKeyword: result = "Texture1DArray"; return true; + case TokenKind.Texture2DKeyword: result = "Texture2D"; return true; + case TokenKind.Texture2DArrayKeyword: result = "Texture2DArray"; return true; + case TokenKind.Texture2DMSKeyword: result = "Texture2DMS"; return true; + case TokenKind.Texture2DMSArrayKeyword: result = "Texture2DMSArray"; return true; + case TokenKind.Texture3DKeyword: result = "Texture3D"; return true; + case TokenKind.TextureCubeKeyword: result = "TextureCube"; return true; + case TokenKind.TextureCubeArrayKeyword: result = "TextureCubeArray"; return true; + case TokenKind.TriangleKeyword: result = "triangle"; return true; + case TokenKind.TriangleAdjKeyword: result = "triangleadj"; return true; + case TokenKind.TriangleStreamKeyword: result = "TriangleStream"; return true; + case TokenKind.TypedefKeyword: result = "typedef"; return true; + case TokenKind.UniformKeyword: result = "uniform"; return true; + case TokenKind.UNormKeyword: result = "unorm"; return true; + case TokenKind.UintKeyword: result = "uint"; return true; + case TokenKind.Uint1Keyword: result = "uint1"; return true; + case TokenKind.Uint2Keyword: result = "uint2"; return true; + case TokenKind.Uint3Keyword: result = "uint3"; return true; + case TokenKind.Uint4Keyword: result = "uint4"; return true; + case TokenKind.Uint1x1Keyword: result = "uint1x1"; return true; + case TokenKind.Uint1x2Keyword: result = "uint1x2"; return true; + case TokenKind.Uint1x3Keyword: result = "uint1x3"; return true; + case TokenKind.Uint1x4Keyword: result = "uint1x4"; return true; + case TokenKind.Uint2x1Keyword: result = "uint2x1"; return true; + case TokenKind.Uint2x2Keyword: result = "uint2x2"; return true; + case TokenKind.Uint2x3Keyword: result = "uint2x3"; return true; + case TokenKind.Uint2x4Keyword: result = "uint2x4"; return true; + case TokenKind.Uint3x1Keyword: result = "uint3x1"; return true; + case TokenKind.Uint3x2Keyword: result = "uint3x2"; return true; + case TokenKind.Uint3x3Keyword: result = "uint3x3"; return true; + case TokenKind.Uint3x4Keyword: result = "uint3x4"; return true; + case TokenKind.Uint4x1Keyword: result = "uint4x1"; return true; + case TokenKind.Uint4x2Keyword: result = "uint4x2"; return true; + case TokenKind.Uint4x3Keyword: result = "uint4x3"; return true; + case TokenKind.Uint4x4Keyword: result = "uint4x4"; return true; + case TokenKind.VectorKeyword: result = "vector"; return true; + case TokenKind.VerticesKeyword: result = "vertices"; return true; + case TokenKind.VolatileKeyword: result = "volatile"; return true; + case TokenKind.VoidKeyword: result = "void"; return true; + case TokenKind.WarningKeyword: result = "warning"; return true; + case TokenKind.WhileKeyword: result = "while"; return true; + case TokenKind.TrueKeyword: result = "true"; return true; + case TokenKind.FalseKeyword: result = "false"; return true; + case TokenKind.UnsignedKeyword: result = "unsigned"; return true; + case TokenKind.DwordKeyword: result = "dword"; return true; + case TokenKind.CompileFragmentKeyword: result = "compile_fragment"; return true; + case TokenKind.DepthStencilViewKeyword: result = "DepthStencilView"; return true; + case TokenKind.PixelfragmentKeyword: result = "pixelfragment"; return true; + case TokenKind.RenderTargetViewKeyword: result = "RenderTargetView"; return true; + case TokenKind.StateblockStateKeyword: result = "stateblock_state"; return true; + case TokenKind.StateblockKeyword: result = "stateblock"; return true; + default: result = string.Empty; return false; + } + } + + public static bool TryConvertIdentifierOrKeywordToString(Token token, out string result) + { + if (token.Identifier != null) + { + result = token.Identifier; + return true; + } + + if (TryConvertKeywordToString(token.Kind, out result)) + { + return true; + } + + result = string.Empty; + return false; + } + + public static string IdentifierOrKeywordToString(Token token) + { + if (token.Identifier != null) + return token.Identifier; + + if (TryConvertKeywordToString(token.Kind, out string result)) + return result; + + return "__INVALID"; + } + + public static string TokenToString(Token token) + { + switch (token.Kind) + { + case TokenKind.OpenParenToken: return "("; + case TokenKind.CloseParenToken: return ")"; + case TokenKind.OpenBracketToken: return "["; + case TokenKind.CloseBracketToken: return "]"; + case TokenKind.OpenBraceToken: return "{"; + case TokenKind.CloseBraceToken: return "}"; + case TokenKind.SemiToken: return ";"; + case TokenKind.CommaToken: return ","; + case TokenKind.LessThanToken: return "<"; + case TokenKind.LessThanEqualsToken: return "<="; + case TokenKind.GreaterThanToken: return ">"; + case TokenKind.GreaterThanEqualsToken: return ">="; + case TokenKind.LessThanLessThanToken: return "<<"; + case TokenKind.GreaterThanGreaterThanToken: return ">>"; + case TokenKind.PlusToken: return "+"; + case TokenKind.PlusPlusToken: return "++"; + case TokenKind.MinusToken: return "-"; + case TokenKind.MinusMinusToken: return "--"; + case TokenKind.AsteriskToken: return "*"; + case TokenKind.SlashToken: return "/"; + case TokenKind.PercentToken: return "%"; + case TokenKind.AmpersandToken: return "&"; + case TokenKind.BarToken: return "|"; + case TokenKind.AmpersandAmpersandToken: return "&&"; + case TokenKind.BarBarToken: return "||"; + case TokenKind.CaretToken: return "^"; + case TokenKind.NotToken: return "!"; + case TokenKind.TildeToken: return "~"; + case TokenKind.QuestionToken: return "?"; + case TokenKind.ColonToken: return ":"; + case TokenKind.ColonColonToken: return "::"; + case TokenKind.EqualsToken: return "="; + case TokenKind.AsteriskEqualsToken: return "*"; + case TokenKind.SlashEqualsToken: return "/="; + case TokenKind.PercentEqualsToken: return "%="; + case TokenKind.PlusEqualsToken: return "+="; + case TokenKind.MinusEqualsToken: return "-="; + case TokenKind.LessThanLessThanEqualsToken: return "<<="; + case TokenKind.GreaterThanGreaterThanEqualsToken: return ">>="; + case TokenKind.AmpersandEqualsToken: return "&="; + case TokenKind.CaretEqualsToken: return "^="; + case TokenKind.BarEqualsToken: return "|="; + case TokenKind.EqualsEqualsToken: return "=="; + case TokenKind.ExclamationEqualsToken: return "!="; + case TokenKind.DotToken: return "."; + case TokenKind.HashToken: return "#"; + case TokenKind.HashHashToken: return "##"; + + case TokenKind.DefineDirectiveKeyword: return "#define"; + case TokenKind.IncludeDirectiveKeyword: return "#include"; + case TokenKind.LineDirectiveKeyword: return "#line"; + case TokenKind.UndefDirectiveKeyword: return "#undef"; + case TokenKind.ErrorDirectiveKeyword: return "#error"; + case TokenKind.PragmaDirectiveKeyword: return "#pragma"; + case TokenKind.IfDirectiveKeyword: return "#if"; + case TokenKind.IfdefDirectiveKeyword: return "#ifdef"; + case TokenKind.IfndefDirectiveKeyword: return "#ifndef"; + case TokenKind.ElifDirectiveKeyword: return "#elif"; + case TokenKind.ElseDirectiveKeyword: return "#else"; + case TokenKind.EndifDirectiveKeyword: return "#endif"; + case TokenKind.EndDirectiveToken: return "\n"; + + default: return IdentifierOrKeywordToString(token); + } + } + + public static string TokensToString(IEnumerable> tokens) + { + return string.Join(" ", tokens.Select(x => TokenToString(x))); + } + } +} + + +// HLSL/HLSLSyntaxVisitor.cs +namespace UnityShaderParser.HLSL +{ + public abstract class HLSLSyntaxVisitor + { + protected void DefaultVisit(HLSLSyntaxNode node) + { + foreach (var child in node.Children) + { + child.Accept(this); + } + } + + public void VisitMany(IEnumerable nodes) + { + foreach (HLSLSyntaxNode node in nodes) + { + Visit(node); + } + } + + public void VisitMany(IList nodes, Action runBetween) + where T : HLSLSyntaxNode + { + for (int i = 0; i < nodes.Count; i++) + { + Visit(nodes[i]); + if (i < nodes.Count - 1) + runBetween(); + } + } + + public virtual void Visit(HLSLSyntaxNode node) => node?.Accept(this); + public virtual void VisitFormalParameterNode(FormalParameterNode node) => DefaultVisit(node); + public virtual void VisitVariableDeclaratorNode(VariableDeclaratorNode node) => DefaultVisit(node); + public virtual void VisitArrayRankNode(ArrayRankNode node) => DefaultVisit(node); + public virtual void VisitValueInitializerNode(ValueInitializerNode node) => DefaultVisit(node); + public virtual void VisitStateInitializerNode(StateInitializerNode node) => DefaultVisit(node); + public virtual void VisitStateArrayInitializerNode(StateArrayInitializerNode node) => DefaultVisit(node); + public virtual void VisitFunctionDeclarationNode(FunctionDeclarationNode node) => DefaultVisit(node); + public virtual void VisitFunctionDefinitionNode(FunctionDefinitionNode node) => DefaultVisit(node); + public virtual void VisitStructDefinitionNode(StructDefinitionNode node) => DefaultVisit(node); + public virtual void VisitInterfaceDefinitionNode(InterfaceDefinitionNode node) => DefaultVisit(node); + public virtual void VisitConstantBufferNode(ConstantBufferNode node) => DefaultVisit(node); + public virtual void VisitNamespaceNode(NamespaceNode node) => DefaultVisit(node); + public virtual void VisitTypedefNode(TypedefNode node) => DefaultVisit(node); + public virtual void VisitSemanticNode(SemanticNode node) => DefaultVisit(node); + public virtual void VisitRegisterLocationNode(RegisterLocationNode node) => DefaultVisit(node); + public virtual void VisitPackoffsetNode(PackoffsetNode node) => DefaultVisit(node); + public virtual void VisitBlockNode(BlockNode node) => DefaultVisit(node); + public virtual void VisitVariableDeclarationStatementNode(VariableDeclarationStatementNode node) => DefaultVisit(node); + public virtual void VisitReturnStatementNode(ReturnStatementNode node) => DefaultVisit(node); + public virtual void VisitBreakStatementNode(BreakStatementNode node) => DefaultVisit(node); + public virtual void VisitContinueStatementNode(ContinueStatementNode node) => DefaultVisit(node); + public virtual void VisitDiscardStatementNode(DiscardStatementNode node) => DefaultVisit(node); + public virtual void VisitEmptyStatementNode(EmptyStatementNode node) => DefaultVisit(node); + public virtual void VisitForStatementNode(ForStatementNode node) => DefaultVisit(node); + public virtual void VisitWhileStatementNode(WhileStatementNode node) => DefaultVisit(node); + public virtual void VisitDoWhileStatementNode(DoWhileStatementNode node) => DefaultVisit(node); + public virtual void VisitIfStatementNode(IfStatementNode node) => DefaultVisit(node); + public virtual void VisitSwitchStatementNode(SwitchStatementNode node) => DefaultVisit(node); + public virtual void VisitSwitchClauseNode(SwitchClauseNode node) => DefaultVisit(node); + public virtual void VisitSwitchCaseLabelNode(SwitchCaseLabelNode node) => DefaultVisit(node); + public virtual void VisitSwitchDefaultLabelNode(SwitchDefaultLabelNode node) => DefaultVisit(node); + public virtual void VisitExpressionStatementNode(ExpressionStatementNode node) => DefaultVisit(node); + public virtual void VisitAttributeNode(AttributeNode node) => DefaultVisit(node); + public virtual void VisitQualifiedIdentifierExpressionNode(QualifiedIdentifierExpressionNode node) => DefaultVisit(node); + public virtual void VisitIdentifierExpressionNode(IdentifierExpressionNode node) => DefaultVisit(node); + public virtual void VisitLiteralExpressionNode(LiteralExpressionNode node) => DefaultVisit(node); + public virtual void VisitAssignmentExpressionNode(AssignmentExpressionNode node) => DefaultVisit(node); + public virtual void VisitBinaryExpressionNode(BinaryExpressionNode node) => DefaultVisit(node); + public virtual void VisitCompoundExpressionNode(CompoundExpressionNode node) => DefaultVisit(node); + public virtual void VisitPrefixUnaryExpressionNode(PrefixUnaryExpressionNode node) => DefaultVisit(node); + public virtual void VisitPostfixUnaryExpressionNode(PostfixUnaryExpressionNode node) => DefaultVisit(node); + public virtual void VisitFieldAccessExpressionNode(FieldAccessExpressionNode node) => DefaultVisit(node); + public virtual void VisitMethodCallExpressionNode(MethodCallExpressionNode node) => DefaultVisit(node); + public virtual void VisitFunctionCallExpressionNode(FunctionCallExpressionNode node) => DefaultVisit(node); + public virtual void VisitNumericConstructorCallExpressionNode(NumericConstructorCallExpressionNode node) => DefaultVisit(node); + public virtual void VisitElementAccessExpressionNode(ElementAccessExpressionNode node) => DefaultVisit(node); + public virtual void VisitCastExpressionNode(CastExpressionNode node) => DefaultVisit(node); + public virtual void VisitArrayInitializerExpressionNode(ArrayInitializerExpressionNode node) => DefaultVisit(node); + public virtual void VisitTernaryExpressionNode(TernaryExpressionNode node) => DefaultVisit(node); + public virtual void VisitSamplerStateLiteralExpressionNode(SamplerStateLiteralExpressionNode node) => DefaultVisit(node); + public virtual void VisitCompileExpressionNode(CompileExpressionNode node) => DefaultVisit(node); + public virtual void VisitQualifiedNamedTypeNode(QualifiedNamedTypeNode node) => DefaultVisit(node); + public virtual void VisitNamedTypeNode(NamedTypeNode node) => DefaultVisit(node); + public virtual void VisitPredefinedObjectTypeNode(PredefinedObjectTypeNode node) => DefaultVisit(node); + public virtual void VisitStructTypeNode(StructTypeNode node) => DefaultVisit(node); + public virtual void VisitScalarTypeNode(ScalarTypeNode node) => DefaultVisit(node); + public virtual void VisitMatrixTypeNode(MatrixTypeNode node) => DefaultVisit(node); + public virtual void VisitVectorTypeNode(VectorTypeNode node) => DefaultVisit(node); + public virtual void VisitTechniqueNode(TechniqueNode node) => DefaultVisit(node); + public virtual void VisitLiteralTemplateArgumentType(LiteralTemplateArgumentType node) => DefaultVisit(node); + public virtual void VisitStatePropertyNode(StatePropertyNode node) => DefaultVisit(node); + public virtual void VisitPassNode(PassNode node) => DefaultVisit(node); + public virtual void VisitObjectLikeMacroNode(ObjectLikeMacroNode node) => DefaultVisit(node); + public virtual void VisitFunctionLikeMacroNode(FunctionLikeMacroNode node) => DefaultVisit(node); + public virtual void VisitIncludeDirectiveNode(IncludeDirectiveNode node) => DefaultVisit(node); + public virtual void VisitLineDirectiveNode(LineDirectiveNode node) => DefaultVisit(node); + public virtual void VisitUndefDirectiveNode(UndefDirectiveNode node) => DefaultVisit(node); + public virtual void VisitErrorDirectiveNode(ErrorDirectiveNode node) => DefaultVisit(node); + public virtual void VisitPragmaDirectiveNode(PragmaDirectiveNode node) => DefaultVisit(node); + public virtual void VisitIfDefDirectiveNode(IfDefDirectiveNode node) => DefaultVisit(node); + public virtual void VisitIfNotDefDirectiveNode(IfNotDefDirectiveNode node) => DefaultVisit(node); + public virtual void VisitIfDirectiveNode(IfDirectiveNode node) => DefaultVisit(node); + public virtual void VisitElseDirectiveNode(ElseDirectiveNode node) => DefaultVisit(node); + } + + public abstract class HLSLSyntaxVisitor + { + protected TReturn DefaultVisit(HLSLSyntaxNode node) + { + foreach (var child in node.Children) + { + child.Accept(this); + } + return default; + } + + public List VisitMany(IEnumerable nodes) + { + List result = new List(); + foreach (HLSLSyntaxNode node in nodes) + { + result.Add(Visit(node)); + } + return result; + } + + public List VisitMany(IList nodes, Action runBetween) + where T : HLSLSyntaxNode + { + List result = new List(); + for (int i = 0; i < nodes.Count; i++) + { + result.Add(Visit(nodes[i])); + if (i < nodes.Count - 1) + runBetween(); + } + return result; + } + + public virtual TReturn Visit(HLSLSyntaxNode node) => node == null ? default : node.Accept(this); + public virtual TReturn VisitFormalParameterNode(FormalParameterNode node) => DefaultVisit(node); + public virtual TReturn VisitVariableDeclaratorNode(VariableDeclaratorNode node) => DefaultVisit(node); + public virtual TReturn VisitArrayRankNode(ArrayRankNode node) => DefaultVisit(node); + public virtual TReturn VisitValueInitializerNode(ValueInitializerNode node) => DefaultVisit(node); + public virtual TReturn VisitStateInitializerNode(StateInitializerNode node) => DefaultVisit(node); + public virtual TReturn VisitStateArrayInitializerNode(StateArrayInitializerNode node) => DefaultVisit(node); + public virtual TReturn VisitFunctionDeclarationNode(FunctionDeclarationNode node) => DefaultVisit(node); + public virtual TReturn VisitFunctionDefinitionNode(FunctionDefinitionNode node) => DefaultVisit(node); + public virtual TReturn VisitStructDefinitionNode(StructDefinitionNode node) => DefaultVisit(node); + public virtual TReturn VisitInterfaceDefinitionNode(InterfaceDefinitionNode node) => DefaultVisit(node); + public virtual TReturn VisitConstantBufferNode(ConstantBufferNode node) => DefaultVisit(node); + public virtual TReturn VisitNamespaceNode(NamespaceNode node) => DefaultVisit(node); + public virtual TReturn VisitTypedefNode(TypedefNode node) => DefaultVisit(node); + public virtual TReturn VisitSemanticNode(SemanticNode node) => DefaultVisit(node); + public virtual TReturn VisitRegisterLocationNode(RegisterLocationNode node) => DefaultVisit(node); + public virtual TReturn VisitPackoffsetNode(PackoffsetNode node) => DefaultVisit(node); + public virtual TReturn VisitBlockNode(BlockNode node) => DefaultVisit(node); + public virtual TReturn VisitVariableDeclarationStatementNode(VariableDeclarationStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitReturnStatementNode(ReturnStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitBreakStatementNode(BreakStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitContinueStatementNode(ContinueStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitDiscardStatementNode(DiscardStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitEmptyStatementNode(EmptyStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitForStatementNode(ForStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitWhileStatementNode(WhileStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitDoWhileStatementNode(DoWhileStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitIfStatementNode(IfStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitSwitchStatementNode(SwitchStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitSwitchClauseNode(SwitchClauseNode node) => DefaultVisit(node); + public virtual TReturn VisitSwitchCaseLabelNode(SwitchCaseLabelNode node) => DefaultVisit(node); + public virtual TReturn VisitSwitchDefaultLabelNode(SwitchDefaultLabelNode node) => DefaultVisit(node); + public virtual TReturn VisitExpressionStatementNode(ExpressionStatementNode node) => DefaultVisit(node); + public virtual TReturn VisitAttributeNode(AttributeNode node) => DefaultVisit(node); + public virtual TReturn VisitQualifiedIdentifierExpressionNode(QualifiedIdentifierExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitIdentifierExpressionNode(IdentifierExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitLiteralExpressionNode(LiteralExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitAssignmentExpressionNode(AssignmentExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitBinaryExpressionNode(BinaryExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitCompoundExpressionNode(CompoundExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitPrefixUnaryExpressionNode(PrefixUnaryExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitPostfixUnaryExpressionNode(PostfixUnaryExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitFieldAccessExpressionNode(FieldAccessExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitMethodCallExpressionNode(MethodCallExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitFunctionCallExpressionNode(FunctionCallExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitNumericConstructorCallExpressionNode(NumericConstructorCallExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitElementAccessExpressionNode(ElementAccessExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitCastExpressionNode(CastExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitArrayInitializerExpressionNode(ArrayInitializerExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitTernaryExpressionNode(TernaryExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitSamplerStateLiteralExpressionNode(SamplerStateLiteralExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitCompileExpressionNode(CompileExpressionNode node) => DefaultVisit(node); + public virtual TReturn VisitQualifiedNamedTypeNode(QualifiedNamedTypeNode node) => DefaultVisit(node); + public virtual TReturn VisitNamedTypeNode(NamedTypeNode node) => DefaultVisit(node); + public virtual TReturn VisitPredefinedObjectTypeNode(PredefinedObjectTypeNode node) => DefaultVisit(node); + public virtual TReturn VisitStructTypeNode(StructTypeNode node) => DefaultVisit(node); + public virtual TReturn VisitScalarTypeNode(ScalarTypeNode node) => DefaultVisit(node); + public virtual TReturn VisitMatrixTypeNode(MatrixTypeNode node) => DefaultVisit(node); + public virtual TReturn VisitVectorTypeNode(VectorTypeNode node) => DefaultVisit(node); + public virtual TReturn VisitTechniqueNode(TechniqueNode node) => DefaultVisit(node); + public virtual TReturn VisitLiteralTemplateArgumentType(LiteralTemplateArgumentType node) => DefaultVisit(node); + public virtual TReturn VisitStatePropertyNode(StatePropertyNode node) => DefaultVisit(node); + public virtual TReturn VisitPassNode(PassNode node) => DefaultVisit(node); + public virtual TReturn VisitObjectLikeMacroNode(ObjectLikeMacroNode node) => DefaultVisit(node); + public virtual TReturn VisitFunctionLikeMacroNode(FunctionLikeMacroNode node) => DefaultVisit(node); + public virtual TReturn VisitIncludeDirectiveNode(IncludeDirectiveNode node) => DefaultVisit(node); + public virtual TReturn VisitLineDirectiveNode(LineDirectiveNode node) => DefaultVisit(node); + public virtual TReturn VisitUndefDirectiveNode(UndefDirectiveNode node) => DefaultVisit(node); + public virtual TReturn VisitErrorDirectiveNode(ErrorDirectiveNode node) => DefaultVisit(node); + public virtual TReturn VisitPragmaDirectiveNode(PragmaDirectiveNode node) => DefaultVisit(node); + public virtual TReturn VisitIfDefDirectiveNode(IfDefDirectiveNode node) => DefaultVisit(node); + public virtual TReturn VisitIfNotDefDirectiveNode(IfNotDefDirectiveNode node) => DefaultVisit(node); + public virtual TReturn VisitIfDirectiveNode(IfDirectiveNode node) => DefaultVisit(node); + public virtual TReturn VisitElseDirectiveNode(ElseDirectiveNode node) => DefaultVisit(node); + } +} + + +// Common/BaseLexer.cs +namespace UnityShaderParser.Common +{ + public abstract class BaseLexer + where T : struct + { + protected abstract ParserStage Stage { get; } + + protected bool throwExceptionOnError = false; + protected string source = string.Empty; + protected int position = 0; + protected int line = 1; + protected int column = 1; + protected int anchorLine = 1; + protected int anchorColumn = 1; + protected int anchorPosition = 0; + protected string basePath; + protected string fileName; + protected DiagnosticFlags diagnosticFilter = DiagnosticFlags.All; + + protected List> tokens = new List>(); + protected List diagnostics = new List(); + + public BaseLexer(string source, string basePath, string fileName, bool throwExceptionOnError, SourceLocation offset) + { + this.source = source; + this.throwExceptionOnError = throwExceptionOnError; + this.line = offset.Line; + this.column = offset.Column; + this.basePath = basePath; + this.fileName = fileName; + } + + protected char Peek() => IsAtEnd() ? '\0' : source[position]; + protected char LookAhead(int offset = 1) => IsAtEnd(offset) ? '\0' : source[position + offset]; + protected bool LookAhead(char c, int offset = 1) => LookAhead(offset) == c; + protected bool Match(char tok) => Peek() == tok; + protected bool IsAtEnd(int offset = 0) => position + offset >= source.Length; + protected void Add(string identifier, T kind) => tokens.Add(new Token(kind, identifier, GetCurrentSpan(), tokens.Count)); + protected void Add(T kind) => tokens.Add(new Token(kind, null, GetCurrentSpan(), tokens.Count)); + protected void Eat(char tok) + { + if (!Match(tok)) + Error(DiagnosticFlags.SyntaxError, $"Expected token '{tok}', got '{Peek()}'."); + Advance(); + } + protected char Advance(int amount = 1) + { + if (IsAtEnd(amount - 1)) + return '\0'; + column++; + if (Peek() == '\n') + { + column = 1; + line++; + } + char result = source[position]; + position += amount; + return result; + } + protected void Error(DiagnosticFlags kind, string err) + { + if (!diagnosticFilter.HasFlag(kind)) + return; + + if (throwExceptionOnError && kind != DiagnosticFlags.Warning) + { + throw new Exception($"Error at line {line}, column {column} during {Stage}: {err}"); + } + diagnostics.Add(new Diagnostic(new SourceLocation(line, column, position), kind, this.Stage, err)); + } + + protected void StartCurrentSpan() + { + anchorLine = line; + anchorColumn = column; + anchorPosition = position; + } + + protected SourceSpan GetCurrentSpan() + { + return new SourceSpan(basePath, fileName, new SourceLocation(anchorLine, anchorColumn, anchorPosition), new SourceLocation(line, column, position)); + } + + protected string EatStringLiteral(char start, char end) + { + StringBuilder builder = new StringBuilder(); + Eat(start); + while (Peek() != end) + { + builder.Append(Advance()); + } + Eat(end); + return builder.ToString(); + } + + protected string EatIdentifier() + { + StringBuilder builder = new StringBuilder(); + while (IsAlphaNumericOrUnderscore(Peek())) + { + builder.Append(Advance()); + } + return builder.ToString(); + } + + protected string EatNumber(out bool isFloat) + { + StringBuilder builder = new StringBuilder(); + if (Match('-')) + { + builder.Append(Advance()); + } + while (true) + { + char c = Peek(); + if (char.IsDigit(c) || c == '.') + { + builder.Append(Advance()); + } + // Scientific notation + else if (c == 'e' || c == 'E') + { + builder.Append(Advance()); + if (Peek() == '-') + builder.Append(Advance()); + } + else + { + break; + } + } + if (Match('f') || Match('F') || Match('h') || Match('H') || Match('u') || Match('U')) + { + builder.Append(Advance()); + } + string number = builder.ToString(); + isFloat = number.Contains(".") || + number.EndsWith("f") || + number.EndsWith("F") || + number.EndsWith("h") || + number.EndsWith("H"); + return number; + } + + protected void SkipWhitespace(bool skipNewLines = false) + { + while (Peek() == ' ' || Peek() == '\t' || Peek() == '\r' || (skipNewLines && Peek() == '\n')) + { + Advance(); + } + } + + protected static bool IsAlphaNumericOrUnderscore(char c) => c == '_' || char.IsLetterOrDigit(c); + + protected abstract void ProcessChar(char nextChar); + + public void Lex() + { + while (!IsAtEnd()) + { + StartCurrentSpan(); + ProcessChar(Peek()); + } + } + } +} + + +// Common/BaseParser.cs +namespace UnityShaderParser.Common +{ + public abstract class BaseParser + where T : struct, Enum + { + // Require token kinds + protected abstract T StringLiteralTokenKind { get; } + protected abstract T IntegerLiteralTokenKind { get; } + protected abstract T FloatLiteralTokenKind { get; } + protected abstract T IdentifierTokenKind { get; } + protected abstract T InvalidTokenKind { get; } + protected abstract ParserStage Stage { get; } + + protected Token InvalidToken => new Token(InvalidTokenKind, null, anchorSpan, position); + + protected List> tokens = new List>(); + protected int position = 0; + protected SourceSpan anchorSpan = default; + protected List diagnostics = new List(); + protected bool isRecovering = false; + + protected bool throwExceptionOnError = false; + protected DiagnosticFlags diagnosticFilter = DiagnosticFlags.All; + public List Diagnostics => diagnostics; + + public BaseParser(List> tokens, bool throwExceptionOnError, DiagnosticFlags diagnosticFilter) + { + // Need to copy since the parser might want to modify tokens in place + this.tokens = new List>(tokens); + this.throwExceptionOnError = throwExceptionOnError; + this.diagnosticFilter = diagnosticFilter; + } + + protected Stack<(int position, bool isRecovering, SourceSpan span, int diagnosticCount)> snapshots = new Stack<(int position, bool isRecovering, SourceSpan span, int diagnosticCount)>(); + + protected void SnapshotState() + { + snapshots.Push((position, isRecovering, anchorSpan, diagnostics.Count)); + } + + protected void RestoreState() + { + var snapshot = snapshots.Pop(); + position = snapshot.position; + isRecovering = snapshot.isRecovering; + anchorSpan = snapshot.span; + diagnostics.RemoveRange(snapshot.diagnosticCount, diagnostics.Count - snapshot.diagnosticCount); + } + + protected void DropState() + { + snapshots.Pop(); + } + + protected bool Speculate(Func parser) + { + SnapshotState(); + + try + { + // Try the parser + bool result = parser(); + + // If we encountered any errors, report false + if (diagnostics.Count > snapshots.Peek().diagnosticCount) + { + return false; + } + + // Otherwise report whatever the parser got + return result; + } + finally + { + RestoreState(); + } + } + + protected bool TryParse

(Func

parser, out P parsed) + { + SnapshotState(); + + // Try the parser + parsed = parser(); + + // If we encountered any errors, report false + if (diagnostics.Count > snapshots.Peek().diagnosticCount) + { + RestoreState(); + parsed = default; + return false; + } + + // Otherwise return whatever the parser got + DropState(); + return true; + } + + protected Token LookAhead(int offset = 1) + { + if (IsAtEnd(offset)) + return InvalidToken; + // If we are currently recovering from an error, return an error token. + else if (isRecovering) + return InvalidToken; + else + return tokens[position + offset]; + } + protected Token Peek() => LookAhead(0); + protected bool Match(Func, bool> predicate) => predicate(Peek()); + protected bool Match(Func predicate) => predicate(Peek().Kind); + protected bool Match(T kind) => Match(tok => EqualityComparer.Default.Equals(tok.Kind, kind)); + protected bool Match(params T[] alternatives) => Match(tok => alternatives.Contains(tok.Kind)); + protected bool IsAtEnd(int offset = 0) => position + offset >= tokens.Count; + protected bool LoopShouldContinue() => !IsAtEnd() && !isRecovering; + protected Token Eat(Func predicate) + { + if (!Match(predicate)) + Error(DiagnosticFlags.SyntaxError, $"Unexpected token '{Peek()}'."); + return Advance(); + } + protected Token Eat(T kind) + { + if (!Match(kind)) + Error(DiagnosticFlags.SyntaxError, $"Expected token type '{kind}', got '{Peek().Kind}'."); + return Advance(); + } + protected Token Eat(params T[] alternatives) + { + if (!Match(alternatives)) + { + string allowed = string.Join(", ", alternatives); + Error(DiagnosticFlags.SyntaxError, $"Unexpected token '{Peek()}', expected one of the following token types: {allowed}."); + } + return Advance(); + } + protected Token Advance(int amount = 1) + { + if (IsAtEnd(amount - 1)) + return InvalidToken; + // If we are currently recovering from an error, don't keep eating tokens, and instead return an error token. + else if (isRecovering) + return InvalidToken; + Token result = tokens[position]; + position += amount; + anchorSpan = Peek().Span; + return result; + } + protected Token Previous() => LookAhead(-1); + + protected void Error(DiagnosticFlags kind, string msg) + { + // If we don't care about this kind of warning, or we are currently recovering from an error, bail + if (!diagnosticFilter.HasFlag(kind) || isRecovering) + return; + + // If we have hit an actual error, start error recovery mode + if (kind != DiagnosticFlags.Warning) + { + isRecovering = true; + } + + // Throw an exception if requested and while we aren't speculating + if (throwExceptionOnError && snapshots.Count == 0 && kind != DiagnosticFlags.Warning) + { + throw new Exception($"Error at line {anchorSpan.Start.Line}, column {anchorSpan.Start.Column} during {Stage}: {msg}"); + } + + // Log the diagnostic + diagnostics.Add(new Diagnostic(anchorSpan.Start, kind, Stage, msg)); + } + + protected void Error(DiagnosticFlags kind, string msg, SourceSpan span) + { + anchorSpan = span; + Error(kind, msg); + } + + protected void Error(string expected, Token token) + { + Error(DiagnosticFlags.SyntaxError, $"Expected {expected}, got token ({token})", token.Span); + } + + protected List> Range(Token first, Token last) + { + if (first == null || last == null) return new List>(); + int count = last.Position - first.Position + 1; + if (count < 0) count = 0; + if (first.Position + count > tokens.Count) count = tokens.Count - first.Position; + return tokens.GetRange(first.Position, count); + } + + protected string ParseIdentifier() + { + Token identifierToken = Eat(IdentifierTokenKind); + string identifier = identifierToken.Identifier ?? string.Empty; + if (string.IsNullOrEmpty(identifier)) + Error("a valid identifier", identifierToken); + return identifier; + } + + protected string ParseStringLiteral() + { + Token literalToken = Eat(StringLiteralTokenKind); + return literalToken.Identifier ?? string.Empty; + } + + protected float ParseNumericLiteral() + { + Token literalToken = Eat(FloatLiteralTokenKind, IntegerLiteralTokenKind); + string literal = literalToken.Identifier ?? string.Empty; + if (string.IsNullOrEmpty(literal)) + Error("a valid numeric literal", literalToken); + return float.Parse(literal, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture); + } + + protected int ParseIntegerLiteral() + { + return (int)ParseNumericLiteral(); + } + + protected byte ParseByteLiteral() + { + return (byte)ParseNumericLiteral(); + } + + protected TEnum ParseEnum(string expected) + where TEnum : struct + { + Token next = Advance(); + // ShaderLab has a lot of ambiguous syntax, many keywords are reused in multiple places as regular identifiers. + // If we fail to use the identifier directly, it might be an overlapping keyword, so try that instead. + string identifier = next.Identifier ?? next.Kind.ToString()?.Replace("Keyword", "") ?? String.Empty; + if (Enum.TryParse(identifier, true, out TEnum result)) + { + return result; + } + else + { + Error(expected, next); + return default; + } + } + + #region Parser combinators + protected List

ParseSeparatedList0

(T end, T separator, Func

parser, bool allowTrailingSeparator = false) + { + if (Match(end)) + return new List

(); + + List

result = new List

(); + + result.Add(parser()); + + if (isRecovering) + return result; + + while (Match(separator)) + { + int lastPosition = position; + + Advance(); + if (!allowTrailingSeparator || !Match(end)) + { + result.Add(parser()); + } + + if (isRecovering) + return result; + + if (lastPosition == position) + { +#if DEBUG + throw new Exception($"Parser got stuck parsing {Peek()}. Please file a bug report."); +#else + return result; +#endif + } + } + + return result; + } + + protected List

ParseSeparatedList1

(T seperator, Func

parser) + { + List

result = new List

(); + + result.Add(parser()); + + if (isRecovering) + return result; + + while (Match(seperator)) + { + int lastPosition = position; + + Eat(seperator); + result.Add(parser()); + + if (isRecovering) + return result; + + if (lastPosition == position) + { +#if DEBUG + throw new Exception($"Parser got stuck parsing {Peek()}. Please file a bug report."); +#else + return result; +#endif + } + } + + return result; + } + + protected List

ParseMany1

(T first, Func

parser) + { + List

result = new List

(); + + result.Add(parser()); + + if (isRecovering) + return result; + + while (Match(first)) + { + int lastPosition = position; + + result.Add(parser()); + + if (isRecovering) + return result; + + if (lastPosition == position) + { +#if DEBUG + throw new Exception($"Parser got stuck parsing {Peek()}. Please file a bug report."); +#else + return result; +#endif + } + } + + return result; + } + + protected List

ParseMany0

(T first, Func

parser) + { + if (!Match(first)) + return new List

(); + + return ParseMany1(first, parser); + } + + protected List

ParseMany1

(Func first, Func

parser) + { + List

result = new List

(); + + result.Add(parser()); + + if (isRecovering) + return result; + + while (first()) + { + int lastPosition = position; + + result.Add(parser()); + + if (isRecovering) + return result; + + if (lastPosition == position) + { +#if DEBUG + throw new Exception($"Parser got stuck parsing {Peek()}. Please file a bug report."); +#else + return result; +#endif + } + } + + return result; + } + + protected List

ParseMany0

(Func first, Func

parser) + { + if (!first()) + return new List

(); + + return ParseMany1(first, parser); + } + + protected P ParseOptional

(T first, Func

parser) + { + if (Match(first)) + return parser(); + return default; + } + + protected P ParseOptional

(Func first, Func

parser) + { + if (first()) + return parser(); + return default; + } + + protected void RecoverTo(T sync, bool inclusive = true) + { + // If not recovering, nothing to do + if (!isRecovering) + return; + + // Otherwise advance until the sync token + isRecovering = false; + while (!IsAtEnd() && !Match(sync)) Advance(); + if (inclusive && Match(sync)) Advance(); + } + + protected void RecoverTo(Func predicate, bool inclusive = true) + { + // If not recovering, nothing to do + if (!isRecovering) + return; + + // Otherwise advance until the sync token + isRecovering = false; + while (!IsAtEnd() && !predicate(Peek().Kind)) Advance(); + if (inclusive && predicate(Peek().Kind)) Advance(); + } + + protected void RecoverTo(params T[] syncs) + { + // If not recovering, nothing to do + if (!isRecovering) + return; + + // Otherwise advance until the sync token + isRecovering = false; + while (!IsAtEnd() && !Match(syncs)) Advance(); + if (Match(syncs)) Advance(); + } + #endregion + } +} + + +// Common/BaseSyntaxElements.cs +namespace UnityShaderParser.Common +{ + public enum ParserStage + { + HLSLLexing, + HLSLPreProcessing, + HLSLParsing, + ShaderLabLexing, + ShaderLabParsing, + } + + public struct SourceLocation + { + // For better diagnostics + public int Line { get; } + public int Column { get; } + + // For analysis + public int Index { get; } + + public SourceLocation(int line, int column, int index) + { + Line = line; + Column = column; + Index = index; + } + + public override string ToString() => $"({Line}, {Column})"; + } + + [Flags] + public enum DiagnosticFlags + { + None = 0, + SyntaxError = 1 << 0, // Ill-formed source code + SemanticError = 1 << 1, // Well-formed source code, but incorrect meaning + PreProcessorError = 1 << 2, // Error during preprocessing + Warning = 1 << 3, // Well-formed source code, but probably not what was intended + + OnlyErrors = SyntaxError | SemanticError | PreProcessorError, + All = OnlyErrors | Warning + } + + public struct Diagnostic + { + public SourceLocation Location { get; } + public DiagnosticFlags Kind { get; } + public ParserStage Stage { get; } + public string Text { get; } + + public Diagnostic(SourceLocation location, DiagnosticFlags kind, ParserStage stage, string text) + { + Location = location; + Kind = kind; + Stage = stage; + Text = text; + } + + public override string ToString() + { + return $"Error during {Stage}, line {Location.Line}, col {Location.Column}: {Text}"; + } + } + + public struct SourceSpan + { + public string BasePath { get; } + public string FileName { get; } + public SourceLocation Start { get; } + public SourceLocation End { get; } + + public int StartIndex => Start.Index; + public int EndIndex => End.Index; + public int Length => EndIndex - StartIndex; + + public SourceSpan(string basePath, string fileName, SourceLocation start, SourceLocation end) + { + BasePath = basePath; + FileName = fileName; + Start = start; + End = end; + } + + public override string ToString() => $"({Start.Line}:{Start.Column} - {End.Line}:{End.Column})"; + + public string GetCodeInSourceText(string sourceText) => sourceText.Substring(StartIndex, Length); + + public static SourceSpan FromTokens(IEnumerable> tokens) + where T : struct + { + if (tokens == null || !tokens.Any()) + throw new ArgumentException(nameof(tokens)); + var ordered = tokens.OrderBy(x => x.Span.StartIndex); + var first = ordered.First(); + var last = ordered.Last(); + return BetweenTokens(first, last); + } + + public static SourceSpan BetweenTokens(Token first, Token last) + where T : struct => new SourceSpan(first.Span.BasePath, first.Span.FileName, first.Span.Start, last.Span.End); + + public static SourceSpan Between(SourceSpan first, SourceSpan last) + => new SourceSpan(first.BasePath, first.FileName, first.Start, last.End); + } + + public class Token + where T : struct + { + public T Kind { get; private set; } + public string Identifier { get; private set; } // Optional + public SourceSpan Span { get; private set; } // Location in source code + public SourceSpan OriginalSpan { get; private set; } + public int Position { get; private set; } // Location in token stream + + public Token(T kind, string identifier, SourceSpan span, int position) + { + Kind = kind; + Identifier = identifier; + Span = span; + OriginalSpan = span; + Position = position; + } + + public Token(T kind, string identifier, SourceSpan span, SourceSpan originalSpan, int position) + { + Kind = kind; + Identifier = identifier; + Span = span; + OriginalSpan = originalSpan; + Position = position; + } + + // TODO: Trivia + public override string ToString() + { + if (Identifier == null) + return Kind.ToString() ?? string.Empty; + else + return $"{Kind}({Identifier})"; + } + + public string GetCodeInSourceText(string sourceText) => Span.GetCodeInSourceText(sourceText); + } + + public abstract class SyntaxNode + where TSelf : SyntaxNode + { + // Helpers + protected static IEnumerable MergeChildren(params IEnumerable[] children) + => children.SelectMany(x => x); + protected static IEnumerable OptionalChild(TSelf child) + => child == null ? Enumerable.Empty() : new[] { child }; + protected static IEnumerable Child(TSelf child) + => new[] { child }; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + protected abstract IEnumerable GetChildren { get; } + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private TSelf parent; + internal void ComputeParents() + { + foreach (var child in GetChildren) + { + child.parent = (TSelf)this; + child.ComputeParents(); + } + } + + // Public API + public List Children => GetChildren.ToList(); + public TSelf Parent => parent; + public abstract SourceSpan Span { get; } + public abstract SourceSpan OriginalSpan { get; } + } + + public enum PrettyEnumStyle + { + AllLowerCase, + AllUpperCase, + CamelCase, + PascalCase, + } + + public class PrettyEnumAttribute : Attribute + { + public PrettyEnumStyle Style { get; set; } + public PrettyEnumAttribute(PrettyEnumStyle firstIsLowerCase) + { + Style = firstIsLowerCase; + } + } + + public class PrettyNameAttribute : Attribute + { + public string Name { get; set; } + + public PrettyNameAttribute(string name) + { + Name = name; + } + } + + public static class PrintingUtil + { + public static string GetEnumName(T val) + where T : Enum + { + string name; + PrettyEnumAttribute[] enumAttrs = typeof(T).GetCustomAttributes().ToArray(); + if (enumAttrs == null || enumAttrs.Length == 0) + { + name = Enum.GetName(typeof(T), val); + } + else + { + MemberInfo[] memberInfo = typeof(T).GetMember(val.ToString()); + if (memberInfo != null && memberInfo.Length > 0) + { + foreach (MemberInfo member in memberInfo) + { + PrettyNameAttribute[] attrs = member.GetCustomAttributes().ToArray(); + + if (attrs != null && attrs.Length > 0) + { + //Pull out the description value + return attrs[0].Name; + } + } + } + name = Enum.GetName(typeof(T), val); + } + + switch (enumAttrs[0].Style) + { + case PrettyEnumStyle.AllLowerCase: return name.ToLower(); + case PrettyEnumStyle.AllUpperCase: return name.ToUpper(); + case PrettyEnumStyle.CamelCase: + if (name.Length > 0) + { + name = $"{char.ToLower(name[0])}{name.Substring(1)}"; + } + return name; + default: + return name; + } + } + + // TODO: Edits across macro boundaries + public static string ApplyEditsToSourceText(IEnumerable<(SourceSpan span, string newText)> edits, string source) + { + var orderedEdits = edits.OrderBy(x => x.span.Start.Index); + var editedSourced = new StringBuilder(source); + int offset = 0; + foreach ((SourceSpan span, string newText) in orderedEdits) + { + editedSourced.Remove(span.Start.Index + offset, span.Length); + editedSourced.Insert(span.Start.Index + offset, newText); + offset -= span.Length; + offset += newText.Length; + } + return editedSourced.ToString(); + } + } +} + + +// Common/ShaderParser.cs +namespace UnityShaderParser.Common +{ + public static class ShaderParser + { + private static HLSLParserConfig DefaultHLSLConfig = new HLSLParserConfig(); + private static ShaderLabParserConfig DefaultShaderLabConfig = new ShaderLabParserConfig(); + + public static ShaderNode ParseUnityShader(string source, ShaderLabParserConfig config, out List diagnostics) + { + var tokens = ShaderLabLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var rootNode = ShaderLabParser.ParseShader(tokens, config, out var parserDiags); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return rootNode; + } + public static ShaderNode ParseUnityShader(string source, ShaderLabParserConfig config) => ParseUnityShader(source, config, out _); + public static ShaderNode ParseUnityShader(string source, out List diagnostics) => ParseUnityShader(source, DefaultShaderLabConfig, out diagnostics); + public static ShaderNode ParseUnityShader(string source) => ParseUnityShader(source, DefaultShaderLabConfig, out _); + + public static List ParseTopLevelDeclarations(string source, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + var tokens = HLSLLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var decls = HLSLParser.ParseTopLevelDeclarations(tokens, config, out var parserDiags, out pragmas); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return decls; + } + public static List ParseTopLevelDeclarations(string source, HLSLParserConfig config) => ParseTopLevelDeclarations(source, config, out _, out _); + public static List ParseTopLevelDeclarations(string source, out List diagnostics, out List pragmas) => ParseTopLevelDeclarations(source, DefaultHLSLConfig, out diagnostics, out pragmas); + public static List ParseTopLevelDeclarations(string source) => ParseTopLevelDeclarations(source, DefaultHLSLConfig, out _, out _); + + public static HLSLSyntaxNode ParseTopLevelDeclaration(string source, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + var tokens = HLSLLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var decl = HLSLParser.ParseTopLevelDeclaration(tokens, config, out var parserDiags, out pragmas); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return decl; + } + public static HLSLSyntaxNode ParseTopLevelDeclaration(string source, HLSLParserConfig config) => ParseTopLevelDeclaration(source, config, out _, out _); + public static HLSLSyntaxNode ParseTopLevelDeclaration(string source, out List diagnostics, out List pragmas) => ParseTopLevelDeclaration(source, DefaultHLSLConfig, out diagnostics, out pragmas); + public static HLSLSyntaxNode ParseTopLevelDeclaration(string source) => ParseTopLevelDeclaration(source, DefaultHLSLConfig, out _, out _); + + public static List ParseStatements(string source, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + var tokens = HLSLLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var stmt = HLSLParser.ParseStatements(tokens, config, out var parserDiags, out pragmas); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return stmt; + } + public static List ParseStatements(string source, HLSLParserConfig config) => ParseStatements(source, config, out _, out _); + public static List ParseStatements(string source, out List diagnostics, out List pragmas) => ParseStatements(source, DefaultHLSLConfig, out diagnostics, out pragmas); + public static List ParseStatements(string source) => ParseStatements(source, DefaultHLSLConfig, out _, out _); + + public static StatementNode ParseStatement(string source, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + var tokens = HLSLLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var stmt = HLSLParser.ParseStatement(tokens, config, out var parserDiags, out pragmas); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return stmt; + } + public static StatementNode ParseStatement(string source, HLSLParserConfig config) => ParseStatement(source, config, out _, out _); + public static StatementNode ParseStatement(string source, out List diagnostics, out List pragmas) => ParseStatement(source, DefaultHLSLConfig, out diagnostics, out pragmas); + public static StatementNode ParseStatement(string source) => ParseStatement(source, DefaultHLSLConfig, out _, out _); + + public static ExpressionNode ParseExpression(string source, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + var tokens = HLSLLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var expr = HLSLParser.ParseExpression(tokens, config, out var parserDiags, out pragmas); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return expr; + } + public static ExpressionNode ParseExpression(string source, HLSLParserConfig config) => ParseExpression(source, config, out _, out _); + public static ExpressionNode ParseExpression(string source, out List diagnostics, out List pragmas) => ParseExpression(source, DefaultHLSLConfig, out diagnostics, out pragmas); + public static ExpressionNode ParseExpression(string source) => ParseExpression(source, DefaultHLSLConfig, out _, out _); + + public static SubShaderNode ParseUnitySubShader(string source, ShaderLabParserConfig config, out List diagnostics) + { + var tokens = ShaderLabLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var rootNode = ShaderLabParser.ParseSubShader(tokens, config, out var parserDiags); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return rootNode; + } + public static SubShaderNode ParseUnitySubShader(string source, ShaderLabParserConfig config) => ParseUnitySubShader(source, config, out _); + public static SubShaderNode ParseUnitySubShader(string source, out List diagnostics) => ParseUnitySubShader(source, DefaultShaderLabConfig, out diagnostics); + public static SubShaderNode ParseUnitySubShader(string source) => ParseUnitySubShader(source, DefaultShaderLabConfig, out _); + + public static ShaderPassNode ParseUnityShaderPass(string source, ShaderLabParserConfig config, out List diagnostics) + { + var tokens = ShaderLabLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var rootNode = ShaderLabParser.ParseShaderPass(tokens, config, out var parserDiags); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return rootNode; + } + public static ShaderPassNode ParseUnityShaderPass(string source, ShaderLabParserConfig config) => ParseUnityShaderPass(source, config, out _); + public static ShaderPassNode ParseUnityShaderPass(string source, out List diagnostics) => ParseUnityShaderPass(source, DefaultShaderLabConfig, out diagnostics); + public static ShaderPassNode ParseUnityShaderPass(string source) => ParseUnityShaderPass(source, DefaultShaderLabConfig, out _); + + public static ShaderPropertyNode ParseUnityShaderProperty(string source, ShaderLabParserConfig config, out List diagnostics) + { + var tokens = ShaderLabLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var rootNode = ShaderLabParser.ParseShaderProperty(tokens, config, out var parserDiags); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return rootNode; + } + public static ShaderPropertyNode ParseUnityShaderProperty(string source, ShaderLabParserConfig config) => ParseUnityShaderProperty(source, config, out _); + public static ShaderPropertyNode ParseUnityShaderProperty(string source, out List diagnostics) => ParseUnityShaderProperty(source, DefaultShaderLabConfig, out diagnostics); + public static ShaderPropertyNode ParseUnityShaderProperty(string source) => ParseUnityShaderProperty(source, DefaultShaderLabConfig, out _); + + public static List ParseUnityShaderProperties(string source, ShaderLabParserConfig config, out List diagnostics) + { + var tokens = ShaderLabLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var rootNode = ShaderLabParser.ParseShaderProperties(tokens, config, out var parserDiags); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return rootNode; + } + public static List ParseUnityShaderProperties(string source, ShaderLabParserConfig config) => ParseUnityShaderProperties(source, config, out _); + public static List ParseUnityShaderProperties(string source, out List diagnostics) => ParseUnityShaderProperties(source, DefaultShaderLabConfig, out diagnostics); + public static List ParseUnityShaderProperties(string source) => ParseUnityShaderProperties(source, DefaultShaderLabConfig, out _); + + public static List ParseUnityShaderPropertyBlock(string source, ShaderLabParserConfig config, out List diagnostics) + { + var tokens = ShaderLabLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var rootNode = ShaderLabParser.ParseShaderPropertyBlock(tokens, config, out var parserDiags); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return rootNode; + } + public static List ParseUnityShaderPropertyBlock(string source, ShaderLabParserConfig config) => ParseUnityShaderPropertyBlock(source, config, out _); + public static List ParseUnityShaderPropertyBlock(string source, out List diagnostics) => ParseUnityShaderPropertyBlock(source, DefaultShaderLabConfig, out diagnostics); + public static List ParseUnityShaderPropertyBlock(string source) => ParseUnityShaderPropertyBlock(source, DefaultShaderLabConfig, out _); + + public static ShaderLabCommandNode ParseUnityShaderCommand(string source, ShaderLabParserConfig config, out List diagnostics) + { + var tokens = ShaderLabLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var rootNode = ShaderLabParser.ParseShaderLabCommand(tokens, config, out var parserDiags); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return rootNode; + } + public static ShaderLabCommandNode ParseUnityShaderCommand(string source, ShaderLabParserConfig config) => ParseUnityShaderCommand(source, config, out _); + public static ShaderLabCommandNode ParseUnityShaderCommand(string source, out List diagnostics) => ParseUnityShaderCommand(source, DefaultShaderLabConfig, out diagnostics); + public static ShaderLabCommandNode ParseUnityShaderCommand(string source) => ParseUnityShaderCommand(source, DefaultShaderLabConfig, out _); + + public static List ParseUnityShaderCommands(string source, ShaderLabParserConfig config, out List diagnostics) + { + var tokens = ShaderLabLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var rootNode = ShaderLabParser.ParseShaderLabCommands(tokens, config, out var parserDiags); + diagnostics = lexerDiags.Concat(parserDiags).ToList(); + return rootNode; + } + public static List ParseUnityShaderCommands(string source, ShaderLabParserConfig config) => ParseUnityShaderCommands(source, config, out _); + public static List ParseUnityShaderCommands(string source, out List diagnostics) => ParseUnityShaderCommands(source, DefaultShaderLabConfig, out diagnostics); + public static List ParseUnityShaderCommands(string source) => ParseUnityShaderCommands(source, DefaultShaderLabConfig, out _); + + public static List> PreProcessToTokens(string source, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + var tokens = HLSLLexer.Lex(source, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + var ppTokens = HLSLPreProcessor.PreProcess( + tokens, + config.ThrowExceptionOnError, + config.DiagnosticFilter, + config.PreProcessorMode, + config.BasePath, + config.IncludeResolver, + config.Defines, + out pragmas, + out var ppDiags); + diagnostics = lexerDiags.Concat(ppDiags).ToList(); + return ppTokens; + } + public static List> PreProcessToTokens(string source, HLSLParserConfig config) => PreProcessToTokens(source, config, out _, out _); + public static List> PreProcessToTokens(string source, out List diagnostics, out List pragmas) => PreProcessToTokens(source, DefaultHLSLConfig, out diagnostics, out pragmas); + public static List> PreProcessToTokens(string source) => PreProcessToTokens(source, DefaultHLSLConfig, out _, out _); + + public static string PreProcessToString(string source, HLSLParserConfig config, out List diagnostics, out List pragmas) + { + return HLSLSyntaxFacts.TokensToString(PreProcessToTokens(source, config, out diagnostics, out pragmas)); + } + public static string PreProcessToString(string source, HLSLParserConfig config) => PreProcessToString(source, config, out _, out _); + public static string PreProcessToString(string source, out List diagnostics, out List pragmas) => PreProcessToString(source, DefaultHLSLConfig, out diagnostics, out pragmas); + public static string PreProcessToString(string source) => PreProcessToString(source, DefaultHLSLConfig, out _, out _); + } +} + + +// ShaderLab/ShaderLabEditor.cs +namespace UnityShaderParser.ShaderLab +{ + public abstract class ShaderLabEditor : ShaderLabSyntaxVisitor + { + public string Source { get; private set; } + public List> Tokens { get; private set; } + + public ShaderLabEditor(string source, List> tokens) + { + Source = source; + Tokens = tokens; + } + + protected HashSet<(SourceSpan span, string newText)> Edits = new HashSet<(SourceSpan, string)>(); + + protected void Edit(SourceSpan span, string newText) => Edits.Add((span, newText)); + protected void Edit(Token token, string newText) => Edit(token.Span, newText); + protected void Edit(ShaderLabSyntaxNode node, string newText) => Edit(node.Span, newText); + protected void AddBefore(SourceSpan span, string newText) => Edit(new SourceSpan(span.BasePath, span.FileName, span.Start, span.Start), newText); + protected void AddBefore(Token token, string newText) => Edit(new SourceSpan(token.Span.BasePath, token.Span.FileName, token.Span.Start, token.Span.Start), newText); + protected void AddBefore(ShaderLabSyntaxNode node, string newText) => Edit(new SourceSpan(node.Span.BasePath, node.Span.FileName, node.Span.Start, node.Span.Start), newText); + protected void AddAfter(SourceSpan span, string newText) => Edit(new SourceSpan(span.BasePath, span.FileName, span.End, span.End), newText); + protected void AddAfter(Token token, string newText) => Edit(new SourceSpan(token.Span.BasePath, token.Span.FileName, token.Span.End, token.Span.End), newText); + protected void AddAfter(ShaderLabSyntaxNode node, string newText) => Edit(new SourceSpan(node.Span.BasePath, node.Span.FileName, node.Span.End, node.Span.End), newText); + + public string ApplyCurrentEdits() => PrintingUtil.ApplyEditsToSourceText(Edits, Source); + + public string ApplyEdits(ShaderLabSyntaxNode node) + { + Visit(node); + return ApplyCurrentEdits(); + } + + public string ApplyEdits(IEnumerable nodes) + { + VisitMany(nodes); + return ApplyCurrentEdits(); + } + + public static string RunEditor(string source, ShaderLabSyntaxNode node) + where T : ShaderLabEditor + { + var editor = (ShaderLabEditor)Activator.CreateInstance(typeof(T), source, node.Tokens); + return editor.ApplyEdits(node); + } + + public static string RunEditor(string source, IEnumerable node) + where T : ShaderLabEditor + { + var editor = (ShaderLabEditor)Activator.CreateInstance(typeof(T), source, node.SelectMany(x => x.Tokens).ToList()); + return editor.ApplyEdits(node); + } + } +} + + +// ShaderLab/ShaderLabLexer.cs +namespace UnityShaderParser.ShaderLab +{ + using SLToken = Token; + + public class ShaderLabLexer : BaseLexer + { + protected override ParserStage Stage => ParserStage.ShaderLabLexing; + + public ShaderLabLexer(string source, string basePath, string fileName, bool throwExceptionOnError) + : base(source, basePath, fileName, throwExceptionOnError, new SourceLocation(1, 1, 0)) { } + + public static List Lex(string source, string basePath, string fileName, bool throwExceptionOnError, out List diagnostics) + { + ShaderLabLexer lexer = new ShaderLabLexer(source, basePath, fileName, throwExceptionOnError); + + lexer.Lex(); + + diagnostics = lexer.diagnostics; + return lexer.tokens; + } + + protected override void ProcessChar(char nextChar) + { + switch (nextChar) + { + case char c when char.IsLetter(c) || c == '_': + LexIdentifier(); + break; + + case '2' when LookAhead('D') || LookAhead('d'): + case '3' when LookAhead('D') || LookAhead('d'): + LexDimensionalTextureType(); + break; + + case char c when char.IsDigit(c) || ((c == '.' || c == '-') && char.IsDigit(LookAhead())): + string num = EatNumber(out bool isFloat); + TokenKind kind = isFloat ? TokenKind.FloatLiteralToken : TokenKind.IntegerLiteralToken; + Add(num, kind); + break; + + case '"': + Add(EatStringLiteral('"', '"'), TokenKind.StringLiteralToken); + break; + + case '[' when IsAlphaNumericOrUnderscore(LookAhead()): + Add(EatStringLiteral('[', ']'), TokenKind.BracketedStringLiteralToken); + break; + + case ' ': + case '\t': + case '\r': + case '\n': + Advance(); + break; + + case '/' when LookAhead('/'): + Advance(2); + while (!Match('\n')) + { + Advance(); + if (IsAtEnd()) + break; + } + break; + + case '/' when LookAhead('*'): + Advance(2); + while (!(Match('*') && LookAhead('/'))) + { + Advance(); + if (IsAtEnd()) + { + Error(DiagnosticFlags.SyntaxError, $"Unterminated comment."); + break; + } + } + Advance(2); + break; + + case '(': Advance(); Add(TokenKind.OpenParenToken); break; + case ')': Advance(); Add(TokenKind.CloseParenToken); break; + case '[': Advance(); Add(TokenKind.OpenBracketToken); break; + case ']': Advance(); Add(TokenKind.CloseBracketToken); break; + case '{': Advance(); Add(TokenKind.OpenBraceToken); break; + case '}': Advance(); Add(TokenKind.CloseBraceToken); break; + case ';': Advance(); Add(TokenKind.SemiToken); break; + case ',': Advance(); Add(TokenKind.CommaToken); break; + case '.': Advance(); Add(TokenKind.DotToken); break; + case '~': Advance(); Add(TokenKind.TildeToken); break; + case '?': Advance(); Add(TokenKind.QuestionToken); break; + + case '<' when LookAhead('='): Advance(2); Add(TokenKind.LessThanEqualsToken); break; + case '<' when LookAhead('<') && LookAhead('=', 2): Advance(3); Add(TokenKind.LessThanLessThanEqualsToken); break; + case '<' when LookAhead('<'): Advance(2); Add(TokenKind.LessThanLessThanToken); break; + case '<': Advance(); Add(TokenKind.LessThanToken); break; + + case '>' when LookAhead('='): Advance(2); Add(TokenKind.GreaterThanEqualsToken); break; + case '>' when LookAhead('>') && LookAhead('=', 2): Advance(3); Add(TokenKind.GreaterThanGreaterThanEqualsToken); break; + case '>' when LookAhead('>'): Advance(2); Add(TokenKind.GreaterThanGreaterThanToken); break; + case '>': Advance(); Add(TokenKind.GreaterThanToken); break; + + case '+' when LookAhead('+'): Advance(2); Add(TokenKind.PlusPlusToken); break; + case '+' when LookAhead('='): Advance(2); Add(TokenKind.PlusEqualsToken); break; + case '+': Advance(); Add(TokenKind.PlusToken); break; + + case '-' when LookAhead('-'): Advance(2); Add(TokenKind.MinusMinusToken); break; + case '-' when LookAhead('='): Advance(2); Add(TokenKind.MinusEqualsToken); break; + case '-': Advance(); Add(TokenKind.MinusToken); break; + + case '*' when LookAhead('='): Advance(2); Add(TokenKind.AsteriskEqualsToken); break; + case '*': Advance(); Add(TokenKind.AsteriskToken); break; + + case '/' when LookAhead('='): Advance(2); Add(TokenKind.SlashEqualsToken); break; + case '/': Advance(); Add(TokenKind.SlashToken); break; + + case '%' when LookAhead('='): Advance(2); Add(TokenKind.PercentEqualsToken); break; + case '%': Advance(); Add(TokenKind.PercentToken); break; + + case '&' when LookAhead('&'): Advance(2); Add(TokenKind.AmpersandAmpersandToken); break; + case '&' when LookAhead('='): Advance(2); Add(TokenKind.AmpersandEqualsToken); break; + case '&': Advance(); Add(TokenKind.AmpersandToken); break; + + case '|' when LookAhead('|'): Advance(2); Add(TokenKind.BarBarToken); break; + case '|' when LookAhead('='): Advance(2); Add(TokenKind.BarEqualsToken); break; + case '|': Advance(); Add(TokenKind.BarToken); break; + + case '^' when LookAhead('='): Advance(2); Add(TokenKind.CaretEqualsToken); break; + case '^': Advance(); Add(TokenKind.CaretToken); break; + + case ':' when LookAhead(':'): Advance(2); Add(TokenKind.ColonColonToken); break; + case ':': Advance(); Add(TokenKind.ColonToken); break; + + case '=' when LookAhead('='): Advance(2); Add(TokenKind.EqualsEqualsToken); break; + case '=': Advance(); Add(TokenKind.EqualsToken); break; + + case '!' when LookAhead('='): Advance(2); Add(TokenKind.ExclamationEqualsToken); break; + case '!': Advance(); Add(TokenKind.NotToken); break; + + case char c: + Advance(); + Error(DiagnosticFlags.SyntaxError, $"Unexpected token '{c}'."); + break; + } + } + + private string SkipProgramBody(string expectedEnd) + { + StringBuilder builder = new StringBuilder(); + while (true) + { + // If there is still space for the terminator + if (!IsAtEnd(expectedEnd.Length)) + { + // And we have reached the terminator, stop + if (source.Substring(position, expectedEnd.Length) == expectedEnd) + { + Advance(expectedEnd.Length); + break; + } + + // Otherwise advance + builder.Append(Advance()); + } + // No space for terminator, error + else + { + Error(DiagnosticFlags.SyntaxError, $"Unterminated program block."); + break; + } + } + + return builder.ToString(); + } + + private void LexDimensionalTextureType() + { + StringBuilder builder = new StringBuilder(); + builder.Append(Advance()); + while (char.IsLetter(Peek())) + { + builder.Append(Advance()); + } + + switch (builder.ToString().ToLower()) + { + case "2darray": Add(TokenKind._2DArrayKeyword); break; + case "3darray": Add(TokenKind._3DArrayKeyword); break; + case "2d": Add(TokenKind._2DKeyword); break; + case "3d": Add(TokenKind._3DKeyword); break; + } + } + + private void LexIdentifier() + { + string identifier = EatIdentifier(); + if (ShaderLabSyntaxFacts.TryParseShaderLabKeyword(identifier, out TokenKind token)) + { + if (token == TokenKind.CgProgramKeyword) + { + string body = SkipProgramBody("ENDCG"); + Add(body, TokenKind.ProgramBlock); + } + else if (token == TokenKind.CgIncludeKeyword) + { + string body = SkipProgramBody("ENDCG"); + Add(body, TokenKind.IncludeBlock); + } + else if (token == TokenKind.HlslProgramKeyword) + { + string body = SkipProgramBody("ENDHLSL"); + Add(body, TokenKind.ProgramBlock); + } + else if (token == TokenKind.HlslIncludeKeyword) + { + string body = SkipProgramBody("ENDHLSL"); + Add(body, TokenKind.IncludeBlock); + } + else if (token == TokenKind.GlslProgramKeyword) + { + string body = SkipProgramBody("ENDGLSL"); + Add(body, TokenKind.ProgramBlock); + } + else if (token == TokenKind.GlslIncludeKeyword) + { + string body = SkipProgramBody("ENDGLSL"); + Add(body, TokenKind.IncludeBlock); + } + else + { + Add(token); + } + } + else + { + Add(identifier, TokenKind.IdentifierToken); + } + } + } +} + + +// ShaderLab/ShaderLabParser.cs +namespace UnityShaderParser.ShaderLab +{ + using SLToken = Token; + using HLSLToken = Token; + + public class ShaderLabParserConfig : HLSLParserConfig + { + public bool ParseEmbeddedHLSL { get; set; } + + public ShaderLabParserConfig() + : base() + { + ParseEmbeddedHLSL = true; + } + + public ShaderLabParserConfig(ShaderLabParserConfig config) + : base(config) + { + ParseEmbeddedHLSL = config.ParseEmbeddedHLSL; + } + } + + public class ShaderLabParser : BaseParser + { + public ShaderLabParser(List tokens, ShaderLabParserConfig config) + : base(tokens, config.ThrowExceptionOnError, config.DiagnosticFilter) + { + this.config = config; + } + + protected override TokenKind StringLiteralTokenKind => TokenKind.StringLiteralToken; + protected override TokenKind IntegerLiteralTokenKind => TokenKind.IntegerLiteralToken; + protected override TokenKind FloatLiteralTokenKind => TokenKind.FloatLiteralToken; + protected override TokenKind IdentifierTokenKind => TokenKind.IdentifierToken; + protected override TokenKind InvalidTokenKind => TokenKind.InvalidToken; + protected override ParserStage Stage => ParserStage.ShaderLabParsing; + + // Tokens that we may be able to recover to after encountered an error in a command. + private static readonly HashSet commandSyncTokens = new HashSet() + { + TokenKind.TagsKeyword, TokenKind.LodKeyword, TokenKind.LightingKeyword, TokenKind.SeparateSpecularKeyword, + TokenKind.ZWriteKeyword,TokenKind.AlphaToMaskKeyword, TokenKind.ZClipKeyword, TokenKind.ConservativeKeyword, + TokenKind.CullKeyword, TokenKind.ZTestKeyword, TokenKind.BlendKeyword, TokenKind.OffsetKeyword, TokenKind.ColorMaskKeyword, + TokenKind.AlphaTestKeyword, TokenKind.FogKeyword, TokenKind.NameKeyword, TokenKind.BindChannelsKeyword, TokenKind.ColorKeyword, + TokenKind.BlendOpKeyword,TokenKind.MaterialKeyword, TokenKind.SetTextureKeyword, TokenKind.ColorMaterialKeyword, TokenKind.StencilKeyword, + TokenKind.SubShaderKeyword, TokenKind.ShaderKeyword, TokenKind.PassKeyword, TokenKind.CategoryKeyword, TokenKind.GrabPassKeyword, + TokenKind.UsePassKeyword, TokenKind.FallbackKeyword, TokenKind.CustomEditorKeyword, + }; + + protected ShaderLabParserConfig config = default; + protected Stack> currentIncludeBlocks = new Stack>(); + + public static ShaderNode Parse(List tokens, ShaderLabParserConfig config, out List diagnostics) + { + ShaderLabParser parser = new ShaderLabParser(tokens, config); + var result = parser.ParseShader(); + result.ComputeParents(); + diagnostics = parser.diagnostics; + return result; + } + + public static ShaderNode ParseShader(List tokens, ShaderLabParserConfig config, out List diagnostics) + { + return Parse(tokens, config, out diagnostics); + } + + public static SubShaderNode ParseSubShader(List tokens, ShaderLabParserConfig config, out List diagnostics) + { + ShaderLabParser parser = new ShaderLabParser(tokens, config); + var result = parser.ParseSubShader(); + result.ComputeParents(); + diagnostics = parser.diagnostics; + return result; + } + + public static ShaderPassNode ParseShaderPass(List tokens, ShaderLabParserConfig config, out List diagnostics) + { + ShaderLabParser parser = new ShaderLabParser(tokens, config); + ShaderPassNode result = null; + switch (parser.Peek().Kind) + { + case TokenKind.PassKeyword: result = parser.ParseCodePass(); break; + case TokenKind.GrabPassKeyword: result = parser.ParseGrabPass(); break; + case TokenKind.UsePassKeyword: result = parser.ParseUsePass(); break; + } + result.ComputeParents(); + diagnostics = parser.diagnostics; + return result; + } + + public static ShaderPropertyNode ParseShaderProperty(List tokens, ShaderLabParserConfig config, out List diagnostics) + { + ShaderLabParser parser = new ShaderLabParser(tokens, config); + var result = parser.ParseProperty(); + result.ComputeParents(); + diagnostics = parser.diagnostics; + return result; + } + + public static List ParseShaderProperties(List tokens, ShaderLabParserConfig config, out List diagnostics) + { + ShaderLabParser parser = new ShaderLabParser(tokens, config); + List result = new List(); + while (parser.Match(TokenKind.IdentifierToken, TokenKind.BracketedStringLiteralToken)) + { + result.Add(parser.ParseProperty()); + } + foreach (var property in result) + { + property.ComputeParents(); + } + diagnostics = parser.diagnostics; + return result; + } + + public static List ParseShaderPropertyBlock(List tokens, ShaderLabParserConfig config, out List diagnostics) + { + ShaderLabParser parser = new ShaderLabParser(tokens, config); + List result = new List(); + parser.ParsePropertySection(result); + foreach (var property in result) + { + property.ComputeParents(); + } + diagnostics = parser.diagnostics; + return result; + } + + public static ShaderLabCommandNode ParseShaderLabCommand(List tokens, ShaderLabParserConfig config, out List diagnostics) + { + ShaderLabParser parser = new ShaderLabParser(tokens, config); + parser.TryParseCommand(out var result); + result.ComputeParents(); + diagnostics = parser.diagnostics; + return result; + } + + public static List ParseShaderLabCommands(List tokens, ShaderLabParserConfig config, out List diagnostics) + { + ShaderLabParser parser = new ShaderLabParser(tokens, config); + List result = new List(); + parser.ParseCommandsIfPresent(result); + foreach (var property in result) + { + property.ComputeParents(); + } + diagnostics = parser.diagnostics; + return result; + } + + protected void ProcessCurrentIncludes( + SLToken programToken, + bool lexEmbeddedHLSL, + out string fullCode, + out List tokenStream) + { + tokenStream = new List(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < currentIncludeBlocks.Count; i++) + { + var includeBlockList = currentIncludeBlocks.ElementAt(currentIncludeBlocks.Count - 1 - i); + foreach (var includeBlock in includeBlockList) + { + if (lexEmbeddedHLSL) + { + tokenStream.AddRange(HLSLLexer.Lex(includeBlock.Code, config.BasePath, config.FileName, config.ThrowExceptionOnError, includeBlock.Location, out var includeLexerDiags)); + diagnostics.AddRange(includeLexerDiags); + } + sb.Append(includeBlock.Code); + } + } + if (lexEmbeddedHLSL) + { + tokenStream.AddRange(HLSLLexer.Lex(programToken.Identifier, config.BasePath, config.FileName, config.ThrowExceptionOnError, programToken.Span.Start, out var lexerDiags)); + diagnostics.AddRange(lexerDiags); + } + sb.Append(programToken.Identifier); + fullCode = sb.ToString(); + } + protected HLSLProgramBlock ParseOrSkipEmbeddedHLSL() + { + var programToken = Eat(TokenKind.ProgramBlock); + string program = programToken.Identifier; + + // Prepend include blocks + ProcessCurrentIncludes( + programToken, + config.ParseEmbeddedHLSL, + out string fullCode, + out var tokenStream); + + // Try to figure out if we have surface shader. + // Surface shaders have some additional implicit includes. + string[] lines = fullCode.Split('\n'); + bool isSurfaceShader = false; + foreach (string line in lines) + { + if (line.TrimStart().StartsWith("#pragma")) + { + string[] args = line.TrimStart().Split(' '); + if (args.Length > 0) + { + if (args[1] == "surface") + { + isSurfaceShader = true; + break; + } + else if (args[1] == "vertex" || args[1] == "fragment") + { + isSurfaceShader = false; + break; + } + } + } + } + + // Add preamble + string preamble; + if (isSurfaceShader) + { + // Surface shader compiler has some secret INTERNAL_DATA macro and special includes :( + preamble = $"#ifndef INTERNAL_DATA\n#define INTERNAL_DATA\n#endif\n#include \"UnityCG.cginc\"\n"; + } + else + { + // UnityShaderVariables.cginc should always be included otherwise + preamble = $"#include \"UnityShaderVariables.cginc\"\n"; + } + fullCode = $"{preamble}{fullCode}"; + if (!config.ParseEmbeddedHLSL) + { + return new HLSLProgramBlock + { + CodeWithoutIncludes = program, + FullCode = fullCode, + Pragmas = new List(), + TopLevelDeclarations = new List(), + }; + } + + // Lex preamble + var premableTokens = HLSLLexer.Lex(preamble, config.BasePath, config.FileName, config.ThrowExceptionOnError, out var lexerDiags); + diagnostics.InsertRange(0, lexerDiags); + tokenStream.InsertRange(0, premableTokens); + + // TODO: Don't redo the parsing work every time - it's slow x) + var decls = HLSLParser.ParseTopLevelDeclarations(tokenStream, config, out var parserDiags, out var pragmas); + diagnostics.AddRange(parserDiags); + return new HLSLProgramBlock + { + CodeWithoutIncludes = program, + FullCode = fullCode, + Location = programToken.Span.Start, + Pragmas = pragmas, + TopLevelDeclarations = decls, + }; + } + protected void PushIncludes() => currentIncludeBlocks.Push(new List()); + protected void PopIncludes() => currentIncludeBlocks.Pop(); + protected void SetIncludes(List includes) + { + currentIncludeBlocks.Pop(); + currentIncludeBlocks.Push(includes); + } + + public ShaderNode ParseShader() + { + PushIncludes(); + + var keywordTok = Eat(TokenKind.ShaderKeyword); + string name = Eat(TokenKind.StringLiteralToken).Identifier ?? string.Empty; + Eat(TokenKind.OpenBraceToken); + + List includeBlocks = new List(); + + ParseIncludeBlocksIfPresent(includeBlocks); + + List properties = new List(); + if (Match(TokenKind.PropertiesKeyword)) + { + ParsePropertySection(properties); + } + + List subshaders = new List(); + string fallback = null; + bool fallbackDisabledExplicitly = false; + string customEditor = null; + Dictionary dependencies = new Dictionary(); + + // Keep track of commands inherited by categories as we parse. + // We essentially pretend categories don't exist, since they are a niche feature. + Stack> categoryCommands = new Stack>(); + + while (LoopShouldContinue()) + { + ParseIncludeBlocksIfPresent(includeBlocks); + SetIncludes(includeBlocks); + + // If we are in a category, put the commands there + if (categoryCommands.Count > 0) + ParseCommandsIfPresent(categoryCommands.Peek()); + + SLToken next = Peek(); + if (next.Kind == TokenKind.CloseBraceToken) + break; + + switch (next.Kind) + { + case TokenKind.SubShaderKeyword: + var subShader = ParseSubShader(); + subShader.Commands.AddRange(categoryCommands.SelectMany(x => x)); + subshaders.Add(subShader); + break; + case TokenKind.FallbackKeyword: + Advance(); + if (Match(TokenKind.OffKeyword, TokenKind.FalseKeyword)) + { + fallbackDisabledExplicitly = true; + Advance(); + } + else + { + fallback = Eat(TokenKind.StringLiteralToken).Identifier ?? string.Empty; + } + break; + case TokenKind.DependencyKeyword: + Advance(); + string key = ParseStringLiteral(); + Eat(TokenKind.EqualsToken); + string val = ParseStringLiteral(); + dependencies[key] = val; + break; + case TokenKind.CustomEditorKeyword: + Advance(); + customEditor = Eat(TokenKind.StringLiteralToken).Identifier ?? string.Empty; + break; + case TokenKind.CategoryKeyword: + Advance(); + Eat(TokenKind.OpenBraceToken); + categoryCommands.Push(new List()); + break; + case TokenKind.CloseBraceToken when categoryCommands.Count > 0: + Advance(); + categoryCommands.Pop(); + break; + default: + Advance(); + Error($"SubShader, Fallback, Dependency or CustomEditor", next); + break; + } + } + + ParseIncludeBlocksIfPresent(includeBlocks); + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + PopIncludes(); + + return new ShaderNode(Range(keywordTok, closeTok)) + { + Name = name, + Properties = properties, + SubShaders = subshaders, + Fallback = fallback, + FallbackDisabledExplicitly = fallbackDisabledExplicitly, + CustomEditor = customEditor, + Dependencies = dependencies, + IncludeBlocks = includeBlocks, + }; + } + + public void ParseIncludeBlocksIfPresent(List outIncludeBlocks) + { + while (true) + { + SLToken next = Peek(); + if (next.Kind == TokenKind.IncludeBlock && !string.IsNullOrEmpty(next.Identifier)) + { + outIncludeBlocks.Add(new HLSLIncludeBlock { Location = next.Span.Start, Code = next.Identifier }); + Advance(); + } + else + { + break; + } + } + } + + // TODO: Actually parse contents. In rare cases it can matter. + public string ParseBracketedStringLiteral() + { + SLToken literalToken = Eat(TokenKind.BracketedStringLiteralToken); + string literal = literalToken.Identifier ?? string.Empty; + if (string.IsNullOrEmpty(literal)) + Error("a valid bracketed string literal / property reference", literalToken); + return literal; + } + + public void ParsePropertySection(List outProperties) + { + Eat(TokenKind.PropertiesKeyword); + Eat(TokenKind.OpenBraceToken); + + while (Match(TokenKind.IdentifierToken, TokenKind.BracketedStringLiteralToken)) + { + outProperties.Add(ParseProperty()); + } + + Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + } + + public ShaderPropertyNode ParseProperty() + { + var firstTok = Peek(); + List attributes = new List(); + while (Match(TokenKind.BracketedStringLiteralToken)) + { + attributes.Add(ParseBracketedStringLiteral()); + } + + string uniform = ParseIdentifier(); + + Eat(TokenKind.OpenParenToken); + + string name = ParseStringLiteral(); + Eat(TokenKind.CommaToken); + + ShaderPropertyKind kind = ShaderPropertyKind.None; + (float Min, float Max)? rangeMinMax = null; + SLToken typeToken = Advance(); + switch (typeToken.Kind) + { + case TokenKind.FloatKeyword: kind = ShaderPropertyKind.Float; break; + case TokenKind.IntegerKeyword: kind = ShaderPropertyKind.Integer; break; + case TokenKind.IntKeyword: kind = ShaderPropertyKind.Int; break; + case TokenKind.ColorKeyword: kind = ShaderPropertyKind.Color; break; + case TokenKind.VectorKeyword: kind = ShaderPropertyKind.Vector; break; + case TokenKind._2DKeyword: case TokenKind.RectKeyword: kind = ShaderPropertyKind.Texture2D; break; + case TokenKind._3DKeyword: kind = ShaderPropertyKind.Texture3D; break; + case TokenKind.CubeKeyword: kind = ShaderPropertyKind.TextureCube; break; + case TokenKind._2DArrayKeyword: kind = ShaderPropertyKind.Texture2DArray; break; + case TokenKind._3DArrayKeyword: kind = ShaderPropertyKind.Texture3DArray; break; + case TokenKind.CubeArrayKeyword: kind = ShaderPropertyKind.TextureCubeArray; break; + case TokenKind.AnyKeyword: kind = ShaderPropertyKind.TextureAny; break; + case TokenKind.RangeKeyword: + kind = ShaderPropertyKind.Range; + Eat(TokenKind.OpenParenToken); + float min = ParseNumericLiteral(); + Eat(TokenKind.CommaToken); + float max = ParseNumericLiteral(); + Eat(TokenKind.CloseParenToken); + rangeMinMax = (min, max); + break; + default: + Error("a valid type", typeToken); + break; + } + + Eat(TokenKind.CloseParenToken); + + Eat(TokenKind.EqualsToken); + + var valueNodeFirstTok = Peek(); + ShaderPropertyValueNode valueNode = null; + switch (kind) + { + case ShaderPropertyKind.Color: + case ShaderPropertyKind.Vector: + Eat(TokenKind.OpenParenToken); + float x = ParseNumericLiteral(); + Eat(TokenKind.CommaToken); + float y = ParseNumericLiteral(); + Eat(TokenKind.CommaToken); + float z = ParseNumericLiteral(); + float w = 1; + bool hasLastChannel = false; + if (Match(TokenKind.CommaToken)) + { + Eat(TokenKind.CommaToken); + w = ParseNumericLiteral(); + hasLastChannel = true; + } + var closeTok = Eat(TokenKind.CloseParenToken); + if (kind == ShaderPropertyKind.Color) + valueNode = new ShaderPropertyValueColorNode(Range(valueNodeFirstTok, closeTok)) { HasAlphaChannel = hasLastChannel, Color = (x, y, z, w) }; + else + valueNode = new ShaderPropertyValueVectorNode(Range(valueNodeFirstTok, closeTok)) { HasWChannel = hasLastChannel, Vector = (x, y, z, w) }; + break; + + case ShaderPropertyKind.TextureCube: + case ShaderPropertyKind.Texture2D: + case ShaderPropertyKind.Texture3D: + case ShaderPropertyKind.TextureAny: + case ShaderPropertyKind.TextureCubeArray: + case ShaderPropertyKind.Texture2DArray: + case ShaderPropertyKind.Texture3DArray: + string texName = ParseStringLiteral(); + valueNode = new ShaderPropertyValueTextureNode(Range(valueNodeFirstTok, Previous())) { Kind = ShaderLabSyntaxFacts.ShaderPropertyTypeToTextureType(kind), TextureName = texName }; + break; + + case ShaderPropertyKind.Integer: + case ShaderPropertyKind.Int: + int intVal = ParseIntegerLiteral(); + valueNode = new ShaderPropertyValueIntegerNode(Range(valueNodeFirstTok, Previous())) { Number = intVal }; + break; + + case ShaderPropertyKind.Float: + case ShaderPropertyKind.Range: + float floatVal = ParseNumericLiteral(); + valueNode = new ShaderPropertyValueFloatNode(Range(valueNodeFirstTok, Previous())) { Number = floatVal }; + break; + + default: + break; + } + + if (Match(TokenKind.OpenBraceToken)) + { + Eat(TokenKind.OpenBraceToken); + while (Peek().Kind != TokenKind.CloseBraceToken) + Advance(); + Eat(TokenKind.CloseBraceToken); + } + + return new ShaderPropertyNode(Range(firstTok, Previous())) + { + Attributes = attributes, + Uniform = uniform, + Name = name, + Kind = kind, + RangeMinMax = rangeMinMax, + Value = valueNode, + }; + } + + public SubShaderNode ParseSubShader() + { + PushIncludes(); + + var keywordTok = Eat(TokenKind.SubShaderKeyword); + Eat(TokenKind.OpenBraceToken); + + List passes = new List(); + List commands = new List(); + List programBlocks = new List(); + List includeBlocks = new List(); + + while (LoopShouldContinue()) + { + SLToken next = Peek(); + if (next.Kind == TokenKind.CloseBraceToken) + break; + + switch (next.Kind) + { + case TokenKind.PassKeyword: passes.Add(ParseCodePass()); break; + case TokenKind.GrabPassKeyword: passes.Add(ParseGrabPass()); break; + case TokenKind.UsePassKeyword: passes.Add(ParseUsePass()); break; + case TokenKind.ProgramBlock: programBlocks.Add(ParseOrSkipEmbeddedHLSL()); break; + default: + ParseCommandsAndIncludeBlocksIfPresent(commands, includeBlocks); + SetIncludes(includeBlocks); + break; + } + } + + ParseCommandsAndIncludeBlocksIfPresent(commands, includeBlocks); + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + PopIncludes(); + + return new SubShaderNode(Range(keywordTok, closeTok)) + { + Passes = passes, + Commands = commands, + IncludeBlocks = includeBlocks, + ProgramBlocks = programBlocks, + }; + } + + public ShaderCodePassNode ParseCodePass() + { + PushIncludes(); + + var keywordTok = Eat(TokenKind.PassKeyword); + Eat(TokenKind.OpenBraceToken); + + List commands = new List(); + List programBlocks = new List(); + List includeBlocks = new List(); + + ParseCommandsAndIncludeBlocksIfPresent(commands, includeBlocks); + SetIncludes(includeBlocks); + + while (Match(TokenKind.ProgramBlock)) + { + programBlocks.Add(ParseOrSkipEmbeddedHLSL()); + ParseCommandsAndIncludeBlocksIfPresent(commands, includeBlocks); + SetIncludes(includeBlocks); + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + PopIncludes(); + + return new ShaderCodePassNode(Range(keywordTok, closeTok)) + { + ProgramBlocks = programBlocks, + Commands = commands, + IncludeBlocks = includeBlocks + }; + } + + public ShaderGrabPassNode ParseGrabPass() + { + var keywordTok = Eat(TokenKind.GrabPassKeyword); + Eat(TokenKind.OpenBraceToken); + + List commands = new List(); + List includeBlocks = new List(); + + ParseCommandsAndIncludeBlocksIfPresent(commands, includeBlocks); + string name = null; + if (Peek().Kind != TokenKind.CloseBraceToken) + { + name = ParseStringLiteral(); + + ParseCommandsAndIncludeBlocksIfPresent(commands, includeBlocks); + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new ShaderGrabPassNode(Range(keywordTok, closeTok)) + { + TextureName = name, + Commands = commands, + IncludeBlocks = includeBlocks, + }; + } + + public ShaderUsePassNode ParseUsePass() + { + var keywordTok = Eat(TokenKind.UsePassKeyword); + string name = ParseStringLiteral(); + return new ShaderUsePassNode(Range(keywordTok, Previous())) + { + PassName = name + }; + } + + public void ParseCommandsAndIncludeBlocksIfPresent(List outCommands, List outIncludeBlocks) + { + while (true) + { + int lastPosition = position; + + ParseCommandsIfPresent(outCommands); + ParseIncludeBlocksIfPresent(outIncludeBlocks); + + if (lastPosition == position) + break; + } + } + + public bool TryParseCommand(out ShaderLabCommandNode result) + { + var next = Peek(); + switch (next.Kind) + { + case TokenKind.LightingKeyword: result = ParseBasicToggleCommand(next.Kind, (a, b) => new ShaderLabCommandLightingNode(Range(a, b))); return true; + case TokenKind.SeparateSpecularKeyword: result = ParseBasicToggleCommand(next.Kind, (a, b) => new ShaderLabCommandSeparateSpecularNode(Range(a, b))); return true; + case TokenKind.ZWriteKeyword: result = ParseBasicToggleCommand(next.Kind, (a, b) => new ShaderLabCommandZWriteNode(Range(a, b))); return true; + case TokenKind.AlphaToMaskKeyword: result = ParseBasicToggleCommand(next.Kind, (a, b) => new ShaderLabCommandAlphaToMaskNode(Range(a, b))); return true; + case TokenKind.ZClipKeyword: result = ParseBasicToggleCommand(next.Kind, (a, b) => new ShaderLabCommandZClipNode(Range(a, b))); return true; + case TokenKind.ConservativeKeyword: result = ParseBasicToggleCommand(next.Kind, (a, b) => new ShaderLabCommandConservativeNode(Range(a, b))); return true; + case TokenKind.TagsKeyword: result = ParseTagsCommand(); return true; + case TokenKind.LodKeyword: result = ParseLodCommand(); return true; + case TokenKind.CullKeyword: result = ParseCullCommand(); return true; + case TokenKind.ZTestKeyword: result = ParseZTestCommand(); return true; + case TokenKind.BlendKeyword: result = ParseBlendCommand(); return true; + case TokenKind.OffsetKeyword: result = ParseOffsetCommand(); return true; + case TokenKind.ColorMaskKeyword: result = ParseColorMaskCommand(); return true; + case TokenKind.AlphaTestKeyword: result = ParseAlphaTestCommand(); return true; + case TokenKind.FogKeyword: result = ParseFogCommand(); return true; + case TokenKind.NameKeyword: result = ParseNameCommand(); return true; + case TokenKind.BindChannelsKeyword: result = ParseBindChannelsCommand(); return true; + case TokenKind.ColorKeyword: result = ParseColorCommand(); return true; + case TokenKind.BlendOpKeyword: result = ParseBlendOpCommand(); return true; + case TokenKind.MaterialKeyword: result = ParseMaterialCommand(); return true; + case TokenKind.SetTextureKeyword: result = ParseSetTextureCommand(); return true; + case TokenKind.ColorMaterialKeyword: result = ParseColorMaterialNode(); return true; + case TokenKind.StencilKeyword: result = ParseStencilNode(); return true; + default: result = null; return false; + } + } + + public void ParseCommandsIfPresent(List outCommands) + { + bool run = true; + while (run) + { + if (TryParseCommand(out var command)) + { + outCommands.Add(command); + } + else + { + run = false; + } + + // If we encountered an error, try to find the next command. + RecoverTo(kind => commandSyncTokens.Contains(kind), false); + } + } + + public T ParseBasicToggleCommand(TokenKind keyword, Func ctor) + where T : ShaderLabBasicToggleCommandNode + { + var firstTok = Eat(keyword); + var prop = ParsePropertyReferenceOr(() => + { + var kind = Eat(TokenKind.OnKeyword, TokenKind.OffKeyword, TokenKind.TrueKeyword, TokenKind.FalseKeyword).Kind; + return kind == TokenKind.OnKeyword || kind == TokenKind.TrueKeyword; + }); + var lastTok = Previous(); + var result = ctor(firstTok, lastTok); + result.Enabled = prop; + return result; + } + + public ShaderLabCommandTagsNode ParseTagsCommand() + { + var keywordTok = Eat(TokenKind.TagsKeyword); + Eat(TokenKind.OpenBraceToken); + + Dictionary tags = new Dictionary(); + while (Peek().Kind != TokenKind.CloseBraceToken) + { + var tagKeySpan = Peek().Span; + string key = ParseStringLiteral(); + Eat(TokenKind.EqualsToken); + string val = ParseStringLiteral(); + + if (tags.ContainsKey(key)) + { + Error(DiagnosticFlags.Warning, $"Duplicate definition of tag '{key}' found.", tagKeySpan); + } + tags[key] = val; + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new ShaderLabCommandTagsNode(Range(keywordTok, closeTok)) + { + Tags = tags + }; + } + + public ShaderLabCommandLodNode ParseLodCommand() + { + var keywordTok = Eat(TokenKind.LodKeyword); + int level = ParseIntegerLiteral(); + return new ShaderLabCommandLodNode(Range(keywordTok, Previous())) + { + LodLevel = level, + }; + } + + public PropertyReferenceOr ParsePropertyReferenceOr(Func otherParser) + { + if (Match(TokenKind.BracketedStringLiteralToken)) + { + return new PropertyReferenceOr { Property = ParseBracketedStringLiteral() }; + } + else + { + return new PropertyReferenceOr { Value = otherParser() }; + } + } + + public ShaderLabCommandCullNode ParseCullCommand() + { + var keywordTok = Eat(TokenKind.CullKeyword); + var prop = ParsePropertyReferenceOr(() => + { + var kind = Eat(TokenKind.OffKeyword, TokenKind.FrontKeyword, TokenKind.BackKeyword, TokenKind.FalseKeyword).Kind; + CullMode mode = default; + if (kind == TokenKind.OffKeyword || kind == TokenKind.FalseKeyword) + mode = CullMode.Off; + else if (kind == TokenKind.FrontKeyword) + mode = CullMode.Front; + else if (kind == TokenKind.BackKeyword) + mode = CullMode.Back; + return mode; + }); + return new ShaderLabCommandCullNode(Range(keywordTok, Previous())) { Mode = prop }; + } + + public ShaderLabCommandZTestNode ParseZTestCommand() + { + var keywordTok = Eat(TokenKind.ZTestKeyword); + var prop = ParsePropertyReferenceOr(() => ParseEnum("a valid comparison operator")); + return new ShaderLabCommandZTestNode(Range(keywordTok, Previous())) { Mode = prop }; + } + + private static readonly Dictionary blendFactors = new Dictionary() + { + { TokenKind.OneKeyword, BlendFactor.One }, + { TokenKind.ZeroKeyword, BlendFactor.Zero }, + { TokenKind.SrcColorKeyword, BlendFactor.SrcColor }, + { TokenKind.SrcAlphaKeyword, BlendFactor.SrcAlpha }, + { TokenKind.SrcAlphaSaturateKeyword, BlendFactor.SrcAlphaSaturate }, + { TokenKind.DstColorKeyword, BlendFactor.DstColor }, + { TokenKind.DstAlphaKeyword, BlendFactor.DstAlpha }, + { TokenKind.OneMinusSrcColorKeyword, BlendFactor.OneMinusSrcColor }, + { TokenKind.OneMinusSrcAlphaKeyword, BlendFactor.OneMinusSrcAlpha }, + { TokenKind.OneMinusDstColorKeyword, BlendFactor.OneMinusDstColor }, + { TokenKind.OneMinusDstAlphaKeyword, BlendFactor.OneMinusDstAlpha } + }; + private static readonly TokenKind[] blendFactorsKeys = blendFactors.Keys.ToArray(); + + private static U GetValueOrDefault(Dictionary dictionary, T key) + { + if (dictionary.TryGetValue(key, out U result)) + return result; + else + return default; + } + + public ShaderLabCommandBlendNode ParseBlendCommand() + { + var keywordTok = Eat(TokenKind.BlendKeyword); + + int renderTarget = 0; + if (Match(TokenKind.FloatLiteralToken, TokenKind.IntegerLiteralToken)) + { + renderTarget = ParseIntegerLiteral(); + } + + if (Match(TokenKind.OffKeyword, TokenKind.FalseKeyword)) + { + var offTok = Advance(); + return new ShaderLabCommandBlendNode(Range(keywordTok, offTok)) { RenderTarget = renderTarget, Enabled = false }; + } + + var srcRGB = ParsePropertyReferenceOr(() => GetValueOrDefault(blendFactors, Eat(blendFactorsKeys).Kind)); + var dstRGB = ParsePropertyReferenceOr(() => GetValueOrDefault(blendFactors, Eat(blendFactorsKeys).Kind)); + + var srcAlpha = srcRGB; + var dstAlpha = dstRGB; + if (Match(TokenKind.CommaToken)) + { + Eat(TokenKind.CommaToken); + srcAlpha = ParsePropertyReferenceOr(() => GetValueOrDefault(blendFactors, Eat(blendFactorsKeys).Kind)); + dstAlpha = ParsePropertyReferenceOr(() => GetValueOrDefault(blendFactors, Eat(blendFactorsKeys).Kind)); + } + + return new ShaderLabCommandBlendNode(Range(keywordTok, Previous())) + { + RenderTarget = renderTarget, + Enabled = true, + SourceFactorRGB = srcRGB, + DestinationFactorRGB = dstRGB, + SourceFactorAlpha = srcAlpha, + DestinationFactorAlpha = dstAlpha + }; + } + + public ShaderLabCommandOffsetNode ParseOffsetCommand() + { + var keywordTok = Eat(TokenKind.OffsetKeyword); + var factor = ParsePropertyReferenceOr(ParseNumericLiteral); + Eat(TokenKind.CommaToken); + var units = ParsePropertyReferenceOr(ParseNumericLiteral); + return new ShaderLabCommandOffsetNode(Range(keywordTok, Previous())) { Factor = factor, Units = units }; + } + + public ShaderLabCommandColorMaskNode ParseColorMaskCommand() + { + var keywordTok = Eat(TokenKind.ColorMaskKeyword); + var mask = ParsePropertyReferenceOr(() => + { + SLToken next = Peek(); + if (next.Kind == TokenKind.FloatLiteralToken || next.Kind == TokenKind.IntegerLiteralToken) + { + string result = ParseNumericLiteral().ToString(); + if (result != "0") + Error("the numeric literal 0", next); + return result; + } + else + { + string result = ParseIdentifier(); + if (!result.ToLower().All(x => x == 'r' || x == 'g' || x == 'b' || x == 'a')) + Error("a valid mask containing only the letter 'r', 'g', 'b', 'a'", next); + return result; + } + }); + int renderTarget = 0; + if (Match(TokenKind.FloatLiteralToken, TokenKind.IntegerLiteralToken)) + { + renderTarget = ParseIntegerLiteral(); + } + return new ShaderLabCommandColorMaskNode(Range(keywordTok, Previous())) { RenderTarget = renderTarget, Mask = mask }; + } + + public ShaderLabCommandAlphaTestNode ParseAlphaTestCommand() + { + var keywordTok = Eat(TokenKind.AlphaTestKeyword); + var prop = ParsePropertyReferenceOr(() => ParseEnum("a valid comparison operator")); + PropertyReferenceOr? alpha = null; + if (Match(TokenKind.FloatLiteralToken, TokenKind.IntegerLiteralToken, TokenKind.BracketedStringLiteralToken)) + { + alpha = ParsePropertyReferenceOr(ParseNumericLiteral); + } + return new ShaderLabCommandAlphaTestNode(Range(keywordTok, Previous())) { Mode = prop, AlphaValue = alpha }; + } + + public void ParseColor(out (float r, float g, float b, float a) color, out bool hasAlphaChannel) + { + hasAlphaChannel = false; + float r, g, b, a = 1; + Eat(TokenKind.OpenParenToken); + r = ParseNumericLiteral(); + Eat(TokenKind.CommaToken); + g = ParseNumericLiteral(); + Eat(TokenKind.CommaToken); + b = ParseNumericLiteral(); + if (Match(TokenKind.CommaToken)) + { + Eat(TokenKind.CommaToken); + a = ParseNumericLiteral(); + hasAlphaChannel = true; + } + Eat(TokenKind.CloseParenToken); + color = (r, g, b, a); + } + + public ShaderLabCommandFogNode ParseFogCommand() + { + var keywordTok = Eat(TokenKind.FogKeyword); + Eat(TokenKind.OpenBraceToken); + + (float, float, float, float)? color = null; + bool isEnabled; + if (Match(TokenKind.ColorKeyword)) + { + isEnabled = true; + + Eat(TokenKind.ColorKeyword); + ParseColor(out var parsedColor, out _); + color = parsedColor; + } + else + { + Eat(TokenKind.ModeKeyword); + + TokenKind modeKind = Eat(TokenKind.OffKeyword, TokenKind.GlobalKeyword).Kind; + isEnabled = modeKind == TokenKind.GlobalKeyword; + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + return new ShaderLabCommandFogNode(Range(keywordTok, closeTok)) { Enabled = isEnabled, Color = color }; + } + + public ShaderLabCommandNameNode ParseNameCommand() + { + var keywordTok = Eat(TokenKind.NameKeyword); + string name = ParseStringLiteral(); + return new ShaderLabCommandNameNode(Range(keywordTok, Previous())) { Name = name }; + } + + public ShaderLabCommandBindChannelsNode ParseBindChannelsCommand() + { + var keywordTok = Eat(TokenKind.BindChannelsKeyword); + Eat(TokenKind.OpenBraceToken); + + Dictionary bindings = new Dictionary(); + while (Peek().Kind != TokenKind.CloseBraceToken) + { + Eat(TokenKind.BindKeyword); + string source = ParseStringLiteral(); + Eat(TokenKind.CommaToken); + SLToken targetToken = Advance(); + // Handle ShaderLab's ambiguous syntax: Could be a keyword or an identifier here, in the case of color. + string target = targetToken.Kind == TokenKind.ColorKeyword ? "color" : targetToken.Identifier ?? String.Empty; + if (ShaderLabSyntaxFacts.TryParseBindChannelName(source, out BindChannel sourceChannel) && + ShaderLabSyntaxFacts.TryParseBindChannelName(target, out BindChannel targetChannel)) + { + bindings[sourceChannel] = targetChannel; + } + else + { + Error(DiagnosticFlags.SemanticError, $"Failed to parse channel binding from '{source}' to '{target}'."); + } + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new ShaderLabCommandBindChannelsNode(Range(keywordTok, closeTok)) { Bindings = bindings }; + } + + public ShaderLabCommandColorNode ParseColorCommand() + { + var keywordTok = Eat(TokenKind.ColorKeyword); + bool hasAlphaChannel = false; + var prop = ParsePropertyReferenceOr(() => + { + ParseColor(out var color, out hasAlphaChannel); + return color; + }); + return new ShaderLabCommandColorNode(Range(keywordTok, Previous())) { Color = prop, HasAlphaChannel = hasAlphaChannel }; + } + + private static readonly Dictionary blendOps = new Dictionary() + { + { TokenKind.AddKeyword, BlendOp.Add }, + { TokenKind.SubKeyword, BlendOp.Sub }, + { TokenKind.RevSubKeyword, BlendOp.RevSub }, + { TokenKind.MinKeyword, BlendOp.Min }, + { TokenKind.MaxKeyword, BlendOp.Max }, + { TokenKind.LogicalClearKeyword, BlendOp.LogicalClear }, + { TokenKind.LogicalSetKeyword, BlendOp.LogicalSet }, + { TokenKind.LogicalCopyKeyword, BlendOp.LogicalCopy }, + { TokenKind.LogicalCopyInvertedKeyword, BlendOp.LogicalCopyInverted }, + { TokenKind.LogicalNoopKeyword, BlendOp.LogicalNoop }, + { TokenKind.LogicalInvertKeyword, BlendOp.LogicalInvert }, + { TokenKind.LogicalAndKeyword, BlendOp.LogicalAnd }, + { TokenKind.LogicalNandKeyword, BlendOp.LogicalNand }, + { TokenKind.LogicalOrKeyword, BlendOp.LogicalOr }, + { TokenKind.LogicalNorKeyword, BlendOp.LogicalNor }, + { TokenKind.LogicalXorKeyword, BlendOp.LogicalXor }, + { TokenKind.LogicalEquivKeyword, BlendOp.LogicalEquiv }, + { TokenKind.LogicalAndReverseKeyword, BlendOp.LogicalAndReverse }, + { TokenKind.LogicalOrReverseKeyword, BlendOp.LogicalOrReverse }, + { TokenKind.LogicalOrInvertedKeyword, BlendOp.LogicalOrInverted }, + { TokenKind.MultiplyKeyword, BlendOp.Multiply }, + { TokenKind.ScreenKeyword, BlendOp.Screen }, + { TokenKind.OverlayKeyword, BlendOp.Overlay }, + { TokenKind.DarkenKeyword, BlendOp.Darken }, + { TokenKind.LightenKeyword, BlendOp.Lighten }, + { TokenKind.ColorDodgeKeyword, BlendOp.ColorDodge }, + { TokenKind.ColorBurnKeyword, BlendOp.ColorBurn }, + { TokenKind.HardLightKeyword, BlendOp.HardLight }, + { TokenKind.SoftLightKeyword, BlendOp.SoftLight }, + { TokenKind.DifferenceKeyword, BlendOp.Difference }, + { TokenKind.ExclusionKeyword, BlendOp.Exclusion }, + { TokenKind.HSLHueKeyword, BlendOp.HSLHue }, + { TokenKind.HSLSaturationKeyword, BlendOp.HSLSaturation }, + { TokenKind.HSLColorKeyword, BlendOp.HSLColor }, + { TokenKind.HSLLuminosityKeyword, BlendOp.HSLLuminosity }, + }; + private static readonly TokenKind[] blendOpsKeys = blendOps.Keys.ToArray(); + public ShaderLabCommandBlendOpNode ParseBlendOpCommand() + { + var keywordTok = Eat(TokenKind.BlendOpKeyword); + var op = ParsePropertyReferenceOr(() => GetValueOrDefault(blendOps, Eat(blendOpsKeys).Kind)); + PropertyReferenceOr? alphaOp = null; + if (Match(TokenKind.CommaToken)) + { + Eat(TokenKind.CommaToken); + alphaOp = ParsePropertyReferenceOr(() => GetValueOrDefault(blendOps, Eat(blendOpsKeys).Kind)); + } + return new ShaderLabCommandBlendOpNode(Range(keywordTok, Previous())) { BlendOp = op, BlendOpAlpha = alphaOp }; + } + + private static readonly Dictionary fixedFunctionsMatProps = new Dictionary() + { + { TokenKind.DiffuseKeyword, FixedFunctionMaterialProperty.Diffuse }, + { TokenKind.SpecularKeyword, FixedFunctionMaterialProperty.Specular }, + { TokenKind.AmbientKeyword, FixedFunctionMaterialProperty.Ambient }, + { TokenKind.EmissionKeyword, FixedFunctionMaterialProperty.Emission }, + { TokenKind.ShininessKeyword, FixedFunctionMaterialProperty.Shininess }, + }; + private static readonly TokenKind[] fixedFunctionsMatPropsKeys = fixedFunctionsMatProps.Keys.ToArray(); + + public ShaderLabCommandMaterialNode ParseMaterialCommand() + { + var keywordTok = Eat(TokenKind.MaterialKeyword); + Eat(TokenKind.OpenBraceToken); + + var props = new Dictionary>(); + while (!Match(TokenKind.CloseBraceToken)) + { + var prop = GetValueOrDefault(fixedFunctionsMatProps, Eat(fixedFunctionsMatPropsKeys).Kind); + var val = ParsePropertyReferenceOr(() => + { + ParseColor(out var color, out _); + return color; + }); + + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new ShaderLabCommandMaterialNode(Range(keywordTok, closeTok)) { Properties = props }; + } + + public ShaderLabCommandSetTextureNode ParseSetTextureCommand() + { + var keywordTok = Eat(TokenKind.SetTextureKeyword); + string name = ParseBracketedStringLiteral(); + Eat(TokenKind.OpenBraceToken); + + List tokens = new List(); + while (!Match(TokenKind.CloseBraceToken)) + { + tokens.Add(Advance()); + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new ShaderLabCommandSetTextureNode(Range(keywordTok, closeTok)) { TextureName = name, Body = tokens }; + } + + public ShaderLabCommandColorMaterialNode ParseColorMaterialNode() + { + var keywordTok = Eat(TokenKind.ColorMaterialKeyword); + var modeTok = Eat(TokenKind.EmissionKeyword, TokenKind.AmbientAndDiffuseKeyword); + bool ambient = modeTok.Kind == TokenKind.AmbientAndDiffuseKeyword; + return new ShaderLabCommandColorMaterialNode(Range(keywordTok, modeTok)) { AmbientAndDiffuse = ambient }; + } + + public ShaderLabCommandStencilNode ParseStencilNode() + { + var keywordTok = Eat(TokenKind.StencilKeyword); + Eat(TokenKind.OpenBraceToken); + + // Set defaults + var @ref = new PropertyReferenceOr { Value = 0 }; + var readMask = new PropertyReferenceOr { Value = 255 }; + var writeMask = new PropertyReferenceOr { Value = 255 }; + var comparisonOperationBack = new PropertyReferenceOr { Value = ComparisonMode.Always }; + var passOperationBack = new PropertyReferenceOr { Value = StencilOp.Keep }; + var failOperationBack = new PropertyReferenceOr { Value = StencilOp.Keep }; + var zFailOperationBack = new PropertyReferenceOr { Value = StencilOp.Keep }; + var comparisonOperationFront = new PropertyReferenceOr { Value = ComparisonMode.Always }; + var passOperationFront = new PropertyReferenceOr { Value = StencilOp.Keep }; + var failOperationFront = new PropertyReferenceOr { Value = StencilOp.Keep }; + var zFailOperationFront = new PropertyReferenceOr { Value = StencilOp.Keep }; + + StencilOp ParseStencilOp() => ParseEnum("a valid stencil operator"); + ComparisonMode ParseComparisonMode() => ParseEnum("a valid stencil comparison operator"); + + while (!Match(TokenKind.CloseBraceToken)) + { + SLToken next = Advance(); + switch (next.Kind) + { + case TokenKind.RefKeyword: @ref = ParsePropertyReferenceOr(ParseByteLiteral); break; + case TokenKind.ReadMaskKeyword: readMask = ParsePropertyReferenceOr(ParseByteLiteral); break; + case TokenKind.WriteMaskKeyword: writeMask = ParsePropertyReferenceOr(ParseByteLiteral); break; + case TokenKind.CompKeyword: comparisonOperationBack = comparisonOperationFront = ParsePropertyReferenceOr(ParseComparisonMode); break; + case TokenKind.PassKeyword: passOperationBack = passOperationFront = ParsePropertyReferenceOr(ParseStencilOp); break; + case TokenKind.FailKeyword: failOperationBack = failOperationFront = ParsePropertyReferenceOr(ParseStencilOp); break; + case TokenKind.ZFailKeyword: zFailOperationBack = zFailOperationFront = ParsePropertyReferenceOr(ParseStencilOp); break; + case TokenKind.CompBackKeyword: comparisonOperationBack = ParsePropertyReferenceOr(ParseComparisonMode); break; + case TokenKind.PassBackKeyword: passOperationBack = ParsePropertyReferenceOr(ParseStencilOp); break; + case TokenKind.FailBackKeyword: failOperationBack = ParsePropertyReferenceOr(ParseStencilOp); break; + case TokenKind.ZFailBackKeyword: zFailOperationBack = ParsePropertyReferenceOr(ParseStencilOp); break; + case TokenKind.CompFrontKeyword: comparisonOperationFront = ParsePropertyReferenceOr(ParseComparisonMode); break; + case TokenKind.PassFrontKeyword: passOperationFront = ParsePropertyReferenceOr(ParseStencilOp); break; + case TokenKind.FailFrontKeyword: failOperationFront = ParsePropertyReferenceOr(ParseStencilOp); break; + case TokenKind.ZFailFrontKeyword: zFailOperationFront = ParsePropertyReferenceOr(ParseStencilOp); break; + + default: + Error("a valid stencil operation", next); + break; + } + } + + var closeTok = Eat(TokenKind.CloseBraceToken); + RecoverTo(TokenKind.CloseBraceToken); + + return new ShaderLabCommandStencilNode(Range(keywordTok, closeTok)) + { + Ref = @ref, + ReadMask = readMask, + WriteMask = writeMask, + ComparisonOperationBack = comparisonOperationBack, + PassOperationBack = passOperationBack, + FailOperationBack = failOperationBack, + ZFailOperationBack = zFailOperationBack, + ComparisonOperationFront = comparisonOperationFront, + PassOperationFront = passOperationFront, + FailOperationFront = failOperationFront, + ZFailOperationFront = zFailOperationFront, + }; + } + } +} + + +// ShaderLab/ShaderLabSyntaxElements.cs +namespace UnityShaderParser.ShaderLab +{ + using SLToken = Token; + + #region Tokens + public enum TokenKind + { + InvalidToken, + + OpenParenToken, + CloseParenToken, + OpenBracketToken, + CloseBracketToken, + OpenBraceToken, + CloseBraceToken, + + SemiToken, + CommaToken, + + LessThanToken, + LessThanEqualsToken, + GreaterThanToken, + GreaterThanEqualsToken, + LessThanLessThanToken, + GreaterThanGreaterThanToken, + PlusToken, + PlusPlusToken, + MinusToken, + MinusMinusToken, + AsteriskToken, + SlashToken, + PercentToken, + AmpersandToken, + BarToken, + AmpersandAmpersandToken, + BarBarToken, + CaretToken, + NotToken, + TildeToken, + QuestionToken, + ColonToken, + ColonColonToken, + + EqualsToken, + AsteriskEqualsToken, + SlashEqualsToken, + PercentEqualsToken, + PlusEqualsToken, + MinusEqualsToken, + LessThanLessThanEqualsToken, + GreaterThanGreaterThanEqualsToken, + AmpersandEqualsToken, + CaretEqualsToken, + BarEqualsToken, + + EqualsEqualsToken, + ExclamationEqualsToken, + DotToken, + + IdentifierToken, + IntegerLiteralToken, + FloatLiteralToken, + StringLiteralToken, + BracketedStringLiteralToken, + + ShaderKeyword, + PropertiesKeyword, + RangeKeyword, + FloatKeyword, + IntKeyword, + IntegerKeyword, + ColorKeyword, + VectorKeyword, + _2DKeyword, + _3DKeyword, + CubeKeyword, + _2DArrayKeyword, + _3DArrayKeyword, + CubeArrayKeyword, + AnyKeyword, + RectKeyword, + CategoryKeyword, + SubShaderKeyword, + TagsKeyword, + PassKeyword, + CgProgramKeyword, + CgIncludeKeyword, + EndCgKeyword, + HlslProgramKeyword, + HlslIncludeKeyword, + EndHlslKeyword, + GlslProgramKeyword, + GlslIncludeKeyword, + EndGlslKeyword, + FallbackKeyword, + CustomEditorKeyword, + CullKeyword, + ZWriteKeyword, + ZTestKeyword, + OffsetKeyword, + BlendKeyword, + BlendOpKeyword, + ColorMaskKeyword, + AlphaToMaskKeyword, + ZClipKeyword, + ConservativeKeyword, + LodKeyword, + NameKeyword, + LightingKeyword, + StencilKeyword, + RefKeyword, + ReadMaskKeyword, + WriteMaskKeyword, + CompKeyword, + CompBackKeyword, + CompFrontKeyword, + FailKeyword, + ZFailKeyword, + FailBackKeyword, + FailFrontKeyword, + ZFailBackKeyword, + ZFailFrontKeyword, + PassFrontKeyword, + PassBackKeyword, + UsePassKeyword, + GrabPassKeyword, + DependencyKeyword, + MaterialKeyword, + DiffuseKeyword, + AmbientKeyword, + ShininessKeyword, + SpecularKeyword, + EmissionKeyword, + AmbientAndDiffuseKeyword, + FogKeyword, + ModeKeyword, + DensityKeyword, + SeparateSpecularKeyword, + SetTextureKeyword, + CombineKeyword, + AlphaKeyword, + LerpKeyword, + DoubleKeyword, + QuadKeyword, + ConstantColorKeyword, + MatrixKeyword, + AlphaTestKeyword, + ColorMaterialKeyword, + BindChannelsKeyword, + BindKeyword, + + TrueKeyword, + FalseKeyword, + OffKeyword, + OnKeyword, + FrontKeyword, + BackKeyword, + OneKeyword, + ZeroKeyword, + SrcColorKeyword, + SrcAlphaKeyword, + SrcAlphaSaturateKeyword, + DstColorKeyword, + DstAlphaKeyword, + OneMinusSrcColorKeyword, + OneMinusSrcAlphaKeyword, + OneMinusDstColorKeyword, + OneMinusDstAlphaKeyword, + GlobalKeyword, + AddKeyword, + SubKeyword, + RevSubKeyword, + MinKeyword, + MaxKeyword, + LogicalClearKeyword, + LogicalSetKeyword, + LogicalCopyKeyword, + LogicalCopyInvertedKeyword, + LogicalNoopKeyword, + LogicalInvertKeyword, + LogicalAndKeyword, + LogicalNandKeyword, + LogicalOrKeyword, + LogicalNorKeyword, + LogicalXorKeyword, + LogicalEquivKeyword, + LogicalAndReverseKeyword, + LogicalOrReverseKeyword, + LogicalOrInvertedKeyword, + MultiplyKeyword, + ScreenKeyword, + OverlayKeyword, + DarkenKeyword, + LightenKeyword, + ColorDodgeKeyword, + ColorBurnKeyword, + HardLightKeyword, + SoftLightKeyword, + DifferenceKeyword, + ExclusionKeyword, + HSLHueKeyword, + HSLSaturationKeyword, + HSLColorKeyword, + HSLLuminosityKeyword, + + IncludeBlock, + ProgramBlock, + } + #endregion + + #region Common types + // Either a reference to a property or some other type + public struct PropertyReferenceOr + { + public TOther Value; + public string Property; + + public bool IsValue => Value != null; + public bool IsPropertyReference => Property != null; + public bool IsValid => IsValue || IsPropertyReference; + + public override string ToString() + { + if (Property != null) return Property; + else if (Value != null) return Value.ToString(); + else return string.Empty; + } + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum ShaderPropertyKind + { + [PrettyName("Any")] None, + [PrettyName("2D")] Texture2D, + [PrettyName("3D")] Texture3D, + [PrettyName("Cube")] TextureCube, + [PrettyName("Any")] TextureAny, + [PrettyName("2DArray")] Texture2DArray, + [PrettyName("3DArray")] Texture3DArray, + [PrettyName("CubeArray")] TextureCubeArray, + Float, + Int, + Integer, + Color, + Vector, + Range, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum TextureType + { + [PrettyName("2D")] Texture2D, + [PrettyName("3D")] Texture3D, + [PrettyName("Cube")] TextureCube, + [PrettyName("Any")] TextureAny, + [PrettyName("2DArray")] Texture2DArray, + [PrettyName("3DArray")] Texture3DArray, + [PrettyName("CubeArray")] TextureCubeArray, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum CullMode + { + Off, + Front, + Back, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum ComparisonMode + { + Off, + Never, + Less, + Equal, + LEqual, + Greater, + NotEqual, + GEqual, + Always, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum BlendFactor + { + One, + Zero, + SrcColor, + SrcAlpha, + SrcAlphaSaturate, + DstColor, + DstAlpha, + OneMinusSrcColor, + OneMinusSrcAlpha, + OneMinusDstColor, + OneMinusDstAlpha, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum BindChannel + { + Vertex, + Normal, + Tangent, + TexCoord0, + TexCoord1, + TexCoord2, + TexCoord3, + TexCoord4, + TexCoord5, + TexCoord6, + TexCoord7, + Color, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum BlendOp + { + Add, + Sub, + RevSub, + Min, + Max, + LogicalClear, + LogicalSet, + LogicalCopy, + LogicalCopyInverted, + LogicalNoop, + LogicalInvert, + LogicalAnd, + LogicalNand, + LogicalOr, + LogicalNor, + LogicalXor, + LogicalEquiv, + LogicalAndReverse, + LogicalOrReverse, + LogicalOrInverted, + Multiply, + Screen, + Overlay, + Darken, + Lighten, + ColorDodge, + ColorBurn, + HardLight, + SoftLight, + Difference, + Exclusion, + HSLHue, + HSLSaturation, + HSLColor, + HSLLuminosity, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum FixedFunctionMaterialProperty + { + Diffuse, + Ambient, + Shininess, + Specular, + Emission, + } + + [PrettyEnum(PrettyEnumStyle.PascalCase)] + public enum StencilOp + { + Keep, + Zero, + Replace, + IncrSat, + DecrSat, + Invert, + IncrWrap, + DecrWrap, + } + #endregion + + #region Syntax Tree + // Embedded HLSL + public struct HLSLProgramBlock + { + public string FullCode; + public string CodeWithoutIncludes; + public SourceLocation Location; + public List Pragmas; + public List TopLevelDeclarations; + } + + public struct HLSLIncludeBlock + { + public string Code; + public SourceLocation Location; + } + + public abstract class ShaderLabSyntaxNode : SyntaxNode + { + public abstract void Accept(ShaderLabSyntaxVisitor visitor); + public abstract T Accept(ShaderLabSyntaxVisitor visitor); + + public override SourceSpan Span => span; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private SourceSpan span; + + public override SourceSpan OriginalSpan => originalSpan; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private SourceSpan originalSpan; + + public List Tokens => tokens; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private List tokens; + + public string GetCodeInSourceText(string sourceText) => Span.GetCodeInSourceText(sourceText); + + public ShaderLabSyntaxNode(List tokens) + { + if (tokens.Count > 0) + { + this.span = SourceSpan.Between(tokens.First().Span, tokens.Last().Span); + this.originalSpan = SourceSpan.Between(tokens.First().OriginalSpan, tokens.Last().OriginalSpan); + } + this.tokens = tokens; + } + } + + public class ShaderNode : ShaderLabSyntaxNode + { + public string Name { get; set; } + public List Properties { get; set; } + public List SubShaders { get; set; } + public string Fallback { get; set; } // Optional + public bool FallbackDisabledExplicitly { get; set; } + public string CustomEditor { get; set; } // Optional + public Dictionary Dependencies { get; set; } + public List IncludeBlocks { get; set; } + + protected override IEnumerable GetChildren => MergeChildren(Properties, SubShaders); + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderNode(this); + + public ShaderNode(List tokens) : base(tokens) { } + } + + public class ShaderPropertyNode : ShaderLabSyntaxNode + { + public List Attributes { get; set; } + public string Uniform { get; set; } + public string Name { get; set; } + public ShaderPropertyKind Kind = ShaderPropertyKind.None; + public (float Min, float Max)? RangeMinMax { get; set; } // Optional + public ShaderPropertyValueNode Value { get; set; } + + protected override IEnumerable GetChildren => new[] { Value }; + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyNode(this); + + public ShaderPropertyNode(List tokens) : base(tokens) { } + } + + public abstract class ShaderPropertyValueNode : ShaderLabSyntaxNode + { + protected override IEnumerable GetChildren => Enumerable.Empty(); + public ShaderPropertyValueNode(List tokens) : base(tokens) { } + } + + public class ShaderPropertyValueFloatNode : ShaderPropertyValueNode + { + public float Number { get; set; } = 0; + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueFloatNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueFloatNode(this); + + public ShaderPropertyValueFloatNode(List tokens) : base(tokens) { } + } + + public class ShaderPropertyValueIntegerNode : ShaderPropertyValueNode + { + public int Number { get; set; } = 0; + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueIntegerNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueIntegerNode(this); + + public ShaderPropertyValueIntegerNode(List tokens) : base(tokens) { } + } + + public class ShaderPropertyValueVectorNode : ShaderPropertyValueNode + { + public bool HasWChannel { get; set; } + public (float x, float y, float z, float w) Vector { get; set; } = default; + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueVectorNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueVectorNode(this); + + public ShaderPropertyValueVectorNode(List tokens) : base(tokens) { } + } + + public class ShaderPropertyValueColorNode : ShaderPropertyValueNode + { + public bool HasAlphaChannel { get; set; } + public (float r, float g, float b, float a) Color { get; set; } = default; + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueColorNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueColorNode(this); + + public ShaderPropertyValueColorNode(List tokens) : base(tokens) { } + } + + public class ShaderPropertyValueTextureNode : ShaderPropertyValueNode + { + public TextureType Kind { get; set; } + public string TextureName { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueTextureNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPropertyValueTextureNode(this); + + public ShaderPropertyValueTextureNode(List tokens) : base(tokens) { } + } + + public class SubShaderNode : ShaderLabSyntaxNode + { + public List Commands { get; set; } + public List Passes { get; set; } + public List ProgramBlocks { get; set; } + public List IncludeBlocks { get; set; } + public HLSLProgramBlock? ProgramBlock => ProgramBlocks.Count > 0 ? (HLSLProgramBlock?)ProgramBlocks[0] : null; + + protected override IEnumerable GetChildren => MergeChildren(Passes, Commands); + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitSubShaderNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitSubShaderNode(this); + + public SubShaderNode(List tokens) : base(tokens) { } + } + + public class ShaderPassNode : ShaderLabSyntaxNode + { + protected override IEnumerable GetChildren => Enumerable.Empty(); + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPassNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderPassNode(this); + + public ShaderPassNode(List tokens) : base(tokens) { } + } + + public class ShaderCodePassNode : ShaderPassNode + { + public List Commands { get; set; } + public List ProgramBlocks { get; set; } + public List IncludeBlocks { get; set; } + public HLSLProgramBlock? ProgramBlock => ProgramBlocks.Count > 0 ? (HLSLProgramBlock?)ProgramBlocks[0] : null; + + protected override IEnumerable GetChildren => Commands; + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderCodePassNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderCodePassNode(this); + + public ShaderCodePassNode(List tokens) : base(tokens) { } + } + + public class ShaderGrabPassNode : ShaderPassNode + { + public string TextureName { get; set; } // Optional + public List Commands { get; set; } + public List IncludeBlocks { get; set; } + + public bool IsUnnamed => string.IsNullOrEmpty(TextureName); + protected override IEnumerable GetChildren => Commands; + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderGrabPassNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderGrabPassNode(this); + + public ShaderGrabPassNode(List tokens) : base(tokens) { } + } + + public class ShaderUsePassNode : ShaderPassNode + { + public string PassName { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderUsePassNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderUsePassNode(this); + + public ShaderUsePassNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandNode : ShaderLabSyntaxNode + { + protected override IEnumerable GetChildren => Enumerable.Empty(); + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandNode(this); + + public ShaderLabCommandNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandTagsNode : ShaderLabCommandNode + { + public Dictionary Tags { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandTagsNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandTagsNode(this); + + public ShaderLabCommandTagsNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandLodNode : ShaderLabCommandNode + { + public int LodLevel { get; set; } = 0; + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandLodNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandLodNode(this); + + public ShaderLabCommandLodNode(List tokens) : base(tokens) { } + } + + public class ShaderLabBasicToggleCommandNode : ShaderLabCommandNode + { + public PropertyReferenceOr Enabled { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabBasicToggleCommandNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabBasicToggleCommandNode(this); + + public ShaderLabBasicToggleCommandNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandLightingNode : ShaderLabBasicToggleCommandNode + { + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandLightingNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandLightingNode(this); + + public ShaderLabCommandLightingNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandSeparateSpecularNode : ShaderLabBasicToggleCommandNode + { + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandSeparateSpecularNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandSeparateSpecularNode(this); + + public ShaderLabCommandSeparateSpecularNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandZWriteNode : ShaderLabBasicToggleCommandNode + { + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandZWriteNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandZWriteNode(this); + + public ShaderLabCommandZWriteNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandAlphaToMaskNode : ShaderLabBasicToggleCommandNode + { + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandAlphaToMaskNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandAlphaToMaskNode(this); + + public ShaderLabCommandAlphaToMaskNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandZClipNode : ShaderLabBasicToggleCommandNode + { + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandZClipNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandZClipNode(this); + + public ShaderLabCommandZClipNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandConservativeNode : ShaderLabBasicToggleCommandNode + { + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandConservativeNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandConservativeNode(this); + + public ShaderLabCommandConservativeNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandCullNode : ShaderLabCommandNode + { + public PropertyReferenceOr Mode { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandCullNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandCullNode(this); + + public ShaderLabCommandCullNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandZTestNode : ShaderLabCommandNode + { + public PropertyReferenceOr Mode { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandZTestNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandZTestNode(this); + + public ShaderLabCommandZTestNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandBlendNode : ShaderLabCommandNode + { + public int RenderTarget { get; set; } = 0; + public bool Enabled { get; set; } + public PropertyReferenceOr? SourceFactorRGB { get; set; } + public PropertyReferenceOr? DestinationFactorRGB { get; set; } + public PropertyReferenceOr? SourceFactorAlpha { get; set; } + public PropertyReferenceOr? DestinationFactorAlpha { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandBlendNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandBlendNode(this); + + public ShaderLabCommandBlendNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandOffsetNode : ShaderLabCommandNode + { + public PropertyReferenceOr Factor { get; set; } + public PropertyReferenceOr Units { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandOffsetNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandOffsetNode(this); + + public ShaderLabCommandOffsetNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandColorMaskNode : ShaderLabCommandNode + { + public PropertyReferenceOr Mask { get; set; } + public int RenderTarget { get; set; } = 0; + + public bool IsZeroMask => Mask.Value == "0"; + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandColorMaskNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandColorMaskNode(this); + + public ShaderLabCommandColorMaskNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandAlphaTestNode : ShaderLabCommandNode + { + public PropertyReferenceOr Mode { get; set; } + public PropertyReferenceOr? AlphaValue { get; set; } // Optional + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandAlphaTestNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandAlphaTestNode(this); + + public ShaderLabCommandAlphaTestNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandFogNode : ShaderLabCommandNode + { + public bool Enabled { get; set; } + public (float r, float g, float b, float a)? Color { get; set; } // Optional + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandFogNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandFogNode(this); + + public ShaderLabCommandFogNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandNameNode : ShaderLabCommandNode + { + public string Name { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandNameNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandNameNode(this); + + public ShaderLabCommandNameNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandBindChannelsNode : ShaderLabCommandNode + { + public Dictionary Bindings { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandBindChannelsNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandBindChannelsNode(this); + + public ShaderLabCommandBindChannelsNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandColorNode : ShaderLabCommandNode + { + public bool HasAlphaChannel { get; set; } + public PropertyReferenceOr<(float r, float g, float b, float a)> Color { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandColorNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandColorNode(this); + + public ShaderLabCommandColorNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandBlendOpNode : ShaderLabCommandNode + { + public PropertyReferenceOr BlendOp { get; set; } + public PropertyReferenceOr? BlendOpAlpha { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandBlendOpNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandBlendOpNode(this); + + public ShaderLabCommandBlendOpNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandMaterialNode : ShaderLabCommandNode + { + public Dictionary> Properties { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandMaterialNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandMaterialNode(this); + + public ShaderLabCommandMaterialNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandSetTextureNode : ShaderLabCommandNode + { + // TODO: Not the lazy way + public string TextureName { get; set; } + public List Body { get; set; } + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandSetTextureNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandSetTextureNode(this); + + public ShaderLabCommandSetTextureNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandColorMaterialNode : ShaderLabCommandNode + { + public bool AmbientAndDiffuse { get; set; } + public bool Emission => !AmbientAndDiffuse; + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandColorMaterialNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandColorMaterialNode(this); + + public ShaderLabCommandColorMaterialNode(List tokens) : base(tokens) { } + } + + public class ShaderLabCommandStencilNode : ShaderLabCommandNode + { + public PropertyReferenceOr Ref { get; set; } + public PropertyReferenceOr ReadMask { get; set; } + public PropertyReferenceOr WriteMask { get; set; } + public PropertyReferenceOr ComparisonOperationBack { get; set; } + public PropertyReferenceOr PassOperationBack { get; set; } + public PropertyReferenceOr FailOperationBack { get; set; } + public PropertyReferenceOr ZFailOperationBack { get; set; } + public PropertyReferenceOr ComparisonOperationFront { get; set; } + public PropertyReferenceOr PassOperationFront { get; set; } + public PropertyReferenceOr FailOperationFront { get; set; } + public PropertyReferenceOr ZFailOperationFront { get; set; } + public PropertyReferenceOr ComparisonOperation => ComparisonOperationFront; + public PropertyReferenceOr PassOperation => PassOperationFront; + public PropertyReferenceOr FailOperation => FailOperationFront; + public PropertyReferenceOr ZFailOperation => ZFailOperationFront; + + public override void Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandStencilNode(this); + public override T Accept(ShaderLabSyntaxVisitor visitor) => visitor.VisitShaderLabCommandStencilNode(this); + + public ShaderLabCommandStencilNode(List tokens) : base(tokens) { } + } + #endregion +} + + +// ShaderLab/ShaderLabSyntaxFacts.cs +namespace UnityShaderParser.ShaderLab +{ + public static class ShaderLabSyntaxFacts + { + public static bool TryParseShaderLabKeyword(string keyword, out TokenKind token) + { + token = default; + + switch (keyword.ToLower()) + { + case "shader": token = TokenKind.ShaderKeyword; return true; + case "properties": token = TokenKind.PropertiesKeyword; return true; + case "range": token = TokenKind.RangeKeyword; return true; + case "float": token = TokenKind.FloatKeyword; return true; + case "integer": token = TokenKind.IntegerKeyword; return true; + case "int": token = TokenKind.IntKeyword; return true; + case "color": token = TokenKind.ColorKeyword; return true; + case "vector": token = TokenKind.VectorKeyword; return true; + case "2d": token = TokenKind._2DKeyword; return true; + case "3d": token = TokenKind._3DKeyword; return true; + case "cube": token = TokenKind.CubeKeyword; return true; + case "2darray": token = TokenKind._2DArrayKeyword; return true; + case "3darray": token = TokenKind._3DArrayKeyword; return true; + case "cubearray": token = TokenKind.CubeArrayKeyword; return true; + case "any": token = TokenKind.AnyKeyword; return true; + case "rect": token = TokenKind.RectKeyword; return true; + case "category": token = TokenKind.CategoryKeyword; return true; + case "subshader": token = TokenKind.SubShaderKeyword; return true; + case "tags": token = TokenKind.TagsKeyword; return true; + case "pass": token = TokenKind.PassKeyword; return true; + case "cgprogram": token = TokenKind.CgProgramKeyword; return true; + case "cginclude": token = TokenKind.CgIncludeKeyword; return true; + case "endcg": token = TokenKind.EndCgKeyword; return true; + case "hlslprogram": token = TokenKind.HlslProgramKeyword; return true; + case "hlslinclude": token = TokenKind.HlslIncludeKeyword; return true; + case "endhlsl": token = TokenKind.EndHlslKeyword; return true; + case "glslprogram": token = TokenKind.GlslProgramKeyword; return true; + case "glslinclude": token = TokenKind.GlslIncludeKeyword; return true; + case "endglsl": token = TokenKind.EndGlslKeyword; return true; + case "fallback": token = TokenKind.FallbackKeyword; return true; + case "customeditor": token = TokenKind.CustomEditorKeyword; return true; + case "cull": token = TokenKind.CullKeyword; return true; + case "zwrite": token = TokenKind.ZWriteKeyword; return true; + case "ztest": token = TokenKind.ZTestKeyword; return true; + case "offset": token = TokenKind.OffsetKeyword; return true; + case "blend": token = TokenKind.BlendKeyword; return true; + case "blendop": token = TokenKind.BlendOpKeyword; return true; + case "colormask": token = TokenKind.ColorMaskKeyword; return true; + case "alphatomask": token = TokenKind.AlphaToMaskKeyword; return true; + case "zclip": token = TokenKind.ZClipKeyword; return true; + case "conservative": token = TokenKind.ConservativeKeyword; return true; + case "lod": token = TokenKind.LodKeyword; return true; + case "name": token = TokenKind.NameKeyword; return true; + case "lighting": token = TokenKind.LightingKeyword; return true; + case "stencil": token = TokenKind.StencilKeyword; return true; + case "ref": token = TokenKind.RefKeyword; return true; + case "readmask": token = TokenKind.ReadMaskKeyword; return true; + case "writemask": token = TokenKind.WriteMaskKeyword; return true; + case "comp": token = TokenKind.CompKeyword; return true; + case "compback": token = TokenKind.CompBackKeyword; return true; + case "compfront": token = TokenKind.CompFrontKeyword; return true; + case "fail": token = TokenKind.FailKeyword; return true; + case "zfail": token = TokenKind.ZFailKeyword; return true; + case "failback": token = TokenKind.FailBackKeyword; return true; + case "failfront": token = TokenKind.FailFrontKeyword; return true; + case "zfailback": token = TokenKind.ZFailBackKeyword; return true; + case "zfailfront": token = TokenKind.ZFailFrontKeyword; return true; + case "passfront": token = TokenKind.PassFrontKeyword; return true; + case "passback": token = TokenKind.PassBackKeyword; return true; + case "usepass": token = TokenKind.UsePassKeyword; return true; + case "grabpass": token = TokenKind.GrabPassKeyword; return true; + case "dependency": token = TokenKind.DependencyKeyword; return true; + case "material": token = TokenKind.MaterialKeyword; return true; + case "diffuse": token = TokenKind.DiffuseKeyword; return true; + case "ambient": token = TokenKind.AmbientKeyword; return true; + case "shininess": token = TokenKind.ShininessKeyword; return true; + case "specular": token = TokenKind.SpecularKeyword; return true; + case "emission": token = TokenKind.EmissionKeyword; return true; + case "ambientanddiffuse": token = TokenKind.AmbientAndDiffuseKeyword; return true; + case "fog": token = TokenKind.FogKeyword; return true; + case "mode": token = TokenKind.ModeKeyword; return true; + case "density": token = TokenKind.DensityKeyword; return true; + case "separatespecular": token = TokenKind.SeparateSpecularKeyword; return true; + case "settexture": token = TokenKind.SetTextureKeyword; return true; + case "combine": token = TokenKind.CombineKeyword; return true; + case "alpha": token = TokenKind.AlphaKeyword; return true; + case "lerp": token = TokenKind.LerpKeyword; return true; + case "double": token = TokenKind.DoubleKeyword; return true; + case "quad": token = TokenKind.QuadKeyword; return true; + case "constantcolor": token = TokenKind.ConstantColorKeyword; return true; + case "matrix": token = TokenKind.MatrixKeyword; return true; + case "alphatest": token = TokenKind.AlphaTestKeyword; return true; + case "colormaterial": token = TokenKind.ColorMaterialKeyword; return true; + case "bindchannels": token = TokenKind.BindChannelsKeyword; return true; + case "bind": token = TokenKind.BindKeyword; return true; + case "true": token = TokenKind.TrueKeyword; return true; + case "false": token = TokenKind.FalseKeyword; return true; + case "off": token = TokenKind.OffKeyword; return true; + case "on": token = TokenKind.OnKeyword; return true; + case "front": token = TokenKind.FrontKeyword; return true; + case "back": token = TokenKind.BackKeyword; return true; + case "one": token = TokenKind.OneKeyword; return true; + case "zero": token = TokenKind.ZeroKeyword; return true; + case "srccolor": token = TokenKind.SrcColorKeyword; return true; + case "srcalpha": token = TokenKind.SrcAlphaKeyword; return true; + case "srcalphasaturate": token = TokenKind.SrcAlphaSaturateKeyword; return true; + case "dstcolor": token = TokenKind.DstColorKeyword; return true; + case "dstalpha": token = TokenKind.DstAlphaKeyword; return true; + case "oneminussrccolor": token = TokenKind.OneMinusSrcColorKeyword; return true; + case "oneminussrcalpha": token = TokenKind.OneMinusSrcAlphaKeyword; return true; + case "oneminusdstcolor": token = TokenKind.OneMinusDstColorKeyword; return true; + case "oneminusdstalpha": token = TokenKind.OneMinusDstAlphaKeyword; return true; + case "global": token = TokenKind.GlobalKeyword; return true; + case "add": token = TokenKind.AddKeyword; return true; + case "sub": token = TokenKind.SubKeyword; return true; + case "revsub": token = TokenKind.RevSubKeyword; return true; + case "min": token = TokenKind.MinKeyword; return true; + case "max": token = TokenKind.MaxKeyword; return true; + case "logicalclear": token = TokenKind.LogicalClearKeyword; return true; + case "logicalset": token = TokenKind.LogicalSetKeyword; return true; + case "logicalcopy": token = TokenKind.LogicalCopyKeyword; return true; + case "logicalcopyinverted": token = TokenKind.LogicalCopyInvertedKeyword; return true; + case "logicalnoop": token = TokenKind.LogicalNoopKeyword; return true; + case "logicalinvert": token = TokenKind.LogicalInvertKeyword; return true; + case "logicaland": token = TokenKind.LogicalAndKeyword; return true; + case "logicalnand": token = TokenKind.LogicalNandKeyword; return true; + case "logicalor": token = TokenKind.LogicalOrKeyword; return true; + case "logicalnor": token = TokenKind.LogicalNorKeyword; return true; + case "logicalxor": token = TokenKind.LogicalXorKeyword; return true; + case "logicalequiv": token = TokenKind.LogicalEquivKeyword; return true; + case "logicalandreverse": token = TokenKind.LogicalAndReverseKeyword; return true; + case "logicalorreverse": token = TokenKind.LogicalOrReverseKeyword; return true; + case "logicalorinverted": token = TokenKind.LogicalOrInvertedKeyword; return true; + case "multiply": token = TokenKind.MultiplyKeyword; return true; + case "screen": token = TokenKind.ScreenKeyword; return true; + case "overlay": token = TokenKind.OverlayKeyword; return true; + case "darken": token = TokenKind.DarkenKeyword; return true; + case "lighten": token = TokenKind.LightenKeyword; return true; + case "colordodge": token = TokenKind.ColorDodgeKeyword; return true; + case "colorburn": token = TokenKind.ColorBurnKeyword; return true; + case "hardlight": token = TokenKind.HardLightKeyword; return true; + case "softlight": token = TokenKind.SoftLightKeyword; return true; + case "difference": token = TokenKind.DifferenceKeyword; return true; + case "exclusion": token = TokenKind.ExclusionKeyword; return true; + case "hslhue": token = TokenKind.HSLHueKeyword; return true; + case "hslsaturation": token = TokenKind.HSLSaturationKeyword; return true; + case "hslcolor": token = TokenKind.HSLColorKeyword; return true; + case "hslluminosity": token = TokenKind.HSLLuminosityKeyword; return true; + default: return false; + } + } + + public static bool TryParseBindChannelName(string name, out BindChannel bindChannel) + { + bindChannel = default; + + switch (name.ToLower()) + { + case "vertex": bindChannel = BindChannel.Vertex; return true; + case "normal": bindChannel = BindChannel.Normal; return true; + case "tangent": bindChannel = BindChannel.Tangent; return true; + case "texcoord0": case "texcoord": bindChannel = BindChannel.TexCoord0; return true; + case "texcoord1": bindChannel = BindChannel.TexCoord1; return true; + case "texcoord2": bindChannel = BindChannel.TexCoord2; return true; + case "texcoord3": bindChannel = BindChannel.TexCoord3; return true; + case "texcoord4": bindChannel = BindChannel.TexCoord4; return true; + case "texcoord5": bindChannel = BindChannel.TexCoord5; return true; + case "texcoord6": bindChannel = BindChannel.TexCoord6; return true; + case "texcoord7": bindChannel = BindChannel.TexCoord7; return true; + case "color": bindChannel = BindChannel.Color; return true; + default: return false; + } + } + + public static TextureType ShaderPropertyTypeToTextureType(ShaderPropertyKind kind) + { + switch (kind) + { + case ShaderPropertyKind.Texture2D: return TextureType.Texture2D; + case ShaderPropertyKind.Texture3D: return TextureType.Texture3D; + case ShaderPropertyKind.TextureCube: return TextureType.TextureCube; + case ShaderPropertyKind.TextureAny: return TextureType.TextureAny; + case ShaderPropertyKind.Texture2DArray: return TextureType.Texture2DArray; + case ShaderPropertyKind.Texture3DArray: return TextureType.Texture3DArray; + case ShaderPropertyKind.TextureCubeArray: return TextureType.TextureCubeArray; + default: return default; + } + } + } + +} + + +// ShaderLab/ShaderLabSyntaxVisitor.cs +namespace UnityShaderParser.ShaderLab +{ + public abstract class ShaderLabSyntaxVisitor + { + protected void DefaultVisit(ShaderLabSyntaxNode node) + { + foreach (var child in node.Children) + { + child.Accept(this); + } + } + + public void VisitMany(IEnumerable nodes) + { + foreach (ShaderLabSyntaxNode node in nodes) + { + Visit(node); + } + } + + public void VisitMany(IList nodes, Action runBetween) + where T : ShaderLabSyntaxNode + { + for (int i = 0; i < nodes.Count; i++) + { + Visit(nodes[i]); + if (i < nodes.Count - 1) + runBetween(); + } + } + + public virtual void Visit(ShaderLabSyntaxNode node) => node?.Accept(this); + public virtual void VisitShaderNode(ShaderNode node) => DefaultVisit(node); + public virtual void VisitShaderPropertyNode(ShaderPropertyNode node) => DefaultVisit(node); + public virtual void VisitShaderPropertyValueFloatNode(ShaderPropertyValueFloatNode node) => DefaultVisit(node); + public virtual void VisitShaderPropertyValueIntegerNode(ShaderPropertyValueIntegerNode node) => DefaultVisit(node); + public virtual void VisitShaderPropertyValueVectorNode(ShaderPropertyValueVectorNode node) => DefaultVisit(node); + public virtual void VisitShaderPropertyValueColorNode(ShaderPropertyValueColorNode node) => DefaultVisit(node); + public virtual void VisitShaderPropertyValueTextureNode(ShaderPropertyValueTextureNode node) => DefaultVisit(node); + public virtual void VisitSubShaderNode(SubShaderNode node) => DefaultVisit(node); + public virtual void VisitShaderPassNode(ShaderPassNode node) => DefaultVisit(node); + public virtual void VisitShaderCodePassNode(ShaderCodePassNode node) => DefaultVisit(node); + public virtual void VisitShaderGrabPassNode(ShaderGrabPassNode node) => DefaultVisit(node); + public virtual void VisitShaderUsePassNode(ShaderUsePassNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandNode(ShaderLabCommandNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandTagsNode(ShaderLabCommandTagsNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandLodNode(ShaderLabCommandLodNode node) => DefaultVisit(node); + public virtual void VisitShaderLabBasicToggleCommandNode(ShaderLabBasicToggleCommandNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandLightingNode(ShaderLabCommandLightingNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandSeparateSpecularNode(ShaderLabCommandSeparateSpecularNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandZWriteNode(ShaderLabCommandZWriteNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandAlphaToMaskNode(ShaderLabCommandAlphaToMaskNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandZClipNode(ShaderLabCommandZClipNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandConservativeNode(ShaderLabCommandConservativeNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandCullNode(ShaderLabCommandCullNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandZTestNode(ShaderLabCommandZTestNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandBlendNode(ShaderLabCommandBlendNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandOffsetNode(ShaderLabCommandOffsetNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandColorMaskNode(ShaderLabCommandColorMaskNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandAlphaTestNode(ShaderLabCommandAlphaTestNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandFogNode(ShaderLabCommandFogNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandNameNode(ShaderLabCommandNameNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandBindChannelsNode(ShaderLabCommandBindChannelsNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandColorNode(ShaderLabCommandColorNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandBlendOpNode(ShaderLabCommandBlendOpNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandMaterialNode(ShaderLabCommandMaterialNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandSetTextureNode(ShaderLabCommandSetTextureNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandColorMaterialNode(ShaderLabCommandColorMaterialNode node) => DefaultVisit(node); + public virtual void VisitShaderLabCommandStencilNode(ShaderLabCommandStencilNode node) => DefaultVisit(node); + } + + public abstract class ShaderLabSyntaxVisitor + { + protected TReturn DefaultVisit(ShaderLabSyntaxNode node) + { + foreach (var child in node.Children) + { + child.Accept(this); + } + return default; + } + + public List VisitMany(IEnumerable nodes) + { + List result = new List(); + foreach (ShaderLabSyntaxNode node in nodes) + { + result.Add(Visit(node)); + } + return result; + } + + public List VisitMany(IList nodes, Action runBetween) + where T : ShaderLabSyntaxNode + { + List result = new List(); + for (int i = 0; i < nodes.Count; i++) + { + result.Add(Visit(nodes[i])); + if (i < nodes.Count - 1) + runBetween(); + } + return result; + } + + public virtual TReturn Visit(ShaderLabSyntaxNode node) => node == null ? default : node.Accept(this); + public virtual TReturn VisitShaderNode(ShaderNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderPropertyNode(ShaderPropertyNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderPropertyValueFloatNode(ShaderPropertyValueFloatNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderPropertyValueIntegerNode(ShaderPropertyValueIntegerNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderPropertyValueVectorNode(ShaderPropertyValueVectorNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderPropertyValueColorNode(ShaderPropertyValueColorNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderPropertyValueTextureNode(ShaderPropertyValueTextureNode node) => DefaultVisit(node); + public virtual TReturn VisitSubShaderNode(SubShaderNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderPassNode(ShaderPassNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderCodePassNode(ShaderCodePassNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderGrabPassNode(ShaderGrabPassNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderUsePassNode(ShaderUsePassNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandNode(ShaderLabCommandNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandTagsNode(ShaderLabCommandTagsNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandLodNode(ShaderLabCommandLodNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabBasicToggleCommandNode(ShaderLabBasicToggleCommandNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandLightingNode(ShaderLabCommandLightingNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandSeparateSpecularNode(ShaderLabCommandSeparateSpecularNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandZWriteNode(ShaderLabCommandZWriteNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandAlphaToMaskNode(ShaderLabCommandAlphaToMaskNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandZClipNode(ShaderLabCommandZClipNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandConservativeNode(ShaderLabCommandConservativeNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandCullNode(ShaderLabCommandCullNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandZTestNode(ShaderLabCommandZTestNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandBlendNode(ShaderLabCommandBlendNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandOffsetNode(ShaderLabCommandOffsetNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandColorMaskNode(ShaderLabCommandColorMaskNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandAlphaTestNode(ShaderLabCommandAlphaTestNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandFogNode(ShaderLabCommandFogNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandNameNode(ShaderLabCommandNameNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandBindChannelsNode(ShaderLabCommandBindChannelsNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandColorNode(ShaderLabCommandColorNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandBlendOpNode(ShaderLabCommandBlendOpNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandMaterialNode(ShaderLabCommandMaterialNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandSetTextureNode(ShaderLabCommandSetTextureNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandColorMaterialNode(ShaderLabCommandColorMaterialNode node) => DefaultVisit(node); + public virtual TReturn VisitShaderLabCommandStencilNode(ShaderLabCommandStencilNode node) => DefaultVisit(node); + } +} + + +// HLSL/PreProcessor/ConstExpressionEvaluator.cs +namespace UnityShaderParser.HLSL.PreProcessor +{ + using HLSLToken = Token; + + internal class ConstExpressionEvaluator + { + public static bool EvaluateConstExprTokens(List exprTokens, bool throwExceptionOnError, DiagnosticFlags diagnosticFilter, out List diagnostics) + { + HLSLParser localParser = new HLSLParser(exprTokens, throwExceptionOnError, diagnosticFilter); + var expr = localParser.ParseExpression(); + + if (localParser.Diagnostics.Count > 0) + { + diagnostics = new List() { "Failed to evaluated const expression in preprocessor directive." }; + return false; + } + + var self = new ConstExpressionEvaluator(); + bool result = self.EvaluateConstExpr(expr) != 0; + diagnostics = self.diagnostics; + return result; + } + + private List diagnostics = new List(); + + private void Error(string err) + { + diagnostics.Add(err); + } + + private static bool ToBool(long i) => i != 0; + private static long ToNum(bool i) => i ? 1 : 0; + + public long EvaluateConstExpr(ExpressionNode node) + { + switch (node) + { + case LiteralExpressionNode literalExpr: + switch (literalExpr.Kind) + { + case LiteralKind.Integer: + if (literalExpr.Lexeme.StartsWith("0x")) + { + string lexeme = literalExpr.Lexeme.Substring(2); + if (lexeme.EndsWith("u") || lexeme.EndsWith("U")) + lexeme = lexeme.Substring(0, lexeme.Length - 1); + return long.Parse(lexeme, System.Globalization.NumberStyles.HexNumber); + } + return long.Parse(literalExpr.Lexeme); + case LiteralKind.Character: + return char.Parse(literalExpr.Lexeme); + default: + Error($"Literals of type '{literalExpr.Kind}' are not supported in constant expressions."); + return 0; + } + case BinaryExpressionNode binExpr: + long left = EvaluateConstExpr(binExpr.Left); + long right = EvaluateConstExpr(binExpr.Right); + switch (binExpr.Operator) + { + case OperatorKind.LogicalOr: return ToNum(ToBool(left) || ToBool(right)); + case OperatorKind.LogicalAnd: return ToNum(ToBool(left) && ToBool(right)); + case OperatorKind.BitwiseOr: return left | right; + case OperatorKind.BitwiseAnd: return left & right; + case OperatorKind.BitwiseXor: return left ^ right; + case OperatorKind.Equals: return ToNum(left == right); + case OperatorKind.NotEquals: return ToNum(left != right); + case OperatorKind.LessThan: return ToNum(left < right); + case OperatorKind.LessThanOrEquals: return ToNum(left <= right); + case OperatorKind.GreaterThan: return ToNum(left > right); + case OperatorKind.GreaterThanOrEquals: return ToNum(left >= right); + case OperatorKind.ShiftLeft: return left << (int)right; + case OperatorKind.ShiftRight: return left >> (int)right; + case OperatorKind.Plus: return left + right; + case OperatorKind.Minus: return left - right; + case OperatorKind.Mul: return left * right; + case OperatorKind.Div: return left / right; + case OperatorKind.Mod: return left % right; + default: + Error($"Binary operators of type '{binExpr.Operator}' are not supported in constant expressions."); + return 0; + } + case PrefixUnaryExpressionNode unExpr: + long unary = EvaluateConstExpr(unExpr.Expression); + switch (unExpr.Operator) + { + case OperatorKind.Not: return ToNum(!ToBool(unary)); + case OperatorKind.BitFlip: return ~unary; + default: + Error($"Unary operators of type '{unExpr.Operator}' are not supported in constant expressions."); + return 0; + } + default: + Error($"Illegal expression type '{node.GetType().Name}' found in constant expression."); + return 0; + } + } + } +} + + +// HLSL/PreProcessor/HLSLPreProcessor.cs +namespace UnityShaderParser.HLSL.PreProcessor +{ + using HLSLToken = Token; + + public enum PreProcessorMode + { + ExpandAll, + ExpandIncludesOnly, + ExpandAllExceptIncludes, + StripDirectives, + DoNothing, + // TODO: Option to embed directives into tokens + } + + internal struct Macro + { + public bool FunctionLike; + public string Name; + public List Parameters; + public List Tokens; + } + + public class HLSLPreProcessor : BaseParser + { + protected override TokenKind StringLiteralTokenKind => TokenKind.StringLiteralToken; + protected override TokenKind IntegerLiteralTokenKind => TokenKind.IntegerLiteralToken; + protected override TokenKind FloatLiteralTokenKind => TokenKind.FloatLiteralToken; + protected override TokenKind IdentifierTokenKind => TokenKind.IdentifierToken; + protected override TokenKind InvalidTokenKind => TokenKind.InvalidToken; + protected override ParserStage Stage => ParserStage.HLSLPreProcessing; + + protected string basePath; + protected string fileName; + protected IPreProcessorIncludeResolver includeResolver; + + protected int lineOffset = 0; + internal Dictionary defines = new Dictionary(); + + protected List outputTokens = new List(); + protected List outputPragmas = new List(); + + protected SourceSpan AddFileContext(SourceSpan span) + { + string newBasePath = span.BasePath; + string newFilePath = span.FileName; + if (string.IsNullOrEmpty(newBasePath)) newBasePath = basePath; + if (string.IsNullOrEmpty(newFilePath)) newFilePath = fileName; + + return new SourceSpan( + newBasePath, + newFilePath, + new SourceLocation(span.Start.Line + lineOffset, span.Start.Column, span.Start.Index), + new SourceLocation(span.End.Line + lineOffset, span.End.Column, span.End.Index)); + } + + protected void Passthrough() + { + var token = Advance(); + var newToken = new HLSLToken(token.Kind, token.Identifier, AddFileContext(token.Span), token.OriginalSpan, outputTokens.Count); + outputTokens.Add(newToken); + } + + public HLSLPreProcessor(List tokens, bool throwExceptionOnError, DiagnosticFlags diagnosticFilter, string basePath, IPreProcessorIncludeResolver includeResolver, Dictionary defines) + : base(tokens, throwExceptionOnError, diagnosticFilter) + { + this.basePath = basePath; + this.includeResolver = includeResolver; + + foreach (var kvp in defines) + { + var localTokens = HLSLLexer.Lex(kvp.Value, null, null, false, out var localLexerDiags); + if (localLexerDiags.Count > 0) + { + Error(DiagnosticFlags.SyntaxError, $"Invalid define '{kvp.Key}' passed."); + } + string key = kvp.Key; + bool functionLike = false; + var parameters = new List(); + if (kvp.Key.Contains("(")) + { + key = kvp.Key.Substring(0, kvp.Key.IndexOf('(')); + var paramsLexeme = kvp.Key.Substring(kvp.Key.IndexOf('(')); + paramsLexeme = paramsLexeme.TrimStart('(').TrimEnd(')'); + parameters = paramsLexeme.Split(',').Select(x => x.Trim()).ToList(); + functionLike = true; + } + this.defines.Add(key, new Macro + { + FunctionLike = functionLike, + Name = key, + Parameters = parameters, + Tokens = localTokens + }); + } + } + + public static List PreProcess( + List tokens, + bool throwExceptionOnError, + DiagnosticFlags diagnosticFilter, + PreProcessorMode mode, + string basePath, + IPreProcessorIncludeResolver includeResolver, + Dictionary defines, + out List pragmas, + out List diagnostics) + { + HLSLPreProcessor preProcessor = new HLSLPreProcessor(tokens, throwExceptionOnError, diagnosticFilter, basePath, includeResolver, defines); + switch (mode) + { + case PreProcessorMode.ExpandAll: + preProcessor.ExpandDirectives(true); + break; + case PreProcessorMode.ExpandIncludesOnly: + preProcessor.ExpandIncludesOnly(); + break; + case PreProcessorMode.ExpandAllExceptIncludes: + preProcessor.ExpandDirectives(false); + break; + case PreProcessorMode.StripDirectives: + preProcessor.StripDirectives(); + break; + case PreProcessorMode.DoNothing: + preProcessor.outputTokens = tokens; + break; + } + pragmas = preProcessor.outputPragmas; + diagnostics = preProcessor.diagnostics; + return preProcessor.outputTokens; + } + + private new string ParseIdentifier() + { + if (Match(TokenKind.IdentifierToken)) + { + return base.ParseIdentifier(); + } + else + { + var identifierToken = Advance(); + if (HLSLSyntaxFacts.TryConvertKeywordToString(identifierToken.Kind, out string result)) + { + return result; + } + Error("a valid identifier", identifierToken); + return string.Empty; + } + } + + protected struct PreProcessorSnapshot + { + public List Tokens; + public int LineOffset; + public string BasePath; + public int ExitPosition; + public SourceSpan IncludeSpan; + public string FileName; + } + + protected Stack fileSnapshots = new Stack(); + + protected void EnterFile(SourceSpan includeSpan, string newFileName) + { + string source = includeResolver.ReadFile(basePath, newFileName); + var sourceTokens = HLSLLexer.Lex(source, basePath, fileName, throwExceptionOnError, out var diagnosticsToAdd); + diagnostics.AddRange(diagnosticsToAdd); + + fileSnapshots.Push(new PreProcessorSnapshot + { + Tokens = tokens, + LineOffset = lineOffset, + BasePath = basePath, + ExitPosition = position, + IncludeSpan = includeSpan, + FileName = fileName, + }); + + position = 0; + lineOffset = 0; + tokens = sourceTokens; + + string[] pathParts = newFileName.Split('/', '\\'); + if (pathParts.Length > 1) + { + basePath = Path.Combine(basePath, string.Join("/", pathParts.Take(pathParts.Length - 1))); + } + fileName = pathParts.LastOrDefault(); + } + + protected void ExitFile() + { + var snapshot = fileSnapshots.Pop(); + tokens = snapshot.Tokens; + lineOffset = snapshot.LineOffset; + basePath = snapshot.BasePath; + fileName = snapshot.FileName; + position = snapshot.ExitPosition; + } + + private void ExpandInclude(bool expandIncludesOnly) + { + var keywordTok = Eat(TokenKind.IncludeDirectiveKeyword); + var pathToken = Eat(TokenKind.SystemIncludeLiteralToken, TokenKind.StringLiteralToken); + var endTok = Eat(TokenKind.EndDirectiveToken); + var includeSpan = SourceSpan.Between(keywordTok.Span, endTok.Span); + string newFileName = pathToken.Identifier ?? string.Empty; + + EnterFile(includeSpan, newFileName); + + if (expandIncludesOnly) + ExpandIncludesOnly(); + else + ExpandDirectives(); + + ExitFile(); + } + + // Glues tokens together with ## and evaluates defined(x) between each expansion + private void ReplaceBetweenExpansions(List tokens) + { + HLSLToken LocalPeek(int i) => i < tokens.Count ? tokens[i] : InvalidToken; + + List result = new List(); + for (int i = 0; i < tokens.Count; i++) + { + var token = tokens[i]; + if (HLSLSyntaxFacts.TryConvertIdentifierOrKeywordToString(token, out string gluedIdentifier) && LocalPeek(i + 1).Kind == TokenKind.HashHashToken) + { + SourceSpan startSpan = token.Span; + SourceSpan startSpanOriginal = token.OriginalSpan; + SourceSpan endSpan = token.Span; + SourceSpan endSpanOriginal = token.OriginalSpan; + int startPosition = token.Position; + + i++; // identifier + while (LocalPeek(i).Kind == TokenKind.HashHashToken && + HLSLSyntaxFacts.TryConvertIdentifierOrKeywordToString(LocalPeek(i + 1), out string nextIdentifier)) + { + i++; // ## + var nextToken = LocalPeek(i++); // identifier + gluedIdentifier += nextIdentifier; + endSpan = nextToken.Span; + endSpanOriginal = nextToken.OriginalSpan; + } + + var gluedToken = new HLSLToken( + TokenKind.IdentifierToken, + gluedIdentifier, + SourceSpan.Between(startSpan, endSpan), + SourceSpan.Between(startSpanOriginal, endSpanOriginal), + startPosition); + i--; // For loop continues + + result.Add(gluedToken); + } + else if (token.Kind == TokenKind.IdentifierToken && token.Identifier == "defined") + { + SourceSpan startSpan = token.Span; + SourceSpan startSpanOriginal = token.OriginalSpan; + int startPosition = token.Position; + + i++; // defined + bool hasParen = LocalPeek(i).Kind == TokenKind.OpenParenToken; + if (hasParen) i++; + HLSLToken identifier = LocalPeek(i++); + SourceSpan endSpan = identifier.Span; + SourceSpan endSpanOriginal = identifier.OriginalSpan; + if (hasParen) + { + var closeParen = LocalPeek(i++); + endSpan = closeParen.Span; + endSpanOriginal = closeParen.OriginalSpan; + } + + var replacedToken = new HLSLToken( + TokenKind.IntegerLiteralToken, + defines.ContainsKey(HLSLSyntaxFacts.IdentifierOrKeywordToString(identifier)) ? "1" : "0", + SourceSpan.Between(startSpan, endSpan), + SourceSpan.Between(startSpanOriginal, endSpanOriginal), + startPosition); + i--; // For loop continues + + result.Add(replacedToken); + } + else + { + result.Add(token); + } + } + + tokens.Clear(); + tokens.AddRange(result); + } + + private bool TryParseFunctionLikeMacroInvocationParameters(List tokenStream, ref int streamOffset, out List> parameters) + { + int localOffset = streamOffset + 1; + + // Setup local parser functionality (we want to parse on a secondary token stream) + bool LocalIsAtEnd() => localOffset >= tokenStream.Count; + HLSLToken LocalAdvance() => LocalIsAtEnd() ? InvalidToken : tokenStream[localOffset++]; + HLSLToken LocalPeek() => LocalIsAtEnd() ? InvalidToken : tokenStream[localOffset]; + bool LocalMatch(TokenKind kind) => LocalIsAtEnd() ? false : kind == tokenStream[localOffset].Kind; + HLSLToken LocalEat(TokenKind kind) + { + if (!LocalMatch(kind)) + Error(DiagnosticFlags.PreProcessorError, $"Expected token type '{kind}', got '{LocalPeek().Kind}'."); + return LocalAdvance(); + } + + parameters = new List>(); + + // Eat arguments if they are available + if (LocalMatch(TokenKind.OpenParenToken)) + { + // Always eat open paren + LocalEat(TokenKind.OpenParenToken); + + // Check for special case of 0 args + if (LocalMatch(TokenKind.CloseParenToken)) + { + LocalEat(TokenKind.CloseParenToken); + streamOffset = localOffset - 1; + return true; + } + + parameters.Add(new List()); + + // Parse until we have match parens, they might be nested + int numParens = 1; + while (numParens > 0) + { + var next = LocalAdvance(); + switch (next.Kind) + { + case TokenKind.OpenParenToken: + numParens++; + if (numParens > 1) parameters.Last().Add(next); + break; + case TokenKind.CloseParenToken: + if (numParens > 1) parameters.Last().Add(next); + numParens--; + break; + case TokenKind.CommaToken when numParens == 1: + parameters.Add(new List()); + break; + default: + parameters.Last().Add(next); + break; + } + } + streamOffset = localOffset - 1; + return true; + } + // If no args, it must be a regular identifier + return false; + } + + private List ApplyMacros() + { + // First, get the entire macro identifier + List expanded = new List(); + var identifierTok = Eat(TokenKind.IdentifierToken); + expanded.Add(identifierTok); + string identifier = identifierTok.Identifier ?? string.Empty; + + // Check if it is a functionlike macro + bool isFunctionLike = (defines.ContainsKey(identifier) && defines[identifier].FunctionLike) || identifier == "defined"; + if (isFunctionLike) + { + // If so, eat arguments if they are available + if (Match(TokenKind.OpenParenToken)) + { + expanded.Add(Eat(TokenKind.OpenParenToken)); + int numParens = 1; + while (numParens > 0) // Might have nested parens + { + var next = Advance(); + if (next.Kind == TokenKind.OpenParenToken) + numParens++; + else if (next.Kind == TokenKind.CloseParenToken) + numParens--; + expanded.Add(next); + } + } + // Otherwise, it must be a regular identifier + else + { + return expanded; + } + } + + // Optimization: Only do this if necessary + bool hasGlueTokenOrDefined = expanded.Any(x => x.Kind == TokenKind.HashHashToken || x.Identifier == "defined"); + if (hasGlueTokenOrDefined) + { + ReplaceBetweenExpansions(expanded); + } + + HashSet hideSet = new HashSet(); + + // Loop until we can't apply macros anymore + while (true) + { + List next = new List(); + HashSet nextHideSet = new HashSet(); + + // Go over each token and try to apply, adding to the hideset as we go + bool anyThingApplied = false; + for (int i = 0; i < expanded.Count; i++) + { + HLSLToken token = expanded[i]; + + string lexeme = HLSLSyntaxFacts.IdentifierOrKeywordToString(token); + // If the macro matches + if (!hideSet.Contains(lexeme) && defines.TryGetValue(lexeme, out Macro macro)) + { + // Add it to the hideset + if (!nextHideSet.Contains(lexeme)) + { + nextHideSet.Add(lexeme); + } + + anyThingApplied = true; + + // We need to replace tokens. + // First, check if we have a functionlike macro + if (macro.FunctionLike) + { + // Try to parase parameters. If they aren't there, it's just an identifier. + if (!TryParseFunctionLikeMacroInvocationParameters(expanded, ref i, out var parameters)) + next.Add(token); + + if (parameters.Count != macro.Parameters.Count) + Error(DiagnosticFlags.PreProcessorError, $"Incorrect number of arguments passed to macro '{macro.Name}', expected {macro.Parameters.Count}, got {parameters.Count}."); + + // If they are there, substitute them + foreach (var macroToken in macro.Tokens) + { + string macroTokenLexeme = HLSLSyntaxFacts.IdentifierOrKeywordToString(macroToken); + int paramIndex = macro.Parameters.IndexOf(macroTokenLexeme); + if (paramIndex >= 0 && paramIndex < parameters.Count) + { + var parameter = parameters[paramIndex]; + foreach (var parameterToken in parameter) + { + next.Add(new HLSLToken(parameterToken.Kind, parameterToken.Identifier, macroToken.Span, parameterToken.Span, parameterToken.Position)); + } + } + else + { + next.Add(macroToken); + } + } + } + // If not, we can just substitute tokens directly + else + { + next.AddRange(macro.Tokens); + } + } + // Otherwise just pass the token through + else + { + next.Add(token); + } + } + + // Optimization: Check if anything changed - costly to replace + if (anyThingApplied) + { + ReplaceBetweenExpansions(next); + } + + hideSet = nextHideSet; + expanded = next; + + // If nothing was applied, stop + if (!anyThingApplied) + { + break; + } + } + + return expanded; + } + + private static void ShiftPositionsToStartFrom(int start, List tokens) + { + for (int i = 0; i < tokens.Count; i++) + { + var token = tokens[i]; + var newToken = new HLSLToken(token.Kind, token.Identifier, token.Span, token.OriginalSpan, start + i); + tokens[i] = newToken; + } + } + + private List SkipUntilEndOfConditional() + { + List skipped = new List(); + int depth = 0; + while (true) + { + if (!LoopShouldContinue()) + { + Error(DiagnosticFlags.PreProcessorError, "Unterminated conditional directive."); + break; + } + + switch (Peek().Kind) + { + case TokenKind.IfdefDirectiveKeyword: + case TokenKind.IfndefDirectiveKeyword: + case TokenKind.IfDirectiveKeyword: + depth++; + skipped.Add(Advance()); + break; + + case TokenKind.ElseDirectiveKeyword: + case TokenKind.ElifDirectiveKeyword: + if (depth == 0) + { + return skipped; + } + else + { + skipped.Add(Advance()); + } + break; + + case TokenKind.EndifDirectiveKeyword: + if (depth == 0) + { + return skipped; + } + else + { + depth--; + skipped.Add(Advance()); + } + break; + + default: + skipped.Add(Advance()); + break; + } + } + return skipped; + } + + private bool EvaluateConstExpr(List exprTokens) + { + bool result = ConstExpressionEvaluator.EvaluateConstExprTokens(exprTokens, throwExceptionOnError, diagnosticFilter, out var evalDiags); + if (evalDiags.Count > 0) + { + foreach (var diag in evalDiags) + { + Error(DiagnosticFlags.PreProcessorError, diag); + } + return false; + } + return result; + } + + private bool EvaluateCondition(bool continued) + { + HLSLToken conditional = Advance(); + switch (conditional.Kind) + { + case TokenKind.IfdefDirectiveKeyword: + string ifdefName = ParseIdentifier(); + Eat(TokenKind.EndDirectiveToken); + return defines.ContainsKey(ifdefName); + + case TokenKind.IfndefDirectiveKeyword: + string ifndefName = ParseIdentifier(); + Eat(TokenKind.EndDirectiveToken); + return !defines.ContainsKey(ifndefName); + + case TokenKind.ElseDirectiveKeyword: + Eat(TokenKind.EndDirectiveToken); + if (!continued) + { + Error(DiagnosticFlags.PreProcessorError, "Unexpected #else directive - there is no conditional directive preceding it."); + } + return true; + + case TokenKind.IfDirectiveKeyword: + case TokenKind.ElifDirectiveKeyword: + if (!continued && conditional.Kind == TokenKind.ElifDirectiveKeyword) + { + Error(DiagnosticFlags.PreProcessorError, "Unexpected #elif directive - there is no conditional directive preceding it."); + } + // Get the expanded tokens for the condition expression + List expandedConditionTokens = new List(); + while (LoopShouldContinue() && !Match(TokenKind.EndDirectiveToken)) + { + // If we find an identifier, eagerly expand (https://www.math.utah.edu/docs/info/cpp_1.html) + var next = Peek(); + if (next.Kind == TokenKind.IdentifierToken) + { + expandedConditionTokens.AddRange(ApplyMacros()); + } + else + { + expandedConditionTokens.Add(Advance()); + } + } + // The C spec says we should replace any identifiers remaining after expansion with the literal 0 + for (int i = 0; i < expandedConditionTokens.Count; i++) + { + var token = expandedConditionTokens[i]; + if (token.Kind == TokenKind.IdentifierToken) + { + var newToken = new HLSLToken(TokenKind.IntegerLiteralToken, "0", token.Span, token.OriginalSpan, token.Position); + expandedConditionTokens[i] = newToken; + } + } + Eat(TokenKind.EndDirectiveToken); + // Finally evaluate the expression + ShiftPositionsToStartFrom(0, expandedConditionTokens); + return EvaluateConstExpr(expandedConditionTokens); + default: + Error(DiagnosticFlags.PreProcessorError, $"Unexpected token '{conditional.Kind}', expected preprocessor directive."); + return false; + } + } + + private void ExpandConditional() + { + int startPosition = position; + List takenTokens = new List(); + bool branchTaken = false; + + bool condEvaluation = EvaluateCondition(false); + + while (true) + { + if (!LoopShouldContinue()) + { + Error(DiagnosticFlags.PreProcessorError, "Unterminated conditional directive."); + break; + } + + // Eat the body + var skipped = SkipUntilEndOfConditional(); + + // If we haven't already taken a branch, and this one is true, take it + if (!branchTaken && condEvaluation) + { + branchTaken = true; + takenTokens = skipped; + } + + // If we have reached the end, stop + if (Match(TokenKind.EndifDirectiveKeyword)) + { + Eat(TokenKind.EndifDirectiveKeyword); + Eat(TokenKind.EndDirectiveToken); + break; + } + + condEvaluation = EvaluateCondition(true); + } + + // Substitution. First take away the tokens we just evaluated, then insert the substitution, + // and rewind to the start of it + int numTokensInDirective = position - startPosition; + position = startPosition; + tokens.RemoveRange(position, numTokensInDirective); + tokens.InsertRange(position, takenTokens); + } + + private void GlueStringLiteralsPass() + { + position = 0; + lineOffset = 0; + tokens = new List(outputTokens); + outputTokens.Clear(); + while (LoopShouldContinue()) + { + if (Match(TokenKind.StringLiteralToken)) + { + var strTok = Eat(TokenKind.StringLiteralToken); + string glued = strTok.Identifier ?? string.Empty; + SourceSpan spanStart = strTok.Span; + SourceSpan spanStartOriginal = strTok.OriginalSpan; + SourceSpan spanEnd = strTok.Span; + SourceSpan spanEndOriginal = strTok.OriginalSpan; + while (Match(TokenKind.StringLiteralToken)) + { + var nextStrTok = Eat(TokenKind.StringLiteralToken); + glued += nextStrTok.Identifier ?? string.Empty; + spanEnd = nextStrTok.Span; + spanEndOriginal = nextStrTok.OriginalSpan; + } + var gluedSpan = SourceSpan.Between(spanStart, spanEnd); + var gluedSpanOriginal = SourceSpan.Between(spanStartOriginal, spanEndOriginal); + var gluedToken = new HLSLToken(TokenKind.StringLiteralToken, glued, gluedSpan, gluedSpanOriginal, outputTokens.Count); + outputTokens.Add(gluedToken); + } + else + { + Passthrough(); + } + } + } + + public void ExpandDirectives(bool expandIncludes = true) + { + while (LoopShouldContinue()) + { + HLSLToken next = Peek(); + switch (next.Kind) + { + case TokenKind.IncludeDirectiveKeyword: + if (expandIncludes) + { + ExpandInclude(false); + } + else + { + // Skip the include + Eat(TokenKind.IncludeDirectiveKeyword); + var pathToken = Eat(TokenKind.SystemIncludeLiteralToken, TokenKind.StringLiteralToken); + Eat(TokenKind.EndDirectiveToken); + } + break; + + case TokenKind.LineDirectiveKeyword: + int tokenLine = next.Span.Start.Line; // where we actually are + Eat(TokenKind.LineDirectiveKeyword); + int targetLine = ParseIntegerLiteral(); // where we want to be + lineOffset = targetLine - tokenLine - 1; // calculate the offset + if (Match(TokenKind.StringLiteralToken)) + { + Advance(); + } + Eat(TokenKind.EndDirectiveToken); + break; + + case TokenKind.DefineDirectiveKeyword: + Eat(TokenKind.DefineDirectiveKeyword); + string from = ParseIdentifier(); + List args = new List(); + bool functionLike = false; + if (Match(TokenKind.OpenFunctionLikeMacroParenToken)) + { + functionLike = true; + Eat(TokenKind.OpenFunctionLikeMacroParenToken); + args = ParseSeparatedList0(TokenKind.CloseParenToken, TokenKind.CommaToken, ParseIdentifier); + Eat(TokenKind.CloseParenToken); + } + List toks = ParseMany0(() => !Match(TokenKind.EndDirectiveToken), () => Advance()); + Eat(TokenKind.EndDirectiveToken); + defines[from] = new Macro + { + Name = from, + FunctionLike = functionLike, + Parameters = args, + Tokens = toks + }; + break; + + case TokenKind.UndefDirectiveKeyword: + Eat(TokenKind.UndefDirectiveKeyword); + string undef = ParseIdentifier(); + Eat(TokenKind.EndDirectiveToken); + defines.Remove(undef); + break; + + case TokenKind.ErrorDirectiveKeyword: + Eat(TokenKind.ErrorDirectiveKeyword); + var errorToks = ParseMany0(() => !Match(TokenKind.EndDirectiveToken), () => Advance()) + .Select(x => HLSLSyntaxFacts.TokenToString(x)); + Eat(TokenKind.EndDirectiveToken); + string error = string.Join(" ", errorToks); + Error(DiagnosticFlags.PreProcessorError, error); + break; + + case TokenKind.PragmaDirectiveKeyword: + Eat(TokenKind.PragmaDirectiveKeyword); + var pragmaToks = ParseMany0(() => !Match(TokenKind.EndDirectiveToken), () => Advance()) + .Select(x => HLSLSyntaxFacts.TokenToString(x)); + Eat(TokenKind.EndDirectiveToken); + string pragma = string.Join(" ", pragmaToks); + outputPragmas.Add(pragma); + break; + + case TokenKind.IfdefDirectiveKeyword: + case TokenKind.IfndefDirectiveKeyword: + case TokenKind.IfDirectiveKeyword: + case TokenKind.ElifDirectiveKeyword: + case TokenKind.ElseDirectiveKeyword: + case TokenKind.EndifDirectiveKeyword: + ExpandConditional(); + break; + + case TokenKind.IdentifierToken: + var startSpan = Peek().Span; + var expanded = ApplyMacros(); + var endSpan = Previous().Span; + var newSpan = SourceSpan.Between(startSpan, endSpan); + foreach (var token in expanded) + { + var newToken = new HLSLToken(token.Kind, token.Identifier, AddFileContext(newSpan), token.Span, outputTokens.Count); + outputTokens.Add(newToken); + } + break; + + default: + Passthrough(); + break; + } + } + + if (fileSnapshots.Count == 0) + { + // C spec says we need to glue adjacent string literals + GlueStringLiteralsPass(); + } + } + + public void ExpandIncludesOnly() + { + while (LoopShouldContinue()) + { + HLSLToken next = Peek(); + if (next.Kind == TokenKind.IncludeDirectiveKeyword) + { + ExpandInclude(true); + } + else + { + Passthrough(); + } + } + } + + public void StripDirectives(bool expandIncludes = true) + { + while (LoopShouldContinue()) + { + HLSLToken next = Peek(); + switch (next.Kind) + { + case TokenKind.IncludeDirectiveKeyword: + case TokenKind.LineDirectiveKeyword: + case TokenKind.DefineDirectiveKeyword: + case TokenKind.UndefDirectiveKeyword: + case TokenKind.ErrorDirectiveKeyword: + case TokenKind.PragmaDirectiveKeyword: + case TokenKind.IfdefDirectiveKeyword: + case TokenKind.IfndefDirectiveKeyword: + case TokenKind.IfDirectiveKeyword: + case TokenKind.ElifDirectiveKeyword: + case TokenKind.ElseDirectiveKeyword: + case TokenKind.EndifDirectiveKeyword: + while (LoopShouldContinue() && !Match(TokenKind.EndDirectiveToken)) + { + Advance(); + } + if (Match(TokenKind.EndDirectiveToken)) + { + Advance(); + } + break; + + default: + Passthrough(); + break; + } + } + + // C spec says we need to glue adjacent string literals + GlueStringLiteralsPass(); + } + } +} + + +// HLSL/PreProcessor/IPreProcessorIncludeResolver.cs +namespace UnityShaderParser.HLSL.PreProcessor +{ + public interface IPreProcessorIncludeResolver + { + string ReadFile(string basePath, string filePath); + } + + public sealed class DefaultPreProcessorIncludeResolver : IPreProcessorIncludeResolver + { + private List includePaths = new List(); + + public DefaultPreProcessorIncludeResolver() { } + + public DefaultPreProcessorIncludeResolver(List includePaths) + { + foreach (var includePath in includePaths) + { + if (!Directory.Exists(includePath)) + { + this.includePaths.Add(Path.GetFullPath(includePath)); + } + else + { + this.includePaths.Add(includePath); + } + } + } + + public string ReadFile(string basePath, string filePath) + { + // Fix windows-specific include paths + filePath = filePath.Replace("\\", "/"); + + string path = string.IsNullOrEmpty(basePath) + ? filePath + : Path.Combine(basePath, filePath); + + // Try include paths instead + if (!File.Exists(path)) + { + foreach (string includePath in includePaths) + { + string combinedPath = Path.Combine(includePath, filePath); + if (File.Exists(combinedPath)) + return File.ReadAllText(combinedPath); + combinedPath = Path.Combine(basePath, includePath, filePath); + if (File.Exists(combinedPath)) + return File.ReadAllText(combinedPath); + } + } + + // Still not found, so try current directory instead + if (!File.Exists(path)) + { + string lastFolder = Path.GetFileName(basePath); + if (!string.IsNullOrEmpty(lastFolder) && filePath.StartsWith(lastFolder)) + { + path = Path.Combine($"{basePath}/..", filePath); + } + } + + return File.ReadAllText(path); + } + } +} + diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindow.cs.meta b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.cs.meta old mode 100644 new mode 100755 similarity index 83% rename from Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindow.cs.meta rename to Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.cs.meta index e2b96474..b7ffbd33 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindow.cs.meta +++ b/Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d75fcaecb8b9e7f4bbe783e5f4c9838a +guid: d0ae30693941675479b7a0e08ccfc132 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Packages/sh.orels.shaders.generator/Editor/GeneratorProjectSettings.cs b/Packages/sh.orels.shaders.generator/Editor/GeneratorProjectSettings.cs new file mode 100644 index 00000000..c0e1a086 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Editor/GeneratorProjectSettings.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using System.IO; +using NUnit.Framework; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace ORL.ShaderGenerator.Settings +{ + [Serializable] + public struct ModuleRemap + { + public string Source; + public string Destination; + } + + public class GeneratorProjectSettings : ScriptableObject + { + + public List alwaysIncludedBlocks = new() { + "@/Structs/VertexData", + "@/Structs/FragmentData", + "@/Libraries/CoreRPShaderLibrary/BiRPtoURP", + "@/Libraries/Utilities", + "@/Libraries/SamplingLibrary" + }; + + public string defaultLightingModel = "@/LightingModels/PBR"; + + public bool forceDebugBuilds = false; + + public List userModuleRemaps = new(); + + internal const string SETTINGS_FOLDER = "Assets/Settings"; + internal const string SETTINGS_PATH = "Assets/Settings/ORLShaderGeneratorSettings.asset"; + + public static GeneratorProjectSettings GetOrCreateSettings() + { + var settings = AssetDatabase.LoadAssetAtPath(SETTINGS_PATH); + if (settings != null) return settings; + + settings = ScriptableObject.CreateInstance(); + if (!Directory.Exists(SETTINGS_FOLDER)) + { + Directory.CreateDirectory(SETTINGS_FOLDER); + } + AssetDatabase.CreateAsset(settings, SETTINGS_PATH); + AssetDatabase.SaveAssets(); + + return settings; + } + + ///

+ /// This version of Get Settings does not create a physical asset if none exists. + /// This is needed for scripted importers, as creating an asset during import will cause a unity error + /// + /// + public static GeneratorProjectSettings GetSettings() + { + var settings = AssetDatabase.LoadAssetAtPath(SETTINGS_PATH); + if (settings != null) return settings; + + settings = ScriptableObject.CreateInstance(); + return settings; + } + + public static SerializedObject GetSerializedSettings() + { + return new SerializedObject(GetOrCreateSettings()); + } + + public static void ResetSettings() + { + if (!File.Exists(SETTINGS_PATH)) return; + AssetDatabase.DeleteAsset(SETTINGS_PATH); + GetOrCreateSettings(); + } + } + + internal class GeneratorProjectSettingsProvider : SettingsProvider + { + public GeneratorProjectSettingsProvider(string path, SettingsScope scope = SettingsScope.Project) : base(path, scope) { } + + public static bool IsSettingsAvailable() + { + return File.Exists(GeneratorProjectSettings.SETTINGS_PATH); + } + + private SerializedObject _settings; + public override void OnActivate(string searchContext, VisualElement rootElement) + { + _settings = GeneratorProjectSettings.GetSerializedSettings(); + } + + public override void OnGUI(string searchContext) + { + _settings.Update(); + EditorGUILayout.LabelField("Always Included Blocks", EditorStyles.boldLabel); + EditorGUILayout.HelpBox(new GUIContent("These blocks will always be included in every shader")); + EditorGUILayout.PropertyField(_settings.FindProperty("alwaysIncludedBlocks"), new GUIContent("Blocks List")); + + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(_settings.FindProperty("defaultLightingModel")); + EditorGUILayout.HelpBox(new GUIContent("The default lighting model is used when no lighting model is specified in the shader definition")); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("User Module Remaps", EditorStyles.boldLabel); + EditorGUILayout.HelpBox(new GUIContent("This list of remaps allows you to arbitrarily swap out modules by import path. E.g. you can replace all inclusions of a particular module with your custom one")); + + var remapsProp = _settings.FindProperty("userModuleRemaps"); + remapsProp.isExpanded = EditorGUILayout.Foldout(remapsProp.isExpanded, new GUIContent("Remaps List")); + if (remapsProp.isExpanded) + { + using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) + { + for (var i = 0; i < remapsProp.arraySize; i++) + { + using (new EditorGUILayout.HorizontalScope()) + { + var sourceProp = remapsProp.GetArrayElementAtIndex(i).FindPropertyRelative("Source"); + var destinationProp = remapsProp.GetArrayElementAtIndex(i).FindPropertyRelative("Destination"); + EditorGUILayout.PropertyField(sourceProp, GUIContent.none); + EditorGUILayout.LabelField(" -> ", GUILayout.Width(30)); + EditorGUILayout.PropertyField(destinationProp, GUIContent.none); + if (GUILayout.Button("Remove")) + { + remapsProp.DeleteArrayElementAtIndex(i); + break; + } + } + } + if (GUILayout.Button("Add New Remap")) + { + remapsProp.InsertArrayElementAtIndex(remapsProp.arraySize); + } + } + } + + if (GUILayout.Button("Regenerate All Shaders")) + { + AssetDatabase.StartAssetEditing(); + try + { + foreach (var asset in AssetDatabase.FindAssets("t:shader", new string[] { "Assets", "Packages" })) + { + var path = AssetDatabase.GUIDToAssetPath(asset); + var importer = AssetImporter.GetAtPath(path) as ShaderDefinitionImporter; + if (importer != null) + { + AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate); + } + } + } + finally + { + AssetDatabase.StopAssetEditing(); + AssetDatabase.Refresh(); + } + } + EditorGUILayout.HelpBox("This will regenerate all shaders in the project. This is useful if you have made changes to the remaps", MessageType.Info); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(_settings.FindProperty("forceDebugBuilds")); + + _settings.ApplyModifiedPropertiesWithoutUndo(); + + if (GUILayout.Button("Reset Settings")) + { + if (EditorUtility.DisplayDialog("Reset Settings", "Are you sure you want to reset the settings? This will delete all the remaps and any other settings you have changed", "Yes", "No")) + { + GeneratorProjectSettings.ResetSettings(); + _settings = GeneratorProjectSettings.GetSerializedSettings(); + return; + } + } + } + + [SettingsProvider] + public static SettingsProvider CreateGeneratorProjectSettingsProvider() + { + if (IsSettingsAvailable()) + { + var provider = new GeneratorProjectSettingsProvider("Project/orels1/Shader Generator", SettingsScope.Project); + provider.keywords = GetSearchKeywordsFromSerializedObject(GeneratorProjectSettings.GetSerializedSettings()); + return provider; + } + else + { + GeneratorProjectSettings.GetOrCreateSettings(); + } + + return null; + } + + + } +} \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindowData.cs.meta b/Packages/sh.orels.shaders.generator/Editor/GeneratorProjectSettings.cs.meta similarity index 83% rename from Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindowData.cs.meta rename to Packages/sh.orels.shaders.generator/Editor/GeneratorProjectSettings.cs.meta index da310c35..ada6d623 100644 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker/PackageMakerWindowData.cs.meta +++ b/Packages/sh.orels.shaders.generator/Editor/GeneratorProjectSettings.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0adae93375f5d5840a30b6e47f324172 +guid: d7b36c05dee70ed489b7118695f1c05c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Packages/sh.orels.shaders.generator/ORL.ShaderGenerator.asmdef b/Packages/sh.orels.shaders.generator/Editor/ORL.ShaderGenerator.asmdef old mode 100644 new mode 100755 similarity index 82% rename from Packages/sh.orels.shaders.generator/ORL.ShaderGenerator.asmdef rename to Packages/sh.orels.shaders.generator/Editor/ORL.ShaderGenerator.asmdef index 0d6e7535..dd810e9c --- a/Packages/sh.orels.shaders.generator/ORL.ShaderGenerator.asmdef +++ b/Packages/sh.orels.shaders.generator/Editor/ORL.ShaderGenerator.asmdef @@ -1,6 +1,8 @@ { "name": "ORL.ShaderGenerator", + "rootNamespace": "", "references": [ + "GUID:a5857e7d50658ab468a75fe6fb42fda9" ], "includePlatforms": [ "Editor" diff --git a/Packages/sh.orels.shaders.generator/ORL.ShaderGenerator.asmdef.meta b/Packages/sh.orels.shaders.generator/Editor/ORL.ShaderGenerator.asmdef.meta old mode 100644 new mode 100755 similarity index 100% rename from Packages/sh.orels.shaders.generator/ORL.ShaderGenerator.asmdef.meta rename to Packages/sh.orels.shaders.generator/Editor/ORL.ShaderGenerator.asmdef.meta diff --git a/Packages/sh.orels.shaders.generator/Editor/Parser.cs b/Packages/sh.orels.shaders.generator/Editor/Parser.cs old mode 100644 new mode 100755 index 6731db51..ea088ae7 --- a/Packages/sh.orels.shaders.generator/Editor/Parser.cs +++ b/Packages/sh.orels.shaders.generator/Editor/Parser.cs @@ -2,46 +2,176 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using UnityShaderParser.Common; +using UnityShaderParser.HLSL; using Debug = UnityEngine.Debug; namespace ORL.ShaderGenerator { + [Serializable] public class ShaderBlock { - public string Name { get; set; } - public List Params { get; set; } - public List Contents { get; set; } - public bool IsFunction { get; set; } - public string CallSign { get; set; } - public int Order { get; set; } = 0; + public enum BlockType + { + Unknown, + ShaderName, + Template, + TemplateFeatures, + LightingModel, + Properties, + Includes, + ShaderTags, + ShaderModifiers, + PassModifiers, + Variables, + GlobalVariables, + Textures, + ShaderFeatures, + ShaderDefines, + CheckedInclude, + FreeFunctions, + LibraryFunctions, + DataStructs, + VertexBase, + FragmentBase, + ExtraPass, + Custom + } + + public enum ExtraPassType + { + PrePass, + PostPass + } + + public static BlockType GetBlockType(string name) + { + switch (name) + { + case "%ShaderName": + return BlockType.ShaderName; + case "%Template": + return BlockType.Template; + case "%TemplateFeatures": + return BlockType.TemplateFeatures; + case "%LightingModel": + return BlockType.LightingModel; + case "%Properties": + return BlockType.Properties; + case "%Includes": + return BlockType.Includes; + case "%ShaderTags": + return BlockType.ShaderTags; + case "%ShaderModifiers": + return BlockType.ShaderModifiers; + case "%PassModifiers": + case "%AddPassModifiers": + case "%MetaPassModifiers": + case "%ShadowPassModifiers": + case "%OutlinePassModifiers": + return BlockType.PassModifiers; + case "%Variables": + return BlockType.Variables; + case "%GlobalVariables": + return BlockType.GlobalVariables; + case "%Textures": + return BlockType.Textures; + case "%ShaderFeatures": + return BlockType.ShaderFeatures; + case "%ShaderDefines": + return BlockType.ShaderDefines; + case "%CheckedInclude": + return BlockType.CheckedInclude; + case "%FreeFunctions": + return BlockType.FreeFunctions; + case "%LibraryFunctions": + return BlockType.LibraryFunctions; + case "%DataStructs": + return BlockType.DataStructs; + case "%VertexBase": + return BlockType.VertexBase; + case "%FragmentBase": + return BlockType.FragmentBase; + case "%ExtraPass": + return BlockType.ExtraPass; + case "%Custom": + return BlockType.Custom; + default: + return BlockType.Unknown; + } + } + + public struct HookPoint + { + public string Name; + public int Line; + public int Indentation; + } + + public string Name; + public BlockType CoreBlockType; + public List Params; + public List TypedParams; + public List Contents; + public bool IsFunction; + public string CallSign; + public int Order; + public string Path; + public int Line; + public int Indentation; + + public List HookPoints; + + private List _nodes; + public List Nodes + { + get + { + if (_nodes == null) + { + _nodes = ShaderParser.ParseTopLevelDeclarations(string.Join(Environment.NewLine, Contents.Where(l => !l.TrimStart().StartsWith("%"))), ShaderAnalyzers.SLConfig); + } + return _nodes; + } + } + + private FunctionDefinitionNode _functionNode; + + public FunctionDefinitionNode FunctionNode + { + get + { + if (Params.Count == 0) return null; + if (_functionNode == null) + { + foreach (var node in Nodes) + { + if (node is FunctionDefinitionNode fnNode) + { + if (fnNode.Name.GetName() == Params[0].Replace("\"", "")) + { + _functionNode = fnNode; + return _functionNode; + } + } + } + } + return _functionNode; + } + } } public class Parser { - private static HashSet _functionIdentifiers = new HashSet - { - "%PrePassColor", - "%Fragment", - "%FragmentBase", - "%Vertex", - "%VertexBase", - "%TessFactor", - "%Color", - "%Shadow" - }; - - private static Regex _callSignRegex = new Regex(@"(?[\w]+)\((?[\w\,\s]+)\)"); - private int _current; private int _start; private int _total; private int _lineNumber; private string[] _lines; private string _currentLine; - private bool _debugMode; - public List Parse(string[] source) + public List Parse(string[] source, string path = null) { _lines = source; var blocks = new List(); @@ -83,6 +213,7 @@ public List Parse(string[] source) Debug.Log($"Found Block: {blockName}"); } + var blockIndentation = _current; _start = _current + 1; var paramsString = ConsumeUntil(')'); var paramsList = new List(); @@ -98,50 +229,62 @@ public List Parse(string[] source) var contentOffset = BlockHasContent(); var blockContent = new List(); + var blockStartLine = _lineNumber; + var hookPoints = new List(); if (contentOffset > 0) { _lineNumber += contentOffset; + blockStartLine = _lineNumber; if (_debugMode) { Debug.Log($"{blockName} Has block content"); } - var contents = ConsumeBlockContent(); + var contents = ConsumeBlockContent(ref hookPoints); if (contents != null) { blockContent = contents; - + if (_debugMode) { - Debug.Log($"{blockName} block content: {string.Join(",",blockContent)}"); + Debug.Log($"{blockName} block content: {string.Join(",", blockContent)}"); } } } - + var newBlock = new ShaderBlock { Name = blockName, + CoreBlockType = ShaderBlock.GetBlockType(blockName), Params = paramsList, - Contents = blockContent + Contents = blockContent, + Path = path, + Line = blockStartLine, + Indentation = blockIndentation, }; - if (_functionIdentifiers.Contains(blockName)) + + if (hookPoints.Count > 0) { - newBlock.IsFunction = true; - newBlock.Order = newBlock.Params.Count > 1 - ? int.Parse(newBlock.Params[1].Replace("\"", "")) - : 0; - var fnName = newBlock.Params[0].Replace("\"", ""); - var fnLine = newBlock.Contents.Find(s => s.Contains($"void {fnName}")); - var fnStartIndex = fnLine.IndexOf(fnName, StringComparison.InvariantCulture); - if (fnStartIndex > 0) + newBlock.HookPoints = hookPoints; + } + + // ExtraPasses can have a type + if (newBlock.CoreBlockType == ShaderBlock.BlockType.ExtraPass) + { + if (newBlock.Params.Count > 1) { - var callSignLine = fnLine.Substring(fnStartIndex, fnLine.Substring(fnStartIndex).IndexOf(')') + 1) + ";"; - var callSignMatch = _callSignRegex.Match(callSignLine); - var paramsStr = callSignMatch.Groups["params"].Value; - var fnParams = paramsStr.Split(','); - fnParams = fnParams.Select(p => p.Split(' ').Last().Trim()).ToArray(); - newBlock.CallSign = $"{fnName}({string.Join(", ", fnParams)});"; + newBlock.TypedParams = newBlock.Params.ConvertAll(p => (object)p); + newBlock.TypedParams[1] = newBlock.Params[1] == "ExtraPassType.PrePass" ? ShaderBlock.ExtraPassType.PrePass : ShaderBlock.ExtraPassType.PostPass; } } + + newBlock.IsFunction = newBlock.FunctionNode != null; + if (newBlock.IsFunction) + { + newBlock.Order = newBlock.Params.Count > 1 + ? int.Parse(newBlock.Params[1].Replace("\"", "")) + : 0; + newBlock.CallSign = $"{newBlock.FunctionNode.Name.GetName()}({string.Join(", ", newBlock.FunctionNode.Parameters.Select(p => p.Declarator.Name))});"; + } blocks.Add(newBlock); } _current++; @@ -194,11 +337,11 @@ private int BlockHasContent() return 0; } - private List ConsumeBlockContent() + private List ConsumeBlockContent(ref List hookPoints) { var result = new List(); if (_lineNumber + 1 >= _lines.Length) return null; - + var subset = _lines.Skip(_lineNumber).ToList(); var linesSkipped = 0; var nestLevel = 1; @@ -231,6 +374,15 @@ private List ConsumeBlockContent() { offset = line.Length - line.TrimStart().Length; } + if (line.TrimStart().StartsWith("%")) + { + hookPoints.Add(new ShaderBlock.HookPoint + { + Name = line.Trim().Substring(1), + Line = linesSkipped - 1, + Indentation = offset + }); + } result.Add(line.Substring(string.IsNullOrWhiteSpace(line) ? 0 : offset)); } return null; diff --git a/Packages/sh.orels.shaders.generator/Editor/ShaderAnalyzers.cs b/Packages/sh.orels.shaders.generator/Editor/ShaderAnalyzers.cs new file mode 100755 index 00000000..6650fe6e --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Editor/ShaderAnalyzers.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +#if UNITY_2022_3_OR_NEWER +using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif +using UnityShaderParser.Common; +using UnityShaderParser.HLSL; +using UnityShaderParser.HLSL.PreProcessor; +using UnityShaderParser.ShaderLab; + + +namespace ORL.ShaderGenerator +{ + public class ShaderAnalyzers + { + public static ShaderLabParserConfig SLConfig = new ShaderLabParserConfig + { + IncludeResolver = new DefaultPreProcessorIncludeResolver(new List + { + Path.Combine(UnityEditor.EditorApplication.applicationContentsPath, "CGIncludes") + }), + PreProcessorMode = PreProcessorMode.ExpandAllExceptIncludes, + Defines = new Dictionary + { + {"SHADER_API_D3D11", "1"}, + {"TEXTURE2D(textureName)", "Texture2D textureName"}, + {"SAMPLER(samplerName)", "SamplerState samplerName"}, + {"TEXTURE2D_PARAM(textureName, samplerName)", "TEXTURE2D(textureName), SAMPLER(samplerName)"}, + {"TEXTURE2D_ARGS(textureName, samplerName)", "textureName, samplerName"}, + } + }; + + public class TextureObjectCounter : HLSLSyntaxVisitor + { + private readonly string _source; + + public TextureObjectCounter(string source) + { + _source = source; + } + + public int texturesFound; + + private PredefinedObjectType[] _supportedTexTypes = new PredefinedObjectType[] + { + PredefinedObjectType.Texture, + PredefinedObjectType.Texture2D, + PredefinedObjectType.Texture2DArray, + PredefinedObjectType.Texture3D, + PredefinedObjectType.TextureCube, + PredefinedObjectType.TextureCubeArray, + }; + + public override void VisitVariableDeclarationStatementNode(VariableDeclarationStatementNode node) + { +#if UNITY_2021_3_OR_NEWER + if (node.Kind is not PredefinedObjectTypeNode predefinedObjectTypeNode) return; + if (_supportedTexTypes.Contains(predefinedObjectTypeNode.Kind)) + { + texturesFound++; + } +#endif + } + } + + public class SamplerCounter : HLSLSyntaxVisitor + { + private readonly string _source; + + public SamplerCounter(string source) + { + _source = source; + } + + public int samplersFound; + + public override void VisitVariableDeclarationStatementNode(VariableDeclarationStatementNode node) + { +#if UNITY_2021_3_OR_NEWER + if (node.Kind is not PredefinedObjectTypeNode predefinedObjectTypeNode) return; + if (predefinedObjectTypeNode.Kind == PredefinedObjectType.SamplerState) + { + samplersFound++; + } +#endif + } + } + + + public static int CountTextureObjects(List blocks, ref AssetImportContext ctx, ShaderDefinitionImporter importer) + { + var textures = 0; + var samplingLib = File.ReadAllLines("Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/SamplingLibrary.orlsource"); + var samplingLibText = string.Join(Environment.NewLine, samplingLib.Skip(2).Take(samplingLib.Length - 3)); + foreach (var block in blocks) + { + if (block == null) continue; + var blockSource = string.Join("\n", block.Contents.ToArray()); + blockSource = samplingLibText + Environment.NewLine + blockSource; + var parsedBlock = ShaderParser.ParseTopLevelDeclarations(blockSource, SLConfig); + var texVisitor = new TextureObjectCounter(blockSource); + texVisitor.VisitMany(parsedBlock); + textures += texVisitor.texturesFound; + } + + return textures; + } + + public static int CountSamplers(List blocks, ref AssetImportContext ctx, ShaderDefinitionImporter importer) + { + var samplers = 0; + var samplingLib = File.ReadAllLines("Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/SamplingLibrary.orlsource"); + var samplingLibText = string.Join(Environment.NewLine, samplingLib.Skip(2).Take(samplingLib.Length - 3)); + foreach (var block in blocks) + { + if (block == null) continue; + var blockSource = string.Join(Environment.NewLine, block.Contents.ToArray()); + blockSource = samplingLibText + Environment.NewLine + blockSource; + var parsedBlock = ShaderParser.ParseTopLevelDeclarations(blockSource, SLConfig); + var samplerVisitor = new SamplerCounter(blockSource); + samplerVisitor.VisitMany(parsedBlock); + samplers += samplerVisitor.samplersFound; + } + + return samplers; + } + + public static int CountShaderFeatures(string finalShader) + { + ShaderParser.ParseTopLevelDeclarations(finalShader, SLConfig, out _, out var pragmas); + var pragmaSet = new HashSet(); + foreach (var pragma in pragmas) + { + if (!pragma.Contains("shader_feature")) continue; + pragmaSet.Add(pragma); + } + + return pragmaSet.Count; + } + } +} \ No newline at end of file diff --git a/Packages/com.vrchat.core.bootstrap/Editor/Bootstrap.cs.meta b/Packages/sh.orels.shaders.generator/Editor/ShaderAnalyzers.cs.meta old mode 100644 new mode 100755 similarity index 83% rename from Packages/com.vrchat.core.bootstrap/Editor/Bootstrap.cs.meta rename to Packages/sh.orels.shaders.generator/Editor/ShaderAnalyzers.cs.meta index d7ac1ae3..e778e01e --- a/Packages/com.vrchat.core.bootstrap/Editor/Bootstrap.cs.meta +++ b/Packages/sh.orels.shaders.generator/Editor/ShaderAnalyzers.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: eea11c44cabdaaa43ac0a21dbbbd9824 +guid: e4623d54a9149e0448f7db79ccb61f74 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Packages/sh.orels.shaders.generator/Editor/ShaderBlockValidations.cs b/Packages/sh.orels.shaders.generator/Editor/ShaderBlockValidations.cs new file mode 100755 index 00000000..b544c47f --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Editor/ShaderBlockValidations.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.IO; + +#if UNITY_2022_3_OR_NEWER +using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif +using UnityShaderParser.Common; +using UnityShaderParser.HLSL; +using UnityShaderParser.HLSL.PreProcessor; +using UnityShaderParser.ShaderLab; + +namespace ORL.ShaderGenerator +{ + public class ShaderBlockValidations + { + private static ShaderLabParserConfig SLConfig = new ShaderLabParserConfig + { + IncludeResolver = new DefaultPreProcessorIncludeResolver(new List + { + Path.Combine(UnityEditor.EditorApplication.applicationContentsPath, "CGIncludes") + }), + PreProcessorMode = PreProcessorMode.ExpandAll, + Defines = new Dictionary + { + {"SHADER_API_D3D11", "1"} + } + }; + + public struct FunctionParamError + { + public string Name; + public string Type; + public int StartIndex; + public int EndIndex; + public int Line; + public string PrettyCode; + } + + public struct FunctionParamType + { + public Type NodeType; + public ScalarType Kind; + public int Dimension; + public string Name; + } + + public class FunctionBlockValidator : HLSLSyntaxVisitor + { + protected string _mainFnName; + + protected List<(FunctionParamType paramType, string paramName)> _allowedParams; + + protected string AllowedParamsFormatted => string.Join(", ", _allowedParams.ConvertAll(p => $"{p.paramType.Name} {p.paramName}")); + + public Dictionary Errors = new Dictionary(); + + + public List FoundFunctions = new List(); + + public FunctionBlockValidator(string mainFnName) : base() + { + _mainFnName = mainFnName; + } + + public override void VisitFunctionDefinitionNode(FunctionDefinitionNode node) + { + FoundFunctions.Add(node.Name.GetName()); + if (node.Name.GetName() != _mainFnName) return; + foreach (var parameter in node.Parameters) + { + var matchedParams = _allowedParams.FindAll(p => + { + if (parameter.Declarator.Name != p.paramName) return false; + if (parameter.ParamType.GetType() != p.paramType.NodeType) return false; + switch (parameter.ParamType) + { + case NamedTypeNode named: + if (named.Name != p.paramType.Name) return false; + break; + case ScalarTypeNode scalar: + if (scalar.Kind != p.paramType.Kind) return false; + break; + case VectorTypeNode vector: + if (vector.Kind != p.paramType.Kind || vector.Dimension != p.paramType.Dimension) return false; + break; + default: + UnityEngine.Debug.LogWarning($"Unknown parameter type {parameter.ParamType.GetType()} for {parameter.Declarator.Name}"); + return false; + } + return true; + }); + if (matchedParams.Count == 0) + { + var paramType = ""; + switch (parameter.ParamType) + { + case ScalarTypeNode s: + paramType = PrintingUtil.GetEnumName(s.Kind); + break; + case VectorTypeNode v: + paramType = PrintingUtil.GetEnumName(v.Kind) + v.Dimension; + break; + } + + Errors.Add(new FunctionParamError + { + Line = parameter.Span.Start.Line, + StartIndex = parameter.Span.Start.Index, + EndIndex = parameter.Span.End.Index, + Name = parameter.Declarator.Name, + Type = paramType, + PrettyCode = node.GetPrettyPrintedCode() + }, $"Invalid {paramType} {parameter.Declarator.Name} parameter in function {node.Name.GetName()}, only {AllowedParamsFormatted} are supported"); + } + } + } + } + + public class VertexBlockValidator : FunctionBlockValidator + { + public VertexBlockValidator(string mainFnName) : base(mainFnName) + { + _allowedParams = new List<(FunctionParamType paramType, string paramName)> + { + (new FunctionParamType + { + NodeType = typeof(NamedTypeNode), + Name = "VertexData", + }, "v"), + (new FunctionParamType + { + NodeType = typeof(NamedTypeNode), + Name = "FragmentData", + }, "o") + }; + } + } + + public class FragmentBlockValidator : FunctionBlockValidator + { + public FragmentBlockValidator(string mainFnName) : base(mainFnName) + { + _allowedParams = new List<(FunctionParamType paramType, string paramName)> + { + (new FunctionParamType + { + NodeType = typeof(NamedTypeNode), + Name = "MeshData", + }, "d"), + (new FunctionParamType + { + NodeType = typeof(NamedTypeNode), + Name = "SurfaceData", + }, "o"), + (new FunctionParamType + { + NodeType = typeof(NamedTypeNode), + Name = "FragmentData", + }, "i"), + (new FunctionParamType + { + NodeType = typeof(ScalarTypeNode), + Kind = ScalarType.Bool + }, "facing") + }; + } + } + + + public static void ValidateVertexFunction(ShaderBlock block, ref AssetImportContext ctx, ShaderDefinitionImporter importer) + { + if (block == null) return; + var blockSource = string.Join("\n", block.Contents.ToArray()); + var parsedBlock = ShaderParser.ParseTopLevelDeclarations(blockSource, SLConfig); + var strippedName = block.Params[0].Replace("\"", string.Empty); + var vertexValidator = new VertexBlockValidator(strippedName); + vertexValidator.VisitMany(parsedBlock); + if (!vertexValidator.FoundFunctions.Contains(strippedName)) + { + var message = + $"Vertex function set to {strippedName}, but only {string.Join(", ", vertexValidator.FoundFunctions)} found"; + ctx.LogImportError(message, importer); + ctx.LogImportError("Block source was:\n" + blockSource, importer); + importer.Errors.Add(new ShaderDefinitionImporter.ShaderError(block, -1, "somefile", message)); + } + foreach (var error in vertexValidator.Errors) + { + ctx.LogImportError(error.Value, importer); + importer.Errors.Add(new ShaderDefinitionImporter.ShaderError(block, error.Key.Line, "somefile", error.Value, error.Key.PrettyCode, error.Key.StartIndex, error.Key.EndIndex)); + } + } + + public static void ValidateFragmentFunction(ShaderBlock block, ref AssetImportContext ctx, ShaderDefinitionImporter importer) + { + if (block == null) return; + var blockSource = string.Join("\n", block.Contents.ToArray()); + var parsedBlock = ShaderParser.ParseTopLevelDeclarations(blockSource, SLConfig); + var strippedName = block.Params[0].Replace("\"", string.Empty); + var fragmentValidator = new FragmentBlockValidator(strippedName); + fragmentValidator.VisitMany(parsedBlock); + if (!fragmentValidator.FoundFunctions.Contains(strippedName)) + { + var message = + $"Fragment function set to {strippedName}, but only {string.Join(", ", fragmentValidator.FoundFunctions)} found"; + ctx.LogImportError(message, importer); + ctx.LogImportError("Block source was:\n" + blockSource, importer); + importer.Errors.Add(new ShaderDefinitionImporter.ShaderError(block, -1, "somefile", message)); + } + foreach (var error in fragmentValidator.Errors) + { + ctx.LogImportError(error.Value, importer); + importer.Errors.Add(new ShaderDefinitionImporter.ShaderError(block, error.Key.Line, "somefile", error.Value, error.Key.PrettyCode, error.Key.StartIndex, error.Key.EndIndex)); + } + } + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Editor/ShaderBlockValidations.cs.meta b/Packages/sh.orels.shaders.generator/Editor/ShaderBlockValidations.cs.meta new file mode 100755 index 00000000..34b1f7bc --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Editor/ShaderBlockValidations.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a0f5d88c623e4625b5d40ed16f234847 +timeCreated: 1708553506 \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Editor/ShaderDefinitionImporter.cs b/Packages/sh.orels.shaders.generator/Editor/ShaderDefinitionImporter.cs old mode 100644 new mode 100755 index d260a429..0917b5e5 --- a/Packages/sh.orels.shaders.generator/Editor/ShaderDefinitionImporter.cs +++ b/Packages/sh.orels.shaders.generator/Editor/ShaderDefinitionImporter.cs @@ -7,43 +7,98 @@ using UnityEditor; #if UNITY_2022_3_OR_NEWER using UnityEditor.AssetImporters; + #else using UnityEditor.Experimental.AssetImporters; #endif using UnityEngine; +using UnityShaderParser.Common; +using UnityShaderParser.HLSL; +using UnityShaderParser.ShaderLab; +using Debug = UnityEngine.Debug; +using BlockType = ORL.ShaderGenerator.ShaderBlock.BlockType; +using ORL.ShaderGenerator.Settings; namespace ORL.ShaderGenerator { [ScriptedImporter(1, "orlshader")] public class ShaderDefinitionImporter : ScriptedImporter { + #region Serialized Fields + public bool debugBuild; - + private bool DebugBuild => debugBuild || GeneratorProjectSettings.GetSettings().forceDebugBuilds; + // Cached version of the debug flag to avoid constant asset pinging + private bool _isDebugBuild; + + public int samplerCount; + public int textureCount; + public int featureCount; + + public Dictionary FunctionErrors = + new Dictionary(); + + public List Errors = new List(); + + [Serializable] + public struct ShaderError + { + public ShaderBlock Block; + public int Line; + public string File; + public string Message; + public int StartIndex; + public int EndIndex; + public string PrettyCode; + + public ShaderError(ShaderBlock block, int line, string file, string message, string prettyCode = "", int startIndex = -1, int endIndex = -1) + { + Block = block; + Line = line; + File = file; + Message = message; + PrettyCode = prettyCode; + StartIndex = startIndex; + EndIndex = endIndex; + } + } + + public string ShaderName; + public string LightingModel; + public List IncludedModules = new List(); + + #endregion + + #region Internal Block Config + private readonly HashSet _paramsOnlyBlock = new HashSet { "%ShaderName", - "%CustomEditor" + "%CustomEditor", + "%PassName" }; private List _builtInBlocks; - private readonly string[] _dataStructs = { - "@/Structs/VertexData", - "@/Structs/FragmentData" - }; - - private List BuiltInBlocks + private List UserModuleRemaps => GeneratorProjectSettings.GetSettings().userModuleRemaps; + // Cached version of the user module remaps to avoid constant asset pinging + private List _userModuleRemaps; + + // Some blocks need to be included in all shaders + private List AlwaysIncludedBlockSources => GeneratorProjectSettings.GetSettings().alwaysIncludedBlocks; + + private List AlwaysIncludedBlocks { get { if (_builtInBlocks != null) return _builtInBlocks; var blocks = new List(); - foreach (var block in _dataStructs) + foreach (var block in AlwaysIncludedBlockSources) { try { var parser = new Parser(); - var sourceStrings = Utils.GetORLSource(block); + var sourceStrings = Utils.GetORLSource(block, _userModuleRemaps); var blockSource = parser.Parse(sourceStrings); blocks.AddRange(blockSource); } @@ -57,74 +112,24 @@ private List BuiltInBlocks return _builtInBlocks; } } - - private List _builtInFunctions; - - private readonly string[] _functions = { - }; - - private List BuiltInFunctions - { - get - { - if (_builtInFunctions != null) return _builtInFunctions; - var blocks = new List(); - foreach (var function in _functions) - { - var parser = new Parser(); - var sourceStrings = Utils.GetORLSource(function); - var blockSource = parser.Parse(sourceStrings); - blocks.AddRange(blockSource); - } - - _builtInFunctions = blocks; - return _builtInFunctions; - } - } - - private readonly string[] _libraries = { - "@/Libraries/Utilities" - }; - - private const string SamplingLib = "@/Libraries/SamplingLibrary"; - - private List _builtInLibraries; - - private List BuiltInLibraries - { - get - { - if (_builtInLibraries != null) return _builtInLibraries; - var blocks = new List(); - foreach (var library in _libraries) - { - var parser = new Parser(); - var sourceStrings = Utils.GetORLSource(library); - var blockSource = parser.Parse(sourceStrings); - blocks.AddRange(blockSource); - } - // Add sampling lib directly as well, we want it everywhere - { - var parser = new Parser(); - var sourceStrings = Utils.GetORLSource(SamplingLib); - var blockSource = parser.Parse(sourceStrings); - blocks.AddRange(blockSource); - } - - _builtInLibraries = blocks; - return _builtInLibraries; - } - } + private string DefaultLightingModel => GeneratorProjectSettings.GetSettings().defaultLightingModel; - private const string DefaultLightingModel = "@/LightingModels/PBR"; + #endregion // Matches %BlockName without nuking %FunctionName() private readonly Regex _replacerRegex = new Regex(@"(?) private readonly Regex _templateFeatureRegex = new Regex(@"%TemplateFeature\((?""\w+"")\)"); + private struct GeneratedExtraPass + { + public List content; + public int count; + public ShaderBlock.ExtraPassType passType; + } + /// /// Here's the import flow: /// - First we parse the original shader definition @@ -150,72 +155,60 @@ private List BuiltInLibraries /// public override void OnImportAsset(AssetImportContext ctx) { + FunctionErrors.Clear(); + Errors.Clear(); var textContent = File.ReadAllLines(ctx.assetPath); var workingFolder = ctx.assetPath.Substring(0, ctx.assetPath.LastIndexOf("/", StringComparison.InvariantCulture)); + // Cache debug build + _isDebugBuild = DebugBuild; + // Cache remaps + _userModuleRemaps = UserModuleRemaps; + var parser = new Parser(); List blocks = new List(); // We built-in imports first, otherwise the order of imports will be incorrect // Collecting and registering all the dependency objects var depList = new List(); - depList.AddRange(_dataStructs); - depList.AddRange(_functions); - depList.AddRange(_libraries); - depList.Add(SamplingLib); + depList.AddRange(AlwaysIncludedBlockSources); RegisterDependencies(depList, ctx); // Adding all the dependencies to the list of blocks - blocks.AddRange(BuiltInBlocks); - blocks.AddRange(BuiltInFunctions); - blocks.AddRange(BuiltInLibraries); + blocks.AddRange(AlwaysIncludedBlocks); - string shaderName; + // Load all the direct blocks from the source try { blocks.AddRange(parser.Parse(textContent)); - var shaderNameBlockIndex = blocks.FindIndex(b => b.Name == "%ShaderName"); - if (shaderNameBlockIndex == -1) - { - throw new MissingBlockException("%ShaderName", ""); - } - shaderName = blocks[shaderNameBlockIndex].Params[0]; - if (string.IsNullOrWhiteSpace(shaderName?.Replace("\"", ""))) - { - throw new MissingParameterException("name", "%ShaderName", ""); - } - var includesIndex = blocks.FindIndex(b => b.Name == "%Includes"); - // Shaders can have direct includes (not via LightingModel or anything else - // Here we deep-resolve them and inject them back into the blocks in the respective order - if (includesIndex != -1) - { - var resolvedBlocks = new List(); - foreach (var include in blocks[includesIndex].Contents) - { - var stripped = include.Replace("\"", "").Replace(",", ""); - // We inject the already parsed blocks in place of "self" - if (stripped == "self") - { - resolvedBlocks.AddRange(blocks.Where(b => b.Name != "%Includes")); - continue; - } - - var blockParser = new Parser(); - var deepDeps = new List(); - // We recursively collect everything that the lighting model depends on into a flattened list - Utils.RecursivelyCollectDependencies(new [] {stripped}.ToList(), ref deepDeps, workingFolder); - deepDeps.ForEach(dep => ctx.DependsOnSourceAsset(Utils.ResolveORLAsset(dep, dep.StartsWith("@/"), workingFolder))); - var deepBlocks = new List(); - foreach (var deepDep in deepDeps) - { - // since we already have the deps flattened, we can safely strip all the dependencies here - deepBlocks.AddRange(blockParser.Parse(Utils.GetAssetSource(deepDep, workingFolder)).Where(b => b.Name != "%Includes")); - } - resolvedBlocks.AddRange(deepBlocks); - } + } + catch (Exception ex) + { + ctx.LogImportError(ex.ToString()); + ctx.LogImportError($"Failed to process the shader definition file {ctx.assetPath}"); + return; + } - blocks = resolvedBlocks; - } + IncludedModules.Clear(); + + // Get the shader name + string shaderName; + try + { + shaderName = GetShaderName(blocks); + ShaderName = shaderName; + } + catch (Exception ex) + { + ctx.LogImportError(ex.ToString()); + ctx.LogImportError($"Failed to get the shader name from {ctx.assetPath}"); + return; + } + + // Recursively get all the blocks + try + { + blocks = RecursivelyGetDirectDependencies(ctx, workingFolder, blocks); } catch (Exception ex) { @@ -226,197 +219,480 @@ public override void OnImportAsset(AssetImportContext ctx) // Find and load the lighting model List lightingModel; + var lightingModelName = DefaultLightingModel; + string lightingModelPath; + try + { + GetLightingModel(ctx, workingFolder, blocks, out lightingModel, out lightingModelName, out lightingModelPath); + } + catch (Exception ex) + { + ctx.LogImportError(ex.ToString()); + ctx.LogImportError($"Failed to load Lighting Model in {ctx.assetPath}", this); + throw; + } + LightingModel = lightingModelName; + + // Recursively get all the lighting model blocks + try + { + blocks = RecursivelyGetLightingModelDependencies(ctx, blocks, lightingModel, lightingModelPath); + } + catch (Exception ex) + { + ctx.LogImportError(ex.ToString()); + ctx.LogImportError($"Failed to load Lighting Model in {ctx.assetPath}", this); + throw; + } + + // Find and load the template file + string[] template; + var templateName = "@/Templates/PBR"; try { - var lightingModelIndex = blocks.FindIndex(b => b.Name == "%LightingModel"); - // If we don't have a lighting model, use the default (PBR) - var lightingModelName = lightingModelIndex == -1 - ? DefaultLightingModel - : blocks[lightingModelIndex].Params[0].Replace("\"", ""); - var lightingModelPath = - Utils.ResolveORLAsset(lightingModelName, lightingModelName.StartsWith("@/"), workingFolder); - var lmParser = new Parser(); - lightingModel = lmParser.Parse(Utils.GetAssetSource(lightingModelName, workingFolder)); - if (!string.IsNullOrEmpty(lightingModelPath)) + template = GetTemplate(ctx, blocks, lightingModel, out templateName); + } + catch (Exception ex) + { + ctx.LogImportError(ex.ToString()); + ctx.LogImportError($"Failed to load Template in {ctx.assetPath}", this); + throw; + } + + // Find and toggle template features + try + { + template = ToggleTemplateFeatures(ctx, blocks, template).ToArray(); + } + catch (Exception ex) + { + ctx.LogImportError(ex.ToString()); + ctx.LogImportError($"Failed to toggle Template Features in {ctx.assetPath}", this); + throw; + } + + // Collapse non-function blocks together and de-dupe things where makes sense + blocks = OptimizeBlocks(blocks); + + // Load all the extra passes + var extraPasses = blocks.FindAll(b => b.CoreBlockType == BlockType.ExtraPass); + var generatedExtraPasses = new List(); + var extraPassBlocks = new Dictionary>(); + foreach (var extraPass in extraPasses) + { + try { - ctx.DependsOnSourceAsset(lightingModelPath); + GetExtraPass(ctx, blocks, templateName, ref generatedExtraPasses, ref extraPassBlocks, extraPass); } + catch (Exception ex) + { + ctx.LogImportError(ex.ToString()); + ctx.LogImportError($"Failed to process the extra pass {extraPass.Name} in {ctx.assetPath}", this); + throw; + } + } + + // Insert blocks at hook points + var hookPointBlocks = blocks.FindAll(b => (b.HookPoints?.Count ?? 0) > 0).ToList(); + try + { + InjectBlocksIntoHookPoints(blocks, hookPointBlocks); + } + catch (Exception ex) + { + ctx.LogImportError(ex.ToString()); + ctx.LogImportError($"Failed to inject blocks into hook points in {ctx.assetPath}", this); + throw; + } - // Lighting model defines some basic functions and dictates where the source shader gets plugged in - var updatedBlocks = new List(); - foreach (var lmInclude in lightingModel.Find(b => b.Name == "%Includes").Contents) + // Override shader name to be the one from the source shader + blocks[blocks.FindIndex(b => b.CoreBlockType == BlockType.ShaderName)].Params[0] = shaderName; + + // save function blocks to a separate list as they need special handling + var functionBlocks = blocks.Where(b => b.IsFunction).Reverse().ToList(); + + // Re-hydrate function blocks, we allow nesting of up to 1 level deep + functionBlocks = functionBlocks.Select(b => + { + var filtered = functionBlocks.Where(i => !i.Equals(b)).ToList(); + b.Contents = HydrateTemplate(new StringBuilder(), b.Contents, filtered, filtered, ctx).ToString().Split(new[] { Environment.NewLine, "\n" }, StringSplitOptions.None).ToList(); + return b; + }).ToList(); + + // Assemble the final shader with all the source and pre-hydrated blocks + var finalShader = new StringBuilder(); + finalShader = HydrateTemplate(finalShader, template, blocks, functionBlocks, ctx, generatedExtraPasses); + + var shaderString = finalShader.ToString(); + var shader = ShaderUtil.CreateShaderAsset(ctx, shaderString, true); + + if (ShaderUtil.ShaderHasError(shader)) + { + var errors = ShaderUtil.GetShaderMessages(shader); + foreach (var error in errors) + { + ctx.LogImportError(error.message + $"on line {error.line} in {ctx.assetPath}"); + } + } + else + { + ShaderUtil.ClearShaderMessages(shader); + } + + // Dump shader source as a hidden sub-asset + var textAsset = new TextAsset(shaderString) + { + name = "Shader Source", + hideFlags = HideFlags.HideInHierarchy + }; + + // Dump errors for basic Vert/Frag parameters + ValidateBasicFunctions(blocks, ref ctx); + + // This is currently too slow + // We should do this on the parser step + // UpdateStats(blocks, ref finalShader, ref ctx); + + ctx.AddObjectToAsset("Shader", shader); + ctx.SetMainObject(shader); + ctx.AddObjectToAsset("Shader Source", textAsset); + } + + #region Generator Steps + + private static string GetShaderName(List blocks) + { + string shaderName; + var shaderNameBlockIndex = blocks.FindIndex(b => b.CoreBlockType == BlockType.ShaderName); + if (shaderNameBlockIndex == -1) + { + throw new MissingBlockException("%ShaderName", ""); + } + shaderName = blocks[shaderNameBlockIndex].Params[0]; + if (string.IsNullOrWhiteSpace(shaderName?.Replace("\"", ""))) + { + throw new MissingParameterException("name", "%ShaderName", ""); + } + + return shaderName; + } + + private List RecursivelyGetDirectDependencies(AssetImportContext ctx, string workingFolder, List blocks) + { + var includesIndex = blocks.FindIndex(b => b.CoreBlockType == BlockType.Includes); + // Shaders can have direct includes (not via LightingModel or anything else) + // Here we deep-resolve them and inject them back into the blocks in the respective order + if (includesIndex != -1) + { + var resolvedBlocks = new List(); + foreach (var include in blocks[includesIndex].Contents) { - var stripped = lmInclude.Replace("\"", "").Replace(",", ""); - if (stripped == "target") + var stripped = include.Replace("\"", "").Replace(",", ""); + // We inject the already parsed blocks in place of "self" + if (stripped == "self") { - updatedBlocks.AddRange(blocks); + resolvedBlocks.AddRange(blocks.Where(b => b.CoreBlockType != BlockType.Includes)); continue; } var blockParser = new Parser(); var deepDeps = new List(); - var lmWorkingFolder = lightingModelPath.Substring(0, - lightingModelPath.LastIndexOf("/", StringComparison.InvariantCulture)); - // We recursively collect everything that the lighting model depends on into a flattened list - Utils.RecursivelyCollectDependencies(new[] {stripped}.ToList(), ref deepDeps, lmWorkingFolder); - deepDeps.ForEach(dep => - ctx.DependsOnSourceAsset(Utils.ResolveORLAsset(dep, dep.StartsWith("@/"), lmWorkingFolder))); + + // Save direct dependencies + IncludedModules.Add(Utils.ResolveORLAsset(stripped, stripped.StartsWith("@/"), _userModuleRemaps, workingFolder)); + + // We recursively collect everything that the shader depends on into a flattened list + Utils.RecursivelyCollectDependencies(new[] { stripped }.ToList(), ref deepDeps, workingFolder, _userModuleRemaps); + var resolvedDeepDeps = deepDeps.Select(dep => Utils.ResolveORLAsset(dep, dep.StartsWith("@/"), _userModuleRemaps, workingFolder)).ToList(); + + // Register all the dependencies + resolvedDeepDeps.ForEach(ctx.DependsOnSourceAsset); + + // Load all the blocks var deepBlocks = new List(); foreach (var deepDep in deepDeps) { // since we already have the deps flattened, we can safely strip all the dependencies here - deepBlocks.AddRange(blockParser.Parse(Utils.GetAssetSource(deepDep, lmWorkingFolder)) - .Where(b => b.Name != "%Includes")); + deepBlocks.AddRange(blockParser.Parse(Utils.GetAssetSource(deepDep, workingFolder, _userModuleRemaps)).Where(b => b.CoreBlockType != BlockType.Includes)); } - - updatedBlocks.AddRange(deepBlocks); + resolvedBlocks.AddRange(deepBlocks); } - blocks = updatedBlocks; + blocks = resolvedBlocks; } - catch (Exception ex) + return blocks; + } + + private void GetLightingModel(AssetImportContext ctx, string workingFolder, List blocks, out List lightingModel, out string lightingModelName, out string lightingModelPath) + { + var lightingModelIndex = blocks.FindIndex(b => b.CoreBlockType == BlockType.LightingModel); + // If we don't have a lighting model, use the default (PBR) + lightingModelName = lightingModelIndex == -1 + ? DefaultLightingModel + : blocks[lightingModelIndex].Params[0].Replace("\"", ""); + lightingModelPath = Utils.ResolveORLAsset(lightingModelName, lightingModelName.StartsWith("@/"), _userModuleRemaps, workingFolder); + var lmParser = new Parser(); + lightingModel = lmParser.Parse(Utils.GetAssetSource(lightingModelName, workingFolder, _userModuleRemaps)); + if (!string.IsNullOrEmpty(lightingModelPath)) { - ctx.LogImportError(ex.ToString()); - ctx.LogImportError($"Failed to load Lighting Model in {ctx.assetPath}", this); - throw; + ctx.DependsOnSourceAsset(lightingModelPath); } + } - // Find and load the template file - string[] template; - try + private List RecursivelyGetLightingModelDependencies(AssetImportContext ctx, List blocks, List lightingModel, string lightingModelPath) + { + // Lighting model defines some basic functions and dictates where the source shader gets plugged in + var updatedBlocks = new List(); + foreach (var lmInclude in lightingModel.Find(b => b.CoreBlockType == BlockType.Includes).Contents) { - var templateBlockIndex = blocks.FindIndex(b => b.Name == "%Template"); - // if no template is found - use the Lighting Model supplied one - string templateName; - if (templateBlockIndex > -1) + var stripped = lmInclude.Replace("\"", "").Replace(",", ""); + if (stripped == "target") { - templateName = blocks[templateBlockIndex].Params[0].Replace("\"", ""); + updatedBlocks.AddRange(blocks); + continue; } - else + + var blockParser = new Parser(); + var deepDeps = new List(); + var lmWorkingFolder = lightingModelPath.Substring(0, + lightingModelPath.LastIndexOf("/", StringComparison.InvariantCulture)); + + // We recursively collect everything that the lighting model depends on into a flattened list + Utils.RecursivelyCollectDependencies(new[] { stripped }.ToList(), ref deepDeps, lmWorkingFolder, _userModuleRemaps); + var resolvedDeepDeps = deepDeps.Select(dep => Utils.ResolveORLAsset(dep, dep.StartsWith("@/"), _userModuleRemaps, lmWorkingFolder)).ToList(); + + // Register all the dependencies + resolvedDeepDeps.ForEach(ctx.DependsOnSourceAsset); + + // Load all the blocks + var deepBlocks = new List(); + foreach (var deepDep in deepDeps) { - templateBlockIndex = lightingModel.FindIndex(b => b.Name == "%Template"); - if (templateBlockIndex == -1) - { - throw new MissingBlockException("%Template", - "The lighting model is missing the %Template block"); - } + // since we already have the deps flattened, we can safely strip all the dependencies here + deepBlocks.AddRange(blockParser.Parse(Utils.GetAssetSource(deepDep, lmWorkingFolder, _userModuleRemaps)) + .Where(b => b.CoreBlockType != BlockType.Includes)); + } - templateName = lightingModel[templateBlockIndex].Params[0]?.Replace("\"", ""); - ; - if (string.IsNullOrWhiteSpace(templateName)) - { - throw new MissingParameterException("name", "%Template", ""); - } + updatedBlocks.AddRange(deepBlocks); + } + + return updatedBlocks; + } + + private string[] GetTemplate(AssetImportContext ctx, List blocks, List lightingModel, out string templateName) + { + var templateBlockIndex = blocks.FindIndex(b => b.CoreBlockType == BlockType.Template); + // if no template is found - use the Lighting Model supplied one + if (templateBlockIndex > -1) + { + templateName = blocks[templateBlockIndex].Params[0].Replace("\"", ""); + } + else + { + templateBlockIndex = lightingModel.FindIndex(b => b.CoreBlockType == BlockType.Template); + if (templateBlockIndex == -1) + { + throw new MissingBlockException("%Template", + "The lighting model is missing the %Template block"); } - var templatePath = Utils.ResolveORLAsset(templateName); - template = Utils.GetORLTemplate(templateName); - if (!string.IsNullOrEmpty(templatePath)) + templateName = lightingModel[templateBlockIndex].Params[0]?.Replace("\"", ""); + ; + if (string.IsNullOrWhiteSpace(templateName)) { - ctx.DependsOnSourceAsset(templatePath); + throw new MissingParameterException("name", "%Template", ""); } } - catch (Exception ex) + + var templatePath = Utils.ResolveORLAsset(templateName); + if (!string.IsNullOrEmpty(templatePath)) { - ctx.LogImportError(ex.ToString()); - ctx.LogImportError($"Failed to load Template in {ctx.assetPath}", this); - throw; + ctx.DependsOnSourceAsset(templatePath); } - - // Find and toggle template features - try + + return Utils.GetORLTemplate(templateName, _userModuleRemaps); + } + + private List ToggleTemplateFeatures(AssetImportContext ctx, List blocks, string[] template) + { + var templateFeatures = new List(); + var templateFeaturesIndex = blocks.FindIndex(b => b.CoreBlockType == BlockType.TemplateFeatures); + if (templateFeaturesIndex > -1) + { + templateFeatures = blocks[templateFeaturesIndex].Params.Select(p => p.Replace("\"", "")).ToList(); + } + + // run through the template and mutate it based on the features + var newTemplate = new List(); + var enteredFeature = false; + string currentFeatureName = null; + var skippingFeature = false; + var nestLevel = 0; + for (var index = 0; index < template.Length; index++) { - var templateFeatures = new List(); - var templateFeaturesIndex = blocks.FindIndex(b => b.Name == "%TemplateFeatures"); - if (templateFeaturesIndex > -1) + var trimmedLine = template[index].Trim(); + if (trimmedLine.StartsWith("//", StringComparison.InvariantCulture)) { - templateFeatures = blocks[templateFeaturesIndex].Params.Select(p => p.Replace("\"", "")).ToList(); + newTemplate.Add(template[index]); + continue; } - // run through the template and mutate it based on the features - var newTemplate = new StringBuilder(); - var enteredFeature = false; - string currentFeatureName = null; - var skippingFeature = false; - var nestLevel = 0; - for (var index = 0; index < template.Length; index++) + if (enteredFeature) { - var trimmedLine = template[index].Trim(); - if (trimmedLine.StartsWith("//", StringComparison.InvariantCulture)) + if (trimmedLine.StartsWith("{")) nestLevel++; + if (trimmedLine.StartsWith("}")) nestLevel--; + } + + if (enteredFeature && nestLevel == 0) + { + enteredFeature = false; + skippingFeature = false; + // feature exited, skip this line for the closing `}` + continue; + } + + var match = _templateFeatureRegex.Match(trimmedLine); + // add all normal lines + if (!match.Success) + { + if (!skippingFeature) { - newTemplate.AppendLine(template[index]); - continue; + newTemplate.Add(template[index]); } + continue; + } + + // if encountered nested feature - abort + if (enteredFeature) + { + ctx.LogImportError($"Found nested Template Features in {ctx.assetPath}. {match.Groups["identifier"].Value} was inside {currentFeatureName}", this); + throw new Exception("Nested Template Features are not supported"); + } + + currentFeatureName = match.Groups["identifier"].Value.Replace("\"", string.Empty); + + // if this isn't a feature we want - skip it altogether + if (!templateFeatures.Contains(currentFeatureName)) + { + skippingFeature = true; + enteredFeature = true; + // we skip 1 line for the opening `{` + nestLevel++; + index++; + continue; + } + + enteredFeature = true; + // we skip 1 line for the opening `{` + nestLevel++; + index++; + } + + return newTemplate; + } + + private void GetExtraPass(AssetImportContext ctx, List blocks, string templateName, ref List generatedExtraPasses, ref Dictionary> extraPassBlocks, ShaderBlock extraPass) + { + var extraPassName = extraPass.Params[0].Replace("\"", ""); + var extraPassType = extraPass.TypedParams?[1] as ShaderBlock.ExtraPassType? ?? ShaderBlock.ExtraPassType.PostPass; + var extraPassParser = new Parser(); + var extraPassBlocksList = extraPassParser.Parse(extraPass.Contents.ToArray()); + extraPassBlocksList.Add(new ShaderBlock + { + Name = "%PassName", + Params = new List() { $"\"{extraPassName}\"" } + }); + + // don't want to include main pass functions in extra pass blocks with an exception for the base functions + var combinedList = extraPassBlocksList.Concat(blocks.Where(b => (b.IsFunction && b.Name.EndsWith("Base")) || (!b.IsFunction && !b.Name.StartsWith("%Pass")))).ToList(); + + extraPassBlocksList = OptimizeBlocks(combinedList); + extraPassBlocks.Add(extraPassName, extraPassBlocksList); + var extraPassFunctions = extraPassBlocksList.Where(b => b.IsFunction).ToList(); + + var extraPassTemplateName = templateName + "ExtraPass"; + var extraPassTemplatePath = Utils.ResolveORLAsset(extraPassTemplateName, true, _userModuleRemaps); + var extrapassTemplate = Utils.GetORLTemplate(extraPassTemplateName, _userModuleRemaps); + if (string.IsNullOrEmpty(extraPassTemplatePath)) return; + + ctx.DependsOnSourceAsset(extraPassTemplatePath); + // Hydrate loaded template + var hydratedExtraPass = new StringBuilder(); + var hydratedExtraPassString = HydrateTemplate(hydratedExtraPass, extrapassTemplate, combinedList, extraPassFunctions, ctx).ToString(); + generatedExtraPasses.Add(new GeneratedExtraPass + { + content = hydratedExtraPassString.Split(new[] { Environment.NewLine, "\n" }, StringSplitOptions.None).ToList(), + count = hydratedExtraPassString.Length, + passType = extraPassType + }); + } + - if (enteredFeature) + private void InjectBlocksIntoHookPoints(List blocks, List hookPointBlocks) + { + for (var i = 0; i < hookPointBlocks.Count; i++) + { + for (var j = 0; j < hookPointBlocks[i].HookPoints.Count; j++) + { + var blocksToInsert = blocks.FindAll(b => { - if (trimmedLine.StartsWith("{")) nestLevel++; - if (trimmedLine.StartsWith("}")) nestLevel--; - } - - if (enteredFeature && nestLevel == 0) + var hookPointName = hookPointBlocks[i].HookPoints[j].Name; + if (b.Name == "%" + hookPointName) return true; + if (b.Name == "%" + hookPointName + "Functions") return true; + return false; + }); + // No blocks for this hook point, we can skip it + if (blocksToInsert.Count == 0) continue; + // these blocks are transient and we dont want to keep them around, unless they're functions + blocksToInsert.ForEach(b => { - enteredFeature = false; - skippingFeature = false; - // feature exited, skip this line for the closing `}` - continue; - } - - var match = _templateFeatureRegex.Match(trimmedLine); - // add all normal lines - if (!match.Success) + if (b.IsFunction) return; + blocks.Remove(b); + }); + foreach (var block in blocksToInsert) { - if (!skippingFeature) + if (block.IsFunction) { - newTemplate.AppendLine(template[index]); + if (hookPointBlocks[i].HookPoints[j].Name.EndsWith("Functions")) + { + var fnName = ""; + fnName = hookPointBlocks[i].HookPoints[j].Name.Replace("Functions", ""); + + var fnBlocks = blocks.FindAll(b => b.IsFunction && b.Name == "%" + fnName); + fnBlocks.Reverse(); + fnBlocks.Sort((a, b) => a.Order.CompareTo(b.Order)); + fnBlocks.Reverse(); + foreach (var fnBlock in fnBlocks) + { + hookPointBlocks[i].Contents.InsertRange(hookPointBlocks[i].HookPoints[j].Line, IndentContentsList(new List { fnBlock.CallSign }, hookPointBlocks[i].HookPoints[j].Indentation)); + } + continue; + } + + hookPointBlocks[i].Contents.InsertRange(hookPointBlocks[i].HookPoints[j].Line, IndentContentsList(new List { block.CallSign }, hookPointBlocks[i].HookPoints[j].Indentation)); + continue; } - continue; - } - // if encountered nested feature - abort - if (enteredFeature) - { - ctx.LogImportError($"Found nested Template Features in {ctx.assetPath}. {match.Groups["identifier"].Value} was inside {currentFeatureName}", this); - throw new Exception("Nested Template Features are not supported"); + hookPointBlocks[i].Contents.InsertRange(hookPointBlocks[i].HookPoints[j].Line, IndentContentsList(block.Contents, hookPointBlocks[i].HookPoints[j].Indentation)); } - - currentFeatureName = match.Groups["identifier"].Value.Replace("\"", string.Empty); - - // if this isn't a feature we want - skip it altogether - if (!templateFeatures.Contains(currentFeatureName)) - { - skippingFeature = true; - enteredFeature = true; - // we skip 1 line for the opening `{` - nestLevel++; - index++; - continue; - } - - enteredFeature = true; - // we skip 1 line for the opening `{` - nestLevel++; - index++; + hookPointBlocks[i].Contents.RemoveAt(hookPointBlocks[i].HookPoints[j].Line + 1); } - template = newTemplate.ToString().Split(new[] { Environment.NewLine, "\n"}, StringSplitOptions.None); - } - catch (Exception ex) - { - ctx.LogImportError(ex.ToString()); - ctx.LogImportError($"Failed to toggle Template Features in {ctx.assetPath}", this); - throw; } + } - // Collapse non-function blocks together and de-dupe things where makes sense - blocks = OptimizeBlocks(blocks); - - // Override shader name to be the one from the source shader - blocks[blocks.FindIndex(b => b.Name == "%ShaderName")].Params[0] = shaderName; - - // save function blocks to a separate list as they need special handling - var functionBlocks = blocks.Where(b => b.IsFunction).Reverse().ToList(); - - var finalShader = new StringBuilder(); + /// + /// Hydrates the template with provided shader blocks + /// Optionally injects extra passes (for use in final shader assembly) + /// + /// Target shader + /// Template to hydrate + /// Shader blocks to insert into the template + /// Function blocks to insert into the template + /// Asset import context for logging + /// Extra passes list to inject into the template, should only be used for final shader assembly + /// final shader after hydration + private StringBuilder HydrateTemplate(StringBuilder finalShader, IEnumerable template, List blocks, List functionBlocks, AssetImportContext ctx, List generatedExtraPasses = null) + { foreach (var line in template) { var newLine = new StringBuilder(line); @@ -430,65 +706,51 @@ public override void OnImportAsset(AssetImportContext ctx) // Functions are a special case, they insert their code into the %Functions block // And then insert a call to the function in the respective stage - switch (matchVal) + + // Here we save all the function source code into the shader %Functions space + if (matchVal == "%Functions") { - // Here we save all the function source code into the shader %Functions space - case "%Functions": - { - InsertContentsAtPosition(ref newLine, functionBlocks, match.Index, matchLen); - continue; - } - // Here we insert function calls into the pre-pass fragment stage - case "%PrePassColorFunctions": - { - var fragmentFns = functionBlocks.FindAll(b => b.Name == "%PrePassColor"); - fragmentFns.Reverse(); - fragmentFns.Sort((a,b) => a.Order.CompareTo(b.Order)); - // the calls are inserted in reverse order to maintain offsets, so we reverse them back - fragmentFns.Reverse(); - InsertFnCallAtPosition(ref newLine, fragmentFns, match.Index, matchLen); - continue; - } - // Here we insert function calls into the fragment stage - case "%FragmentFunctions": - { - var fragmentFns = functionBlocks.FindAll(b => b.Name == "%Fragment"); - fragmentFns.Reverse(); - fragmentFns.Sort((a,b) => a.Order.CompareTo(b.Order)); - // the calls are inserted in reverse order to maintain offsets, so we reverse them back - fragmentFns.Reverse(); - InsertFnCallAtPosition(ref newLine, fragmentFns, match.Index, matchLen); - continue; - } - // Here we insert function calls into the vertex stage - case "%VertexFunctions": + InsertContentsAtPosition(ref newLine, functionBlocks, match.Index, matchLen); + continue; + } + + // Here we insert actual function calls if they follow a couple rules + // - The function block name is the same as the block name, but without the % prefix + // - The functio block has a parameter which matches some HLSL function within the block + if (matchVal.Contains("Functions") && matchVal != "%LibraryFunctions" && matchVal != "%FreeFunctions" && matchVal != "%PassFunctions") + { + var fnName = ""; + try { - var vertexFns = functionBlocks.FindAll(b => b.Name == "%Vertex"); - vertexFns.Reverse(); - vertexFns.Sort((a,b) => a.Order.CompareTo(b.Order)); - vertexFns.Reverse(); - InsertFnCallAtPosition(ref newLine, vertexFns, match.Index, matchLen); - continue; + fnName = matchVal.Substring(1).Replace("Functions", ""); } - // Here we insert function calls into the vertex stage - case "%ColorFunctions": + catch (Exception e) { - var colorFns = functionBlocks.FindAll(b => b.Name == "%Color"); - colorFns.Reverse(); - colorFns.Sort((a,b) => a.Order.CompareTo(b.Order)); - colorFns.Reverse(); - InsertFnCallAtPosition(ref newLine, colorFns, match.Index, matchLen); + ctx.LogImportError($"Failed to extract function name from {matchVal} in {ctx.assetPath}. {e.Message}"); continue; } - // Here we insert function calls into the fragment stage of shadowcaster - case "%ShadowFunctions": + + var fnBlocks = functionBlocks.FindAll(b => b.Name == "%" + fnName); + fnBlocks.Reverse(); + fnBlocks.Sort((a, b) => a.Order.CompareTo(b.Order)); + fnBlocks.Reverse(); + InsertFnCallAtPosition(ref newLine, fnBlocks, match.Index, matchLen); + continue; + } + + // Checked includes are special and just get inserted into ShaderDefines section + if (matchVal == "%ShaderDefines") + { + var checkedIncludes = blocks.FindAll(b => b.CoreBlockType == BlockType.CheckedInclude); + foreach (var checkedInclude in checkedIncludes) { - var shadowFns = functionBlocks.FindAll(b => b.Name == "%Shadow"); - shadowFns.Reverse(); - shadowFns.Sort((a,b) => a.Order.CompareTo(b.Order)); - shadowFns.Reverse(); - InsertFnCallAtPosition(ref newLine, shadowFns, match.Index, matchLen); - continue; + if (File.Exists(checkedInclude.Params[0].Replace("\"", ""))) + { + newLine.AppendLine(); + newLine.Append(new string(' ', match.Index)); + newLine.Append("#include "); + newLine.AppendLine(checkedInclude.Params[0]); + } } } @@ -497,7 +759,7 @@ public override void OnImportAsset(AssetImportContext ctx) if (foundBlockIndex != -1) { var block = blocks[foundBlockIndex]; - + // These are special single-line blocks that only insert their params value if (_paramsOnlyBlock.Contains(block.Name)) { @@ -530,7 +792,59 @@ public override void OnImportAsset(AssetImportContext ctx) newLine.Insert(match.Index, IndentContents(block.Contents, match.Index)); continue; } - + + if (generatedExtraPasses != null) + { + // Inject pre-hydrated extra pre-passes + if (matchVal == "%ExtraPrePasses") + { + var insertionIndex = match.Index; + newLine.Remove(match.Index, matchLen); + + var onlyPrePasses = generatedExtraPasses.Where(b => b.passType == ShaderBlock.ExtraPassType.PrePass); + + foreach (var extraPass in onlyPrePasses) + { + var indented = IndentContentsList(extraPass.content, insertionIndex); + foreach (var indentedLine in indented) + { + newLine.AppendLine(indentedLine.Replace(Environment.NewLine, string.Empty)); + // insertionIndex += indentedLine.Length; + } + // newLine.Insert(insertionIndex, indented); + // insertionIndex += indented.Count`; + // newLine.Insert(insertionIndex, Environment.NewLine); + // insertionIndex += Environment.NewLine.Length; + } + continue; + } + + // Inject pre-hydrated extra passes + if (matchVal == "%ExtraPasses") + { + var insertionIndex = match.Index; + newLine.Remove(match.Index, matchLen); + + var onlyPostPasses = generatedExtraPasses.Where(b => b.passType == ShaderBlock.ExtraPassType.PostPass); + + foreach (var extraPass in onlyPostPasses) + { + var indented = IndentContentsList(extraPass.content, insertionIndex); + foreach (var indentedLine in indented) + { + newLine.AppendLine(indentedLine.Replace(Environment.NewLine, string.Empty)); + // insertionIndex += indentedLine.Length; + } + // var indented = IndentContents(extraPass.content, insertionIndex); + // newLine.Insert(insertionIndex, indented); + // insertionIndex += indented.Length; + // newLine.Insert(insertionIndex, Environment.NewLine); + // insertionIndex += Environment.NewLine.Length; + } + continue; + } + } + // if nothing matched - clear out the current template hook and move on { newLine.Remove(match.Index, matchLen); @@ -545,33 +859,12 @@ public override void OnImportAsset(AssetImportContext ctx) finalShader.AppendLine(stringLine); } } - - var shaderString = finalShader.ToString(); - var shader = ShaderUtil.CreateShaderAsset(ctx, shaderString, true); - - if (ShaderUtil.ShaderHasError(shader)) - { - var errors = ShaderUtil.GetShaderMessages(shader); - foreach (var error in errors) - { - ctx.LogImportError(error.message + $"on line {error.line} in {ctx.assetPath}"); - } - } - else - { - ShaderUtil.ClearShaderMessages(shader); - } + return finalShader; + } - var textAsset = new TextAsset(shaderString) - { - name = "Shader Source", - hideFlags = HideFlags.HideInHierarchy - }; + #endregion - ctx.AddObjectToAsset("Shader", shader); - ctx.SetMainObject(shader); - ctx.AddObjectToAsset("Shader Source", textAsset); - } + #region Helpers private void RegisterDependencies(List dependencyPaths, AssetImportContext ctx) { @@ -579,10 +872,13 @@ private void RegisterDependencies(List dependencyPaths, AssetImportConte foreach (var s in dependencyPaths) { string path; - if (s.StartsWith("@/")) { - path = Utils.ResolveORLAsset(s); - } else { - path = Utils.ResolveORLAsset(s, false, workingFolder); + if (s.StartsWith("@/")) + { + path = Utils.ResolveORLAsset(s, true, _userModuleRemaps); + } + else + { + path = Utils.ResolveORLAsset(s, false, _userModuleRemaps, workingFolder); } if (!string.IsNullOrEmpty(path)) { @@ -592,7 +888,7 @@ private void RegisterDependencies(List dependencyPaths, AssetImportConte ctx.LogImportWarning("Failed to resolve dependency: " + s); } } - + /// /// Collapses all the same blocks together and deduplicates entries of blocks like Properties or Variables. /// Special blocks, like functions, are left untouched @@ -613,30 +909,56 @@ private List OptimizeBlocks(List sourceBlocks) continue; } + // We do not merge extra passes + if (block.CoreBlockType == BlockType.ExtraPass) + { + collapsedBlocks.Add(block); + continue; + } + if (!keySet.ContainsKey(block.Name)) { keySet.Add(block.Name, collapsedBlocks.Count); collapsedBlocks.Add(block); continue; } - + var index = keySet[block.Name]; collapsedBlocks[index].Contents.Add(""); + if (block.HookPoints != null) + { + if (collapsedBlocks[index].HookPoints == null) + { + collapsedBlocks[index].HookPoints = new List(); + } + collapsedBlocks[index].HookPoints.AddRange(block.HookPoints.Select(h => + { + h.Line += collapsedBlocks[index].Contents.Count; + return h; + })); + } collapsedBlocks[index].Contents.AddRange(block.Contents); } // Second pass - deduplicate things where it makes sense for (var i = 0; i < collapsedBlocks.Count; i++) { var block = collapsedBlocks[i]; - switch (block.Name) + switch (block.CoreBlockType) { - case "%Properties": - collapsedBlocks[i].Contents = DeDuplicateByRegex(block.Contents, _propertyRegex); + case BlockType.ShaderTags: + block.Contents = DeDuplicateByParser(block.Contents, DeDupeType.Tags); + continue; + case BlockType.Properties: + collapsedBlocks[i].Contents = DeDuplicateByParser(block.Contents, DeDupeType.Properties); continue; - case "%Variables": + case BlockType.ShaderModifiers: + case BlockType.PassModifiers: + collapsedBlocks[i].Contents = DeDuplicateByParser(block.Contents, DeDupeType.Modifiers); + continue; + case BlockType.Variables: collapsedBlocks[i].Contents = DeDuplicateByRegex(block.Contents, _varRegex); continue; - case "%Textures": + case BlockType.Textures: collapsedBlocks[i].Contents = DeDuplicateByRegex(block.Contents, _texSamplerCombinedRegex); continue; } @@ -645,8 +967,6 @@ private List OptimizeBlocks(List sourceBlocks) return collapsedBlocks; } - // Matches _VarNames - private Regex _propertyRegex = new Regex(@"(?:\[.*\])*\s*(?[\w]+)(?:\s?\(\"".*\""\,[\w\s\(\,\.\-\)]+\)\s*=)"); // Matches floatX halfX and intX variables private Regex _varRegex = new Regex(@"(?:uniform)?(?:\s*)(?:half|float|int|real|fixed|bool|float2x2|float3x3|float4x4|half2x2|half3x3|half4x4|fixed2x2|fixed3x3|fixed4x4|real2x2|real3x3|real4x4){1}(?:\d)?\s+(?\w+)"); // Matches either TEXTUREXXX() or SAMPLER() @@ -656,7 +976,105 @@ private List OptimizeBlocks(List sourceBlocks) private Regex _texRegex = new Regex(@"(?:RW_)?(?:TEXTURE[23DCUBE]+[_A-Z]*)\((?[\w]+)\)"); // Matches SAMPLER() private Regex _samplerRegex = new Regex(@"(?:SAMPLER)(?:_CMP)?\((?[\w]+)\)"); - + + private enum DeDupeType + { + Properties, + Tags, + Modifiers, + } + + private List DeDuplicateByParser(List source, DeDupeType type) + { + var keySet = new HashSet(); + var deduped = new List(); + var combined = string.Join(Environment.NewLine, source); + switch (type) + { + case DeDupeType.Properties: + { + var tokens = ShaderLabLexer.Lex(combined, null, null, false, out _); + var nodes = ShaderLabParser.ParseShaderProperties(tokens, ShaderAnalyzers.SLConfig, out _); + foreach (var node in nodes) + { + if (keySet.Contains(node.Uniform)) + { + if (_isDebugBuild) + { + Debug.LogWarning("Found duplicate item, skipping: " + node.Uniform); + } + continue; + } + keySet.Add(node.Uniform); + deduped.Add(node.GetCodeInSourceText(combined)); + + } + break; + } + case DeDupeType.Tags: + { + var dedupedTags = new Dictionary(); + var dedupedTagsString = new StringBuilder(); + combined = $"Tags {{{combined}}}"; + var tokens = ShaderLabLexer.Lex(combined, null, null, false, out _); + var nodes = ShaderLabParser.ParseShaderLabCommands(tokens, ShaderAnalyzers.SLConfig, out _); + foreach (var node in nodes) + { + if (node is ShaderLabCommandTagsNode tags) + { + foreach (var tag in tags.Tags) + { + var tagKey = tag.Key; + var tagValue = tag.Value; + if (keySet.Contains(tagKey)) + { + if (_isDebugBuild) + { + Debug.LogWarning("Found duplicate tag, updating: " + tagKey + " to " + tagValue); + } + dedupedTags[tagKey] = tagValue; + continue; + } + keySet.Add(tagKey); + dedupedTags.Add(tagKey, tagValue); + } + } + } + + foreach (var dedupedTag in dedupedTags) + { + dedupedTagsString.Append($"\"{dedupedTag.Key}\" = \"{dedupedTag.Value}\" "); + } + deduped.Add(dedupedTagsString.ToString()); + break; + } + case DeDupeType.Modifiers: + { + var tokens = ShaderLabLexer.Lex(combined, null, null, false, out _); + var nodes = ShaderLabParser.ParseShaderLabCommands(tokens, ShaderAnalyzers.SLConfig, out _); + var dedupedModifiers = new Dictionary(); + foreach (var node in nodes) + { + if (dedupedModifiers.ContainsKey(node.GetType())) + { + if (_isDebugBuild) + { + Debug.LogWarning($"Found duplicate shader/pass modifier, skipping: {node.GetCodeInSourceText(combined)}"); + } + continue; + } + dedupedModifiers.Add(node.GetType(), node); + } + foreach (var dedupedModifier in dedupedModifiers) + { + deduped.Add(dedupedModifier.Value.GetCodeInSourceText(combined)); + } + break; + } + } + return deduped; + } + private List DeDuplicateByRegex(List source, Regex matcher) { var keySet = new HashSet(); @@ -684,7 +1102,7 @@ private List DeDuplicateByRegex(List source, Regex matcher) var identifier = matcher.Match(item).Groups.Cast().Skip(1).ToList().Find(m => !string.IsNullOrEmpty(m.Value)).Value; if (keySet.Contains(identifier)) { - if (debugBuild) + if (_isDebugBuild) { Debug.LogWarning("Found duplicate item, skipping: " + identifier); } @@ -696,7 +1114,7 @@ private List DeDuplicateByRegex(List source, Regex matcher) return deduped; } - + private void InsertContentsAtPosition(ref StringBuilder line, List blocks, int position, int cleanLen) { line.Remove(position, cleanLen); @@ -712,7 +1130,7 @@ private void InsertContentsAtPosition(ref StringBuilder line, List i++; } } - + private void InsertFnCallAtPosition(ref StringBuilder line, List blocks, int position, int cleanLen) { line.Remove(position, cleanLen); @@ -728,7 +1146,6 @@ private void InsertFnCallAtPosition(ref StringBuilder line, List bl i++; } } - private string IndentContents(List contents, int indentLevel) { @@ -757,13 +1174,128 @@ private string IndentContents(List contents, int indentLevel) return sb.ToString(); } + private List IndentContentsList(List contents, int indentLevel) + { + var result = new List(); + var i = 0; + foreach (var contentLine in contents) + { + if (i == 0) + { + result.Add(contentLine + (contents.Count == 1 ? "" : Environment.NewLine)); + i++; + continue; + } + + if (i == contents.Count - 1) + { + result.Add(new string(' ', indentLevel) + contentLine); + } + else + { + result.Add(new string(' ', indentLevel) + contentLine + Environment.NewLine); + } + i++; + } + + return result; + } + + #endregion + + #region Parser-Based Stats and Validation + + private class StatsUpdater : HLSLSyntaxVisitor + { + public struct FunctionParamerror + { + public string Name; + public string Type; + public int StartIndex; + public int EndIndex; + public int Line; + } + + public Dictionary Errors = new Dictionary(); + + public override void VisitFunctionDefinitionNode(FunctionDefinitionNode node) + { + var allowedParams = new List { "v", "d", "o", "FinalColor" }; + foreach (var parameter in node.Parameters) + { + if (!allowedParams.Contains(parameter.Declarator.Name)) + { + var paramType = ""; + switch (parameter.ParamType) + { + case ScalarTypeNode s: + paramType = PrintingUtil.GetEnumName(s.Kind); + break; + case VectorTypeNode v: + paramType = PrintingUtil.GetEnumName(v.Kind) + v.Dimension; + break; + } + + Errors.Add(new FunctionParamerror + { + Line = parameter.Span.Start.Line, + StartIndex = parameter.Span.Start.Index, + EndIndex = parameter.Span.End.Index, + Name = parameter.Declarator.Name, + Type = paramType, + }, $"Invalid {paramType} parameter {parameter.Declarator.Name} in function {node.Name.GetName()}, only {string.Join(", ", allowedParams)} are supported"); + // if (!Errors.ContainsKey(node)) + // { + // } + // Debug.LogError($"Invalid {paramType} parameter {parameter.Declarator.Name} in function {node.Name.GetName()}, only {string.Join(", ", allowedParams)} are supported"); + } + } + // Debug.Log($"Function declaration {node.Name.GetName()}"); + } + } + + private void ValidateBasicFunctions(List blocks, ref AssetImportContext ctx) + { + try + { + var vertBlock = blocks.Find(b => b.Name == "%Vertex"); + ShaderBlockValidations.ValidateVertexFunction(vertBlock, ref ctx, this); + var fragBlock = blocks.Find(b => b.Name == "%Fragment"); + ShaderBlockValidations.ValidateFragmentFunction(fragBlock, ref ctx, this); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + + private void UpdateStats(List blocks, ref StringBuilder shaderContent, ref AssetImportContext ctx) + { + try + { + Undo.RecordObject(this, "Update Stats"); + textureCount = ShaderAnalyzers.CountTextureObjects(blocks, ref ctx, this); + samplerCount = ShaderAnalyzers.CountSamplers(blocks, ref ctx, this); + featureCount = ShaderAnalyzers.CountShaderFeatures(shaderContent.ToString()); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + + #endregion + + #region Public API + /// /// Saves the generated shader source to the path provided /// /// Path to the source shader /// Save path /// Strips the sampling macros from the final shader - public static void GenerateShader(string assetPath, string outputPath, bool stripSamplingMacros = false) { + public static void GenerateShader(string assetPath, string outputPath, bool stripSamplingMacros = false) + { var importer = GetAtPath(assetPath) as ShaderDefinitionImporter; if (importer == null) { @@ -776,11 +1308,11 @@ public static void GenerateShader(string assetPath, string outputPath, bool stri { return; } - + File.WriteAllText(outputPath, textSource); AssetDatabase.Refresh(); } - + /// /// Gets the generated shader code from the asset /// @@ -816,16 +1348,16 @@ public string GenerateShader(bool stripSamplingMacros = false) textSource = text; } } - + if (string.IsNullOrWhiteSpace(textSource)) { Debug.LogWarning($"Shader source for {assetPath} is empty! Generation likely failed"); return null; } - + if (stripSamplingMacros) { - var source = textSource.Split(new[] {Environment.NewLine, "\n"}, StringSplitOptions.None); + var source = textSource.Split(new[] { Environment.NewLine, "\n" }, StringSplitOptions.None); var processedSource = new StringBuilder(); var skippingSampling = false; @@ -843,7 +1375,7 @@ public string GenerateShader(bool stripSamplingMacros = false) continue; } if (skippingSampling) continue; - + var texMatch = _texRegex.Match(line); if (texMatch.Success) { @@ -851,7 +1383,7 @@ public string GenerateShader(bool stripSamplingMacros = false) processedSource.AppendLine(newLine); continue; } - + var samplerMatch = _samplerRegex.Match(line); if (samplerMatch.Success) { @@ -860,34 +1392,65 @@ public string GenerateShader(bool stripSamplingMacros = false) continue; } - if (line.Contains("SAMPLE_TEXTURE2D")) + if (line.Contains("SAMPLE_TEXTURE2D_GRAD")) { - var newLine = line.Replace("SAMPLE_TEXTURE2D", "UNITY_SAMPLE_TEX2D_SAMPLER").Replace("sampler_", "_"); + // search and parse parameters to rewrite into a `tex.SampleGrad` call + var substring = line.Substring(line.IndexOf("SAMPLE_TEXTURE2D_GRAD") + 21); + substring = substring.Substring(substring.IndexOf("(") + 1); + var levelsIn = 1; + var iterations = 0; + while (true) + { + if (substring[iterations] == '(') levelsIn++; + if (substring[iterations] == ')') levelsIn--; + if (levelsIn == 0) break; + iterations++; + if (iterations > 10000) break; + } + + if (iterations > 10000) + { + Debug.LogWarning("Could find the end of macro in 10000 iterations\n" + + $"Line was {substring}"); + continue; + } + + var parametersString = substring.Substring(0, iterations); + var parameterList = Regex.Split(parametersString, @",(?=(?:[^()]*\([^()]*\))*[^()]*$)"); + var newLine = line.Replace($"SAMPLE_TEXTURE2D_GRAD({parametersString})", $"{parameterList[0].Trim()}.SampleGrad({parameterList[1].Trim()}, {parameterList[2].Trim()}, {parameterList[3].Trim()}, {parameterList[4].Trim()})"); processedSource.AppendLine(newLine); continue; } - + + if (line.Contains("SAMPLE_TEXTURE2D_LOD")) { var newLine = line.Replace("SAMPLE_TEXTURE2D_LOD", "UNITY_SAMPLE_TEX2D_LOD_SAMPLER").Replace("sampler_", "_"); processedSource.AppendLine(newLine); continue; } - - if (line.Contains("SAMPLE_TEXTURECUBE")) + + if (line.Contains("SAMPLE_TEXTURE2D")) { - var newLine = line.Replace("SAMPLE_TEXTURECUBE", "UNITY_SAMPLE_TEXCUBE_SAMPLER").Replace("sampler_", "_"); + var newLine = line.Replace("SAMPLE_TEXTURE2D", "UNITY_SAMPLE_TEX2D_SAMPLER").Replace("sampler_", "_"); processedSource.AppendLine(newLine); continue; } - + if (line.Contains("SAMPLE_TEXTURECUBE_LOD")) { var newLine = line.Replace("SAMPLE_TEXTURECUBE_LOD", "UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD").Replace("sampler_", "_"); processedSource.AppendLine(newLine); continue; } - + + if (line.Contains("SAMPLE_TEXTURECUBE")) + { + var newLine = line.Replace("SAMPLE_TEXTURECUBE", "UNITY_SAMPLE_TEXCUBE_SAMPLER").Replace("sampler_", "_"); + processedSource.AppendLine(newLine); + continue; + } + processedSource.AppendLine(line); } @@ -897,4 +1460,6 @@ public string GenerateShader(bool stripSamplingMacros = false) return textSource; } } -} \ No newline at end of file + #endregion +} + diff --git a/Packages/sh.orels.shaders.generator/Editor/ShaderDefinitionImporterEditor.cs b/Packages/sh.orels.shaders.generator/Editor/ShaderDefinitionImporterEditor.cs old mode 100644 new mode 100755 index 56ff8d0d..158a9a42 --- a/Packages/sh.orels.shaders.generator/Editor/ShaderDefinitionImporterEditor.cs +++ b/Packages/sh.orels.shaders.generator/Editor/ShaderDefinitionImporterEditor.cs @@ -1,4 +1,10 @@ -using System.Text; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; using UnityEditor; #if UNITY_2022_3_OR_NEWER using UnityEditor.AssetImporters; @@ -12,11 +18,28 @@ namespace ORL.ShaderGenerator [CustomEditor(typeof(ShaderDefinitionImporter))] public class ShaderDefinitionImporterEditor : ScriptedImporterEditor { + private bool _includedModulesFoldout; private bool _sourceCodeFoldout; + private bool _shaderCompilationIssuesFoldout; + private bool _shaderGenerationIssuesFoldout; private Font _monoFont; + private GUIStyle _monoStyle; + private GUIStyle _boldFoldoutStyle; + private GUIStyle _richLabelStyle; private Vector2 _sourceScrollPos; private string[] _linedText; private ulong _lastTimestamp; + private int _goToLineNum; + private int _currentLine; + private bool _stripMacros; + + private readonly string[] _passList = { + "ForwardBase", + "ForwardAdd", + "Meta", + "ShadowCaster" + }; + public override void OnInspectorGUI() { @@ -24,6 +47,28 @@ public override void OnInspectorGUI() if (_monoFont == null) { _monoFont = Font.CreateDynamicFontFromOSFont("Consolas", 12); + _monoStyle = new GUIStyle(EditorStyles.textArea) + { + font = _monoFont, + wordWrap = false, + richText = true + }; + } + + if (_boldFoldoutStyle == null) + { + _boldFoldoutStyle = new GUIStyle(EditorStyles.foldout) + { + fontStyle = FontStyle.Bold + }; + } + + if (_richLabelStyle == null) + { + _richLabelStyle = new GUIStyle(EditorStyles.wordWrappedLabel) + { + richText = true, + }; } var importer = target as ShaderDefinitionImporter; @@ -54,7 +99,8 @@ public override void OnInspectorGUI() _linedText[i] = $"{(i + 1).ToString(),4} {_linedText[i]}"; } _lastTimestamp = importer.assetTimeStamp; - } else if (_lastTimestamp != importer.assetTimeStamp) + } + else if (_lastTimestamp != importer.assetTimeStamp) { _lastTimestamp = importer.assetTimeStamp; _linedText = textSource.Split('\n'); @@ -64,46 +110,229 @@ public override void OnInspectorGUI() } } + if (importer.Errors.Any()) + { + EditorGUILayout.LabelField("Shader Generation Issues", EditorStyles.boldLabel); + foreach (var error in importer.Errors) + { + var line = error.Line + error.Block.Line; + var snippet = new StringBuilder(); + var currFile = string.IsNullOrWhiteSpace(error.Block.Path); + string[] fileContents = new string[0]; + if (currFile) + { + fileContents = File.ReadAllLines(importer.assetPath); + } + + var startLine = Mathf.Max(0, line - 5); + var endLine = Mathf.Min(fileContents.Length, line + 5); + for (int i = startLine; i < endLine; i++) + { + snippet.AppendFormat("{0,4}", i + 1); + snippet.Append(" "); + if (i + 1 == line) + { + if (error.StartIndex > -1) + { + var offset = fileContents[i].Length - fileContents[i].TrimStart().Length; + if (fileContents[i].Length == 0 || (error.StartIndex + offset) > fileContents[i].Length) + { + continue; + } + snippet.Append(fileContents[i].Substring(0, error.StartIndex + offset)); + snippet.Append(""); + snippet.Append(fileContents[i].Substring(error.StartIndex + offset, error.EndIndex - error.StartIndex)); + snippet.Append(""); + snippet.Append(fileContents[i].Substring(error.EndIndex + offset)); + snippet.AppendLine(); + } + else + { + snippet.Append(""); + snippet.Append(fileContents[i]); + snippet.Append(""); + snippet.AppendLine(); + } + } + else + { + snippet.AppendLine(fileContents[i]); + } + } + + var message = $"{error.Message} on line {line}"; + if (!currFile) + { + message += $" in {error.Block.Path}"; + } + + EditorGUILayout.LabelField(message, _richLabelStyle); + EditorGUILayout.TextArea(snippet.ToString(), _monoStyle); + } + } + var finalShader = AssetDatabase.LoadAssetAtPath(importer.assetPath); if (ShaderUtil.ShaderHasError(finalShader)) { - EditorGUILayout.LabelField("Shader Compilation Issues", EditorStyles.boldLabel); - var errors = ShaderUtil.GetShaderMessages(finalShader); - foreach (var error in errors) + _shaderCompilationIssuesFoldout = + EditorGUILayout.Foldout(_shaderCompilationIssuesFoldout, "Shader Compilation Issues", _boldFoldoutStyle); + // EditorGUILayout.LabelField("Shader Compilation Issues", EditorStyles.boldLabel); + if (_shaderCompilationIssuesFoldout) { - var line = error.line; - var snippet = new StringBuilder(); - for (int i = Mathf.Max(0, line - 10); i < Mathf.Min(_linedText.Length, line + 10); i++) + var errors = ShaderUtil.GetShaderMessages(finalShader); + foreach (var error in errors) { - snippet.AppendLine(_linedText[i]); + var line = error.line; + var snippet = new StringBuilder(); + for (int i = Mathf.Max(0, line - 5); i < Mathf.Min(_linedText.Length, line + 5); i++) + { + if (i + 1 == line) + { + snippet.Append(""); + } + snippet.Append(_linedText[i]); + if (i + 1 == line) + { + snippet.Append(""); + } + + snippet.AppendLine(); + } + + EditorGUILayout.LabelField($"{error.message} on line {line}"); + EditorGUILayout.TextArea(snippet.ToString(), _monoStyle); } + } + } + + // TODO: re-enable it when parsing of shaders is multi-threaded and fast + // EditorGUILayout.LabelField("Stats", EditorStyles.boldLabel); + // var oldWidth = EditorGUIUtility.labelWidth; + // EditorGUIUtility.labelWidth = 64; + // using (new EditorGUILayout.HorizontalScope()) + // { + // using (new EditorGUI.DisabledScope(true)) + // { + // EditorGUILayout.IntField("Features:", serializedObject.FindProperty("featureCount").intValue); + // EditorGUILayout.IntField("Textures:", serializedObject.FindProperty("textureCount").intValue); + // EditorGUILayout.IntField("Samplers:", serializedObject.FindProperty("samplerCount").intValue); + // } + // } + + // EditorGUIUtility.labelWidth = oldWidth; + // EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Shader Info", EditorStyles.miniBoldLabel); + EditorGUILayout.LabelField("Lighting Model", importer.LightingModel); + - EditorGUILayout.LabelField($"{error.message} on line {line}"); - EditorGUILayout.TextArea(snippet.ToString()); + _includedModulesFoldout = EditorGUILayout.Foldout(_includedModulesFoldout, "Included Modules"); + if (_includedModulesFoldout) + { + using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) + { + foreach (var module in importer.IncludedModules) + { + var sourceAsset = AssetDatabase.LoadAssetAtPath(module); + var sourceShader = AssetDatabase.LoadAssetAtPath(module); + EditorGUILayout.ObjectField(sourceAsset != null ? sourceAsset : sourceShader, typeof(UnityEngine.Object), false); + } } } _sourceCodeFoldout = EditorGUILayout.Foldout(_sourceCodeFoldout, "Compiled Source"); if (_sourceCodeFoldout && !string.IsNullOrWhiteSpace(textSource)) { - var style = new GUIStyle(EditorStyles.textArea) + using (var c = new EditorGUI.ChangeCheckScope()) { - font = _monoFont, - wordWrap = false - }; + _goToLineNum = EditorGUILayout.IntField("Go To Line", _goToLineNum); + if (c.changed) + { + _sourceScrollPos = new Vector2(0, 1) * (Mathf.Max(0, _goToLineNum - 5) * _monoStyle.lineHeight); + } + } + + _currentLine = Mathf.Max(0, Mathf.FloorToInt(_sourceScrollPos.y / _monoStyle.lineHeight)); + EditorGUILayout.LabelField("Quick Jump", EditorStyles.boldLabel); + using (new EditorGUILayout.HorizontalScope()) + { + foreach (var pass in _passList) + { + if (GUILayout.Button(pass)) + { + var lineNum = Array.FindIndex(_linedText, l => l.Contains($"{pass} Pass Start")); + if (lineNum > -1) + { + _sourceScrollPos = new Vector2(0, 1) * (Mathf.Max(0, lineNum - 5) * _monoStyle.lineHeight); + } + } + } + } + EditorGUILayout.LabelField(new GUIContent("Closest Jump", "Jumps to the closest instance of selected type"), EditorStyles.boldLabel); + using (new EditorGUILayout.HorizontalScope()) + { + var lineNum = 0; + if (GUILayout.Button("Vertex")) + { + lineNum = Array.FindIndex(_linedText.Skip(_currentLine).ToArray(), l => l.Contains("FragmentData Vertex(VertexData v)")); + } + if (GUILayout.Button("Fragment")) + { + lineNum = Array.FindIndex(_linedText.Skip(_currentLine).ToArray(), l => l.Contains("half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace)")); + } + + if (GUILayout.Button("Variables")) + { + lineNum = Array.FindIndex(_linedText.Skip(_currentLine).ToArray(), l => l.Contains("// Variables")); + } + + if (GUILayout.Button("Textures")) + { + lineNum = Array.FindIndex(_linedText.Skip(_currentLine).ToArray(), l => l.Contains("// Textures")); + } + + if (GUILayout.Button("Functions")) + { + lineNum = Array.FindIndex(_linedText.Skip(_currentLine).ToArray(), l => l.Contains("// Functions")); + } + + if (lineNum > 0) + { + _sourceScrollPos = new Vector2(0, 1) * (Mathf.Max(0, lineNum + _currentLine - 5) * _monoStyle.lineHeight); + } + } + EditorGUILayout.Space(); using (var sv = new EditorGUILayout.ScrollViewScope(_sourceScrollPos, GUILayout.Height(500 * EditorGUIUtility.pixelsPerPoint))) { - EditorGUILayout.TextArea(string.Join("\n", _linedText), style); + EditorGUILayout.TextArea(string.Join("\n", _linedText), _monoStyle); _sourceScrollPos = sv.scrollPosition; } + using (new EditorGUILayout.HorizontalScope()) + { + if (GUILayout.Button("Copy Generated Code")) + { + GUIUtility.systemCopyBuffer = textSource; + } + if (GUILayout.Button("Open in Text Editor")) + { + var path = Application.dataPath.Replace("/Assets", "/Library/TempArtifacts/Extra/"); + var filename = Path.GetFileNameWithoutExtension(importer.assetPath); + path += filename + ".shader"; + File.WriteAllText(path, textSource); + EditorUtility.OpenWithDefaultApp(path); + } + } } EditorGUILayout.PropertyField(serializedObject.FindProperty("debugBuild")); + EditorGUILayout.LabelField("Conversions", EditorStyles.miniBoldLabel); + if (GUILayout.Button("Generate Static .shader File")) { - ShaderDefinitionImporter.GenerateShader(importer.assetPath, importer.assetPath.Replace(".orlshader", ".shader").Replace(".orlconfshader", ".shader")); + ShaderDefinitionImporter.GenerateShader(importer.assetPath, importer.assetPath.Replace(".orlshader", ".shader").Replace(".orlconfshader", ".shader"), _stripMacros); } + _stripMacros = EditorGUILayout.ToggleLeft("Strip Sampling Macros", _stripMacros); serializedObject.ApplyModifiedProperties(); ApplyRevertGUI(); diff --git a/Packages/sh.orels.shaders.generator/Editor/Utils.cs b/Packages/sh.orels.shaders.generator/Editor/Utils.cs index 30a31c36..b079af3a 100644 --- a/Packages/sh.orels.shaders.generator/Editor/Utils.cs +++ b/Packages/sh.orels.shaders.generator/Editor/Utils.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; +using ORL.ShaderGenerator.Settings; using UnityEditor; using UnityEngine; @@ -23,7 +25,7 @@ public static string GetORLSourceFolder() { return "/Packages/sh.orels.shaders.generator/Runtime/Sources"; } - + public static string ResolveORLAsset(string path, bool bundled, string basePath = null) { if (bundled) @@ -34,7 +36,42 @@ public static string ResolveORLAsset(string path, bool bundled, string basePath var freeAsset = ResolveFreeAsset(path, basePath); if (freeAsset == null) { - throw new SourceAssetNotFoundException(path, new[] {basePath}); + throw new SourceAssetNotFoundException(path, new[] { basePath }); + } + + return freeAsset; + } + + public static string ResolveORLAsset(string path, bool bundled, List remaps, string basePath = null) + { + if (remaps != null) + { + foreach (var remap in remaps) + { + // Ignore empty entries + if (string.IsNullOrWhiteSpace(remap.Source) || string.IsNullOrWhiteSpace(remap.Destination)) continue; + + if (path.Equals(remap.Source, StringComparison.InvariantCultureIgnoreCase)) + { + path = remap.Destination; + } + // If the remap is not bundled, resolve as free asset + if (!path.StartsWith("@/")) + { + bundled = false; + } + } + } + + if (bundled) + { + return ResolveBundledAsset(path); + } + + var freeAsset = ResolveFreeAsset(path, basePath); + if (freeAsset == null) + { + throw new SourceAssetNotFoundException(path, new[] { basePath }); } return freeAsset; @@ -51,7 +88,7 @@ private static string ResolveBundledAsset(string path) if (!string.IsNullOrWhiteSpace(builtInAsset)) return builtInAsset; var shaderPackageAsset = ResolveFreeAsset(cleaned, shaderSourcesFolder); - + if (builtInAsset == null && shaderPackageAsset == null) { throw new SourceAssetNotFoundException(path, new[] { sourcesFolder, shaderSourcesFolder }); @@ -65,7 +102,8 @@ private static string ResolveFreeAsset(string path, string basePath) var fullPath = basePath + "/" + path; // Resolve absolute paths var isAbsoluteImport = path.StartsWith("/"); - if (isAbsoluteImport) { + if (isAbsoluteImport) + { fullPath = path.Substring(1); } // Resolve relative paths @@ -110,12 +148,12 @@ private static string ResolveFreeAsset(string path, string basePath) { return (isAbsoluteImport ? path.Substring(1) : fullPath) + ".orlsource"; } - + if (orlShaderExists) { return (isAbsoluteImport ? path.Substring(1) : fullPath) + ".orlshader"; } - + if (orlTemplateExists) { return (isAbsoluteImport ? path.Substring(1) : fullPath) + ".orltemplate"; @@ -128,16 +166,26 @@ public static string ResolveORLAsset(string path) { return ResolveORLAsset(path, true); } - + public static string[] GetORLTemplate(string path) { - var fullPath = ResolveORLAsset(path, true); + return GetORLTemplate(path, null); + } + + public static string[] GetORLTemplate(string path, List remaps) + { + var fullPath = ResolveORLAsset(path, true, remaps); return File.ReadAllLines(fullPath); } - + public static string[] GetORLSource(string path) { - var fullPath = ResolveORLAsset(path, true); + return GetORLSource(path, null); + } + + public static string[] GetORLSource(string path, List remaps) + { + var fullPath = ResolveORLAsset(path, true, remaps); return File.ReadAllLines(fullPath); } @@ -146,12 +194,17 @@ public static string[] GetAssetSource(string path, string basePath) return File.ReadAllLines(ResolveORLAsset(path, path.StartsWith("@/"), basePath)); } + public static string[] GetAssetSource(string path, string basePath, List remaps) + { + return File.ReadAllLines(ResolveORLAsset(path, path.StartsWith("@/"), remaps, basePath)); + } + public static Texture2D GetNonModifiableTexture(Shader shader, string name) { var so = new SerializedObject(shader); var texList = so.FindProperty("m_NonModifiableTextures"); if (texList.arraySize == 0) return null; - + for (var i = 0; i < texList.arraySize; i++) { var tex = texList.GetArrayElementAtIndex(i); @@ -164,13 +217,19 @@ public static Texture2D GetNonModifiableTexture(Shader shader, string name) return null; } + public static void RecursivelyCollectDependencies(List sourceList, ref List dependencies, string basePath) + { + RecursivelyCollectDependencies(sourceList, ref dependencies, basePath, null); + } + + public static void RecursivelyCollectDependencies(List sourceList, ref List dependencies, string basePath, List remaps) { var parser = new Parser(); foreach (var source in sourceList) { - var blocks = parser.Parse(GetAssetSource(source, basePath)); - var includesBlockIndex = blocks.FindIndex(b => b.Name == "%Includes"); + var blocks = parser.Parse(GetAssetSource(source, basePath, remaps)); + var includesBlockIndex = blocks.FindIndex(b => b.CoreBlockType == ShaderBlock.BlockType.Includes); if (includesBlockIndex == -1) { dependencies.Add(source); @@ -191,7 +250,7 @@ public static void RecursivelyCollectDependencies(List sourceList, ref L if (!dependencies.Contains(depPath)) { var deepDeps = new List(); - RecursivelyCollectDependencies(new List {depPath}, ref deepDeps, basePath); + RecursivelyCollectDependencies(new List { depPath }, ref deepDeps, basePath, remaps); dependencies.AddRange(deepDeps); } } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Assets/BayerDither4x4.png.meta b/Packages/sh.orels.shaders.generator/Runtime/Assets/BayerDither4x4.png.meta index 98c0b0b5..3387be52 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Assets/BayerDither4x4.png.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Assets/BayerDither4x4.png.meta @@ -3,7 +3,7 @@ guid: 91b289fc86f50cf499e212aab7cd52ce TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 11 + serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 @@ -20,9 +20,12 @@ TextureImporter: externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 + flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -54,10 +57,15 @@ TextureImporter: textureType: 0 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + ignorePngGamma: 0 applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform @@ -69,6 +77,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -81,6 +90,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -93,6 +103,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -105,6 +116,33 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: @@ -120,9 +158,9 @@ TextureImporter: edges: [] weights: [] secondaryTextures: [] - spritePackingTag: + nameFileIdTable: {} + mipmapLimitGroupName: pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: diff --git a/Packages/sh.orels.shaders.generator/Runtime/Assets/DissolvePattern.png.meta b/Packages/sh.orels.shaders.generator/Runtime/Assets/DissolvePattern.png.meta index c52eb6c7..e3f37be1 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Assets/DissolvePattern.png.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Assets/DissolvePattern.png.meta @@ -3,7 +3,7 @@ guid: 6b0f7088106a26c46b15f9494b829f4a TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 11 + serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 1 @@ -20,9 +20,12 @@ TextureImporter: externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 + flipGreenChannel: 0 isReadable: 0 - streamingMipmaps: 0 + streamingMipmaps: 1 streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -54,10 +57,15 @@ TextureImporter: textureType: 0 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + ignorePngGamma: 0 applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform @@ -69,6 +77,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -81,6 +90,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -93,6 +103,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -105,6 +116,20 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 2 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: @@ -120,9 +145,9 @@ TextureImporter: edges: [] weights: [] secondaryTextures: [] - spritePackingTag: + nameFileIdTable: {} + mipmapLimitGroupName: pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: diff --git a/Packages/sh.orels.shaders.generator/Runtime/Assets/Puddles_mask.exr.meta b/Packages/sh.orels.shaders.generator/Runtime/Assets/Puddles_mask.exr.meta index ce227059..3e273b8d 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Assets/Puddles_mask.exr.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Assets/Puddles_mask.exr.meta @@ -3,7 +3,7 @@ guid: d35ed5b61e65f1045b3eb890dd6d3c71 TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 11 + serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 1 @@ -20,9 +20,12 @@ TextureImporter: externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 + flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -54,21 +57,27 @@ TextureImporter: textureType: 0 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + ignorePngGamma: 0 applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 1 + textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -81,6 +90,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -93,6 +103,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -105,6 +116,20 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: @@ -120,9 +145,9 @@ TextureImporter: edges: [] weights: [] secondaryTextures: [] - spritePackingTag: + nameFileIdTable: {} + mipmapLimitGroupName: pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: diff --git a/Packages/sh.orels.shaders.generator/Runtime/Assets/SSRNoise.png b/Packages/sh.orels.shaders.generator/Runtime/Assets/SSRNoise.png new file mode 100644 index 00000000..73b98b72 Binary files /dev/null and b/Packages/sh.orels.shaders.generator/Runtime/Assets/SSRNoise.png differ diff --git a/Packages/sh.orels.shaders.generator/Runtime/Assets/SSRNoise.png.meta b/Packages/sh.orels.shaders.generator/Runtime/Assets/SSRNoise.png.meta new file mode 100644 index 00000000..4b370531 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Assets/SSRNoise.png.meta @@ -0,0 +1,99 @@ +fileFormatVersion: 2 +guid: 297cae0750c326744b268b99c9c8140c +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 1 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 16 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders.generator/Runtime/Assets/dfg-multiscatter.exr.meta b/Packages/sh.orels.shaders.generator/Runtime/Assets/dfg-multiscatter.exr.meta index d5fdeb05..c87f9b07 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Assets/dfg-multiscatter.exr.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Assets/dfg-multiscatter.exr.meta @@ -3,7 +3,7 @@ guid: f8ddbd1e1d2a4415a10b4d48daeba743 TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 11 + serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 @@ -20,9 +20,12 @@ TextureImporter: externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 + flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -54,10 +57,15 @@ TextureImporter: textureType: 0 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + ignorePngGamma: 0 applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform @@ -69,6 +77,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -81,6 +90,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -93,6 +103,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 @@ -105,6 +116,7 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: @@ -120,9 +132,9 @@ TextureImporter: edges: [] weights: [] secondaryTextures: [] - spritePackingTag: + nameFileIdTable: {} + mipmapLimitGroupName: pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/MapBaker.meta similarity index 77% rename from Packages/com.vrchat.core.vpm-resolver/Editor.meta rename to Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/MapBaker.meta index 0f0ccc36..74a6278a 100644 --- a/Packages/com.vrchat.core.vpm-resolver/Editor.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/MapBaker.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1058b5946fb23674cad310b1f4bd5b61 +guid: 7d338facc24855446a9f512b3d7f4daa folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/MapBaker/FragmentBase.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/MapBaker/FragmentBase.orlsource new file mode 100644 index 00000000..72cd8211 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/MapBaker/FragmentBase.orlsource @@ -0,0 +1,53 @@ +%Properties() +{ + _BakerChannel("Baker Channel", Int) = 0 +} + +%Variables() +{ + int _BakerChannel; + float4 __MapBaker_MainTex_ST; +} + +%Fragment("MapBakerBlitWorkaroundFragment", -9999) +{ + void MapBakerBlitWorkaroundFragment() + { + // workaround for tiling being broken in the map baker + _MainTex_ST = __MapBaker_MainTex_ST; + } +} + +%FragmentBase("FragmentBase") +{ + void FragmentBase(MeshData d, FragmentData i, SurfaceData o, inout half4 FinalColor) + { + FinalColor.a = 1; + switch (_BakerChannel) + { + case 0: + { + FinalColor.rgb = o.Albedo; + return; + } + case 1: + { + FinalColor.r = o.Metallic; + FinalColor.g = o.Occlusion; + FinalColor.b = 1; + FinalColor.a = o.Smoothness; + return; + } + case 2: + { + float2 reconvertedNormal = o.Normal; + reconvertedNormal = reconvertedNormal * 0.5 + 0.5; + FinalColor.r = reconvertedNormal.x; + FinalColor.g = reconvertedNormal.y; + FinalColor.b = 1; + FinalColor.a = 1; + return; + } + } + } +} diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/PackageMakerWindowStyle.uss.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/MapBaker/FragmentBase.orlsource.meta similarity index 55% rename from Packages/com.vrchat.core.vpm-resolver/Editor/Resources/PackageMakerWindowStyle.uss.meta rename to Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/MapBaker/FragmentBase.orlsource.meta index 80fa1a72..5708549b 100644 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/PackageMakerWindowStyle.uss.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/MapBaker/FragmentBase.orlsource.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8dfe8fb3b6d0f3e4693553ecc1cb23dd +guid: 76f9322ecf4056e4e8faa23e71c3f2c8 ScriptedImporter: internalIDToNameTable: [] externalObjects: {} @@ -7,5 +7,4 @@ ScriptedImporter: userData: assetBundleName: assetBundleVariant: - script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} - disableValidation: 0 + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/PBR/FragmentBase.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/PBR/FragmentBase.orlsource index a5ca57b3..65682564 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/PBR/FragmentBase.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/PBR/FragmentBase.orlsource @@ -1,44 +1,143 @@ %Properties() { + UI_ShadingModeHeader("# Shading Mode", Int) = 0 + [KeywordEnum(Default, Cloth)]SHADING_MODE("Shading Mode", Int) = 0 + [Toggle(CLEARCOAT)]_ClearCoat("Add Clear Coat %ShowIf(SHADING_MODE_DEFAULT)", Int) = 0 + _ClearCoatStrength("Clear Coat Strength %ShowIf(SHADING_MODE_DEFAULT && CLEARCOAT)", Range(0,1)) = 1 + _ClearCoatSmoothness("Clear Coat Smoothness %ShowIf(SHADING_MODE_DEFAULT && CLEARCOAT)", Range(0, 1)) = 0.999 + [ToggleUI]_ClothHasCustomSheen("Custom Sheen Color %ShowIf(SHADING_MODE_CLOTH)", Int) = 0 + _ClothSheenColor("Sheen Color %ShowIf(SHADING_MODE_CLOTH && _ClothHasCustomSheen)", Color) = (0.04,0.04,0.04,1) + [ToggleUI]_ClothHasSubsurface("Add Subsurface Color %ShowIf(SHADING_MODE_CLOTH)", Int) = 0 + _ClothSubsurfaceColor("Subsurface Color %ShowIf(SHADING_MODE_CLOTH && _ClothHasSubsurface)", Color) = (1,1,1,1) + UI_AdvancedSettingsHeader("# Advanced Settings", Int) = 1 [Enum(UnityEngine.Rendering.CullMode)]_CullMode("Culling Mode", Int) = 2 + _RenderType("Render Type %RenderType(_BlendOp, _SrcBlend, _DstBlend, _BlendOpAlpha, _SrcBlendAlpha, _DstBlendAlpha, _ZWrite)", Float) = -1 + [Enum(UnityEngine.Rendering.BlendOp)]_BlendOp("Blend Operation %ShowIf(_RenderType == 4)", Int) = 0 + [Enum(UnityEngine.Rendering.BlendMode)]_SrcBlend("Source Blend %ShowIf(_RenderType == 4)", Int) = 1 + [Enum(UnityEngine.Rendering.BlendMode)]_DstBlend("Destination Blend %ShowIf(_RenderType == 4)", Int) = 0 + [Enum(UnityEngine.Rendering.BlendOp)]_BlendOpAlpha("Blend Operation Alpha %ShowIf(_RenderType == 4)", Int) = 0 + [Enum(UnityEngine.Rendering.BlendMode)]_SrcBlendAlpha("Source Blend Alpha %ShowIf(_RenderType == 4)", Int) = 1 + [Enum(UnityEngine.Rendering.BlendMode)]_DstBlendAlpha("Destination Blend Alpha %ShowIf(_RenderType == 4)", Int) = 0 + _Cutoff("Cutoff %ShowIf(_RenderType == 1)", Range(0, 1)) = 0.5 + [Toggle(SHADE_VERTEXLIGHTS)]_ShadeVertexLights("Enable Vertex Lights", Int) = 0 + UI_ShadeVertexLightsNote("?> This will enable vertex-light compatible shader variants. If you're not planning to use vertex (non-important) lights - you can keep this off to make the final shader smaller", Int) = 0 + + UI_AdvancedSettingsDepthHeader("## Depth", Int) = 1 [Enum(Off, 0, On, 1)]_ZWrite("Depth Write", Int) = 1 [Enum(UnityEngine.Rendering.CompareFunction)]_ZTest("Depth Test", Int) = 4 + UI_GSAAHeader("## GSAA", Float) = 0 [Toggle(GSAA)]_EnableGSAA("GSAA Enabled", Int) = 1 UI_GSAANote("> GSAA dramatically reduces specular aliasing", Int) = 0 _GSAAVariance("GSAA Variance %ShowIf(GSAA)", Range(0, 1)) = 0.05 _GSAAThreshold("GSAA Threshold %ShowIf(GSAA)", Range(0, 1)) = 0.1 - [Toggle(NONLINEAR_SH)]_NonlinearSH("Non-Linear Lightprobe SH", Int) = 0 + [ToggleUI]_GSAAIncludeNormalMaps("Include Normal Maps %ShowIf(GSAA)", Int) = 0 + UI_GSAAIncludeNormalMapsNote("?> GSAA calculation can include per-pixel normal maps. This can sometimes lead to a 'pixelated' look when used with sharp angle or heavily tiled normal maps. You can disable this option to only use mesh normals.", Int) = 0 + + UI_MobileTweaks("## Mobile Tweaks", Int) = 1 [Toggle(FORCE_BOX_PROJECTION)]_ForceBoxProjection("Force Box Projection", Int) = 0 + [Toggle(APPLY_COLOR_CORRECTION)]_ApplyColorCorrection("Apply Mobile Color Correction", Int) = 0 + UI_ApplyColorCorrectionNote("?> Enables in-shader color correction, useful for Mobile platforms where PostProcessing is not available", Int) = 0 + [KeywordEnum(ACES, Unreal, Uncharted)]MOBILE_TONEMAP("Mobile Tonemap Mode %ShowIf(_ApplyColorCorrection)", Int) = 0 + _ColorCorrLift("Lift %ShowIf(_ApplyColorCorrection)", Range(0, 2)) = 1 + _ColorCorrGamma("Gamma %ShowIf(_ApplyColorCorrection)", Range(0,2)) = 1.1 + _ColorCorrGain("Gain %ShowIf(_ApplyColorCorrection)", Range(0, 2)) = 1.4 + UI_LightmappingHeader("# Lightmapping", Int) = 1 UI_LightmappingDocs("[This module has documentation](https://shaders.orels.sh/docs/orl-standard/base-shader#lightmapping)", Int) = 0 - _SpecOcclusion("Specular Occlusion", Range(0, 1)) = 0.75 - _SpecularRoughnessMod("Specular Roughness Mod", Range(0, 1)) = 1 + [Toggle(NONLINEAR_SH)]_NonlinearSH("Non-Linear Lightprobe SH", Int) = 0 + _SpecOcclusion("Reflection Probe Occlusion", Range(0, 1)) = 0.25 + UI_SpecOcclusionNote("?> a.k.a. Specular Occlusion. Controls how much the reflection probe specular will be occluded by the lightmap / lightprobe diffuse", Int) = 0 + _RealtimeShadowSpecOcclusion("Realtime Shadow Specular Occlusion", Range(0, 1)) = 0 + UI_RealtimeShadowSpecularOcclusionNote("> This effect is not physically correct, it can be useful to tone down strong reflection probes in shadowed areas %ShowIf(_RealtimeShadowSpecOcclusion > 0)", Int) = 0 [Toggle(BICUBIC_LIGHTMAP)]_Bicubic("Bicubic Sampling", Int) = 0 [Toggle(BAKED_SPECULAR)]_BakedSpecular("Baked Specular", Int) = 0 + _SpecularRoughnessMod("Specular Roughness Mod %ShowIf(BAKED_SPECULAR)", Range(0, 1)) = 1 + _BakedSpecularOcclusion("Baked Specular Occlusion %ShowIf(BAKED_SPECULAR)", Range(0, 1)) = 0.75 + UI_BakedSpecularOcclusionNote("?> If the object is lightmapped: this will adjust the intensity of the lightmap specular derived from the Directional lightmap.\nIf the object is not lightmapped: this will adjust the intensity of the specular derived from lightprobes %ShowIf(BAKED_SPECULAR)", Int) = 0 + + UI_GITweaksHeader("## Global Illumination Tweaks", Int) = 0 + [ToggleUI]_BoxProjectionContactHardening("Box Projection Contact Hardening", Int) = 0 + _BoxProjectionContactHardeningStrength("Hardening Strength %ShowIf(_BoxProjectionContactHardening)", Range(0, 1)) = 1 + UI_BoxProjectionContactHardeningNote("?> This will make the box projected reflections more visible closer to the surface. This creates more accurate looking reflections, especially on rougher materials", Int) = 0 + _GIEmissiveBoost("GI Emissive Boost", Float) = 1 + [ToggleUI]_IgnoreRealtimeGI("Ignore Relatime GI", Int) = 0 + UI_IgnoreRealtimeGINote("?> This will make the material ignore Unity Realtime GI system. It does not affect custom RTGI systems like LTCGI", Int) = 0 + [ToggleUI]_RealtimeGIDisableBicubic("Disable Bicubic for RTGI %ShowIf(BICUBIC_LIGHTMAP)", Int) = 0 + UI_BakeryHeader("## Bakery Features", Int) = 0 [Toggle(BAKERY_ENABLED)]_BakeryEnabled("Enable Bakery Features", Int) = 0 [KeywordEnum(None, MONOSH, SH, RNM)]BAKERY("Bakery Mode %ShowIf(BAKERY_ENABLED)", Int) = 0 [Toggle(BAKERY_SHNONLINEAR)]_BakerySHNonLinear("Bakery Non-Linear SH %ShowIf(BAKERY_ENABLED)", Int) = 1 + [Toggle(BAKERY_VOLUME)]_BakeryVolume("Support Volumes %ShowIf(BAKERY_ENABLED)", Int) = 0 + UI_BakeryVolumeAssigner("Volume Assigner %ShowIf(BAKERY_ENABLED && BAKERY_VOLUME) %BakeryVolumeAssigner()", Int) = 0 + [Toggle(BAKERY_COMPRESSED_VOLUME)]_BakeryCompressedVolume("Support Compressed Volumes %ShowIf(BAKERY_ENABLED && BAKERY_VOLUME)", Int) = 0 + [Toggle(BAKERY_VOLROTATIONY)]_BakeryVolumeRotationY("Support Baked Volume Rotation %ShowIf(BAKERY_ENABLED && BAKERY_VOLUME)", Int) = 0 + [Toggle(BAKERY_VOLROTATION)]_BakeryVolumeRotation("Support Runtime Volume Rotation %ShowIf(BAKERY_ENABLED && BAKERY_VOLUME)", Int) = 0 + UI_BakeryVolumeRotationNote("> Volume rotation support requires extra scripting in VRChat %ShowIf(BAKERY_ENABLED && BAKERY_VOLUME && (BAKERY_VOLROTATION || BAKERY_VOLROTATIONY))", Int) = 0 + + UI_AdvancedSettingsStancilHeader("# Stencils", Int) = 0 + [IntRange]_StencilRef("Reference", Range(0, 255)) = 0 + [Enum(UnityEngine.Rendering.CompareFunction)]_StencilComp("Comparison", Float) = 8 + [Enum(UnityEngine.Rendering.StencilOp)]_StencilPassOp("Pass Operation", Float) = 0 + [Enum(UnityEngine.Rendering.StencilOp)]_StencilFailOp("Fail Operation", Float) = 0 + [Enum(UnityEngine.Rendering.StencilOp)]_StencilZFailOp("ZFail Operation", Float) = 0 + UI_InternalHeader("# Internal", Int) = 0 + [HideInInspector]INTERNAL_ShaderVersion("Shader Version", Int) = 700 + [HideInInspector]INTERNAL_MaterialShaderVersion("Material Shader Version", Int) = 0 [NonModifiableTextureData]_DFG("DFG > %RequiredTexture(@/dfg-multiscatter.exr)", 2D) = "white" {} + + UI_BakerySHHeader("## Bakery SH", Int) = 0 _RNM0("RNM0 >", 2D) = "white" {} _RNM1("RNM1 >", 2D) = "white" {} _RNM2("RNM2 >", 2D) = "white" {} + + UI_BakeryVolumesHeader("## Bakery Volumes", Int) = 0 + _Volume0("Volume 0 >", 3D) = "white" {} + _Volume1("Volume 1 >", 3D) = "white" {} + _Volume2("Volume 2 >", 3D) = "white" {} + _Volume3("Volume 3 >", 3D) = "white" {} + _VolumeMask("Volume Mask >", 3D) = "white" {} + _VolumeMin("Volume min", Vector) = (0,0,0) + _VolumeInvSize("Volume Inv Size", Vector) = (1000001, 1000001, 1000001) } %ShaderFeatures() { - #pragma shader_feature_local BICUBIC_LIGHTMAP - #pragma shader_feature_local BAKED_SPECULAR - #pragma shader_feature_local GSAA - #pragma shader_feature_local FORCE_BOX_PROJECTION - #pragma shader_feature_local NONLINEAR_SH + #pragma shader_feature_local_fragment BAKED_SPECULAR + #pragma shader_feature_local_fragment GSAA + #pragma shader_feature_local_fragment NONLINEAR_SH + #pragma shader_feature_local_fragment SHADE_VERTEXLIGHTS + #pragma shader_feature_local_fragment SHADING_MODE_DEFAULT SHADING_MODE_CLOTH + #pragma shader_feature_local_fragment CLEARCOAT + + // PC Only Features + #if !defined(UNITY_PBS_USE_BRDF2) && !defined(SHADER_API_MOBILE) + #pragma shader_feature_local_fragment BICUBIC_LIGHTMAP + #endif + + // Mobile Only Features + #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) + #pragma shader_feature_local_fragment FORCE_BOX_PROJECTION + #pragma shader_feature_local_fragment APPLY_COLOR_CORRECTION + #pragma shader_feature_local_fragment MOBILE_TONEMAP_ACES MOBILE_TONEMAP_UNREAL MOBILE_TONEMAP_UNCHARTED + #endif + + #if defined(SHADE_VERTEXLIGHTS) + #pragma multi_compile_fragment _ VERTEXLIGHT_ON + #endif + + #if !defined(MOBILE_TONEMAP_ACES) && !defined(MOBILE_TONEMAP_UNREAL) && !defined(MOBILE_TONEMAP_UNCHARTED) + #define MOBILE_TONEMAP_ACES + #endif } %ShaderDefines() { + #define ORL_LIGHTING_MODEL_PBR + #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) #define PLAT_QUEST #else @@ -47,15 +146,68 @@ #endif #endif + #define ORL_MIN_ROUGHNESS 0.002025 + #if defined(PLAT_QUEST) + #define ORL_MIN_ROUGHNESS 0.007921 + #endif + + #if !defined(SHADING_MODE_DEFAULT) && !defined(SHADING_MODE_CLOTH) + #define SHADING_MODE_DEFAULT + #endif + #define NEED_SCREEN_POS + #if !defined(NEED_FRAGMENT_IN_SHADOW) + #define NEED_FRAGMENT_IN_SHADOW + #endif +} + +%ShaderModifiers() +{ + Stencil + { + Ref [_StencilRef] + Comp [_StencilComp] + Pass [_StencilPassOp] + Fail [_StencilFailOp] + ZFail [_StencilZFailOp] + } + + ZTest[_ZTest] + ZWrite[_ZWrite] + Cull[_CullMode] + BlendOp [_BlendOp], [_BlendOpAlpha] + Blend [_SrcBlend] [_DstBlend], [_SrcBlendAlpha] [_DstBlendAlpha] } %Variables() { half _GSAAVariance; half _GSAAThreshold; + int _GSAAIncludeNormalMaps; + half _ColorCorrLift; + half _ColorCorrGamma; + half _ColorCorrGain; + + half _ClearCoatStrength; + float _ClearCoatSmoothness; + int _ClothHasCustomSheen; + half4 _ClothSheenColor; + int _ClothHasSubsurface; + half4 _ClothSubsurfaceColor; + half _SpecOcclusion; + half _RealtimeShadowSpecOcclusion; + float _BakedSpecularOcclusion; half _SpecularRoughnessMod; + + int _BoxProjectionContactHardening; + half _BoxProjectionContactHardeningStrength; + half _GIEmissiveBoost; + int _IgnoreRealtimeGI; + int _RealtimeGIDisableBicubic; + + int _RenderType; + half _Cutoff; } %Textures() @@ -78,53 +230,205 @@ #if defined(UNITY_PASS_SHADOWCASTER) return; #else + half reflectance = 0.5; - half3 f0 = 0.16 * reflectance * reflectance * (1 - o.Metallic) + o.Albedo * o.Metallic; - half3 pixelLight = 0; + float oneMinusReflectivity = 1.0 - 0.04 - o.Metallic * (1.0 - 0.04); + half3 f0 = 0.16 * reflectance * reflectance * oneMinusReflectivity + o.Albedo * o.Metallic; + half3 indirectDiffuse = 1; half3 indirectSpecular = 0; - half3 directSpecular = 0; + half occlusion = o.Occlusion; + half perceptualRoughness = 1 - o.Smoothness; - half3 tangentNormal = o.Normal; - o.Normal = normalize(mul(o.Normal, d.TBNMatrix)); + + float3 tangentNormal = o.Normal; + + #if defined(SHADING_MODE_CLOTH) + half3 albedoSqrt = sqrt(o.Albedo); + #endif + + o.Normal = Unity_SafeNormalize(mul(o.Normal, d.TBNMatrix)); #ifndef USING_DIRECTIONAL_LIGHT - fixed3 lightDir = normalize(UnityWorldSpaceLightDir(d.worldSpacePosition)); + float3 lightDir = Unity_SafeNormalize(UnityWorldSpaceLightDir(d.worldSpacePosition)); #else - fixed3 lightDir = _WorldSpaceLightPos0.xyz; + float3 lightDir = Unity_SafeNormalize(_WorldSpaceLightPos0.xyz); #endif #if defined(GSAA) - perceptualRoughness = GSAA_Filament(o.Normal, perceptualRoughness, _GSAAVariance, _GSAAThreshold); + perceptualRoughness = GSAA_Filament(_GSAAIncludeNormalMaps ? o.Normal : d.worldNormal, perceptualRoughness, _GSAAVariance, _GSAAThreshold); #endif UNITY_LIGHT_ATTENUATION(lightAttenuation, i, d.worldSpacePosition); half3 lightColor = lightAttenuation * _LightColor0.rgb; - half3 lightHalfVector = Unity_SafeNormalize(lightDir + d.worldSpaceViewDir); + float3 lightHalfVector = Unity_SafeNormalize(lightDir + d.worldSpaceViewDir); half lightNoL = saturate(dot(o.Normal, lightDir)); half lightLoH = saturate(dot(lightDir, lightHalfVector)); half NoV = abs(dot(o.Normal, d.worldSpaceViewDir)) + 1e-5; - pixelLight = lightNoL * lightColor * Fd_Burley(perceptualRoughness, NoV, lightNoL, lightLoH); + + // Standard BRDF Setup + half3 dfguv = half3(NoV, perceptualRoughness, 0); + float2 dfg = SAMPLE_TEXTURE2D(_DFG, sampler_DFG, dfguv).xy; + half3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0); + + float rough = perceptualRoughness * perceptualRoughness; + half clampedRoughness = max(rough, ORL_MIN_ROUGHNESS); + + // Clear Coat BRDF Setup + #if defined(CLEARCOAT) + half3 clearcoatdfguv = 0; + float2 clearcoatdfg = 0; + + float clearCoatAttenuation = 1.0; + float clearCoatRoughness = 1.0 - _ClearCoatSmoothness; + half clampedClearCoatRoughness = max(clearCoatRoughness * clearCoatRoughness, ORL_MIN_ROUGHNESS); + half3 clearCoatMainLightSpecular = 0; + half3 clearCoatIndirectSpecular = 0; + #endif + + half3 mainLightDiffuse = 0; + half3 mainLightSpecular = 0; + + mainLightDiffuse = Fd_Burley(perceptualRoughness, NoV, lightNoL, lightLoH); + + #if defined(SHADING_MODE_CLOTH) + { + if (_ClothHasSubsurface) + { + mainLightDiffuse *= Fd_Wrap(dot(o.Normal, lightDir), 0.5); + mainLightDiffuse *= saturate(_ClothSubsurfaceColor.rgb + lightNoL); + } else { + mainLightDiffuse *= lightNoL; + } + mainLightDiffuse *= lightColor; + } + #else + mainLightDiffuse *= lightColor * lightNoL; + #endif + + + // Collect Vertex Light Data and calculate direct diffuse + #if defined(SHADE_VERTEXLIGHTS) &&defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + float4x4 vLightColors = getVertexLightsColors(d.worldSpacePosition, o.Normal, false); + float4x4 vLightDirections = getVertexLightsDir(d.worldSpacePosition); + float4x4 vLightHalfVectors = 0; + float4 vLightNoLs = 0; + float4 vLightLoHs = 0; + + half3 vertexLightDiffuse = 0; + half3 vertexLightSpecular = 0; + half3 clearCoatVertexLightSpecular = 0; + + [unroll(4)] + for (int i = 0; i < 4; i++) + { + vLightHalfVectors[i].rgb = Unity_SafeNormalize(vLightDirections[i] + d.worldSpaceViewDir); + vLightLoHs[i] = saturate(dot(vLightDirections[i], vLightHalfVectors[i])); + vLightNoLs[i] = saturate(dot(o.Normal, vLightDirections[i])); + + half3 vLightDiffuse = Fd_Burley(perceptualRoughness, NoV, vLightNoLs[i], vLightLoHs[i]); + + #if defined(SHADING_MODE_CLOTH) + { + if (_ClothHasSubsurface) + { + vLightColors[i].rgb *= Fd_Wrap(dot(o.Normal, vLightDirections[i]), 0.5); + vLightColors[i].rgb *= saturate(_ClothSubsurfaceColor.rgb + vLightNoLs[i]); + } else { + vLightDiffuse *= vLightNoLs[i]; + } + vLightDiffuse *= vLightColors[i]; + } + #else + vLightDiffuse *= vLightColors[i] * vLightNoLs[i]; + #endif + + vertexLightDiffuse += vLightDiffuse; + } + #endif + + // https://assetstore.unity.com/packages/tools/level-design/bakery-gpu-lightmapper-122218 + #if defined(BAKERY_ENABLED) && defined(BAKERY_VOLUME) + BakeryVolumeData volumeData = (BakeryVolumeData) 0; + + if (_Udon_GlobalVolumeAdapterEnabled == 1) + { + _GlobalVolumeMin = _Udon_GlobalVolumeMin; + _GlobalVolumeInvSize = _Udon_GlobalVolumeInvSize; + + // Arbitrary rotation (runtime only) + #if defined(BAKERY_VOLROTATION) + _GlobalVolumeMatrix = _Udon_GlobalVolumeMatrix; + #endif + + // Y Rotation (baked) + #if defined(BAKERY_VOLROTATIONY) + _GlobalVolumeRY = _Udon_GlobalVolumeRY; + #endif + } + + bool isGlobalVolume = _VolumeInvSize.x > 1000000; // ~inf + volumeData.viewDir = Unity_SafeNormalize(d.worldSpaceViewDir); + + // Runtime volume rotation + // Requires a special adapter to work in VRChat + #if defined(BAKERY_VOLROTATION) + float4x4 volMatrix = (isGlobalVolume ? _GlobalVolumeMatrix : _VolumeMatrix); + float3 volInvSize = (isGlobalVolume ? _GlobalVolumeInvSize : _VolumeInvSize); + volumeData.uv = mul(volMatrix, float4(d.worldSpacePosition,1)).xyz * volInvSize + 0.5f; + + volumeData.normal = mul((float3x3)volMatrix, o.Normal); + volumeData.normal = Unity_SafeNormalize(volumeData.normal); + + #if defined(BAKED_SPECULAR) + volumeData.viewDir = mul((float3x3)volMatrix, volumeData.viewDir); + #endif + #else + volumeData.uv = d.worldSpacePosition - (isGlobalVolume ? _GlobalVolumeMin : _VolumeMin); + #if defined(BAKERY_VOLROTATIONY) + float2 sc = (isGlobalVolume ? _GlobalVolumeRY : _VolumeRY); + volumeData.uv.xz = mul(float2x2(sc.y, -sc.x, sc.x, sc.y), volumeData.uv.xz); + #endif + volumeData.uv *= (isGlobalVolume ? _GlobalVolumeInvSize : _VolumeInvSize); + volumeData.normal = o.Normal; + #endif + + volumeData.occlusion = saturate(dot(_VolumeMask.Sample(sampler_VolumeMask, volumeData.uv), unity_OcclusionMaskSelector)); + + lightColor *= volumeData.occlusion; + mainLightDiffuse *= volumeData.occlusion; + + #if defined(SHADE_VERTEXLIGHTS) &&defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + { + vertexLightDiffuse *= volumeData.occlusion; + } + #endif + + #endif // READ THE LIGHTMAP - #if defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) + // Can be Baked, Realtime, both or either + #if (defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)) && !defined(UNITY_PASS_FORWARDADD) half3 lightMap = 0; half4 bakedColorTex = 0; half2 lightmapUV = d.lightmapUv.xy; + // explicitly checking for lightmap on because we can be in rtgi only mode + #if defined(LIGHTMAP_ON) + // UNITY LIGHTMAPPING #if !defined(BAKERYLM_ENABLED) || !defined(BAKERY_ENABLED) lightMap = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); #endif - // BAKERY RNM MODE (why do we even support it??) + // BAKERY RNM MODE #if defined(BAKERY_RNM) && defined(BAKERY_ENABLED) - half3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, sampler_RNM0, lightmapUV, _RNM0_TexelSize)); - half3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, sampler_RNM0, lightmapUV, _RNM0_TexelSize)); - half3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, sampler_RNM0, lightmapUV, _RNM0_TexelSize)); + float3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, sampler_RNM0, lightmapUV, _RNM0_TexelSize)); + float3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, sampler_RNM0, lightmapUV, _RNM0_TexelSize)); + float3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, sampler_RNM0, lightmapUV, _RNM0_TexelSize)); lightMap = saturate(dot(rnmBasis0, tangentNormal)) * rnm0 + saturate(dot(rnmBasis1, tangentNormal)) * rnm1 + @@ -158,6 +462,7 @@ #endif #endif + // Load directional lightmap #if defined(DIRLIGHTMAP_COMBINED) half4 lightMapDirection = tex2DFastBicubicSample(unity_LightmapInd, samplerunity_Lightmap, lightmapUV); #if !defined(BAKERY_MONOSH) @@ -172,6 +477,7 @@ lightMap = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); #endif + // Bakery MonoSH handling #if defined(BAKERY_MONOSH) && defined(BAKERY_ENABLED) && defined(DIRLIGHTMAP_COMBINED) half3 L0 = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); half3 nL1 = lightMapDirection.xyz * 2.0 - 1.0; @@ -196,78 +502,163 @@ lightMap = max(lightMap, 0.0); #endif - #if defined(DYNAMICLIGHTMAP_ON) && !defined(UNITY_PBS_USE_BRDF2) - half3 realtimeLightMap = getRealtimeLightmap(d.lightmapUv.zw, o.Normal); - lightMap += realtimeLightMap; + #endif // defined(LIGHTMAP_ON) + + // Handle RTGI specifically + #if defined(DYNAMICLIGHTMAP_ON) && !defined(PLAT_QUEST) + // only branch on non-meta passes + #if !defined(UNITY_PASS_META) + { + [branch] + if (!_IgnoreRealtimeGI) { + half3 realtimeLightMap = getRealtimeLightmap(d.lightmapUv.zw, o.Normal, _RealtimeGIDisableBicubic); + lightMap += realtimeLightMap; + } + } + #else + { + half3 realtimeLightMap = getRealtimeLightmap(d.lightmapUv.zw, o.Normal); + lightMap += realtimeLightMap; + } + #endif #endif #if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) - pixelLight = 0; + mainLightDiffuse = 0; lightMap = SubtractMainLightWithRealtimeAttenuationFromLightmapMultiply(lightMap, lightAttenuation, bakedColorTex, o.Normal); #endif + indirectDiffuse = lightMap; + // Lightmapping end + + // Bakery Volume Sampling (replaces probes and LPPVs) + #elif defined(BAKERY_ENABLED) && defined(BAKERY_VOLUME) && defined(UNITY_PASS_FORWARDBASE) + // Sample the volume textures + volumeData = GetBakeryVolumeTextureData(volumeData); + // Sample using Geomerics approach, similar to lightprobes and LPPVs + indirectDiffuse = max(0, GetNonLinearSH( + volumeData.L0, + float3(volumeData.L1x.r, volumeData.L1y.r, volumeData.L1z.r), + float3(volumeData.L1x.g, volumeData.L1y.g, volumeData.L1z.g), + float3(volumeData.L1x.b, volumeData.L1y.b, volumeData.L1z.b), + volumeData.normal) + ); + // Lightprobes Sampling #else // LPPV support #if UNITY_LIGHT_PROBE_PROXY_VOLUME - UNITY_BRANCH - if (unity_ProbeVolumeParams.x == 1) { - indirectDiffuse = SHEvalLinearL0L1_SampleProbeVolume(half4(o.Normal, 1), d.worldSpacePosition); + UNITY_BRANCH + if (unity_ProbeVolumeParams.x == 1) + { + indirectDiffuse = SHEvalLinearL0L1_SampleProbeVolume(half4(o.Normal, 1), d.worldSpacePosition); + } + else // Mesh has BlendProbes instead of LPPV + { + #if defined(NONLINEAR_SH) + { + half3 L0 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); + half3 L0L2 = half3(unity_SHBr.z, unity_SHBg.z, unity_SHBb.z) / 3.0; + L0 = L0+L0L2; + indirectDiffuse = max(0, GetNonLinearSH(L0, unity_SHAr, unity_SHAg, unity_SHAb, o.Normal)); + indirectDiffuse += SHEvalLinearL2(float4(o.Normal, 1)); + } + #else + { + indirectDiffuse = max(0, ShadeSH9(half4(o.Normal, 1))); + } + #endif + } } - else // Mesh has BlendProbes instead of LPPV + #else // No LPPVs enabled project-wide { #if defined(NONLINEAR_SH) - half3 L0 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); - indirectDiffuse.r = shEvaluateDiffuseL1Geomerics(L0.r, unity_SHAr.xyz, o.Normal); - indirectDiffuse.g = shEvaluateDiffuseL1Geomerics(L0.g, unity_SHAg.xyz, o.Normal); - indirectDiffuse.b = shEvaluateDiffuseL1Geomerics(L0.b, unity_SHAb.xyz, o.Normal); - indirectDiffuse = max(0, indirectDiffuse); + { + half3 L0 = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); + half3 L0L2 = half3(unity_SHBr.z, unity_SHBg.z, unity_SHBb.z) / 3.0; + L0 = L0+L0L2; + indirectDiffuse = max(0, GetNonLinearSH(L0, unity_SHAr, unity_SHAg, unity_SHAb, o.Normal)); + indirectDiffuse += SHEvalLinearL2(float4(o.Normal, 1)); + } #else - indirectDiffuse = max(0, ShadeSH9(half4(o.Normal, 1))); + { + indirectDiffuse = max(0, ShadeSH9(half4(o.Normal, 1))); + } #endif } - #else // No LPPVs enabled project-wide - - #if defined(NONLINEAR_SH) - half3 L0 = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); - indirectDiffuse.r = shEvaluateDiffuseL1Geomerics(L0.r, unity_SHAr.xyz, o.Normal); - indirectDiffuse.g = shEvaluateDiffuseL1Geomerics(L0.g, unity_SHAg.xyz, o.Normal); - indirectDiffuse.b = shEvaluateDiffuseL1Geomerics(L0.b, unity_SHAb.xyz, o.Normal); - indirectDiffuse = max(0, indirectDiffuse); - #else - indirectDiffuse = max(0, ShadeSH9(half4(o.Normal, 1))); - #endif - #endif #endif // end of #if defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) #if defined(LIGHTMAP_SHADOW_MIXING) && defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) && defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) - pixelLight *= UnityComputeForwardShadows(d.lightmapUv.xy, d.worldSpacePosition, d.screenPos); + { + float3 forwardShadows = UnityComputeForwardShadows(d.lightmapUv.xy, d.worldSpacePosition, d.screenPos); + mainLightDiffuse *= forwardShadows; + } #endif + #if defined(CLEARCOAT) && defined(SHADING_MODE_DEFAULT) + clearcoatdfguv = half3(NoV, clearCoatRoughness, 0); + clearcoatdfg = SAMPLE_TEXTURE2D(_DFG, sampler_DFG, clearcoatdfguv).xy; + #endif - half3 dfguv = half3(NoV, perceptualRoughness, 0); - half2 dfg = SAMPLE_TEXTURE2D(_DFG, sampler_DFG, dfguv).xy; - half3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0); - - half rough = perceptualRoughness * perceptualRoughness; - half clampedRoughness = max(rough, 0.002); - + // DIRECT REALTIME SPECULAR #if !defined(SPECULAR_HIGHLIGHTS_OFF) && defined(USING_LIGHT_MULTI_COMPILE) - half NoH = saturate(dot(o.Normal, lightHalfVector)); - half3 F = F_Schlick(lightLoH, f0); - half D = D_GGX(NoH, clampedRoughness); - half V = V_SmithGGXCorrelated(NoV, lightNoL, clampedRoughness); + { + // Main Light + { + #if defined(SHADING_MODE_DEFAULT) + { + mainLightSpecular = GetSpecularHighlights(lightColor, f0, o.Normal, lightHalfVector, lightLoH, lightNoL, NoV, clampedRoughness, energyCompensation); + } + #elif defined(SHADING_MODE_CLOTH) + { + mainLightSpecular = GetSpecularHighlightsCloth(lightColor, o.Normal, lightHalfVector, lightNoL, NoV, clampedRoughness, energyCompensation, albedoSqrt, _ClothHasCustomSheen, _ClothSheenColor); + } + #endif + + mainLightSpecular *= lightNoL; - F *= energyCompensation; + #if defined(CLEARCOAT) && defined(SHADING_MODE_DEFAULT) + { + clearCoatMainLightSpecular = GetSpecularHighlightsClearCoat(lightColor, f0, d.worldNormal, lightHalfVector, lightLoH, clampedClearCoatRoughness, _ClearCoatStrength, clearCoatAttenuation); + clearCoatMainLightSpecular *= saturate(dot(d.worldNormal, lightDir)); + } + #endif + } - directSpecular = max(0, D * V * F) * pixelLight * UNITY_PI; + // Vertex Lights + #if defined(SHADE_VERTEXLIGHTS) && defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + { + [unroll(4)] + for (int i = 0; i < 4; i++) + { + #if defined(SHADING_MODE_DEFAULT) + { + vertexLightSpecular += vLightNoLs[i] * GetSpecularHighlights(vLightColors[i], f0, o.Normal, vLightHalfVectors[i], vLightLoHs[i], vLightNoLs[i], NoV, clampedRoughness, energyCompensation); + } + #elif defined(SHADING_MODE_CLOTH) + { + vertexLightSpecular += vLightNoLs[i] * GetSpecularHighlightsCloth(vLightColors[i], o.Normal, vLightHalfVectors[i], vLightNoLs[i], NoV, clampedRoughness, energyCompensation, albedoSqrt, _ClothHasCustomSheen, _ClothSheenColor); + } + #endif + + // Clear Coat + #if defined(CLEARCOAT) && defined(SHADING_MODE_DEFAULT) + { + clearCoatVertexLightSpecular += GetSpecularHighlightsClearCoat(vLightColors[i], f0, d.worldNormal, vLightHalfVectors[i], vLightLoHs[i], clampedClearCoatRoughness, _ClearCoatStrength, clearCoatAttenuation) * saturate(dot(d.worldNormal, vLightDirections[i])); + } + #endif + } + } + #endif + } #endif // BAKED SPECULAR - #if defined(BAKED_SPECULAR) && !defined(BAKERYLM_ENABLED) && !defined(UNITY_PASS_FORWARDADD) + half3 bakedDirectSpecular = 0; + #if defined(BAKED_SPECULAR) && !defined(BAKERYLM_ENABLED) && defined(UNITY_PASS_FORWARDBASE) { half3 bakedDominantDirection = 1; half3 bakedSpecularColor = 0; @@ -287,29 +678,49 @@ #endif bakedDominantDirection = normalize(bakedDominantDirection); - directSpecular += GetSpecularHighlights(o.Normal, bakedSpecularColor, bakedDominantDirection, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); + #if defined(SHADING_MODE_DEFAULT) + { + bakedDirectSpecular = GetSpecularHighlights(o.Normal, bakedSpecularColor, bakedDominantDirection, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); + } + #elif defined(SHADING_MODE_CLOTH) + { + bakedDirectSpecular = GetSpecularHighlightsCloth(o.Normal, bakedSpecularColor, bakedDominantDirection, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, albedoSqrt, _ClothHasCustomSheen, _ClothSheenColor); + } + #endif } #endif - half3 fresnel = F_Schlick(NoV, f0); - // BAKERY DIRECT SPECULAR - #if defined(LIGHTMAP_ON) && defined(BAKERY_LMSPEC) && defined(BAKERY_ENABLED) && !defined(UNITY_PASS_FORWARDADD) + #if defined(LIGHTMAP_ON) && defined(BAKERY_LMSPEC) && defined(BAKERY_ENABLED) && defined(UNITY_PASS_FORWARDBASE) #if defined(BAKERY_RNM) { - half3 viewDirTangent = -normalize(d.tangentSpaceViewDir); - half3 dominantDirTangent = rnmBasis0 * dot(rnm0, lumaConv) + + float3 viewDirTangent = -Unity_SafeNormalize(d.tangentSpaceViewDir); + float3 dominantDirTangent = rnmBasis0 * dot(rnm0, lumaConv) + rnmBasis1 * dot(rnm1, lumaConv) + rnmBasis2 * dot(rnm2, lumaConv); - half3 dominantDirTangentNormalized = normalize(dominantDirTangent); + float3 dominantDirTangentNormalized = Unity_SafeNormalize(dominantDirTangent); + half3 specColor = saturate(dot(rnmBasis0, dominantDirTangentNormalized)) * rnm0 + saturate(dot(rnmBasis1, dominantDirTangentNormalized)) * rnm1 + saturate(dot(rnmBasis2, dominantDirTangentNormalized)) * rnm2; - half3 halfDir = Unity_SafeNormalize(dominantDirTangentNormalized - viewDirTangent); - half NoH = saturate(dot(tangentNormal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - directSpecular += spec * specColor * fresnel; + + float3 halfVector = Unity_SafeNormalize(dominantDirTangentNormalized - viewDirTangent); + float NoH = saturate(dot(tangentNormal, halfVector)); + half3 F = 0 + float D = 0; + #if defined(SHADING_MODE_DEFAULT) + { + F = F_Schlick(NoV, f0); + D = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)) * energyCompensation; + } + #elif defined(SHADING_MODE_CLOTH) + { + F = _ClothHasCustomSheen ? _ClothSheenColor : albedoSqrt; + D = D_Charlie(lerp(1, clampedRoughness, _SpecularRoughnessMod), NoH); + } + #endif + bakedDirectSpecular += D * specColor * F; } #endif @@ -318,7 +729,15 @@ half3 dominantDir = half3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(L1z, lumaConv)); half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; dominantDir = normalize(dominantDir); - directSpecular += GetSpecularHighlights(o.Normal, sh, dominantDir, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); + #if defined(SHADING_MODE_DEFAULT) + { + bakedDirectSpecular += GetSpecularHighlights(o.Normal, sh, dominantDir, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); + } + #elif defined(SHADING_MODE_CLOTH) + { + bakedDirectSpecular += GetSpecularHighlightsCloth(o.Normal, sh, dominantDir, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, albedoSqrt, _ClothHasCustomSheen, _ClothSheenColor); + } + #endif } #endif @@ -327,50 +746,253 @@ half3 dominantDir = nL1; half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; dominantDir = normalize(dominantDir); - directSpecular += GetSpecularHighlights(o.Normal, sh, dominantDir, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); + #if defined(SHADING_MODE_DEFAULT) + { + bakedDirectSpecular += GetSpecularHighlights(o.Normal, sh, dominantDir, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); + } + #elif defined(SHADING_MODE_CLOTH) + { + bakedDirectSpecular += GetSpecularHighlightsCloth(o.Normal, sh, dominantDir, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, albedoSqrt, _ClothHasCustomSheen, _ClothSheenColor); + } + #endif } #endif #endif // End of #if defined(BAKERY_LMSPEC) && defined(BAKERY_ENABLED) && !defined(UNITY_PASS_FORWARDADD) + // BAKERY VOLUME SPECULAR + #if defined(BAKERY_ENABLED) && defined(BAKERY_VOLUME) && defined(BAKERY_LMSPEC) && defined(UNITY_PASS_FORWARDBASE) + BakeryVolumeSpecularData volumeSpecularData = GetBakeryVolumeSpecularData(volumeData); + #if defined(SHADING_MODE_DEFAULT) + { + bakedDirectSpecular += GetSpecularHighlights(volumeData.normal, volumeSpecularData.color, volumeSpecularData.direction, f0, volumeData.viewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), volumeSpecularData.NoV, energyCompensation); + } + #elif defined(SHADING_MODE_CLOTH) + { + bakedDirectSpecular += GetSpecularHighlightsCloth(volumeData.normal, volumeSpecularData.color, volumeSpecularData.direction, f0, volumeData.viewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), volumeSpecularData.NoV, albedoSqrt, _ClothHasCustomSheen, _ClothSheenColor); + } + #endif + #endif + // REFLECTIONS #if !defined(UNITY_PASS_FORWARDADD) - half3 reflDir = reflect(-d.worldSpaceViewDir, o.Normal); - reflDir = lerp(reflDir, o.Normal, clampedRoughness); - - Unity_GlossyEnvironmentData envData; - envData.roughness = perceptualRoughness; - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); + float3 reflDir = reflect(-d.worldSpaceViewDir, o.Normal); - half3 probe0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData); - indirectSpecular = probe0; - - #if defined(UNITY_SPECCUBE_BLENDING) || defined(FORCE_BOX_PROJECTION) - UNITY_BRANCH - if (unity_SpecCube0_BoxMin.w < 0.99999) + // Box projection contact hardening is only available on PC + #if !defined(PLAT_QUEST) + { + // This is based on David M's improved box projection code https://github.com/frostbone25/Unity-Improved-Box-Projected-Reflections + // Licensed under MIT license, see https://github.com/frostbone25/Unity-Improved-Box-Projected-Reflections/blob/master/LICENSE for details + // Only used if probe is set to be box projected + if (_BoxProjectionContactHardening && unity_SpecCube0_ProbePosition.w > 0) + { + indirectSpecular = getEnvReflectionHardened(reflDir, d.worldSpacePosition, perceptualRoughness, _BoxProjectionContactHardeningStrength); + } else { + indirectSpecular = getEnvReflectionDirect(reflDir, d.worldSpacePosition, o.Normal, perceptualRoughness, -1); + } + } + #else { - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half3 probe1 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0), unity_SpecCube1_HDR, envData); - indirectSpecular = lerp(probe1, probe0, unity_SpecCube0_BoxMin.w); + indirectSpecular = getEnvReflectionDirect(reflDir, d.worldSpacePosition, o.Normal, perceptualRoughness, -1); } #endif half horizon = min(1 + dot(reflDir, o.Normal), 1); indirectSpecular *= horizon * horizon; - half specularOcclusion = saturate(length(indirectDiffuse) * (1.0 / _SpecOcclusion)); - dfg.x *= specularOcclusion; - specularOcclusion = computeSpecularAO(NoV, o.Occlusion, clampedRoughness); + #if defined(CLEARCOAT) && defined(SHADING_MODE_DEFAULT) + { + // Clear Coat uses a different roughness and a mesh normal instead of the normal map + reflDir = reflect(-d.worldSpaceViewDir, d.worldNormal); + + // Box projection contact hardening is only available on PC + #if !defined(PLAT_QUEST) + { + // This is based on David M's improved box projection code https://github.com/frostbone25/Unity-Improved-Box-Projected-Reflections + // Licensed under MIT license, see https://github.com/frostbone25/Unity-Improved-Box-Projected-Reflections/blob/master/LICENSE for details + // Only used if probe is set to be box projected + if (_BoxProjectionContactHardening && unity_SpecCube0_ProbePosition.w > 0) + { + clearCoatIndirectSpecular = getEnvReflectionHardened(reflDir, d.worldSpacePosition, clearCoatRoughness, _BoxProjectionContactHardeningStrength); + } else { + clearCoatIndirectSpecular = getEnvReflectionDirect(reflDir, d.worldSpacePosition, d.worldNormal, clearCoatRoughness, -1); + } + } + #else + { + clearCoatIndirectSpecular = getEnvReflectionDirect(reflDir, d.worldSpacePosition, d.worldNormal, clearCoatRoughness, -1); + } + #endif + + half clearCoatHorizon = min(1 + dot(reflDir, d.worldNormal), 1); + clearCoatIndirectSpecular *= clearCoatHorizon * clearCoatHorizon; + clearCoatIndirectSpecular *= _ClearCoatStrength; + } + #endif + + half indirectSpecularOcclusion = saturate(length(indirectDiffuse) * (1.0 / _SpecOcclusion)); + + // We should only add dfg _after_ we calculated spec occlusion factors + half3 envBRDF = EnvBRDFMultiscatter(dfg, f0); + indirectDiffuse *= 1.0 - envBRDF; + indirectSpecular *= envBRDF; + + indirectSpecularOcclusion *= lerp(1, lightAttenuation, _RealtimeShadowSpecOcclusion); + + half computedSpecularOcclusion = computeSpecularAO(NoV, o.Occlusion * indirectSpecularOcclusion, clampedRoughness); + computedSpecularOcclusion *= energyCompensation; + + #if defined(BAKED_SPECULAR) + { + bakedDirectSpecular *= saturate(lerp(1, computedSpecularOcclusion, _BakedSpecularOcclusion)); + } + #endif + + indirectSpecular *= gtaoMultiBounce(computedSpecularOcclusion, f0); + + #if defined(CLEARCOAT) && defined(SHADING_MODE_DEFAULT) + { + half clearcoatNoV = abs(dot(d.worldNormal, d.worldSpaceViewDir)) + 1e-5; + computedSpecularOcclusion = computeSpecularAO(clearcoatNoV, o.Occlusion * indirectSpecularOcclusion, clampedRoughness); + computedSpecularOcclusion *= energyCompensation; + + half3 envBRDF = EnvBRDFMultiscatter(clearcoatdfg, f0); + clearCoatIndirectSpecular *= envBRDF; + clearCoatIndirectSpecular *= gtaoMultiBounce(computedSpecularOcclusion, f0); + } + #endif + + #endif // !defined(UNITY_PASS_FORWARDADD) + + // Standard-Like transparent (premult alpha) + if (_RenderType == 2) + { + o.Albedo.rgb *= o.Alpha; + o.Alpha = 1 - (oneMinusReflectivity) + o.Alpha * (oneMinusReflectivity); + } - indirectSpecular *= specularOcclusion * EnvBRDFMultiscatter(dfg, f0); + #if !defined(_NATIVE_A2C) + { + // Standard-Like cutout + if (_RenderType == 1) + { + clip(o.Alpha - _Cutoff); + } + } #endif - #if defined(_INTEGRATE_CUSTOMGI) && !defined(UNITY_PASS_FORWARDADD) - IntegrateCustomGI(d, o, indirectSpecular, indirectDiffuse); + FinalColor.rgb = o.Albedo.rgb * (oneMinusReflectivity); + + half3 customGIDiffuse = 0; + half3 customGISpecular = 0; + // Custom GI + { + #if defined(_INTEGRATE_CUSTOMGI) && !defined(UNITY_PASS_FORWARDADD) + IntegrateCustomGI(d, o, indirectSpecular, indirectDiffuse); + #endif + + #if defined (_INTEGRATE_CUSTOMGI_FLEX) && !defined(UNITY_PASS_FORWARDADD) + %CustomGIFunctions + #endif + } + + // Diffuse Contributions + half3 diffuseContributions = 0; + diffuseContributions += mainLightDiffuse; + diffuseContributions += indirectDiffuse * occlusion; + diffuseContributions += customGIDiffuse * occlusion; + + // Add vertex Lights + #if defined(SHADE_VERTEXLIGHTS) && defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + { + diffuseContributions += vertexLightDiffuse; + } + #endif + + // Specular Contributions + half3 specularContributions = 0; + specularContributions += mainLightSpecular; + specularContributions += bakedDirectSpecular; + specularContributions += indirectSpecular; + specularContributions += customGISpecular; + + // Add vertex Lights + #if defined(SHADE_VERTEXLIGHTS) && defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + { + specularContributions += vertexLightSpecular; + } #endif - // FINAL COLOR - FinalColor = half4(o.Albedo.rgb * (1 - o.Metallic) * (indirectDiffuse * occlusion + (pixelLight)) + indirectSpecular + directSpecular, o.Alpha); + // Add clear coat layer + #if defined(CLEARCOAT) && defined(SHADING_MODE_DEFAULT) + { + specularContributions += clearCoatMainLightSpecular; + specularContributions += clearCoatIndirectSpecular; + + // Add vertex Lights + #if defined(SHADE_VERTEXLIGHTS) && defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + { + specularContributions += clearCoatVertexLightSpecular; + } + #endif + } + #endif + + // Compositing + FinalColor.rgb *= diffuseContributions; + FinalColor.rgb += specularContributions; + FinalColor.a = o.Alpha; + + #if defined(UNITY_PASS_FORWARDBASE) FinalColor.rgb += o.Emission; #endif + + // Premulty output by alpha for correct `Fade` mode + #if defined(UNITY_PASS_FORWARDADD) + if (_RenderType == 3) + { + FinalColor.rgb *= o.Alpha; + } + #endif + + #endif // shadowcaster check + } +} + +%Color("FragmentBaseMetaColor", 1000) +{ + void FragmentBaseMetaColor(inout SurfaceData o) + { + // Boost emissive for Meta (mostly for RTGI) + #if defined(UNITY_PASS_META) + o.Emission *= pow(_GIEmissiveBoost, 2.2); + #endif + } +} + +%Color("FragmentBaseColorCorr", 1001) +{ + void FragmentBaseColorCorr(inout half4 FinalColor) { + #if defined(APPLY_COLOR_CORRECTION) && defined(PLAT_QUEST) + + #if defined(MOBILE_TONEMAP_ACES) + FinalColor.rgb = Tonemap_ACES(FinalColor.rgb); + #elif defined(MOBILE_TONEMAP_UNREAL) + FinalColor.rgb = pow(Tonemap_Unreal(FinalColor.rgb), 2.2); + #elif defined(MOBILE_TONEMAP_UNCHARTED) + FinalColor.rgb = pow(Tonemap_Uncharted2(FinalColor.rgb),2.2); + #endif + + FinalColor.rgb = applyLiftGammaGainEffect(FinalColor.rgb, _ColorCorrLift, _ColorCorrGamma, _ColorCorrGain); + #endif + } +} + +%Shadow("PBRBaseShadow") +{ + void PBRBaseShadow(SurfaceData o) { + if (_RenderType == 1) + { + clip(o.Alpha - _Cutoff); + } } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/FragmentBase.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/FragmentBase.orlsource index cb8a90c0..21977965 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/FragmentBase.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/FragmentBase.orlsource @@ -5,6 +5,10 @@ [Enum(Off, 0, On, 1)]_ZWrite("Depth Write", Int) = 1 [Enum(UnityEngine.Rendering.CompareFunction)]_ZTest("Depth Test", Int) = 4 [ToggleUI]_IgnoreLightprobeNormal("Uniform Lightprobe Color", Int) = 0 + [ToggleUI]_MinLight("Raise Minimum Light", Int) = 0 + UI_MinLightNote("?> This will raise the minimum light level and make you glow in dark environments. While not accurate to any world lighting, this can be nice to have to take pictures", Int) = 0 + _MonochromeLighting("Monochrome Lighting", Range(0,1)) = 0 + UI_MonochromeLightingNote("?> This will make the environment lighting only control the intensity without affecting the color of your object. This is now physically accurate.", Int) = 0 } %Includes() @@ -13,8 +17,22 @@ "self" } +%ShaderFeatures() +{ + #pragma multi_compile _ VERTEXLIGHT_ON +} + +%ShaderModifiers() +{ + ZTest [_ZTest] + ZWrite [_ZWrite] + Cull [_CullMode] +} + %ShaderDefines() { + #define ORL_LIGHTING_MODEL_TOON + #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) #define PLAT_QUEST #else @@ -31,6 +49,8 @@ %Variables() { int _IgnoreLightprobeNormal; + int _MinLight; + half _MonochromeLighting; } %Textures() @@ -79,7 +99,8 @@ half grayIndirect = dot(indirectDiffuse, float3(1,1,1)); half attenFactor = lerp(attenuation, 1, smoothstep(0, 0.2, grayIndirect)); - diffuse = ramp * attenFactor * half4(lightCol, 1) + indirect; + diffuse = ramp * attenFactor * half4(lightCol, 1); + diffuse += indirect; diffuse = albedo.xyzz * diffuse; return diffuse; } @@ -186,7 +207,8 @@ float3 directSpecularAniso = max(0, (D * V) * F); specular = lerp(directSpecularNonAniso, directSpecularAniso, saturate(abs(anisotropy * 100))); - specular = lerp(specular, smoothstep(0.5, 0.51, specular), o.SpecularSharpness) * 3 * lightColor.xyz * specularIntensity; // Multiply by 3 to bring up to brightness of standard + specular = lerp(specular, smoothstep(0.5, 0.51, specular), o.SpecularSharpness); + specular *= 3 * lightColor.xyz * specularIntensity; // Multiply by 3 to bring up to brightness of standard specular *= lerp(1, o.Albedo, o.SpecularAlbedoTint); specular = clamp(specular, 0, specularIntensity); return specular; @@ -194,16 +216,18 @@ half3 calcReflectionBlending(SurfaceData o, half reflectivity, half3 col, half3 indirectSpecular) { - if (o.ReflectionBlendMode == 0) { // Additive - col += indirectSpecular.xyzz * reflectivity; - return col; - } else if (o.ReflectionBlendMode == 1) { //Multiplicitive - col = lerp(col, col * indirectSpecular.xyz, reflectivity); - return col; - } else if(o.ReflectionBlendMode == 2) { //Subtractive - col -= indirectSpecular.xyz * reflectivity; - return col; - } + half3 reflection = indirectSpecular.xyzz * reflectivity; + + // Doing a Lerp allows shaders to smoothly transition between blend modes + col = lerp( + col + reflection, // Additive + lerp( + lerp(col, col * indirectSpecular.xyz, reflectivity), // Multiplicitive + col - reflection, // Subtractive + saturate(o.ReflectionBlendMode - 1) + ), + saturate(o.ReflectionBlendMode) + ); return col; } @@ -302,11 +326,48 @@ indirectDiffuse.g = shEvaluateDiffuseL1Geomerics(L0.g, unity_SHAg.xyz, lerp(o.Normal, half3(0,0.5,0), _IgnoreLightprobeNormal)); indirectDiffuse.b = shEvaluateDiffuseL1Geomerics(L0.b, unity_SHAb.xyz, lerp(o.Normal, half3(0,0.5,0), _IgnoreLightprobeNormal)); indirectDiffuse = max(0, indirectDiffuse); - #else - indirectDiffuse = 0; + #elif defined(UNITY_PASS_FORWARDBASE) + // This here is an attempt to provide a somewhat usable ramp for lightmaps + half2 lightmapUV = d.lightmapUv.xy; + half4 bakedColorTex = 0; + half3 lightMap = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); + + // Support basic directionality + #if defined(DIRLIGHTMAP_COMBINED) + half4 lightMapDirection = tex2DFastBicubicSample(unity_LightmapInd, samplerunity_Lightmap, lightmapUV); + + // use lightmap direction if we can, realtim light is ignored in that case + lightDir.xyz = lightMapDirection.xyz - 0.5; + lightHalfVector = Unity_SafeNormalize(lightDir + d.worldSpaceViewDir); + lightNoL = dot(o.Normal, lightDir); + lightLoH = dot(lightDir, lightHalfVector); + + lightMap = DecodeDirectionalLightmap(lightMap, lightMapDirection, o.Normal); + + lightColor = lightMap * 0.6; + indirectDiffuse = lightMap * 0.4; + #else + // Hacky way to support both cases of dirlight + baked and bakedy only but no directionality + // baked generates a light dir of 0,1,0 + if (dot(lightDir.xyz, half3(0,1,0)) > 0.95) { + lightDir.xyz = 0; + lightNoL = 1; + } + indirectDiffuse = lightMap; + #endif + + // we can end up using this twice, once above in the Dirlight logic and once here if both a realtime light + // and baked lightmap are present + half sharp2 = o.ShadowSharpness * 0.5; + lightAttenuation = smoothstep(sharp, 1 - sharp, saturate(length(lightMap))); #endif indirectDiffuse *= lerp(occlusion, 1, o.OcclusionMode); + if (_MonochromeLighting > 0) + { + indirectDiffuse = lerp(indirectDiffuse, dot(indirectDiffuse, float3(0.299, 0.587, 0.114)), _MonochromeLighting); + } + bool lightEnv = any(lightDir.xyz); // if there is no realtime light - we rely solely on probes if (!lightEnv) { @@ -314,6 +375,10 @@ indirectDiffuse = indirectDiffuse * 0.4; } + #if defined(UNITY_PASS_FORWARDBASE) + indirectDiffuse = lerp(indirectDiffuse, max(indirectDiffuse, 0.05), _MinLight); + #endif + half lightAvg = (dot(indirectDiffuse.rgb, grayscaleVec) + dot(lightColor.rgb, grayscaleVec)) / 2; // Light Ramp @@ -322,6 +387,26 @@ ramp = calcRamp(lightNoL, lightAttenuation, occlusion, o.OcclusionMode); diffuse = calcDiffuse(lightAttenuation, o.Albedo.rgb, indirectDiffuse, lightColor, ramp); + #if defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + float4 vLightAttenuations = 0; + float4x4 vLightColors = getVertexLightsColors(d.worldSpacePosition, o.Normal, vLightAttenuations, false); + float4x4 vLightDirections = getVertexLightsDir(d.worldSpacePosition); + float4x4 vLightHalfVectors = 0; + float4 vLightNoLs = 0; + float4 vLightLoHs = 0; + half4 vRamp = 1; + + [unroll(4)] + for (int i = 0; i < 4; i++) + { + vLightHalfVectors[i].rgb = Unity_SafeNormalize(vLightDirections[i] + d.worldSpaceViewDir); + vLightLoHs[i] = saturate(dot(vLightDirections[i], vLightHalfVectors[i])); + vLightNoLs[i] = saturate(dot(o.Normal, vLightDirections[i])); + vRamp = calcRamp(vLightNoLs[i], vLightAttenuations[i], occlusion, o.OcclusionMode); + diffuse += calcDiffuse(vLightAttenuations[i], o.Albedo.rgb, 0, vLightColors[i], vRamp); + } + #endif + // Rims half3 rimLight = 0; #if defined(RIMLIGHT_ON) @@ -342,7 +427,17 @@ #endif #if defined(SPECULAR_ON) - directSpecular = calcDirectSpecular(d, o, lightNoL, NoH, NoV, lightLoH, lightColor, lightHalfVector, o.SpecularAnisotropy) * lightNoL * occlusion * lightAttenuation; + directSpecular = calcDirectSpecular(d, o, lightNoL, NoH, NoV, lightLoH, lightColor, lightHalfVector, o.SpecularAnisotropy); + directSpecular *= lightNoL * occlusion * lightAttenuation; + #if defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + { + [unroll(4)] + for (int i = 0; i < 4; i++) + { + directSpecular += calcDirectSpecular(d, o, vLightNoLs[i], vLightLoHs[i], NoV, vLightLoHs[i], vLightColors[i], vLightHalfVectors[i], o.SpecularAnisotropy) * vLightNoLs[i] * occlusion * vLightAttenuations[i]; + } + } + #endif #endif FinalColor.rgb = diffuse.rgb * rimShadow.rgb; diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/v2.meta similarity index 77% rename from Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker.meta rename to Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/v2.meta index b14bc72c..0b0ee8ff 100644 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/PackageMaker.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/v2.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5da3ddd939264fc40a113d615f3ca77a +guid: 0418eb193f696384b964d9e0c706172a folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/v2/FragmentBase.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/v2/FragmentBase.orlsource new file mode 100644 index 00000000..b8b97a4b --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/v2/FragmentBase.orlsource @@ -0,0 +1,163 @@ +%Properties() +{ + UI_AdvancedSettingsHeader("# Advanced Settings", Int) = 1 + [Enum(UnityEngine.Rendering.CullMode)]_CullMode("Culling Mode", Int) = 2 + [Enum(Off, 0, On, 1)]_ZWrite("Depth Write", Int) = 1 + [Enum(UnityEngine.Rendering.CompareFunction)]_ZTest("Depth Test", Int) = 4 + [ToggleUI]_IgnoreLightprobeNormal("Uniform Lightprobe Color", Int) = 0 + [ToggleUI]_MinLight("Raise Minimum Light", Int) = 0 + UI_MinLightNote("?> This will raise the minimum light level and make you glow in dark environments. While not accurate to any world lighting, this can be nice to have to take pictures", Int) = 0 + _MonochromeLighting("Monochrome Lighting", Range(0,1)) = 0 + UI_MonochromeLightingNote("?> This will make the environment lighting only control the intensity without affecting the color of your object. This is now physically accurate.", Int) = 0 +} + +%Includes() +{ + "@/Libraries/PBR/LightingHelpers", + "self" +} + +%ShaderFeatures() +{ + #pragma multi_compile _ VERTEXLIGHT_ON +} + +%ShaderModifiers() +{ + ZTest [_ZTest] + ZWrite [_ZWrite] + Cull [_CullMode] +} + +%ShaderDefines() +{ + #define ORL_LIGHTING_MODEL_TOON_V2 + + #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) + #define PLAT_QUEST + #else + #ifdef PLAT_QUEST + #undef PLAT_QUEST + #endif + #endif + + #define NEED_SCREEN_POS +} + +%Variables() +{ + int _IgnoreLightprobeNormal; + int _MinLight; + half _MonochromeLighting; +} + +%FragmentBase("ToonFragmentBaseV2") +{ + void ToonFragmentBaseV2(MeshData d, FragmentData i, SurfaceData o, inout half4 FinalColor) + { + o.WorldNormal = Unity_SafeNormalize(mul(o.Normal, d.TBNMatrix)); + half3 f0 = 0.16 * 0.5 * 0.5 + o.Albedo; + + #ifndef USING_DIRECTIONAL_LIGHT + float3 lightDir = UnityWorldSpaceLightDir(d.worldSpacePosition); + #else + float3 lightDir = _WorldSpaceLightPos0.xyz; + #endif + bool hasRealtimeLight = any(lightDir.xyz); + float3 probeLightDir = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz; + bool probesAreBlack = length(dot(probeLightDir, float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w))) < 0.01; + bool noLightDir = !hasRealtimeLight && probesAreBlack; + + // If no realtime light is present - use direction from probes + if (!hasRealtimeLight) + { + lightDir = Unity_SafeNormalize(probeLightDir); + } + + // If no light is present, we use a default direction + #if !defined(POINT) && !defined(SPOT) + if (noLightDir) + { + // normalize(float3(1,1,1)); + lightDir = float3(0.577, 0.577, 0.577); + } + #endif + lightDir = Unity_SafeNormalize(lightDir); + + UNITY_LIGHT_ATTENUATION(lightAttenuation, i, d.worldSpacePosition); + half3 lightColor = _LightColor0.rgb; + #if defined(UNITY_PASS_FORWARDBASE) + { + if(all(_LightColor0.rgb == 0.0)) + { + lightAttenuation = 1.0; + } + } + #endif + + float3 lightHalfVector = Unity_SafeNormalize(lightDir + d.worldSpaceViewDir); + half lightNoL = dot(o.WorldNormal, lightDir); + half lightLoH = dot(lightDir, lightHalfVector); + half NoV = abs(dot(o.WorldNormal, d.worldSpaceViewDir)) + 1e-5; + + half3 mainLightDiffuse = 0; + half3 indirectDiffuse = 0; + half3 customGIDiffuse = 0; + // Diffuse modifier is mixed with the main diffuse via multiply + half3 diffuseModifier = 1; + + half3 mainLightSpecular = 0; + half3 indirectSpecular = 0; + half3 customGISpecular = 0; + // Main light mixed specular is mixed with the main light specular via max + half3 mainLightMixedSpecular = 0; + + half3 emission = 0; + + // Inject module-base lighting functions + { + %ModuleLightingFunctions + } + + // Inject Custom GI functions + { + #if defined (_INTEGRATE_CUSTOMGI_FLEX) && !defined(UNITY_PASS_FORWARDADD) + %CustomGIFunctions + #endif + } + + FinalColor.rgb = o.Albedo.rgb; + + half3 diffuseContributions = 0; + diffuseContributions += mainLightDiffuse; + diffuseContributions += indirectDiffuse; + diffuseContributions += customGIDiffuse; + diffuseContributions *= diffuseModifier; + + #if defined(UNITY_PASS_FORWARDBASE) + diffuseContributions = lerp(diffuseContributions, max(diffuseContributions, 0.05), _MinLight); + #endif + diffuseContributions = lerp(diffuseContributions, dot(diffuseContributions, float3(0.299, 0.587, 0.114)), _MonochromeLighting); + + half3 specularContributions = 0; + specularContributions += max(mainLightSpecular, mainLightMixedSpecular); + specularContributions += indirectSpecular; + specularContributions += customGISpecular; + + specularContributions = lerp(specularContributions, dot(specularContributions, float3(0.299, 0.587, 0.114)), _MonochromeLighting); + + // Composite final color + FinalColor.rgb *= diffuseContributions; + FinalColor.rgb += specularContributions; + FinalColor.a = o.Alpha; + + // Sometimes we want to operate on the final color directly but before the fog is applied + { + %ModuleFinalColorFunctions + } + + #if defined(UNITY_PASS_FORWARDBASE) + FinalColor.rgb += emission; + #endif + } +} diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/ResolverWindowStyle.uss.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/v2/FragmentBase.orlsource.meta similarity index 55% rename from Packages/com.vrchat.core.vpm-resolver/Editor/Resources/ResolverWindowStyle.uss.meta rename to Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/v2/FragmentBase.orlsource.meta index 042729bb..7054f041 100644 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resources/ResolverWindowStyle.uss.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/Toon/v2/FragmentBase.orlsource.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 346f7a547766ecb4396d15f585a15133 +guid: 06fd6216a081a5f4bb1e22f134bfbe23 ScriptedImporter: internalIDToNameTable: [] externalObjects: {} @@ -7,5 +7,4 @@ ScriptedImporter: userData: assetBundleName: assetBundleVariant: - script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} - disableValidation: 0 + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/UI/FragmentBase.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/UI/FragmentBase.orlsource index 19db0350..c18a600a 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/UI/FragmentBase.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/UI/FragmentBase.orlsource @@ -52,8 +52,10 @@ #pragma multi_compile_local _ UNITY_UI_ALPHACLIP } -%ShadeDefines() +%ShaderDefines() { + #define ORL_LIGHTING_MODEL_UI + #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) #define PLAT_QUEST #else @@ -61,11 +63,13 @@ #undef PLAT_QUEST #endif #endif + + #include "UnityUI.cginc" } %FragmentBase("FragmentBase") { - void FragmentBase(SurfaceData o, inout half4 FinalColor) + void FragmentBase(MeshData d, SurfaceData o, inout half4 FinalColor) { o.Albedo += _TextureSampleAdd; o.Albedo *= _Color.rgb; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/VFX/FragmentBase.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/VFX/FragmentBase.orlsource index 500bf9d1..f6ee20db 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/VFX/FragmentBase.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/VFX/FragmentBase.orlsource @@ -1,5 +1,23 @@ -%ShadeDefines() +%Properties() { + UI_AdvancedSettingsHeader("# Advanced Settings", Int) = 1 + [Enum(UnityEngine.Rendering.CullMode)]_CullMode("Culling Mode", Int) = 2 + _RenderType("Render Type %RenderType(_BlendOp, _SrcBlend, _DstBlend, _BlendOpAlpha, _SrcBlendAlpha, _DstBlendAlpha, _ZWrite)", Float) = -1 + [Enum(UnityEngine.Rendering.BlendOp)]_BlendOp("Blend Operation %ShowIf(_RenderType == 4)", Int) = 0 + [Enum(UnityEngine.Rendering.BlendMode)]_SrcBlend("Source Blend %ShowIf(_RenderType == 4)", Int) = 1 + [Enum(UnityEngine.Rendering.BlendMode)]_DstBlend("Destination Blend %ShowIf(_RenderType == 4)", Int) = 0 + [Enum(UnityEngine.Rendering.BlendOp)]_BlendOpAlpha("Blend Operation Alpha %ShowIf(_RenderType == 4)", Int) = 0 + [Enum(UnityEngine.Rendering.BlendMode)]_SrcBlendAlpha("Source Blend Alpha %ShowIf(_RenderType == 4)", Int) = 1 + [Enum(UnityEngine.Rendering.BlendMode)]_DstBlendAlpha("Destination Blend Alpha %ShowIf(_RenderType == 4)", Int) = 0 + [Enum(Off, 0, On, 1)]_ZWrite("Depth Write", Int) = 1 + [Enum(UnityEngine.Rendering.CullMode)]_CullMode("Culling Mode", Int) = 2 + _Cutoff("Cutoff %ShowIf(_RenderType == 1)", Range(0, 1)) = 0.5 +} + +%ShaderDefines() +{ + #define ORL_LIGHTING_MODEL_VFX + #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) #define PLAT_QUEST #else @@ -9,10 +27,31 @@ #endif } +%ShaderModifiers() +{ + BlendOp [_BlendOp], [_BlendOpAlpha] + Blend [_SrcBlend] [_DstBlend], [_SrcBlendAlpha] [_DstBlendAlpha] +} + +%ShaderModifiers() +{ + ZWrite [_ZWrite] + Cull [_CullMode] +} + +%Variables() +{ + half _Cutoff; + int _RenderType; +} + %FragmentBase("FragmentBase") { void FragmentBase(SurfaceData o, inout half4 FinalColor) { + if (_RenderType == 1) { + clip(o.Alpha - _Cutoff); + } FinalColor = half4(o.Albedo.rgb + o.Emission.rgb, o.Alpha); } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/VertexBase.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/VertexBase.orlsource index a20dbc64..c0a51c1a 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/VertexBase.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Functions/VertexBase.orlsource @@ -2,16 +2,28 @@ { void VertexBase(inout VertexData v, inout FragmentData o) { - #if defined(UNITY_PASS_META) + #if defined(UNITY_PASS_META) && !defined(UNITY_PASS_BAKERY_META) o.pos = UnityMetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST); #else - o.pos = UnityObjectToClipPos(v.vertex); + o.pos = TransformObjectToHClip(v.vertex); #endif o.normal = v.normal; o.uv0 = v.uv0; o.uv1 = v.uv1; o.uv2 = v.uv2; o.uv3 = v.uv3; + #if defined(NEED_UV4) + o.uv4 = v.uv4; + #endif + #if defined(NEED_UV5) + o.uv5 = v.uv5; + #endif + #if defined(NEED_UV6) + o.uv6 = v.uv6; + #endif + #if defined(NEED_UV7) + o.uv7 = v.uv7; + #endif o.worldPos = mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1)); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz); @@ -33,7 +45,8 @@ #endif #if defined(NEED_SCREEN_POS) - o.screenPos = ComputeScreenPos(o.pos); + o.screenPos = GetScreenPosition(o.pos); + o.screenPos.z = -TransformWorldToView(TransformObjectToWorld(v.vertex)).z; #endif #if !defined(UNITY_PASS_META) diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary.meta similarity index 77% rename from Packages/com.vrchat.core.vpm-resolver/Editor/Resolver.meta rename to Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary.meta index 25636fb8..0ef95a4d 100644 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0aa72fa778aef5b4cb5fa177c19d3636 +guid: 944493aeb2722e745831581fca59e84f folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/BiRPtoURP.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/BiRPtoURP.orlsource new file mode 100644 index 00000000..5b630bae --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/BiRPtoURP.orlsource @@ -0,0 +1,556 @@ +%LibraryFunctions() +{ + //-------------------------------------------------------------- + // Macros to redefine built-in macros to those used by the URP + //-------------------------------------------------------------- + + #if !defined(BIRP_TO_URP) + #define BIRP_TO_URP + + //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- + // StdLib.hlsl ---------------------------------------------------------------- + //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- + + #define HALF_MAX 65504.0 // (2 - 2^-10) * 2^15 + #define HALF_MAX_MINUS1 65472.0 // (2 - 2^-9) * 2^15 + #define EPSILON 1.0e-4 + #define PI 3.14159265359 + #define TWO_PI 6.28318530718 + #define FOUR_PI 12.56637061436 + #define INV_PI 0.31830988618 + #define INV_TWO_PI 0.15915494309 + #define INV_FOUR_PI 0.07957747155 + #define HALF_PI 1.57079632679 + #define INV_HALF_PI 0.636619772367 + + #define FLT_EPSILON 1.192092896e-07 // Smallest positive number, such that 1.0 + FLT_EPSILON != 1.0 + #define FLT_MIN 1.175494351e-38 // Minimum representable positive floating-point number + #define FLT_MAX 3.402823466e+38 // Maximum representable floating-point number + + + + //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- + // Common.hlsl ---------------------------------------------------------------- + //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- + /* + #define half min16float + #define half2 min16float2 + #define half3 min16float3 + #define half4 min16float4 + #define half2x2 min16float2x2 + #define half2x3 min16float2x3 + #define half3x2 min16float3x2 + #define half3x3 min16float3x3 + #define half3x4 min16float3x4 + #define half4x3 min16float4x3 + #define half4x4 min16float4x4 + */ + #define real half + #define real2 half2 + #define real3 half3 + #define real4 half4 + #define real2x2 half2x2 + #define real2x3 half2x3 + #define real2x4 half2x4 + #define real3x2 half3x2 + #define real3x3 half3x3 + #define real3x4 half3x4 + #define real4x3 half4x3 + #define real4x4 half4x4 + + + float3 SafeNormalize(float3 inVec) + { + float dp3 = max(FLT_MIN, dot(inVec, inVec)); + return inVec * rsqrt(dp3); + } + + + #if defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED) + + #define SLICE_ARRAY_INDEX unity_StereoEyeIndex + + #define TEXTURE2D_X(textureName) TEXTURE2D_ARRAY(textureName) + #define TEXTURE2D_X_PARAM(textureName, samplerName) TEXTURE2D_ARRAY_PARAM(textureName, samplerName) + #define TEXTURE2D_X_ARGS(textureName, samplerName) TEXTURE2D_ARRAY_ARGS(textureName, samplerName) + #define TEXTURE2D_X_HALF(textureName) TEXTURE2D_ARRAY_HALF(textureName) + #define TEXTURE2D_X_FLOAT(textureName) TEXTURE2D_ARRAY_FLOAT(textureName) + + #define LOAD_TEXTURE2D_X(textureName, unCoord2) LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, SLICE_ARRAY_INDEX) + #define LOAD_TEXTURE2D_X_LOD(textureName, unCoord2, lod) LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, SLICE_ARRAY_INDEX, lod) + #define SAMPLE_TEXTURE2D_X(textureName, samplerName, coord2) SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, SLICE_ARRAY_INDEX) + #define SAMPLE_TEXTURE2D_X_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, SLICE_ARRAY_INDEX, lod) + #define GATHER_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, SLICE_ARRAY_INDEX) + #define GATHER_RED_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_RED_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX)) + #define GATHER_GREEN_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_GREEN_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX)) + #define GATHER_BLUE_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_BLUE_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX)) + + #else + #define SLICE_ARRAY_INDEX 0 + + #define TEXTURE2D_X(textureName) TEXTURE2D(textureName) + #define TEXTURE2D_X_PARAM(textureName, samplerName) TEXTURE2D_PARAM(textureName, samplerName) + #define TEXTURE2D_X_ARGS(textureName, samplerName) TEXTURE2D_ARGS(textureName, samplerName) + #define TEXTURE2D_X_HALF(textureName) TEXTURE2D_HALF(textureName) + #define TEXTURE2D_X_FLOAT(textureName) TEXTURE2D_FLOAT(textureName) + + #define LOAD_TEXTURE2D_X(textureName, unCoord2) LOAD_TEXTURE2D(textureName, unCoord2) + #define LOAD_TEXTURE2D_X_LOD(textureName, unCoord2, lod) LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) + #define SAMPLE_TEXTURE2D_X(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2) + #define SAMPLE_TEXTURE2D_X_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) + #define GATHER_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_TEXTURE2D(textureName, samplerName, coord2) + #define GATHER_RED_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) + #define GATHER_GREEN_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) + #define GATHER_BLUE_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) + #endif + + + + //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- + // SpaceTransforms.hlsl ---------------------------------------------------------------- + //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- + + + float4x4 GetObjectToWorldMatrix() + { + return UNITY_MATRIX_M; + } + + #define UNITY_MATRIX_I_M unity_WorldToObject + float4x4 GetWorldToObjectMatrix() + { + return UNITY_MATRIX_I_M; + } + /* Does not exist in BiRP + float4x4 GetPrevObjectToWorldMatrix() + { + return UNITY_PREV_MATRIX_M; + } + + float4x4 GetPrevWorldToObjectMatrix() + { + return UNITY_PREV_MATRIX_I_M; + } + */ + + float4x4 GetWorldToViewMatrix() + { + return UNITY_MATRIX_V; + } + + float4x4 GetViewToWorldMatrix() + { + return UNITY_MATRIX_I_V; + } + + // Transform to homogenous clip space + float4x4 GetWorldToHClipMatrix() + { + return UNITY_MATRIX_VP; + } + + // Transform to homogenous clip space + float4x4 GetViewToHClipMatrix() + { + return UNITY_MATRIX_P; + } + + // This function always return the absolute position in WS + float3 GetAbsolutePositionWS(float3 positionRWS) + { + #if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0) + positionRWS += _WorldSpaceCameraPos.xyz; + #endif + return positionRWS; + } + + // This function return the camera relative position in WS + float3 GetCameraRelativePositionWS(float3 positionWS) + { + #if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0) + positionWS -= _WorldSpaceCameraPos.xyz; + #endif + return positionWS; + } + + half GetOddNegativeScale() + { + // FIXME: We should be able to just return unity_WorldTransformParams.w, but it is not + // properly set at the moment, when doing ray-tracing; once this has been fixed in cpp, + // we can revert back to the former implementation. + return unity_WorldTransformParams.w >= 0.0 ? 1.0 : -1.0; + } + + float3 TransformObjectToWorld(float3 positionOS) + { + #if defined(SHADER_STAGE_RAY_TRACING) + return mul(ObjectToWorld3x4(), float4(positionOS, 1.0)).xyz; + #else + return mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)).xyz; + #endif + } + + float3 TransformWorldToObject(float3 positionWS) + { + #if defined(SHADER_STAGE_RAY_TRACING) + return mul(WorldToObject3x4(), float4(positionWS, 1.0)).xyz; + #else + return mul(GetWorldToObjectMatrix(), float4(positionWS, 1.0)).xyz; + #endif + } + + float3 TransformWorldToView(float3 positionWS) + { + return mul(GetWorldToViewMatrix(), float4(positionWS, 1.0)).xyz; + } + + float3 TransformViewToWorld(float3 positionVS) + { + return mul(GetViewToWorldMatrix(), float4(positionVS, 1.0)).xyz; + } + + // Transforms position from object space to homogenous space + float4 TransformObjectToHClip(float3 positionOS) + { + // More efficient than computing M*VP matrix product + return mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0))); + } + + // Transforms position from world space to homogenous space + float4 TransformWorldToHClip(float3 positionWS) + { + return mul(GetWorldToHClipMatrix(), float4(positionWS, 1.0)); + } + + // Transforms position from view space to homogenous space + float4 TransformWViewToHClip(float3 positionVS) + { + return mul(GetViewToHClipMatrix(), float4(positionVS, 1.0)); + } + + // Normalize to support uniform scaling + float3 TransformObjectToWorldDir(float3 dirOS, bool doNormalize = true) + { + #ifndef SHADER_STAGE_RAY_TRACING + float3 dirWS = mul((float3x3)GetObjectToWorldMatrix(), dirOS); + #else + float3 dirWS = mul((float3x3)ObjectToWorld3x4(), dirOS); + #endif + if (doNormalize) + return SafeNormalize(dirWS); + return dirWS; + } + + // Normalize to support uniform scaling + float3 TransformWorldToObjectDir(float3 dirWS, bool doNormalize = true) + { + #ifndef SHADER_STAGE_RAY_TRACING + float3 dirOS = mul((float3x3)GetWorldToObjectMatrix(), dirWS); + #else + float3 dirOS = mul((float3x3)WorldToObject3x4(), dirWS); + #endif + if (doNormalize) + return normalize(dirOS); + + return dirOS; + } + + // Transforms vector from world space to view space + float3 TransformWorldToViewDir(float3 dirWS, bool doNormalize = false) + { + float3 dirVS = mul( (float3x3)UNITY_MATRIX_V, dirWS).xyz; + if (doNormalize) + return normalize(dirVS); + + return dirVS; + } + + // Transforms vector from view space to world space + float3 TransformViewToWorldDir(float3 dirVS, bool doNormalize = false) + { + float3 dirWS = mul((float3x3)GetViewToWorldMatrix(), dirVS).xyz; + if (doNormalize) + return normalize(dirWS); + + return dirWS; + } + + // Transforms normal from world space to view space + float3 TransformWorldToViewNormal(float3 normalWS, bool doNormalize = false) + { + // assuming view matrix is uniformly scaled, we can use direction transform + return TransformWorldToViewDir(normalWS, doNormalize); + } + + // Transforms normal from view space to world space + float3 TransformViewToWorldNormal(float3 normalVS, bool doNormalize = false) + { + // assuming view matrix is uniformly scaled, we can use direction transform + return TransformViewToWorldDir(normalVS, doNormalize); + } + + // Transforms vector from world space to homogenous space + float3 TransformWorldToHClipDir(float3 directionWS, bool doNormalize = false) + { + float3 dirHCS = mul((float3x3)GetWorldToHClipMatrix(), directionWS).xyz; + if (doNormalize) + return normalize(dirHCS); + + return dirHCS; + } + + // Transforms normal from object to world space + float3 TransformObjectToWorldNormal(float3 normalOS, bool doNormalize = true) + { + #ifdef UNITY_ASSUME_UNIFORM_SCALING + return TransformObjectToWorldDir(normalOS, doNormalize); + #else + // Normal need to be multiply by inverse transpose + float3 normalWS = mul(normalOS, (float3x3)GetWorldToObjectMatrix()); + if (doNormalize) + return SafeNormalize(normalWS); + + return normalWS; + #endif + } + + // Transforms normal from world to object space + float3 TransformWorldToObjectNormal(float3 normalWS, bool doNormalize = true) + { + #ifdef UNITY_ASSUME_UNIFORM_SCALING + return TransformWorldToObjectDir(normalWS, doNormalize); + #else + // Normal need to be multiply by inverse transpose + float3 normalOS = mul(normalWS, (float3x3)GetObjectToWorldMatrix()); + if (doNormalize) + return SafeNormalize(normalOS); + + return normalOS; + #endif + } + + float3x3 CreateTangentToWorld(float3 normal, float3 tangent, float flipSign) + { + // For odd-negative scale transforms we need to flip the sign + float sgn = flipSign * GetOddNegativeScale(); + float3 bitangent = cross(normal, tangent) * sgn; + + return float3x3(tangent, bitangent, normal); + } + + // this function is intended to work on Normals (handles non-uniform scale) + // tangentToWorld is the matrix representing the transformation of a normal from tangent to world space + float3 TransformTangentToWorld(float3 normalTS, float3x3 tangentToWorld, bool doNormalize = false) + { + // Note matrix is in row major convention with left multiplication as it is build on the fly + float3 result = mul(normalTS, tangentToWorld); + if (doNormalize) + return SafeNormalize(result); + return result; + } + + // this function is intended to work on Normals (handles non-uniform scale) + // This function does the exact inverse of TransformTangentToWorld() and is + // also decribed within comments in mikktspace.h and it follows implicitly + // from the scalar triple product (google it). + // tangentToWorld is the matrix representing the transformation of a normal from tangent to world space + float3 TransformWorldToTangent(float3 normalWS, float3x3 tangentToWorld, bool doNormalize = true) + { + // Note matrix is in row major convention with left multiplication as it is build on the fly + float3 row0 = tangentToWorld[0]; + float3 row1 = tangentToWorld[1]; + float3 row2 = tangentToWorld[2]; + + // these are the columns of the inverse matrix but scaled by the determinant + float3 col0 = cross(row1, row2); + float3 col1 = cross(row2, row0); + float3 col2 = cross(row0, row1); + + float determinant = dot(row0, col0); + + // inverse transposed but scaled by determinant + // Will remove transpose part by using matrix as the first arg in the mul() below + // this makes it the exact inverse of what TransformTangentToWorld() does. + float3x3 matTBN_I_T = float3x3(col0, col1, col2); + float3 result = mul(matTBN_I_T, normalWS); + if (doNormalize) + { + float sgn = determinant < 0.0 ? (-1.0) : 1.0; + return SafeNormalize(sgn * result); + } + else + return result / determinant; + } + + // this function is intended to work on Vectors/Directions + // tangentToWorld is the matrix representing the transformation of a normal from tangent to world space + float3 TransformWorldToTangentDir(float3 dirWS, float3x3 tangentToWorld, bool doNormalize = false) + { + // Note matrix is in row major convention with left multiplication as it is build on the fly + float3 result = mul(tangentToWorld, dirWS); + if (doNormalize) + return SafeNormalize(result); + return result; + } + + // this function is intended to work on Vectors/Directions + // This function does the exact inverse of TransformWorldToTangentDir() + // tangentToWorld is the matrix representing the transformation of a normal from tangent to world space + float3 TransformTangentToWorldDir(float3 dirWS, float3x3 tangentToWorld, bool doNormalize = false) + { + // Note matrix is in row major convention with left multiplication as it is build on the fly + float3 row0 = tangentToWorld[0]; + float3 row1 = tangentToWorld[1]; + float3 row2 = tangentToWorld[2]; + + // these are the columns of the inverse matrix but scaled by the determinant + float3 col0 = cross(row1, row2); + float3 col1 = cross(row2, row0); + float3 col2 = cross(row0, row1); + + float determinant = dot(row0, col0); + + // inverse transposed but scaled by determinant + // Will remove transpose part by using matrix as the second arg in the mul() below + // this makes it the exact inverse of what TransformWorldToTangentDir() does. + float3x3 matTBN_I_T = float3x3(col0, col1, col2); + float3 result = mul(dirWS, matTBN_I_T); + if (doNormalize) + { + float sgn = determinant < 0.0 ? (-1.0) : 1.0; + return SafeNormalize(sgn * result); + } + else + return result / determinant; + } + + // tangentToWorld is the matrix representing the transformation of a normal from tangent to world space + float3 TransformTangentToObject(float3 dirTS, float3x3 tangentToWorld) + { + // Note matrix is in row major convention with left multiplication as it is build on the fly + float3 normalWS = TransformTangentToWorld(dirTS, tangentToWorld); + return TransformWorldToObjectNormal(normalWS); + } + + // tangentToWorld is the matrix representing the transformation of a normal from tangent to world space + float3 TransformObjectToTangent(float3 dirOS, float3x3 tangentToWorld) + { + // Note matrix is in row major convention with left multiplication as it is build on the fly + + // don't normalize, as normalWS will be normalized after TransformWorldToTangent + float3 normalWS = TransformObjectToWorldNormal(dirOS, false); + + // transform from world to tangent + return TransformWorldToTangent(normalWS, tangentToWorld); + } + + // orels1 additions + + float3 GetObjectScale() + { + float4x4 objToWorld = GetObjectToWorldMatrix(); + return float3( + length(objToWorld._m00_m10_m20), + length(objToWorld._m01_m11_m21), + length(objToWorld._m02_m12_m22) + ); + } + + float4 GetScreenPosition(float4 positionCS) + { + float4 ndc = positionCS * 0.5f; + ndc.xy = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w; + ndc.zw = positionCS.zw; + + ndc.xy = TransformStereoScreenSpaceTex(ndc.xy, ndc.w); + return ndc; + } + + // Delcare things in-place so that the sampler/texture can be used in the function below + TEXTURE2D_X_FLOAT(_CameraDepthTexture); + SAMPLER(sampler_CameraDepthTexture); + + float SampleSceneDepth(float2 uv) + { + return SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, uv).r; + } + + float2 SampleSceneDepthRGDecoded(float2 uv) + { + float2 depthRG = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, uv).rg; + return dot(depthRG, float2(1.0, 1/255.0)); + } + + // We need this so that we can replace `UNITY_LIGHT_ATTENUATION` + struct Light + { + float3 direction; + half3 color; + half shadowAttenuation; + }; + + Light GetMainLight() + { + Light light; + + light.direction = _WorldSpaceLightPos0.xyz; + light.shadowAttenuation = 1.0; + light.color = _LightColor0.rgb; + + return light; + } + + struct __BridgeShadowStruct + { + float4 pos; + float4 _ShadowCoord; + }; + + Light GetMainLight(float4 shadowCoord) + { + Light light = GetMainLight(); + + __BridgeShadowStruct input = (__BridgeShadowStruct) 0; + input._ShadowCoord = shadowCoord; + UNITY_LIGHT_ATTENUATION(lightAttenuation, input, 0..xxx); + light.shadowAttenuation = lightAttenuation; + return light; + } + + Light GetMainLight(float4 shadowCoord, float3 positionWS, half4 shadowMask) + { + Light light = GetMainLight(); + + // In BIRP we consider all lights "main lights", so we utilize world space position to get final light direction + #ifndef USING_DIRECTIONAL_LIGHT + light.direction = normalize(UnityWorldSpaceLightDir(positionWS)); + #endif + + __BridgeShadowStruct input = (__BridgeShadowStruct) 0; + input._ShadowCoord = shadowCoord; + UNITY_LIGHT_ATTENUATION(lightAttenuation, input, positionWS); + + light.shadowAttenuation = lightAttenuation; + + return light; + } + + float3 UnpackNormalScale(float4 packedNormal, float scale) + { + return UnpackScaleNormal(packedNormal, scale); + } + + void LODFadeCrossFade(float2 positionCS) + { + #if defined(LOD_FADE_CROSSFADE) + UnityApplyDitherCrossFade(positionCS.xy); + #endif + } + #endif +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tesselated Displacement.shader.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/BiRPtoURP.orlsource.meta similarity index 80% rename from Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tesselated Displacement.shader.meta rename to Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/BiRPtoURP.orlsource.meta index e7ca630b..1bf6ce9e 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tesselated Displacement.shader.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/BiRPtoURP.orlsource.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2758518bdcab40a3abd3807018be68ca +guid: e83de5a4bab3e6345b1475bea1e0261f ShaderImporter: externalObjects: {} defaultTextures: [] diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/LICENSE.md b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/LICENSE.md new file mode 100644 index 00000000..c92af0f6 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/LICENSE.md @@ -0,0 +1,3 @@ +Taken from https://github.com/Error-mdl/URP-ShaderIncludes-For-BiRP + +All files in this folder are from the [Unity Scriptable Render Pipeline](https://github.com/Unity-Technologies/Graphics) repo, and are licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](https://unity.com/legal/licenses/unity-companion-license) \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.txt.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/LICENSE.md.meta similarity index 75% rename from Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.txt.meta rename to Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/LICENSE.md.meta index 028d199a..7e69c003 100644 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Dependencies/Serilog.Sinks.File.txt.meta +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/CoreRPShaderLibrary/LICENSE.md.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ca344e99cdd379947ab3e8e5b346428c +guid: ba80e3c5d6cfde34db7b7f1d1753cf98 TextScriptImporter: externalObjects: {} userData: diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/PBR/LightingHelpers.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/PBR/LightingHelpers.orlsource index b611bd3c..52521f08 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/PBR/LightingHelpers.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/PBR/LightingHelpers.orlsource @@ -4,10 +4,11 @@ // [Xiexe-Unity-Shaders](https://github.com/Xiexe/Xiexes-Unity-Shaders) (c) Xiexe (MIT) // [z3y shaders](https://github.com/z3y/shaders) (c) z3y (MIT) - half D_GGX(half NoH, half roughness) + // Default shading mode + float D_GGX(float NoH, float roughness) { - half a = NoH * roughness; - half k = roughness / (1.0 - NoH * NoH + a * a); + float a = NoH * roughness; + float k = roughness / (1.0 - NoH * NoH + a * a); return k * k * (1.0 / UNITY_PI); } @@ -24,12 +25,46 @@ half V_SmithGGXCorrelated(half NoV, half NoL, half roughness) { - half a2 = roughness * roughness; + half a2 = roughness * roughness; half GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); half GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); return 0.5 / (GGXV + GGXL); } + // Clear Coat visibility + float V_Kelemen(float LoH) { + // Kelemen 2001, "A Microfacet Based Coupled Specular-Matte BRDF Model with Importance Sampling" + return min((0.25 / (LoH * LoH)), 65504.0); + } + + // Cloth shading mode + half D_Ashikhmin(half roughness, half NoH) { + // Ashikhmin 2007, "Distribution-based BRDFs" + half a2 = roughness * roughness; + half cos2h = NoH * NoH; + half sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16 + half sin4h = sin2h * sin2h; + half cot2 = -cos2h / (a2 * sin2h); + return 1.0 / (PI * (4.0 * a2 + 1.0) * sin4h) * (4.0 * exp(cot2) + sin4h); + } + + half D_Charlie(half roughness, half NoH) { + // Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF" + half invAlpha = 1.0 / roughness; + half cos2h = NoH * NoH; + half sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16 + return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI); + } + + half V_Neubelt(half NoV, half NoL) { + // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886" + return min(1.0 / (4.0 * (NoL + NoV - NoL * NoV)), 65504.0); + } + + float Fd_Wrap(float NoL, float w) { + return saturate((NoL + w) / ((1.0 + w) * (1.0 + w))); + } + half3 F_Schlick(half u, half3 f0) { return f0 + (1.0 - f0) * pow(1.0 - u, 5.0); @@ -41,6 +76,10 @@ return f0 + (f90 - f0) * pow(1.0 - VoH, 5); } + float F_Schlick(float f0, float f90, float VoH) { + return f0 + (f90 - f0) * pow5(1.0 - VoH); + } + half3 fresnel(half3 f0, half LoH) { half f90 = saturate(dot(f0, half(50.0 / 3).xxx)); @@ -56,6 +95,47 @@ return lightScatter * viewScatter; } + // These are taken from David M's improved box projection code https://github.com/frostbone25/Unity-Improved-Box-Projected-Reflections + //SOURCE - https://github.com/Unity-Technologies/Graphics/blob/504e639c4e07492f74716f36acf7aad0294af16e/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl + //From Moving Frostbite to PBR document + //This function fakes the roughness based integration of reflection probes by adjusting the roughness value + //NOTE: Untouched from HDRP + float ComputeDistanceBaseRoughness(float distanceIntersectionToShadedPoint, float distanceIntersectionToProbeCenter, float perceptualRoughness) + { + float newPerceptualRoughness = clamp(distanceIntersectionToShadedPoint / distanceIntersectionToProbeCenter * perceptualRoughness, 0, perceptualRoughness); + return lerp(newPerceptualRoughness, perceptualRoughness, perceptualRoughness); + } + + //SOURCE - https://github.com/Unity-Technologies/Graphics/blob/504e639c4e07492f74716f36acf7aad0294af16e/Packages/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl#L78 + //This simplified version assume that we care about the result only when we are inside the box + //NOTE: Untouched from HDRP + float IntersectRayAABBSimple(float3 start, float3 dir, float3 boxMin, float3 boxMax) + { + float3 invDir = rcp(dir); + + // Find the ray intersection with box plane + float3 rbmin = (boxMin - start) * invDir; + float3 rbmax = (boxMax - start) * invDir; + + float3 rbminmax = float3((dir.x > 0.0) ? rbmax.x : rbmin.x, (dir.y > 0.0) ? rbmax.y : rbmin.y, (dir.z > 0.0) ? rbmax.z : rbmin.z); + + return min(min(rbminmax.x, rbminmax.y), rbminmax.z); + } + + //SOURCE - https://github.com/Unity-Technologies/Graphics/blob/504e639c4e07492f74716f36acf7aad0294af16e/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl + //return projectionDistance, can be used in ComputeDistanceBaseRoughness formula + //return in R the unormalized corrected direction which is used to fetch cubemap but also its length represent the distance of the capture point to the intersection + //Length R can be reuse as a parameter of ComputeDistanceBaseRoughness for distIntersectionToProbeCenter + //NOTE: Modified to be much simpler, and to work with the Built-In Render Pipeline (BIRP) + float EvaluateLight_EnvIntersection(float3 worldSpacePosition, inout float3 R, float4 probePosition, float4 boxMin, float4 boxMax) + { + float projectionDistance = IntersectRayAABBSimple(worldSpacePosition, R, boxMin.xyz, boxMax.xyz); + + R = (worldSpacePosition + projectionDistance * R) - probePosition.xyz; + + return projectionDistance; + } + half3 getBoxProjection(half3 direction, half3 position, half4 cubemapPosition, half3 boxMin, half3 boxMax) { #if defined(UNITY_SPECCUBE_BOX_PROJECTION) && !defined(UNITY_PBS_USE_BRDF2) || defined(FORCE_BOX_PROJECTION) @@ -70,38 +150,105 @@ return direction; } - half3 getEnvReflection(half3 worldSpaceViewDir, half3 worldSpacePosition, half3 normal, half smoothness, int mip) + half3 getEnvReflectionDirect(float3 reflDir, half3 worldSpacePosition, half3 normal, half roughness, int mip, inout half4 rawProbe0) { half3 env = 0; - half3 reflDir = reflect(worldSpaceViewDir, normal); - half perceptualRoughness = 1 - smoothness; - half rough = perceptualRoughness * perceptualRoughness; - reflDir = lerp(reflDir, normal, rough * rough); + + float mipLevel = (float) mip; + if (mip == -1) + { + mipLevel = perceptualRoughnessToMipmapLevel(roughness*(1.7 - 0.7*roughness)); + } half3 reflectionUV1 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, mip); + half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, mipLevel); + rawProbe0 = probe0; half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR); half3 indirectSpecular; half interpolator = unity_SpecCube0_BoxMin.w; + indirectSpecular = probe0sample; + + #if defined(UNITY_SPECCUBE_BLENDING) || defined(FORCE_BOX_PROJECTION) UNITY_BRANCH if (interpolator < 0.99999) { half3 reflectionUV2 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, mip); + half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, mipLevel); half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR); indirectSpecular = lerp(probe1sample, probe0sample, interpolator); } - else - { - indirectSpecular = probe0sample; - } + #endif env = indirectSpecular; return env; } + half3 getEnvReflectionDirect(float3 reflDir, half3 worldSpacePosition, half3 normal, half roughness, int mip) + { + half4 rawProbe0; + return getEnvReflectionDirect(reflDir, worldSpacePosition, normal, roughness, mip, rawProbe0); + } + + half3 getEnvReflectionHardened(float3 reflDir, half3 worldSpacePosition, half roughness, half hardenStrength) + { + float3 boxProjectedReflDir = reflDir; + float projectionDistance = EvaluateLight_EnvIntersection(worldSpacePosition, boxProjectedReflDir, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax); + float distanceBasedRoughness = ComputeDistanceBaseRoughness(projectionDistance, length(boxProjectedReflDir), roughness); + + distanceBasedRoughness = lerp(roughness, distanceBasedRoughness, hardenStrength); + float mipLevel = perceptualRoughnessToMipmapLevel(distanceBasedRoughness * (1.7 - 0.7 * distanceBasedRoughness)); + + half4 probe0data = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, boxProjectedReflDir, mipLevel); + half3 probe0 = DecodeHDR(probe0data, unity_SpecCube0_HDR); + + half3 indirectSpecular = probe0; + + + #if defined(UNITY_SPECCUBE_BLENDING) || defined(FORCE_BOX_PROJECTION) + UNITY_BRANCH + if (unity_SpecCube0_BoxMin.w < 0.99999) + { + boxProjectedReflDir = reflDir; + distanceBasedRoughness = roughness; + if (unity_SpecCube1_ProbePosition.w > 0) + { + projectionDistance = EvaluateLight_EnvIntersection(worldSpacePosition, boxProjectedReflDir, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax); + distanceBasedRoughness = ComputeDistanceBaseRoughness(projectionDistance, length(boxProjectedReflDir), roughness); + distanceBasedRoughness = lerp(roughness, distanceBasedRoughness, hardenStrength); + } + + mipLevel = perceptualRoughnessToMipmapLevel(distanceBasedRoughness * (1.7 - 0.7 * distanceBasedRoughness)); + half4 probe1data = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube1, samplerunity_SpecCube0, boxProjectedReflDir, mipLevel); + half3 probe1 = DecodeHDR(probe1data, unity_SpecCube1_HDR); + + indirectSpecular = lerp(probe1, probe0, unity_SpecCube0_BoxMin.w); + } + #endif + return indirectSpecular; + } + + half3 getEnvReflection(half3 worldSpaceViewDir, half3 worldSpacePosition, half3 normal, half smoothness) + { + float3 reflDir = reflect(worldSpaceViewDir, normal); + half perceptualRoughness = 1 - smoothness; + reflDir = lerp(reflDir, normal, max(perceptualRoughness * perceptualRoughness, 0.002)); + perceptualRoughness = perceptualRoughness * (1.7 - 0.7 * perceptualRoughness); + + return getEnvReflectionDirect(reflDir, worldSpacePosition, normal, perceptualRoughness, -1); + } + + half3 getEnvReflection(half3 worldSpaceViewDir, half3 worldSpacePosition, half3 normal, half smoothness, int mip) + { + float3 reflDir = reflect(worldSpaceViewDir, normal); + half perceptualRoughness = 1 - smoothness; + reflDir = lerp(reflDir, normal, max(perceptualRoughness * perceptualRoughness, 0.002)); + perceptualRoughness = perceptualRoughness * (1.7 - 0.7 * perceptualRoughness); + + return getEnvReflectionDirect(reflDir, worldSpacePosition, normal, perceptualRoughness, mip); + } + half3 EnvBRDFMultiscatter(half2 dfg, half3 f0) { return lerp(dfg.xxx, dfg.yyy, f0); @@ -183,16 +330,62 @@ #endif } - half3 GetSpecularHighlights(half3 worldNormal, half3 lightColor, half3 lightDirection, half3 f0, half3 viewDir, half clampedRoughness, half NoV, half3 energyCompensation) + half3 GetSpecularHighlights(half3 lightColor, half3 f0, float3 worldNormal, float3 halfVector, half LoH, half NoL, half NoV, half roughness, half3 energyCompensation) { - half3 halfVector = Unity_SafeNormalize(lightDirection + viewDir); + half NoH = saturate(dot(worldNormal, halfVector)); + half3 F = F_Schlick(LoH, f0); + float D = D_GGX(NoH, roughness); + half V = V_SmithGGXCorrelated(NoV, NoL, roughness); + F *= energyCompensation; + + return max(0, D * V * F) * lightColor * UNITY_PI; + } + + half3 GetSpecularHighlightsAnisotropic(half3 lightColor, half3 f0, float3 worldNormal, float3 worldTangent, float3 bitangent, float3 halfVector, half LoH, half NoL, half NoV, half roughness, half3 energyCompensation, half anisotropy) + { + half NoH = saturate(dot(worldNormal, halfVector)); + half3 F = F_Schlick(LoH, f0); + float at = max(roughness * (1.0 + anisotropy), 0.001); + float ab = max(roughness * (1.0 - anisotropy), 0.001); + float D = D_GGX_Anisotropic(NoH, halfVector, worldTangent, bitangent, at, ab); + half V = V_SmithGGXCorrelated(NoV, NoL, roughness); + F *= energyCompensation; + + return max(0, D * V * F) * lightColor * UNITY_PI; + } + + half3 GetSpecularHighlightsClearCoat(half3 lightColor, half3 f0, float3 worldNormal, float3 halfVector, half LoH, half roughness, half strength, inout half clearCoatAttenuation) + { + half NoH = saturate(dot(worldNormal, halfVector)); + half3 F = F_Schlick(0.04, 1.0, LoH) * strength; + float D = D_GGX(NoH, roughness); + half V = V_Kelemen(LoH); + + clearCoatAttenuation = 1.0 - F; + + return max(0, D * V * F) * lightColor * UNITY_PI; + } + + half3 GetSpecularHighlightsCloth(half3 lightColor, float3 worldNormal, float3 halfVector, half NoL, half NoV, half roughness, half3 energyCompensation, half3 albedoSqrt, int customSheen, half3 sheenColor) + { + half NoH = saturate(dot(worldNormal, halfVector)); + half3 F = customSheen ? sheenColor : albedoSqrt; + float D = D_Charlie(roughness, NoH); + half V = V_Neubelt(NoV, NoL); + + return max(0, D * V * F) * lightColor * UNITY_PI; + } + + half3 GetSpecularHighlights(float3 worldNormal, half3 lightColor, float3 lightDirection, half3 f0, float3 viewDir, half clampedRoughness, half NoV, half3 energyCompensation) + { + float3 halfVector = Unity_SafeNormalize(lightDirection + viewDir); half NoH = saturate(dot(worldNormal, halfVector)); half NoL = saturate(dot(worldNormal, lightDirection)); half LoH = saturate(dot(lightDirection, halfVector)); half3 F = F_Schlick(LoH, f0); - half D = D_GGX(NoH, clampedRoughness); + float D = D_GGX(NoH, clampedRoughness); half V = V_SmithGGXCorrelated(NoV, NoL, clampedRoughness); #ifndef UNITY_PBS_USE_BRDF2 @@ -202,15 +395,30 @@ return max(0, (D * V) * F) * lightColor * NoL * UNITY_PI; } + half3 GetSpecularHighlightsCloth(float3 worldNormal, half3 lightColor, float3 lightDirection, half3 f0, float3 viewDir, half clampedRoughness, half NoV, half3 albedoSqrt, int customSheen, half3 sheenColor) + { + float3 halfVector = Unity_SafeNormalize(lightDirection + viewDir); + + half NoH = saturate(dot(worldNormal, halfVector)); + half NoL = saturate(dot(worldNormal, lightDirection)); + half LoH = saturate(dot(lightDirection, halfVector)); + + half3 F = customSheen ? sheenColor : albedoSqrt; + float D = D_Charlie(clampedRoughness, NoH); + half V = V_Neubelt(NoV, NoL); + + return max(0, (D * V) * F) * lightColor * NoL * UNITY_PI; + } + #ifdef DYNAMICLIGHTMAP_ON half3 getRealtimeLightmap(half2 uv, half3 worldNormal) { half2 realtimeUV = uv; - half4 bakedCol = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, realtimeUV); + half4 bakedCol = tex2DFastBicubicSample(unity_DynamicLightmap, samplerunity_DynamicLightmap, realtimeUV); half3 realtimeLightmap = DecodeRealtimeLightmap(bakedCol); #ifdef DIRLIGHTMAP_COMBINED - half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, realtimeUV); + half4 realtimeDirTex = tex2DFastBicubicSample(unity_DynamicDirectionality, samplerunity_DynamicLightmap, realtimeUV); realtimeLightmap += DecodeDirectionalLightmap(realtimeLightmap, realtimeDirTex, worldNormal); #endif @@ -218,15 +426,67 @@ } #endif + #ifdef DYNAMICLIGHTMAP_ON + half3 getRealtimeLightmap(half2 uv, half3 worldNormal, int disableBicubic) + { + half2 realtimeUV = uv; + half4 bakedCol; + + // Sample main lightmap + #if defined(BICUBIC_LIGHTMAP) + [branch] + if (disableBicubic) + { + bakedCol = SAMPLE_TEXTURE2D(unity_DynamicLightmap, samplerunity_DynamicLightmap, realtimeUV); + } else { + bakedCol = tex2DFastBicubicSample(unity_DynamicLightmap, samplerunity_DynamicLightmap, realtimeUV); + } + #else + bakedCol = SAMPLE_TEXTURE2D(unity_DynamicLightmap, samplerunity_DynamicLightmap, realtimeUV); + #endif + half3 realtimeLightmap = DecodeRealtimeLightmap(bakedCol); + + // Sample directional lightmap + #ifdef DIRLIGHTMAP_COMBINED + { + half4 realtimeDirTex; + #if defined(BICUBIC_LIGHTMAP) + [branch] + if (disableBicubic) + { + realtimeDirTex = SAMPLE_TEXTURE2D(unity_DynamicDirectionality, samplerunity_DynamicLightmap, realtimeUV); + } else { + realtimeDirTex = tex2DFastBicubicSample(unity_DynamicDirectionality, samplerunity_DynamicLightmap, realtimeUV); + } + #else + realtimeDirTex = SAMPLE_TEXTURE2D(unity_DynamicDirectionality, samplerunity_DynamicLightmap, realtimeUV); + #endif + realtimeLightmap += DecodeDirectionalLightmap(realtimeLightmap, realtimeDirTex, worldNormal); + } + #endif + + return realtimeLightmap; + } + #endif + half computeSpecularAO(half NoV, half ao, half roughness) { - return clamp(pow(NoV + ao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ao, 0.0, 1.0); + return saturate(pow(NoV + ao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ao); + } + + half3 gtaoMultiBounce(half visibility, half3 albedo) { + // Jimenez et al. 2016, "Practical Realtime Strategies for Accurate Indirect Occlusion" + half3 a = 2.0404 * albedo - 0.3324; + half3 b = -4.7951 * albedo + 0.6417; + half3 c = 2.7552 * albedo + 0.6903; + + return max((visibility), ((visibility * a + b) * visibility + c) * visibility); } - half shEvaluateDiffuseL1Geomerics(half L0, half3 L1, half3 n) + half shEvaluateDiffuseL1Geomerics(half L0, half3 L1, float3 n) { // average energy - half R0 = L0; + half R0 = max(0,L0); // avg direction of incoming light half3 R1 = 0.5f * L1; @@ -252,6 +512,15 @@ return max(0, R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p))); } + half3 GetNonLinearSH(half3 L0, half3 L1r, half3 L1g, half3 L1b, float3 n) + { + half3 result; + result.r = shEvaluateDiffuseL1Geomerics(L0.r, L1r.xyz, n); + result.g = shEvaluateDiffuseL1Geomerics(L0.g, L1g.xyz, n); + result.b = shEvaluateDiffuseL1Geomerics(L0.b, L1b.xyz, n); + return result; + } + // Based on bakery's suggestion - use multiply instead of min for the darkest color half3 SubtractMainLightWithRealtimeAttenuationFromLightmapMultiply(half3 lightmap, half attenuation, half4 bakedColorTex, half3 normalWorld) { @@ -282,4 +551,109 @@ // 3) Pick darkest color return lightmap * realtimeShadow; } + + float4x4 getVertexLightsDir(float3 worldPos) { + float3 toLightX = float3(unity_4LightPosX0.x, unity_4LightPosY0.x, unity_4LightPosZ0.x); + float3 toLightY = float3(unity_4LightPosX0.y, unity_4LightPosY0.y, unity_4LightPosZ0.y); + float3 toLightZ = float3(unity_4LightPosX0.z, unity_4LightPosY0.z, unity_4LightPosZ0.z); + float3 toLightW = float3(unity_4LightPosX0.w, unity_4LightPosY0.w, unity_4LightPosZ0.w); + + float3 dirX = normalize(toLightX - worldPos); + float3 dirY = length(toLightY) > 0 ? normalize(toLightY - worldPos) : 0; + float3 dirZ = length(toLightZ) > 0 ? normalize(toLightZ - worldPos) : 0; + float3 dirW = length(toLightW) > 0 ? normalize(toLightW - worldPos) : 0; + + float4x4 retval = 0; + retval[0] = float4(dirX, 0); + retval[1] = float4(dirY, 0); + retval[2] = float4(dirZ, 0); + retval[3] = float4(dirW, 0); + return retval; + } + + float4x4 getVertexLightsColors(float3 worldPos, float3 normal, bool usendl = true) + { + float4 toLightX = unity_4LightPosX0 - worldPos.x; + float4 toLightY = unity_4LightPosY0 - worldPos.y; + float4 toLightZ = unity_4LightPosZ0 - worldPos.z; + + float4 lengthSq = 0; + lengthSq += toLightX * toLightX; + lengthSq += toLightY * toLightY; + lengthSq += toLightZ * toLightZ; + lengthSq = max(lengthSq, 0.000001); + + float4 ndl = 0; + UNITY_BRANCH + if (usendl) { + ndl += toLightX * normal.x; + ndl += toLightY * normal.y; + ndl += toLightZ * normal.z; + ndl = max (float4(0,0,0,0), ndl * rsqrt(lengthSq)); + ndl = ndl*0.5+0.5; + } + + float4 atten = 1.0 / (1.0 + lengthSq * unity_4LightAtten0); + float4 atten2 = saturate(1 - (unity_4LightAtten0 * lengthSq / 25)); // Black magic + atten = min(atten, atten2 * atten2); // more black magic + atten *= usendl ? ndl : 1; + + float4x4 retval = 0; + retval[0] = unity_LightColor[0] * atten.x; + retval[1] = unity_LightColor[1] * atten.y; + retval[2] = unity_LightColor[2] * atten.z; + retval[3] = unity_LightColor[3] * atten.w; + return retval; + } + + float4x4 getVertexLightsColors(float3 worldPos, float3 normal, out float4 attenuation, bool usendl = true) + { + float4 toLightX = unity_4LightPosX0 - worldPos.x; + float4 toLightY = unity_4LightPosY0 - worldPos.y; + float4 toLightZ = unity_4LightPosZ0 - worldPos.z; + + float4 lengthSq = 0; + lengthSq += toLightX * toLightX; + lengthSq += toLightY * toLightY; + lengthSq += toLightZ * toLightZ; + lengthSq = max(lengthSq, 0.000001); + + float4 ndl = 0; + UNITY_BRANCH + if (usendl) { + ndl += toLightX * normal.x; + ndl += toLightY * normal.y; + ndl += toLightZ * normal.z; + ndl = max (float4(0,0,0,0), ndl * rsqrt(lengthSq)); + ndl = ndl*0.5+0.5; + } + + float4 atten = 1.0 / (1.0 + lengthSq * unity_4LightAtten0); + float4 atten2 = saturate(1 - (unity_4LightAtten0 * lengthSq / 25)); // Black magic + atten = min(atten, atten2 * atten2); // more black magic + atten *= usendl ? ndl : 1; + + attenuation = atten; + + float4x4 retval = 0; + retval[0] = unity_LightColor[0] * atten.x; + retval[1] = unity_LightColor[1] * atten.y; + retval[2] = unity_LightColor[2] * atten.z; + retval[3] = unity_LightColor[3] * atten.w; + return retval; + } + + float4 getVertexLightRanges() + { + float4 ranges = 5.0 * (1.0 / sqrt(unity_4LightAtten0.xyzw)); + + if (all(!isnan(ranges))) return ranges; + + return float4( + isnan(ranges.x) ? 0.0 : ranges.x, + isnan(ranges.y) ? 0.0 : ranges.y, + isnan(ranges.z) ? 0.0 : ranges.z, + isnan(ranges.w) ? 0.0 : ranges.w + ); + } } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/Utilities.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/Utilities.orlsource index 43544e4a..0b7cf181 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/Utilities.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Libraries/Utilities.orlsource @@ -2,6 +2,11 @@ { #define FLT_EPSILON 1.192092896e-07 + // Helpful Macros + #define DEBUG_FC(x) FinalColor.rgb *= 0.0001; \ + FinalColor.rgb += x; \ + return + half3 BlendOverlay(half3 target, half3 source) { return (target > 0.5) * (1 - (1 - 2 * (target - 0.5)) * (1 - source)) + (target <= 0.5) * (2 * target * source); @@ -16,6 +21,14 @@ #endif } + bool isStereoView() { + #ifdef USING_STEREO_MATRICES + return true; + #else + return UNITY_MATRIX_P._13 != 0; + #endif + } + half3 BlendLighten(half3 target, half3 source) { return max(target, source); } @@ -83,7 +96,7 @@ return 1.0f + w3(a) / (w2(a) + w3(a)) + 0.5f; } - half4 tex2DFastBicubicSample(Texture2D tex, SamplerState texSampler, half2 uv) + half4 tex2DFastBicubicSample(Texture2D tex, SamplerState texSampler, float2 uv) { #if !defined(PLAT_QUEST) && defined(BICUBIC_LIGHTMAP) half width; @@ -119,7 +132,39 @@ #endif } - half4 tex2DFastBicubicSampleLevel(Texture2D tex, SamplerState texSampler, half2 uv, int level) + float4 tex2DFastBicubicSampleNoChecks(Texture2D tex, SamplerState texSampler, float2 uv) + { + half width; + half height; + tex.GetDimensions(width, height); + half x = uv.x * width; + half y = uv.y * height; + + + + x -= 0.5f; + y -= 0.5f; + half px = floor(x); + half py = floor(y); + half fx = x - px; + half fy = y - py; + + // note: we could store these functions in a lookup table texture, but maths is cheap + half g0x = g0(fx); + half g1x = g1(fx); + half h0x = h0(fx); + half h1x = h1(fx); + half h0y = h0(fy); + half h1y = h1(fy); + + half4 r = g0(fy) * (g0x * tex.Sample(texSampler, (half2(px + h0x, py + h0y) * 1.0f / width)) + + g1x * tex.Sample(texSampler, (half2(px + h1x, py + h0y) * 1.0f / width))) + + g1(fy) * (g0x * tex.Sample(texSampler, (half2(px + h0x, py + h1y) * 1.0f / width)) + + g1x * tex.Sample(texSampler, (half2(px + h1x, py + h1y) * 1.0f / width))); + return r; + } + + half4 tex2DFastBicubicSampleLevel(Texture2D tex, SamplerState texSampler, float2 uv, int level) { #if !defined(PLAT_QUEST) && defined(BICUBIC_LIGHTMAP) half width; @@ -155,33 +200,49 @@ #endif } - half getBakedNoise(Texture2D noiseTex, SamplerState noiseTexSampler, half3 p) + half getBakedNoise(Texture2D noiseTex, SamplerState noiseTexSampler, float3 p) { - half3 i = floor(p); p -= i; p *= p * (3. - 2. * p); - half2 uv = (p.xy + i.xy + half2(37, 17) * i.z + .5) / 256.; + float3 i = floor(p); p -= i; p *= p * (3. - 2. * p); + float2 uv = (p.xy + i.xy + float2(37, 17) * i.z + .5) / 256.; uv.y *= -1; p.xy = noiseTex.SampleLevel(noiseTexSampler, uv, 0).yx; return lerp(p.x, p.y, p.z); } - half getBakedNoiseBicubic(Texture2D noiseTex, SamplerState noiseTexSampler, half3 p) + // Manual bilinear sampling to avoid 8 bit precision issues + // Based on https://www.shadertoy.com/view/MllSzX + half getBakedNoiseBilinear(Texture2D noiseTex, SamplerState noiseTexSampler, float4 texSize, float3 p) { - half3 i = floor(p); p -= i; p *= p * (3. - 2. * p); - half2 uv = (p.xy + i.xy + half2(37, 17) * i.z + .5) / 256.; + float3 i = floor(p); p -= i; p *= p * (3. - 2. * p); + float2 uv = (p.xy + i.xy + float2(37, 17) * i.z + .5) / 256.; uv.y *= -1; - p.xy = tex2DFastBicubicSampleLevel(noiseTex, noiseTexSampler, uv, 0).yx; + + float2 pixelUv = uv * texSize.zw + 0.5; + float2 pixelUvFrac = frac(pixelUv); + + pixelUv = (floor(pixelUv) / texSize.zw) - texSize.xy * 0.5; + + float4 sample0 = noiseTex.SampleLevel(noiseTexSampler, pixelUv, 0); + float4 sample1 = noiseTex.SampleLevel(noiseTexSampler, pixelUv + float2(texSize.x, 0), 0); + float4 sample2 = noiseTex.SampleLevel(noiseTexSampler, pixelUv + float2(0, texSize.y), 0); + float4 sample3 = noiseTex.SampleLevel(noiseTexSampler, pixelUv + float2(texSize.x, texSize.y), 0); + + float4 filtered1 = lerp(sample0, sample1, pixelUvFrac.x); + float4 filtered2 = lerp(sample2, sample3, pixelUvFrac.x); + float4 filtered = lerp(filtered1, filtered2, pixelUvFrac.y); + + p.xy = filtered.yx; return lerp(p.x, p.y, p.z); } - half3 TransformObjectToWorld(half3 pos) + half getBakedNoiseBicubic(Texture2D noiseTex, SamplerState noiseTexSampler, float3 p) { - return mul(unity_ObjectToWorld, half4(pos, 1)).xyz; - }; - - half3 TransformWorldToObject(half3 pos) - { - return mul(unity_WorldToObject, half4(pos, 0)).xyz; - }; + float3 i = floor(p); p -= i; p *= p * (3. - 2. * p); + float2 uv = (p.xy + i.xy + float2(37, 17) * i.z + .5) / 256.; + uv.y *= -1; + p.xy = tex2DFastBicubicSampleLevel(noiseTex, noiseTexSampler, uv, 0).yx; + return lerp(p.x, p.y, p.z); + } half remap(half s, half a1, half a2, half b1, half b2) { @@ -413,6 +474,45 @@ return mul(rotMat, source); } + struct ORL_UVChannelData + { + float4 uv0; + float4 uv1; + float4 uv2; + float4 uv3; + }; + + #define SetupChannelData(d) (ORL_UVChannelData)0; \ + uvData.uv0 = d.uv0; \ + uvData.uv1 = d.uv1; \ + uvData.uv2 = d.uv2; \ + uvData.uv3 = d.uv3 + + float2 GetUVChannel(ORL_UVChannelData d, int channel, float4 ST) + { + float2 UV = 0; + switch (channel) { + case 0: UV = d.uv0; break; + case 1: UV = d.uv1; break; + case 2: UV = d.uv2; break; + case 3: UV = d.uv3; break; + } + UV = UV * ST.xy + ST.zw; + return UV; + } + + float2 RotateAroundCenter2D(float2 source, float angle) + { + angle = radians(angle); + float sinAngle = sin(angle); + float cosAngle = cos(angle); + float2x2 rotationMatrix = { cosAngle, -sinAngle, sinAngle, cosAngle }; + source -= 0.5; + source = mul(rotationMatrix, source); + source += 0.5; + return source; + } + float GLSLMod(float x, float y) { @@ -423,4 +523,124 @@ { return (((x)-(y)*floor((x)/(y)))); } + + // Found in this article on tonemapping: https://mini.gmshaders.com/p/tonemaps + // Narkowicz 2015, "ACES Filmic Tone Mapping Curve" + float3 Tonemap_ACES(float3 x) + { + float a = 2.51; + float b = 0.03; + float c = 2.43; + float d = 0.59; + float e = 0.14; + return (x * (a * x + b)) / (x * (c * x + d) + e); + } + + // Hable 2010, "Filmic Tonemapping Operators" + float3 Tonemap_Uncharted2(float3 x) + { + x *= 16.0; + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + + return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F; + } + + float3 Tonemap_Unreal(float3 x) + { + // Unreal 3, Documentation: "Color Grading" + // Adapted to be close to Tonemap_ACES, with similar range + // Gamma 2.2 correction is baked in, don't use with sRGB conversion! + return x / (x + 0.155) * 1.019; + } + + // https://github.com/yuki-koyama/enhancer + // MIT License + + // Copyright (c) 2018 Yuki Koyama + + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + + // The above copyright notice and this permission notice shall be included in all + // copies or substantial portions of the Software. + + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + // SOFTWARE. + float3 applyLiftGammaGainEffect(float3 linear_rgb, float3 lift, float3 gamma, float3 gain) + { + float3 lift_applied_linear_rgb = clamp((linear_rgb - 1.0) * (2.0 - lift) + 1.0, 0.0, 1.0); + float3 gain_applied_linear_rgb = lift_applied_linear_rgb * gain; + float3 gamma_applied_linear_rgb = pow(gain_applied_linear_rgb, 1.0 / gamma); + + return gamma_applied_linear_rgb; + } + + + // https://github.com/MochiesCode/Mochies-Unity-Shaders/ + // MIT License + + // Copyright (c) 2020 MochiesCode + + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + + // The above copyright notice and this permission notice shall be included in all + // copies or substantial portions of the Software. + + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + // SOFTWARE. + float3 GetSpritesheetUV(float2 uv, float2 rowsColumns, float fps, int pauseFrames, int frameOffset){ + float2 size = float2(1/rowsColumns.x, 1/rowsColumns.y); + uint totalFrames = rowsColumns.x * rowsColumns.y; + uint index = 0; + index = (_Time.y * fps + frameOffset) % (totalFrames + pauseFrames); + + if (index > totalFrames) { + index = totalFrames; + } + + uint indexX = index % rowsColumns.x; + uint indexY = floor((index % totalFrames) / rowsColumns.x); + float2 offset = float2(size.x*indexX,-size.y*indexY); + float2 uv1 = uv*size; + uv1.y = uv1.y + size.y*(rowsColumns.y - 1); + uv = uv1 + offset; + return float3(uv,0); + } + + // SDFS + // https://iquilezles.org/articles/distfunctions2d/ + float SDFBox(float2 p, float2 b ) + { + float2 d = abs(p)-b; + return length(max(d,0.0)) + min(max(d.x,d.y),0.0); + } + + float SDFCircle(float2 p, float r) + { + return length(p) - r; + } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/MapBaker.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/MapBaker.orlsource new file mode 100644 index 00000000..e01ea57c --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/MapBaker.orlsource @@ -0,0 +1,10 @@ +%Template("@/Templates/VFX") + +%Includes() +{ + "target", + "@/Structs/MeshData", + "@/Structs/PBR/SurfaceData", + "@/Functions/MapBaker/FragmentBase", + "@/Functions/VertexBase", +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/MapBaker.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/MapBaker.orlsource.meta new file mode 100644 index 00000000..73429d0b --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/MapBaker.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 16038c503abb9384ba6dd389a4884018 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/Toon_v2.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/Toon_v2.orlsource new file mode 100644 index 00000000..b774e1ef --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/Toon_v2.orlsource @@ -0,0 +1,10 @@ +%Template("@/Templates/Toon") + +%Includes() +{ + "target", + "@/Structs/Toon/MeshData", + "@/Structs/Toon/v2/SurfaceData", + "@/Functions/Toon/v2/FragmentBase", + "@/Functions/VertexBase", +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/Toon_v2.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/Toon_v2.orlsource.meta new file mode 100644 index 00000000..564bc70d --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/LightingModels/Toon_v2.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6acc18955c814fb4ebd29a418bea89fd +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AreaLit.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AreaLit.orlsource new file mode 100644 index 00000000..f5b82a66 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AreaLit.orlsource @@ -0,0 +1,164 @@ +%Properties() +{ + [ToggleUI]UI_AreaLitHeader ("# AreaLit", Int) = 1 + UI_AreaLitDocs("[This module has documentation](https://shaders.orels.sh/docs/orl-standard/arealit)", Int) = 0 + [Toggle(INTEGRATE_AREALIT)]_IntegrateAreaLit("Integrate AreaLit", Int) = 0 + UI_AreaLitDownload("[Make sure to download AreaLit before enabling this option](https://lox9973.booth.pm/items/3661829)", Int) = 0 + [ToggleUI]_AreaLitEnableOnMobile("Enable on Mobile", Int) = 0 + UI_AreaLitEnableOnMobileNote("?> AreaLit is pretty heavy for mobile devices, please test your content when enabling this option", Int) = 0 + [ToggleUI]_AreaLitClampBrightness("Clamp Brightness", Int) = 0 + _AreaLitMaxBrightness("Max Brightness %ShowIf(_AreaLitClampBrightness)", Range(0,1)) = 1 + [ToggleOff]_OpaqueLights("Opaque Lights %ShowIf(INTEGRATE_AREALIT)", Float) = 1.0 + _AreaLitRoughnessModifier("Roughness Modifier %ShowIf(INTEGRATE_AREALIT)", Range(-1,1)) = 0 + [TpggleUI]_AreaLitAlphaPremultiply("Alpha Premultiply %ShowIf(INTEGRATE_AREALIT)", Float) = 0 + + UI_AreaLitInternalHeader("## AreaLit Inputs %ShowIf(INTEGRATE_AREALIT)", Int) = 0 + _LightMesh("Light Mesh > %ShowIf(INTEGRATE_AREALIT)", 2D) = "black" {} + _LightTex0("Light Texture 0 > %ShowIf(INTEGRATE_AREALIT)", 2D) = "white" {} + _LightTex1("Light Texture 1 > %ShowIf(INTEGRATE_AREALIT)", 2D) = "black" {} + [Tooltip(Intended for indirect light)]_LightTex2("Light Texture 2 > %ShowIf(INTEGRATE_AREALIT)", 2D) = "black" {} + [Tooltip(Intended for static lights)]_LightTex3("Light Texture 3 > %ShowIf(INTEGRATE_AREALIT)", 2DArray) = "black" {} + _AreaLitOcclusionMap("Shadowmask (Occlusion Map) > %ShowIf(INTEGRATE_AREALIT)", 2D) = "white" {} + [Enum(UV0,0,UV1,1,UV1_LightmapST,9)]_AreaLitOcclusionUVSet("Shadowmask UV Set %ShowIf(INTEGRATE_AREALIT && _AreaLitOcclusionMap)", Int) = 0 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment INTEGRATE_AREALIT + #pragma shader_feature_local_fragment _OPAQUELIGHTS_OFF +} + +%ShaderDefines() +{ + #if defined(INTEGRATE_AREALIT) + #define _INTEGRATE_CUSTOMGI_FLEX + #endif + + #define INCLUDE_AREALIT defined(INTEGRATE_AREALIT) + + #if INCLUDE_AREALIT + #include "Assets/AreaLit/Shader/Lighting.hlsl" + #endif +} + +%Variables() +{ + int _AreaLitEnableOnMobile; + int _AreaLitClampBrightness; + half _AreaLitMaxBrightness; + half _AreaLitRoughnessModifier; + int _AreaLitAlphaPremultiply; + int _AreaLitOcclusionUVSet; + float4 _AreaLitOcclusionMap_TexelSize; + float4 _AreaLitOcclusionMap_ST; +} + +%Textures() +{ + TEXTURE2D(_AreaLitOcclusionMap); + SAMPLER(sampler_AreaLitOcclusionMap); +} + +%CustomGI("AreaLitCustomGI") +{ + half4 GetAraLitOcclusion(half occlusion, MeshData d) + { + if (_AreaLitOcclusionMap_TexelSize.z <= 16) return occlusion.xxxx; + + float2 uv = _AreaLitOcclusionUVSet == 0 ? d.uv0 : d.uv1; + + uv = uv * _AreaLitOcclusionMap_ST.xy + _AreaLitOcclusionMap_ST.zw; + + #if defined(LIGHTMAP_ON) + if (_AreaLitOcclusionUVSet == 9) { + uv = uv * unity_LightmapST.xy + unity_LightmapST.zw; + } + #endif + + return SAMPLE_TEXTURE2D(_AreaLitOcclusionMap, sampler_AreaLitOcclusionMap, uv); + } + + void AreaLitCustomGI(MeshData d, SurfaceData o, half3 tangentNormal, FragmentData i, half clampedRoughness, inout half3 customGISpecular, inout half3 customGIDiffuse) + { + // VFX lighting model does not support customgi functions + #if !defined(ORL_LIGHTING_MODEL_VFX) + { + #if defined(PLAT_QUEST) + if (!_AreaLitEnableOnMobile) return; + #endif + + #if defined(INTEGRATE_AREALIT) + half4 diffuse = 0; + half4 specular = 0; + + AreaLightFragInput input; + input.pos = d.worldSpacePosition; + input.view = d.worldSpaceViewDir; + input.normal = o.Normal; + input.occlusion = GetAraLitOcclusion(o.Occlusion, d); + input.roughness = max(saturate(clampedRoughness + _AreaLitRoughnessModifier), 0.007921); + input.screenPos = i.pos.xy; + + ShadeAreaLights(input, diffuse, specular, true, true, isStereoView()); + + if (_AreaLitClampBrightness) { + half3 hsv = RGB2HSV(specular); + hsv.z = tanh(hsv.z) * max(0, _AreaLitMaxBrightness); + customGISpecular += HSV2RGB(hsv); + } else { + customGISpecular += specular.rgb; + } + customGIDiffuse += diffuse.rgb; + #endif + } + #endif + + } +} + +%Color("AreaLitColor") +{ + void AreaLitColor(MeshData d, FragmentData i, inout half4 FinalColor, bool facing) + { + #if defined(ORL_LIGHTING_MODEL_VFX) + { + #if defined(PLAT_QUEST) + if (!_AreaLitEnableOnMobile) return; + #endif + + #if defined(INTEGRATE_AREALIT) + half4 diffuse = 0; + half4 specular = 0; + + AreaLightFragInput input; + input.pos = d.worldSpacePosition; + input.view = d.worldSpaceViewDir; + input.normal = d.worldNormal; + if (!facing) + { + input.view = -d.worldSpaceViewDir; + } + input.occlusion = GetAraLitOcclusion(1, d); + input.roughness = saturate(0.5 + _AreaLitRoughnessModifier); + input.screenPos = i.pos.xy; + + ShadeAreaLights(input, diffuse, specular, true, true, isStereoView()); + + if (_AreaLitClampBrightness) { + half3 hsv = RGB2HSV(specular); + hsv.z = tanh(hsv.z) * max(0, _AreaLitMaxBrightness); + FinalColor.rgb += HSV2RGB(hsv); + } else { + + FinalColor.rgb += specular.rgb; + } + FinalColor.rgb += diffuse.rgb; + if (_AreaLitAlphaPremultiply) + { + FinalColor.rgb *= FinalColor.a; + } + #endif + } + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AreaLit.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AreaLit.orlsource.meta new file mode 100644 index 00000000..8d9e04b4 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AreaLit.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 0e627b5abeb4aba498b3fb9b04376dcc +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AudioLink.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AudioLink.orlsource index 8bdfffd1..cea17592 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AudioLink.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AudioLink.orlsource @@ -42,6 +42,7 @@ #define ALPASS_GENERALVU_UNIX_DAYS uint2(5,23) #define ALPASS_GENERALVU_UNIX_SECONDS uint2(6,23) #define ALPASS_GENERALVU_SOURCE_POS uint2(7,23) + #define ALPASS_MEDIASTATE uint2(5,22) #define ALPASS_CCINTERNAL uint2(12,22) //Size: 12, 2 #define ALPASS_CCCOLORS uint2(25,22) //Size: 12, 1 (Note Color #0 is always black, Colors start at 1) @@ -131,6 +132,7 @@ #endif } + // DEPRECATED! Use AudioLinkGetVersionMajor and AudioLinkGetVersionMinor() instead. //Get version of audiolink present in the world, 0 if no audiolink is present float AudioLinkGetVersion() { @@ -149,6 +151,37 @@ return 0; } + float AudioLinkGetVersionMajor() + { + return AudioLinkData(ALPASS_GENERALVU).y; + } + + float AudioLinkGetVersionMinor() + { + // If the major version is 1 or greater, we are using the new versioning system. + if (AudioLinkGetVersionMajor() > 0) + { + return AudioLinkData(ALPASS_GENERALVU).w; + } + // Otherwise, defer to the old logic for determining version. + else + { + int2 dims; + #if !defined(AUDIOLINK_STANDARD_INDEXING) + _AudioTexture.GetDimensions(dims.x, dims.y); + #else + dims = _AudioTexture_TexelSize.zw; + #endif + + if (dims.x >= 128) + return AudioLinkData(ALPASS_GENERALVU).x; + else if (dims.x > 16) + return 1; + else + return 0; + } + } + // This pulls data from this texture. #define AudioLinkGetSelfPixelData(xy) _SelfTexture2D[xy] diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AudioLinkEffects.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AudioLinkEffects.orlsource index aa133242..1f7b525a 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AudioLinkEffects.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AudioLinkEffects.orlsource @@ -64,7 +64,7 @@ %ShaderFeatures() { - #pragma shader_feature_local _ AL_EFFECT_BAND_SELECTION AL_EFFECT_UV_BASED AL_EFFECT_WAVEFORM AL_EFFECT_PULSE AL_EFFECT_BAR + #pragma shader_feature_local_fragment _ AL_EFFECT_BAND_SELECTION AL_EFFECT_UV_BASED AL_EFFECT_WAVEFORM AL_EFFECT_PULSE AL_EFFECT_BAR } %ShaderDefines() @@ -136,7 +136,7 @@ half3 finalEmission = 0; half finalAlpha = 1; - half2 uv = 0; + float2 uv = 0; switch(_ALUVChannel) { case 0: uv = d.uv0.xy; break; @@ -150,13 +150,13 @@ half uvSource = lerp(uv.x, lerp(uv.y, lerp(1 - uv.x, 1 - uv.y, saturate(_BandScrollAxis - 2)), saturate(_BandScrollAxis - 1)), saturate(_BandScrollAxis)); half scaledUv = (uvSource * _BandHistoryRange) % 128.0; - half4 bandData = AudioLinkLerp(half2(scaledUv, clamp(_BandFrequency - 1, 0, 3))); + half4 bandData = AudioLinkLerp(float2(scaledUv, clamp(_BandFrequency - 1, 0, 3))); finalEmission = bandData.rgb * _ALTint; finalAlpha = bandData.r; #elif defined(AL_EFFECT_UV_BASED) - half2 scaledUv = half2(lerp(uv.x, uv.y, _UVFlipXY) * _UVHistoryRange % 128, floor(lerp(uv.y, uv.x, _UVFlipXY) * 4)); + float2 scaledUv = float2(lerp(uv.x, uv.y, _UVFlipXY) * _UVHistoryRange % 128, floor(lerp(uv.y, uv.x, _UVFlipXY) * 4)); half4 bandData = AudioLinkLerp(scaledUv).rrra; if (_UVUseThemeColors) { @@ -233,7 +233,7 @@ #elif defined(AL_EFFECT_BAR) - half uvSource = lerp(uv.x, lerp(uv.y, lerp(1 - uv.x, 1 - uv.y, saturate(_BarAxis - 2)), saturate(_BarAxis - 1)), saturate(_BarAxis)); + float uvSource = lerp(uv.x, lerp(uv.y, lerp(1 - uv.x, 1 - uv.y, saturate(_BarAxis - 2)), saturate(_BarAxis - 1)), saturate(_BarAxis)); half3 color = SAMPLE_TEXTURE2D(_BarColor, sampler_BarColor, half2(uvSource, 0)).rgb; half bandData = 0; UNITY_BRANCH diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Bakery.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Bakery.orlsource index 6fca6db7..42abd1af 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Bakery.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Bakery.orlsource @@ -1,8 +1,11 @@ %ShaderFeatures() { - #pragma shader_feature_local BAKERY_ENABLED - #pragma shader_feature_local _ BAKERY_RNM BAKERY_SH BAKERY_MONOSH - #pragma shader_feature_local BAKERY_SHNONLINEAR + #pragma shader_feature_local_fragment BAKERY_ENABLED + #pragma shader_feature_local_fragment _ BAKERY_RNM BAKERY_SH BAKERY_MONOSH + #pragma shader_feature_local_fragment BAKERY_SHNONLINEAR + #pragma shader_feature_local_fragment BAKERY_VOLUME + #pragma shader_feature_local_fragment BAKERY_COMPRESSED_VOLUME + #pragma shader_feature_local_fragment BAKERY_VOLROTATIONY } %ShaderDefines() @@ -34,6 +37,7 @@ #endif #endif } + %Variables() { #if defined(BAKERY_ENABLED) @@ -42,13 +46,30 @@ #endif #endif - #ifdef BAKERY_VOLUME + #if defined(BAKERY_ENABLED) && defined(BAKERY_VOLUME) half3 _VolumeMin; - half3 _VolumnInvSize; + half3 _VolumeInvSize; half3 _GlobalVolumeMin; + int _Udon_GlobalVolumeAdapterEnabled; + half3 _Udon_GlobalVolumeMin; half3 _GlobalVolumeInvSize; + half3 _Udon_GlobalVolumeInvSize; + + #if defined(BAKERY_VOLROTATION) + float4x4 _GlobalVolumeMatrix; + float4x4 _Udon_GlobalVolumeMatrix; + float4x4 _VolumeMatrix; + #endif + + #if defined(BAKERY_VOLROTATIONY) + float2 _GlobalVolumeRY; + float2 _Udon_GlobalVolumeRY; + float2 _VolumeRY; + #endif + #endif } + %Textures() { #if defined(BAKERY_ENABLED) @@ -60,14 +81,18 @@ #endif #endif - // Bakery volumes are technically not supported yet - // But I added the variables for the future - #ifdef BAKERY_VOLUME + #if defined(BAKERY_ENABLED) && defined(BAKERY_VOLUME) TEXTURE3D(_Volume0); TEXTURE3D(_Volume1); TEXTURE3D(_Volume2); TEXTURE3D(_VolumeMask); + + #if defined(BAKERY_COMPRESSED_VOLUME) + TEXTURE3D(_Volume3); + #endif + SAMPLER(sampler_Volume0); + SAMPLER(sampler_VolumeMask); #endif } @@ -135,6 +160,31 @@ #define lumaConv float3(0.2125f, 0.7154f, 0.0721f) + struct BakeryVolumeData + { + float3 L0; + float3 L1x; + float3 L1y; + float3 L1z; + + float4 tex0; + float4 tex1; + float4 tex2; + float4 tex3; + + float3 viewDir; + float3 normal; + float3 uv; + float occlusion; + }; + + struct BakeryVolumeSpecularData + { + float3 direction; + float3 color; + float NoV; + }; + #ifdef BAKERY_BICUBIC float BakeryBicubic_w0(float a) { @@ -248,3 +298,51 @@ #endif //BAKERY_ENABLED } + +// These are defined separately so that they can reference Tesxture variables from inside the pass +%PassFunctions() +{ + // Bakery volume helpers + #if defined(BAKERY_ENABLED) + #if defined(BAKERY_VOLUME) + BakeryVolumeData GetBakeryVolumeTextureData(BakeryVolumeData data) + { + #ifdef BAKERY_COMPRESSED_VOLUME + data.tex0 = _Volume0.Sample(sampler_Volume0, data.uv); + data.tex1 = _Volume1.Sample(sampler_Volume0, data.uv) * 2 - 1; + data.tex2 = _Volume2.Sample(sampler_Volume0, data.uv) * 2 - 1; + data.tex3 = _Volume3.Sample(sampler_Volume0, data.uv) * 2 - 1; + data.L0 = data.tex0.xyz; + data.L1x = data.tex1.xyz * data.L0 * 2; + data.L1y = data.tex2.xyz * data.L0 * 2; + data.L1z = data.tex3.xyz * data.L0 * 2; + #else + data.tex0 = _Volume0.Sample(sampler_Volume0, data.uv); + data.tex1 = _Volume1.Sample(sampler_Volume0, data.uv); + data.tex2 = _Volume2.Sample(sampler_Volume0, data.uv); + data.L0 = data.tex0.xyz; + data.L1x = data.tex1.xyz; + data.L1y = data.tex2.xyz; + data.L1z = float3(data.tex0.w, data.tex1.w, data.tex2.w); + #endif + return data; + } + + BakeryVolumeSpecularData GetBakeryVolumeSpecularData(BakeryVolumeData data) + { + BakeryVolumeSpecularData ret = (BakeryVolumeSpecularData) 0; + + float3 nL1x = data.L1x / data.L0; + float3 nL1y = data.L1y / data.L0; + float3 nL1z = data.L1z / data.L0; + ret.direction = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); + ret.color = data.L0 + ret.direction.x * data.L1x + ret.direction.y * data.L1y + ret.direction.z * data.L1z; + ret.NoV = dot(data.normal, data.viewDir); + ret.NoV = max(ret.NoV, 0.0001); + return ret; + } + + #endif + + #endif +} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/BaseColor.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/BaseColor.orlsource index 2ec10967..ea33f2cf 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/BaseColor.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/BaseColor.orlsource @@ -24,7 +24,7 @@ half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, d.uv0 * _MainTex_ST.xy + _MainTex_ST.zw); o.Albedo = albedo.rgb * _Color.rgb; - #if (NEED_ALBEDO_ALPHA) + #if defined(NEED_ALBEDO_ALPHA) o.Alpha = albedo.a * _Color.a; #endif } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DepthFade.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DepthFade.orlsource new file mode 100644 index 00000000..d76b1036 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DepthFade.orlsource @@ -0,0 +1,63 @@ +%Properties() +{ + UI_DepthFadeHeader("# Depth Fade", Int) = 1 + UI_DepthFadeDocs("[This module has documentation](https://shaders.orels.sh/docs/configurable-shaders/modules/depth-fade)", Int) = 0 + [Toggle(DEPTH_FADE)]_DepthFade("Enable Depth Fade", Int) = 0 + _DepthParticlesNearFadeDistance("Near Distance %ShowIf(DEPTH_FADE)", Float) = 0.0 + _DepthParticlesFarFadeDistance("Far Distance %ShowIf(DEPTH_FADE)", Float) = 1.0 + [ToggleUI]_DepthFadePremultiply("Alpha Premultiply %ShowIf(DEPTH_FADE)", Int) = 0 +} + +%Variables() +{ + float _DepthParticlesNearFadeDistance; + float _DepthParticlesFarFadeDistance; + int _DepthFadePremultiply; +} + +%ShaderFeatures() +{ + #pragma shader_feature_local DEPTH_FADE +} + +%AdditionalFragmentData() +{ + float4 depthFadeParams : DEPTH_FADE_PARAMS; +} + +%AdditionalMeshData() +{ + float4 depthFadeParams; +} + +%AdditionalMeshDataCreator() +{ + d.depthFadeParams = i.depthFadeParams; +} + +%Vertex("DepthFadeVertex") +{ + void DepthFadeVertex(VertexData v, inout FragmentData o) + { + #if defined(DEPTH_FADE) + o.depthFadeParams = GetScreenPosition(TransformObjectToHClip(v.vertex)); + o.depthFadeParams.z = -TransformWorldToView(TransformObjectToWorld(v.vertex)).z; + #endif + } +} + +%Fragment("DepthFadeFragment") +{ + void DepthFadeFragment(MeshData d, inout SurfaceData o) + { + #if defined(DEPTH_FADE) + float sceneZ = LinearEyeDepth(SampleSceneDepth(d.depthFadeParams.xy / d.depthFadeParams.w)); + float softParticleInvFade = 1.0 / (_DepthParticlesFarFadeDistance - _DepthParticlesNearFadeDistance); + float fade = saturate(softParticleInvFade * ((sceneZ - _DepthParticlesNearFadeDistance) - d.depthFadeParams.z)); + o.Alpha *= fade; + if (_DepthFadePremultiply) { + o.Albedo *= fade; + } + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DepthFade.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DepthFade.orlsource.meta new file mode 100644 index 00000000..ec592b45 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DepthFade.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 0af59be240d33a04d8b0a2d0ad82fbe0 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Details.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Details.orlsource index 958ae21e..1057633e 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Details.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Details.orlsource @@ -5,17 +5,19 @@ [Toggle(DETAILS_OVERLAY)]_DetailsOverlay("Enable Details", Int) = 0 [ToggleUI]_DIgnoreMask("Ignore Mask %ShowIf(DETAILS_OVERLAY)", Int) = 0 UI_IgnoreMaskNote("> Force-draws the detail effects %ShowIf(DETAILS_OVERLAY)", Int) = 0 - [KeywordEnum(Packed, Separated)]DETAILS_MODE("Detail Map Mode %ShowIf(DETAILS_OVERLAY)", Int) = 0 + [KeywordEnum(Packed, Separated)]DETAILS_MODE("Detail Map Mode %ShowIf(DETAILS_OVERLAY)", Int) = 1 _DDetailsMap("Details Map %ShowIf(DETAILS_OVERLAY)", 2D) = "gray" { } UI_DetailsMapNote("> R: Albedo, G: Normal G, B: Smooth, A: Normal R. Uncheck sRGB! %ShowIf(DETAILS_OVERLAY && DETAILS_MODE_PACKED)", Int) = 0 - UI_DetailsMapNoteSeparate("> RGB: Albedo, A: Smooth. Uncheck sRGB! %ShowIf(DETAILS_OVERLAY && DETAILS_MODE_SEPARATED)", Int) = 0 + UI_DetailsMapNoteSeparate("> RGB: Albedo, A: Smooth %ShowIf(DETAILS_OVERLAY && DETAILS_MODE_SEPARATED)", Int) = 0 [NoScaleOffset]_DDetailsNormal("Details Normal Map > %ShowIf(DETAILS_OVERLAY && DETAILS_MODE_SEPARATED)", 2D) = "bump" { } [Enum(UV, 0, Local Space, 1, World Space, 2)]_DMappingSpace("Mapping Space %ShowIf(DETAILS_OVERLAY)", Int) = 0 [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_DUVChannel("UV Set %ShowIf(_DMappingSpace == 0 && DETAILS_OVERLAY)", Int) = 0 [Enum(X, 0, Y, 1, Z, 2)]_DPlanarAxisX("X Axis %ShowIf(_DMappingSpace > 0 && DETAILS_OVERLAY) %CombineWith(_DPlanarAxisY)", Int) = 0 [HideInInspector][Enum(X, 0, Y, 1, Z, 2)]_DPlanarAxisY("Y Axis", Int) = 2 _DAlbedoScale("Albedo Scale %ShowIf(DETAILS_OVERLAY)", Range(0.0, 2.0)) = 1 - UI_DetailAlbedoNote("> Values < 0.5 - darken, > 0.5 - lighten %ShowIf(DETAILS_OVERLAY)", Int) = 0 + UI_DetailAlbedoNote("> Values < 0.5 - darken, > 0.5 - lighten %ShowIf(DETAILS_OVERLAY && !_DAlbedoMixingLegacy)", Int) = 0 + UI_DAlbedoMixingLegacyNote("> Multiplies albedo by 2x the detail Albedo. Same as BIRP Standard Shader %ShowIf(DETAILS_OVERLAY && _DAlbedoMixingLegacy && DETAILS_MODE_SEPARATED)", Int) = 0 + [ToggleUI]_DAlbedoMixingLegacy("Legacy Albedo Mixing %ShowIf(DETAILS_OVERLAY && DETAILS_MODE_SEPARATED)", Int) = 0 _DNormalScale("Normal Scale %ShowIf(DETAILS_OVERLAY)", Range(0.0, 2.0)) = 1 [ToggleUI]_DNormalFlipY("Flip Y (UE Mode) %ShowIf(DETAILS_OVERLAY)", Int) = 0 _DSmoothScale("Smooth Scale %ShowIf(DETAILS_OVERLAY)", Range(0.0, 2.0)) = 1 @@ -24,8 +26,8 @@ %ShaderFeatures() { - #pragma shader_feature_local DETAILS_OVERLAY - #pragma shader_feature_local _ DETAILS_MODE_PACKED DETAILS_MODE_SEPARATED + #pragma shader_feature_local_fragment DETAILS_OVERLAY + #pragma shader_feature_local_fragment _ DETAILS_MODE_PACKED DETAILS_MODE_SEPARATED } %ShaderDefines() @@ -47,6 +49,7 @@ half _DNormalScale; int _DNormalFlipY; half _DSmoothScale; + int _DAlbedoMixingLegacy; } %Textures() @@ -100,7 +103,7 @@ #endif half mask = lerp(masks, 1, _DIgnoreMask); - half2 uv = d.uv0.xy; + float2 uv = d.uv0.xy; switch(_DUVChannel) { case 1: uv = d.uv1.xy; break; @@ -118,6 +121,7 @@ half4 detailsMap = SAMPLE_TEXTURE2D(_DDetailsMap, sampler_DDetailsMap, uv); #if defined(DETAILS_MODE_PACKED) + // 0.5 is the neutral value half detailAlbedo = detailsMap.r * 2.0 - 1.0; half detailSmooth = detailsMap.b * 2.0 - 1.0; @@ -126,10 +130,15 @@ { detailsMap.g = 1 - detailsMap.g; } - detailNormal = UnpackNormalAG(detailsMap, _DNormalScale); + detailNormal = UnpackNormalScale(float4(detailsMap.ag, 1, 1), _DNormalScale); half detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); - #elif defined(DETAILS_MODE_SEPARATED) - half3 detailAlbedo = detailsMap.rgb * 2.0 - 1.0; + half3 albedoOverlay = lerp(sqrt(o.Albedo), (detailAlbedo < 0.0) ? 0.0.xxx : 1.0.xxx, detailAlbedoSpeed * detailAlbedoSpeed); + albedoOverlay *= albedoOverlay; + + // Packed mode only supports HDRP-style albedo mixing + o.Albedo = lerp(o.Albedo, saturate(albedoOverlay), mask); + + #elif defined(DETAILS_MODE_SEPARATED) half detailSmooth = detailsMap.a * 2.0 - 1.0; half4 packedNormal = SAMPLE_TEXTURE2D(_DDetailsNormal, sampler_DDetailsNormal, uv); @@ -137,16 +146,20 @@ { packedNormal.g = 1 - packedNormal.g; } - half3 detailNormal = UnpackScaleNormal(packedNormal, _DNormalScale); - - half3 detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); + half3 detailNormal = UnpackNormalScale(packedNormal, _DNormalScale); + + // Separated mdoe supports BIRP-style 2x albedo mixing + if (_DAlbedoMixingLegacy) { + o.Albedo *= LerpWhiteTo(detailsMap.rgb * unity_ColorSpaceDouble.rgb, mask * _DAlbedoScale); + } else { + half3 detailAlbedo = detailsMap.rgb * 2.0 - 1.0; + half3 detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); + half3 albedoOverlay = lerp(sqrt(o.Albedo), (detailAlbedo < 0.0) ? 0.0.xxx : 1.0.xxx, detailAlbedoSpeed * detailAlbedoSpeed); + albedoOverlay *= albedoOverlay; + o.Albedo = lerp(o.Albedo, saturate(albedoOverlay), mask); + } #endif - // do the albedo details - half3 albedoOverlay = lerp(sqrt(o.Albedo), (detailAlbedo < 0.0) ? 0.0.xxx : 1.0.xxx, detailAlbedoSpeed * detailAlbedoSpeed); - albedoOverlay *= albedoOverlay; - o.Albedo = lerp(o.Albedo, saturate(albedoOverlay), mask); - // do the smooth details half detailSmoothSpeed = saturate(abs(detailSmooth) * _DSmoothScale); half smoothOverlay = lerp(o.Smoothness, (detailSmooth < 0.0) ? 0.0 : 1.0, detailSmoothSpeed * detailSmoothSpeed); diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Displacement.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Displacement.orlsource new file mode 100644 index 00000000..27b066ba --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Displacement.orlsource @@ -0,0 +1,30 @@ +%Properties() +{ + [ToggleUI]UI_VertexHeightHeader("# Displacement", Int) = 0 + _VertexHeight("Displacement Map >", 2D) = "gray" {} + _VertexHeightAmount("Displacement Amount", Range(0, 3)) = 0 + _VertexHeightOffset("Displacement Offset", Range(-1, 1)) = 0.5 +} + +%Variables() +{ + half _VertexHeightAmount; + half _VertexHeightOffset; +} + +%Textures() +{ + TEXTURE2D(_VertexHeight); + SAMPLER(sampler_VertexHeight); +} + +%Vertex("VertexHeightVertex") +{ + void VertexHeightVertex(inout VertexData v) + { + float2 uv = v.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; + half height = (SAMPLE_TEXTURE2D_LOD(_VertexHeight, sampler_VertexHeight, uv, 0).r * 2 - 1); + half3 mainOffset = v.vertex.xyz + v.normal * (height + _VertexHeightOffset) * _VertexHeightAmount; + v.vertex.xyz = mainOffset; + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Displacement.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Displacement.orlsource.meta new file mode 100644 index 00000000..a2a23401 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Displacement.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: e9c9e906d966c214fb055b60d4f93b46 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Dissolve.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Dissolve.orlsource index d51ef23a..62304b16 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Dissolve.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Dissolve.orlsource @@ -1,7 +1,10 @@ %Properties() { UI_DissolveHeader("# Dissolve", Int) = 1 + UI_DissolveDocs("[This module has documentation](https://shaders.orels.sh/docs/orl-standard/dissolve)", Int) = 0 _DissolveCutoff("Cutoff", Range(0,1)) = 0.04 + _DissolveCutoffRangeMin("Cutoff Range Min %CombineWith(_DissolveCutoffRangeMax)", Float) = -0.1 + [HideInInspector]_DissolveCutoffRangeMax("Max", Float) = 1.1 [Enum(Local Position, 0, UV, 1, Texture, 2)]_DissolveSource("Fade Based On", Int) = 0 _DissolveTexture("Fade Texture %ShowIf(_DissolveSource == 2)", 2D) = "grayscaleRamp" {} UI_DissolveTextureNote("> This texture will be used as a base of fade progression. Generally expected to be some kind of gradient, sometimes multiplied by a pattern %ShowIf(_DissolveSource == 2)", Int) = 0 @@ -26,6 +29,8 @@ %Variables() { half _DissolveCutoff; + half _DissolveCutoffRangeMin; + half _DissolveCutoffRangeMax; int _DissolveSource; int _DissolveDirection; half4 _DissolveTexture_ST; @@ -58,25 +63,25 @@ %ShaderFeatures() { - #pragma shader_feature_local DISSOLVE_SHOW_FADE_GRAD + #pragma shader_feature_local_fragment DISSOLVE_SHOW_FADE_GRAD } %ShaderTags() { - "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" + "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" "ORL_RenderType" = "Cutout" } %Fragment("DissolveFragment") { void DissolveFragment(MeshData d, inout SurfaceData o) { - _DissolveCutoff = remap(_DissolveCutoff, 0, 1, -0.1, 1); + _DissolveCutoff = remap(_DissolveCutoff, 0, 1, _DissolveCutoffRangeMin, _DissolveCutoffRangeMax); half gradSource = 0; uint totalChannels = 3; switch (_DissolveSource) { case 0: gradSource = d.localSpacePosition[(_DissolveDirection % totalChannels)] * (_DissolveDirection > 2 ? -1 : 1); break; case 1: gradSource = d.uv0[(_DissolveDirection % totalChannels)] * (_DissolveDirection > 2 ? -1 : 1); break; case 2: { - half2 uv = d.uv0 * _DissolveTexture_ST.xy + _DissolveTexture_ST.zw; + float2 uv = d.uv0 * _DissolveTexture_ST.xy + _DissolveTexture_ST.zw; gradSource = SAMPLE_TEXTURE2D(_DissolveTexture, sampler_DissolveTexture, uv)[(_DissolveDirection % totalChannels)] * (_DissolveDirection > 2 ? -1 : 1); break; } @@ -95,7 +100,7 @@ noise = saturate(remap(noise, 0,1, 1 - _DissolveBakedNoiseStrength,1)); grad = saturate(grad * noise); } - half2 overlayUv = d.uv0 * _DissolveOverlayTex_ST.xy + _DissolveOverlayTex_ST.zw; + float2 overlayUv = d.uv0 * _DissolveOverlayTex_ST.xy + _DissolveOverlayTex_ST.zw; half overlay = SAMPLE_TEXTURE2D(_DissolveOverlayTex, sampler_DissolveOverlayTex, overlayUv)[_DissolveOverlayChannel]; grad = saturate(grad * saturate(remap(overlay, 0, 1, 1 - _DissolveOverlayStrength, 1))); if (grad < _DissolveCutoff) { diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DitherFade.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DitherFade.orlsource index 0de65c30..7dbfd757 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DitherFade.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/DitherFade.orlsource @@ -1,7 +1,7 @@ %Properties() { UI_DFHeadeR("# Fade Settings", Int) = 1 - UI_DFDocs("[This module has documentation](https://shaders.orels.sh/docs/orl-standard/dither-fade)", Int) = 0 + UI_DFDocs("[This module has documentation](https://shaders.orels.sh/docs/configurable-shaders/modules/dither-fade)", Int) = 0 [Toggle(DITHER_FADE)]_EnableDitherFade("Enable", Int) = 0 _DitherTex("Dither Texture > %RequiredTexture(@/BayerDither4x4.png)", 2D) = "unity_DitherMask" {} _DFStart("Fade Start", Float) = 4 @@ -13,7 +13,7 @@ %ShaderTags() { - "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" + "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" "ORL_RenderType" = "Cutout" } %ShaderFeatures() @@ -46,11 +46,11 @@ void DitherFadeVertex(inout VertexData v, inout FragmentData o) { #if defined(DITHER_FADE) - o.extraV2F0 = ComputeScreenPos(UnityObjectToClipPos(v.vertex)); - // COMPUTE_EYEDEPTH macro - o.extraV2F0.z = -UnityObjectToViewPos(v.vertex).z; + o.extraV2F0 = GetScreenPosition(TransformObjectToHClip(v.vertex)); + o.extraV2F0.z = -TransformWorldToView(TransformObjectToWorld(v.vertex)).z; + // yeet the vertices completely if we're beyond the fade range - half dist = distance(mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz, _WorldSpaceCameraPos); + half dist = distance(TransformObjectToWorld(0..xxx), _WorldSpaceCameraPos); half factor = invLerp(_DFEnd, _DFStart, dist); factor = lerp(factor, 1 - _DFOverrideProgress, _DFOverrideFade); if (factor <= 0) { @@ -73,7 +73,7 @@ { #if defined(DITHER_FADE) half2 screenPos = d.extraV2F0 .xy / d.extraV2F0 .w * _ScreenParams.xy; - half dist = distance(mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz, _WorldSpaceCameraPos); + half dist = distance(TransformObjectToWorld(0..xxx), _WorldSpaceCameraPos); half factor = invLerp(_DFEnd, _DFStart, dist); factor = lerp(factor, 1 - _DFOverrideProgress, _DFOverrideFade); SampleDither(screenPos, saturate(factor)); diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LODCrossfade.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LODCrossfade.orlsource index 05f2d43a..019b8e31 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LODCrossfade.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LODCrossfade.orlsource @@ -1,6 +1,6 @@ %ShaderFeatures() { - #pragma multi_compile _ LOD_FADE_CROSSFADE + #pragma multi_compile_fragment _ LOD_FADE_CROSSFADE } %ShaderDefines() @@ -21,7 +21,7 @@ #if defined(LOD_FADE_CROSSFADE) float2 vpos = d.screenPos.xy / d.screenPos.w * _ScreenParams.xy; - UnityApplyDitherCrossFade(vpos); + LODFadeCrossFade(vpos); #endif } @@ -33,7 +33,7 @@ #if defined(LOD_FADE_CROSSFADE) float2 vpos = i.screenPos.xy / i.screenPos.w * _ScreenParams.xy; - UnityApplyDitherCrossFade(vpos); + LODFadeCrossFade(vpos); #endif } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LTCGI.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LTCGI.orlsource index 326a9ce2..bd21271b 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LTCGI.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LTCGI.orlsource @@ -1,6 +1,6 @@ %ShaderTags() { - "LTCGI" = "Always" + "LTCGI" = "_IntegrateLTCGI" } %Properties() @@ -9,38 +9,154 @@ UI_LTCGIDocs("[This module has documentation](https://shaders.orels.sh/docs/orl-standard/ltcgi)", Int) = 0 [Toggle(INTEGRATE_LTCGI)]_IntegrateLTCGI("Integrate LTCGI", Int) = 0 UI_LTCGIDownload("[Make sure to download LTCGI before enabling this option](https://github.com/PiMaker/ltcgi/releases)", Int) = 0 + [ToggleUI]_LTCGIEnableOnMobile("Enable on Mobile", Int) = 0 + UI_LTCGIEnableOnMobileNote("?> LTCGI is pretty heavy for mobile devices, please test your content when enabling this option", Int) = 0 + [ToggleUI]_LTCGIClampBrightness("Clamp Brightness", Int) = 0 + _LTCGIMaxBrightness("Max Brightness %ShowIf(_LTCGIClampBrightness)", Range(0,1)) = 1 + _LTCGIDiffuseIntensity("Diffuse Intensity", Float) = 1 + _LTCGISpecularIntensity("Specular Intensity", Float) = 1 + _LTCGIRoughnessModifier("Roughness Modifier", Range(-1,1)) = 0 + [TpggleUI]_LTCGIAlphaPremultiply("Alpha Premultiply %ShowIf(INTEGRATE_AREALIT)", Float) = 0 } %ShaderFeatures() { - #pragma shader_feature_local INTEGRATE_LTCGI + #pragma shader_feature_local_fragment INTEGRATE_LTCGI } %ShaderDefines() { - #if defined(INTEGRATE_LTCGI) && !defined(PLAT_QUEST) - #define _INTEGRATE_CUSTOMGI - #include "Packages/at.pimaker.ltcgi/Shaders/LTCGI.cginc" + #if defined(INTEGRATE_LTCGI) + #define _INTEGRATE_CUSTOMGI_FLEX #endif + + #define INCLUDE_LTCGI defined(INTEGRATE_LTCGI) + + #if INCLUDE_LTCGI + #include "Packages/at.pimaker.ltcgi/Shaders/LTCGI_structs.cginc" + #endif +} + +%DataStructs() +{ + struct LTCGIAccumulatorStruct { + float3 diffuse; + float3 specular; + }; + + #define LTCGI_V2_CUSTOM_INPUT LTCGIAccumulatorStruct +} + +%PassFunctions() +{ + #if INCLUDE_LTCGI + + void LTCGICallbackDiffuse(inout LTCGIAccumulatorStruct acc, in ltcgi_output output) + { + acc.diffuse += output.intensity * output.color; + } + + void LTCGICallbackSpecular(inout LTCGIAccumulatorStruct acc, in ltcgi_output output) + { + acc.specular += output.intensity * output.color; + } + + #define LTCGI_V2_DIFFUSE_CALLBACK LTCGICallbackDiffuse + #define LTCGI_V2_SPECULAR_CALLBACK LTCGICallbackSpecular + + #include "Packages/at.pimaker.ltcgi/Shaders/LTCGI.cginc" + #endif +} + +%Variables() +{ + int _LTCGIEnableOnMobile; + int _LTCGIClampBrightness; + half _LTCGIMaxBrightness; + half _LTCGIDiffuseIntensity; + half _LTCGISpecularIntensity; + half _LTCGIRoughnessModifier; + int _LTCGIAlphaPremultiply; } -%Fragment("LTCGIFragment") { - // this function MUST be named IntegrateCustomGI as its called from the Lighting code - void IntegrateCustomGI(MeshData d, SurfaceData o, inout half3 indirectSpecular, inout half3 indirectDiffuse) +%CustomGI("LTCGICustomGI") +{ + void LTCGICustomGI(MeshData d, SurfaceData o, inout half3 customGISpecular, inout half3 customGIDiffuse) { - #if defined(INTEGRATE_LTCGI) && !defined(PLAT_QUEST) - LTCGI_Contribution( - d.worldSpacePosition.xyz, - o.Normal.xyz, - d.worldSpaceViewDir, - 1 - o.Smoothness, - d.uv1.xy, - indirectDiffuse, - indirectSpecular - ); + #if !defined(ORL_LIGHTING_MODEL_VFX) + { + #if defined(PLAT_QUEST) + if (!_LTCGIEnableOnMobile) return; + #endif + + #if defined(INTEGRATE_LTCGI) + LTCGIAccumulatorStruct ltcgiData = (LTCGIAccumulatorStruct) 0; + + LTCGI_Contribution( + ltcgiData, + d.worldSpacePosition.xyz, + o.Normal.xyz, + d.worldSpaceViewDir, + saturate((1 - o.Smoothness) + _LTCGIRoughnessModifier), + d.uv1.xy + ); + + if (_LTCGIClampBrightness) { + half3 hsv = RGB2HSV(ltcgiData.specular); + hsv.z = tanh(hsv.z) * max(0, _LTCGIMaxBrightness); + customGISpecular += HSV2RGB(hsv) * _LTCGISpecularIntensity; + } else { + customGISpecular += ltcgiData.specular * _LTCGISpecularIntensity; + } + customGIDiffuse += ltcgiData.diffuse * _LTCGIDiffuseIntensity; + #endif + } #endif } +} + +%Color("LTCGIColor") +{ + void LTCGIColor(MeshData d, FragmentData i, inout half4 FinalColor, bool facing) + { + #if defined(ORL_LIGHTING_MODEL_VFX) + { + #if defined(PLAT_QUEST) + if (!_LTCGIEnableOnMobile) return; + #endif - void LTCGIFragment() { + #if defined(INTEGRATE_LTCGI) + LTCGIAccumulatorStruct ltcgiData = (LTCGIAccumulatorStruct) 0; + + float3 viewDir = d.worldSpaceViewDir; + if (!facing) + { + viewDir = -d.worldSpaceViewDir; + } + + LTCGI_Contribution( + ltcgiData, + d.worldSpacePosition.xyz, + d.worldNormal.xyz, + viewDir, + saturate(0.5 + _LTCGIRoughnessModifier), + d.uv1.xy + ); + + if (_LTCGIClampBrightness) { + half3 hsv = RGB2HSV(ltcgiData.specular); + hsv.z = tanh(hsv.z) * max(0, _LTCGIMaxBrightness); + FinalColor.rgb += HSV2RGB(hsv) * _LTCGISpecularIntensity; + } else { + FinalColor.rgb += ltcgiData.specular * _LTCGISpecularIntensity; + } + FinalColor.rgb += ltcgiData.diffuse * _LTCGIDiffuseIntensity; + if (_LTCGIAlphaPremultiply) + { + FinalColor.rgb *= FinalColor.a; + } + #endif + } + #endif } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LayeredMaterial.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LayeredMaterial.orlsource index 6c1fbec9..1b6ae4e6 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LayeredMaterial.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LayeredMaterial.orlsource @@ -94,7 +94,7 @@ %ShaderFeatures() { - #pragma shader_feature_local MASK_DEBUGGING + #pragma shader_feature_local_fragment MASK_DEBUGGING } %Variables() @@ -216,7 +216,7 @@ { half4 layerMask = _LMMaskingType == 0 ? d.vertexColor : SAMPLE_TEXTURE2D(_LMMaskTex, sampler_LMMaskTex, d.uv0.xy); - half2 uv = d.uv0.xy * _LMLayer1MainTex_ST.xy + _LMLayer1MainTex_ST.zw; + float2 uv = d.uv0.xy * _LMLayer1MainTex_ST.xy + _LMLayer1MainTex_ST.zw; half mask = _LMLayer1ColorMask == 0 ? all(layerMask.rgb < 0.00001) : _LMLayer1ColorMask == 4 ? all(layerMask.rgb > 0.99999) : layerMask[_LMLayer1ColorMask - 1]; @@ -224,33 +224,38 @@ half4 albedo = SAMPLE_TEXTURE2D(_LMLayer1MainTex, sampler_LMLayer1MainTex, uv); if (_LMLayer1AlbedoChannel > 0) { - albedo.rgb = albedo[_LMLayer1AlbedoChannel].xxx; + albedo.rgb = albedo[_LMLayer1AlbedoChannel].xxx; } + half4 masks = SAMPLE_TEXTURE2D(_LMLayer1MaskMap, sampler_LMLayer1MaskMap, uv); + half4 normalTex = SAMPLE_TEXTURE2D(_LMLayer1BumpMap, sampler_LMLayer1BumpMap, uv); if (_LMLayer1FlipBumpY) { - normalTex.y = 1 - normalTex.y; + normalTex.y = 1 - normalTex.y; } - half3 normal = UnpackScaleNormal(normalTex, _LMLayer1BumpScale); + half3 normal = UnpackNormalScale(normalTex, _LMLayer1BumpScale * mask); + int hasMasks = _LMLayer1MaskMap_TexelSize.z > 8; half metal = masks[_LMLayer1MetalChannel]; + half smooth = masks[_LMLayer1SmoothChannel]; if (_LMLayer1RoughnessMode) { - smooth = 1 - smooth; + smooth = 1 - smooth; } + half detailMask = masks[_LMLayer1DetailMaskChannel]; half occlusion = masks[_LMLayer1AOChannel]; metal = remap(metal, 0, 1, _LMLayer1MetallicRemap.x, _LMLayer1MetallicRemap.y); smooth = remap(smooth, 0, 1, _LMLayer1SmoothnessRemap.x, _LMLayer1SmoothnessRemap.y); - o.Metallic = lerp(_LMLayer1Metallic, metal, hasMasks); - o.Smoothness = lerp(_LMLayer1Smoothness, smooth, hasMasks); - o.Occlusion = lerp(1, occlusion, _LMLayer1OcclusionStrength); - o.Normal = normal; - o.Albedo = albedo.rgb * _LMLayer1Color.rgb; - o.Alpha = albedo.a * _LMLayer1Color.a; + o.Metallic = lerp(o.Metallic, lerp(_LMLayer1Metallic, metal, hasMasks), mask); + o.Smoothness = lerp(o.Smoothness, lerp(_LMLayer1Smoothness, smooth, hasMasks), mask); + o.Occlusion = lerp(o.Occlusion, lerp(1, occlusion, _LMLayer1OcclusionStrength), mask); + o.Normal = BlendNormals(o.Normal, normal); + o.Albedo = lerp(o.Albedo, albedo.rgb * _LMLayer1Color.rgb, mask); + o.Alpha = lerp(o.Alpha, albedo.a * _LMLayer1Color.a, mask); UNITY_BRANCH if (_LayeredMatLayersCount < 2) return; @@ -262,22 +267,27 @@ albedo = SAMPLE_TEXTURE2D(_LMLayer2MainTex, sampler_LMLayer1MainTex, uv); if (_LMLayer2AlbedoChannel > 0) { - albedo.rgb = albedo[_LMLayer2AlbedoChannel].xxx; + albedo.rgb = albedo[_LMLayer2AlbedoChannel].xxx; } + masks = SAMPLE_TEXTURE2D(_LMLayer2MaskMap, sampler_LMLayer1MaskMap, uv); + normalTex = SAMPLE_TEXTURE2D(_LMLayer2BumpMap, sampler_LMLayer1BumpMap, uv); if (_LMLayer2FlipBumpY) { - normalTex.y = 1 - normalTex.y; + normalTex.y = 1 - normalTex.y; } - normal = UnpackScaleNormal(normalTex, _LMLayer2BumpScale * mask); + normal = UnpackNormalScale(normalTex, _LMLayer2BumpScale * mask); + hasMasks = _LMLayer2MaskMap_TexelSize.z > 8; metal = masks[_LMLayer2MetalChannel]; + smooth = masks[_LMLayer2SmoothChannel]; if (_LMLayer2RoughnessMode) { - smooth = 1 - smooth; + smooth = 1 - smooth; } + detailMask = masks[_LMLayer2DetailMaskChannel]; occlusion = masks[_LMLayer2AOChannel]; metal = remap(metal, 0, 1, _LMLayer2MetallicRemap.x, _LMLayer2MetallicRemap.y); @@ -305,22 +315,27 @@ albedo = SAMPLE_TEXTURE2D(_LMLayer3MainTex, sampler_LMLayer1MainTex, uv); if (_LMLayer3AlbedoChannel > 0) { - albedo.rgb = albedo[_LMLayer3AlbedoChannel].xxx; + albedo.rgb = albedo[_LMLayer3AlbedoChannel].xxx; } + masks = SAMPLE_TEXTURE2D(_LMLayer3MaskMap, sampler_LMLayer1MaskMap, uv); + normalTex = SAMPLE_TEXTURE2D(_LMLayer3BumpMap, sampler_LMLayer1BumpMap, uv); if (_LMLayer3FlipBumpY) { - normalTex.y = 1 - normalTex.y; + normalTex.y = 1 - normalTex.y; } - normal = UnpackScaleNormal(normalTex, _LMLayer3BumpScale * mask); + normal = UnpackNormalScale(normalTex, _LMLayer3BumpScale * mask); + hasMasks = _LMLayer3MaskMap_TexelSize.z > 8; metal = masks[_LMLayer3MetalChannel]; + smooth = masks[_LMLayer3SmoothChannel]; if (_LMLayer3RoughnessMode) { - smooth = 1 - smooth; + smooth = 1 - smooth; } + detailMask = masks[_LMLayer3DetailMaskChannel]; occlusion = masks[_LMLayer3AOChannel]; metal = remap(metal, 0, 1, _LMLayer3MetallicRemap.x, _LMLayer3MetallicRemap.y); @@ -343,22 +358,27 @@ albedo = SAMPLE_TEXTURE2D(_LMLayer4MainTex, sampler_LMLayer1MainTex, uv); if (_LMLayer4AlbedoChannel > 0) { - albedo.rgb = albedo[_LMLayer4AlbedoChannel].xxx; + albedo.rgb = albedo[_LMLayer4AlbedoChannel].xxx; } + masks = SAMPLE_TEXTURE2D(_LMLayer4MaskMap, sampler_LMLayer1MaskMap, uv); + normalTex = SAMPLE_TEXTURE2D(_LMLayer4BumpMap, sampler_LMLayer1BumpMap, uv); if (_LMLayer4FlipBumpY) { - normalTex.y = 1 - normalTex.y; + normalTex.y = 1 - normalTex.y; } - normal = UnpackScaleNormal(normalTex, _LMLayer4BumpScale * mask); + normal = UnpackNormalScale(normalTex, _LMLayer4BumpScale * mask); + hasMasks = _LMLayer4MaskMap_TexelSize.z > 8; metal = masks[_LMLayer4MetalChannel]; + smooth = masks[_LMLayer4SmoothChannel]; if (_LMLayer4RoughnessMode) { - smooth = 1 - smooth; + smooth = 1 - smooth; } + detailMask = masks[_LMLayer4DetailMaskChannel]; occlusion = masks[_LMLayer4AOChannel]; metal = remap(metal, 0, 1, _LMLayer4MetallicRemap.x, _LMLayer4MetallicRemap.y); diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LayeredParallax.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LayeredParallax.orlsource index bf13fab3..5b6d1a6a 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LayeredParallax.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/LayeredParallax.orlsource @@ -138,16 +138,16 @@ void LayeredParallaxFragment(MeshData d, inout SurfaceData o) { // BACKGROUND - half2 bgUv = d.uv0.xy * _LPBackground_ST.xy + _LPBackground_ST.zw; + float2 bgUv = d.uv0.xy * _LPBackground_ST.xy + _LPBackground_ST.zw; half4 bg = SAMPLE_TEXTURE2D(_LPBackground, sampler_LPBackground, bgUv); o.Albedo = lerp(o.Albedo, bg.rgb, length(bg.rgb) > 0); // LAYER 1 { - half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer1UV - 2)), saturate(_LPLayer1UV - 1)), saturate(_LPLayer1UV)); + float2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer1UV - 2)), saturate(_LPLayer1UV - 1)), saturate(_LPLayer1UV)); _LPLayer1Direction = _LPLayer1Direction / 10.0; layerUv = layerUv * _LPLayer1_ST.xy + _LPLayer1_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer1Depth, d.tangentSpaceViewDir); + float2 offset = ParallaxOffset1Step(-1, _LPLayer1Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer1Mode) { @@ -174,7 +174,7 @@ UNITY_BRANCH if (_LPLayerCount < 2) { - half2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; + float2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; half4 ov = SAMPLE_TEXTURE2D(_LPOverlay, sampler_LPBackground, ovUv); o.Albedo = lerp(o.Albedo, ov.rgb, ov.a); return; @@ -182,10 +182,10 @@ // LAYER 2 { - half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer2UV - 2)), saturate(_LPLayer2UV - 1)), saturate(_LPLayer2UV)); + float2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer2UV - 2)), saturate(_LPLayer2UV - 1)), saturate(_LPLayer2UV)); _LPLayer2Direction = _LPLayer2Direction / 10.0; layerUv = layerUv * _LPLayer2_ST.xy + _LPLayer2_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer2Depth, d.tangentSpaceViewDir); + float2 offset = ParallaxOffset1Step(-1, _LPLayer2Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer2Mode) { @@ -212,7 +212,7 @@ UNITY_BRANCH if (_LPLayerCount < 3) { - half2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; + float2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; half4 ov = SAMPLE_TEXTURE2D(_LPOverlay, sampler_LPBackground, ovUv); o.Albedo = lerp(o.Albedo, ov.rgb, ov.a); return; @@ -220,10 +220,10 @@ // LAYER 3 { - half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer3UV - 2)), saturate(_LPLayer3UV - 1)), saturate(_LPLayer3UV)); + float2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer3UV - 2)), saturate(_LPLayer3UV - 1)), saturate(_LPLayer3UV)); _LPLayer3Direction = _LPLayer3Direction / 10.0; layerUv = layerUv * _LPLayer3_ST.xy + _LPLayer3_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer3Depth, d.tangentSpaceViewDir); + float2 offset = ParallaxOffset1Step(-1, _LPLayer3Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer3Mode) { @@ -250,7 +250,7 @@ UNITY_BRANCH if (_LPLayerCount < 4) { - half2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; + float2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; half4 ov = SAMPLE_TEXTURE2D(_LPOverlay, sampler_LPBackground, ovUv); o.Albedo = lerp(o.Albedo, ov.rgb, ov.a); return; @@ -258,10 +258,10 @@ // LAYER 4 { - half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer4UV - 2)), saturate(_LPLayer4UV - 1)), saturate(_LPLayer4UV)); + float2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer4UV - 2)), saturate(_LPLayer4UV - 1)), saturate(_LPLayer4UV)); _LPLayer4Direction = _LPLayer4Direction / 10.0; layerUv = layerUv * _LPLayer4_ST.xy + _LPLayer4_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer4Depth, d.tangentSpaceViewDir); + float2 offset = ParallaxOffset1Step(-1, _LPLayer4Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer4Mode) { @@ -288,7 +288,7 @@ UNITY_BRANCH if (_LPLayerCount < 4) { - half2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; + float2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; half4 ov = SAMPLE_TEXTURE2D(_LPOverlay, sampler_LPBackground, ovUv); o.Albedo = lerp(o.Albedo, ov.rgb, ov.a); return; @@ -296,10 +296,10 @@ // LAYER 5 { - half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer5UV - 2)), saturate(_LPLayer5UV - 1)), saturate(_LPLayer5UV)); + float2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer5UV - 2)), saturate(_LPLayer5UV - 1)), saturate(_LPLayer5UV)); _LPLayer5Direction = _LPLayer5Direction / 10.0; layerUv = layerUv * _LPLayer5_ST.xy + _LPLayer5_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer5Depth, d.tangentSpaceViewDir); + float2 offset = ParallaxOffset1Step(-1, _LPLayer5Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer5Mode) { @@ -323,7 +323,7 @@ o.Albedo = lerp(o.Albedo, layerColor.rgb * _LPLayer5Color, factor); } - half2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; + float2 ovUv = d.uv0.xy * _LPOverlay_ST.xy + _LPOverlay_ST.zw; half4 ov = SAMPLE_TEXTURE2D(_LPOverlay, sampler_LPBackground, ovUv); o.Albedo = lerp(o.Albedo, ov.rgb, ov.a); } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/MaskedTweaks.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/MaskedTweaks.orlsource new file mode 100644 index 00000000..c07d550f --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/MaskedTweaks.orlsource @@ -0,0 +1,61 @@ +%Properties() +{ + UI_MaskedTweaksHeader("# Masked Tweaks", Int) = 1 + [Toggle(MASKED_TWEAKS)]_MaskedTweaksEnabled("Enable Masked Tweaks", Int) = 0 + _MaskedTweaksMap("Masked Tweaks Map %ShowIf(_MaskedTweaksColor && MASKED_TWEAKS)", 2D) = "black" {} + [ToggleUI]_MaskedTweaksColor("Tweak Colors %ShowIf(MASKED_TWEAKS)", Int) = 0 + [HDR]_MaskedTweaksRed("Red Mask Color %ShowIf(_MaskedTweaksColor && MASKED_TWEAKS)", Color) = (0.932,0.231,0.278,1) + [HDR]_MaskedTweaksGreen("Green Mask Color %ShowIf(_MaskedTweaksColor && MASKED_TWEAKS)", Color) = (0.0574,0.214,0.0318,1) + [HDR]_MaskedTweaksBlue("Blue Mask Color %ShowIf(_MaskedTweaksColor && MASKED_TWEAKS)", Color) = (0.0239,0.0815,0.401,1) + [ToggleUI]_MaskedTweaksSmoothness("Tweak Smoothness %ShowIf(MASKED_TWEAKS)", Int) = 0 + _MaskedTweaksRedSmoothness("Red Mask Smoothness %ShowIf(_MaskedTweaksSmoothness && MASKED_TWEAKS)", Range(0,1)) = 0.5 + _MaskedTweaksGreenSmoothness("Green Mask Smoothness %ShowIf(_MaskedTweaksSmoothness && MASKED_TWEAKS)", Range(0,1)) = 0.5 + _MaskedTweaksBlueSmoothness("Blue Mask Smoothness %ShowIf(_MaskedTweaksSmoothness && MASKED_TWEAKS)", Range(0,1)) = 0.5 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment MASKED_TWEAKS +} + +%Variables() +{ + half4 _MaskedTweaksMap_ST; + + int _MaskedTweaksColor; + half4 _MaskedTweaksRed; + half4 _MaskedTweaksGreen; + half4 _MaskedTweaksBlue; + + int _MaskedTweaksSmoothness; + half _MaskedTweaksRedSmoothness; + half _MaskedTweaksGreenSmoothness; + half _MaskedTweaksBlueSmoothness; +} + +%Textures() +{ + TEXTURE2D(_MaskedTweaksMap); + SAMPLER(sampler_MaskedTweaksMap); +} + +%Fragment("MaskedTweaksFragment") +{ + void MaskedTweaksFragment(MeshData d, inout SurfaceData o) + { + #if defined(MASKED_TWEAKS) + half4 mask = SAMPLE_TEXTURE2D(_MaskedTweaksMap, sampler_MaskedTweaksMap, d.uv0.xy * _MaskedTweaksMap_ST.xy + _MaskedTweaksMap_ST.zw); + if (_MaskedTweaksColor) { + o.Albedo = lerp(o.Albedo, _MaskedTweaksRed, mask.r); + o.Albedo = lerp(o.Albedo, _MaskedTweaksGreen, mask.g); + o.Albedo = lerp(o.Albedo, _MaskedTweaksBlue, mask.b); + } + + if (_MaskedTweaksSmoothness) { + o.Smoothness = lerp(o.Smoothness, _MaskedTweaksRedSmoothness, mask.r); + o.Smoothness = lerp(o.Smoothness, _MaskedTweaksGreenSmoothness, mask.g); + o.Smoothness = lerp(o.Smoothness, _MaskedTweaksBlueSmoothness, mask.b); + } + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/MaskedTweaks.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/MaskedTweaks.orlsource.meta new file mode 100644 index 00000000..2195cd85 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/MaskedTweaks.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b4e67c9b425cea94aa077a318b693b17 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Parallax.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Parallax.orlsource index 02d45c59..9f3cff1c 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Parallax.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Parallax.orlsource @@ -6,23 +6,24 @@ [NoScaleOffset]_Height("Height > %ShowIf(PARALLAX)", 2D) = "black" {} _HeightScale("Height Scale %ShowIf(PARALLAX)", Range(0, 0.1)) = 0.006 _HeightRefPlane("Height Ref Plane %ShowIf(PARALLAX)", Range(-1, 1)) = 0.5 - _HeightStepsMin("Steps Min %ShowIf(PARALLAX)", Range(8, 32)) = 8 - _HeightStepsMax("Steps Max %ShowIf(PARALLAX)", Range(8, 32)) = 16 + [KeywordEnum(Eight, Sixteen,ThirtyTwo, SixtyFour)]_ParallaxSteps("Steps %ShowIf(PARALLAX)", Int) = 0 + [ToggleUI]_ParallaxScaleBasedOnAngle("Scaled Based On Angle %ShowIf(PARALLAX)", Int) = 0 + UI_ParallaxScaleBasedOnAngleNote("> This will scale the parallax effect based on the angle between the camera forward ray and the surface normal %ShowIf(PARALLAX)", Int) = 0 } %ShaderFeatures() { - #pragma shader_feature_local PARALLAX + #pragma shader_feature_local_fragment PARALLAX + #pragma shader_feature_local_fragment _PARALLAXSTEPS_EIGHT _PARALLAXSTEPS_SIXTEEN _PARALLAXSTEPS_THIRTYTWO _PARALLAXSTEPS_SIXTYFOUR } %Variables() { half _HeightScale; half _HeightRefPlane; - half _HeightStepsMin; - half _HeightStepsMax; + int _ParallaxScaleBasedOnAngle; - half2 GLOBAL_parallaxUv; + float2 GLOBAL_parallaxUv; half GLOBAL_heightMask; half GLOBAL_heightMaskSmoothing; @@ -39,110 +40,79 @@ %Fragment("ParallaxFragment", -100) { - // mostly taken from the Amplify shader reference - half2 POM(Texture2D heightMap, SamplerState heightSampler, half2 uvs, half2 dx, half2 dy, half3 normalWorld, half3 viewWorld, half3 viewDirTan, int minSamples, int maxSamples, half parallax, half refPlane, half2 tilling, half2 curv, int index, half heightMask, half heightMaskSmoothing, inout half finalHeight) + #if defined(_PARALLAXSTEPS_EIGHT) + #define PARALLAX_STEPS 8 + #elif defined(_PARALLAXSTEPS_SIXTEEN) + #define PARALLAX_STEPS 16 + #elif defined(_PARALLAXSTEPS_THIRTYTWO) + #define PARALLAX_STEPS 32 + #elif defined(_PARALLAXSTEPS_SIXTYFOUR) + #define PARALLAX_STEPS 64 + #else + #define PARALLAX_STEPS 1 + #endif + + float2 POM_simple(TEXTURE2D_PARAM(heightMap, heightSampler), float currentHeight, float scale, float2 uv, float3 tangetSpaceViewDir, float refPlane, out float heightOffset) { - half3 result = 0; - int stepIndex = 0; - int numSteps = (int)lerp((half)maxSamples, (half)minSamples, saturate(dot(normalWorld, viewWorld))); - half layerHeight = 1.0 / numSteps; - half2 plane = parallax * (viewDirTan.xy / viewDirTan.z); - uvs.xy += refPlane * plane; - half2 deltaTex = -plane * layerHeight; - half2 prevTexOffset = 0; - half prevRayZ = 1.0f; - half prevHeight = 0.0f; - half2 currTexOffset = deltaTex; - half currRayZ = 1.0f - layerHeight; - half currHeight = 0.0f; - half intersection = 0; - half2 finalTexOffset = 0; - while (stepIndex < numSteps + 1) + heightOffset = 0; + float2 uvOffset = 0; + float stepSize = 1.0 / PARALLAX_STEPS; + float stepHeight = 1; + tangetSpaceViewDir.xy /= (tangetSpaceViewDir.z + 0.42); + float2 uvDelta = tangetSpaceViewDir.xy * (stepSize * scale); + + float2 derivatives = float2(ddx(uv.x), ddy(uv.y)); + + [unroll(PARALLAX_STEPS)] + for (int i = 1; i <= PARALLAX_STEPS && stepHeight > currentHeight; i++) { - currHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + currTexOffset, dx, dy).r; - #if defined(POM_HEIGHT_MASK_SET) - half mask = smoothstep(currHeight - heightMaskSmoothing, currHeight, heightMask); - currHeight = lerp(currHeight, heightMask, mask); - #endif - if (currHeight > currRayZ) - { - stepIndex = numSteps + 1; - } - else - { - stepIndex++; - prevTexOffset = currTexOffset; - prevRayZ = currRayZ; - prevHeight = currHeight; - currTexOffset += deltaTex; - currRayZ -= layerHeight; - } + uvOffset -= uvDelta; + stepHeight -= stepSize; + currentHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uv + uvOffset, derivatives.x, derivatives.y).r + refPlane; } - int sectionSteps = 2; - int sectionIndex = 0; - half newZ = 0; - half newHeight = 0; - while (sectionIndex < sectionSteps) + + [unroll(3)] + for (int k = 0; k < 3; k++) { - intersection = (prevHeight - prevRayZ) / (prevHeight - currHeight + currRayZ - prevRayZ); - finalTexOffset = prevTexOffset +intersection * deltaTex; - newZ = prevRayZ - intersection * layerHeight; - newHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + finalTexOffset, dx, dy).r; - #if defined(POM_HEIGHT_MASK_SET) - half mask = smoothstep(newHeight - heightMaskSmoothing, newHeight, heightMask); - newHeight = lerp(newHeight, heightMask, mask); - #endif - if (newHeight > newZ) - { - currTexOffset = finalTexOffset; - currHeight = newHeight; - currRayZ = newZ; - deltaTex = intersection * deltaTex; - layerHeight = intersection * layerHeight; - } - else + uvDelta *= 0.5; + stepSize *= 0.5; + + if (stepHeight < currentHeight) { - prevTexOffset = finalTexOffset; - prevHeight = newHeight; - prevRayZ = newZ; - deltaTex = (1 - intersection) * deltaTex; - layerHeight = (1 - intersection) * layerHeight; + uvOffset += uvDelta; + stepHeight += stepSize; + } else { + uvOffset -= uvDelta; + stepHeight -= stepSize; } - sectionIndex++; + currentHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uv + uvOffset, derivatives.x, derivatives.y).r + refPlane; } - finalHeight = newHeight; - return uvs.xy + finalTexOffset; + + heightOffset = currentHeight; + return uvOffset; } - void ParallaxFragment(MeshData d) + void ParallaxFragment(MeshData d, FragmentData i) { - // this is a bit "magical" but basically we just push to global UVs - // and then any other module will read from them - // we use FragmentQueue to push the actual function call above the other modules - GLOBAL_parallaxUv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - #if defined(PARALLAX) && !defined(PLAT_QUEST) - half customHeight = 0; - GLOBAL_parallaxUv = POM(_Height, - sampler_Height, - GLOBAL_parallaxUv, - ddx(GLOBAL_parallaxUv), - ddy(GLOBAL_parallaxUv), - d.worldNormal, - d.worldSpaceViewDir, - d.tangentSpaceViewDir, - _HeightStepsMin, - _HeightStepsMax, - _HeightScale, - _HeightRefPlane, - half2(1, 1), - half2(0, 0), - 0, - GLOBAL_heightMask, - GLOBAL_heightMaskSmoothing, - customHeight - ); - GLOBAL_height = customHeight; - GLOBAL_heightSet = 1; - #endif + // this is a bit "magical" but basically we just push to global UVs + // and then any other module will read from them + // we use FragmentQueue to push the actual function call above the other modules + GLOBAL_parallaxUv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; + #if defined(PARALLAX) && !defined(PLAT_QUEST) + { + float customHeight = 0; + if (_ParallaxScaleBasedOnAngle) + { + float3 forwardRay = TransformViewToWorldDir(float3(0,0,1)); + _HeightScale *= pow(saturate(dot(d.worldNormal, forwardRay)), 1.0/1.5); + } + half startingPoint = SAMPLE_TEXTURE2D(_Height, sampler_Height, GLOBAL_parallaxUv).r; + float2 uvOffset = POM_simple(TEXTURE2D_ARGS(_Height, sampler_Height), startingPoint, _HeightScale, GLOBAL_parallaxUv, d.tangentSpaceViewDir, _HeightRefPlane, customHeight); + GLOBAL_parallaxUv += uvOffset; + + GLOBAL_height = customHeight; + GLOBAL_heightSet = 1; + } + #endif } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Puddles.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Puddles.orlsource index 1b2f8a05..28ae163a 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Puddles.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Puddles.orlsource @@ -29,7 +29,7 @@ %ShaderFeatures() { - #pragma shader_feature_local RAINDROPS_ENABLE + #pragma shader_feature_local_fragment RAINDROPS_ENABLE } %Variables() @@ -123,8 +123,8 @@ half puddlesMask = 1; if (_PuddlesMaskMappingSpace == 3) { - half2 uvX, uvY, uvZ; - half weightX, weightY, weightZ; + float2 uvX, uvY, uvZ; + float weightX, weightY, weightZ; GetTriplanarUV(d.worldSpacePosition.xyz * _PuddlesMask_ST.x, uvX, uvY, uvZ); GetTriplanarWeights(d.worldNormal, weightX, weightY, weightZ); puddlesMask = SAMPLE_TEXTURE2D(_PuddlesMask, sampler_PuddlesMask, uvX).r * weightX; @@ -144,12 +144,12 @@ o.Smoothness = lerp(o.Smoothness, 1, mask); o.Metallic = lerp(o.Metallic, 0, mask); - o.Normal = normalize(lerp(o.Normal, UnpackScaleNormal(half4(0.5, 0.5, 0.5, 1.0), 0), mask)); + o.Normal = Unity_SafeNormalize(lerp(o.Normal, float4(0, 0, 1, 0), mask)); o.Albedo = lerp(o.Albedo, o.Albedo * _PuddlesColor.rgb, mask * _PuddlesColor.a); #if defined(RAINDROPS_ENABLE) - half2 uv = 0; + float2 uv = 0; switch (_RaindropsMappingSpace) { case 0: // World Space @@ -196,20 +196,14 @@ sweepMask = sin(sweepMask); sweepMask *= (1 - time) * packed.r; - // half blendLoop = sin((_Time.y * UNITY_PI + UNITY_PI/2.0)) * 0.5 + 0.5; - // blendLoop = smoothstep(0, 1, blendLoop); - half4 packedNormal = half4(packed.gb, 0.5, 1); - float3 unpackedNormal = UnpackScaleNormal(packedNormal, _RaindropsNormalStrength * sweepMask * raindropsFilter * mask); - // o.Normal = unpackedNormal; - // o.Emission = blendLoop; - // return; + float3 unpackedNormal = UnpackNormalScale(packedNormal, _RaindropsNormalStrength * sweepMask * raindropsFilter * mask); uv += half2(0.23, 1.45); //* floor(_Time.y - 0.5); half angle = _RaindropsLayer2Rotation * 360.0; half sinAngle = sin(angle); half cosAngle = cos(angle); - half2x2 rotMat = {cosAngle, sinAngle, -sinAngle, cosAngle}; + float2x2 rotMat = {cosAngle, sinAngle, -sinAngle, cosAngle}; uv = mul(uv, rotMat); packed = SAMPLE_TEXTURE2D(_RaindropsMap, sampler_RaindropsMap, uv); @@ -223,7 +217,7 @@ sweepMask *= (1 - time) * packed.r; packedNormal = half4(packed.gb, 0.5, 1); - float3 unpackedNormal2 = UnpackScaleNormal(packedNormal, _RaindropsNormalStrength * sweepMask * raindropsFilter * mask); + float3 unpackedNormal2 = UnpackNormalScale(packedNormal, _RaindropsNormalStrength * sweepMask * raindropsFilter * mask); o.Normal = BlendNormals(o.Normal, BlendNormals(unpackedNormal, unpackedNormal2)); diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Pulse.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Pulse.orlsource index 5cc8fab4..6696cc74 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Pulse.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Pulse.orlsource @@ -16,7 +16,7 @@ %ShaderFeatures() { - #pragma shader_feature_local PULSE_SHOW_GRAD + #pragma shader_feature_local_fragment PULSE_SHOW_GRAD } %Variables() @@ -58,7 +58,7 @@ case 0: gradSource = d.localSpacePosition[(_PulseGradientDirection % totalChannels)] * (_PulseGradientDirection > 2 ? -1 : 1); break; case 1: gradSource = d.uv0[(_PulseGradientDirection % totalChannels)] * (_PulseGradientDirection > 2 ? -1 : 1); break; case 2: { - half2 uv = d.uv0 * _PulseTexture_ST.xy + _PulseTexture_ST.zw; + float2 uv = d.uv0 * _PulseTexture_ST.xy + _PulseTexture_ST.zw; gradSource = SAMPLE_TEXTURE2D(_PulseTexture, sampler_PulseTexture, uv)[(_PulseGradientDirection % totalChannels)] * (_PulseGradientDirection > 2 ? -1 : 1); break; } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/SSR.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/SSR.orlsource new file mode 100644 index 00000000..4aea659b --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/SSR.orlsource @@ -0,0 +1,203 @@ +%Properties() +{ + UI_SSRHeader("# Screen Space Reflections", Int) = 0 + UI_SSRDocs("[This module has documentation](https://shaders.orels.sh/docs/configurable-shaders/modules/ssr)", Int) = 0 + [Toggle(SSR)]_SSREnabled("Enable SSR %ForceRenderType(Custom,2501,Transparent,Fade) %EnablePass(GrabPass)", Int) = 0 + _SSRStrength("Strength %ShowIf(SSR)", Range(0,1)) = 1 + [IntRange]_SSRMaxSteps("Maximum Steps %ShowIf(SSR)", Range(1,50)) = 50 + _SSRStep("Step Size %ShowIf(SSR)", Float) = 0.09 + _SSREdgeFade("Edge Fade %ShowIf(SSR)", Range(0,1)) = 0.1 + _SSRBakedReflectionStrength("Baked Reflection Strength %ShowIf(SSR)", Range(0, 1)) = 1 + UI_SSRInternalsHeader("## Internals", Int) = 0 + _SSRLRad("Intersection (L) %ShowIf(SSR)", Float) = 0.02 + _SSRSRad("Intersection (R) %ShowIf(SSR)", Float) = 0.02 + _SSRNoiseTexture("Noise Texture > %RequiredTexture(@/SSRNoise.png) %ShowIf(SSR)", 2D) = "black" {} +} + +%Variables() +{ + float _VRChatMirrorMode; + float4 _ORLGrabTexture_TexelSize; + float4 _SSRNoiseTexture_TexelSize; + half _SSRStrength; + int _SSRMaxSteps; + float _SSRStep; + float _SSRLRad; + float _SSRSRad; + half _SSREdgeFade; + half _SSRBakedReflectionStrength; +} + +%Textures() +{ + TEXTURE2D_X(_ORLGrabTexture); + SAMPLER(sampler_ORLGrabTexture); + TEXTURE2D(_SSRNoiseTexture); + SAMPLER(sampler_SSRNoiseTexture); +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment SSR +} + +%PrePasses() +{ + GrabPass { + Tags { "LightMode" = "GrabPass"} + "_ORLGrabTexture" + } +} + +%ShaderDefines() +{ + #if defined(SSR) + #define _INTEGRATE_CUSTOMGI_FLEX + #define NEED_SCREEN_POS + #endif +} + + +// These rely on specific textures, so they are defined in the pass functions instead of library +%PassFunctions() +{ + // Based on Mochie's SSR implementation (Based on ERROR.mdl's implementation) + // https://github.com/MochiesCode/Mochies-Unity-Shaders/ + // Licensed under MIT + float3 GetBlurredGP(float2 texelSize, float2 uvs, float dim){ + float2 pixSize = 2/texelSize; + float center = floor(dim*0.5); + float3 refTotal = float3(0,0,0); + for (int i = 0; i < floor(dim); i++){ + for (int j = 0; j < floor(dim); j++){ + float4 refl = SAMPLE_TEXTURE2D_X(_ORLGrabTexture, sampler_ORLGrabTexture, float2(uvs.x + pixSize.x*(i-center), uvs.y + pixSize.y*(j-center))); + refTotal += refl.rgb; + } + } + return refTotal/(floor(dim)*floor(dim)); + } + + float4 ReflectRay(float3 reflectedRay, float3 rayDir, float lRad, float sRad, float step, float noise, const int maxIterations){ + + #if UNITY_SINGLE_PASS_STEREO + half x_min = 0.5 * unity_StereoEyeIndex; + half x_max = 0.5 + 0.5 * unity_StereoEyeIndex; + #else // SPSI and MultiView work on the full screen + half x_min = 0.0; + half x_max = 1.0; + #endif + + reflectedRay = TransformWorldToView(reflectedRay); + rayDir = TransformWorldToViewDir(rayDir); + int totalIterations = 0; + int direction = 1; + float3 finalPos = 0; + + [loop] + for (int i = 0; i < maxIterations; i++){ + totalIterations = i; + float4 spos = GetScreenPosition(TransformWViewToHClip(reflectedRay)); + float2 uvDepth = spos.xy / spos.w; + UNITY_BRANCH + if (uvDepth.x > x_max || uvDepth.x < x_min || uvDepth.y > 1 || uvDepth.y < 0){ + break; + } + + float rawDepth = SampleSceneDepthRGDecoded(uvDepth); + float linearDepth = Linear01Depth(rawDepth); + float sampleDepth = -reflectedRay.z; + float realDepth = linearDepth * _ProjectionParams.z; + float depthDifference = abs(sampleDepth - realDepth); + + if (depthDifference < lRad){ + if (direction == 1){ + if(sampleDepth > (realDepth - sRad)){ + if(sampleDepth < (realDepth + sRad)){ + finalPos = reflectedRay; + break; + } + direction = -1; + step = step*0.1; + } + } + else { + if(sampleDepth < (realDepth + sRad)){ + direction = 1; + step = step*0.1; + } + } + } + reflectedRay = reflectedRay + direction*step*rayDir; + step += step*(0.025 + 0.005*noise); + lRad += lRad*(0.025 + 0.005*noise); + sRad += sRad*(0.025 + 0.005*noise); + } + return float4(finalPos, totalIterations); + } + + half4 GetSSRColor(float3 worldPos, float3 viewDir, float3 reflDir, float3 worldNormal, float smoothness, half3 albedo, float metallic, float mask, float4 screenPos) { + float NoR = dot(worldNormal, reflDir); + + bool isInVRMirror = _VRChatMirrorMode == 1; + bool isInDesktopMirror = _VRChatMirrorMode == 2; + + [branch] + if ((isInVRMirror || isInDesktopMirror) || NoR < 0 || mask < 0.001) { + return 0; + } + else { + + float4 noiseUvs = screenPos; + noiseUvs.xy = (noiseUvs.xy * _ORLGrabTexture_TexelSize.zw) / (_SSRNoiseTexture_TexelSize.zw * noiseUvs.w); + float4 noiseRGBA = SAMPLE_TEXTURE2D_LOD(_SSRNoiseTexture, sampler_SSRNoiseTexture, noiseUvs.xy,0); + float noise = noiseRGBA.r; + + float3 reflectedRay = worldPos.xyz + (_SSRLRad*_SSRStep/NoR + noise*_SSRStep)*reflDir; + + float scatterMult = 0.2; + float4 scatter = float4(0.5 - noiseRGBA.rgb,0); + reflDir = normalize(reflDir + scatterMult*scatter*(1-smoothness)*sqrt(NoR)); + + float4 finalPos = ReflectRay(reflectedRay, reflDir, _SSRLRad, _SSRSRad, _SSRStep, noise, _SSRMaxSteps); + float totalSteps = finalPos.w; + finalPos.w = 1; + + if (!any(finalPos.xyz)) + return 0; + + float4 uvs = GetScreenPosition(TransformWViewToHClip(finalPos)); + uvs.xy = uvs.xy / uvs.w; + + #if UNITY_SINGLE_PASS_STEREO || defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED) + float xfade = 1; + #else + float xfade = smoothstep(0, _SSREdgeFade, uvs.x)*smoothstep(1, 1-_SSREdgeFade, uvs.x); //Fade x uvs out towards the edges + #endif + float yfade = smoothstep(0, _SSREdgeFade, uvs.y)*smoothstep(1, 1-_SSREdgeFade, uvs.y); //Same for y + float lengthFade = smoothstep(1, 0, 2*(totalSteps / _SSRMaxSteps)-1); + + float fade = xfade * yfade * lengthFade; + + float blurFac = max(1,min(12, 12 * (-2)*(smoothness-1))); + float4 reflection = float4(GetBlurredGP(_ORLGrabTexture_TexelSize.zw, uvs.xy, blurFac),1); + + reflection.rgb = lerp(reflection.rgb, reflection.rgb*albedo.rgb, metallic); + + float RdotV = dot(reflDir, viewDir); + reflection.a = NoR*fade*smoothness * _SSRStrength; + return max(0,reflection); + } + } +} + +%CustomGI("SSRCustomGI") +{ + void SSRCustomGI(MeshData d, SurfaceData o, float3 reflDir, inout half3 indirectSpecular) + { + #if defined(SSR) + half4 ssrResult = GetSSRColor(d.worldSpacePosition, d.worldSpaceViewDir, reflDir, o.Normal, o.Smoothness, o.Albedo, o.Metallic, 1, d.screenPos); + indirectSpecular *= max(_SSRBakedReflectionStrength, 0.0001); + indirectSpecular = lerp(indirectSpecular, ssrResult.rgb, ssrResult.a); + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/SSR.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/SSR.orlsource.meta new file mode 100644 index 00000000..ab15c0c7 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/SSR.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: e3b6bef413be5064da62de5cbd4ba37c +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Tessellation.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Tessellation.orlsource new file mode 100644 index 00000000..229b7204 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Tessellation.orlsource @@ -0,0 +1,195 @@ +%Includes() +{ + "@/Structs/TessVertexData", + "@/Structs/TessFactors", + "self" +} + +%Properties() +{ + UI_TessellationHeader("# Tessellation", Int) = 0 + [Toggle(TESS_PHONG)]_TessPhong("Enable Phong Tessellation", Int) = 0 + [KeywordEnum(Static, DistanceBased, EdgeLength)]TESS_MODE("Tessellation Mode", Int) = 0 + [IntRange]_TessFactor("Tessellation Factor %ShowIf(TESS_MODE_STATIC || TESS_MODE_DISTANCEBASED)", Range(1, 16)) = 3 + _TessMinDist("Start Distance %ShowIf(TESS_MODE_DISTANCEBASED)", Float) = 3 + _TessMaxDist("End Distance %ShowIf(TESS_MODE_DISTANCEBASED)", Float) = 20 + _TessEdgeLength("Max Edge Length %ShowIf(TESS_MODE_EDGELENGTH)", Float) = 80 + _TessMaxDisplacement("Max Displacement %ShowIf(TESS_MODE_EDGELENGTH)", Float) = 0.1 + UI_TessMaxDisplacementNote("> This defines how much you will be displacing the mesh to help with optimisations %ShowIf(TESS_MODE_EDGELENGTH)", Int) = 0 +} + +%ShaderTags() +{ + "DisableBatching" = "True" +} + +%ShaderFeatures() +{ + // Tessellation "features" + #pragma hull Hull + #pragma domain Domain + #pragma require tessellation tessHW + #pragma shader_feature_local_domain TESS_PHONG + #pragma shader_feature_local_hull TESS_MODE_STATIC TESS_MODE_DISTANCEBASED TESS_MODE_EDGELENGTH +} + +%ShaderDefines() +{ + #define TESS_ENABLED + #define TESS_FACTORS_FUNC_DEFINED + + #include "Tessellation.cginc" +} + +%Variables() +{ + int _TessFactor; + half _TessMinDist; + half _TessMaxDist; + half _TessEdgeLength; + half _TessMaxDisplacement; +} + +%FreeFunctions() +{ + // Tess Vertex + TessVertexData Vertex(VertexData v) + { + UNITY_SETUP_INSTANCE_ID(v); + TessVertexData o = (TessVertexData) 0; + UNITY_TRANSFER_INSTANCE_ID(v, o); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + o.vertex = v.vertex; + o.normal = v.normal; + o.tangent = v.tangent; + o.color = v.color; + o.uv0 = v.uv0; + o.uv1 = v.uv1; + o.uv2 = v.uv2; + o.uv3 = v.uv3; + + return o; + } + + // Tess Hull + [maxtessfactor(16.0)] + [UNITY_domain("tri")] + [UNITY_outputcontrolpoints(3)] + [UNITY_outputtopology("triangle_cw")] + [UNITY_partitioning("integer")] + [UNITY_patchconstantfunc("TessFactorsFunction")] + TessVertexData Hull(InputPatch patch, uint id : SV_OutputControlPointID) + { + return patch[id]; + } + + float4 GetTessFactors(InputPatch patch) + { + #if defined(TESS_MODE_DISTANCEBASED) + { + float4 tessFactors = UnityDistanceBasedTess( + patch[0].vertex, + patch[1].vertex, + patch[2].vertex, + _TessMinDist, + _TessMaxDist, + _TessFactor + ); + return tessFactors; + } + #elif defined(TESS_MODE_EDGELENGTH) + { + float4 tessFactors = UnityEdgeLengthBasedTessCull( + patch[0].vertex, + patch[1].vertex, + patch[2].vertex, + _TessEdgeLength, + _TessMaxDisplacement + ); + return tessFactors; + } + #elif defined(CUSTOM_TESS_FACTORS_FUNC) + { + float4 tessFactors = CustomTessFactorsFunc(patch); + return tessFactors; + } + #elif defined(TESS_MODE_STATIC) + { + return _TessFactor.xxxx; + } + #endif + } + + // TessFactor + TessFactors TessFactorsFunction(InputPatch patch) + { + TessFactors f; + float4 TessFactorsOutput = 0; + #if defined(TESS_FACTORS_FUNC_DEFINED) + TessFactorsOutput = GetTessFactors(patch); + #else + TessFactorsOutput = _TessFactor.xxxx; + #endif + f.edge[0] = TessFactorsOutput.x; + f.edge[1] = TessFactorsOutput.y; + f.edge[2] = TessFactorsOutput.z; + f.inside = TessFactorsOutput.w; + return f; + } + + // Tess Domain + [UNITY_domain("tri")] + FragmentData Domain(TessFactors factors, OutputPatch patch, float3 baryCoords : SV_DomainLocation) + { + VertexData v = (VertexData) 0; + UNITY_TRANSFER_INSTANCE_ID(patch[0], v); + v.vertex = patch[0].vertex * baryCoords.x + patch[1].vertex * baryCoords.y + patch[2].vertex * baryCoords.z; + + #if defined(TESS_PHONG) + float3 pp[3]; + for (int index = 0; index < 3; ++index) + { + pp[index] = v.vertex.xyz - patch[index].normal * (dot(v.vertex.xyz, patch[index].normal) - dot(patch[index].vertex.xyz, patch[index].normal)); + } + v.vertex.xyz = 0.5 * (pp[0]*baryCoords.x + pp[1]*baryCoords.y + pp[2]*baryCoords.z) + (0.5) * v.vertex.xyz; + #endif + + v.normal = patch[0].normal * baryCoords.x + patch[1].normal * baryCoords.y + patch[2].normal * baryCoords.z; + v.tangent = patch[0].tangent * baryCoords.x + patch[1].tangent * baryCoords.y + patch[2].tangent * baryCoords.z; + v.color = patch[0].color * baryCoords.x + patch[1].color * baryCoords.y + patch[2].color * baryCoords.z; + v.uv0 = patch[0].uv0 * baryCoords.x + patch[1].uv0 * baryCoords.y + patch[2].uv0 * baryCoords.z; + v.uv1 = patch[0].uv1 * baryCoords.x + patch[1].uv1 * baryCoords.y + patch[2].uv1 * baryCoords.z; + v.uv2 = patch[0].uv2 * baryCoords.x + patch[1].uv2 * baryCoords.y + patch[2].uv2 * baryCoords.z; + v.uv3 = patch[0].uv3 * baryCoords.x + patch[1].uv3 * baryCoords.y + patch[2].uv3 * baryCoords.z; + + FragmentData o; + UNITY_INITIALIZE_OUTPUT(FragmentData, o); + UNITY_TRANSFER_INSTANCE_ID(patch[0], o); + + // Outlines skip the vertex shader if they are disabled + #if !defined(PASS_OUTLINE) || defined(OUTLINE_ENABLED) + + // ForwardBase Tess Domain Vertex Chain + %VertexFunctions + + // ForwardBase Tess Domain VertexBase + %VertexBase + + #endif + + // Outlines nan the vertices if they are disbaled + #if defined(PASS_OUTLINE) && !defined(OUTLINE_ENABLED) + + o.pos = asfloat(-1); + return o; + + #endif + + #if defined(UNITY_PASS_SHADOWCASTER) + TRANSFER_SHADOW_CASTER_NORMALOFFSET(o); + #endif + + return o; + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Tessellation.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Tessellation.orlsource.meta new file mode 100644 index 00000000..205f86bc --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Tessellation.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 25a4209e72b0ff940bfa34fb8699c03a +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/AudioLink.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/AudioLink.orlsource index a0711583..24bc7d1e 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/AudioLink.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/AudioLink.orlsource @@ -25,7 +25,10 @@ %ShaderFeatures() { - #pragma shader_feature_local AL_MODE_NONE AL_MODE_SINGLE_CHANNEL AL_MODE_PACKED_MAP AL_MODE_UV_BASED + #pragma shader_feature_local_fragment AL_MODE_SINGLE_CHANNEL AL_MODE_PACKED_MAP AL_MODE_UV_BASED + #if !defined(AL_MODE_SINGLE_CHANNEL) && !defined(AL_MODE_PACKED_MAP) && !defined(AL_MODE_UV_BASED) + #define AL_MODE_NONE + #endif } %Includes() @@ -131,6 +134,8 @@ half sampledAL = AudioLinkLerp(aluv).x; half3 em = alMask.rgb * _ALEmissionColor.rgb * sampledAL; + #else + half3 em = 0; #endif half NoV = saturate(dot(d.worldNormal, d.worldSpaceViewDir)); diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Emission.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Emission.orlsource index 3c65df9f..8d785983 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Emission.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Emission.orlsource @@ -10,7 +10,7 @@ %ShaderFeatures() { - #pragma shader_feature_local _EMISSION + #pragma shader_feature_local_fragment _EMISSION } %Variables() diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Main.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Main.orlsource index 511ca0dc..2c963082 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Main.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Main.orlsource @@ -25,7 +25,7 @@ %ShaderFeatures() { - #pragma shader_feature_local SEPARATE_ALPHA + #pragma shader_feature_local_fragment SEPARATE_ALPHA } @@ -60,7 +60,7 @@ { void ToonMainFragment(MeshData d, inout SurfaceData o, bool facing) { - half2 uv = 0; + float2 uv = 0; switch (_MainTexUVSet) { case 0: uv = d.uv0; break; case 1: uv = d.uv1; break; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Normals.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Normals.orlsource index b0b9436b..a0ffefd3 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Normals.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Normals.orlsource @@ -8,6 +8,7 @@ UI_BumpMapTilingIndependentNote("> Will scale UVs on its own %ShowIf(_BumpMapTilingMode == 1 && _BumpMap)", Int) = 0 _BumpScale("Normal Map Scale %ShowIf(_BumpMap)", Range(-2, 2)) = 1 [ToggleUI]_FlipBumpY ("Flip Y (UE Mode) %ShowIf(_BumpMap)", Int) = 0 + [ToggleUI]_NormalBicubicSampling("Use Bicubic Sampling %ShowIf(_BumpMap)", Int) = 0 _DetailNormalMap("Detail Normal > %SetKeyword(_DetailNormalMap, DETAIL_NORMALS_SET)", 2D) = "bump" {} [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_DetailNormalsUVSet("UV Set %ShowIf(_DetailNormalMap)", Int) = 0 @@ -21,8 +22,8 @@ %ShaderFeatures() { - #pragma shader_feature_local NORMALS_SET - #pragma shader_feature_local DETAIL_NORMALS_SET + #pragma shader_feature_local_fragment NORMALS_SET + #pragma shader_feature_local_fragment DETAIL_NORMALS_SET } %ShaderDefines() @@ -37,6 +38,7 @@ half _BumpScale; int _FlipBumpY; + int _NormalBicubicSampling; half4 _DetailNormalMap_ST; int _DetailNormalsUVSet; half _DetailNormalTiling; @@ -71,12 +73,17 @@ #endif #if defined(NORMALS_SET) - half4 normalTex = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, lerp(globalUv, d.uv0.xy, _BumpMapTilingMode) * _BumpMapTiling); + float4 normalTex = 0; + if (_NormalBicubicSampling) { + normalTex = tex2DFastBicubicSampleNoChecks(_BumpMap, sampler_BumpMap, lerp(globalUv, d.uv0.xy, _BumpMapTilingMode) * _BumpMapTiling); + } else { + normalTex = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, lerp(globalUv, d.uv0.xy, _BumpMapTilingMode) * _BumpMapTiling); + } if (_FlipBumpY) { normalTex.y = 1 - normalTex.y; } - half3 normal = UnpackScaleNormal(normalTex, _BumpScale); + half3 normal = UnpackNormalScale(normalTex, _BumpScale); o.Normal = BlendNormals(o.Normal, normal); #endif @@ -107,7 +114,7 @@ detailMaskUV *= _DetailNormalMaskTiling; half detailMask = SAMPLE_TEXTURE2D(_DetailNormalMask, sampler_DetailNormalMask, detailMaskUV).r; - half3 detailNormal = UnpackScaleNormal(detailNormalTex, _DetailNormalScale); + half3 detailNormal = UnpackNormalScale(detailNormalTex, _DetailNormalScale); o.Normal = lerp(o.Normal, BlendNormals(o.Normal, detailNormal), detailMask); diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Outline.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Outline.orlsource index a16535e7..96df6343 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Outline.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Outline.orlsource @@ -1,14 +1,19 @@ %Properties() { UI_OutlineHeader("# Outline", Int) = 0 - [Toggle(OUTLINE_ENABLED)]_Outline("Enable Outline %SetProp((OUTLINE_ENABLED), _StencilBasePass, 2, 0)", Int) = 0 + [Toggle(OUTLINE_ENABLED)]_Outline("Enable Outline %SetProp((!_OutlineIgnoreStencils && OUTLINE_ENABLED), _StencilBasePass, 2, 0)", Int) = 0 _OutlineTex("Texture > %ShowIf(OUTLINE_ENABLED)", 2D) = "white" {} [HDR]_OutlineColor("Color %ShowIf(OUTLINE_ENABLED)", Color) = (0.5, 0.5, 0.5, 1) [Enum(Lit, 0, Emissive, 1)]_OutlineLightingMode("Lighting Mode %ShowIf(OUTLINE_ENABLED)", Int) = 0 _OutlineAlbedoTint("Albedo Tint %ShowIf(OUTLINE_ENABLED)", Range(0, 1)) = 0 [Tooltip(Uses the Red channel)]_OutlineMask("Width Mask > %ShowIf(OUTLINE_ENABLED)", 2D) = "white" {} - [PowerSlider(3.0)]_OutlineWidth("Width %ShowIf(OUTLINE_ENABLED)", Range(0, 5)) = 1 + [PowerSlider(3.0)]_OutlineWidth("Width %ShowIf(OUTLINE_ENABLED)", Range(0, 10)) = 1 + [ToggleUI]_OutlineWidthAdjustByVertexColor("Adjust by Vertex Color", Int) = 0 [HideInInspector]_StencilBasePass("Stencil Base Pass", Float) = 0 + [ToggleUI]_OutlineIgnoreStencils("Ignore Stencils %SetProp((_OutlineIgnoreStencils), _StencilOutlineComp, 8, 6) %ShowIf(OUTLINE_ENABLED)", Int) = 0 + UI_OutlineIgnoreStencilsNote("> Allows overlapping shapes to show outlines on top of each other. Does not work correctly with transparent materials", Int) = 0 + [HideInInspector]_StencilOutlineComp("Stencil Outline Comp", Float) = 6 + [HideInInspector]_StencilBaseComp("Stencil Base Comp", Float) = 8 } %ShaderFeatures() @@ -19,11 +24,14 @@ %Variables() { int _StencilBasePass; + int _StencilBaseComp; + int _StencilOutlineComp; half4 _OutlineColor; int _OutlineLightingMode; half _OutlineAlbedoTint; half _OutlineWidth; + int _OutlineWidthAdjustByVertexColor; } %Textures() @@ -40,8 +48,8 @@ #if defined(PASS_OUTLINE) half mask = SAMPLE_TEXTURE2D_LOD(_OutlineMask, sampler_OutlineMask, v.uv0, 0); half3 width = mask * _OutlineWidth * .01; - width *= min(distance(mul(unity_ObjectToWorld, v.vertex), _WorldSpaceCameraPos) * 3, 1); - v.vertex.xyz += v.normal.xyz * width; + width *= min(distance(TransformObjectToWorld(v.vertex.xyz), _WorldSpaceCameraPos) * 3, 1); + v.vertex.xyz += v.normal.xyz * lerp(width, width * v.color.r, _OutlineWidthAdjustByVertexColor); #endif } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Reflections.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Reflections.orlsource index 970301af..91013e7c 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Reflections.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Reflections.orlsource @@ -2,7 +2,7 @@ { UI_ReflectionsHeader("# Reflections", Int) = 0 [KeywordEnum(Off, PBR, Baked Cubemap, Matcap)]REFLECTION_MODE("Reflection Mode", Int) = 0 - [Enum(Additive,0,Multiply,1,Subtract,2)] _ReflectionBlendMode("Reflection Blend Mode %ShowIf(!REFLECTION_MODE_OFF)", Int) = 0 + [Enum(Additive,0,Multiply,1,Subtract,2)] _ReflectionBlendMode("Reflection Blend Mode %ShowIf(!REFLECTION_MODE_OFF)", Float) = 0 _BakedCubemap("BakedCubemap > %ShowIf(REFLECTION_MODE_PBR || REFLECTION_MODE_BAKED_CUBEMAP)", CUBE) = "black" {} UI_FallbackNote("> Will be used if world has no reflections %ShowIf(REFLECTION_MODE_PBR)", Int) = 0 _MetallicGlossMap("Metallic Smoothness > %ShowIf(REFLECTION_MODE_PBR || REFLECTION_MODE_BAKED_CUBEMAP)", 2D) = "white" {} @@ -33,13 +33,13 @@ %ShaderFeatures() { - #pragma shader_feature_local REFLECTION_MODE_OFF REFLECTION_MODE_PBR REFLECTION_MODE_BAKED_CUBEMAP REFLECTION_MODE_MATCAP + #pragma shader_feature_local_fragment REFLECTION_MODE_OFF REFLECTION_MODE_PBR REFLECTION_MODE_BAKED_CUBEMAP REFLECTION_MODE_MATCAP } %Variables() { int _ReflectionMode; - int _ReflectionBlendMode; + half _ReflectionBlendMode; half _Smoothness; half _Metallic; int _RoughnessMode; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/RimLight.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/RimLight.orlsource index 5b076350..1b906591 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/RimLight.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/RimLight.orlsource @@ -9,12 +9,12 @@ [Tooltip(Controls how much the rimlight will be visible in shadowed areas. 0 always visible)]_RimAttenuation("Attenuation %ShowIf(RIMLIGHT_ON)", Range(0,1)) = 1 _RimRange("Range %ShowIf(RIMLIGHT_ON)", Range(0, 1)) = 0.7 [Tooltip(Controls how much the rim light will be offset by the light direction. 1 Will only show up in the areas hit by the light, 0 will show up everywhere)]_RimThreshold("Threshold %ShowIf(RIMLIGHT_ON)", Range(0, 1)) = 0.1 - _RimSharpness("Sarpness %ShowIf(RIMLIGHT_ON)", Range(0,1)) = 0.1 + _RimSharpness("Sharpness %ShowIf(RIMLIGHT_ON)", Range(0,1)) = 0.1 } %ShaderFeatures() { - #pragma shader_feature_local RIMLIGHT_ON + #pragma shader_feature_local_fragment RIMLIGHT_ON } %Variables() diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/ShadowRim.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/ShadowRim.orlsource index 6eacce1a..4a94a4d7 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/ShadowRim.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/ShadowRim.orlsource @@ -5,13 +5,13 @@ _ShadowRimTint("Tint %ShowIf(RIMSHADOW_ON)", Color) = (1,1,1,1) _ShadowRimRange("Range %ShowIf(RIMSHADOW_ON)", Range(0,1)) = 0.7 [Tooltip(Controls how much the rim shadow will be offset by the light direction. 1 Will only show up in the areas in shadow, 0 will show up everywhere)]_ShadowRimThreshold("Threshold %ShowIf(RIMSHADOW_ON)", Range(0,1)) = 0.1 - _ShadowRimSharpness("Sarpness %ShowIf(RIMSHADOW_ON)", Range(0,1)) = 0.3 + _ShadowRimSharpness("Sharpness %ShowIf(RIMSHADOW_ON)", Range(0,1)) = 0.3 _ShadowRimAlbedoTint("Albedo Tint %ShowIf(RIMSHADOW_ON)", Range(0,1)) = 0 } %ShaderFeatures() { - #pragma shader_feature_local RIMSHADOW_ON + #pragma shader_feature_local_fragment RIMSHADOW_ON } %Variables() @@ -28,11 +28,10 @@ void ToonShadowRimFragment(MeshData d, inout SurfaceData o) { #if defined(RIMSHADOW_ON) - #ifndef USING_DIRECTIONAL_LIGHT - fixed3 lightDir = normalize(UnityWorldSpaceLightDir(d.worldSpacePosition)); - #else - fixed3 lightDir = _WorldSpaceLightPos0.xyz; - #endif + Light mainLight = GetMainLight(0..xxxx, d.worldSpacePosition, 0..xxxx); + + float3 lightDir = mainLight.direction; + bool lightEnv = any(lightDir.xyz); if (!lightEnv) { lightDir = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Specular.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Specular.orlsource index cf034dc6..af4222cb 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Specular.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/Specular.orlsource @@ -26,7 +26,7 @@ %ShaderFeatures() { - #pragma shader_feature_local SPECULAR_ON + #pragma shader_feature_local_fragment SPECULAR_ON } %Variables() @@ -72,7 +72,7 @@ half3 specMap = SAMPLE_TEXTURE2D(_SpecularMap, sampler_MainTex, specularUv); o.SpecularIntensity = max(0, _SpecularIntensity * specMap.r); - o.SpecularArea = max(0.01, GSAA_Filament(o.Normal, _SpecularRoughness, 0.05, 0.1) * specMap.b); + o.SpecularArea = max(0.01, GSAA_Filament(d.worldNormal, _SpecularRoughness, 0.05, 0.1) * specMap.b); o.SpecularAnisotropy = _SpecularAnisotropy; o.SpecularAlbedoTint = _SpecularAlbedoTint * specMap.g; o.SpecularSharpness = _SpecularSharpness; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/UVDiscard.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/UVDiscard.orlsource index 0da05c6e..3b6d62ff 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/UVDiscard.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/UVDiscard.orlsource @@ -17,7 +17,7 @@ %ShaderFeatures() { - #pragma shader_feature_local UV_DISCARD + #pragma shader_feature_local_vertex UV_DISCARD } %Variables() @@ -45,7 +45,7 @@ void ToonUVDiscardVertex(inout VertexData v) { #if defined(UV_DISCARD) - half2 uv = v.uv0; + float2 uv = v.uv0; switch (_UVDiscardUVSet) { case 0: uv = v.uv0; break; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2.meta new file mode 100644 index 00000000..2369672e --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d39bf75136828641abe0e25e322f147 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Decals.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Decals.orlsource new file mode 100644 index 00000000..0655d32c --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Decals.orlsource @@ -0,0 +1,401 @@ +%Properties() +{ + UI_DecalsHeader("# Decals", Int) = 0 + _DecalsMask("Decals Mask %SetKeyword(_DecalsMask, DECALS_MASK_SET)", 2D) = "white" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_DecalsMaskUVSet("UV Set %ShowIf(DECALS_MASK_SET)", Int) = 0 + + UI_DecalsLayer1Header("## Layer 1", Int) = 0 + [Toggle(DECAL_0)]_Decal0Enabled("Enable Layer 1", Int) = 0 + _Decal0Map("Decal > %ShowIf(DECAL_0)", 2D) = "white" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_Decal0UVSet("UV Set %ShowIf(_Decal0Map && DECAL_0)", Int) = 0 + _Decal0Scale("Scale %ShowIf(_Decal0Map && DECAL_0)", Float) = 1 + _Decal0Offset("Offset %ShowIf(_Decal0Map && DECAL_0) %Vector2(Offset X, Y)", Vector) = (0,0,0,0) + _Decal0Rotation("Rotation %ShowIf(DECAL_0)", Range(0, 360)) = 0 + [ToggleUI]_Decal0Tile("Tile Decal %ShowIf(_Decal0Map && DECAL_0)", Int) = 0 + _Decal0Tiling("Tiling %ShowIf(_Decal0Map && DECAL_0 && _Decal0Tile) %Vector2(Tiling X, Y)", Vector) = (1,1,0,0) + + UI_Decal0ColorsHeader("### Colors %ShowIf(DECAL_0)", Int) = 0 + _Decal0Tint("Tint %ShowIf(DECAL_0)", Color) = (1,1,1,1) + [ToggleUI]_Decal0UseEmission("Use Emission %ShowIf(DECAL_0)", Int) = 0 + _Decal0EmissionStrength("Emission Strength %ShowIf(DECAL_0 && _Decal0UseEmission)", Float) = 0 + [ToggleUI]_Decal0RimFade("Rim Fade %ShowIf(DECAL_0)", Int) = 0 + _Decal0RimFadePower("Rim Fade Power %ShowIf(DECAL_0 && _Decal0RimFade)", Float) = 6 + [ToggleUI]_Decal0RimFadeInvert("Invert Rim Fade %ShowIf(DECAL_0 && _Decal0RimFade)", Int) = 0 + _Decal0RimFadeUnderlay("Rim Fade Underlay %ShowIf(DECAL_0 && _Decal0RimFade)", Color) = (0,0,0,1) + + UI_Decal0MaskingHeader("### Masking %ShowIf(DECAL_0)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_Decal0MaskChannel("Mask Channel %ShowIf(DECAL_0)", Int) = 0 + _Decal0MaskStrength("Mask Strength %ShowIf(DECAL_0)", Range(0, 1)) = 1 + [ToggleUI]_Decal0Clip("Clip Decal %ShowIf(DECAL_0)", Int) = 0 + [ToggleUI]_Decal0ClipCirlce("Circle Clip %ShowIf(DECAL_0 && _Decal0Clip)", Int) = 0 + _Decal0ClipSize("Clip Size %ShowIf(DECAL_0 && _Decal0Clip)", Range(0.0001, 0.5)) = 0.5 + _Decal0ClipFalloff("Clip Falloff %ShowIf(DECAL_0 && _Decal0Clip)", Range(0, 0.5)) = 0.01 + + UI_Decal0Separator("--- %ShowIf(DECAL_0)", Int) = 0 + + UI_DecalsLayer2Header("## Layer 2", Int) = 0 + [Toggle(DECAL_1)]_Decal1Enabled("Enable Layer 2", Int) = 0 + _Decal1Map("Decal %ShowIf(DECAL_1)", 2D) = "white" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_Decal1UVSet("UV Set %ShowIf(_Decal1Map && DECAL_1)", Int) = 0 + _Decal1Scale("Scale %ShowIf(_Decal1Map && DECAL_1)", Float) = 1 + _Decal1Offset("Offset %ShowIf(_Decal1Map && DECAL_1) %Vector2(Offset X, Y)", Vector) = (0,0,0,0) + _Decal1Rotation("Rotation %ShowIf(DECAL_1)", Range(0, 360)) = 0 + [ToggleUI]_Decal1Tile("Tile Decal %ShowIf(_Decal1Map && DECAL_1)", Int) = 0 + _Decal1Tiling("Tiling %ShowIf(_Decal1Map && DECAL_1 && _Decal1Tile) %Vector2(Tiling X, Y)", Vector) = (1,1,0,0) + + UI_Decal1ColorsHeader("### Colors %ShowIf(DECAL_1)", Int) = 0 + _Decal1Tint("Tint %ShowIf(DECAL_1)", Color) = (1,1,1,1) + [ToggleUI]_Decal1UseEmission("Use Emission %ShowIf(DECAL_1)", Int) = 0 + _Decal1EmissionStrength("Emission Strength %ShowIf(DECAL_1 && _Decal1UseEmission)", Float) = 0 + [ToggleUI]_Decal1RimFade("Rim Fade %ShowIf(DECAL_1)", Int) = 0 + _Decal1RimFadePower("Rim Fade Power %ShowIf(DECAL_1 && _Decal1RimFade)", Float) = 6 + [ToggleUI]_Decal1RimFadeInvert("Invert Rim Fade %ShowIf(DECAL_1 && _Decal1RimFade)", Int) = 0 + _Decal1RimFadeUnderlay("Rim Fade Underlay %ShowIf(DECAL_1 && _Decal1RimFade)", Color) = (0,0,0,1) + + UI_Decal1MaskingHeader("### Masking %ShowIf(DECAL_1)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_Decal1MaskChannel("Mask Channel %ShowIf(DECAL_1)", Int) = 0 + _Decal1MaskStrength("Mask Strength %ShowIf(DECAL_1)", Range(0, 1)) = 1 + [ToggleUI]_Decal1Clip("Clip Decal %ShowIf(DECAL_1)", Int) = 0 + [ToggleUI]_Decal1ClipCirlce("Circle Clip %ShowIf(DECAL_1 && _Decal1Clip)", Int) = 0 + _Decal1ClipSize("Clip Size %ShowIf(DECAL_1 && _Decal1Clip)", Range(0.0001, 0.5)) = 0.5 + _Decal1ClipFalloff("Clip Falloff %ShowIf(DECAL_1 && _Decal1Clip)", Range(0, 0.5)) = 0.01 + + UI_Decal1Separator("--- %ShowIf(DECAL_1)", Int) = 0 + + UI_DecalsLayer3Header("## Layer 3", Int) = 0 + [Toggle(DECAL_2)]_Decal2Enabled("Enable Layer 3", Int) = 0 + _Decal2Map("Decal %ShowIf(DECAL_2)", 2D) = "white" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_Decal2UVSet("UV Set %ShowIf(_Decal2Map && DECAL_2)", Int) = 0 + _Decal2Scale("Scale %ShowIf(_Decal2Map && DECAL_2)", Float) = 1 + _Decal2Offset("Offset %ShowIf(_Decal2Map && DECAL_2) %Vector2(Offset X, Y)", Vector) = (0,0,0,0) + _Decal2Rotation("Rotation %ShowIf(DECAL_2)", Range(0, 360)) = 0 + [ToggleUI]_Decal2Tile("Tile Decal %ShowIf(_Decal2Map && DECAL_2)", Int) = 0 + _Decal2Tiling("Tiling %ShowIf(_Decal2Map && DECAL_2 && _Decal2Tile) %Vector2(Tiling X, Y)", Vector) = (1,1,0,0) + + UI_Decal2ColorsHeader("### Colors %ShowIf(DECAL_2)", Int) = 0 + _Decal2Tint("Tint %ShowIf(DECAL_2)", Color) = (1,1,1,1) + [ToggleUI]_Decal2UseEmission("Use Emission %ShowIf(DECAL_2)", Int) = 0 + _Decal2EmissionStrength("Emission Strength %ShowIf(DECAL_2 && _Decal2UseEmission)", Float) = 0 + [ToggleUI]_Decal2RimFade("Rim Fade %ShowIf(DECAL_2)", Int) = 0 + _Decal2RimFadePower("Rim Fade Power %ShowIf(DECAL_2 && _Decal2RimFade)", Float) = 6 + [ToggleUI]_Decal2RimFadeInvert("Invert Rim Fade %ShowIf(DECAL_2 && _Decal2RimFade)", Int) = 0 + _Decal2RimFadeUnderlay("Rim Fade Underlay %ShowIf(DECAL_2 && _Decal2RimFade)", Color) = (0,0,0,1) + + UI_Decal2MaskingHeader("### Masking %ShowIf(DECAL_2)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_Decal2MaskChannel("Mask Channel %ShowIf(DECAL_2)", Int) = 0 + _Decal2MaskStrength("Mask Strength %ShowIf(DECAL_2)", Range(0, 1)) = 1 + [ToggleUI]_Decal2Clip("Clip Decal %ShowIf(DECAL_2)", Int) = 0 + [ToggleUI]_Decal2ClipCirlce("Circle Clip %ShowIf(DECAL_2 && _Decal2Clip)", Int) = 0 + _Decal2ClipSize("Clip Size %ShowIf(DECAL_2 && _Decal2Clip)", Range(0.0001, 0.5)) = 0.5 + _Decal2ClipFalloff("Clip Falloff %ShowIf(DECAL_2 && _Decal2Clip)", Range(0, 0.5)) = 0.01 + + UI_Decal2Separator("--- %ShowIf(DECAL_2)", Int) = 0 + + UI_DecalsLayer4Header("## Layer 4", Int) = 0 + [Toggle(DECAL_3)]_Decal3Enabled("Enable Layer 4", Int) = 0 + _Decal3Map("Decal %ShowIf(DECAL_3)", 2D) = "white" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_Decal3UVSet("UV Set %ShowIf(_Decal3Map && DECAL_3)", Int) = 0 + _Decal3Scale("Scale %ShowIf(_Decal3Map && DECAL_3)", Float) = 1 + _Decal3Offset("Offset %ShowIf(_Decal3Map && DECAL_3) %Vector2(Offset X, Y)", Vector) = (0,0,0,0) + _Decal3Rotation("Rotation %ShowIf(DECAL_3)", Range(0, 360)) = 0 + [ToggleUI]_Decal3Tile("Tile Decal %ShowIf(_Decal3Map && DECAL_3)", Int) = 0 + _Decal3Tiling("Tiling %ShowIf(_Decal3Map && DECAL_3 && _Decal3Tile) %Vector2(Tiling X, Y)", Vector) = (1,1,0,0) + + UI_Decal3ColorsHeader("### Colors %ShowIf(DECAL_3)", Int) = 0 + _Decal3Tint("Tint %ShowIf(DECAL_3)", Color) = (1,1,1,1) + [ToggleUI]_Decal3UseEmission("Use Emission %ShowIf(DECAL_3)", Int) = 0 + _Decal3EmissionStrength("Emission Strength %ShowIf(DECAL_3 && _Decal3UseEmission)", Float) = 0 + [ToggleUI]_Decal3RimFade("Rim Fade %ShowIf(DECAL_3)", Int) = 0 + _Decal3RimFadePower("Rim Fade Power %ShowIf(DECAL_3 && _Decal3RimFade)", Float) = 6 + [ToggleUI]_Decal3RimFadeInvert("Invert Rim Fade %ShowIf(DECAL_3 && _Decal3RimFade)", Int) = 0 + _Decal3RimFadeUnderlay("Rim Fade Underlay %ShowIf(DECAL_3 && _Decal3RimFade)", Color) = (0,0,0,1) + + UI_Decal3MaskingHeader("### Masking %ShowIf(DECAL_3)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_Decal3MaskChannel("Mask Channel %ShowIf(DECAL_3)", Int) = 0 + _Decal3MaskStrength("Mask Strength %ShowIf(DECAL_3)", Range(0, 1)) = 1 + [ToggleUI]_Decal3Clip("Clip Decal %ShowIf(DECAL_3)", Int) = 0 + [ToggleUI]_Decal3ClipCirlce("Circle Clip %ShowIf(DECAL_3 && _Decal3Clip)", Int) = 0 + _Decal3ClipSize("Clip Size %ShowIf(DECAL_3 && _Decal3Clip)", Range(0.0001, 0.5)) = 0.5 + _Decal3ClipFalloff("Clip Falloff %ShowIf(DECAL_3 && _Decal3Clip)", Range(0, 0.5)) = 0.01 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment DECALS_MASK_SET + #pragma shader_feature_local_fragment DECAL_0 + #pragma shader_feature_local_fragment DECAL_1 + #pragma shader_feature_local_fragment DECAL_2 + #pragma shader_feature_local_fragment DECAL_3 +} + +%Variables() +{ + #if defined(DECALS_MASK_SET) + float4 _DecalsMask_ST; + int _DecalsMaskUVSet; + #endif + + + #if defined(DECAL_0) + int _Decal0UVSet; + float _Decal0Scale; + float2 _Decal0Offset; + float _Decal0Rotation; + int _Decal0Tile; + float2 _Decal0Tiling; + + half4 _Decal0Tint; + int _Decal0UseEmission; + half _Decal0EmissionStrength; + int _Decal0RimFade; + half _Decal0RimFadePower; + int _Decal0RimFadeInvert; + half4 _Decal0RimFadeUnderlay; + + int _Decal0MaskChannel; + half _Decal0MaskStrength; + int _Decal0Clip; + int _Decal0ClipCirlce; + half _Decal0ClipSize; + half _Decal0ClipFalloff; + #endif + + #if defined(DECAL_1) + int _Decal1UVSet; + float _Decal1Scale; + float2 _Decal1Offset; + float _Decal1Rotation; + int _Decal1Tile; + float2 _Decal1Tiling; + + half4 _Decal1Tint; + int _Decal1UseEmission; + half _Decal1EmissionStrength; + int _Decal1RimFade; + half _Decal1RimFadePower; + int _Decal1RimFadeInvert; + half4 _Decal1RimFadeUnderlay; + + int _Decal1MaskChannel; + half _Decal1MaskStrength; + int _Decal1Clip; + int _Decal1ClipCirlce; + half _Decal1ClipSize; + half _Decal1ClipFalloff; + #endif + + #if defined(DECAL_2) + int _Decal2UVSet; + float _Decal2Scale; + float2 _Decal2Offset; + float _Decal2Rotation; + int _Decal2Tile; + float2 _Decal2Tiling; + + half4 _Decal2Tint; + int _Decal2UseEmission; + half _Decal2EmissionStrength; + int _Decal2RimFade; + half _Decal2RimFadePower; + int _Decal2RimFadeInvert; + half4 _Decal2RimFadeUnderlay; + + int _Decal2MaskChannel; + half _Decal2MaskStrength; + int _Decal2Clip; + int _Decal2ClipCirlce; + half _Decal2ClipSize; + half _Decal2ClipFalloff; + #endif + + #if defined(DECAL_3) + int _Decal3UVSet; + float _Decal3Scale; + float2 _Decal3Offset; + float _Decal3Rotation; + int _Decal3Tile; + float2 _Decal3Tiling; + + half4 _Decal3Tint; + int _Decal3UseEmission; + half _Decal3EmissionStrength; + int _Decal3RimFade; + half _Decal3RimFadePower; + int _Decal3RimFadeInvert; + half4 _Decal3RimFadeUnderlay; + + int _Decal3MaskChannel; + half _Decal3MaskStrength; + int _Decal3Clip; + int _Decal3ClipCirlce; + half _Decal3ClipSize; + half _Decal3ClipFalloff; + #endif +} + +%Textures() +{ + TEXTURE2D(_DecalsMask); + SAMPLER(sampler_DecalsMask); + + #if defined(DECAL_0) + TEXTURE2D(_Decal0Map); + #endif + + #if defined(DECAL_1) + TEXTURE2D(_Decal1Map); + #endif + + #if defined(DECAL_2) + TEXTURE2D(_Decal2Map); + #endif + + #if defined(DECAL_3) + TEXTURE2D(_Decal3Map); + #endif + + // Define correct samplers in case some are not defined + // This allows to always reuse the earlier sampler if it was available + #if defined(DECAL_0) + SAMPLER(sampler_Decal0Map); + #define DecalSampler sampler_Decal0Map + #endif + + #if !defined(DECAL_0) && defined(DECAL_1) + SAMPLER(sampler_Decal1Map); + #define DecalSampler sampler_Decal1Map + #endif + + #if !defined(DECAL_0) && !defined(DECAL_1) && defined(DECAL_2) + SAMPLER(sampler_Decal2Map); + #define DecalSampler sampler_Decal2Map + #endif + + #if !defined(DECAL_0) && !defined(DECAL_1) && !defined(DECAL_2) && defined(DECAL_3) + SAMPLER(sampler_Decal3Map); + #define DecalSampler sampler_Decal3Map + #endif +} + +%Fragment("ToonDecalsFragment") +{ + half4 GetDecalTexture(MeshData d, int uvSet, float scale, int shouldTile, float2 tiling, float2 offset, float rotation, TEXTURE2D_PARAM(decalTexture, sampler_decalTexture), half4 tint, out float2 decalUV) + { + decalUV = 0; + switch (uvSet) { + case 0: decalUV = d.uv0; break; + case 1: decalUV = d.uv1; break; + case 2: decalUV = d.uv2; break; + case 3: decalUV = d.uv3; break; + } + decalUV -= offset; + decalUV -= 0.5; + decalUV *= 1.0 / scale; + decalUV += 0.5; + + // Using a separate deriv UV so we can avoiod artifacts + float2 derivUV = decalUV; + + if (shouldTile) + { + derivUV = decalUV * tiling; + decalUV = frac(decalUV * tiling); + } + + if (rotation > 0) + { + decalUV = RotateAroundCenter2D(decalUV, rotation); + } + half4 decalTexData = SAMPLE_TEXTURE2D_GRAD(decalTexture, sampler_decalTexture, decalUV, ddx(derivUV), ddy(derivUV)); + decalTexData *= tint; + return decalTexData; + } + + half4 GetDecalRimFade(half4 decalTexture, int fade, int invertFade, half NoV, half power, half4 rimFadeUnderlay) + { + if (!fade) return decalTexture; + half rimFade = pow(saturate(invertFade ? 1 - NoV : NoV), power); + decalTexture.rgb = lerp(rimFadeUnderlay.rgb, decalTexture.rgb, lerp(1, rimFade, rimFadeUnderlay.a)); + return decalTexture; + } + + half4 GetDecalClip(half4 decalTexture, float2 decalUV, int clip, int clipAsCircle, half clipSize, half clipFalloff) + { + if (!clip) return decalTexture; + float clipShape = (clipAsCircle ? SDFCircle(decalUV.xy - 0.5, clipSize.xx) : SDFBox(decalUV.xy - 0.5, clipSize.xx)) + clipFalloff; + clipShape = 1 - smoothstep(0, clipFalloff, clipShape); + decalTexture.a *= clipShape; + return decalTexture; + } + + void CompositeDecal(inout SurfaceData o, half4 decalTexture, half4 maskTexture, int maskChannel, half maskStrength, int useEmission, half emissionStrength) + { + half mask = maskTexture[maskChannel]; + mask = lerp(1, mask, maskStrength); + o.Albedo = lerp(o.Albedo, decalTexture, decalTexture.a * mask); + if (useEmission) + { + o.Emission += (decalTexture.rgb * decalTexture.a * mask) * emissionStrength; + } + } + + void ToonDecalsFragment(MeshData d, inout SurfaceData o) { + ORL_UVChannelData uvData = SetupChannelData(d); + half4 decalsMask = 1; + #if defined(DECALS_MASK_SET) + { + float2 decalsMaskUV = GetUVChannel(uvData, _DecalsMaskUVSet, _DecalsMask_ST); + decalsMask = SAMPLE_TEXTURE2D(_DecalsMask, sampler_DecalsMask, decalsMaskUV); + } + #endif + + #if defined(DECAL_0) || defined(DECAL_1) || defined(DECAL_2) || defined(DECAL_3) + half NoV = dot(d.worldNormal, d.worldSpaceViewDir); + #endif + + // Decal 1 + #if defined(DECAL_0) + { + float2 decalUV = 0; + half4 decalTexture = GetDecalTexture(d, _Decal0UVSet, _Decal0Scale, _Decal0Tile, _Decal0Tiling, _Decal0Offset, _Decal0Rotation, TEXTURE2D_ARGS(_Decal0Map, DecalSampler), _Decal0Tint, decalUV); + decalTexture = GetDecalRimFade(decalTexture, _Decal0RimFade, _Decal0RimFadeInvert, NoV, _Decal0RimFadePower, _Decal0RimFadeUnderlay); + decalTexture = GetDecalClip(decalTexture, decalUV, _Decal0Clip, _Decal0ClipCirlce, _Decal0ClipSize, _Decal0ClipFalloff); + CompositeDecal(o, decalTexture, decalsMask, _Decal0MaskChannel, _Decal0MaskStrength, _Decal0UseEmission, _Decal0EmissionStrength); + + } + #endif + + // Decal 2 + #if defined(DECAL_1) + { + float2 decalUV = 0; + half4 decalTexture = GetDecalTexture(d, _Decal1UVSet, _Decal1Scale, _Decal1Tile, _Decal1Tiling, _Decal1Offset, _Decal1Rotation, TEXTURE2D_ARGS(_Decal1Map, DecalSampler), _Decal1Tint, decalUV); + decalTexture = GetDecalRimFade(decalTexture, _Decal1RimFade, _Decal1RimFadeInvert, NoV, _Decal1RimFadePower, _Decal1RimFadeUnderlay); + decalTexture = GetDecalClip(decalTexture, decalUV, _Decal1Clip, _Decal1ClipCirlce, _Decal1ClipSize, _Decal1ClipFalloff); + CompositeDecal(o, decalTexture, decalsMask, _Decal1MaskChannel, _Decal1MaskStrength, _Decal1UseEmission, _Decal1EmissionStrength); + } + #endif + + // Decal 3 + #if defined(DECAL_2) + { + float2 decalUV = 0; + half4 decalTexture = GetDecalTexture(d, _Decal2UVSet, _Decal2Scale, _Decal2Tile, _Decal2Tiling, _Decal2Offset, _Decal2Rotation, TEXTURE2D_ARGS(_Decal2Map, DecalSampler), _Decal2Tint, decalUV); + decalTexture = GetDecalRimFade(decalTexture, _Decal2RimFade, _Decal2RimFadeInvert, NoV, _Decal2RimFadePower, _Decal2RimFadeUnderlay); + decalTexture = GetDecalClip(decalTexture, decalUV, _Decal2Clip, _Decal2ClipCirlce, _Decal2ClipSize, _Decal2ClipFalloff); + CompositeDecal(o, decalTexture, decalsMask, _Decal2MaskChannel, _Decal2MaskStrength, _Decal2UseEmission, _Decal2EmissionStrength); + } + #endif + + // Decal 3 + #if defined(DECAL_3) + { + float2 decalUV = 0; + half4 decalTexture = GetDecalTexture(d, _Decal3UVSet, _Decal3Scale, _Decal3Tile, _Decal3Tiling, _Decal3Offset, _Decal3Rotation, TEXTURE2D_ARGS(_Decal3Map, DecalSampler), _Decal3Tint, decalUV); + decalTexture = GetDecalRimFade(decalTexture, _Decal3RimFade, _Decal3RimFadeInvert, NoV, _Decal3RimFadePower, _Decal3RimFadeUnderlay); + decalTexture = GetDecalClip(decalTexture, decalUV, _Decal3Clip, _Decal3ClipCirlce, _Decal3ClipSize, _Decal3ClipFalloff); + CompositeDecal(o, decalTexture, decalsMask, _Decal3MaskChannel, _Decal3MaskStrength, _Decal3UseEmission, _Decal3EmissionStrength); + } + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Decals.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Decals.orlsource.meta new file mode 100644 index 00000000..83647987 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Decals.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 78e789740505dea49a297c24e673e139 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Emission.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Emission.orlsource new file mode 100644 index 00000000..21c3e638 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Emission.orlsource @@ -0,0 +1,93 @@ +%Properties() +{ + UI_EmissionHeader("# Emission", Int) = 0 + [NoScaleOffset]_EmissionMap("Emission Map > %SetKeyword(_EmissionMap, _EMISSION)", 2D) = "white" {} + [Enum(RGB, 0, R, 1, G, 2, B, 3, A, 4)]_EmissionMapChannel("Emission Map Channel", Int) = 0 + [HDR]_EmissionColor("Color", Color) = (0,0,0,1) + _EmissionHue("Hue", Range(0,1)) = 0 + _EmissionSaturation("Saturation", Range(-1,1)) = 0 + _EmissionValue("Value", Range(-1,1)) = 0 + _EmissionTintToDiffuse("Tint To Diffuse", Range(0,1)) = 0 + [Enum(No,0,Yes,1)]_EmissionScaleWithLight("Scale w/ Light", Int) = 0 + UI_EmissionScaleWithLightNote("> Hides emission unless light is weaker than Scaling Sensitivity", Int) = 0 + _EmissionScaleWithLightSensitivity("Scaling Sensitivity %ShowIf(_EmissionScaleWithLight == 1)", Range(0,1)) = 1 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment _EMISSION +} + +%Variables() +{ + int _EmissionMapChannel; + half4 _EmissionColor; + half _EmissionHue; + half _EmissionSaturation; + half _EmissionValue; + half _EmissionTintToDiffuse; + int _EmissionScaleWithLight; + half _EmissionScaleWithLightSensitivity; +} + +%AdditionalSurfaceData() +{ + half EmissionHue; + half EmissionSaturation; + half EmissionValue; + half EmissionTintToDiffuse; + int EmissionScaleWithLight; + half EmissionScaleWithLightSensitivity; +} + +%Textures() +{ + TEXTURE2D(_EmissionMap); +} + +%Fragment("ToonEmissionFragment") +{ + void ToonEmissionFragment(inout SurfaceData o) { + #if defined(_EMISSION) + half4 emissionMap = SAMPLE_TEXTURE2D(_EmissionMap, sampler_MainTex, GLOBAL_uv); + + half3 emission = emissionMap.rgb; + if (_EmissionMapChannel > 0) { + emission = emission[_EmissionMapChannel - 1].rrr; + } + emission *= _EmissionColor.rgb; + o.Emission.rgb += emission.rgb; + #endif + + o.EmissionHue = _EmissionHue; + o.EmissionSaturation = _EmissionSaturation; + o.EmissionValue = _EmissionValue; + + o.EmissionTintToDiffuse = _EmissionTintToDiffuse; + o.EmissionScaleWithLight = _EmissionScaleWithLight; + o.EmissionScaleWithLightSensitivity = _EmissionScaleWithLightSensitivity; + } +} + +%ModuleLighting("ToonEmissionLighting") +{ + void ToonEmissionLighting(SurfaceData o, MeshData d, half3 lightColor, half3 indirectDiffuse, inout half3 emission) + { + half lightAvg = (dot(indirectDiffuse.rgb, float3(0.299, 0.587, 0.114)) + dot(lightColor.rgb, float3(0.299, 0.587, 0.114))) / 2.0; + + emission = o.Emission.rgb; + emission *= lerp(1, o.Albedo.rgb, o.EmissionTintToDiffuse); + + half intensity = length(emission.rgb); + + half3 emissionHSV = RGB2HSV(normalize(emission.rgb)); + emissionHSV.x = fmod(emissionHSV.x + o.EmissionHue, 1); + emissionHSV.y = saturate(emissionHSV.y + o.EmissionSaturation); + emissionHSV.z = saturate(emissionHSV.z + o.EmissionValue); + emission.rgb = HSV2RGB(emissionHSV) * intensity; + + half3 scaledEmission = emission * saturate(smoothstep(1 - o.EmissionScaleWithLightSensitivity, 1 + o.EmissionScaleWithLightSensitivity, 1 - lightAvg)); + + emission = o.EmissionScaleWithLight ? scaledEmission : emission; + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Emission.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Emission.orlsource.meta new file mode 100644 index 00000000..74f14e8e --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Emission.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 4b606e0d7635d3e458df9f730dea991f +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Main.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Main.orlsource new file mode 100644 index 00000000..b83ee1ce --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Main.orlsource @@ -0,0 +1,98 @@ +%Properties() +{ + UI_MainHeader("# Main Settings", Int) = 1 + UI_ToonDocs("[This shader has documentation](https://shaders.orels.sh/docs/toon)", Int) = 0 + _Color("Main Color", Color) = (1, 1, 1, 1) + _BackfaceColor("Backface Color %ShowIf(_CullMode != 2)", Color) = (1, 1, 1, 1) + _BackfaceAlbedoTint("Backface Albedo Tint", Range(0,1)) = 1 + [ToggleUI]_TintByVertexColor("Tint By Vertex Color", Int) = 0 + _MainTex("Albedo", 2D) = "white" {} + [Toggle(SEPARATE_ALPHA)]_SeparateAlpha("Separate Transparency Texture", Int) = 0 + _AlphaTex("Transparency %ShowIf(_SeparateAlpha)", 2D) = "white" {} + _AlphaScale("Alpha Scale %ShowIf(_MainTex || SEPARATE_ALPHA)", Range(0,2)) = 1 + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_MainTexUVSet("UV Set", Int) = 0 + _Hue("Hue", Range(0,1)) = 0 + _Saturation("Saturation", Range(-1,1)) = 0 + _Value("Value", Range(-1,1)) = 0 +} + +%ShaderDefines() +{ + #define GLOBAL_UV_SET +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment SEPARATE_ALPHA +} + + +%Variables() +{ + float4 _MainTex_ST; + int _MainTexUVSet; + int _TintByVertexColor; + half4 _Color; + half4 _BackfaceColor; + half _BackfaceAlbedoTint; + half _AlphaScale; + half _Hue; + half _Saturation; + half _Value; + + float2 GLOBAL_uv; +} + +%Textures() +{ + TEXTURE2D(_MainTex); + SAMPLER(sampler_MainTex); + + #if defined(SEPARATE_ALPHA) + TEXTURE2D(_AlphaTex); + #endif +} + +%Fragment("ToonMainFragment") +{ + void ToonMainFragment(MeshData d, inout SurfaceData o, bool facing) + { + float2 uv = 0; + switch (_MainTexUVSet) { + case 0: uv = d.uv0; break; + case 1: uv = d.uv1; break; + case 2: uv = d.uv2; break; + case 3: uv = d.uv3; break; + } + uv = uv * _MainTex_ST.xy + _MainTex_ST.zw; + GLOBAL_uv = uv; + half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, GLOBAL_uv); + if (facing) { + albedo *= _Color; + } else { + albedo = lerp(_BackfaceColor, albedo * _BackfaceColor, _BackfaceAlbedoTint); + } + half3 albedoHSV = RGB2HSV(albedo.rgb); + + albedoHSV.x = fmod(albedoHSV.x + _Hue, 1); + albedoHSV.y = saturate(albedoHSV.y + _Saturation); + albedoHSV.z = saturate(albedoHSV.z + _Value); + albedo.rgb = HSV2RGB(albedoHSV); + + if (_TintByVertexColor) { + albedo.rgb *= d.vertexColor.rgb; + } + o.Albedo = albedo.rgb; + #if defined(NEED_ALBEDO_ALPHA) + { + #if defined(SEPARATE_ALPHA) + o.Alpha = saturate(SAMPLE_TEXTURE2D(_AlphaTex, sampler_MainTex, GLOBAL_uv).r * _AlphaScale); + #else + o.Alpha = saturate(albedo.a * _AlphaScale); + #endif + } + #else + o.Alpha = 1; + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Main.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Main.orlsource.meta new file mode 100644 index 00000000..df4af5b4 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Main.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2ee065a99b4378e419db0db69a31435d +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Matcaps.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Matcaps.orlsource new file mode 100644 index 00000000..3be6f939 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Matcaps.orlsource @@ -0,0 +1,412 @@ +%Properties() +{ + UI_MatcapsHader("# Matcaps", Int) = 1 + _MatcapsMask("Matcap Mask %SetKeyword(_MatcapsMask, MATCAPS_MASK_SET)", 2D) = "white" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_MatcapsMaskUVSet("UV Set %ShowIf(_MatcapsMask)", Int) = 0 + + UI_Matcap0Header("## Layer 1", Int) = 0 + [Toggle(MATCAP_0)]_Matcap0Enabled("Enable Layer 1", Int) = 0 + _Matcap0Tex("Matcap > %ShowIf(MATCAP_0)", 2D) = "white" {} + _Matcap0Tint("Tint %ShowIf(MATCAP_0)", Color) = (1,1,1,1) + [Enum(UTS, 0, Top Pinch, 1, Double Sided, 2)]_Matcap0UVMode("UV Mode %ShowIf(MATCAP_0)", Int) = 2 + _Matcap0Border("Border %ShowIf(MATCAP_0)", Range(0, 1)) = 0.43 + _Matcap0Blur("Matcap Blur Level %ShowIf(MATCAP_0)", Range(0, 1)) = 0 + _Matcap0TintToDiffuse("Tint Matcap to Diffuse %ShowIf(MATCAP_0)", Range(0, 1)) = 0 + [Enum(Additive,0,Multiply,1,Subtract,2)]_Matcap0BlendMode("Blend Mode %ShowIf(MATCAP_0)", Float) = 0 + _Matcap0Strength("Strength %ShowIf(MATCAP_0)", Range(0, 1)) = 1 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_Matcap0MaskChannel("Mask Channel %ShowIf(MATCAP_0)", Int) = 0 + _Matcap0MaskStrength("Mask Strength %ShowIf(MATCAP_0)", Range(0, 1)) = 1 + + UI_Matcap1Header("## Layer 2", Int) = 0 + [Toggle(MATCAP_1)]_Matcap1Enabled("Enable Layer 2", Int) = 0 + _Matcap1Tex("Matcap > %ShowIf(MATCAP_1)", 2D) = "white" {} + _Matcap1Tint("Tint %ShowIf(MATCAP_1)", Color) = (1,1,1,1) + [Enum(UTS, 0, Top Pinch, 1, Double Sided, 2)]_Matcap1UVMode("UV Mode %ShowIf(MATCAP_1)", Int) = 2 + _Matcap1Border("Border %ShowIf(MATCAP_1)", Range(0, 1)) = 0.43 + _Matcap1Blur("Matcap Blur Level %ShowIf(MATCAP_1)", Range(0, 1)) = 0 + _Matcap1TintToDiffuse("Tint Matcap to Diffuse %ShowIf(MATCAP_1)", Range(0, 1)) = 0 + [Enum(Additive,0,Multiply,1,Subtract,2)]_Matcap1BlendMode("Blend Mode %ShowIf(MATCAP_1)", Float) = 0 + _Matcap1Strength("Strength %ShowIf(MATCAP_1)", Range(0, 1)) = 1 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_Matcap1MaskChannel("Mask Channel %ShowIf(MATCAP_1)", Int) = 0 + _Matcap1MaskStrength("Mask Strength %ShowIf(MATCAP_1)", Range(0, 1)) = 1 + + UI_Matcap2Header("## Layer 3", Int) = 0 + [Toggle(MATCAP_2)]_Matcap2Enabled("Enable Layer 3", Int) = 0 + _Matcap2Tex("Matcap > %ShowIf(MATCAP_2)", 2D) = "white" {} + _Matcap2Tint("Tint %ShowIf(MATCAP_2)", Color) = (1,1,1,1) + [Enum(UTS, 0, Top Pinch, 1, Double Sided, 2)]_Matcap2UVMode("UV Mode %ShowIf(MATCAP_2)", Int) = 2 + _Matcap2Border("Border %ShowIf(MATCAP_2)", Range(0, 1)) = 0.43 + _Matcap2Blur("Matcap Blur Level %ShowIf(MATCAP_2)", Range(0, 1)) = 0 + _Matcap2TintToDiffuse("Tint Matcap to Diffuse %ShowIf(MATCAP_2)", Range(0, 1)) = 0 + [Enum(Additive,0,Multiply,1,Subtract,2)]_Matcap2BlendMode("Blend Mode %ShowIf(MATCAP_2)", Float) = 0 + _Matcap2Strength("Strength %ShowIf(MATCAP_2)", Range(0, 1)) = 1 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_Matcap2MaskChannel("Mask Channel %ShowIf(MATCAP_2)", Int) = 0 + _Matcap2MaskStrength("Mask Strength %ShowIf(MATCAP_2)", Range(0, 1)) = 1 + + UI_Matcap3Header("## Layer 4", Int) = 0 + [Toggle(MATCAP_3)]_Matcap3Enabled("Enable Layer 4", Int) = 0 + _Matcap3Tex("Matcap > %ShowIf(MATCAP_3)", 2D) = "white" {} + _Matcap3Tint("Tint %ShowIf(MATCAP_3)", Color) = (1,1,1,1) + [Enum(UTS, 0, Top Pinch, 1, Double Sided, 2)]_Matcap3UVMode("UV Mode %ShowIf(MATCAP_3)", Int) = 2 + _Matcap3Border("Border %ShowIf(MATCAP_3)", Range(0, 1)) = 0.43 + _Matcap3Blur("Matcap Blur Level %ShowIf(MATCAP_3)", Range(0, 1)) = 0 + _Matcap3TintToDiffuse("Tint Matcap to Diffuse %ShowIf(MATCAP_3)", Range(0, 1)) = 0 + [Enum(Additive,0,Multiply,1,Subtract,2)]_Matcap3BlendMode("Blend Mode %ShowIf(MATCAP_3)", Float) = 0 + _Matcap3Strength("Strength %ShowIf(MATCAP_3)", Range(0, 1)) = 1 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_Matcap3MaskChannel("Mask Channel %ShowIf(MATCAP_3)", Int) = 0 + _Matcap3MaskStrength("Mask Strength %ShowIf(MATCAP_3)", Range(0, 1)) = 1 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment MATCAPS_MASK_SET + #pragma shader_feature_local_fragment MATCAP_0 + #pragma shader_feature_local_fragment MATCAP_1 + #pragma shader_feature_local_fragment MATCAP_2 + #pragma shader_feature_local_fragment MATCAP_3 +} + +%Variables() +{ + int _MatcapsMaskUVSet; + float4 _MatcapsMask_ST; + + #if defined(MATCAP_0) + half4 _Matcap0Tint; + int _Matcap0UVMode; + half _Matcap0Border; + half _Matcap0Blur; + half _Matcap0TintToDiffuse; + half _Matcap0Strength; + int _Matcap0BlendMode; + int _Matcap0MaskChannel; + half _Matcap0MaskStrength; + #endif + + #if defined(MATCAP_1) + half4 _Matcap1Tint; + int _Matcap1UVMode; + half _Matcap1Border; + half _Matcap1Blur; + half _Matcap1TintToDiffuse; + half _Matcap1Strength; + int _Matcap1BlendMode; + int _Matcap1MaskChannel; + half _Matcap1MaskStrength; + #endif + + #if defined(MATCAP_2) + half4 _Matcap2Tint; + int _Matcap2UVMode; + half _Matcap2Border; + half _Matcap2Blur; + half _Matcap2TintToDiffuse; + half _Matcap2Strength; + int _Matcap2BlendMode; + int _Matcap2MaskChannel; + half _Matcap2MaskStrength; + #endif + + #if defined(MATCAP_3) + half4 _Matcap3Tint; + int _Matcap3UVMode; + half _Matcap3Border; + half _Matcap3Blur; + half _Matcap3TintToDiffuse; + half _Matcap3Strength; + int _Matcap3BlendMode; + int _Matcap3MaskChannel; + half _Matcap3MaskStrength; + #endif +} + +%AdditionalSurfaceData() +{ + #if defined(MATCAP_0) + half3 Matcap0; + half Matcap0BlendMode; + half Matcap0Mask; + #endif + + #if defined(MATCAP_1) + half3 Matcap1; + half Matcap1BlendMode; + half Matcap1Mask; + #endif + + #if defined(MATCAP_2) + half3 Matcap2; + half Matcap2BlendMode; + half Matcap2Mask; + #endif + + #if defined(MATCAP_3) + half3 Matcap3; + half Matcap3BlendMode; + half Matcap3Mask; + #endif +} + +%Textures() +{ + TEXTURE2D(_MatcapsMask); + SAMPLER(sampler_MatcapsMask); + + #if defined(MATCAP_0) + TEXTURE2D(_Matcap0Tex); + #endif + + #if defined(MATCAP_1) + TEXTURE2D(_Matcap1Tex); + #endif + + #if defined(MATCAP_2) + TEXTURE2D(_Matcap2Tex); + #endif + + #if defined(MATCAP_3) + TEXTURE2D(_Matcap3Tex); + #endif + + // Define correct samplers in case some are not defined + // This allows to always reuse the earlier sampler if it was available + #if defined(MATCAP_0) + SAMPLER(sampler_Matcap0Tex); + #define MatcapSampler sampler_Matcap0Tex + #endif + + #if !defined(MATCAP_0) && defined(MATCAP_1) + SAMPLER(sampler_Matcap1Tex); + #define MatcapSampler sampler_Matcap1Tex + #endif + + #if !defined(MATCAP_0) && !defined(MATCAP_1) && defined(MATCAP_2) + SAMPLER(sampler_Matcap2Tex); + #define MatcapSampler sampler_Matcap2Tex + #endif + + #if !defined(MATCAP_0) && !defined(MATCAP_1) && !defined(MATCAP_2) && defined(MATCAP_3) + SAMPLER(sampler_Matcap3Tex); + #define MatcapSampler sampler_Matcap3Tex + #endif +} + +%PassFunctions() +{ + // https://github.com/poiyomi/PoiyomiToonShader + // MIT License + + // Copyright (c) 2023 Poiyomi Inc. + + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + + // The above copyright notice and this permission notice shall be included in all + // copies or substantial portions of the Software. + + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + // SOFTWARE. + float2 GetMatcapUV(int _MatcapUVMode, float3 worldNormal, float3 viewDir, half border) + { + float2 matcapUV = 0; + switch(_MatcapUVMode) + { + // Normal / UTS + case 0: + { + float3 viewNormal = TransformWorldToViewNormal(worldNormal); + float3 normalBasedDirection = viewNormal.xyz * float3(-1, -1, 1); + float3 viewSpaceViewDir = TransformWorldToViewDir(viewDir); + float3 viewBasedDirection = viewSpaceViewDir * float3(-1, -1, 1) + float3(0, 0, 1); + float3 noSknewViewNormal = viewBasedDirection * dot(viewBasedDirection, normalBasedDirection) / viewBasedDirection.b - normalBasedDirection; + + matcapUV = noSknewViewNormal.rg * border + 0.5; + break; + } + + // Top Pinch + case 1: + { + float3 worldViewUp = normalize(float3(0, 1, 0) - viewDir * dot(viewDir, float3(0, 1, 0))); + float3 worldViewRight = normalize(cross(viewDir, worldViewUp)); + matcapUV = float2(dot(worldViewRight, worldNormal), dot(worldViewUp, worldNormal)) * border + 0.5; + break; + } + // Custom Double Sided + case 2: + { + float3 reflection = reflect(-viewDir, worldNormal); + float2 uv = float2(dot(reflection, float3(1, 0, 0)), dot(reflection, float3(0, 1, 0))); + matcapUV = uv * border + 0.5; + break; + } + } + + return matcapUV; + } +} + +%Fragment("ToonMatcapFragment") +{ + void ToonMatcapFragment(MeshData d, inout SurfaceData o) + { + half4 matcapMask = 1; + #if defined(MATCAPS_MASK_SET) + { + float2 matcapMaskUV = 0; + switch (_MatcapsMaskUVSet) { + case 0: matcapMaskUV = d.uv0; break; + case 1: matcapMaskUV = d.uv1; break; + case 2: matcapMaskUV = d.uv2; break; + case 3: matcapMaskUV = d.uv3; break; + } + matcapMaskUV = matcapMaskUV * _MatcapsMask_ST.xy + _MatcapsMask_ST.zw; + matcapMask = SAMPLE_TEXTURE2D(_MatcapsMask, sampler_MatcapsMask, matcapMaskUV); + } + #endif + + float3 worldNormal = Unity_SafeNormalize(mul(o.Normal, d.TBNMatrix)); + #if defined(MATCAP_0) + { + half2 matcapUv = GetMatcapUV(_Matcap0UVMode, worldNormal, d.worldSpaceViewDir, _Matcap0Border); + half3 matcap = SAMPLE_TEXTURE2D_LOD(_Matcap0Tex, MatcapSampler, matcapUv, _Matcap0Blur * UNITY_SPECCUBE_LOD_STEPS).rgb; + matcap *= lerp(1, o.Albedo, _Matcap0TintToDiffuse); + matcap *= _Matcap0Tint; + + o.Matcap0 = matcap; + o.Matcap0BlendMode = _Matcap0BlendMode; + o.Matcap0Mask = lerp(1, matcapMask[_Matcap0MaskChannel], _Matcap0MaskStrength) * _Matcap0Strength; + } + #endif + + #if defined(MATCAP_1) + { + half2 matcapUv = GetMatcapUV(_Matcap1UVMode, worldNormal, d.worldSpaceViewDir, _Matcap1Border); + half3 matcap = SAMPLE_TEXTURE2D_LOD(_Matcap1Tex, MatcapSampler, matcapUv, _Matcap1Blur * UNITY_SPECCUBE_LOD_STEPS).rgb; + matcap *= lerp(1, o.Albedo, _Matcap1TintToDiffuse); + matcap *= _Matcap1Tint; + + o.Matcap1 = matcap; + o.Matcap1BlendMode = _Matcap1BlendMode; + o.Matcap1Mask = lerp(1, matcapMask[_Matcap1MaskChannel], _Matcap1MaskStrength) * _Matcap1Strength; + } + #endif + + #if defined(MATCAP_2) + { + half2 matcapUv = GetMatcapUV(_Matcap2UVMode, worldNormal, d.worldSpaceViewDir, _Matcap2Border); + half3 matcap = SAMPLE_TEXTURE2D_LOD(_Matcap2Tex, MatcapSampler, matcapUv, _Matcap2Blur * UNITY_SPECCUBE_LOD_STEPS).rgb; + matcap *= lerp(1, o.Albedo, _Matcap2TintToDiffuse); + matcap *= _Matcap2Tint; + + o.Matcap2 = matcap; + o.Matcap2BlendMode = _Matcap2BlendMode; + o.Matcap2Mask = lerp(1, matcapMask[_Matcap2MaskChannel], _Matcap2MaskStrength) * _Matcap2Strength; + } + #endif + + #if defined(MATCAP_3) + { + half2 matcapUv = GetMatcapUV(_Matcap3UVMode, worldNormal, d.worldSpaceViewDir, _Matcap3Border); + half3 matcap = SAMPLE_TEXTURE2D_LOD(_Matcap3Tex, MatcapSampler, matcapUv, _Matcap3Blur * UNITY_SPECCUBE_LOD_STEPS).rgb; + matcap *= lerp(1, o.Albedo, _Matcap3TintToDiffuse); + matcap *= _Matcap3Tint; + + o.Matcap3 = matcap; + o.Matcap3BlendMode = _Matcap3BlendMode; + o.Matcap3Mask = lerp(1, matcapMask[_Matcap3MaskChannel], _Matcap3MaskStrength) * _Matcap3Strength; + } + #endif + } +} + +%ModuleFinalColor("ToonMatcapFinalColor") +{ + void ToonMatcapFinalColor(SurfaceData o, MeshData d, half3 lightColor, half lightAttenuation, half3 indirectDiffuse, inout half4 FinalColor) + { + #if defined(MATCAP_0) + { + half3 matcapBlended = o.Matcap0 * (indirectDiffuse + lightColor * lightAttenuation * 0.5); + // Pre-blend based on mastcap blend mode + half3 matcap = lerp(matcapBlended, lerp(o.Matcap0, matcapBlended, saturate(o.Matcap0BlendMode - 1)), o.Matcap0BlendMode); + + // Blend with final color + FinalColor.rgb = lerp( + FinalColor.rgb + lerp(0, matcap, o.Matcap0Mask), + lerp( + FinalColor.rgb * lerp(1, matcap, o.Matcap0Mask), + FinalColor.rgb - lerp(0, matcap, o.Matcap0Mask), + saturate(o.Matcap0BlendMode - 1) + ), + saturate(o.Matcap0BlendMode) + ); + } + #endif + + #if defined(MATCAP_1) + { + half3 matcapBlended = o.Matcap1 * (indirectDiffuse + lightColor * lightAttenuation * 0.5); + // Pre-blend based on mastcap blend mode + half3 matcap = lerp(matcapBlended, lerp(o.Matcap1, matcapBlended, saturate(o.Matcap1BlendMode - 1)), o.Matcap1BlendMode); + + // Blend with final color + FinalColor.rgb = lerp( + FinalColor.rgb + lerp(0, matcap, o.Matcap1Mask), + lerp( + FinalColor.rgb * lerp(1, matcap, o.Matcap1Mask), + FinalColor.rgb - lerp(0, matcap, o.Matcap1Mask), + saturate(o.Matcap1BlendMode - 1) + ), + saturate(o.Matcap1BlendMode) + ); + } + #endif + + #if defined(MATCAP_2) + { + half3 matcapBlended = o.Matcap2 * (indirectDiffuse + lightColor * lightAttenuation * 0.5); + // Pre-blend based on mastcap blend mode + half3 matcap = lerp(matcapBlended, lerp(o.Matcap2, matcapBlended, saturate(o.Matcap2BlendMode - 1)), o.Matcap2BlendMode); + + // Blend with final color + FinalColor.rgb = lerp( + FinalColor.rgb + lerp(0, matcap, o.Matcap2Mask), + lerp( + FinalColor.rgb * lerp(1, matcap, o.Matcap2Mask), + FinalColor.rgb - lerp(0, matcap, o.Matcap2Mask), + saturate(o.Matcap2BlendMode - 1) + ), + saturate(o.Matcap2BlendMode) + ); + } + #endif + + #if defined(MATCAP_3) + { + half3 matcapBlended = o.Matcap3 * (indirectDiffuse + lightColor * lightAttenuation * 0.5); + // Pre-blend based on mastcap blend mode + half3 matcap = lerp(matcapBlended, lerp(o.Matcap3, matcapBlended, saturate(o.Matcap3BlendMode - 1)), o.Matcap3BlendMode); + + // Blend with final color + FinalColor.rgb = lerp( + FinalColor.rgb + lerp(0, matcap, o.Matcap3Mask), + lerp( + FinalColor.rgb * lerp(1, matcap, o.Matcap3Mask), + FinalColor.rgb - lerp(0, matcap, o.Matcap3Mask), + saturate(o.Matcap3BlendMode - 1) + ), + saturate(o.Matcap3BlendMode) + ); + } + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Matcaps.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Matcaps.orlsource.meta new file mode 100644 index 00000000..3e972dc2 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Matcaps.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8648dd891c89b1740b47a1380b9ad432 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Normals.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Normals.orlsource new file mode 100644 index 00000000..df34ba98 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Normals.orlsource @@ -0,0 +1,310 @@ +%Properties() +{ + UI_NormalsHeader("# Normals", Int) = 1 + [Normal]_BumpMap("Normal Map > %SetKeyword(_BumpMap, NORMALS_SET)", 2D) = "bump" {} + [Enum(Synced With Albedo, 0, Independent, 1)]_BumpMapTilingMode("Normal Tiling Mode %ShowIf(_BumpMap)", Int) = 0 + _BumpMapTiling("Normal Tiling %ShowIf(_BumpMap)", Float) = 1 + UI_BumpMapTilingSyncedNote("> Will scale UVs based on the Albedo texture Tiling and Offset settings %ShowIf(_BumpMapTilingMode == 0 && _BumpMap)", Int) = 0 + UI_BumpMapTilingIndependentNote("> Will scale UVs on its own %ShowIf(_BumpMapTilingMode == 1 && _BumpMap)", Int) = 0 + _BumpScale("Normal Map Scale %ShowIf(_BumpMap)", Range(-2, 2)) = 1 + [ToggleUI]_FlipBumpY ("Flip Y (UE Mode) %ShowIf(_BumpMap)", Int) = 0 + [ToggleUI]_NormalBicubicSampling("Use Bicubic Sampling %ShowIf(_BumpMap)", Int) = 0 + + UI_DetailNormalsHeader("# Detail Normals", Int) = 0 + _DetailNormalsMask("Detail Normals Mask %SetKeyword(_DetailNormalsMask, DETAIL_NORMALS_MASK_SET)", 2D) = "white" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_DetailNormalsMaskUVSet("UV Set %ShowIf(DETAIL_NORMALS_MASK_SET)", Int) = 0 + + UI_DetailNormalsLayer1Header("## Layer 1", Int) = 0 + [Toggle(DETAIL_NORMALS_0)]_DetailNormals0Enabled("Enable Layer 1", Int) = 0 + [Normal]_DetailNormals0Map("Detail Normal %ShowIf(DETAIL_NORMALS_0)", 2D) = "bump" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_DetailNormals0UVSet("UV Set %ShowIf(_DetailNormals0Map && DETAIL_NORMALS_0)", Int) = 0 + _DetailNormals0Scale("Detail Normal Map Scale %ShowIf(_DetailNormals0Map && DETAIL_NORMALS_0)", Range(-2, 2)) = 1 + [ToggleUI]_FlipDetailNormals0Y("Flip Y (UE Mode) %ShowIf(_DetailNormals0Map && DETAIL_NORMALS_0)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_DetailNormals0MaskChannel("Mask Channel %ShowIf(DETAIL_NORMALS_0)", Int) = 0 + _DetailNormals0MaskStrength("Mask Strength %ShowIf(DETAIL_NORMALS_0)", Range(0, 1)) = 1 + + UI_DetailNormalsLayer2Header("## Layer 2", Int) = 0 + [Toggle(DETAIL_NORMALS_1)]_DetailNormals1Enabled("Enable Layer 2", Int) = 0 + [Normal]_DetailNormals1Map("Detail Normal %ShowIf(DETAIL_NORMALS_1)", 2D) = "bump" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_DetailNormals1UVSet("UV Set %ShowIf(_DetailNormals1Map && DETAIL_NORMALS_1)", Int) = 0 + _DetailNormals1Scale("Detail Normal Map Scale %ShowIf(_DetailNormals1Map && DETAIL_NORMALS_1)", Range(-2, 2)) = 1 + [ToggleUI]_FlipDetailNormals1Y("Flip Y (UE Mode) %ShowIf(_DetailNormals1Map && DETAIL_NORMALS_1)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_DetailNormals1MaskChannel("Mask Channel %ShowIf(DETAIL_NORMALS_1)", Int) = 0 + _DetailNormals1MaskStrength("Mask Strength %ShowIf(DETAIL_NORMALS_1)", Range(0, 1)) = 1 + + UI_DetailNormalsLayer3Header("## Layer 3", Int) = 0 + [Toggle(DETAIL_NORMALS_2)]_DetailNormals2Enabled("Enable Layer 3", Int) = 0 + [Normal]_DetailNormals2Map("Detail Normal %ShowIf(DETAIL_NORMALS_2)", 2D) = "bump" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_DetailNormals2UVSet("UV Set %ShowIf(_DetailNormals2Map && DETAIL_NORMALS_2)", Int) = 0 + _DetailNormals2Scale("Detail Normal Map Scale %ShowIf(_DetailNormals2Map && DETAIL_NORMALS_2)", Range(-2, 2)) = 1 + [ToggleUI]_FlipDetailNormals2Y("Flip Y (UE Mode) %ShowIf(_DetailNormals2Map && DETAIL_NORMALS_2)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_DetailNormals2MaskChannel("Mask Channel %ShowIf(DETAIL_NORMALS_2)", Int) = 0 + _DetailNormals2MaskStrength("Mask Strength %ShowIf(DETAIL_NORMALS_2)", Range(0, 1)) = 1 + + UI_DetailNormalsLayer4Header("## Layer 4", Int) = 0 + [Toggle(DETAIL_NORMALS_3)]_DetailNormals3Enabled("Enable Layer 4", Int) = 0 + [Normal]_DetailNormals3Map("Detail Normal %ShowIf(DETAIL_NORMALS_3)", 2D) = "bump" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_DetailNormals3UVSet("UV Set %ShowIf(_DetailNormals3Map && DETAIL_NORMALS_3)", Int) = 0 + _DetailNormals3Scale("Detail Normal Map Scale %ShowIf(_DetailNormals3Map && DETAIL_NORMALS_3)", Range(-2, 2)) = 1 + [ToggleUI]_FlipDetailNormals3Y("Flip Y (UE Mode) %ShowIf(_DetailNormals3Map && DETAIL_NORMALS_3)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_DetailNormals3MaskChannel("Mask Channel %ShowIf(DETAIL_NORMALS_3)", Int) = 0 + _DetailNormals3MaskStrength("Mask Strength %ShowIf(DETAIL_NORMALS_3)", Range(0, 1)) = 1 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment NORMALS_SET + #pragma shader_feature_local_fragment DETAIL_NORMALS_MASK_SET + #pragma shader_feature_local_fragment DETAIL_NORMALS_0 + #pragma shader_feature_local_fragment DETAIL_NORMALS_1 + #pragma shader_feature_local_fragment DETAIL_NORMALS_2 + #pragma shader_feature_local_fragment DETAIL_NORMALS_3 +} + +%Variables() +{ + #if defined(NORMALS_SET) + int _BumpMapTilingMode; + float _BumpMapTiling; + half _BumpScale; + int _FlipBumpY; + int _NormalBicubicSampling; + #endif + + #if defined(DETAIL_NORMALS_MASK_SET) + float4 _DetailNormalsMask_ST; + int _DetailNormalsMaskUVSet; + #endif + + + #if defined(DETAIL_NORMALS_0) + int _DetailNormals0UVSet; + float4 _DetailNormals0Map_ST; + half _DetailNormals0Scale; + half _FlipDetailNormals0Y; + int _DetailNormals0MaskChannel; + half _DetailNormals0MaskStrength; + #endif + + #if defined(DETAIL_NORMALS_1) + int _DetailNormals1UVSet; + float4 _DetailNormals1Map_ST; + half _DetailNormals1Scale; + half _FlipDetailNormals1Y; + int _DetailNormals1MaskChannel; + half _DetailNormals1MaskStrength; + #endif + + #if defined(DETAIL_NORMALS_2) + int _DetailNormals2UVSet; + float4 _DetailNormals2Map_ST; + half _DetailNormals2Scale; + half _FlipDetailNormals2Y; + int _DetailNormals2MaskChannel; + half _DetailNormals2MaskStrength; + #endif + + #if defined(DETAIL_NORMALS_3) + int _DetailNormals3UVSet; + float4 _DetailNormals3Map_ST; + half _DetailNormals3Scale; + half _FlipDetailNormals3Y; + int _DetailNormals3MaskChannel; + half _DetailNormals3MaskStrength; + #endif +} + +%Textures() +{ + #if defined(NORMALS_SET) + TEXTURE2D(_BumpMap); + SAMPLER(sampler_BumpMap); + #endif + + #if defined(DETAIL_NORMALS_MASK_SET) + TEXTURE2D(_DetailNormalsMask); + SAMPLER(sampler_DetailNormalsMask); + #endif + + #if defined(DETAIL_NORMALS_0) + TEXTURE2D(_DetailNormals0Map); + #endif + + #if defined(DETAIL_NORMALS_1) + TEXTURE2D(_DetailNormals1Map); + #endif + + #if defined(DETAIL_NORMALS_2) + TEXTURE2D(_DetailNormals2Map); + #endif + + #if defined(DETAIL_NORMALS_3) + TEXTURE2D(_DetailNormals3Map); + #endif + + // Define correct samplers in case some are not defined + // This allows to always reuse the earlier sampler if it was available + #if defined(DETAIL_NORMALS_0) + SAMPLER(sampler_DetailNormals0Map); + #define DetailsLayerSampler sampler_DetailNormals0Map + #endif + + #if !defined(DETAIL_NORMALS_0) && defined(DETAIL_NORMALS_1) + SAMPLER(sampler_DetailNormals1Map); + #define DetailsLayerSampler sampler_DetailNormals1Map + #endif + + #if !defined(DETAIL_NORMALS_0) && !defined(DETAIL_NORMALS_1) && defined(DETAIL_NORMALS_2) + SAMPLER(sampler_DetailNormals2Map); + #define DetailsLayerSampler sampler_DetailNormals2Map + #endif + + #if !defined(DETAIL_NORMALS_0) && !defined(DETAIL_NORMALS_1) && !defined(DETAIL_NORMALS_2) && defined(DETAIL_NORMALS_3) + SAMPLER(sampler_DetailNormals3Map); + #define DetailsLayerSampler sampler_DetailNormals3Map + #endif +} + + +%Fragment("ToonNormalsFragment") +{ + void ToonNormalsFragment(inout MeshData d, inout SurfaceData o) { + float2 globalUv = 0; + + #if defined(GLOBAL_UV_SET) + globalUv = GLOBAL_uv; + #else + globalUv = d.uv0; + #endif + + // Main normal map, bicubic support, expected non-tiling + #if defined(NORMALS_SET) + { + float4 normalTex = 0; + if (_NormalBicubicSampling) { + normalTex = tex2DFastBicubicSampleNoChecks(_BumpMap, sampler_BumpMap, lerp(globalUv, d.uv0.xy, _BumpMapTilingMode) * _BumpMapTiling); + } else { + normalTex = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, lerp(globalUv, d.uv0.xy, _BumpMapTilingMode) * _BumpMapTiling); + } + if (_FlipBumpY) + { + normalTex.y = 1 - normalTex.y; + } + half3 normal = UnpackNormalScale(normalTex, _BumpScale); + + o.Normal = BlendNormals(o.Normal, normal); + } + #endif + + // Detail normals, tiling expected, RGBA masking + half4 detailMask = 1; + #if defined(DETAIL_NORMALS_MASK_SET) + { + float2 detailMaskUV = 0; + switch (_DetailNormalsMaskUVSet) { + case 0: detailMaskUV = d.uv0; break; + case 1: detailMaskUV = d.uv1; break; + case 2: detailMaskUV = d.uv2; break; + case 3: detailMaskUV = d.uv3; break; + } + detailMaskUV = detailMaskUV * _DetailNormalsMask_ST.xy + _DetailNormalsMask_ST.zw; + detailMask = SAMPLE_TEXTURE2D(_DetailNormalsMask, sampler_DetailNormalsMask, detailMaskUV); + } + #endif + + // Details Layer 1 + #if defined(DETAIL_NORMALS_0) + { + float2 detailUV = 0; + switch (_DetailNormals0UVSet) { + case 0: detailUV = d.uv0; break; + case 1: detailUV = d.uv1; break; + case 2: detailUV = d.uv2; break; + case 3: detailUV = d.uv3; break; + } + detailUV = detailUV * _DetailNormals0Map_ST.xy + _DetailNormals0Map_ST.zw; + half4 detailNormalsTex = SAMPLE_TEXTURE2D(_DetailNormals0Map, DetailsLayerSampler, detailUV); + if (_FlipDetailNormals0Y) + { + detailNormalsTex.y = 1 - detailNormalsTex.y; + } + half3 detailNormal = UnpackNormalScale(detailNormalsTex, _DetailNormals0Scale); + o.Normal = lerp(o.Normal, BlendNormals(o.Normal, detailNormal), lerp(1, detailMask[_DetailNormals0MaskChannel], _DetailNormals0MaskStrength)); + } + #endif + + #if defined(DETAIL_NORMALS_1) + { + float2 detailUV = 0; + switch (_DetailNormals1UVSet) { + case 0: detailUV = d.uv0; break; + case 1: detailUV = d.uv1; break; + case 2: detailUV = d.uv2; break; + case 3: detailUV = d.uv3; break; + } + detailUV = detailUV * _DetailNormals1Map_ST.xy + _DetailNormals1Map_ST.zw; + half4 detailNormalsTex = SAMPLE_TEXTURE2D(_DetailNormals1Map, DetailsLayerSampler, detailUV); + if (_FlipDetailNormals1Y) + { + detailNormalsTex.y = 1 - detailNormalsTex.y; + } + half3 detailNormal = UnpackNormalScale(detailNormalsTex, _DetailNormals1Scale); + o.Normal = lerp(o.Normal, BlendNormals(o.Normal, detailNormal), lerp(1, detailMask[_DetailNormals1MaskChannel], _DetailNormals1MaskStrength)); + } + #endif + + #if defined(DETAIL_NORMALS_2) + { + float2 detailUV = 0; + switch (_DetailNormals2UVSet) { + case 0: detailUV = d.uv0; break; + case 1: detailUV = d.uv1; break; + case 2: detailUV = d.uv2; break; + case 3: detailUV = d.uv3; break; + } + detailUV = detailUV * _DetailNormals2Map_ST.xy + _DetailNormals2Map_ST.zw; + half4 detailNormalsTex = SAMPLE_TEXTURE2D(_DetailNormals2Map, DetailsLayerSampler, detailUV); + if (_FlipDetailNormals2Y) + { + detailNormalsTex.y = 1 - detailNormalsTex.y; + } + half3 detailNormal = UnpackNormalScale(detailNormalsTex, _DetailNormals2Scale); + o.Normal = lerp(o.Normal, BlendNormals(o.Normal, detailNormal), lerp(1, detailMask[_DetailNormals2MaskChannel], _DetailNormals2MaskStrength)); + } + #endif + + #if defined(DETAIL_NORMALS_3) + { + float2 detailUV = 0; + switch (_DetailNormals3UVSet) { + case 0: detailUV = d.uv0; break; + case 1: detailUV = d.uv1; break; + case 2: detailUV = d.uv2; break; + case 3: detailUV = d.uv3; break; + } + detailUV = detailUV * _DetailNormals3Map_ST.xy + _DetailNormals3Map_ST.zw; + half4 detailNormalsTex = SAMPLE_TEXTURE2D(_DetailNormals3Map, DetailsLayerSampler, detailUV); + if (_FlipDetailNormals3Y) + { + detailNormalsTex.y = 1 - detailNormalsTex.y; + } + half3 detailNormal = UnpackNormalScale(detailNormalsTex, _DetailNormals3Scale); + o.Normal = lerp(o.Normal, BlendNormals(o.Normal, detailNormal), lerp(1, detailMask[_DetailNormals3MaskChannel], _DetailNormals3MaskStrength)); + } + #endif + + // #if defined(NORMALS_SET) || defined(DETAIL_NORMALS_SET) + + // // half3 properNormal = normalize(mul(o.Normal, d.TBNMatrix)); + // // d.worldSpaceTangent.xyz = cross(d.bitangent.xyz, properNormal); + // // d.bitangent.xyz = cross(properNormal, d.worldSpaceTangent.xyz); + // // d.TBNMatrix = float3x3(normalize(d.worldSpaceTangent.xyz), d.bitangent, d.worldNormal); + // // GLOBAL_pixelNormal = properNormal; + + // #else + + // // GLOBAL_pixelNormal = normalize(mul(o.Normal, d.TBNMatrix)); + + // #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Normals.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Normals.orlsource.meta new file mode 100644 index 00000000..b436bc5e --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Normals.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 23b6f22bb6c8d8548bcab89a071d6c0c +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Occlusion.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Occlusion.orlsource new file mode 100644 index 00000000..6ccc235f --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Occlusion.orlsource @@ -0,0 +1,154 @@ +%Properties() +{ + UI_OcclusionHeader("# Occlusion", Int) = 1 + _OcclusionMap("Occlusion >", 2D) = "white" {} + _OcclusionStrength("Occlusion Strength %ShowIf(_OcclusionMap)", Range(0,1)) = 0 + [Enum(Synced With Albedo, 0, Independent, 1)]_OcclusionTilingMode("Tiling Mode %ShowIf(_OcclusionMap)", Int) = 0 + _OcclusionTiling("Tiling %ShowIf(_OcclusionMap)", Float) = 1 + UI_OcclusionTilingSyncedNote("> Will scale UVs based on the Albedo texture Tiling and Offset settings %ShowIf(_OcclusionTilingMode == 0 && _OcclusionMap)", Int) = 0 + UI_OcclusionTilingIndependentNote("> Will scale UVs on its own %ShowIf(_OcclusionTilingMode == 1 && _OcclusionMap)", Int) = 0 + + [ToggleUI]_OcclusionDetailEnabled("Occlusion Detail Enabled", Int) = 0 + _OcclusionDetail("Occlusion Detail > %ShowIf(_OcclusionDetailEnabled)", 2D) = "white" {} + _OcclusionDetailStrength("Occlusion Detail Strength %ShowIf(_OcclusionDetail && _OcclusionDetailEnabled)", Range(0,1)) = 1 + [Enum(Synced With Albedo, 0, Independent, 1)]_OcclusionDetailTilingMode("Tiling Mode %ShowIf(_OcclusionDetail)", Int) = 0 + _OcclusionDetailTiling("Tiling %ShowIf(_OcclusionDetail)", Float) = 1 + UI_OcclusionDetailTilingSyncedNote("> Will scale UVs based on the Albedo texture Tiling and Offset settings %ShowIf(_OcclusionDetailTilingMode == 0 && _OcclusionDetail)", Int) = 0 + UI_OcclusionDetailTilingIndependentNote("> Will scale UVs on its own %ShowIf(_OcclusionDetailTilingMode == 1 && _OcclusionDetail)", Int) = 0 + + // [Toggle(SSAO)]_SSAOEnabled("Screen Space Occlusion", Int) = 0 + // _SSAONoiseTexture("Noise Texture > %RequiredTexture(@/SSRNoise.png) %ShowIf(SSAO)", 2D) = "black" {} + // _SSAORadius("Radius %ShowIf(SSAO)", Float) = 5 + // _SSAOPower("Power %ShowIf(SSAO)", Float) = 3 + // _SSAOBoost("Boost %ShowIf(SSAO)", Float) = 1 + // _SSAOStrength("Strength %ShowIf(SSAO)", Range(0,1)) = 1 +} + +%ShaderFeatures() +{ + // #pragma shader_feature_local_fragment SSAO +} + +%Variables() +{ + half _OcclusionStrength; + int _OcclusionTilingMode; + half _OcclusionTiling; + + int _OcclusionDetailEnabled; + half _OcclusionDetailStrength; + int _OcclusionDetailTilingMode; + half _OcclusionDetailTiling; + + float4 _SSAONoiseTexture_TexelSize; + half _SSAORadius; + half _SSAOPower; + half _SSAOBoost; + half _SSAOStrength; +} + +%Textures() +{ + TEXTURE2D(_OcclusionMap); + TEXTURE2D(_OcclusionDetail); + + #if defined(SSAO) + TEXTURE2D(_SSAONoiseTexture); + SAMPLER(sampler_SSAONoiseTexture); + #endif +} + +%Fragment("ToonOcclusionFragment") +{ + float chash11(float p) + { + p = frac(p * .1031); + p *= p + 33.33; + p *= p + p; + return frac(p); + } + + float3 chash31(float p) + { + float3 p3 = frac(p * float3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yzx+33.33); + return frac((p3.xxy+p3.yzz)*p3.zyx); + } + + void ToonOcclusionFragment(MeshData d, inout SurfaceData o) { + half2 globalUv = 0; + + #if defined(GLOBAL_UV_SET) + globalUv = GLOBAL_uv; + #else + globalUv = d.uv0; + #endif + + half occlusion = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_MainTex, lerp(globalUv * _OcclusionTiling, d.uv0 * _OcclusionTiling, _OcclusionTilingMode)).r; + o.Occlusion = lerp(1, occlusion, _OcclusionStrength); + + if (_OcclusionDetailEnabled) { + half occlusionDetail = SAMPLE_TEXTURE2D(_OcclusionDetail, sampler_MainTex, lerp(globalUv * _OcclusionDetailTiling, d.uv0 * _OcclusionDetailTiling, _OcclusionDetailTilingMode)).r; + o.Occlusion *= lerp(1, occlusionDetail, _OcclusionDetailStrength); + } + + #if defined(SSAO) + // float3 startingPoint = d.worldSpacePosition.xyz; + // float3 worldNormal = Unity_SafeNormalize(mul(o.Normal, d.TBNMatrix)); + // // float3 dir = worldNormal; + + // float radius = _SSAORadius / 100.0; + // float3 samplePoint = 0; + + // half ssao = 0; + + // const int kernelSize = 16; + + // float3 ssaoKernel[kernelSize]; + // float4 noiseUvs = d.screenPos; + // noiseUvs.xy = (noiseUvs.xy * _ScreenParams.xy) / (_SSAONoiseTexture_TexelSize.zw * noiseUvs.w); + + // float3 noise = SAMPLE_TEXTURE2D_LOD(_SSAONoiseTexture, sampler_SSAONoiseTexture, noiseUvs.xy,0).xyz; + // noise.x = noise.x * 2 - 1; + // noise.y = noise.y * 2 - 1; + + // // kernel + // [loop] + // for (int i = 0; i < kernelSize; i++) + // { + // // ssaoKernel[i] = chash31(chash11(i)); + // // ssaoKernel[i].x = ssaoKernel[i].x * 2 - 1; + // // ssaoKernel[i].y = ssaoKernel[i].y * 2 - 1; + // ssaoKernel[i] = noise.xyz; + // float scale = (float) i / (float) kernelSize; + // float scaleMultiplier = lerp(0.1,1.0, scale * scale); + // ssaoKernel[i] *= scaleMultiplier; + // ssaoKernel[i] = mul(ssaoKernel[i], d.TBNMatrix); + // } + // // float3 randomDir = float3(noise.xy, 0); + // // float3 randomTangent = normalize(randomDir - dot(randomDir, worldNormal) * worldNormal); + // // float3 randomBitangent = cross(worldNormal, randomTangent); + // // float3x3 TBN = float3x3(randomTangent, randomBitangent, worldNormal); + + // // startingPoint += worldNormal * 0.01; + + // [loop] + // for (int j = 0; j < kernelSize; j++) { + // // samplePoint = startingPoint + mul(ssaoKernel[j], TBN) * radius; + // samplePoint = startingPoint + ssaoKernel[j] * radius; + // // float samplePointZ = LinearEyeDepth(SampleSceneDepth(d.screenPos.xy / d.screenPos.w)); + // float samplePointZ = d.screenPos.z; + // float3 sampleDir = normalize(samplePoint - startingPoint); + // float NoS = saturate(dot(worldNormal, sampleDir)); + // float4 offset = GetScreenPosition(TransformWorldToHClip(samplePoint)); + // offset.xy /= offset.w; + // float sceneDepth = LinearEyeDepth(SampleSceneDepth(offset.xy)); + // float rangeCheck = saturate(radius / abs(samplePointZ - sceneDepth)); + // ssao += rangeCheck * step(sceneDepth + 0.005, samplePointZ) * NoS; + // } + // ssao = (ssao / (float) kernelSize); + // ssao = pow(saturate(1 - saturate(ssao * _SSAOBoost)), _SSAOPower); + // o.Occlusion *= lerp(1, ssao, _SSAOStrength); + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Occlusion.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Occlusion.orlsource.meta new file mode 100644 index 00000000..7fa45fa3 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Occlusion.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 145cc2e14d3d40746be8612e553096c3 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Outline.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Outline.orlsource new file mode 100644 index 00000000..3e037597 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Outline.orlsource @@ -0,0 +1,97 @@ +%Properties() +{ + UI_OutlineHeader("# Outline", Int) = 0 + [Toggle(OUTLINE_ENABLED)]_Outline("Enable Outline %SetProp((!_OutlineIgnoreStencils && OUTLINE_ENABLED), _StencilBasePass, 2, 0)", Int) = 0 + _OutlineTex("Texture > %ShowIf(OUTLINE_ENABLED)", 2D) = "white" {} + [HDR]_OutlineColor("Color %ShowIf(OUTLINE_ENABLED)", Color) = (0.5, 0.5, 0.5, 1) + [Enum(Lit, 0, Emissive, 1)]_OutlineLightingMode("Lighting Mode %ShowIf(OUTLINE_ENABLED)", Int) = 0 + _OutlineAlbedoTint("Albedo Tint %ShowIf(OUTLINE_ENABLED)", Range(0, 1)) = 0 + [Tooltip(Uses the Red channel)]_OutlineMask("Width Mask > %ShowIf(OUTLINE_ENABLED)", 2D) = "white" {} + [PowerSlider(3.0)]_OutlineWidth("Width %ShowIf(OUTLINE_ENABLED)", Range(0, 10)) = 1 + [ToggleUI]_OutlineWidthAdjustByVertexColor("Adjust by Vertex Color", Int) = 0 + [HideInInspector]_StencilBasePass("Stencil Base Pass", Float) = 0 + [ToggleUI]_OutlineIgnoreStencils("Ignore Stencils %SetProp((_OutlineIgnoreStencils), _StencilOutlineComp, 8, 6) %ShowIf(OUTLINE_ENABLED)", Int) = 0 + UI_OutlineIgnoreStencilsNote("> Allows overlapping shapes to show outlines on top of each other. Does not work correctly with transparent materials", Int) = 0 + [HideInInspector]_StencilOutlineComp("Stencil Outline Comp", Float) = 6 + [HideInInspector]_StencilBaseComp("Stencil Base Comp", Float) = 8 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local OUTLINE_ENABLED +} + +%Variables() +{ + #if defined(OUTLINE_ENABLED) && defined(PASS_OUTLINE) + int _StencilBasePass; + int _StencilBaseComp; + int _StencilOutlineComp; + + half4 _OutlineColor; + int _OutlineLightingMode; + half _OutlineAlbedoTint; + half _OutlineWidth; + int _OutlineWidthAdjustByVertexColor; + #endif +} + +%AdditionalSurfaceData() +{ + #if defined(OUTLINE_ENABLED) && defined(PASS_OUTLINE) + half3 OutlineColor; + half OutlineAlbedoTint; + int OutlineLightingMode; + #endif +} + +%Textures() +{ + #if defined(OUTLINE_ENABLED) && defined(PASS_OUTLINE) + TEXTURE2D(_OutlineTex); + TEXTURE2D(_OutlineMask); + SAMPLER(sampler_OutlineTex); + SAMPLER(sampler_OutlineMask); + #endif +} + +%Vertex("ToonOutlineVertex") +{ + void ToonOutlineVertex(inout VertexData v) + { + #if defined(OUTLINE_ENABLED) && defined(PASS_OUTLINE) + half mask = SAMPLE_TEXTURE2D_LOD(_OutlineMask, sampler_OutlineMask, v.uv0, 0); + half3 width = mask * _OutlineWidth * .01; + width *= min(distance(TransformObjectToWorld(v.vertex.xyz), _WorldSpaceCameraPos) * 3, 1); + v.vertex.xyz += v.normal.xyz * lerp(width, width * v.color.r, _OutlineWidthAdjustByVertexColor); + #endif + } +} + +%Fragment("ToonOutlineFragment") +{ + void ToonOutlineFragment(MeshData d, inout SurfaceData o) + { + #if defined(OUTLINE_ENABLED) && defined(PASS_OUTLINE) + half3 outline = SAMPLE_TEXTURE2D(_OutlineTex, sampler_OutlineTex, d.uv0).rgb; + o.OutlineColor = _OutlineColor * outline; + o.OutlineLightingMode = _OutlineLightingMode; + #endif + } +} + +%ModuleFinalColor("ToonOutlineFinalColor") +{ + void ToonOutlineFinalColor(SurfaceData o, MeshData d, half lightAttenuation, half lightNoL, half3 lightColor, half3 indirectDiffuse, inout half4 FinalColor) + { + #if defined(OUTLINE_ENABLED) && defined(PASS_OUTLINE) + half3 outlineColor = 0; + half3 ol = o.OutlineColor; + ol = lerp(ol.rgb, ol.rgb * o.Albedo, o.OutlineAlbedoTint); + outlineColor = ol * saturate(lightAttenuation * lightNoL) * lightColor.rgb; + outlineColor += indirectDiffuse * ol; + outlineColor = lerp(outlineColor, ol, o.OutlineLightingMode); + FinalColor.rgb = outlineColor; + #endif + } +} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Outline.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Outline.orlsource.meta new file mode 100644 index 00000000..d6377712 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Outline.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3d74b453b85f659409b69a481c7a9db8 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Reflections.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Reflections.orlsource new file mode 100644 index 00000000..f69f4673 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Reflections.orlsource @@ -0,0 +1,195 @@ +%Properties() +{ + UI_ReflectionsHeader("# Reflections", Int) = 0 + [Toggle(REFLECTIONS_ON)]_ReflectionsOn("Enable Reflections", Int) = 0 + + _MetallicGlossMap("Metallic Smoothness %ShowIf(REFLECTIONS_ON)", 2D) = "white" {} + UI_MetallicNote("> R - Metallic, A - Smoothness %ShowIf(REFLECTIONS_ON)", Int) = 0 + _Smoothness ("Smoothness %ShowIf(!_MetallicGlossMap && (REFLECTIONS_ON))", Range(0, 1)) = 0.5 + [ToggleUI]_RoughnessMode ("Roughness Mode %ShowIf(_MetallicGlossMap && (REFLECTIONS_ON))", Int) = 0 + _Metallic ("Metallic %ShowIf(!_MetallicGlossMap && (REFLECTIONS_ON))", Range(0, 1)) = 0 + _MetallicRemap("Metallic Remap %ShowIf(_MetallicGlossMap && (REFLECTIONS_ON)) %RemapSlider(0,1)", Vector) = (0, 1, 0, 1) + _SmoothnessRemap("Smoothness Remap %ShowIf(_MetallicGlossMap && (REFLECTIONS_ON)) %RemapSlider(0,1)", Vector) = (0, 1, 0, 1) + _ReflectionAnisotropy("Anisotropy %ShowIf(REFLECTIONS_ON)", Range(-1, 1)) = 0 + _ReflectivityLevel("Reflectivity %ShowIf(REFLECTIONS_ON)", Range(0, 1)) = 0.5 + + UI_ReflectionMaskingHeader("## Masking %ShowIf(REFLECTIONS_ON)", Int) = 0 + _ReflectionMask("Reflection Mask %ShowIf(REFLECTIONS_ON)", 2D) = "white" {} + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_ReflectionMaskUVSet("UV Set %ShowIf(_ReflectionMask && REFLECTIONS_ON)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_ReflectionMaskChannel("Mask Channel %ShowIf(_ReflectionMask && REFLECTIONS_ON)", Int) = 0 + _ReflectionMaskStrength("Mask Strength %ShowIf(_ReflectionMask && REFLECTIONS_ON)", Range(0, 1)) = 1 + _ReflectionStrength("Reflection Strength %ShowIf(REFLECTIONS_ON)", Range(0, 1)) = 1 + + UI_ReflectionTweaksHeader("## Tweaks %ShowIf(REFLECTIONS_ON)", Int) = 0 + _ReflectionOcclusion("Reflection Occlusion %ShowIf(REFLECTIONS_ON)", Range(0, 1)) = 0.25 + _ReflectionRealtimeShadowOcclusion("Realtime Shadow Reflection Occlusion %ShowIf(REFLECTIONS_ON)", Range(0, 1)) = 0 + UI_ReflectionOcclusionNote("> This effect is not physically accurate, it can be useful to tone down strong reflection probes in shadowed areas %ShowIf(_ReflectionRealtimeShadowOcclusion > 0 && REFLECTIONS_ON)", Int) = 0 + _ReflectionGSAAVariance("GSAA Variance %ShowIf(GSAA)", Range(0, 1)) = 0.05 + _ReflectionGSAAThreshold("GSAA Threshold %ShowIf(GSAA)", Range(0, 1)) = 0.1 + + _BakedCubemap("Fallback Cubemap > %ShowIf(REFLECTIONS_ON)", CUBE) = "black" {} + UI_FallbackNote("> Will be used if world has no reflections %ShowIf(REFLECTIONS_ON)", Int) = 0 + [NonModifiableTextureData]_DFG("DFG > %RequiredTexture(@/dfg-multiscatter.exr) %ShowIf(REFLECTIONS_ON)", 2D) = "white" {} +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment REFLECTIONS_ON +} + +%Variables() +{ + #if defined(REFLECTIONS_ON) + float4 _MetallicGlossMap_ST; + half _Smoothness; + int _RoughnessMode; + half _Metallic; + half4 _MetallicRemap; + half4 _SmoothnessRemap; + half4 _MetallicGlossMap_TexelSize; + half _ReflectionAnisotropy; + half _ReflectivityLevel; + + float4 _ReflectionMask_ST; + int _ReflectionMaskUVSet; + int _ReflectionMaskChannel; + half _ReflectionMaskStrength; + half _ReflectionStrength; + + half _ReflectionOcclusion; + half _ReflectionRealtimeShadowOcclusion; + half _ReflectionGSAAVariance; + half _ReflectionGSAAThreshold; + + half4 _BakedCubemap_TexelSize; + #endif +} + +%Textures() +{ + #if defined(REFLECTIONS_ON) + TEXTURE2D(_MetallicGlossMap); + TEXTURE2D(_ReflectionMask); + + TEXTURECUBE(_BakedCubemap); + SAMPLER(sampler_BakedCubemap); + + TEXTURE2D(_DFG); + SAMPLER(sampler_DFG); + #endif +} + +%AdditionalSurfaceData() +{ + #if defined(REFLECTIONS_ON) + half ReflectionMetallic; + half ReflectionSmoothness; + half ReflectivityLevel; + half ReflectionAnisotropy; + half ReflectionStrength; + #endif +} + +%ShaderDefines() +{ + #define ORL_MIN_ROUGHNESS 0.002025 + #if defined(PLAT_QUEST) + #define ORL_MIN_ROUGHNESS 0.007921 + #endif +} + +%Fragment("ToonReflectionFragment") +{ + void ToonReflectionFragment(MeshData d, inout SurfaceData o) { + #if defined(REFLECTIONS_ON) + + float2 reflectionMaskUv = 0; + switch (_MatcapsMaskUVSet) { + case 0: reflectionMaskUv = d.uv0; break; + case 1: reflectionMaskUv = d.uv1; break; + case 2: reflectionMaskUv = d.uv2; break; + case 3: reflectionMaskUv = d.uv3; break; + } + reflectionMaskUv = reflectionMaskUv * _ReflectionMask_ST.xy + _ReflectionMask_ST.zw; + half mask = SAMPLE_TEXTURE2D(_ReflectionMask, sampler_MainTex, reflectionMaskUv)[_ReflectionMaskChannel]; + mask = _ReflectionStrength * lerp(1, mask, _ReflectionMaskStrength); + + half4 metalSmooth = SAMPLE_TEXTURE2D(_MetallicGlossMap, sampler_MainTex, d.uv0.xy * _MetallicGlossMap_ST.xy + _MetallicGlossMap_ST.zw); + int hasMetallicSmooth = _MetallicGlossMap_TexelSize.z > 8; + half metal = metalSmooth.r; + half smooth = metalSmooth.a; + + if (_RoughnessMode) + { + smooth = 1 - smooth; + } + + metal = remap(metal, 0, 1, _MetallicRemap.x, _MetallicRemap.y); + smooth = remap(smooth, 0, 1, _SmoothnessRemap.x, _SmoothnessRemap.y); + o.ReflectionMetallic = lerp(_Metallic, metal, hasMetallicSmooth); + o.ReflectionSmoothness = lerp(_Smoothness, smooth, hasMetallicSmooth); + o.ReflectionAnisotropy = _ReflectionAnisotropy; + + o.ReflectionStrength = mask; + o.ReflectivityLevel = _ReflectivityLevel; + #endif + } +} + +%ModuleLighting("ToonReflectionLighting") +{ + void ToonReflectionLighting(SurfaceData o, MeshData d, half lightAttenuation, float3 lightHalfVector, half NoV, half3 indirectDiffuse, inout half3 indirectSpecular) + { + #if defined(REFLECTIONS_ON) && defined(UNITY_PASS_FORWARDBASE) + half oneMinusReflectivity = 1.0 - 0.04 - o.ReflectionMetallic * (1.0 - 0.04); + half3 f0 = 0.16 * o.ReflectivityLevel * o.ReflectivityLevel * oneMinusReflectivity + o.Albedo * o.ReflectionMetallic; + + half perceptualRoughness = 1 - o.ReflectionSmoothness; + perceptualRoughness = GSAA_Filament(d.worldNormal, perceptualRoughness, _ReflectionGSAAVariance, _ReflectionGSAAThreshold); + + float3 dfguv = float3(NoV, perceptualRoughness, 0); + float2 dfg = SAMPLE_TEXTURE2D(_DFG, sampler_DFG, dfguv).xy; + half3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0); + + half clampedRoughness = max(perceptualRoughness * perceptualRoughness, ORL_MIN_ROUGHNESS); + + float3 reflDir = 0; + half anisotropyAbs = abs(o.ReflectionAnisotropy); + if (anisotropyAbs > 0.0001) + { + float3 anisotropicDirection = o.ReflectionAnisotropy >= 0.0 ? d.bitangent : d.worldSpaceTangent.xyz; + float3 anisotropicTangent = cross(anisotropicDirection, d.worldSpaceViewDir); + float3 anisotropicNormal = cross(anisotropicTangent, anisotropicDirection); + float bendFactor = anisotropyAbs * saturate(5.0 * perceptualRoughness); + float3 bentNormal = normalize(lerp(o.WorldNormal, anisotropicNormal, bendFactor)); + reflDir = reflect(-d.worldSpaceViewDir, bentNormal); + } else { + reflDir = reflect(-d.worldSpaceViewDir, o.WorldNormal); + } + + half4 rawProbe0; + half3 reflection = getEnvReflectionDirect(reflDir, d.worldSpacePosition, o.WorldNormal, perceptualRoughness, -1, rawProbe0); + + // If reflection doesn't exist - fall back to a cubemap + if (unity_SpecCube0_HDR.a == 0 && rawProbe0.a == 0) + { + half mipLevel = perceptualRoughnessToMipmapLevel(perceptualRoughness*(1.7 - 0.7*perceptualRoughness)); + reflection = SAMPLE_TEXTURECUBE_LOD(_BakedCubemap, sampler_BakedCubemap, reflDir, mipLevel).rgb; + } + + half horizon = min(1 + dot(reflDir, o.WorldNormal), 1); + reflection *= horizon * horizon; + half reflectionOcclusion = saturate(length(indirectDiffuse) * (1.0 / _ReflectionOcclusion)); + + half3 envBRDF = EnvBRDFMultiscatter(dfg, f0); + reflection *= envBRDF; + + reflectionOcclusion *= lerp(1, lightAttenuation, _ReflectionRealtimeShadowOcclusion); + half computedSpecularOcclusion = computeSpecularAO(NoV, o.Occlusion * reflectionOcclusion, clampedRoughness); + computedSpecularOcclusion *= energyCompensation; + reflection *= gtaoMultiBounce(computedSpecularOcclusion, f0); + + indirectSpecular += reflection * o.ReflectionStrength; + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Reflections.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Reflections.orlsource.meta new file mode 100644 index 00000000..d003346e --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Reflections.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b71b95ce39b170e42b9eff0e02ee35d6 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimLight.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimLight.orlsource new file mode 100644 index 00000000..ce846627 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimLight.orlsource @@ -0,0 +1,101 @@ +%Properties() +{ + UI_RimLightHeader("# Rim Light", Int) = 0 + [Toggle(RIMLIGHT_ON)]_RimLight("Enable Rim Light", Int) = 0 + _RimTint("Tint %ShowIf(RIMLIGHT_ON)", Color) = (1,1,1,1) + _RimIntensity("Intensity %ShowIf(RIMLIGHT_ON)", Float) = 0.4 + _RimAlbedoTint("Albedo Tint %ShowIf(RIMLIGHT_ON)", Range(0,1)) = 1 + _RimEnvironmentTint("Environment Tint %ShowIf(RIMLIGHT_ON)", Range(0,1)) = 0 + _RimSpread("Spread %ShowIf(RIMLIGHT_ON)", Range(0, 1)) = 0.3 + _RimSharpness("Sharpness %ShowIf(RIMLIGHT_ON)", Range(0,1)) = 0.95 + _RimThreshold("Threshold %ShowIf(RIMLIGHT_ON)", Range(0, 1)) = 0 + UI_RimThresholdNote("> Controls how much the rim light will be offset by the light direction. 1 Will only show up in the areas hit by the light, 0 will show up everywhere %ShowIf(RIMLIGHT_ON)", Int) = 0 + _RimAttenuation("Attenuation %ShowIf(RIMLIGHT_ON)", Range(0,1)) = 1 + UI_RimAttenuationNote("> Controls how much the rimlight will be visible in shadowed areas. 0 always visible %ShowIf(RIMLIGHT_ON)", Int) = 0 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment RIMLIGHT_ON +} + + +%AdditionalSurfaceData() +{ + #if defined(RIMLIGHT_ON) + half3 RimTint; + half RimIntensity; + half RimAlbedoTint; + half RimEnvTint; + half RimSpread; + half RimSharpness; + half RimLightThreshold; + half RimLightAttenuation; + #endif +} + + +%Variables() +{ + #if defined(RIMLIGHT_ON) + half4 _RimTint; + half _RimIntensity; + half _RimAlbedoTint; + half _RimEnvironmentTint; + half _RimAttenuation; + half _RimSpread; + half _RimThreshold; + half _RimSharpness; + #endif +} + +%Fragment("ToonRimLightFragment") +{ + void ToonRimLightFragment(MeshData d, inout SurfaceData o) { + #if defined(RIMLIGHT_ON) + + // This module is almost fully passthrough + // This allows other modules to vary the parameters + // While the final calculations are done in the lighting module + o.RimIntensity = _RimIntensity; + o.RimTint = _RimTint.rgb * _RimTint.a; + o.RimAlbedoTint = _RimAlbedoTint; + o.RimEnvTint = _RimEnvironmentTint; + o.RimSpread = 1.0 - _RimSpread; + o.RimSharpness = 1.0 - _RimSharpness; + o.RimLightThreshold = _RimThreshold; + o.RimLightAttenuation = _RimAttenuation; + + #endif + } +} + +%ModuleLighting("ToonRimLightLighting") +{ + void ToonRimLightLighting(SurfaceData o, MeshData d, half lightNoL, half3 lightColor, half lightAttenuation, half3 indirectDiffuse, inout half3 mainLightMixedSpecular) + { + #if defined(RIMLIGHT_ON) + half SVDNoN = abs(dot(d.svdn, o.WorldNormal)); + + // Rim Light Env Tint + half3 env = 0; + #if defined(UNITY_PASS_FORWARDBASE) + env = getEnvReflection(d.worldSpaceViewDir.xyz, d.worldSpacePosition.xyz, o.WorldNormal, 0.5, 5); + #endif + + half lightThreshold = o.RimLightThreshold < 0.0001 ? 1 : saturate(pow(saturate(lightNoL), o.RimLightThreshold)); + + half rimIntensity = saturate((1 - SVDNoN)) * lightThreshold; + rimIntensity = smoothstep(o.RimSpread - o.RimSharpness, o.RimSpread + o.RimSharpness, rimIntensity); + + half3 rim = rimIntensity * o.RimIntensity; + rim *= o.RimTint; + rim *= lerp(1, o.Albedo.rgb, o.RimAlbedoTint); + rim *= lerp(1, env.rgb, o.RimEnvTint); + rim *= lightColor + indirectDiffuse; + rim *= lerp(1, lightAttenuation + indirectDiffuse, o.RimLightAttenuation); + + mainLightMixedSpecular += rim; + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimLight.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimLight.orlsource.meta new file mode 100644 index 00000000..8420d110 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimLight.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 52cd8fa02cf34d94a9d79fa798759f55 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimShadow.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimShadow.orlsource new file mode 100644 index 00000000..056ebd77 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimShadow.orlsource @@ -0,0 +1,73 @@ +%Properties() +{ + [ToggleUI]UI_RimShadowHeader("# Rim Shadow", Int) = 0 + [Toggle(RIMSHADOW_ON)]_RimShadow("Enable Rim Shadow", Int) = 0 + _ShadowRimTint("Tint %ShowIf(RIMSHADOW_ON)", Color) = (1,1,1,1) + _ShadowRimAlbedoTint("Albedo Tint %ShowIf(RIMSHADOW_ON)", Range(0,1)) = 1 + _ShadowRimSpread("Spread %ShowIf(RIMSHADOW_ON)", Range(0,1)) = 0.5 + _ShadowRimSharpness("Sharpness %ShowIf(RIMSHADOW_ON)", Range(0,1)) = 0.3 + _ShadowRimThreshold("Threshold %ShowIf(RIMSHADOW_ON)", Range(0,1)) = 0.3 + UI_ShadowRimThresholdNote("> Controls how much the rim shadow will be offset by the light direction. 1 Will only show up in the areas in shadow, 0 will show up everywhere %ShowIf(RIMSHADOW_ON)", Int) = 0 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment RIMSHADOW_ON +} + +%AdditionalSurfaceData() +{ + #if defined(RIMSHADOW_ON) + half3 ShadowRimTint; + half ShaderRimAlbedoTint; + half ShadowRimSpread; + half ShadowRimLightThreshold; + half ShadowRimSharpness; + #endif +} + +%Variables() +{ + #if defined(RIMSHADOW_ON) + half4 _ShadowRimTint; + half _ShadowRimSpread; + half _ShadowRimThreshold; + half _ShadowRimSharpness; + half _ShadowRimAlbedoTint; + #endif +} + +%Fragment("ToonShadowRimFragment") +{ + void ToonShadowRimFragment(MeshData d, inout SurfaceData o) { + #if defined(RIMSHADOW_ON) + + o.ShadowRimTint = _ShadowRimTint; + o.ShadowRimSpread = 1.0 - _ShadowRimSpread; + o.ShadowRimSharpness = 1.0 - _ShadowRimSharpness; + o.ShadowRimLightThreshold = _ShadowRimThreshold; + + #endif + } +} + +%ModuleLighting("ToonShadowRimLightLighting") +{ + void ToonShadowRimLightLighting(SurfaceData o, MeshData d, half lightNoL, inout half3 diffuseModifier) + { + #if defined(RIMSHADOW_ON) + + half SVDNoN = abs(dot(d.svdn, o.WorldNormal)); + + half lightThreshold = o.ShadowRimLightThreshold < 0.0001 ? 1 : saturate(pow(1 - lightNoL, o.ShadowRimLightThreshold)); + + half shadowRimIntensity = saturate((1 - SVDNoN)) * lightThreshold; + shadowRimIntensity = smoothstep(o.ShadowRimSpread - o.ShadowRimSharpness, o.ShadowRimSpread + o.ShadowRimSharpness, shadowRimIntensity); + + half3 rimShadow = lerp(1, o.ShadowRimTint, shadowRimIntensity); + rimShadow *= lerp(1, o.Albedo.rgb, o.ShaderRimAlbedoTint); + + diffuseModifier *= rimShadow; + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimShadow.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimShadow.orlsource.meta new file mode 100644 index 00000000..063b914f --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimShadow.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8fd48fc6093f0584b83bbd1935778538 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Shading.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Shading.orlsource new file mode 100644 index 00000000..a2874573 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Shading.orlsource @@ -0,0 +1,128 @@ +%Properties() +{ + UI_ShadingHeader("# Shading Settings", Int) = 1 + _Ramp("Ramp %Gradient()", 2D) = "grayscaleRamp" {} + _ShadowSharpness("Shadow Sharpness", Range(0,1)) = 0 + [ToggleUI]_OffsetRampByOcclusion("Offset Ramp by Occlusion", Int) = 0 + [ToggleUI]_IgnoreLightprobeNormal("Uniform Probe Lighting", Int) = 1 +} + +%Variables() +{ + half _ShadowSharpness; + int _OffsetRampByOcclusion; + int _IgnoreLightprobeNormal; +} + +%AdditionalSurfaceData() +{ + half3 Ramp; + + #if defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + float4x4 VertexLightColors; + float4x4 VertexLightDirections; + float4x4 VertexLightHalfVectors; + float4 VertexLightNoLs; + float4 VertexLightLoHs; + half4 VertexLightAttenuations; + half4x4 VertexLightRamps; + #endif +} + +%Textures() +{ + TEXTURE2D(_Ramp); + SAMPLER(sampler_Ramp); +} + +%ModuleLighting("ToonShadingLightingRamp") +{ + void ToonShadingLightingRamp(half lightNoL, inout half lightAttenuation, inout SurfaceData o, MeshData d) + { + half rampPos = lightNoL * 0.5 + 0.5; + + if (_OffsetRampByOcclusion) + { + rampPos *= o.Occlusion; + } + + #if defined(USING_DIRECTIONAL_LIGHT) + { + half sharp = _ShadowSharpness * 0.5; + lightAttenuation = smoothstep(sharp, 1 - sharp, lightAttenuation); + } + #endif + + #if defined(UNITY_PASS_FORWARDBASE) + rampPos *= lightAttenuation; + #endif + + o.Ramp = SAMPLE_TEXTURE2D(_Ramp, sampler_Ramp, float2(rampPos, 0)).rgb; + + #if defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + o.VertexLightColors = getVertexLightsColors(d.worldSpacePosition, o.Normal, o.VertexLightAttenuations, false); + o.VertexLightDirections = getVertexLightsDir(d.worldSpacePosition); + o.VertexLightHalfVectors = 0; + o.VertexLightRamps = 0; + + [unroll(4)] + for (int i = 0; i < 4; i++) + { + o.VertexLightHalfVectors[i].rgb = Unity_SafeNormalize(o.VertexLightDirections[i] + d.worldSpaceViewDir); + o.VertexLightNoLs[i] = saturate(dot(o.Normal, o.VertexLightDirections[i])); + half vertexLightRampPos = o.VertexLightNoLs[i] * 0.5 + 0.5; + if (_OffsetRampByOcclusion) + { + vertexLightRampPos *= o.Occlusion; + } + o.VertexLightRamps[i] = SAMPLE_TEXTURE2D(_Ramp, sampler_Ramp, float2(vertexLightRampPos, 0)); + } + #endif + } +} + +%ModuleLighting("ToonShadingLightingIndirect") +{ + void ToonShadingLightingIndirect(SurfaceData o, MeshData d, inout half3 indirectDiffuse) + { + half3 L0 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); + half3 L0L2 = half3(unity_SHBr.z, unity_SHBg.z, unity_SHBb.z) / 3.0; + L0 = L0+L0L2; + + float3 normal = _IgnoreLightprobeNormal ? float3(0, 0.5, 0) : o.WorldNormal; + + indirectDiffuse = max(0, GetNonLinearSH(L0, unity_SHAr, unity_SHAg, unity_SHAb, normal)); + indirectDiffuse += SHEvalLinearL2(float4(normal, 1)); + if (!_OffsetRampByOcclusion) + { + indirectDiffuse *= o.Occlusion; + } + } +} + +%ModuleLighting("ToonShadingLightingDirect") +{ + void ToonShadingLightingDirect(SurfaceData o, MeshData d, half lightAttenuation, bool hasRealtimeLight, inout half3 lightColor, inout half3 indirectDiffuse, inout half3 mainLightDiffuse) + { + half grayscaleIndirect = dot(indirectDiffuse, float3(0.299, 0.587, 0.114));// float3(0.299, 0.587, 0.114) + half adjustedAttenuation = lerp(lightAttenuation, 1, smoothstep(0, 0.2, grayscaleIndirect)); + + // If no realtime light is present - we treat probes as the light source + if (!hasRealtimeLight) + { + lightColor = indirectDiffuse * 0.6; + indirectDiffuse = indirectDiffuse * 0.4; + } + + mainLightDiffuse = lightColor * adjustedAttenuation * o.Ramp; + + #if defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + [unroll(4)] + for (int i = 0; i < 4; i++) + { + adjustedAttenuation = lerp(o.VertexLightAttenuations[i], 1, smoothstep(0, 0.2, grayscaleIndirect)); + mainLightDiffuse += o.VertexLightColors[i] * o.VertexLightRamps[i] * adjustedAttenuation; + } + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Shading.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Shading.orlsource.meta new file mode 100644 index 00000000..aa12b960 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Shading.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f5f76ae8b2751dd4089a75d45a95079e +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Specular.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Specular.orlsource new file mode 100644 index 00000000..6b4d9e72 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Specular.orlsource @@ -0,0 +1,187 @@ +%Properties() +{ + UI_SpecularHeader("# Specular", Int) = 1 + [Toggle(SPECULAR_ON)]_SpecularOn("Enable Specular", Int) = 0 + _SpecularMap("Specular Map > %ShowIf(SPECULAR_ON)", 2D) = "white" {} + UI_SpecMapdNote("> Red - Intensity, Green - Albedo Tint, Blue - Roughness %ShowIf(SPECULAR_ON)", Int) = 0 + [Enum(Synced With Albedo, 0, Independent, 1)]_SpecularTilingMode("Tiling Mode %ShowIf(_SpecularMap)", Int) = 0 + _SpecularTiling("Tiling %ShowIf(_SpecularMap)", Float) = 1 + UI_SpecularTilingSyncedNote("> Will scale UVs based on the Albedo texture Tiling and Offset settings %ShowIf(_SpecularTilingMode == 0 && _SpecularMap)", Int) = 0 + UI_SpecularTilingIndependentNote("> Will scale UVs on its own %ShowIf(_SpecularTilingMode == 1 && _SpecularMap)", Int) = 0 + + _SpecularTint("Tint %ShowIf(SPECULAR_ON)", Color) = (1,1,1,1) + _SpecularIntensity("Intensity %ShowIf(SPECULAR_ON)", Float) = 0 + _SpecularRoughness("Roughness %ShowIf(SPECULAR_ON)", Range(0, 1)) = 0.5 + _SpecularSharpness("Sharpness %ShowIf(SPECULAR_ON)", Range(0, 1)) = 0 + _SpecularAnisotropy("Anisotropy %ShowIf(SPECULAR_ON)", Range(-1.0, 1.0)) = 0 + _SpecularAlbedoTint("Albedo Tint %ShowIf(SPECULAR_ON)", Range(0, 1)) = 1 + + UI_SpecularMasking("## Masking %ShowIf(SPECULAR_ON)", Int) = 0 + _SpecularMask("Specular Mask > %ShowIf(SPECULAR_ON)", 2D) = "white" {} + [Enum(Synced With Albedo, 0, Independent, 1)]_SpecularMaskTilingMode("Tiling Mode %ShowIf(_SpecularMask)", Int) = 0 + _SpecularMaskTiling("Tiling %ShowIf(_SpecularMask)", Float) = 1 + UI_SpecularMaskTilingSyncedNote("> Will scale UVs based on the Albedo texture Tiling and Offset settings %ShowIf(_SpecularMaskTilingMode == 0 && _SpecularMask)", Int) = 0 + UI_SpecularMaskTilingIndependentNote("> Will scale UVs on its own %ShowIf(_SpecularMaskTilingMode == 1 && _SpecularMask)", Int) = 0 + [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)]_SpecularMaskChannel("Mask Channel %ShowIf(SPECULAR_ON)", Int) = 0 + _SpecularMaskStrength("Mask Strength %ShowIf(SPECULAR_ON)", Range(0, 1)) = 1 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment SPECULAR_ON +} + +%Variables() +{ + #if defined(SPECULAR_ON) + int _SpecularTilingMode; + half _SpecularTiling; + + half4 _SpecularTint; + half _SpecularIntensity; + half _SpecularRoughness; + half _SpecularSharpness; + half _SpecularAnisotropy; + half _SpecularAlbedoTint; + + int _SpecularMaskTilingMode; + half _SpecularMaskTiling; + int _SpecularMaskChannel; + half _SpecularMaskStrength; + #endif + + float2 GLOBAL_uv; +} + +%Textures() +{ + #if defined(SPECULAR_ON) + TEXTURE2D(_SpecularMap); + TEXTURE2D(_SpecularMask); + #endif +} + +%AdditionalSurfaceData() +{ + #if defined(SPECULAR_ON) + half3 SpecularTint; + half SpecularIntensity; + half SpecularRoughness; + half SpecularAnisotropy; + half SpecularSharpness; + half SpecularAlbedoTint; + #endif +} + +%Fragment("ToonSpecularFragment") +{ + void ToonSpecularFragment(MeshData d, inout SurfaceData o) { + #if defined(SPECULAR_ON) + + float2 globalUv = 0; + + #if defined(GLOBAL_UV_SET) + globalUv = GLOBAL_uv; + #else + globalUv = d.uv0; + #endif + + float2 specularUv = lerp(globalUv * _SpecularTiling, d.uv0 * _SpecularTiling, _SpecularTilingMode); + half3 specMap = SAMPLE_TEXTURE2D(_SpecularMap, sampler_MainTex, specularUv); + float2 specularMaskUv = lerp(globalUv * _SpecularMaskTiling, d.uv0 * _SpecularMaskTiling, _SpecularMaskTilingMode); + half specMask = SAMPLE_TEXTURE2D(_SpecularMask, sampler_MainTex, specularMaskUv)[_SpecularMaskChannel]; + + o.SpecularIntensity = max(0, _SpecularIntensity * specMap.r); + + o.SpecularRoughness = max(0.01, GSAA_Filament(d.worldNormal, _SpecularRoughness, 0.05, 0.1) * specMap.b); + o.SpecularRoughness = lerp(o.SpecularRoughness, o.SpecularRoughness * specMask, _SpecularMaskStrength); + + o.SpecularAnisotropy = _SpecularAnisotropy; + o.SpecularAlbedoTint = _SpecularAlbedoTint * specMap.g; + o.SpecularSharpness = _SpecularSharpness; + o.SpecularTint = _SpecularTint; + + #endif + } +} + +%ModuleLighting("ToonSpecularLighting") +{ + void ToonSpecularLighting(SurfaceData o, MeshData d, half3 lightColor, half lightAttenuation, float3 lightHalfVector, half lightLoH, half lightNoL, half NoV, half3 indirectDiffuse, inout half3 mainLightSpecular) + { + #if defined(SPECULAR_ON) + half perceptualRoughness = max(0.01, o.SpecularRoughness); + perceptualRoughness = perceptualRoughness * (1.7 - 0.7 * perceptualRoughness); + + half anisotropy = o.SpecularAnisotropy * saturate(5.0 * perceptualRoughness); + + perceptualRoughness *= perceptualRoughness; + perceptualRoughness = max(perceptualRoughness, 0.0045); + + lightNoL = saturate(lightNoL); + + half NoH = saturate(dot(o.WorldNormal, lightHalfVector)); + // Calculate f0 in place with Metallic = 0 + half3 F = F_Schlick(lightLoH, 0.16 * 0.5 * 0.5 + lerp(1, o.Albedo, o.SpecularAlbedoTint)); + + float D = D_GGX(NoH, perceptualRoughness); + half V = V_SmithGGXCorrelated(NoV, lightNoL, perceptualRoughness); + half3 isotropicSpecular = max(0, D * V * F); + + float at = max(perceptualRoughness * (1.0 + anisotropy), 0.001); + float ab = max(perceptualRoughness * (1.0 - anisotropy), 0.001); + + // Recalculate tangent and bitangent for proper aniso specular + d.worldSpaceTangent.xyz = cross(d.bitangent.xyz, o.WorldNormal); + d.bitangent.xyz = cross(o.WorldNormal, d.worldSpaceTangent.xyz); + + D = D_GGX_Anisotropic(NoH, lightHalfVector, d.worldSpaceTangent, d.bitangent, at, ab); + half3 anisotropicSpecular = max(0, D * V * F); + + half3 finalSpecular = lerp(isotropicSpecular, anisotropicSpecular, saturate(abs(anisotropy * 100))); + // Apply sharpness modifier by focusing in the center + finalSpecular = lerp(finalSpecular, smoothstep(0.5, 0.51, finalSpecular), o.SpecularSharpness); + finalSpecular *= UNITY_PI; // Multiply by PI to bring up to brightness of standard + finalSpecular *= lightColor; + finalSpecular *= o.SpecularIntensity; + finalSpecular *= o.SpecularTint; + finalSpecular = clamp(finalSpecular, 0, o.SpecularIntensity); + + finalSpecular *= lightNoL * lightAttenuation; + + #if defined(VERTEXLIGHT_ON) && defined(UNITY_PASS_FORWARDBASE) + [unroll(4)] + for (int i = 0; i < 4; i++) + { + o.VertexLightNoLs[i] = saturate(o.VertexLightNoLs[i]); + NoH = saturate(dot(o.WorldNormal, o.VertexLightHalfVectors[i])); + o.VertexLightLoHs[i] = saturate(dot(o.VertexLightDirections[i], o.VertexLightHalfVectors[i])); + F = F_Schlick(o.VertexLightLoHs[i], 0.16 * 0.5 * 0.5 + lerp(1, o.Albedo, o.SpecularAlbedoTint)); + + D = D_GGX(NoH, perceptualRoughness); + V = V_SmithGGXCorrelated(NoV, o.VertexLightNoLs[i], perceptualRoughness); + isotropicSpecular = max(0, D * V * F); + + D = D_GGX_Anisotropic(NoH, o.VertexLightHalfVectors[i], d.worldSpaceTangent, d.bitangent, at, ab); + anisotropicSpecular = max(0, D * V * F); + + half3 vertexLightSpecular = lerp(isotropicSpecular, anisotropicSpecular, saturate(abs(anisotropy * 100))); + // Apply sharpness modifier by focusing in the center + vertexLightSpecular = lerp(vertexLightSpecular, smoothstep(0.5, 0.51, vertexLightSpecular), o.SpecularSharpness); + vertexLightSpecular *= UNITY_PI; // Multiply by PI to bring up to brightness of standard + vertexLightSpecular *= o.VertexLightColors[i]; + vertexLightSpecular *= o.SpecularIntensity; + vertexLightSpecular *= o.SpecularTint; + vertexLightSpecular = clamp(vertexLightSpecular, 0, o.SpecularIntensity); + + vertexLightSpecular *= o.VertexLightNoLs[i] * o.VertexLightAttenuations[i]; + finalSpecular += vertexLightSpecular; + } + #endif + + finalSpecular *= o.Occlusion; + + mainLightSpecular += finalSpecular; + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Specular.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Specular.orlsource.meta new file mode 100644 index 00000000..c39e5413 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Specular.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 29e4bb5c886b97247af9c481de5e13f6 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/TriplanarEffects.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/TriplanarEffects.orlsource index 35d7400f..dccfaa8d 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/TriplanarEffects.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/TriplanarEffects.orlsource @@ -37,9 +37,9 @@ %ShaderFeatures() { - #pragma shader_feature_local DIRT_MODE_NONE DIRT_MODE_LOCAL_SPACE DIRT_MODE_WORLD_SPACE - #pragma shader_feature_local DAMAGE_MODE_NONE DAMAGE_MODE_ENABLED - #pragma shader_feature_local DEBUG_TRIPLANAR_NONE DEBUG_TRIPLANAR_DIRT DEBUG_TRIPLANAR_DAMAGE + #pragma shader_feature_local_fragment DIRT_MODE_NONE DIRT_MODE_LOCAL_SPACE DIRT_MODE_WORLD_SPACE + #pragma shader_feature_local_fragment DAMAGE_MODE_NONE DAMAGE_MODE_ENABLED + #pragma shader_feature_local_fragment DEBUG_TRIPLANAR_NONE DEBUG_TRIPLANAR_DIRT DEBUG_TRIPLANAR_DAMAGE } %ShaderDefines() @@ -104,11 +104,15 @@ #else - half3 wsAligned = (d.worldSpacePosition / - _TriplanarMaskTiling); + float3 wsAligned = (d.worldSpacePosition / - _TriplanarMaskTiling); + + float2 xyUV = wsAligned.xy; + float2 zyUV = wsAligned.zy; + float2 xzUV = wsAligned.xz; - half3 xySample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, wsAligned.xy).rgb; - half3 yzSample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, wsAligned.yz).rgb; - half3 xzSample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, wsAligned.xz).rgb; + half3 xySample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, xyUV).rgb; + half3 zySample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, zyUV).rgb; + half3 xzSample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, xzUV).rgb; half3 worldNormal = abs(d.worldNormal); worldNormal = saturate(worldNormal - (1 - _TriplanarBlend)); @@ -118,7 +122,7 @@ half yNormalMask = saturate(lerp(-1, 1, worldNormal.y)); half zNormalMask = saturate(lerp(-1, 1, worldNormal.z)); - half3 triplanarMask = lerp(lerp(lerp(0, xzSample, yNormalMask), yzSample, xNormalMask), xySample, zNormalMask); + half3 triplanarMask = lerp(lerp(lerp(0, xzSample, yNormalMask), zySample, xNormalMask), xySample, zNormalMask); half damageMask = triplanarMask.g; half dirtMask = triplanarMask.b; @@ -144,7 +148,7 @@ { damageNormalPacked.y = 1 - damageNormalPacked.y; } - half3 damageNormal = UnpackScaleNormal(damageNormalPacked, _DamageNormalScale * damageMask); + half3 damageNormal = UnpackNormalScale(damageNormalPacked, _DamageNormalScale * damageMask); o.Normal = BlendNormals(o.Normal, damageNormal); o.Smoothness = lerp(o.Smoothness, clamp(o.Smoothness, _DamageSmooth.x, _DamageSmooth.y), damageMask); @@ -166,7 +170,7 @@ #if defined(DIRT_MODE_WORLD_SPACE) // world space grad - half gradMask = (d.worldSpacePosition - TransformObjectToWorld(half3(0, 0, 0))).y; + half gradMask = (d.worldSpacePosition - TransformObjectToWorld(0..xxx)).y; gradMask = (gradMask - _DirtGradientMax) / (_DirtGradientMin - _DirtGradientMax); gradMask = saturate(gradMask); dirtMask *= gradMask; @@ -197,11 +201,15 @@ { void TriplanarColor(MeshData d, inout half4 FinalColor) { #if !defined(DEBUG_TRIPLANAR_NONE) - half3 wsAligned = (d.worldSpacePosition / - _TriplanarMaskTiling); + float3 wsAligned = (d.worldSpacePosition / - _TriplanarMaskTiling); + + float2 xyUV = wsAligned.xy; + float2 zyUV = wsAligned.zy; + float2 xzUV = wsAligned.xz; - half3 xySample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, wsAligned.xy).rgb; - half3 yzSample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, wsAligned.yz).rgb; - half3 xzSample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, wsAligned.xz).rgb; + half3 xySample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, xyUV).rgb; + half3 zySample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, zyUV).rgb; + half3 xzSample = SAMPLE_TEXTURE2D(_TriplanarMask, sampler_TriplanarMask, xzUV).rgb; half3 worldNormal = abs(d.worldNormal); worldNormal = saturate(worldNormal - (1 - _TriplanarBlend)); @@ -211,7 +219,7 @@ half yNormalMask = saturate(lerp(-1, 1, worldNormal.y)); half zNormalMask = saturate(lerp(-1, 1, worldNormal.z)); - half3 triplanarMask = lerp(lerp(lerp(0, xzSample, yNormalMask), yzSample, xNormalMask), xySample, zNormalMask); + half3 triplanarMask = lerp(lerp(lerp(0, xzSample, yNormalMask), zySample, xNormalMask), xySample, zNormalMask); half damageMask = triplanarMask.g; half dirtMask = triplanarMask.b; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VFX/GlitchScreen.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VFX/GlitchScreen.orlsource index 8b312866..92a1bb98 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VFX/GlitchScreen.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VFX/GlitchScreen.orlsource @@ -3,6 +3,9 @@ UI_GlitchHeader("# Glitch Screen", Int) = 1 UI_GlitchDocs("[This module has documentation](https://shaders.orels.sh/docs/vfx/glitch-screen)", Int) = 0 _GlitchTexture("Base Texture", 2D) = "white" {} + [Toggle(SEPARATE_ALPHA)]_SeparateAlpha("Separate Transparency Texture", Int) = 0 + _AlphaTex("Transparency %ShowIf(_SeparateAlpha)", 2D) = "white" {} + _AlphaScale("Alpha Scale %ShowIf(_MainTex || SEPARATE_ALPHA)", Range(0,2)) = 1 [HDR]_PosterEmission("Emission", Color) = (1,1,1,1) _GlitchEffectCycleSpeed("Effects Cycle Speed", Float) = 0.5 UI_GlitchEffectCycleNote("> Controls how often the whole effect will be switched around", Int) = 0 @@ -27,23 +30,30 @@ _GlitchColorGlitchSpeed("Speed", Float) = 0.5 } +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment SEPARATE_ALPHA +} + %Variables() { - half4 _GlitchTexture_ST; + float4 _GlitchTexture_ST; + float4 _AlphaTex_ST; + half _AlphaScale; half4 _PosterEmission; half _GlitchEffectCycleSpeed; int _GlitchPixelEnabled; - half4 _GlitchPixel_ST; + float4 _GlitchPixel_ST; float _GlitchPixelHorizontal; float _GlitchPixelVertical; half3 _GlitchColorScales; - half4 _GlitchShiftMask_ST; + float4 _GlitchShiftMask_ST; half _GlitchShiftChance; half _GlitchSiftRandomizationAmount; - half4 _GlitchColorGlitchMask_ST; + float4 _GlitchColorGlitchMask_ST; half _GlitchColorGlitchChance; half _GlitchColorGlitchSpeed; } @@ -52,6 +62,7 @@ { TEXTURE2D(_GlitchPixel); SAMPLER(sampler_GlitchPixel); + TEXTURE2D(_AlphaTex); TEXTURE2D(_GlitchShiftMask); SAMPLER(sampler_GlitchShiftMask); TEXTURE2D(_GlitchTexture); @@ -84,7 +95,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. - half3 RGBPixel(Texture2D subpixel, SamplerState pixelSampler, half3 viewDir, half3 worldNormal, half2 uv, half3 sourceCol) + half3 RGBPixel(Texture2D subpixel, SamplerState pixelSampler, half3 viewDir, half3 worldNormal, float2 uv, half3 sourceCol) { half4 rgbpixel = subpixel.Sample(pixelSampler, uv); @@ -122,24 +133,42 @@ void GlitchFragment(MeshData d, inout SurfaceData o) { int index = floor(_Time.x * (_GlitchEffectCycleSpeed / 100.0) * 64.0 * 64.0) % (64*64); - half2 offset = half2(floor(index % 64.0), floor(index / 64.0)) / 64.0; - half4 offsetMask = SAMPLE_TEXTURE2D(_GlitchShiftMask, sampler_GlitchShiftMask, offset); - half2 uv = d.uv0 * _GlitchShiftMask_ST.xy + _GlitchShiftMask_ST.zw; + float2 offset = float2(floor(index % 64.0), floor(index / 64.0)) / 64.0; + + float2 cleanUV = d.uv0; + float2 derivatives = float2(ddx(cleanUV.x), ddy(cleanUV.y)); + + half4 offsetMask = SAMPLE_TEXTURE2D_GRAD(_GlitchShiftMask, sampler_GlitchShiftMask, offset, derivatives.x, derivatives.y); + float2 uv = d.uv0 * _GlitchShiftMask_ST.xy + _GlitchShiftMask_ST.zw; uv += (offsetMask.aa - 0.5) * (10 * offsetMask.a); - half4 shiftMask = SAMPLE_TEXTURE2D(_GlitchShiftMask, sampler_GlitchShiftMask, uv); + + cleanUV = d.uv0.x * _GlitchShiftMask_ST.xy + _GlitchShiftMask_ST.zw; + derivatives = float2(ddx(cleanUV.x), ddy(cleanUV.y)); + float4 shiftMask = SAMPLE_TEXTURE2D_GRAD(_GlitchShiftMask, sampler_GlitchShiftMask, uv, derivatives.x, derivatives.y); uv = d.uv0 * _GlitchTexture_ST.xy + _GlitchTexture_ST.zw; if (offsetMask.a >= (1 - _GlitchShiftChance)) { uv.y -= saturate((frac(_Time.y * 0.2 + shiftMask.g + offsetMask.a * 0.5) % (shiftMask.b + (offsetMask.a - 0.5) * _GlitchSiftRandomizationAmount))) * shiftMask.r; } - o.Albedo = SAMPLE_TEXTURE2D(_GlitchTexture, sampler_GlitchTexture, uv); + + cleanUV = d.uv0 * _GlitchTexture_ST.xy + _GlitchTexture_ST.zw; + derivatives = float2(ddx(cleanUV.x), ddy(cleanUV.y)); + half4 glitchColor = SAMPLE_TEXTURE2D_GRAD(_GlitchTexture, sampler_GlitchTexture, uv, derivatives.x, derivatives.y); + o.Albedo = glitchColor.rgb; + + + #if defined(SEPARATE_ALPHA) + o.Alpha = saturate(SAMPLE_TEXTURE2D(_AlphaTex, sampler_GlitchTexture, d.uv0.xy * _AlphaTex_ST.xy + _AlphaTex_ST.zw).r * _AlphaScale); + #else + o.Alpha = saturate(glitchColor.a * _AlphaScale); + #endif uv = d.uv0 * _GlitchColorGlitchMask_ST.xy + _GlitchColorGlitchMask_ST.zw; - uv += half2(floor(offsetMask.a * 8) / 8.0, floor(offsetMask.a * 4) / 4.0); + uv += float2(floor(offsetMask.a * 8) / 8.0, floor(offsetMask.a * 4) / 4.0); half4 colorGlitch = SAMPLE_TEXTURE2D(_GlitchColorGlitchMask, sampler_GlitchShiftMask, uv); index = floor(_Time.x * (_GlitchColorGlitchSpeed / 10.0) * 64.0 * 64.0) % (64*64); - offset = half2(floor(index % 64.0), floor(index / 64.0)) / 64.0; + offset = float2(floor(index % 64.0), floor(index / 64.0)) / 64.0; half4 colorGlitchProgression = SAMPLE_TEXTURE2D(_GlitchColorGlitchMask, sampler_GlitchShiftMask, offset); uv = d.uv0; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VFX/Patterns.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VFX/Patterns.orlsource index 88bcdcef..3d3534b1 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VFX/Patterns.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VFX/Patterns.orlsource @@ -5,41 +5,39 @@ UI_PatternsPresesets("Selected Preset %Preset(@/Presets/VFX/Patterns)", Int) = 0 [KeywordEnum(None, 2x, 4x)]PATTERN_SUPERSAMPLING("Super Sampling", Int) = 0 UI_PatternsSuperSamplingNote("> If the patterns look too jagged, you can try increasing the Super Sampling amount", Int) = 0 - // [KeywordEnum(Circles, Triangles, Lines)]PATTERN("Pattern", Int) = 0 - [HDR]_CirclesColor1("Color 1 %ShowIf(PATTERN_CIRCLES)", Color) = (0, 0, 0, 1) - [HDR]_CirclesColor2("Color 2 %ShowIf(PATTERN_CIRCLES)", Color) = (1, 1, 1, 1) + [HDR]_CirclesColor1("Color 1", Color) = (0, 0, 0, 1) + [HDR]_CirclesColor2("Color 2", Color) = (1, 1, 1, 1) - UI_CirclesKaleidoscopeHeader("## Kaleidoscope %ShowIf(PATTERN_CIRCLES)", Int) = 1 - [ToggleUI]_CirclesKaleidoscopeUV("Kaleidoscope UV %ShowIf(PATTERN_CIRCLES)", Int) = 0 - UI_CirclesKaleidoscopeUVNote("> Adds Kaleidoscope effect, recommended to use with Circle Offset of 0,0 %ShowIf(PATTERN_CIRCLES)", Int) = 0 - _CirclesKaleidoscopeSlices("Slice Count %ShowIf(PATTERN_CIRCLES && _CirclesKaleidoscopeUV)", Int) = 2 - _CirclesKaleidoscopeSpinSpeed("Spin Speed %ShowIf(PATTERN_CIRCLES && _CirclesKaleidoscopeUV)", Float) = 0.5 - _CirclesKaleidoscopeSpinOffset("Spin Time Offset %ShowIf(PATTERN_CIRCLES && _CirclesKaleidoscopeUV)", Float) = 0 - _CirclesKaleidoscopeTiling("Tiling %ShowIf(PATTERN_CIRCLES && _CirclesKaleidoscopeUV)", Float) = 1 + UI_CirclesKaleidoscopeHeader("## Kaleidoscope", Int) = 1 + [ToggleUI]_CirclesKaleidoscopeUV("Kaleidoscope UV", Int) = 0 + UI_CirclesKaleidoscopeUVNote("> Adds Kaleidoscope effect, recommended to use with Circle Offset of 0,0", Int) = 0 + _CirclesKaleidoscopeSlices("Slice Count %ShowIf(_CirclesKaleidoscopeUV)", Int) = 2 + _CirclesKaleidoscopeSpinSpeed("Spin Speed %ShowIf(_CirclesKaleidoscopeUV)", Float) = 0.5 + _CirclesKaleidoscopeSpinOffset("Spin Time Offset %ShowIf(_CirclesKaleidoscopeUV)", Float) = 0 + _CirclesKaleidoscopeTiling("Tiling %ShowIf(_CirclesKaleidoscopeUV)", Float) = 1 UI_CirclesSettingsHeader("## Circles Settings", Int) = 0 - _CircleOrigin("Circle Origin %ShowIf(PATTERN_CIRCLES)", Vector) = (0.2, 0.2, 0, 0) + _CircleOrigin("Circle Origin", Vector) = (0.2, 0.2, 0, 0) UI_CircleOriginNote("> Only X and Y values are used", Int) = 1 - _CircleCount("Circle Count %ShowIf(PATTERN_CIRCLES)", Float) = 30 - _CircleSmoothing("Circle Smoothing %ShowIf(PATTERN_CIRCLES)", Float) = 0.1 - _CircleExpandSpeed("Expand Speed %ShowIf(PATTERN_CIRCLES)", Float) = 0.1 + _CircleCount("Circle Count", Float) = 30 + _CircleSmoothing("Circle Smoothing", Float) = 0.1 + _CircleExpandSpeed("Expand Speed", Float) = 0.1 _CircleExpandTimeOffset("Time Offset", Float) = 0 - UI_LinesHeader("## Lines Mask %ShowIf(PATTERN_CIRCLES)", Int) = 1 - [ToggleUI]_CircleAddLines("Add Lines %ShowIf(PATTERN_CIRCLES)", Int) = 0 - _CircleLinesThickness("Line Thickness %ShowIf(PATTERN_CIRCLES && _CircleAddLines)", Float) = 5 - _CircleLinesSmoothing("Line Smoothing %ShowIf(PATTERN_CIRCLES && _CircleAddLines)", Float) = 0.1 - _CircleLinesDegreeOffset("Offset (Degrees) %ShowIf(PATTERN_CIRCLES && _CircleAddLines)", Float) = 30 - UI_CircleLinesDegreeOffsetNote("> Add a line every X degrees. E.g. a value of 30 will draw a line every 30 degrees %ShowIf(PATTERN_CIRCLES && _CircleAddLines)", Int) = 0 - _CircleLinesSpinSpeed("Spin Speed %ShowIf(PATTERN_CIRCLES && _CircleAddLines)", Float) = 0.1 - [ToggleUI]_CircleLinesSpinAlternate("Alternate Spin %ShowIf(PATTERN_CIRCLES && _CircleAddLines)", Int) = 1 - _CircleLinesSpinTimeOffset("Spin Time Offset %ShowIf(PATTERN_CIRCLES && _CircleAddLines)", Float) = 0 + UI_LinesHeader("## Lines Mask", Int) = 1 + [ToggleUI]_CircleAddLines("Add Lines", Int) = 0 + _CircleLinesThickness("Line Thickness %ShowIf(_CircleAddLines)", Float) = 5 + _CircleLinesSmoothing("Line Smoothing %ShowIf(_CircleAddLines)", Float) = 0.1 + _CircleLinesDegreeOffset("Offset (Degrees) %ShowIf(_CircleAddLines)", Float) = 30 + UI_CircleLinesDegreeOffsetNote("> Add a line every X degrees. E.g. a value of 30 will draw a line every 30 degrees %ShowIf(_CircleAddLines)", Int) = 0 + _CircleLinesSpinSpeed("Spin Speed %ShowIf(_CircleAddLines)", Float) = 0.1 + [ToggleUI]_CircleLinesSpinAlternate("Alternate Spin %ShowIf(_CircleAddLines)", Int) = 1 + _CircleLinesSpinTimeOffset("Spin Time Offset %ShowIf(_CircleAddLines)", Float) = 0 } %ShaderFeatures() { - // #pragma shader_feature_local PATTERN_CIRCLES PATTERN_TRIANGLES PATTERN_LINES - #pragma shader_feature_local PATTERN_SUPERSAMPLING_NONE PATTERN_SUPERSAMPLING_2X PATTERN_SUPERSAMPLING_4X + #pragma shader_feature_local_fragment PATTERN_SUPERSAMPLING_NONE PATTERN_SUPERSAMPLING_2X PATTERN_SUPERSAMPLING_4X } %ShaderDefines() @@ -102,7 +100,7 @@ } - half2 GetKaleidoscopeUV(half2 uv, half repeats, half rotation, half scale) + float2 GetKaleidoscopeUV(float2 uv, half repeats, half rotation, half scale) { half timeFactor = rotation; half cosR = cos(rotation) * scale; @@ -110,22 +108,22 @@ for (int i = 0; i < repeats; i++) { uv = abs(uv); uv -= 0.25; - uv = uv * cosR + sinR * uv.yx * half2(1, -1); + uv = uv * cosR + sinR * uv.yx * float2(1, -1); } return uv; } - half2 GetPolarUV(half2 uv, half angle) + float2 GetPolarUV(float2 uv, half angle) { angle = angle / 180 * UNITY_PI; half atanAng = atan2(uv.x, uv.y); half dist = length(uv); atanAng = GLSLMod(atanAng + angle / 2.0, angle) - angle / 2.0; - uv = half2(sin(atanAng), cos(atanAng)) * dist; + uv = float2(sin(atanAng), cos(atanAng)) * dist; return uv; } - half3 CirclesDist(half2 uv) + half3 CirclesDist(float2 uv) { uv = uv - 0.5; if (_CirclesKaleidoscopeUV) @@ -153,7 +151,7 @@ void PatternsFragment(MeshData d, inout SurfaceData o) { - half2 uv = d.uv0; + float2 uv = d.uv0; float2 dxuv = ddx(d.uv0); float2 dyuv = ddy(d.uv0); float goldenRatio = 1.61803398875; @@ -185,11 +183,11 @@ // Currently disabled // TODO: Add more options #if defined(PATTERN_LINES) - half2 uv = d.uv0; + float2 uv = d.uv0; uv = uv - 0.5; { // uv = Rotate2D(uv, _Time.y); - half2 kaleidocscope = GetKaleidoscopeUV(uv, 2, _Time.y * 0.5, .5); + float2 kaleidocscope = GetKaleidoscopeUV(uv, 2, _Time.y * 0.5, .5); // half rotatedUv = // uv = Rotate2D(kaleidocscope, _Time.y); uv = kaleidocscope; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRCFeatures.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRCFeatures.orlsource index 6043d906..c25983eb 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRCFeatures.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRCFeatures.orlsource @@ -17,7 +17,7 @@ %ShaderFeatures() { - #pragma shader_feature_local VRC_FEATURES + #pragma shader_feature_local_vertex VRC_FEATURES } %Variables() diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRSLGI.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRSLGI.orlsource new file mode 100644 index 00000000..8b8b51b1 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRSLGI.orlsource @@ -0,0 +1,132 @@ +%Properties() +{ + [ToggleUI]UI_VRSLGIHeader("# VRSL GI", Int) = 1 + UI_VRSLGIDocs("[This module has documentation](https://shaders.orels.sh/docs/orl-standard/vrslgi)", Int) = 0 + [Toggle(_VRSL_GI)]useVRSLGI("Integrate VRSL GI", Float) = 0.0 + UI_VRSLGIDownload("[Make sure to download VRSLGI Shader Pack before enabling this option](https://github.com/AcChosen/VR-Stage-Lighting-GI-ShaderPack/releases)", Int) = 0 + _VRSLGIStrength("VRSL GI Strength %ShowIf(_VRSL_GI)", Float) = 2 + _VRSLDiffuseMix("VRSL Diffuse Mix %ShowIf(_VRSL_GI)", Range(0, 1)) = 0.25 + _VRSLRoughnessModifier("Roughness Modifier %ShowIf(_VRSL_GI)", Range(-1,1)) = 0 + [TpggleUI]_VRSLAlphaPremultiply("Alpha Premultiply %ShowIf(_VRSL_GI)", Float) = 0 + [Toggle(_VRSL_GI_SPECULARHIGHLIGHTS)]useVRSLGISpecular("Use VRSL GI Specular %ShowIf(_VRSL_GI)", Float) = 1.0 + [KeywordEnum(GGX, Beckman, Phong)]_VRSL_SPECFUNC("VRSL Specular Function %ShowIf(_VRSL_GI && _VRSL_GI_SPECULARHIGHLIGHTS)", Int) = 0 // Selecting the specular function. + _VRSLGISpecularClamp("Max Specular Brightness %ShowIf(_VRSL_GI && _VRSL_GI_SPECULARHIGHLIGHTS)", Range(1.0, 50000.0)) = 10000 + [Toggle(_VRSL_SHADOWMASK1)]_UseVRSLShadowMask1("Use VRSL Shadow Mask 1 %ShowIf(_VRSL_GI)", Int) = 0 // The first shadow mask toggle + _VRSLShadowMask1("VRSL GI ShadowMask 1 > %ShowIf(_VRSL_GI && _VRSL_SHADOWMASK1)", 2D) = "white" {} // The first shadow mask texture + [Enum(UV0, 0, UV1, 1, UV2, 2, UV3, 3, UV1_LightmapST, 9)]_VRSLShadowmaskUVSet("VRSL Shadow Mask UV Set %ShowIf(_VRSL_GI && _VRSL_SHADOWMASK1)", Int) = 1 + + [KeywordEnum(R, RG, RGB, RGBA)]_VRSL_SHADOWMASK("Active Channels %ShowIf(_VRSL_GI && _VRSL_SHADOWMASK1)", Int) = 3 + _UseVRSLShadowMask1RStrength("VRSL SM 1 R Strength %ShowIf(_VRSL_GI && _VRSL_SHADOWMASK1)", Range(0.0, 1.0)) = 1.0 // the R strength of the first shadow mask + _UseVRSLShadowMask1GStrength("VRSL SM 1 G Strength %ShowIf(_VRSL_GI && _VRSL_SHADOWMASK1)", Range(0.0, 1.0)) = 1.0 // the G strength of the first shadow mask + _UseVRSLShadowMask1BStrength("VRSL SM 1 B Strength %ShowIf(_VRSL_GI && _VRSL_SHADOWMASK1)", Range(0.0, 1.0)) = 1.0 // the B strength of the first shadow mask + _UseVRSLShadowMask1AStrength("VRSL SM 1 A Strength %ShowIf(_VRSL_GI && _VRSL_SHADOWMASK1)", Range(0.0, 1.0)) = 1.0 // the A strength of the first shadow mask +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment _VRSL_GI + #pragma shader_feature_local_fragment _VRSL_SPECFUNC_GGX _VRSL_SPECFUNC_BECKMAN _VRSL_SPECFUNC_PHONG + #pragma shader_feature_local_fragment _VRSL_GI_SPECULARHIGHLIGHTS + #pragma shader_feature_local_fragment _VRSL_SHADOWMASK1 + #pragma shader_feature_local_fragment _VRSL_GLOBALLIGHTTEXTURE + #pragma shader_feature_local_fragment _ _VRSL_SHADOWMASK_RG _VRSL_SHADOWMASK_RGB _VRSL_SHADOWMASK_RGBA +} + +%Variables() +{ + half _VRSLRoughnessModifier; + int _VRSLAlphaPremultiply; + int _VRSLShadowmaskUVSet; +} + +%ShaderDefines() +{ + #if !defined(_VRSL_GI) + #define SKIP_VRSLGI + #endif + + #define INCLUDE_VRSLGI defined(_VRSL_GI) + + #if INCLUDE_VRSLGI + #include "Assets/VRSL Addons/VRSL-GI Shader Package/VRSLGI-Functions.cginc" + #endif +} + +%Color("VRSLGIColor") +{ + + void VRSLGIColor(MeshData d, SurfaceData o, inout half4 FinalColor) + { + #if defined(PLAT_QUEST) + { + return; + } + #else + { + #if defined(_VRSL_GI) && !defined(SKIP_VRSLGI) + { + float2 uv = d.uv0.xy; + #if defined(LIGHTMAP_ON) + { + if (_VRSLShadowmaskUVSet == 9) + { + uv = d.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; + } + } + #else + { + switch (_VRSLShadowmaskUVSet) + { + case 1: uv = d.uv1.xy; break; + case 2: uv = d.uv2.xy; break; + case 3: uv = d.uv3.xy; break; + } + } + #endif + + #if defined(ORL_LIGHTING_MODEL_VFX) + float oneMinusReflectivity = 0.96; + #else + float oneMinusReflectivity = 1.0 - 0.04 - o.Metallic * (1.0 - 0.04); + #endif + + _VRSLMetallicMapStrength = 1; + _VRSLSpecularShine = 1; + _VRSLSpecularMultiplier = 1; + + #if defined(ORL_LIGHTING_MODEL_VFX) || defined(ORL_LIGHTING_MODEL_TOONV2) + float3 giOutput = VRSLGI( + d.worldSpacePosition, + d.worldNormal, + saturate(0.5 + _VRSLRoughnessModifier), + d.worldSpaceViewDir, + o.Albedo * oneMinusReflectivity, + float2(0.96, saturate(0.5 + _VRSLRoughnessModifier)), + uv, + 1 + ); + #else + float3 giOutput = VRSLGI( + d.worldSpacePosition, + Unity_SafeNormalize(mul(o.Normal, d.TBNMatrix)), + saturate((1 - o.Smoothness) + _VRSLRoughnessModifier), + d.worldSpaceViewDir, + o.Albedo * oneMinusReflectivity, + float2(o.Metallic, saturate(o.Smoothness + (1 - _VRSLRoughnessModifier))), + uv, + o.Occlusion + ); + #endif + + FinalColor.rgb += giOutput; + + if (_VRSLAlphaPremultiply) + { + FinalColor.rgb *= FinalColor.a; + } + } + #endif + } + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRSLGI.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRSLGI.orlsource.meta new file mode 100644 index 00000000..a587b1f1 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VRSLGI.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c5c97a2ca0d906246be27384757a140e +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexAnimation.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexAnimation.orlsource index 7c0be001..c86b93d6 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexAnimation.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexAnimation.orlsource @@ -6,20 +6,24 @@ UI_SpinHeader("## Spin", Int) = 0 [KeywordEnum(None, Local, World)]SPIN("Spinning", Int) = 0 _SpinAxis("Spin Axis %ShowIf(!SPIN_NONE)", Vector) = (0, 1, 0, 0) - [ToggleUI]_NormalizeSpinAxis("Normalize Axis", Int) = 1 + [ToggleUI]_NormalizeSpinAxis("Normalize Axis %ShowIf(!SPIN_NONE)", Int) = 1 _SpinOrigin("Spin Origin Point %ShowIf(!SPIN_NONE)", Vector) = (0, 0, 0, 0) UI_SpinOriginNote("> Spin Origin Point is considered in object's local space %ShowIf(!SPIN_NONE)", Int) = 0 _SpinSpeed("Spin Speed %ShowIf(!SPIN_NONE)", Float) = 1 + UI_SpinOffsetsHeader("## Offsets %ShowIf(!SPIN_NONE)", Int) = 0 _SpinPhaseOffset("Phase Offset %ShowIf(!SPIN_NONE)", Float) = 0 - [ToggleUI]_SpinPositionOffset("Position Offset %ShowIf(!SPIN_NONE)", Int) = 0 - [Enum(XYZ, 0, X, 1, Y, 2, Z, 3)]_SpinPositionOffsetAxis("Position Offset Axis %ShowIf(!SPIN_NONE && _SpinPositionOffset)", Int) = 0 - _SpinPositionOffsetScale("Position Offset Scale %ShowIf(!SPIN_NONE && _SpinPositionOffset)", Float) = 1 + [ToggleUI]_SpinPositionOffset("Position-Based Offset %ShowIf(!SPIN_NONE)", Int) = 0 + [Enum(XYZ, 0, X, 1, Y, 2, Z, 3)]_SpinPositionOffsetAxis("Offset Axis %ShowIf(!SPIN_NONE && _SpinPositionOffset)", Int) = 0 + _SpinPositionOffsetScale("Offset Scale %ShowIf(!SPIN_NONE && _SpinPositionOffset)", Float) = 1 + _SpinPositionOffsetSpeed("Offset Speed Modifier %ShowIf(!SPIN_NONE && _SpinPositionOffset)", Float) = 0.1 + [ToggleUI]_SpinStoppedChance("Spin Stopped Chance %ShowIf(!SPIN_NONE && _SpinPositionOffset)", Int) = 0 + _SpinStoppedChanceSeed("Spin Stopped Chance Seed %ShowIf(!SPIN_NONE && _SpinStoppedChance && _SpinPositionOffset)", Int) = 0 // FLOATING UI_FloatHeader("## Float", Int) = 0 [KeywordEnum(None, Local, World)]FLOATING("Floating", Int) = 0 _FloatAxis("Float Axis %ShowIf(!FLOATING_NONE)", Vector) = (0, 1, 0, 0) - [ToggleUI]_NormalizeFloatAxis("Normalize Axis", Int) = 1 + [ToggleUI]_NormalizeFloatAxis("Normalize Axis %ShowIf(!FLOATING_NONE)", Int) = 1 _FloatSpeed("Float Speed %ShowIf(!FLOATING_NONE)", Float) = 1 _FloatPhaseOffset("Phase Offset %ShowIf(!FLOATING_NONE)", Float) = 0 [ToggleUI]_FloatPositionOffset("Position Offset %ShowIf(!FLOATING_NONE)", Int) = 0 @@ -49,9 +53,9 @@ %ShaderFeatures() { - #pragma shader_feature_local _ SPIN_LOCAL SPIN_WORLD - #pragma shader_feature_local _ FLOATING_LOCAL FLOATING_WORLD - #pragma shader_feature_local _ SCALE_UNIFORM SCALE_FLOW + #pragma shader_feature_local_vertex SPIN_NONE SPIN_LOCAL SPIN_WORLD + #pragma shader_feature_local_vertex FLOATING_NONE FLOATING_LOCAL FLOATING_WORLD + #pragma shader_feature_local_vertex SCALE_NONE SCALE_UNIFORM SCALE_FLOW } %ShaderTags() @@ -61,15 +65,6 @@ %ShaderDefines() { - #if !defined(SPIN_WORLD) && !defined(SPIN_LOCAL) - #define SPIN_NONE - #endif - #if !defined(FLOATING_WORLD) && !defined(FLOATING_LOCAL) - #define FLOATING_NONE - #endif - #if !defined(SCALE_UNIFORM) && !defined(SCALE_FLOW) - #define SCALE_NONE - #endif #define EXTRA_V2F_0 } @@ -85,6 +80,9 @@ int _SpinPositionOffsetAxis; half _SpinPositionOffsetScale; half4 _SpinOrigin; + half _SpinPositionOffsetSpeed; + int _SpinStoppedChance; + float _SpinStoppedChanceSeed; half4 _FloatAxis; int _NormalizeFloatAxis; @@ -112,11 +110,18 @@ %Vertex("VertexAnimationVertex") { + float chash13(float3 p3) + { + p3 = frac(p3 * .1031); + p3 += dot(p3, p3.zyx + 31.32); + return frac((p3.x + p3.y) * p3.z); + } + void VertexAnimationVertex(inout VertexData v, inout FragmentData o) { // half3 wsVert = TransformObjectToWorld(v.vertex.xyz); // half3 wsNormal = TransformObjectToWorld(v.normal.xyz); - half3 wsObjectPosition = mul(unity_ObjectToWorld, half4(0,0,0,1)); + half3 wsObjectPosition = TransformObjectToWorld(0..xxx); half factor = 0; o.extraV2F0 = v.vertex; @@ -128,25 +133,32 @@ } half offset = _SpinPhaseOffset; + half speedOffset = 0; if (_SpinPositionOffset) { if (_SpinPositionOffsetAxis == 0) { - offset += length(wsObjectPosition.xyz) * _SpinPositionOffsetScale; + offset += length(wsObjectPosition.xyz); } else { - offset += wsObjectPosition[_SpinPositionOffsetAxis - 1] * _SpinPositionOffsetScale; + offset += wsObjectPosition[_SpinPositionOffsetAxis - 1]; } + offset *= _SpinPositionOffsetScale; + speedOffset = pow(abs(_SpinPositionOffsetSpeed), offset) * sign(_SpinPositionOffsetSpeed); + } + + half factor = _Time.y * (_SpinSpeed + speedOffset) + offset; + factor %= 6.2831; + + if (_SpinStoppedChance) { + float3 seed = _SpinStoppedChanceSeed + offset; + float chance = step(0.5, chash13(seed)); + factor *= chance; } - half factor = _Time.y * _SpinSpeed + offset; #if defined(SPIN_LOCAL) v.vertex.xyz = RotateAroundAxis(origin, v.vertex.xyz, _SpinAxis.xyz, factor); v.normal.xyz = RotateAroundAxis(origin, v.normal.xyz, _SpinAxis.xyz, factor); #elif defined(SPIN_WORLD) - float3 scale = float3( - length(unity_ObjectToWorld._m00_m10_m20), - length(unity_ObjectToWorld._m01_m11_m21), - length(unity_ObjectToWorld._m02_m12_m22) - ); - half3 lsAxis = normalize(TransformWorldToObject(_SpinAxis.xyz)); + float3 scale = GetObjectScale(); + half3 lsAxis = normalize(TransformWorldToObjectDir(_SpinAxis.xyz)); half3 vertRot = RotateAroundAxis(origin, v.vertex.xyz, lsAxis, factor); half3 normalRot = RotateAroundAxis(origin, v.normal.xyz, lsAxis, factor); v.vertex.xyz = vertRot; @@ -174,7 +186,7 @@ axis = normalize(axis); } #elif defined(FLOATING_WORLD) - half3 axis = normalize(TransformWorldToObject(_FloatAxis.xyz)).xyz; + half3 axis = normalize(TransformWorldToObjectDir(_FloatAxis.xyz)).xyz; #endif v.vertex.xyz += factor * axis * _FloatAmount; @@ -200,7 +212,7 @@ { half offset = _ScalePhaseOffset; half factor = ((_Time.y * _ScaleSpeed + offset) % (1.1 + _ScaleFlowWidth * 2 + _ScaleFlowCyclePause)) - 0.1; - half2 uvChannel = v.uv0; + float2 uvChannel = v.uv0; switch (_ScaleFlowUVChannel) { case 1: uvChannel = v.uv1; break; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexColors.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexColors.orlsource new file mode 100644 index 00000000..b88f7429 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexColors.orlsource @@ -0,0 +1,66 @@ +%Properties() +{ + UI_VertexColorsHeader("# Vertex Colors", Int) = 1 + UI_VertexColorsDocs("[This module has documentation](https://shaders.orels.sh/docs/configurable-shaders/modules/vertex-colors)", Int) = 0 + UI_VertexColorsNote("> Select which material parameters will be affected by vertex colors", Int) = 0 + [ToggleUI]_VCAlbedo("Albedo", Int) = 0 + _VCAlbedoStrength("Albedo Strength %ShowIf(_VCAlbedo)", Range(0, 1)) = 1 + [ToggleUI]_VCAlpha("Alpha", Int) = 0 + _VCAlphaStrength("Alpha Strength %ShowIf(_VCAlpha) %CombineWith(_VCAlphaChannel)", Range(0, 1)) = 1 + [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)]_VCAlphaChannel("Channel %ShowIf(_VCAlpha)", Int) = 3 + [ToggleUI]_VCAlphaPremultiply("Alpha Premultiply %ShowIf(_VCAlpha)", Int) = 0 + [ToggleUI]_VCEmission("Emission", Int) = 0 + _VCEmissionStrength("Emission Strength %ShowIf(_VCEmission)", Range(0, 1)) = 1 + [ToggleUI]_VCMetallic("Metallic", Int) = 0 + _VCMetallicStrength("Metallic Strength %ShowIf(_VCMetallic) %CombineWith(_VCMetallicMapChannel)", Range(0, 1)) = 1 + [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)]_VCMetallicMapChannel("Channel %ShowIf(_VCMetallic)", Int) = 0 + [ToggleUI]_VCSmoothness("Smoothness", Int) = 0 + _VCSmoothnessStrength("Smoothness Strength %ShowIf(_VCSmoothness) %CombineWith(_VCSmoothnessMapChannel)", Range(0, 1)) = 1 + [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)]_VCSmoothnessMapChannel("Channel %ShowIf(_VCSmoothness)", Int) = 0 + [ToggleUI]_VCOcclusion("Occlusion", Int) = 0 + _VCOcclusionStrength("Occlusion Strength %ShowIf(_VCOcclusion) %CombineWith(_VCOcclusionMapChannel)", Range(0, 1)) = 1 + [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)]_VCOcclusionMapChannel("Channel %ShowIf(_VCOcclusion)", Int) = 0 +} + +%Variables() +{ + int _VCAlbedo; + half _VCAlbedoStrength; + int _VCAlpha; + half _VCAlphaStrength; + int _VCAlphaChannel; + int _VCAlphaPremultiply; + int _VCEmission; + half _VCEmissionStrength; + int _VCMetallic; + half _VCMetallicStrength; + int _VCMetallicMapChannel; + int _VCSmoothness; + half _VCSmoothnessStrength; + int _VCSmoothnessMapChannel; + int _VCOcclusion; + half _VCOcclusionStrength; + int _VCOcclusionMapChannel; +} + +%ShaderDefines() +{ + #define NEED_ALBEDO_ALPHA +} + +%Fragment("VertexColorsFragment") +{ + void VertexColorsFragment(MeshData d, inout SurfaceData o) + { + if (_VCAlbedo) o.Albedo = lerp(o.Albedo, o.Albedo * d.vertexColor.rgb, _VCAlbedoStrength); + if (_VCAlpha) o.Alpha = lerp(o.Alpha, o.Alpha * d.vertexColor[_VCAlphaChannel], _VCAlphaStrength); + if (_VCAlphaPremultiply) o.Albedo *= lerp(1, d.vertexColor[_VCAlphaChannel], _VCAlphaStrength); + if (_VCEmission) o.Emission = lerp(o.Emission, o.Emission * d.vertexColor.rgb, _VCEmissionStrength); + + #if !defined(ORL_LIGHTING_MODEL_VFX) + if (_VCMetallic) o.Metallic = lerp(o.Metallic, o.Metallic * d.vertexColor[_VCMetallicMapChannel], _VCMetallicStrength); + if (_VCSmoothness) o.Smoothness = lerp(o.Smoothness, o.Smoothness * d.vertexColor[_VCSmoothnessMapChannel], _VCSmoothnessStrength); + if (_VCOcclusion) o.Occlusion = lerp(o.Occlusion, o.Occlusion * d.vertexColor[_VCOcclusionMapChannel], _VCOcclusionStrength); + #endif + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexColors.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexColors.orlsource.meta new file mode 100644 index 00000000..30f7627e --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/VertexColors.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 28fb54bc14930ef44afa2fe2ebca8422 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/FragmentData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/FragmentData.orlsource index a58f2601..5d0b0691 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/FragmentData.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/FragmentData.orlsource @@ -9,10 +9,22 @@ #endif float3 normal : RAW_NORMAL; - float2 uv0 : TEXCOORD1; - float2 uv1 : TEXCOORD2; - float2 uv2 : TEXCOORD3; - float2 uv3 : TEXCOORD4; + float4 uv0 : TEXCOORD1; + float4 uv1 : TEXCOORD2; + float4 uv2 : TEXCOORD3; + float4 uv3 : TEXCOORD4; + #if defined(NEED_UV4) + float4 uv4 : TEXCOORD5; + #endif + #if defined(NEED_UV5) + float4 uv5 : TEXCOORD6; + #endif + #if defined(NEED_UV6) + float4 uv6 : TEXCOORD7; + #endif + #if defined(NEED_UV7) + float4 uv7 : TEXCOORD8; + #endif float3 worldPos : WORLD_POS; float3 worldNormal : WORLD_NORMAL; float4 worldTangent : WORLD_TANGENT; @@ -23,8 +35,8 @@ centroid float4 vertexColor : VERTEX_COLOR; #if !defined(UNITY_PASS_META) - UNITY_LIGHTING_COORDS(5, 6) - UNITY_FOG_COORDS(7) + UNITY_LIGHTING_COORDS(9, 10) + UNITY_FOG_COORDS(11) #endif #if defined(EDITOR_VISUALIZATION) @@ -49,6 +61,10 @@ float4 extraV2F3 : EXTRA_V2F_BLOCK3; #endif + // Additional Fragment Data + %AdditionalFragmentData + // Additional Fragment Data End + UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/MeshData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/MeshData.orlsource index 28840b45..5b648709 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/MeshData.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/MeshData.orlsource @@ -2,10 +2,22 @@ { struct MeshData { - half2 uv0; - half2 uv1; - half2 uv2; - half2 uv3; + float4 uv0; + float4 uv1; + float4 uv2; + float4 uv3; + #if defined(NEED_UV4) + float4 uv4; + #endif + #if defined(NEED_UV5) + float4 uv5; + #endif + #if defined(NEED_UV6) + float4 uv6; + #endif + #if defined(NEED_UV7) + float4 uv7; + #endif #if !defined(UNITY_PASS_SHADOWCASTER) half4 lightmapUv; #endif @@ -22,15 +34,31 @@ float4 extraV2F2; float4 extraV2F3; float4 screenPos; + + // Additional Mesh Data + %AdditionalMeshData + // Additional Mesh Data End }; - MeshData CreateMeshData(FragmentData i) + MeshData CreateMeshData(FragmentData i, bool facing) { MeshData d = (MeshData) 0; d.uv0 = i.uv0; d.uv1 = i.uv1; d.uv2 = i.uv2; d.uv3 = i.uv3; + #if defined(NEED_UV4) + d.uv4 = i.uv4; + #endif + #if defined(NEED_UV5) + d.uv5 = i.uv5; + #endif + #if defined(NEED_UV6) + d.uv6 = i.uv6; + #endif + #if defined(NEED_UV7) + d.uv7 = i.uv7; + #endif #if !defined(UNITY_PASS_SHADOWCASTER) d.lightmapUv = i.lightmapUv; #endif @@ -43,8 +71,9 @@ d.vertexColor = i.vertexColor; #if !defined(UNITY_PASS_SHADOWCASTER) - float3 bitangent = Unity_SafeNormalize(cross(i.worldTangent.xyz, d.worldNormal) * i.worldTangent.w * - 1); + float3 bitangent = cross(d.worldNormal, i.worldTangent.xyz) * (i.worldTangent.w > 0.0 ? 1.0 : - 1.0); d.TBNMatrix = float3x3(normalize(i.worldTangent.xyz), bitangent, d.worldNormal); + d.TBNMatrix[2].xyz *= facing ? 1 : -1; d.tangentSpaceViewDir = mul(d.TBNMatrix, d.worldSpaceViewDir); #endif @@ -64,6 +93,10 @@ d.screenPos = i.screenPos; #endif + // Additional Mesh Data Creator + %AdditionalMeshDataCreator + // Additional Mesh Data Creator End + return d; } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/PBR/SurfaceData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/PBR/SurfaceData.orlsource index 8467d959..15ba9c83 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/PBR/SurfaceData.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/PBR/SurfaceData.orlsource @@ -7,8 +7,12 @@ half Metallic; half Smoothness; half Occlusion; - half3 Normal; + float3 Normal; half Alpha; + + // Additional Surface Data + %AdditionalSurfaceData + // Additional Surface Data End }; SurfaceData CreateSurfaceData() @@ -16,7 +20,7 @@ SurfaceData o = (SurfaceData) 0; o.Albedo = 1; o.Occlusion = 1; - o.Normal = half3(0, 0, 1); + o.Normal = float3(0, 0, 1); o.Smoothness = 0.5; o.Alpha = 1; return o; diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessFactors.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessFactors.orlsource new file mode 100644 index 00000000..fc0a263f --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessFactors.orlsource @@ -0,0 +1,8 @@ +%DataStructs() +{ + struct TessFactors + { + float edge[3] : SV_TessFactor; + float inside : SV_InsideTessFactor; + }; +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessFactors.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessFactors.orlsource.meta new file mode 100644 index 00000000..9c2f96fa --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessFactors.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 824a7f22dbd6ab340aec8b947872aa2a +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessVertexData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessVertexData.orlsource new file mode 100644 index 00000000..71144b35 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessVertexData.orlsource @@ -0,0 +1,28 @@ +%DataStructs() +{ + struct TessVertexData + { + float4 vertex : INTERNALTESSPOS; + float3 normal : NORMAL; + float4 tangent : TANGENT; + float4 color : COLOR; + float4 uv0 : TEXCOORD0; + float4 uv1 : TEXCOORD1; + float4 uv2 : TEXCOORD2; + float4 uv3 : TEXCOORD3; + #if defined(NEED_UV4) + float4 uv4 : TEXCOORD4; + #endif + #if defined(NEED_UV5) + float4 uv5 : TEXCOORD5; + #endif + #if defined(NEED_UV6) + float4 uv6 : TEXCOORD6; + #endif + #if defined(NEED_UV7) + float4 uv7 : TEXCOORD7; + #endif + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO + }; +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessVertexData.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessVertexData.orlsource.meta new file mode 100644 index 00000000..588d6bf4 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/TessVertexData.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 7263edac9facdd940a365f64ec392d45 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/MeshData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/MeshData.orlsource index 79d89912..def9b0f9 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/MeshData.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/MeshData.orlsource @@ -2,10 +2,22 @@ { struct MeshData { - half2 uv0; - half2 uv1; - half2 uv2; - half2 uv3; + float4 uv0; + float4 uv1; + float4 uv2; + float4 uv3; + #if defined(NEED_UV4) + float4 uv4; + #endif + #if defined(NEED_UV5) + float4 uv5; + #endif + #if defined(NEED_UV6) + float4 uv6; + #endif + #if defined(NEED_UV7) + float4 uv7; + #endif #if !defined(UNITY_PASS_SHADOWCASTER) half4 lightmapUv; #endif @@ -25,15 +37,31 @@ float4 extraV2F2; float4 extraV2F3; float4 screenPos; + + // Additional Mesh Data + %AdditionalMeshData + // Additional Mesh Data End }; - MeshData CreateMeshData(FragmentData i) + MeshData CreateMeshData(FragmentData i, bool facing) { MeshData d = (MeshData) 0; d.uv0 = i.uv0; d.uv1 = i.uv1; d.uv2 = i.uv2; d.uv3 = i.uv3; + #if defined(NEED_UV4) + d.uv4 = i.uv4; + #endif + #if defined(NEED_UV5) + d.uv5 = i.uv5; + #endif + #if defined(NEED_UV6) + d.uv6 = i.uv6; + #endif + #if defined(NEED_UV7) + d.uv7 = i.uv7; + #endif #if !defined(UNITY_PASS_SHADOWCASTER) d.lightmapUv = i.lightmapUv; #endif @@ -49,6 +77,7 @@ d.bitangent = normalize(cross(i.worldTangent.xyz, d.worldNormal) * i.worldTangent.w * - 1); d.worldSpaceTangent = normalize(i.worldTangent.xyz); d.TBNMatrix = float3x3(normalize(i.worldTangent.xyz), d.bitangent, d.worldNormal); + d.TBNMatrix[2].xyz *= facing ? 1 : -1; d.tangentSpaceViewDir = mul(d.TBNMatrix, d.worldSpaceViewDir); #endif @@ -75,6 +104,10 @@ d.screenPos = i.screenPos; #endif + // Additional Mesh Data Creator + %AdditionalMeshDataCreator + // Additional Mesh Data Creator End + return d; } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/SurfaceData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/SurfaceData.orlsource index d5651e9a..48e8e060 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/SurfaceData.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/SurfaceData.orlsource @@ -34,10 +34,14 @@ half Reflectivity; half3 BakedReflection; - int ReflectionBlendMode; + half ReflectionBlendMode; half3 OutlineColor; int OutlineLightingMode; + + // Additional Surface Data + %AdditionalSurfaceData + // Additional Surface Data End }; SurfaceData CreateSurfaceData() diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/v2.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/v2.meta new file mode 100644 index 00000000..d2ccc1a0 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/v2.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1fd6bb9e8ad8bb447923677c91d9e228 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/v2/SurfaceData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/v2/SurfaceData.orlsource new file mode 100644 index 00000000..1287bba5 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/v2/SurfaceData.orlsource @@ -0,0 +1,26 @@ +%DataStructs() +{ + struct SurfaceData + { + half3 Albedo; + half3 Emission; + half Alpha; + half Occlusion; + float3 Normal; + float3 WorldNormal; + + // Additional Surface Data + %AdditionalSurfaceData + // Additional Surface Data End + }; + + SurfaceData CreateSurfaceData() + { + SurfaceData o = (SurfaceData) 0; + o.Albedo = 0.5; + o.Occlusion = 1; + o.Normal = float3(0, 0, 1); + o.Alpha = 1; + return o; + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/v2/SurfaceData.orlsource.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/v2/SurfaceData.orlsource.meta new file mode 100644 index 00000000..52a71181 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/Toon/v2/SurfaceData.orlsource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 5bb91309e44ff6544962fcd1e65b67e5 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: f43ee36a0ee244f697129b1aba052424, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/UI/SurfaceData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/UI/SurfaceData.orlsource index a9f08aea..56d50623 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/UI/SurfaceData.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/UI/SurfaceData.orlsource @@ -5,6 +5,10 @@ half3 Albedo; half Alpha; half3 Emission; + + // Additional Surface Data + %AdditionalSurfaceData + // Additional Surface Data End }; SurfaceData CreateSurfaceData() diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/VFX/SurfaceData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/VFX/SurfaceData.orlsource index 66bc2c5b..b0524707 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/VFX/SurfaceData.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/VFX/SurfaceData.orlsource @@ -5,6 +5,10 @@ half3 Albedo; half3 Emission; half Alpha; + + // Additional Surface Data + %AdditionalSurfaceData + // Additional Surface Data End }; SurfaceData CreateSurfaceData() diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/VertexData.orlsource b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/VertexData.orlsource index fba52fed..b5e48002 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/VertexData.orlsource +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Structs/VertexData.orlsource @@ -6,10 +6,22 @@ float3 normal : NORMAL; float4 tangent : TANGENT; float4 color : COLOR; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; + float4 uv0 : TEXCOORD0; + float4 uv1 : TEXCOORD1; + float4 uv2 : TEXCOORD2; + float4 uv3 : TEXCOORD3; + #if defined(NEED_UV4) + float4 uv4 : TEXCOORD4; + #endif + #if defined(NEED_UV5) + float4 uv5 : TEXCOORD5; + #endif + #if defined(NEED_UV6) + float4 uv6 : TEXCOORD6; + #endif + #if defined(NEED_UV7) + float4 uv7 : TEXCOORD7; + #endif UNITY_VERTEX_INPUT_INSTANCE_ID }; } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBR.orltemplate b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBR.orltemplate index 31fe0c2c..ef1c47f6 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBR.orltemplate +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBR.orltemplate @@ -7,9 +7,6 @@ SubShader { Tags { "VRCFallback"="Standard" %ShaderTags } - ZTest[_ZTest] - ZWrite[_ZWrite] - Cull[_CullMode] %ShaderModifiers @@ -29,6 +26,9 @@ // PrePasses %PrePasses + // Exra PrePasses + %ExtraPrePasses + Pass { Tags { "LightMode" = "ForwardBase" %PassTags } @@ -59,20 +59,23 @@ // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - // Variables %Variables // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // FreeFunctions + %FreeFunctions + // ForwardBase Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -87,12 +90,26 @@ // ForwardBase VertexBase %VertexBase + // ForwardBase PostVertex Chain + %PostVertexFunctions + return o; } + #endif // ForwardBase Fragment - half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace + #if defined(NEED_SV_DEPTH) + , out float depth: SV_Depth + #endif + #if defined(NEED_SV_DEPTH_LEQUAL) + , out float depth: SV_DepthLessEqual + #endif + ) : SV_TARGET { + #if !defined(NEED_SV_DEPTH) && !defined(NEED_SV_DEPTH_LEQUAL) + float depth = 0; + #endif UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); #ifdef FOG_COMBINED_WITH_TSPACE @@ -104,7 +121,7 @@ #endif SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); half4 FinalColor = 1; // ForwardBase Fragment Chain @@ -157,20 +174,23 @@ // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - // Variables %Variables // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // FreeFunctions + %FreeFunctions + // ForwardAdd Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -185,12 +205,26 @@ // ForwardAdd VertexBase %VertexBase + // ForwardAdd PostVertex Chain + %PostVertexFunctions + return o; } + #endif // ForwardAdd Fragment - half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace + #if defined(NEED_SV_DEPTH) + , out float depth: SV_Depth + #endif + #if defined(NEED_SV_DEPTH_LEQUAL) + , out float depth: SV_DepthLessEqual + #endif + ) : SV_TARGET { + #if !defined(NEED_SV_DEPTH) && !defined(NEED_SV_DEPTH_LEQUAL) + float depth = 0; + #endif UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); #ifdef FOG_COMBINED_WITH_TSPACE @@ -202,7 +236,7 @@ #endif SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); half4 FinalColor = 1; // ForwardAdd Fragment Chain @@ -258,9 +292,7 @@ // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif + // Variables %Variables @@ -268,10 +300,17 @@ // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // FreeFunctions + %FreeFunctions + // ForwardBase Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -286,17 +325,32 @@ // Meta VertexBase %VertexBase + // Meta PostVertex Chain + %PostVertexFunctions + return o; } + #endif // Meta Fragment - half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace + #if defined(NEED_SV_DEPTH) + , out float depth: SV_Depth + #endif + #if defined(NEED_SV_DEPTH_LEQUAL) + , out float depth: SV_DepthLessEqual + #endif + ) : SV_TARGET { + // Stub depth in case its not used + #if !defined(NEED_SV_DEPTH) && !defined(NEED_SV_DEPTH_LEQUAL) + float depth = 0; + #endif UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); // Meta pass only takes Albedo, Alpha and Emission half4 FinalColor = 1; @@ -358,9 +412,7 @@ // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif + // Variables %Variables @@ -368,10 +420,17 @@ // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // FreeFunctions + %FreeFunctions + // ShadowCaster Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -386,20 +445,34 @@ // ShadowCaster VertexBase %VertexBase + // ShadowCaster PostVertex Chain + %PostVertexFunctions + TRANSFER_SHADOW_CASTER_NORMALOFFSET(o); return o; } + #endif // ShadowCaster Fragment - half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace + #if defined(NEED_SV_DEPTH) + , out float depth: SV_Depth + #endif + #if defined(NEED_SV_DEPTH_LEQUAL) + , out float depth: SV_DepthLessEqual + #endif + ) : SV_TARGET { + #if !defined(NEED_SV_DEPTH) && !defined(NEED_SV_DEPTH_LEQUAL) + float depth = 0; + #endif UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); #if defined(NEED_FRAGMENT_IN_SHADOW) SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); half4 FinalColor = 1; // ShadowCaster Fragment Chain @@ -420,6 +493,9 @@ // ShadowCaster Pass End } + // ExtraPasses + %ExtraPasses + // PostPasses %PostPasses } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBRExtraPass.orltemplate b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBRExtraPass.orltemplate new file mode 100644 index 00000000..bb0faff2 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBRExtraPass.orltemplate @@ -0,0 +1,113 @@ +Pass +{ + Name %PassName + Tags { "LightMode" = "ForwardBase" %PassTags } + %PassModifiers + + // ExtraPass Pass Start + CGPROGRAM + #pragma target 4.5 + #pragma multi_compile_instancing + #pragma multi_compile_fwdbase + #pragma multi_compile_fog + #pragma vertex Vertex + #pragma fragment Fragment + %ShaderFeatures + + #define UNITY_INSTANCED_LOD_FADE + #define UNITY_INSTANCED_SH + #define UNITY_INSTANCED_LIGHTMAPSTS + + // ShaderDefines + %ShaderDefines + // DataStructs + %DataStructs + // GlobalVariables + %GlobalVariables + + #if defined(NEED_DEPTH) + UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); + #endif + + // Variables + %Variables + + // Textures + %Textures + + // PassFunctions + %PassFunctions + + // Functions + %Functions + + // FreeFunctions + %FreeFunctions + + // ExtraPass Vertex + #if !defined(TESS_ENABLED) + FragmentData Vertex(VertexData v) + { + UNITY_SETUP_INSTANCE_ID(v); + FragmentData o; + UNITY_INITIALIZE_OUTPUT(FragmentData, o); + UNITY_TRANSFER_INSTANCE_ID(v, o); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + // ExtraPass Vertex Chain + %VertexFunctions + + // ExtraPass VertexBase + %VertexBase + + // ExtraPass PostVertex Chain + %PostVertexFunctions + + return o; + } + #endif + + // ExtraPass Fragment + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace + #if defined(NEED_SV_DEPTH) + , out float depth: SV_Depth + #endif + #if defined(NEED_SV_DEPTH_LEQUAL) + , out float depth: SV_Depth + #endif + ) : SV_TARGET + { + #if !defined(NEED_SV_DEPTH) && !defined(NEED_SV_DEPTH_LEQUAL) + float depth = 0; + #endif + UNITY_SETUP_INSTANCE_ID(i); + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + #ifdef FOG_COMBINED_WITH_TSPACE + UNITY_EXTRACT_FOG_FROM_TSPACE(i); + #elif defined(FOG_COMBINED_WITH_WORLD_POS) + UNITY_EXTRACT_FOG_FROM_WORLD_POS(i); + #else + UNITY_EXTRACT_FOG(i); + #endif + + SurfaceData o = CreateSurfaceData(); + MeshData d = CreateMeshData(i, facing); + half4 FinalColor = 1; + + // ExtraPass Fragment Chain + %FragmentFunctions + + // ExtraPass FragmentBase + %FragmentBase + + UNITY_APPLY_FOG(_unity_fogCoord, FinalColor); + + // ExtraPass Color Chain + %ColorFunctions + + return FinalColor; + } + + ENDCG + // ExtraPass Pass End +} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBRExtraPass.orltemplate.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBRExtraPass.orltemplate.meta new file mode 100644 index 00000000..79c9ef37 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/PBRExtraPass.orltemplate.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9f403c6b4bbff7a489e492fbac4d42d1 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 2fa69a10b9c340b7b2eaa1b19e18bb6e, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/Toon.orltemplate b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/Toon.orltemplate index 0366c79d..e14e3e36 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/Toon.orltemplate +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/Toon.orltemplate @@ -7,9 +7,6 @@ Shader %ShaderName SubShader { Tags { "VRCFallback"="Standard" %ShaderTags } - ZTest[_ZTest] - ZWrite[_ZWrite] - Cull[_CullMode] %ShaderModifiers @@ -30,6 +27,9 @@ Shader %ShaderName // PrePasses %PrePasses + // Exra PrePasses + %ExtraPrePasses + %TemplateFeature("PrePass") { Pass @@ -76,10 +76,17 @@ Shader %ShaderName // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // Free Functions + %FreeFunctions + // ForwardBase Depth Prepass Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -94,8 +101,12 @@ Shader %ShaderName // ForwardBase Depth Prepass VertexBase %VertexBase + // ForwardBase Depth Prepass PostVertex Chain + %PostVertexFunctions + return o; } + #endif // ForwardBase Depth Prepass Fragment half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET @@ -113,7 +124,7 @@ Shader %ShaderName half4 FinalColor = 1; #if defined(NEED_FRAGMENT_IN_PREPASS) SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); // ForwardBase Depth Prepass Fragment Chain %FragmentFunctions @@ -173,20 +184,23 @@ Shader %ShaderName // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - // Variables %Variables // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // Free Functions + %FreeFunctions + // ForwardBase Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -201,8 +215,12 @@ Shader %ShaderName // ForwardBase VertexBase %VertexBase + // ForwardBase PostVertex Chain + %PostVertexFunctions + return o; } + #endif // ForwardBase Fragment half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET @@ -218,7 +236,7 @@ Shader %ShaderName #endif SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); half4 FinalColor = 1; // ForwardBase Fragment Chain @@ -271,20 +289,23 @@ Shader %ShaderName // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - // Variables %Variables // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // Free Functions + %FreeFunctions + // ForwardAdd Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -301,6 +322,7 @@ Shader %ShaderName return o; } + #endif // ForwardAdd Fragment half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET @@ -316,7 +338,7 @@ Shader %ShaderName #endif SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); half4 FinalColor = 1; // ForwardAdd Fragment Chain @@ -328,6 +350,9 @@ Shader %ShaderName // ForwardAdd Color Chain %ColorFunctions + // ForwardAdd PostVertex Chain + %PostVertexFunctions + UNITY_APPLY_FOG(_unity_fogCoord, FinalColor); return FinalColor; @@ -372,20 +397,23 @@ Shader %ShaderName // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - // Variables %Variables // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // Free Functions + %FreeFunctions + // ForwardBase Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -400,8 +428,12 @@ Shader %ShaderName // Meta VertexBase %VertexBase + // Meta PostVertex Chain + %PostVertexFunctions + return o; } + #endif // Meta Fragment half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET @@ -410,7 +442,7 @@ Shader %ShaderName UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); // Meta pass only takes Albedo, Alpha and Emission half4 FinalColor = 1; @@ -472,20 +504,23 @@ Shader %ShaderName // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - // Variables %Variables // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // Free Functions + %FreeFunctions + // ShadowCaster Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -500,10 +535,14 @@ Shader %ShaderName // ShadowCaster VertexBase %VertexBase + // ShadowCaster PostVertex Chain + %PostVertexFunctions + TRANSFER_SHADOW_CASTER_NORMALOFFSET(o); return o; } + #endif // ShadowCaster Fragment half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET @@ -513,7 +552,7 @@ Shader %ShaderName #if defined(NEED_FRAGMENT_IN_SHADOW) SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); half4 FinalColor = 1; // ShadowCaster Fragment Chain @@ -541,7 +580,7 @@ Shader %ShaderName Cull Front Stencil { Ref 69 - Comp NotEqual + Comp [_StencilOutlineComp] Pass Zero Fail Zero } @@ -572,20 +611,23 @@ Shader %ShaderName // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - // Variables %Variables // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // Free Functions + %FreeFunctions + // Outline Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -602,6 +644,9 @@ Shader %ShaderName // Outline VertexBase %VertexBase + // Outline PostVertex Chain + %PostVertexFunctions + return o; #else @@ -611,6 +656,7 @@ Shader %ShaderName #endif } + #endif // Outline Fragment half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET @@ -628,7 +674,7 @@ Shader %ShaderName #endif SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); half4 FinalColor = 1; // Outline Fragment Chain @@ -655,6 +701,9 @@ Shader %ShaderName // Outline Pass End } + // ExtraPasses + %ExtraPasses + // PostPasses %PostPasses } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/ToonExtraPass.orltemplate b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/ToonExtraPass.orltemplate new file mode 100644 index 00000000..655bd38c --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/ToonExtraPass.orltemplate @@ -0,0 +1,108 @@ +Pass +{ + Name %PassName + Tags { "LightMode" = "ForwardBase" %PassTags } + %PassModifiers + + // ForwardBase Pass Start + CGPROGRAM + #pragma target 4.5 + #pragma multi_compile_instancing + #pragma multi_compile_fwdbase + #pragma multi_compile_fog + #pragma vertex Vertex + #pragma fragment Fragment + + %ShaderFeatures + + #define UNITY_INSTANCED_LOD_FADE + #define UNITY_INSTANCED_SH + #define UNITY_INSTANCED_LIGHTMAPSTS + + #ifndef UNITY_PASS_FORWARDBASE + #define UNITY_PASS_FORWARDBASE + #endif + + // ShaderDefines + %ShaderDefines + // DataStructs + %DataStructs + // GlobalVariables + %GlobalVariables + + #if defined(NEED_DEPTH) + UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); + #endif + + // Variables + %Variables + + // Textures + %Textures + + // PassFunctions + %PassFunctions + + // Functions + %Functions + + // Free Functions + %FreeFunctions + + // ExtraPass Vertex + #if !defined(TESS_ENABLED) + FragmentData Vertex(VertexData v) + { + UNITY_SETUP_INSTANCE_ID(v); + FragmentData o; + UNITY_INITIALIZE_OUTPUT(FragmentData, o); + UNITY_TRANSFER_INSTANCE_ID(v, o); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + // ExtraPass Vertex Chain + %VertexFunctions + + // ExtraPass VertexBase + %VertexBase + + // ExtraPass PostVertex Chain + %PostVertexFunctions + + return o; + } + #endif + + // ExtraPass Fragment + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET + { + UNITY_SETUP_INSTANCE_ID(i); + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + #ifdef FOG_COMBINED_WITH_TSPACE + UNITY_EXTRACT_FOG_FROM_TSPACE(i); + #elif defined(FOG_COMBINED_WITH_WORLD_POS) + UNITY_EXTRACT_FOG_FROM_WORLD_POS(i); + #else + UNITY_EXTRACT_FOG(i); + #endif + + SurfaceData o = CreateSurfaceData(); + MeshData d = CreateMeshData(i, facing); + half4 FinalColor = 1; + + // ExtraPass Fragment Chain + %FragmentFunctions + + // ExtraPass FragmentBase + %FragmentBase + + UNITY_APPLY_FOG(_unity_fogCoord, FinalColor); + + // ExtraPass Color Chain + %ColorFunctions + + return FinalColor; + } + + ENDCG + // ExtraPass Pass End +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/ToonExtraPass.orltemplate.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/ToonExtraPass.orltemplate.meta new file mode 100644 index 00000000..60d1de7e --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/ToonExtraPass.orltemplate.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 0212b04cfa84f4e48b0b12b984d2d368 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 2fa69a10b9c340b7b2eaa1b19e18bb6e, type: 3} diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFX.orltemplate b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFX.orltemplate index c60769bb..fdff6b16 100644 --- a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFX.orltemplate +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFX.orltemplate @@ -25,6 +25,120 @@ // PrePasses %PrePasses + // Exra PrePasses + %ExtraPrePasses + + %TemplateFeature("PrePass") + { + Pass + { + Tags { "LightMode" = "ForwardBase" %PassTags } + %PrePassModifiers + + // ForwardBase Depth PrePass Start + CGPROGRAM + #pragma target 4.5 + #pragma multi_compile_instancing + #pragma multi_compile_fwdbase + #pragma multi_compile_fog + #pragma shader_feature_local NEED_FOG + #pragma vertex Vertex + #pragma fragment Fragment + %ShaderFeatures + + #define UNITY_INSTANCED_LOD_FADE + #define UNITY_INSTANCED_SH + #define UNITY_INSTANCED_LIGHTMAPSTS + + #ifndef UNITY_PASS_FORWARDBASE + #define UNITY_PASS_FORWARDBASE + #endif + + // ShaderDefines + %ShaderDefines + // DataStructs + %DataStructs + // GlobalVariables + %GlobalVariables + + // Variables + %Variables + + // Textures + %Textures + + // PassFunctions + %PassFunctions + + // Functions + %Functions + + // Free Functions + %FreeFunctions + + // ForwardBase Depth PrePass Vertex + #if !defined(TESS_ENABLED) + FragmentData Vertex(VertexData v) + { + UNITY_SETUP_INSTANCE_ID(v); + FragmentData o; + UNITY_INITIALIZE_OUTPUT(FragmentData, o); + UNITY_TRANSFER_INSTANCE_ID(v, o); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + // ForwardBase Depth PrePass Vertex Chain + %VertexFunctions + + // ForwardBase Depth PrePass VertexBase + %VertexBase + + // ForwardBase Depth PrePass PostVertex Chain + %PostVertexFunctions + + return o; + } + #endif + + // ForwardBase Depth PrePass Fragment + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET + { + UNITY_SETUP_INSTANCE_ID(i); + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + #if defined(NEED_FOG) + #ifdef FOG_COMBINED_WITH_TSPACE + UNITY_EXTRACT_FOG_FROM_TSPACE(i); + #elif defined(FOG_COMBINED_WITH_WORLD_POS) + UNITY_EXTRACT_FOG_FROM_WORLD_POS(i); + #else + UNITY_EXTRACT_FOG(i); + #endif + #endif + + SurfaceData o = CreateSurfaceData(); + MeshData d = CreateMeshData(i, facing); + half4 FinalColor = 1; + + // ForwardBase Depth PrePass Fragment Chain + %FragmentFunctions + + // ForwardBase Depth PrePass FragmentBase + %FragmentBase + + #if defined(NEED_FOG) + UNITY_APPLY_FOG(_unity_fogCoord, FinalColor); + #endif + + // Final Color Chain + %PrePassColorFunctions + + return FinalColor; + } + + ENDCG + // ForwardBase Depth PrePass End + } + } + Pass { Tags { "LightMode" = "ForwardBase" %PassTags } @@ -39,6 +153,7 @@ #pragma shader_feature_local NEED_FOG #pragma vertex Vertex #pragma fragment Fragment + %ShaderFeatures #define UNITY_INSTANCED_LOD_FADE @@ -56,20 +171,23 @@ // GlobalVariables %GlobalVariables - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - // Variables %Variables // Textures %Textures + // PassFunctions + %PassFunctions + // Functions %Functions + // Free Functions + %FreeFunctions + // ForwardBase Vertex + #if !defined(TESS_ENABLED) FragmentData Vertex(VertexData v) { UNITY_SETUP_INSTANCE_ID(v); @@ -84,11 +202,19 @@ // ForwardBase VertexBase %VertexBase + // ForwardBase PostVertex Chain + %PostVertexFunctions + return o; } + #endif // ForwardBase Fragment - half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace + #if defined(NEED_SV_DEPTH) + , out float depth: SV_Depth + #endif + ) : SV_TARGET { UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); @@ -103,7 +229,7 @@ #endif SurfaceData o = CreateSurfaceData(); - MeshData d = CreateMeshData(i); + MeshData d = CreateMeshData(i, facing); half4 FinalColor = 1; // ForwardBase Fragment Chain @@ -126,6 +252,113 @@ // ForwardBase Pass End } + %TemplateFeature("ShadowCaster") + { + Pass + { + Tags { "LightMode" = "ShadowCaster" %PassTags } + %ShadowPassModifiers + + // ShadowCaster Pass Start + CGPROGRAM + #pragma target 4.5 + #pragma multi_compile_instancing + #pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2 + #pragma multi_compile_shadowcaster + #pragma vertex Vertex + #pragma fragment Fragment + %ShaderFeatures + + #define UNITY_INSTANCED_LOD_FADE + #define UNITY_INSTANCED_SH + #define UNITY_INSTANCED_LIGHTMAPSTS + + #ifndef UNITY_PASS_SHADOWCASTER + #define UNITY_PASS_SHADOWCASTER + #endif + + #include "UnityPBSLighting.cginc" + + // ShaderDefines + %ShaderDefines + // DataStructs + %DataStructs + // GlobalVariables + %GlobalVariables + + // Variables + %Variables + + // Textures + %Textures + + // PassFunctions + %PassFunctions + + // Functions + %Functions + + // Free Functions + %FreeFunctions + + // ShadowCaster Vertex + #if !defined(TESS_ENABLED) + FragmentData Vertex(VertexData v) + { + UNITY_SETUP_INSTANCE_ID(v); + FragmentData o; + UNITY_INITIALIZE_OUTPUT(FragmentData, o); + UNITY_TRANSFER_INSTANCE_ID(v, o); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + // ShadowCaster Vertex Chain + %VertexFunctions + + // ShadowCaster VertexBase + %VertexBase + + // ShadowCaster PostVertex Chain + %PostVertexFunctions + + TRANSFER_SHADOW_CASTER_NORMALOFFSET(o); + + return o; + } + #endif + + // ShadowCaster Fragment + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET + { + UNITY_SETUP_INSTANCE_ID(i); + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + + #if defined(NEED_FRAGMENT_IN_SHADOW) + SurfaceData o = CreateSurfaceData(); + MeshData d = CreateMeshData(i); + half4 FinalColor = 1; + + // ShadowCaster Fragment Chain + %FragmentFunctions + + FinalColor = 1; + + // ShadowCaster Color Chain + %ColorFunctions + #endif + + %ShadowFunctions + + SHADOW_CASTER_FRAGMENT(i); + } + + ENDCG + // ShadowCaster Pass End + } + } + + // Exra Passes + %ExtraPasses + // PostPasses %PostPasses } diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFXExtraPass.orltemplate b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFXExtraPass.orltemplate new file mode 100644 index 00000000..45a438e1 --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFXExtraPass.orltemplate @@ -0,0 +1,109 @@ +Pass +{ + Name %PassName + Tags { "LightMode" = "ForwardBase" %PassTags } + %PassModifiers + + // ExtraPass Pass Start + CGPROGRAM + #pragma target 4.5 + #pragma multi_compile_instancing + #pragma multi_compile_fwdbase + #pragma multi_compile_fog + #pragma shader_feature_local NEED_FOG + #pragma vertex Vertex + #pragma fragment Fragment + + %ShaderFeatures + + #define UNITY_INSTANCED_LOD_FADE + #define UNITY_INSTANCED_SH + #define UNITY_INSTANCED_LIGHTMAPSTS + + // ShaderDefines + %ShaderDefines + // DataStructs + %DataStructs + // GlobalVariables + %GlobalVariables + + #if defined(NEED_DEPTH) + UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); + #endif + + // Variables + %Variables + + // Textures + %Textures + + // PassFunctions + %PassFunctions + + // Functions + %Functions + + // Free Functions + %FreeFunctions + + // ExtraPass Vertex + #if !defined(TESS_ENABLED) + FragmentData Vertex(VertexData v) + { + UNITY_SETUP_INSTANCE_ID(v); + FragmentData o; + UNITY_INITIALIZE_OUTPUT(FragmentData, o); + UNITY_TRANSFER_INSTANCE_ID(v, o); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + // ExtraPass Vertex Chain + %VertexFunctions + + // ExtraPass VertexBase + %VertexBase + + // ForwardBase PostVertex Chain + %PostVertexFunctions + + return o; + } + #endif + + // ExtraPass Fragment + half4 Fragment(FragmentData i, bool facing: SV_IsFrontFace) : SV_TARGET + { + UNITY_SETUP_INSTANCE_ID(i); + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + #if defined(NEED_FOG) + #ifdef FOG_COMBINED_WITH_TSPACE + UNITY_EXTRACT_FOG_FROM_TSPACE(i); + #elif defined(FOG_COMBINED_WITH_WORLD_POS) + UNITY_EXTRACT_FOG_FROM_WORLD_POS(i); + #else + UNITY_EXTRACT_FOG(i); + #endif + #endif + + SurfaceData o = CreateSurfaceData(); + MeshData d = CreateMeshData(i, facing); + half4 FinalColor = 1; + + // ExtraPass Fragment Chain + %FragmentFunctions + + // ExtraPass FragmentBase + %FragmentBase + + #if defined(NEED_FOG) + UNITY_APPLY_FOG(_unity_fogCoord, FinalColor); + #endif + + // Final Color Chain + %ColorFunctions + + return FinalColor; + } + + ENDCG + // ExtraPass Pass End +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFXExtraPass.orltemplate.meta b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFXExtraPass.orltemplate.meta new file mode 100644 index 00000000..1709b38f --- /dev/null +++ b/Packages/sh.orels.shaders.generator/Runtime/Sources/Templates/VFXExtraPass.orltemplate.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 525697ccf22a41149932f65ea33d3c73 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 2fa69a10b9c340b7b2eaa1b19e18bb6e, type: 3} diff --git a/Packages/sh.orels.shaders.generator/package.json b/Packages/sh.orels.shaders.generator/package.json old mode 100644 new mode 100755 index d3ec78cc..2c023a14 --- a/Packages/sh.orels.shaders.generator/package.json +++ b/Packages/sh.orels.shaders.generator/package.json @@ -2,13 +2,14 @@ "name": "sh.orels.shaders.generator", "displayName": "ORL Shader Generator", "description": "A template-based shader generator utilizing scripted importers", - "version": "6.3.0", + "version": "7.0.0-dev.11", "unity": "2019.4", "author": { "name": "orels1", "url": "https://github.com/orels1" }, "documentationUrl": "https://shaders.orels.sh/docs/development", + "changelogUrl": "https://shaders.orels.sh/docs/changelog", "keywords": [ "shaders", "generator", diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/BakeryVolumeAssignerDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/BakeryVolumeAssignerDrawer.cs new file mode 100644 index 00000000..170ea91f --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/BakeryVolumeAssignerDrawer.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using ORL.ShaderInspector; +using UnityEditor; +using UnityEngine; +#if BAKERY_INCLUDED + +namespace ORL.Drawers +{ + public class BakeryVolumeAssignerDrawer : IDrawerFunc + { + public string FunctionName => "BakeryVolumeAssigner"; + + public string[] PersistentKeys => Array.Empty(); + + public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) + { + if (EditorGUI.indentLevel == -1) return true; + + var currentMaterial = editor.target as Material; + + var hasVolume = currentMaterial.GetTexture("_Volume0") != null; + var newVolume = EditorGUILayout.ObjectField(hasVolume ? "Assign New Volume" : "Assign Volume", null, typeof(BakeryVolume), true) as BakeryVolume; + + if (newVolume != null) + { + currentMaterial.SetTexture("_Volume0", newVolume.bakedTexture0); + currentMaterial.SetTexture("_Volume1", newVolume.bakedTexture1); + currentMaterial.SetTexture("_Volume2", newVolume.bakedTexture2); + currentMaterial.SetTexture("_VolumeMask", newVolume.bakedMask); + if (newVolume.bakedTexture3 != null) + { + currentMaterial.SetTexture("_Volume3", newVolume.bakedTexture3); + } + var bounds = newVolume.bounds; + currentMaterial.SetVector("_VolumeMin", bounds.min); + currentMaterial.SetVector("_VolumeInvSize", new Vector3(1.0f / bounds.size.x, 1.0f / bounds.size.y, 1.0f / bounds.size.z)); + } + + if (hasVolume) + { + if (GUILayout.Button("Unset Volume")) + { + currentMaterial.SetTexture("_Volume0", null); + currentMaterial.SetTexture("_Volume1", null); + currentMaterial.SetTexture("_Volume2", null); + currentMaterial.SetTexture("_Volume3", null); + currentMaterial.SetTexture("_VolumeMask", null); + currentMaterial.SetVector("_VolumeMin", Vector3.zero); + currentMaterial.SetVector("_VolumeInvSize", Vector3.one * 1000001); + } + } + + return true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/ResolverWindow.cs.meta b/Packages/sh.orels.shaders.inspector/Editor/Drawers/BakeryVolumeAssignerDrawer.cs.meta similarity index 83% rename from Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/ResolverWindow.cs.meta rename to Packages/sh.orels.shaders.inspector/Editor/Drawers/BakeryVolumeAssignerDrawer.cs.meta index fbfb6ef9..25c848cd 100644 --- a/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/ResolverWindow.cs.meta +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/BakeryVolumeAssignerDrawer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 32d2636186ee0834fa1dc2287750dd32 +guid: 412a73e8655d3c841bfa4968c924f8d5 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/CombineWithDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/CombineWithDrawer.cs index 4625ea60..95ceb594 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/Drawers/CombineWithDrawer.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/CombineWithDrawer.cs @@ -14,7 +14,7 @@ public class CombineWithDrawer : IDrawerFunc // Matches %CombineWith(PropNames); private Regex _matcher = new Regex(@"%CombineWith\(([\w]+),?\s?([\w]+)?,?\s?([\w]+)?\)"); - + private float _baseOffset = 5f * EditorGUIUtility.pixelsPerPoint; public string[] PersistentKeys => Array.Empty(); @@ -22,18 +22,18 @@ public class CombineWithDrawer : IDrawerFunc public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) { if (EditorGUI.indentLevel == -1) return true; - + var match = _matcher.Match(property.displayName); var strippedName = Utils.StripInternalSymbols(property.displayName); var groups = match.Groups.Cast().Where(g => !string.IsNullOrEmpty(g.Value)).ToList(); groups.RemoveAt(0); - + var baseRect = EditorGUILayout.GetControlRect(); var baseSize = baseRect.width / (groups.Count + 1); baseRect.width = baseSize; baseRect.width -= _baseOffset; - DrawElement(baseRect, editor, property); + DrawElement(baseRect, editor, property, index); var i = 1; foreach (var group in groups) @@ -48,24 +48,33 @@ public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, Material var newRect = baseRect; newRect.x += (baseSize) * i + _baseOffset; - DrawElement(newRect, editor, properties[propIndex]); + DrawElement(newRect, editor, properties[propIndex], propIndex); i++; } return true; } - private void DrawElement(Rect controlRect, MaterialEditor editor, MaterialProperty property) + private void DrawElement(Rect controlRect, MaterialEditor editor, MaterialProperty property, int index) { var localRect = controlRect; var name = Utils.StripInternalSymbols(property.displayName); var labelSize = EditorStyles.label.CalcSize(new GUIContent(name)); labelSize.x += _baseOffset; var labelRect = localRect; - labelRect.width = labelSize.x * EditorGUIUtility.pixelsPerPoint ; + labelRect.width = labelSize.x * EditorGUIUtility.pixelsPerPoint; + + var defaultProps = (editor.target as Material).shader.GetPropertyAttributes(index); + var enumAttribute = Array.Find(defaultProps, attr => attr.StartsWith("Enum(")); + + if (!string.IsNullOrWhiteSpace(enumAttribute)) + { + localRect.xMin += labelSize.x; + EditorGUI.LabelField(labelRect, name); + editor.ShaderProperty(localRect, property, new GUIContent("")); + return; + } - localRect.xMin += labelSize.x; - EditorGUI.LabelField(labelRect, name); - editor.ShaderProperty(localRect, property, new GUIContent("")); + editor.ShaderProperty(localRect, property, new GUIContent(name)); } } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/EnablePassDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/EnablePassDrawer.cs new file mode 100644 index 00000000..21141b9d --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/EnablePassDrawer.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; + +namespace ORL.Drawers +{ + public class EnablePassDrawer : IDrawerFunc + { + public string FunctionName => "EnablePass"; + + // Matches %EnablePass(LightMode) + private Regex _matcher = new Regex(@"%EnablePass\((?[\w]+)+\)"); + + public string[] PersistentKeys => Array.Empty(); + + public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) + { + if (EditorGUI.indentLevel == -1) return true; + + var match = _matcher.Match(property.displayName); + var lightMode = match.Groups["lightMode"].Value; + var currentValue = property.floatValue > 0; + + foreach (Material material in editor.targets) + { + if (material.GetShaderPassEnabled(lightMode) == currentValue) continue; + material.SetShaderPassEnabled(lightMode, currentValue); + } + + return next(); + } + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/EnablePassDrawer.cs.meta b/Packages/sh.orels.shaders.inspector/Editor/Drawers/EnablePassDrawer.cs.meta new file mode 100644 index 00000000..4a103e39 --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/EnablePassDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6885b95a59c5fd447bd49e71fb76c930 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/ForceRenderTypeDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/ForceRenderTypeDrawer.cs new file mode 100644 index 00000000..26ced6ab --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/ForceRenderTypeDrawer.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; + +namespace ORL.Drawers +{ + public class ForceRenderTypeDrawer : IDrawerFunc + { + public string FunctionName => "ForceRenderType"; + + // Matches %ForceRenderType(Type,Queue,CompatibleType1,CompatibleType2,CompatibleType3) + private Regex _matcher = new Regex(@"%ForceRenderType\((?[\w]+)+,?\s*(?[\w]+)?,?\s*(?[\w]+)?,?\s*(?[\w]+)?,?\s*(?[\w]+)?\)"); + + public string[] PersistentKeys => Array.Empty(); + + public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) + { + if (EditorGUI.indentLevel == -1) return true; + + var match = _matcher.Match(property.displayName); + var type = match.Groups["type"].Value; + if (string.IsNullOrWhiteSpace(type)) return next(); + + type = type.Trim().ToLower(); + + var queue = match.Groups["queue"].Value; + var compatibleType1 = match.Groups["compatibleType1"].Value; + var compatibleType2 = match.Groups["compatibleType2"].Value; + var compatibleType3 = match.Groups["compatibleType3"].Value; + queue = queue.Trim(); + compatibleType1 = compatibleType1.Trim().ToLower(); + compatibleType2 = compatibleType2.Trim().ToLower(); + compatibleType3 = compatibleType3.Trim().ToLower(); + + var cType1 = RenderTypeDrawer.GetRenderType(compatibleType1); + var cType2 = RenderTypeDrawer.GetRenderType(compatibleType2); + var cType3 = RenderTypeDrawer.GetRenderType(compatibleType3); + foreach (Material material in editor.targets) + { + // unforce type if unchecked + if (property.floatValue < 1) + { + var builtInOverride = material.shader.FindPassTagValue(0, new ShaderTagId("ORL_RenderType")); + if (builtInOverride != null && !string.IsNullOrWhiteSpace(builtInOverride.name)) + { + material.SetOverrideTag("ORL_RenderType", builtInOverride.name); + continue; + } + material.SetOverrideTag("ORL_RenderType", null); + continue; + // if (material.HasProperty("_RenderType")) + // { + // material.SetInt("_RenderType", -1); + // material.renderQueue = -1; + // } + // continue; + } + var currType = material.GetTag("ORL_RenderType", false); + if (string.IsNullOrWhiteSpace(currType) && material.HasProperty("_RenderType")) + { + var savedType = (RenderTypeDrawer.RenderType)material.GetInt("_RenderType"); + if (savedType == RenderTypeDrawer.GetRenderType(type)) continue; + if ((savedType == cType1 && compatibleType1 != string.Empty) || + (savedType == cType2 && compatibleType2 != string.Empty) || + (savedType == cType3 && compatibleType3 != string.Empty)) continue; + } + if (!string.IsNullOrWhiteSpace(currType)) + { + currType = currType.ToLower(); + if (currType == type) continue; + if (currType == compatibleType1 || currType == compatibleType2 || currType == compatibleType3) continue; + } + material.SetOverrideTag("ORL_RenderType", type.Substring(0, 1).ToUpper() + type.Substring(1)); + if (!string.IsNullOrWhiteSpace(queue) && int.TryParse(queue, out var queueValue)) + { + material.renderQueue = queueValue; + } + } + + return next(); + } + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/ForceRenderTypeDrawer.cs.meta b/Packages/sh.orels.shaders.inspector/Editor/Drawers/ForceRenderTypeDrawer.cs.meta new file mode 100644 index 00000000..c6f7681c --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/ForceRenderTypeDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 316aad9acd20a4047b6592422520143e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/GradientDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/GradientDrawer.cs index b8933828..c599c87a 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/Drawers/GradientDrawer.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/GradientDrawer.cs @@ -16,13 +16,13 @@ public class GradientDrawer : IDrawerFunc // Matches "Gradient((0,0,0,1), (1,1,1,1))" // Or "Gradient()" private Regex _matcher = new Regex(@"%Gradient\(((?\([\,\s\d]+\)),\s?(?\([\,\s\d]+\)))?\)"); - - public string[] PersistentKeys => new [] { "Gradient_" }; - + + public string[] PersistentKeys => new[] { "Gradient_" }; + public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) { if (EditorGUI.indentLevel == -1) return true; - + var match = _matcher.Match(property.displayName); var groups = match.Groups.Cast().Where(g => !string.IsNullOrEmpty(g.Value)).ToList(); groups.RemoveAt(0); @@ -43,14 +43,14 @@ public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, Material var color = val.Value.Trim('(', ')').Split(','); endColor = new Color(float.Parse(color[0]), float.Parse(color[1]), float.Parse(color[2]), float.Parse(color[3])); } - + var strippedName = Utils.StripInternalSymbols(property.displayName); var uiKey = "Gradient_" + strippedName; - var savedGradient = uiState.ContainsKey(uiKey) ? (Gradient) uiState[uiKey] : null; + var savedGradient = uiState.ContainsKey(uiKey) ? (Gradient)uiState[uiKey] : null; var hasSavedGradient = savedGradient != null; EditorGUI.BeginChangeCheck(); - + var baseRect = EditorGUILayout.GetControlRect(); var texRect = baseRect; texRect.width = 20f; @@ -60,8 +60,8 @@ public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, Material labelRect.width = Mathf.Min(150f, EditorStyles.label.CalcSize(new GUIContent(strippedName)).x + 20f * EditorGUIUtility.pixelsPerPoint); EditorGUI.LabelField(labelRect, strippedName); var gradRect = baseRect; - gradRect.xMin = EditorGUIUtility.labelWidth + 6.0f; - gradRect.width = EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth - 28f; + gradRect.xMin = EditorGUIUtility.labelWidth + 34.0f; + gradRect.width = EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth - 38f; gradRect.width /= 2f; gradRect.width -= 5f; Gradient grad; @@ -71,14 +71,15 @@ public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, Material if (hasSavedGradient) { oldGradCopy.SetKeys(savedGradient.colorKeys, savedGradient.alphaKeys); + oldGradCopy.mode = savedGradient.mode; } else { - oldGradCopy.SetKeys(new [] + oldGradCopy.SetKeys(new[] { new GradientColorKey(startColor, 0f), new GradientColorKey(endColor, 1f) - }, new [] + }, new[] { new GradientAlphaKey(startColor.a, 0), new GradientAlphaKey(endColor.a, 1) @@ -137,7 +138,7 @@ public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, Material } return true; } - + private Texture2D GenerateGradient(Gradient gradient) { var newTex = new Texture2D(256, 4, TextureFormat.RGBA32, false); @@ -187,5 +188,5 @@ private Texture2D SaveTexture(Texture2D generated, string matName, string stripp return exported; } } - + } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/HeaderDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/HeaderDrawer.cs index e407b23a..d9cdfb3c 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/Drawers/HeaderDrawer.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/HeaderDrawer.cs @@ -43,9 +43,9 @@ public bool OnGUI( var rect = EditorGUILayout.GetControlRect(); rect.yMax += 1f * EditorGUIUtility.pixelsPerPoint; rect.xMin -= 15f * EditorGUIUtility.pixelsPerPoint; - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER rect.xMin -= 15f * EditorGUIUtility.pixelsPerPoint; - #endif +#endif rect.xMax += 5f * EditorGUIUtility.pixelsPerPoint; var dividerRect = rect; dividerRect.y -= 1f; @@ -72,27 +72,27 @@ public bool OnGUI( switch (evt.type) { case EventType.Repaint: - { - if (expanded) { - Styles.FoldoutUnfolded.Draw(foldoutRect, "", false, false, true, false); - } - else - { - Styles.FoldoutFolded.Draw(foldoutRect, "", false, false, true, false); - } + if (expanded) + { + Styles.FoldoutUnfolded.Draw(foldoutRect, "", false, false, true, false); + } + else + { + Styles.FoldoutFolded.Draw(foldoutRect, "", false, false, true, false); + } - break; - } + break; + } case EventType.MouseDown: - { - if (rect.Contains(evt.mousePosition)) { - property.floatValue = property.floatValue > 0 ? 0 : 1; - } + if (rect.Contains(evt.mousePosition)) + { + property.floatValue = property.floatValue > 0 ? 0 : 1; + } - break; - } + break; + } } } @@ -102,6 +102,13 @@ public bool OnGUI( { return true; } + else if (matchLevel == 3) + { + EditorGUI.indentLevel = Mathf.Min(EditorGUI.indentLevel, 1); + var rect = EditorGUILayout.GetControlRect(); + rect.xMin -= 3f * EditorGUIUtility.pixelsPerPoint; + EditorGUI.LabelField(rect, filteredName, EditorStyles.miniBoldLabel); + } else { EditorGUI.indentLevel = Mathf.Min(EditorGUI.indentLevel, 1); diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/MapBaker.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/MapBaker.cs new file mode 100644 index 00000000..177e2ec7 --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/MapBaker.cs @@ -0,0 +1,294 @@ + +using System; +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; +using System.Text; +using UnityEngine.Experimental.Rendering; +using ORL.ShaderInspector; +using JetBrains.Annotations; + + + +#if ORL_SHADER_GENERATOR +using ORL.ShaderGenerator; +#endif + +namespace ORL.Drawers +{ + public static class MapBaker + { + public enum BakerChannel + { + Albedo, + Mask, + Normal + } + + private static Texture _openFolderIcon; + private static GUIStyle _openFolderIconStyle; + + internal static void DrawMapBaker(MaterialEditor editor, Material material, ref Dictionary uiState) + { +#if ORL_SHADER_GENERATOR + uiState.TryGetValue("bakePath", out var bakePathBoxed); + var bakePath = (string)bakePathBoxed; + + var currValue = (bool)uiState["mapBakerShown"]; + var newValue = Styles.DrawFoldoutHeader("Bake Texture Channels", currValue); + + if (currValue != newValue) + { + uiState["mapBakerShown"] = newValue; + editor.Repaint(); + } + + if (!newValue) return; + +#if UNITY_2022_1_OR_NEWER + // Unity 2022 is 1 more level nested + EditorGUI.indentLevel = 0; +#endif + + if (string.IsNullOrWhiteSpace(bakePath)) + { + bakePath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(material)).Replace("\\", "/"); + } + + { + if (_openFolderIcon == null) + { + _openFolderIcon = EditorGUIUtility.IconContent(EditorGUIUtility.isProSkin ? "d_FolderOpened Icon" : "FolderOpened Icon").image; + } + if (_openFolderIconStyle == null) + { +#if UNITY_2022_1_OR_NEWER + _openFolderIconStyle = new GUIStyle(EditorStyles.iconButton) +#else + _openFolderIconStyle = new GUIStyle(EditorStyles.miniButton) +#endif + { + alignment = TextAnchor.MiddleCenter, + margin = new RectOffset(0, 0, 2, 0) + }; + } + + + EditorGUILayout.LabelField("This tool allows you to bake down a shader-based effect into static textures.\nNot every effect will work correctly with this system, so feel free to experiment!", Styles.NoteTextStyle); + EditorGUILayout.Space(10); + + using (new EditorGUILayout.HorizontalScope()) + { + bakePath = EditorGUILayout.TextField("Bake Path", bakePath); + if (GUILayout.Button(_openFolderIcon, _openFolderIconStyle)) + { + bakePath = EditorUtility.OpenFolderPanel("select Bake Path", "Assets", null); + bakePath = "Assets" + bakePath.Replace(Application.dataPath, ""); + } + } + + EditorGUILayout.Space(); + + var materialName = material.name; + materialName = materialName.Replace("/", "").Replace("\\", ""); + + EditorGUILayout.LabelField("Bake Texture Channels", EditorStyles.boldLabel); + EditorGUILayout.LabelField("Bakes the selected channels into a new texture", Styles.NoteTextStyle); + + using (new EditorGUILayout.HorizontalScope()) + { + if (GUILayout.Button("Albedo")) + { + BakeMap(material, $"{bakePath}/{materialName}_Baked_Albedo.png", BakerChannel.Albedo); + } + if (GUILayout.Button("Masks")) + { + BakeMap(material, $"{bakePath}/{materialName}_Baked_Masks.png", BakerChannel.Mask); + } + if (GUILayout.Button("Normal")) + { + BakeMap(material, $"{bakePath}/{materialName}_Baked_Normal.png", BakerChannel.Normal); + } + } + + EditorGUILayout.Space(5); + + EditorGUILayout.LabelField("Bake PBR Material", EditorStyles.boldLabel); + EditorGUILayout.LabelField("Bakes all the channels into textures and creates a new ORL Standard PBR material with them assigned", Styles.NoteTextStyle); + EditorGUILayout.Space(5); + + if (GUILayout.Button("Bake Material", GUILayout.Height(25))) + { + BakeMap(material, $"{bakePath}/{materialName}_Baked_Albedo.png", BakerChannel.Albedo); + BakeMap(material, $"{bakePath}/{materialName}_Baked_Masks.png", BakerChannel.Mask); + BakeMap(material, $"{bakePath}/{materialName}_Baked_Normal.png", BakerChannel.Normal); + var pbrShader = Shader.Find("orels1/Standard"); + var pbrMaterial = new Material(pbrShader); + pbrMaterial.SetTexture("_MainTex", AssetDatabase.LoadAssetAtPath($"{bakePath}/{materialName}_Baked_Albedo.png")); + pbrMaterial.SetTexture("_MaskMap", AssetDatabase.LoadAssetAtPath($"{bakePath}/{materialName}_Baked_Masks.png")); + pbrMaterial.SetTexture("_BumpMap", AssetDatabase.LoadAssetAtPath($"{bakePath}/{materialName}_Baked_Normal.png")); + pbrMaterial.SetTexture("_DFG", AssetDatabase.LoadAssetAtPath("Packages/sh.orels.shaders.generator/Runtime/Assets/dfg-multiscatter.exr")); + var materialPath = $"{bakePath}/{materialName}_Baked_PBR.mat"; + if (File.Exists(materialPath)) + { + File.Delete(materialPath); + } + AssetDatabase.Refresh(); + AssetDatabase.CreateAsset(pbrMaterial, $"{bakePath}/{materialName}_Baked_PBR.mat"); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + } +#endif + } + +#if ORL_SHADER_GENERATOR + [PublicAPI] + public static void BakeMap(Material material, string bakePath, BakerChannel channel) + { + var shaderPath = AssetDatabase.GetAssetPath(material.shader); + var importer = AssetImporter.GetAtPath(shaderPath); + + // Only show the baker if the shader is generated + if (importer is ShaderDefinitionImporter shaderImporter) + { + // Set up the correct lighting model for map extraction + var shaderText = File.ReadAllLines(shaderPath); + var parser = new Parser(); + var blocks = parser.Parse(shaderText); + + var lightingModelIndex = blocks.FindIndex(b => b.Name == "%LightingModel"); + if (lightingModelIndex == -1) + { + blocks.Insert(0, new ShaderBlock + { + Name = "%LightingModel", + Params = new List() + { + "\"@/LightingModels/MapBaker\"" + }, + Order = -1, + Contents = new List() + }); + } + else + { + blocks[lightingModelIndex].Params[0] = "\"@/LightingModels/MapBaker\""; + } + + var shaderNameBlockIndex = blocks.FindIndex(b => b.Name == "%ShaderName"); + if (shaderNameBlockIndex != -1) + { + blocks[shaderNameBlockIndex].Params[0] = $"\"Hidden/orels1/MapBaker\""; + } + + // Construct the new baker shader + try + { + if (!Directory.Exists("Assets/orels1_TempAssets")) + { + Directory.CreateDirectory("Assets/orels1_TempAssets"); + } + + var newShaderBuilder = new StringBuilder(); + + foreach (var block in blocks) + { + newShaderBuilder.AppendLine(); + newShaderBuilder.Append(block.Name); + newShaderBuilder.Append("("); + newShaderBuilder.Append(string.Join(", ", block.Params)); + if (block.Order != -1) + { + newShaderBuilder.Append(", "); + newShaderBuilder.Append(block.Order); + } + newShaderBuilder.Append(")"); + newShaderBuilder.AppendLine("{"); + foreach (var line in block.Contents) + { + newShaderBuilder.AppendLine(line); + } + newShaderBuilder.AppendLine("}"); + } + + File.WriteAllText("Assets/orels1_TempAssets/Baker.orlshader", newShaderBuilder.ToString()); + AssetDatabase.Refresh(); + + var clonedMaterial = new Material(material) + { +#if UNITY_2022_1_OR_NEWER + parent = null +#endif + }; + + AssetDatabase.CreateAsset(clonedMaterial, "Assets/orels1_TempAssets/Baker_mat_temp.mat"); + var bakerShader = AssetDatabase.LoadAssetAtPath("Assets/orels1_TempAssets/Baker.orlshader"); + clonedMaterial.shader = bakerShader; + clonedMaterial.SetInt("_BakerChannel", (int)channel); + + var source = clonedMaterial.GetTexture("_MainTex"); + var shouldDestroySource = false; + if (source == null) + { + source = new Texture2D(4096, 4096, TextureFormat.RGBA32, true); + shouldDestroySource = true; + } + var target = new Texture2D(4096, 4096, TextureFormat.RGBA32, true); + RenderTexture buffer; + if (channel == BakerChannel.Normal) + { +#if UNITY_2022_1_OR_NEWER + buffer = new RenderTexture(4096, 4096, GraphicsFormat.R16G16B16A16_UNorm, GraphicsFormat.D24_UNorm_S8_UInt); +#else + buffer = new RenderTexture(4096, 4096, 24, RenderTextureFormat.ARGB64); +#endif + } + else + { + buffer = new RenderTexture(4096, 4096, 24, DefaultFormat.LDR); + } + clonedMaterial.SetVector("__MapBaker_MainTex_ST", material.GetVector("_MainTex_ST")); + Graphics.Blit(source, buffer, clonedMaterial); + RenderTexture.active = buffer; + target.ReadPixels(new Rect(0, 0, 4096, 4096), 0, 0); + target.Apply(); + RenderTexture.active = null; + if (shouldDestroySource) + { + Object.DestroyImmediate(source); + } + Object.DestroyImmediate(buffer); + + var final = target.EncodeToPNG(); + if (File.Exists(bakePath)) + { + File.Delete(bakePath); + } + File.WriteAllBytes(bakePath, final); + Object.DestroyImmediate(target); + Directory.Delete("Assets/orels1_TempAssets", true); + File.Delete("Assets/orels1_TempAssets.meta"); + AssetDatabase.Refresh(); + + if (channel == BakerChannel.Normal) + { + var textureImporter = AssetImporter.GetAtPath(bakePath) as TextureImporter; + textureImporter.textureType = TextureImporterType.NormalMap; + textureImporter.SaveAndReimport(); + } + } + catch (Exception ex) + { + Debug.LogError("Failed to build the baker shader: " + ex.Message); + Debug.LogException(ex); + } + } + } + + } +#endif + +} diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/MapBaker.cs.meta b/Packages/sh.orels.shaders.inspector/Editor/Drawers/MapBaker.cs.meta new file mode 100644 index 00000000..0aac9721 --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/MapBaker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 839410f2c2131924dae992ffda34fcc4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/RemapSliderDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/RemapSliderDrawer.cs index 59fc3ee0..1f18a0c2 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/Drawers/RemapSliderDrawer.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/RemapSliderDrawer.cs @@ -14,13 +14,13 @@ public class RemapSliderDrawer : IDrawerFunc // Matches "RemapSlider(0, 1)" private Regex _matcher = new Regex(@"%RemapSlider\(([\d]+),?\s?([\d]+)+\)"); - + public string[] PersistentKeys => Array.Empty(); - + public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) { if (EditorGUI.indentLevel == -1) return true; - + var match = _matcher.Match(property.displayName); var groups = match.Groups.Cast().Where(g => !string.IsNullOrEmpty(g.Value)).ToList(); groups.RemoveAt(0); @@ -31,13 +31,13 @@ public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, Material var currValue = property.vectorValue; var strippedName = Utils.StripInternalSymbols(property.displayName); - + var baseRect = EditorGUILayout.GetControlRect(); var maxSliderSize = baseRect.width * 0.62f; var labelRect = baseRect; labelRect.width = EditorStyles.label.CalcSize(new GUIContent(strippedName)).x + 20f * EditorGUIUtility.pixelsPerPoint; - baseRect.x = EditorGUIUtility.labelWidth + 6.0f; - baseRect.width = EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth - 28f; + baseRect.x = EditorGUIUtility.labelWidth + 36.0f; + baseRect.width = EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth - 42f; EditorGUI.BeginChangeCheck(); EditorGUI.LabelField(labelRect, strippedName); diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/RenderTypeDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/RenderTypeDrawer.cs new file mode 100644 index 00000000..e4914a00 --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/RenderTypeDrawer.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using ORL.ShaderInspector; +using UnityEditor; +using UnityEngine; + +namespace ORL.Drawers +{ + /// + /// Overrides an editor with a dropdown to select a render type + /// The desired render parameters are passed to specified properties + /// + public class RenderTypeDrawer : IDrawerFunc + { + public string FunctionName => "RenderType"; + + internal enum RenderType + { + Opaque, + Cutout, + Transparent, + Fade, + Custom, + } + + internal static RenderType GetRenderType(string type) + { + switch (type.ToLower()) + { + case "opaque": return RenderType.Opaque; + case "cutout": return RenderType.Cutout; + case "transparent": return RenderType.Transparent; + case "fade": return RenderType.Fade; + case "custom": return RenderType.Custom; + default: return RenderType.Opaque; + } + } + + private struct MaterialPropertyData + { + public string BlendOpProp; + public string SrcBlendProp; + public string DstBlendProp; + public string BlendOpAlphaProp; + public string SrcBlendAlphaProp; + public string DstBlendAlphaProp; + public string ZWriteProp; + } + + // Matches %RenderType(BlendOp, SrcBlend, DstBlend, BlendOpAlpha, SrcBlendAlpha, DstBlendAlpha, ZWrite) + private Regex _matcher = new Regex(@"%RenderType\((?\w+)\s*,\s*(?\w+)\s*,\s*(?\w+)\s*,\s*(?\w+)\s*,\s*(?\w+)\s*,\s*(?\w+)\s*,\s*(?\w+)\s*\)"); + + public string[] PersistentKeys => Array.Empty(); + + public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, + ref Dictionary uiState, Func next) + { + if (EditorGUI.indentLevel == -1) return true; + + var match = _matcher.Match(property.displayName); + + if (!match.Success) return next(); + var targetMaterial = (Material)editor.target; + + var propertyData = new MaterialPropertyData + { + BlendOpProp = match.Groups["blendOp"].Value, + SrcBlendProp = match.Groups["srcBlend"].Value, + DstBlendProp = match.Groups["dstBlend"].Value, + BlendOpAlphaProp = match.Groups["blendOpAlpha"].Value, + SrcBlendAlphaProp = match.Groups["srcBlendAlpha"].Value, + DstBlendAlphaProp = match.Groups["dstBlendAlpha"].Value, + ZWriteProp = match.Groups["zwrite"].Value + }; + + var savedRenderType = (int)property.floatValue; + + var currentRenderType = savedRenderType == -1 ? RenderType.Opaque : (RenderType)savedRenderType; + + var presetTag = targetMaterial.GetTag("ORL_RenderType", false); + var isForcedType = !string.IsNullOrWhiteSpace(presetTag); + RenderType forcedRenderType = RenderType.Custom; + + switch (presetTag.ToLower()) + { + case "opaque": + forcedRenderType = RenderType.Opaque; + break; + case "cutout": + forcedRenderType = RenderType.Cutout; + break; + case "transparent": + forcedRenderType = RenderType.Transparent; + break; + case "fade": + forcedRenderType = RenderType.Fade; + break; + case "custom": + forcedRenderType = RenderType.Custom; + break; + } + + RenderType newRenderType; + + using (var c = new EditorGUI.ChangeCheckScope()) + { + newRenderType = (RenderType)EditorGUILayout.Popup("RenderType", (int)currentRenderType, new[] { + "Opaque", + "Cutout", + "Transparent", + "Fade", + "Custom" + }); + if (c.changed) + { + property.floatValue = (float)newRenderType; + if (!IsMaterialSetUpForRenderType(targetMaterial, propertyData, newRenderType) || newRenderType != currentRenderType) + { + SetRenderType(targetMaterial, newRenderType, propertyData, property); + } + } + } + + if (isForcedType) + { + EditorGUILayout.LabelField("Render type prefered by current shader: " + Enum.GetName(typeof(RenderType), forcedRenderType), Styles.NoteTextStyle); + if (!IsMaterialSetUpForRenderType(targetMaterial, propertyData, newRenderType) && savedRenderType == -1) + { + SetRenderType(targetMaterial, currentRenderType, propertyData, property); + } + return true; + } + + return true; + } + + private void SetRenderType(Material targetMaterial, RenderType renderType, MaterialPropertyData propData, MaterialProperty property) + { + Undo.RecordObject(targetMaterial, "Adjusted RenderType"); + switch (renderType) + { + case RenderType.Opaque: + targetMaterial.SetOverrideTag("RenderType", "Opaque"); + targetMaterial.SetInt(propData.SrcBlendProp, (int)UnityEngine.Rendering.BlendMode.One); + targetMaterial.SetInt(propData.DstBlendProp, (int)UnityEngine.Rendering.BlendMode.Zero); + targetMaterial.SetInt(propData.BlendOpProp, (int)UnityEngine.Rendering.BlendOp.Add); + targetMaterial.SetInt(propData.SrcBlendAlphaProp, (int)UnityEngine.Rendering.BlendMode.One); + targetMaterial.SetInt(propData.DstBlendAlphaProp, (int)UnityEngine.Rendering.BlendMode.Zero); + targetMaterial.SetInt(propData.BlendOpAlphaProp, (int)UnityEngine.Rendering.BlendOp.Add); + targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry; + targetMaterial.SetInt(propData.ZWriteProp, 1); + break; + case RenderType.Cutout: + targetMaterial.SetOverrideTag("RenderType", "TransparentCutout"); + targetMaterial.SetInt(propData.SrcBlendProp, (int)UnityEngine.Rendering.BlendMode.One); + targetMaterial.SetInt(propData.DstBlendProp, (int)UnityEngine.Rendering.BlendMode.Zero); + targetMaterial.SetInt(propData.BlendOpProp, (int)UnityEngine.Rendering.BlendOp.Add); + targetMaterial.SetInt(propData.SrcBlendAlphaProp, (int)UnityEngine.Rendering.BlendMode.One); + targetMaterial.SetInt(propData.DstBlendAlphaProp, (int)UnityEngine.Rendering.BlendMode.Zero); + targetMaterial.SetInt(propData.BlendOpAlphaProp, (int)UnityEngine.Rendering.BlendOp.Add); + targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest; + targetMaterial.SetInt(propData.ZWriteProp, 1); + break; + case RenderType.Transparent: + targetMaterial.SetOverrideTag("RenderType", "Transparent"); + targetMaterial.SetInt(propData.SrcBlendProp, (int)UnityEngine.Rendering.BlendMode.One); + targetMaterial.SetInt(propData.DstBlendProp, (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + targetMaterial.SetInt(propData.BlendOpProp, (int)UnityEngine.Rendering.BlendOp.Add); + targetMaterial.SetInt(propData.SrcBlendAlphaProp, (int)UnityEngine.Rendering.BlendMode.One); + targetMaterial.SetInt(propData.DstBlendAlphaProp, (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + targetMaterial.SetInt(propData.BlendOpAlphaProp, (int)UnityEngine.Rendering.BlendOp.Add); + targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; + targetMaterial.SetInt(propData.ZWriteProp, 0); + break; + case RenderType.Fade: + targetMaterial.SetOverrideTag("RenderType", "Transparent"); + targetMaterial.SetInt(propData.SrcBlendProp, (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + targetMaterial.SetInt(propData.DstBlendProp, (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + targetMaterial.SetInt(propData.BlendOpProp, (int)UnityEngine.Rendering.BlendOp.Add); + targetMaterial.SetInt(propData.SrcBlendAlphaProp, (int)UnityEngine.Rendering.BlendMode.One); + targetMaterial.SetInt(propData.DstBlendAlphaProp, (int)UnityEngine.Rendering.BlendMode.One); + targetMaterial.SetInt(propData.BlendOpAlphaProp, (int)UnityEngine.Rendering.BlendOp.Max); + targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; + targetMaterial.SetInt(propData.ZWriteProp, 0); + break; + case RenderType.Custom: + break; + } + } + + private bool IsMaterialSetUpForRenderType(Material targetMaterial, MaterialPropertyData propData, RenderType renderType) + { + switch (renderType) + { + case RenderType.Opaque: + return targetMaterial.GetInt(propData.SrcBlendProp) == (int)UnityEngine.Rendering.BlendMode.One && + targetMaterial.GetInt(propData.DstBlendProp) == (int)UnityEngine.Rendering.BlendMode.Zero && + targetMaterial.GetInt(propData.BlendOpProp) == (int)UnityEngine.Rendering.BlendOp.Add && + targetMaterial.GetInt(propData.SrcBlendAlphaProp) == (int)UnityEngine.Rendering.BlendMode.One && + targetMaterial.GetInt(propData.DstBlendAlphaProp) == (int)UnityEngine.Rendering.BlendMode.Zero && + targetMaterial.GetInt(propData.BlendOpAlphaProp) == (int)UnityEngine.Rendering.BlendOp.Add && + targetMaterial.renderQueue > -1 && targetMaterial.renderQueue <= ((int)UnityEngine.Rendering.RenderQueue.AlphaTest) - 1; + // targetMaterial.GetInt(propData.ZWriteProp) == 1; + case RenderType.Cutout: + return targetMaterial.GetInt(propData.SrcBlendProp) == (int)UnityEngine.Rendering.BlendMode.One && + targetMaterial.GetInt(propData.DstBlendProp) == (int)UnityEngine.Rendering.BlendMode.Zero && + targetMaterial.GetInt(propData.BlendOpProp) == (int)UnityEngine.Rendering.BlendOp.Add && + targetMaterial.GetInt(propData.SrcBlendAlphaProp) == (int)UnityEngine.Rendering.BlendMode.One && + targetMaterial.GetInt(propData.DstBlendAlphaProp) == (int)UnityEngine.Rendering.BlendMode.Zero && + targetMaterial.GetInt(propData.BlendOpAlphaProp) == (int)UnityEngine.Rendering.BlendOp.Add && + targetMaterial.renderQueue >= (int)UnityEngine.Rendering.RenderQueue.AlphaTest && targetMaterial.renderQueue <= ((int)UnityEngine.Rendering.RenderQueue.GeometryLast); + // targetMaterial.GetInt(propData.ZWriteProp) == 1; + case RenderType.Transparent: + return targetMaterial.GetInt(propData.SrcBlendProp) == (int)UnityEngine.Rendering.BlendMode.One && + targetMaterial.GetInt(propData.DstBlendProp) == (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha && + targetMaterial.GetInt(propData.BlendOpProp) == (int)UnityEngine.Rendering.BlendOp.Add && + targetMaterial.GetInt(propData.SrcBlendAlphaProp) == (int)UnityEngine.Rendering.BlendMode.One && + targetMaterial.GetInt(propData.DstBlendAlphaProp) == (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha && + targetMaterial.GetInt(propData.BlendOpAlphaProp) == (int)UnityEngine.Rendering.BlendOp.Add && + targetMaterial.renderQueue > ((int)UnityEngine.Rendering.RenderQueue.GeometryLast) + 1 && targetMaterial.renderQueue <= ((int)UnityEngine.Rendering.RenderQueue.Overlay) - 1; + // targetMaterial.GetInt(propData.ZWriteProp) == 0; + case RenderType.Fade: + return targetMaterial.GetInt(propData.SrcBlendProp) == (int)UnityEngine.Rendering.BlendMode.SrcAlpha && + targetMaterial.GetInt(propData.DstBlendProp) == (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha && + targetMaterial.GetInt(propData.BlendOpProp) == (int)UnityEngine.Rendering.BlendOp.Add && + targetMaterial.GetInt(propData.SrcBlendAlphaProp) == (int)UnityEngine.Rendering.BlendMode.One && + targetMaterial.GetInt(propData.DstBlendAlphaProp) == (int)UnityEngine.Rendering.BlendMode.One && + targetMaterial.GetInt(propData.BlendOpAlphaProp) == (int)UnityEngine.Rendering.BlendOp.Max && + targetMaterial.renderQueue > ((int)UnityEngine.Rendering.RenderQueue.GeometryLast) + 1 && targetMaterial.renderQueue <= ((int)UnityEngine.Rendering.RenderQueue.Overlay) - 1; + // targetMaterial.GetInt(propData.ZWriteProp) == 0; + case RenderType.Custom: + return true; + } + + return false; + } + + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/RenderTypeDrawer.cs.meta b/Packages/sh.orels.shaders.inspector/Editor/Drawers/RenderTypeDrawer.cs.meta new file mode 100644 index 00000000..b2af4277 --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/RenderTypeDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c32b0fb186e56c94999455400b06d2bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/RequiredTextureDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/RequiredTextureDrawer.cs index 736eca93..1bba0dba 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/Drawers/RequiredTextureDrawer.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/RequiredTextureDrawer.cs @@ -7,16 +7,16 @@ namespace ORL.Drawers { - public class RequiredTextureDrawer: IDrawerFunc + public class RequiredTextureDrawer : IDrawerFunc { public string FunctionName => "RequiredTexture"; - + // Matches %RequiredTexture(TexPath); private Regex _matcher = new Regex(@"(?<=[\w\s\>\s]+)\%RequiredTexture\((?[\w\,\s\&\|\(\)\!\<\>\=\$\/\-\.\@]+)\)"); private string _savedPath; private Texture2D _savedTex; - + public string[] PersistentKeys => Array.Empty(); public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) @@ -34,14 +34,21 @@ public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, Material return EditorGUI.indentLevel == -1 || next(); } - + private Texture2D FetchTex(string texPath) { var cleaned = texPath.Replace("@/", "Packages/sh.orels.shaders.generator/Runtime/Assets/"); var tex = AssetDatabase.LoadAssetAtPath(cleaned); if (tex == null) { - Debug.LogError($"Could not find texture at path {cleaned}"); + var cleaned2 = texPath.Replace("@/", "Packages/sh.orels.shaders/Runtime/Assets/"); + tex = AssetDatabase.LoadAssetAtPath(cleaned2); + + if (tex == null) + { + Debug.LogError($"Could not find texture at path {cleaned} or {cleaned2}"); + } + } return tex; diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/SeparatorDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/SeparatorDrawer.cs new file mode 100644 index 00000000..fac0ae96 --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/SeparatorDrawer.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; + +namespace ORL.Drawers +{ + public class SeparatorDrawer : IDrawer + { + private Regex _matcher = new Regex(@"^---"); + public bool MatchDrawer(MaterialProperty property) + { + return _matcher.IsMatch(property.displayName); + } + + public string[] PersistentKeys => Array.Empty(); + + public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) + { + if (EditorGUI.indentLevel == -1) return true; + + EditorGUILayout.Space(8); + var rect = EditorGUILayout.GetControlRect(GUILayout.Height(1)); + rect.xMin += 1; + EditorGUI.DrawRect(rect, new Color(0.5f, 0.5f, 0.5f, 1)); + + return true; + } + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/SeparatorDrawer.cs.meta b/Packages/sh.orels.shaders.inspector/Editor/Drawers/SeparatorDrawer.cs.meta new file mode 100644 index 00000000..fd878bd4 --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/SeparatorDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 844280f21e6524a438f59f864991b053 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/SetKeywordDrawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/SetKeywordDrawer.cs index 9522809e..a6040067 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/Drawers/SetKeywordDrawer.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/SetKeywordDrawer.cs @@ -6,19 +6,19 @@ namespace ORL.Drawers { - public class SetKeywordDrawer: IDrawerFunc + public class SetKeywordDrawer : IDrawerFunc { public string FunctionName => "SetKeyword"; - + // Matches %SetKeyword(_TextureVar, KEYWORD_NAME) private Regex _matcher = new Regex(@"%SetKeyword\((?[\w]+)+,\s*(?[\w]+)\)"); - + public string[] PersistentKeys => Array.Empty(); public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) { if (EditorGUI.indentLevel == -1) return true; - + var match = _matcher.Match(property.displayName); var keyword = match.Groups["keyword"].Value; var texture = match.Groups["texture"].Value; diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/TexturePacker.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/TexturePacker.cs index 7572cfa7..4c3b03d1 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/Drawers/TexturePacker.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/TexturePacker.cs @@ -4,6 +4,7 @@ using ORL.ShaderInspector; using UnityEditor; using UnityEngine; +using UnityEngine.Experimental.Rendering; namespace ORL.Drawers { @@ -28,7 +29,7 @@ public static class TexturePacker "2048", "4096" }; - + public static bool DrawPacker(Rect position, bool visible, ref Dictionary uiState, string uiKey, Material material, MaterialProperty property, MaterialEditor materialEditor) { if (EditorGUI.indentLevel == -1) return visible; @@ -43,34 +44,34 @@ public static bool DrawPacker(Rect position, bool visible, ref Dictionary(texFieldRect, label, currTex); + currTex = (Texture2D)Styles.DrawSingleLineTextureGUI(texFieldRect, label, currTex); var dropdownRect = rowRect; dropdownRect.xMin += 70; dropdownRect.xMax = dropdownRect.xMin + 30; - currChannel = EditorGUI.Popup(dropdownRect, currChannel, new []{ + currChannel = EditorGUI.Popup(dropdownRect, currChannel, new[]{ new GUIContent("R", $"Fills the {label} channel of the packed texture with values from the Red channel of the source texture"), new GUIContent("G", $"Fills the {label} channel of the packed texture with values from the Green channel of the source texture"), new GUIContent("B", $"Fills the {label} channel of the packed texture with values from the Blue channel of the source texture"), @@ -161,7 +168,7 @@ private static void DrawPackerRow(string label, ref Texture2D currTex, ref int c EditorGUIUtility.labelWidth = 15; using (new EditorGUI.DisabledScope(currTex != null)) { - currValue = EditorGUI.Slider(sliderRect, new GUIContent("V","Fill Value. This channel will be filled uniformly with this value"), currValue, 0, 1); + currValue = EditorGUI.Slider(sliderRect, new GUIContent("V", "Fill Value. This channel will be filled uniformly with this value"), currValue, 0, 1); } EditorGUIUtility.fieldWidth = oldWidth; var invertRect = rowRect; @@ -172,14 +179,14 @@ private static void DrawPackerRow(string label, ref Texture2D currTex, ref int c } } - public static Texture2D PackTexture(Texture2D[] textures, int[] channels, float[] values, bool[] inverts, bool isLinear, int size, string savePath) + public static Texture2D PackTexture(Texture2D[] textures, int[] channels, float[] values, bool[] inverts, bool[] isSourceLinear, bool isLinear, int size, string savePath) { var rawTextures = new Texture2D[4]; for (int i = 0; i < rawTextures.Length; i++) { if (textures[i] == null) continue; var channelTexPath = AssetDatabase.GetAssetPath(textures[i]); - var tex = new Texture2D(4, 4, TextureFormat.RGBA32, false, true); + var tex = new Texture2D(4, 4, TextureFormat.RGBA64, false, isSourceLinear[i]); tex.LoadImage(File.ReadAllBytes(channelTexPath)); rawTextures[i] = tex; } @@ -197,8 +204,12 @@ public static Texture2D PackTexture(Texture2D[] textures, int[] channels, float[ SetPackerPropsForChannel("Alpha", ref mat, textures[3], channels[3], values[3], inverts[3]); mat.SetInt("_IsLinear", isLinear ? 1 : 0); var source = new Texture2D(size, size); - var buffer = new RenderTexture(size, size, 24, RenderTextureFormat.ARGB32); - var target = new Texture2D(size, size, TextureFormat.ARGB32, true); +#if UNITY_2022_1_OR_NEWER + var buffer = new RenderTexture(size, size, GraphicsFormat.R16G16B16A16_UNorm, GraphicsFormat.D24_UNorm_S8_UInt); +#else + var buffer = new RenderTexture(size, size, 24, RenderTextureFormat.ARGB64); +#endif + var target = new Texture2D(size, size, TextureFormat.RGBA64, true); Graphics.Blit(source, buffer, mat); RenderTexture.active = buffer; target.ReadPixels(new Rect(0, 0, size, size), 0, 0); diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/Vector2Drawer.cs b/Packages/sh.orels.shaders.inspector/Editor/Drawers/Vector2Drawer.cs new file mode 100644 index 00000000..92ae899c --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/Vector2Drawer.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using ORL.ShaderInspector; +using UnityEditor; +using UnityEngine; + +namespace ORL.Drawers +{ + public class Vector2Drawer : IDrawerFunc + { + public string FunctionName => "Vector2"; + + // Matches "RemapSlider(0, 1)" + private Regex _matcher = new Regex(@"%Vector2\(([\w\s]+),?\s?([\w\s]+)+\)"); + + private float _baseOffset = 5f * EditorGUIUtility.pixelsPerPoint; + + public string[] PersistentKeys => Array.Empty(); + + public bool OnGUI(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index, ref Dictionary uiState, Func next) + { + if (EditorGUI.indentLevel == -1) return true; + var match = _matcher.Match(property.displayName); + var groups = match.Groups.Cast().Where(g => !string.IsNullOrEmpty(g.Value)).ToList(); + groups.RemoveAt(0); + + var label1 = groups[0].Value; + var label2 = groups[1].Value; + + + var baseRect = EditorGUILayout.GetControlRect(); + var baseSize = baseRect.width / 2.0f; + + baseRect.width = baseSize; + baseRect.width -= _baseOffset; + var currentValue = property.vectorValue; + + currentValue.x = EditorGUI.FloatField(baseRect, new GUIContent(label1), currentValue.x); + + var newRect = baseRect; + newRect.x += baseSize + _baseOffset; + currentValue.y = EditorGUI.FloatField(newRect, new GUIContent(label2), currentValue.y); + + property.vectorValue = currentValue; + return true; + } + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders.inspector/Editor/Drawers/Vector2Drawer.cs.meta b/Packages/sh.orels.shaders.inspector/Editor/Drawers/Vector2Drawer.cs.meta new file mode 100644 index 00000000..9075c81b --- /dev/null +++ b/Packages/sh.orels.shaders.inspector/Editor/Drawers/Vector2Drawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 278e53e322b19a94d9cde1a0a0203c26 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders.inspector/Editor/InspectorGUI.cs b/Packages/sh.orels.shaders.inspector/Editor/InspectorGUI.cs index 2d060929..9605b7cb 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/InspectorGUI.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/InspectorGUI.cs @@ -10,7 +10,6 @@ using UnityEditor; using UnityEngine; using UnityEngine.Rendering; -using Object = UnityEngine.Object; namespace ORL.ShaderInspector { @@ -28,19 +27,18 @@ public class InspectorGUI : ShaderGUI private Dictionary _drawerFuncs; private Dictionary _uiState; + private GUIStyle _searchClearStyle; private bool _initialized; private List _shaderFeatures; private List _multiCompiles; - + #region State Management - private string[] _persistedKeys = new[] { "debugShown" }; + private string[] _persistedKeys = new[] { "debugShown", "mapBakerShown" }; private void Initialize(MaterialEditor materialEditor, MaterialProperty[] properties) { - Styles.InitTextureStyles(); - // fill in our own stuff _drawers = Assembly .GetAssembly(typeof(IDrawer)).GetTypes() @@ -69,9 +67,12 @@ private void Initialize(MaterialEditor materialEditor, MaterialProperty[] proper var shaderSourcePath = AssetDatabase.GetAssetPath((materialEditor.target as Material).shader); string[] shaderSource; - if (shaderSourcePath.EndsWith(".orlshader")) { + if (shaderSourcePath.EndsWith(".orlshader")) + { shaderSource = AssetDatabase.LoadAllAssetsAtPath(shaderSourcePath).OfType().First().text.Split('\n'); - } else { + } + else + { shaderSource = File.ReadAllLines(Application.dataPath.Replace("\\", "/").Replace("Assets", "") + shaderSourcePath); } @@ -118,6 +119,10 @@ private void Initialize(MaterialEditor materialEditor, MaterialProperty[] proper { _uiState.Add("debugShown", false); } + if (!_uiState.ContainsKey("mapBakerShown")) + { + _uiState.Add("mapBakerShown", false); + } foreach (var prop in properties) { @@ -129,22 +134,22 @@ private void Initialize(MaterialEditor materialEditor, MaterialProperty[] proper _uiState.Add(packerKey + "_blue_tex", prop.textureValue); _uiState.Add(packerKey + "_green_tex", prop.textureValue); _uiState.Add(packerKey + "_alpha_tex", prop.textureValue); - + _uiState.Add(packerKey + "_red_channel", 0); _uiState.Add(packerKey + "_green_channel", 1); _uiState.Add(packerKey + "_blue_channel", 2); - _uiState.Add(packerKey + "_alpha_channel", 3); - + _uiState.Add(packerKey + "_alpha_channel", 0); + _uiState.Add(packerKey + "_red_val", 1f); _uiState.Add(packerKey + "_blue_val", 1f); _uiState.Add(packerKey + "_green_val", 1f); _uiState.Add(packerKey + "_alpha_val", 1f); - + _uiState.Add(packerKey + "_red_invert", false); _uiState.Add(packerKey + "_blue_invert", false); _uiState.Add(packerKey + "_green_invert", false); _uiState.Add(packerKey + "_alpha_invert", false); - + _uiState.Add(packerKey + "_size", 2048); _uiState.Add(packerKey + "_linear", false); _uiState.Add(packerKey + "_name", materialEditor.target.name + "_" + Utils.StripInternalSymbols(prop.displayName).Trim() + "_packed"); @@ -153,7 +158,7 @@ private void Initialize(MaterialEditor materialEditor, MaterialProperty[] proper _initialized = true; } - + private class SerializedState { public string[] keys; @@ -165,7 +170,7 @@ private class SavedGradient { public Gradient value; } - + private Dictionary RestoreState(Material target) { var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(target)); @@ -204,10 +209,10 @@ private Dictionary RestoreState(Material target) break; } } - + return restored; } - + return new Dictionary(); } @@ -275,7 +280,7 @@ private void SaveState(Material target) importer.SaveAndReimport(); #pragma warning restore CS0162 } - + private bool StateHasChanged(Dictionary oldState, Dictionary newState) { if (oldState.Count != newState.Count) @@ -308,13 +313,15 @@ private bool StateHasChanged(Dictionary oldState, Dictionary p.displayName.ToLowerInvariant().Contains(_searchTerm.ToLowerInvariant())).ToArray(); + } EditorGUILayout.Space(); EditorGUIUtility.fieldWidth = 64f; var propIndex = 0; var oldState = new Dictionary(_uiState); - foreach (var property in properties) + foreach (var property in filteredProperties) { if ((property.flags & MaterialProperty.PropFlags.HideInInspector) != 0) { @@ -385,8 +438,21 @@ public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] pro propIndex++; } + if (hasSearch) + { + EditorGUILayout.Space(10); + } + DrawFooter(materialEditor); DrawDebug(materialEditor, materialEditor.target as Material); + +#if ORL_SHADER_GENERATOR + if (Path.GetExtension(AssetDatabase.GetAssetPath(material.shader)).Equals(".orlshader", StringComparison.InvariantCultureIgnoreCase)) + { + MapBaker.DrawMapBaker(materialEditor, materialEditor.target as Material, ref _uiState); + } +#endif + if (!oldState.SequenceEqual(_uiState)) { SaveState(materialEditor.target as Material); @@ -409,7 +475,7 @@ private bool MatchDrawerStack(List drawers, MaterialEditor editor, Mate } drawers.RemoveAt(0); - return MatchDrawerStack(drawers, editor, properties,property, index); + return MatchDrawerStack(drawers, editor, properties, property, index); } private bool MatchDrawerFuncStack(List funcs, MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index) @@ -427,10 +493,10 @@ private bool MatchDrawerFuncStack(List funcs, MaterialEditor editor, Mat } funcs.RemoveAt(0); - return MatchDrawerFuncStack(funcs, editor, properties,property, index); + return MatchDrawerFuncStack(funcs, editor, properties, property, index); } - private readonly static Regex _drawerFuncMatcher = new Regex(@"(?:%)([a-zA-Z]+)(?=\(.*\))"); + private readonly static Regex _drawerFuncMatcher = new Regex(@"(?:%)([a-zA-Z0-9]+)(?=\(.*\))"); private bool DrawUIProp(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index) { @@ -446,34 +512,34 @@ private bool DrawUIProp(MaterialEditor editor, MaterialProperty[] properties, Ma .ToList() .ForEach(g => groups.Add(g.Value)); } - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER var oldIndentLevel = EditorGUI.indentLevel; var shouldRestore = oldIndentLevel != -1; EditorGUI.indentLevel = oldIndentLevel != -1 ? Mathf.Max(0, EditorGUI.indentLevel - 1) : oldIndentLevel; - #endif +#endif drawn = MatchDrawerFuncStack(groups, editor, properties, property, index); - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER if (shouldRestore && EditorGUI.indentLevel != -1) { EditorGUI.indentLevel = oldIndentLevel; } - #endif +#endif } if (!drawn) { - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER var oldIndentLevel = EditorGUI.indentLevel; var shouldRestore = oldIndentLevel != -1; EditorGUI.indentLevel = oldIndentLevel != -1 ? Mathf.Max(0, EditorGUI.indentLevel - 1) : oldIndentLevel; - #endif +#endif drawn = MatchDrawerStack(drawerStack, editor, properties, property, index); - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER if (shouldRestore && EditorGUI.indentLevel != -1) { EditorGUI.indentLevel = oldIndentLevel; } - #endif +#endif } return drawn; } @@ -482,19 +548,20 @@ private bool DrawUIProp(MaterialEditor editor, MaterialProperty[] properties, Ma public void DrawRegularProp(MaterialEditor editor, MaterialProperty[] properties, MaterialProperty property, int index) { - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER var oldIndentLevel = EditorGUI.indentLevel; var shouldRestore = oldIndentLevel != -1; EditorGUI.indentLevel = oldIndentLevel != -1 ? Mathf.Max(0, EditorGUI.indentLevel - 1) : oldIndentLevel; - #endif - +#endif + var strippedName = Utils.StripInternalSymbols(property.displayName); var isSingleLine = property.type == MaterialProperty.PropType.Texture && _singleLineRegex.IsMatch(property.displayName); var defaultProps = (editor.target as Material).shader.GetPropertyAttributes(Array.IndexOf(properties, property)); var tooltip = Array.Find(defaultProps, attr => attr.StartsWith("Tooltip(")); var space = Array.Find(defaultProps, attr => attr.StartsWith("Space(")); - if (!string.IsNullOrWhiteSpace(space)) { + if (!string.IsNullOrWhiteSpace(space)) + { space = space.Substring(space.IndexOf("(") + 1); space = space.Substring(0, space.LastIndexOf(")")); EditorGUILayout.Space(float.Parse(space)); @@ -504,27 +571,28 @@ public void DrawRegularProp(MaterialEditor editor, MaterialProperty[] properties tooltip = tooltip.Substring(tooltip.IndexOf("(") + 1); tooltip = tooltip.Substring(0, tooltip.LastIndexOf(")")); } - + if (isSingleLine) { var buttonRect = editor.TexturePropertySingleLine(new GUIContent(strippedName, tooltip), property); - buttonRect.x = EditorGUIUtility.labelWidth + 20.0f; + buttonRect.x = EditorGUIUtility.labelWidth + 34.0f; buttonRect.width = EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth - 38f; // We can only repack 2D textures if (property.textureDimension != TextureDimension.Tex2D) return; var packerKey = property.name + "_packer"; - _uiState[packerKey] = TexturePacker.DrawPacker(buttonRect, (bool) _uiState[packerKey], ref _uiState, packerKey, editor.target as Material, property, editor); - #if UNITY_2022_1_OR_NEWER + _uiState[packerKey] = TexturePacker.DrawPacker(buttonRect, (bool)_uiState[packerKey], ref _uiState, packerKey, editor.target as Material, property, editor); +#if UNITY_2022_1_OR_NEWER if (shouldRestore) { EditorGUI.indentLevel = oldIndentLevel; } - #endif +#endif return; } var propHeight = editor.GetPropertyHeight(property, strippedName); - if (property.type == MaterialProperty.PropType.Vector && EditorGUIUtility.currentViewWidth > 340) { + if (property.type == MaterialProperty.PropType.Vector && EditorGUIUtility.currentViewWidth > 340) + { propHeight /= 2.0f; } var controlRect = EditorGUILayout.GetControlRect(true, propHeight, EditorStyles.layerMaskField); @@ -540,22 +608,22 @@ public void DrawRegularProp(MaterialEditor editor, MaterialProperty[] properties // We can only repack 2D textures if (property.textureDimension != TextureDimension.Tex2D) return; var packerKey = property.name + "_packer"; - _uiState[packerKey] = TexturePacker.DrawPacker(buttonRect, (bool) _uiState[packerKey], ref _uiState, packerKey, editor.target as Material, property, editor); - #if UNITY_2022_1_OR_NEWER + _uiState[packerKey] = TexturePacker.DrawPacker(buttonRect, (bool)_uiState[packerKey], ref _uiState, packerKey, editor.target as Material, property, editor); +#if UNITY_2022_1_OR_NEWER if (shouldRestore && EditorGUI.indentLevel != -1) { EditorGUI.indentLevel = oldIndentLevel; } - #endif +#endif return; } editor.ShaderProperty(controlRect, property, new GUIContent(strippedName, tooltip)); - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER if (shouldRestore) { EditorGUI.indentLevel = oldIndentLevel; } - #endif +#endif } #endregion @@ -563,18 +631,19 @@ private void DrawFooter(MaterialEditor editor) { Styles.DrawStaticHeader("Extras"); EditorGUI.indentLevel = 1; - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER EditorGUI.indentLevel = 0; - #endif +#endif editor.RenderQueueField(); editor.EnableInstancingField(); editor.LightmapEmissionFlagsProperty(0, true, true); editor.DoubleSidedGIField(); + EditorGUILayout.Space(5); } private void DrawDebug(MaterialEditor editor, Material material) { - var currValue = (bool) _uiState["debugShown"]; + var currValue = (bool)_uiState["debugShown"]; var newValue = Styles.DrawFoldoutHeader("Debug", currValue); if (currValue != newValue) @@ -584,30 +653,37 @@ private void DrawDebug(MaterialEditor editor, Material material) } if (!newValue) return; - - #if UNITY_2022_1_OR_NEWER + +#if UNITY_2022_1_OR_NEWER // Unity 2022 is 1 more level nested EditorGUI.indentLevel = 0; - #endif +#endif EditorGUILayout.LabelField("Active Keywords", EditorStyles.boldLabel); - using (new EditorGUI.DisabledGroupScope(true)) { + using (new EditorGUI.DisabledGroupScope(true)) + { EditorGUILayout.TextArea(string.Join("\n", material.shaderKeywords)); } - if (_shaderFeatures.Count > 0) { + if (_shaderFeatures.Count > 0) + { EditorGUILayout.LabelField("Defined Shader Features", EditorStyles.boldLabel); - using (new EditorGUI.DisabledGroupScope(true)) { + using (new EditorGUI.DisabledGroupScope(true)) + { EditorGUILayout.TextArea(string.Join("\n", _shaderFeatures)); } } - if (_multiCompiles.Count > 0) { + if (_multiCompiles.Count > 0) + { EditorGUILayout.LabelField("Defined Multi-Compiles", EditorStyles.boldLabel); - using (new EditorGUI.DisabledGroupScope(true)) { + using (new EditorGUI.DisabledGroupScope(true)) + { EditorGUILayout.TextArea(string.Join("\n", _multiCompiles)); } } + + EditorGUILayout.Space(10); } } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.inspector/Editor/MaterialLibraries/AmbientCGBrowser.cs b/Packages/sh.orels.shaders.inspector/Editor/MaterialLibraries/AmbientCGBrowser.cs index 746e9938..a50d37c9 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/MaterialLibraries/AmbientCGBrowser.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/MaterialLibraries/AmbientCGBrowser.cs @@ -1,4 +1,4 @@ -#if UNITY_2019_4 +#if false using System; using System.Collections.Generic; using System.IO; diff --git a/Packages/sh.orels.shaders.inspector/Editor/Resources/PackerShader.shader b/Packages/sh.orels.shaders.inspector/Editor/Resources/PackerShader.shader index d529c21d..bac5c4f4 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/Resources/PackerShader.shader +++ b/Packages/sh.orels.shaders.inspector/Editor/Resources/PackerShader.shader @@ -107,16 +107,20 @@ blueData = 1 - blueData; } float alphaData = _AlphaTexPresent ? _AlphaTex.SampleLevel(sampler_AlphaTex, i.uv, 0)[_AlphaChannel] : _AlphaFill; + if (_AlphaInvert) { alphaData = 1 - alphaData; } - // if (!_IsLinear) - // { - // return float4(pow(float3(redData, greenData, blueData),2.2), alphaData); - // } - return float4(redData, greenData, blueData, _AlphaTexPresent ? pow(alphaData, 1.0/2.2) : alphaData); + if (!_IsLinear) + { + redData = LinearToGammaSpaceExact(redData); + greenData = LinearToGammaSpaceExact(greenData); + blueData = LinearToGammaSpaceExact(blueData); + } + + return float4(redData, greenData, blueData, alphaData); } ENDCG } diff --git a/Packages/sh.orels.shaders.inspector/Editor/Styles.cs b/Packages/sh.orels.shaders.inspector/Editor/Styles.cs index 64fca08a..b1ef85c1 100644 --- a/Packages/sh.orels.shaders.inspector/Editor/Styles.cs +++ b/Packages/sh.orels.shaders.inspector/Editor/Styles.cs @@ -6,12 +6,13 @@ namespace ORL.ShaderInspector { public static class Styles { - public static void InitTextureStyles() { + public static void InitTextureStyles() + { Header1BgStyle = new GUIStyle { normal = new GUIStyleState { - background = CreateTexture(new Color(0f,0f,0f,0.3f)) + background = CreateTexture(new Color(0f, 0f, 0f, 0.3f)) } }; @@ -25,6 +26,11 @@ public static void InitTextureStyles() { }; } + public static bool IsInitialized() + { + return Header1BgStyle.normal.background != null && Divider.normal.background != null; + } + public static Texture2D CreateTexture(Color color) { var tex = new Texture2D(1, 1); @@ -58,7 +64,7 @@ public static GUIStyle CustomDividerStyle(float height, Color color) { normal = new GUIStyleState { - background = CreateTexture(new Color(0f,0f,0f,0.3f)) + background = CreateTexture(new Color(0f, 0f, 0f, 0.3f)) } }; @@ -69,7 +75,7 @@ public static GUIStyle CustomDividerStyle(float height, Color color) alignment = TextAnchor.MiddleLeft, normal = new GUIStyleState { - textColor = new Color(1f,1f,1f, 0.8f), + textColor = new Color(1f, 1f, 1f, 0.8f), } }; @@ -80,7 +86,7 @@ public static GUIStyle CustomDividerStyle(float height, Color color) margin = new RectOffset(19, 0, 0, 0), normal = new GUIStyleState { - textColor = new Color(1f,1f,1f, 0.5f), + textColor = new Color(1f, 1f, 1f, 0.5f), } }; @@ -90,7 +96,7 @@ public static GUIStyle CustomDividerStyle(float height, Color color) wordWrap = true, normal = new GUIStyleState { - textColor = new Color(64f/255f, 206f/255f, 245f/255f), + textColor = new Color(64f / 255f, 206f / 255f, 245f / 255f), } }; @@ -137,13 +143,12 @@ public static GUIStyle FoldoutUnfolded public static void DrawStaticHeader(string text) { EditorGUI.indentLevel = 0; - EditorGUILayout.Space(8f * EditorGUIUtility.pixelsPerPoint); var rect = EditorGUILayout.GetControlRect(); rect.yMax += 1f * EditorGUIUtility.pixelsPerPoint; rect.xMin -= 15f * EditorGUIUtility.pixelsPerPoint; - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER rect.xMin -= 15f * EditorGUIUtility.pixelsPerPoint; - #endif +#endif rect.xMax += 5f * EditorGUIUtility.pixelsPerPoint; var dividerRect = rect; dividerRect.y -= 1f; @@ -157,15 +162,15 @@ public static void DrawStaticHeader(string text) EditorGUILayout.Space(8f * EditorGUIUtility.pixelsPerPoint); } - public static bool DrawFoldoutHeader(string text, bool open) { + public static bool DrawFoldoutHeader(string text, bool open) + { EditorGUI.indentLevel = 0; - EditorGUILayout.Space(8f * EditorGUIUtility.pixelsPerPoint); var rect = EditorGUILayout.GetControlRect(); rect.yMax += 1f * EditorGUIUtility.pixelsPerPoint; rect.xMin -= 15f * EditorGUIUtility.pixelsPerPoint; - #if UNITY_2022_1_OR_NEWER +#if UNITY_2022_1_OR_NEWER rect.xMin -= 15f * EditorGUIUtility.pixelsPerPoint; - #endif +#endif rect.xMax += 5f * EditorGUIUtility.pixelsPerPoint; var dividerRect = rect; dividerRect.y -= 1f; @@ -176,7 +181,6 @@ public static bool DrawFoldoutHeader(string text, bool open) { labelRect.y -= 1f * EditorGUIUtility.pixelsPerPoint; labelRect.xMin += 27f * EditorGUIUtility.pixelsPerPoint; GUI.Label(labelRect, text, Header1TextStyle); - EditorGUILayout.Space(8f * EditorGUIUtility.pixelsPerPoint); var foldoutRect = rect; foldoutRect.xMin = 15f * EditorGUIUtility.pixelsPerPoint; @@ -188,30 +192,33 @@ public static bool DrawFoldoutHeader(string text, bool open) { switch (evt.type) { case EventType.Repaint: - { - if (open) - { - FoldoutUnfolded.Draw(foldoutRect, "", false, false, true, false); - } - else { - FoldoutFolded.Draw(foldoutRect, "", false, false, true, false); + if (open) + { + FoldoutUnfolded.Draw(foldoutRect, "", false, false, true, false); + } + else + { + FoldoutFolded.Draw(foldoutRect, "", false, false, true, false); + } + + break; } - - break; - } case EventType.MouseDown: - { - if (rect.Contains(evt.mousePosition)) { - return !open; - } + if (rect.Contains(evt.mousePosition)) + { + return !open; + } - break; - } + break; + } } - GUI.Label(labelRect, text, Styles.Header1TextStyle); + if (open) + { + EditorGUILayout.Space(6f); + } return open; } @@ -220,7 +227,7 @@ public static Texture DrawSingleLineTextureGUI(string label, Texture current, var rect = EditorGUILayout.GetControlRect(true, 20f, EditorStyles.layerMaskField); return DrawSingleLineTextureGUI(rect, label, current, maxWidth); } - + public static Texture DrawSingleLineTextureGUI(Rect position, string label, Texture current, int maxWidth = -1) { var rect = position; @@ -230,12 +237,12 @@ public static Texture DrawSingleLineTextureGUI(Rect position, string label, T } var labelRect = new Rect(); var fieldRect = new Rect(); - var rects = new object[] {rect, labelRect, fieldRect}; + var rects = new object[] { rect, labelRect, fieldRect }; typeof(EditorGUI) .GetMethod("GetRectsForMiniThumbnailField", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance) ?.Invoke(null, rects); - labelRect = (Rect) rects[2]; - fieldRect = (Rect) rects[1]; + labelRect = (Rect)rects[2]; + fieldRect = (Rect)rects[1]; EditorGUI.LabelField(labelRect, label); return EditorGUI.ObjectField(fieldRect, current, typeof(T), false) as Texture; } diff --git a/Packages/sh.orels.shaders.inspector/ORL.ShaderInspector.asmdef b/Packages/sh.orels.shaders.inspector/ORL.ShaderInspector.asmdef index a64deb10..942cfdb1 100644 --- a/Packages/sh.orels.shaders.inspector/ORL.ShaderInspector.asmdef +++ b/Packages/sh.orels.shaders.inspector/ORL.ShaderInspector.asmdef @@ -1,6 +1,11 @@ { "name": "ORL.ShaderInspector", - "references": [], + "rootNamespace": "", + "references": [ + "GUID:a1653399f63795746b1857281d1e400d", + "GUID:7f2b18295eece7a49ab038d58f0c3037", + "GUID:a5857e7d50658ab468a75fe6fb42fda9" + ], "includePlatforms": [ "Editor" ], @@ -10,6 +15,12 @@ "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], - "versionDefines": [], + "versionDefines": [ + { + "name": "sh.orels.shaders.generator", + "expression": "", + "define": "ORL_SHADER_GENERATOR" + } + ], "noEngineReferences": false } \ No newline at end of file diff --git a/Packages/sh.orels.shaders.inspector/package.json b/Packages/sh.orels.shaders.inspector/package.json old mode 100644 new mode 100755 index fba1f6ae..8821fd3c --- a/Packages/sh.orels.shaders.inspector/package.json +++ b/Packages/sh.orels.shaders.inspector/package.json @@ -2,7 +2,7 @@ "name": "sh.orels.shaders.inspector", "displayName": "ORL Shader Inspector", "description": "A simple property-based shader inspector with extension support", - "version": "6.3.0", + "version": "7.0.0-dev.11", "unity": "2019.4", "author": { "name": "orels1", @@ -12,6 +12,7 @@ "com.unity.nuget.newtonsoft-json": "2.0.2" }, "documentationUrl": "https://shaders.orels.sh", + "changelogUrl": "https://shaders.orels.sh/docs/changelog", "keywords": [ "shaders", "inspector", diff --git a/Packages/sh.orels.shaders/Editor/ORL.Shaders.Editor.asmdef b/Packages/sh.orels.shaders/Editor/ORL.Shaders.Editor.asmdef index 23e9c1fb..6cd173b5 100644 --- a/Packages/sh.orels.shaders/Editor/ORL.Shaders.Editor.asmdef +++ b/Packages/sh.orels.shaders/Editor/ORL.Shaders.Editor.asmdef @@ -1,6 +1,9 @@ { "name": "ORL.Shaders.Editor", - "references": [], + "rootNamespace": "", + "references": [ + "GUID:7c60e0ff79a88d0408296a2af802cc74" + ], "includePlatforms": [ "Editor" ], @@ -10,6 +13,12 @@ "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], - "versionDefines": [], + "versionDefines": [ + { + "name": "sh.orels.shaders.inspector", + "expression": "0.0.0", + "define": "ORL_SHADER_INSPECTOR" + } + ], "noEngineReferences": false } \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Editor/ORLShadersMigrator.cs b/Packages/sh.orels.shaders/Editor/ORLShadersMigrator.cs index 8eb402a6..d0a26011 100644 --- a/Packages/sh.orels.shaders/Editor/ORLShadersMigrator.cs +++ b/Packages/sh.orels.shaders/Editor/ORLShadersMigrator.cs @@ -41,7 +41,8 @@ public static void ShowWindow() "0caac922b36d9e74e8435b8316baf498", "5f69cf125658cc046a729a5a5b4b9a11", "307b9906231b0784884d4b52416215a8", - "e67e822f851164b40b6b701128914625" + "e67e822f851164b40b6b701128914625", + "2758518bdcab40a3abd3807018be68ca" }; private static HashSet _revertableShaders = new HashSet @@ -63,7 +64,8 @@ public static void ShowWindow() "650f7b5fdb04efe42ac612d9fd0d03cb", "7de358116a341004b94136337d239d1b", "10f0534e8e8748a409849338afe43251", - "2758518bdcab40a3abd3807018be68ca" + "2758518bdcab40a3abd3807018be68ca", + "09e7e0cd1d5730140b52f4296dc3a4ac" }; // old GUID -> new GUID @@ -86,7 +88,8 @@ public static void ShowWindow() { "0caac922b36d9e74e8435b8316baf498", "650f7b5fdb04efe42ac612d9fd0d03cb" }, { "5f69cf125658cc046a729a5a5b4b9a11", "7de358116a341004b94136337d239d1b" }, { "307b9906231b0784884d4b52416215a8", "10f0534e8e8748a409849338afe43251" }, - { "e67e822f851164b40b6b701128914625", "2758518bdcab40a3abd3807018be68ca" } + { "e67e822f851164b40b6b701128914625", "09e7e0cd1d5730140b52f4296dc3a4ac" }, // v5 tess displacement -> v6 tess displacement + { "2758518bdcab40a3abd3807018be68ca", "09e7e0cd1d5730140b52f4296dc3a4ac"} // static tess displacement -> orlshader tess displacement }; // new GUID -> old GUID @@ -109,7 +112,7 @@ public static void ShowWindow() { "650f7b5fdb04efe42ac612d9fd0d03cb", "0caac922b36d9e74e8435b8316baf498" }, { "7de358116a341004b94136337d239d1b", "5f69cf125658cc046a729a5a5b4b9a11" }, { "10f0534e8e8748a409849338afe43251", "307b9906231b0784884d4b52416215a8" }, - { "2758518bdcab40a3abd3807018be68ca", "e67e822f851164b40b6b701128914625" } + { "09e7e0cd1d5730140b52f4296dc3a4ac", "e67e822f851164b40b6b701128914625" }, }; // name -> old GUID @@ -132,12 +135,13 @@ public static void ShowWindow() { "orels1/VFX/Block Fader", "0caac922b36d9e74e8435b8316baf498" }, { "orels1/VFX/Clouds", "5f69cf125658cc046a729a5a5b4b9a11" }, { "orels1/VFX/Cubemap Screen", "307b9906231b0784884d4b52416215a8" }, - { "orels1/Standard Tesselated Displacement", "e67e822f851164b40b6b701128914625" } + { "orels1/Standard Tesselated Displacement", "e67e822f851164b40b6b701128914625" }, }; // private static string _fileId = "-8512187303908658807"; private List _affectedMaterials = new List(); + private List _affectedMaterialsSelected = new List(); private Vector2 _affectedMatsScrollPos = Vector2.zero; private bool _dryRun; @@ -198,6 +202,11 @@ private void MigrateTab() if (GUILayout.Button("Find Materials using ORL Shaders", GUILayout.Height(30))) { _affectedMaterials = FindAffectedMaterials(); + _affectedMaterialsSelected = new List(); + for (var i = 0; i < _affectedMaterials.Count; i++) + { + _affectedMaterialsSelected.Add(true); + } } EditorGUILayout.HelpBox(new GUIContent("Clicking this button will look through your assets to find materials that might need migration")); @@ -210,9 +219,35 @@ private void MigrateTab() using (var scroller = new GUILayout.ScrollViewScope(_affectedMatsScrollPos)) { _affectedMatsScrollPos = scroller.scrollPosition; + var index = 0; foreach (var mat in _affectedMaterials) { - EditorGUILayout.ObjectField(AssetDatabase.LoadAssetAtPath(mat), typeof (Material), false); + using (new GUILayout.HorizontalScope()) + { + _affectedMaterialsSelected[index] = EditorGUILayout.Toggle(_affectedMaterialsSelected[index], GUILayout.Width(16)); + EditorGUILayout.ObjectField(AssetDatabase.LoadAssetAtPath(mat), typeof (Material), false); + } + + index++; + } + } + } + + using (new GUILayout.HorizontalScope()) + { + if (GUILayout.Button("Select All")) + { + for (var i = 0; i < _affectedMaterialsSelected.Count; i++) + { + _affectedMaterialsSelected[i] = true; + } + } + + if (GUILayout.Button("Deselect All")) + { + for (var i = 0; i < _affectedMaterialsSelected.Count; i++) + { + _affectedMaterialsSelected[i] = false; } } } @@ -315,6 +350,10 @@ private void Migrate(bool revert = false) { foreach (var path in _affectedMaterials) { + if (!_affectedMaterialsSelected[_affectedMaterials.IndexOf(path)]) + { + continue; + } var mat = AssetDatabase.LoadAssetAtPath(path); var matYamlSource = File.ReadAllLines(Application.dataPath.Replace("\\", "/").Replace("Assets", "") + path); @@ -322,14 +361,14 @@ private void Migrate(bool revert = false) if (shaderLines.Count == 0) { EditorUtility.DisplayProgressBar("Migrating Materials", $"Skipping {path}..", - i / _affectedMaterials.Count); + i / _affectedMaterialsSelected.Count); i++; invalidCount++; continue; } EditorUtility.DisplayProgressBar("Migrating Materials", $"Migrating {path}...", - i / _affectedMaterials.Count); + i / _affectedMaterialsSelected.Count); var shaderGuid = ""; if (_nameMap.ContainsKey(mat.shader.name)) { @@ -348,7 +387,7 @@ private void Migrate(bool revert = false) if (!guidLine.Contains("guid: ")) { EditorUtility.DisplayProgressBar("Migrating Materials", $"Skipping {path}..", - i / _affectedMaterials.Count); + i / _affectedMaterialsSelected.Count); i++; invalidCount++; continue; @@ -357,7 +396,7 @@ private void Migrate(bool revert = false) if (!shaderGuid.Contains(",")) { EditorUtility.DisplayProgressBar("Migrating Materials", $"Skipping {path}..", - i / _affectedMaterials.Count); + i / _affectedMaterialsSelected.Count); i++; invalidCount++; continue; @@ -399,11 +438,11 @@ private void Migrate(bool revert = false) EditorUtility.ClearProgressBar(); if (_dryRun) { - Debug.Log($"DRY RUN. Migration finished. Would have migrated {migratedCount} / {_affectedMaterials.Count} materials. Could not find shaders for {missedCount} / {_affectedMaterials.Count} materials. Invalid materials {invalidCount} / {_affectedMaterials.Count}."); + Debug.Log($"DRY RUN. Migration finished. Would have migrated {migratedCount} / {_affectedMaterialsSelected.Count} materials. Could not find shaders for {missedCount} / {_affectedMaterialsSelected.Count} materials. Invalid materials {invalidCount} / {_affectedMaterialsSelected.Count}."); } else { - Debug.Log($"Migration finished. Migrated {migratedCount} / {_affectedMaterials.Count} materials. Could not find shaders for {missedCount} / {_affectedMaterials.Count} materials. Invalid materials {invalidCount} / {_affectedMaterials.Count}."); + Debug.Log($"Migration finished. Migrated {migratedCount} / {_affectedMaterialsSelected.Count} materials. Could not find shaders for {missedCount} / {_affectedMaterialsSelected.Count} materials. Invalid materials {invalidCount} / {_affectedMaterialsSelected.Count}."); } } } @@ -415,6 +454,11 @@ private void RevertTab() if (GUILayout.Button("Find Materials using ORL Shaders", GUILayout.Height(30))) { _affectedMaterials = FindAffectedMaterials(true); + _affectedMaterialsSelected = new List(); + for (var i = 0; i < _affectedMaterials.Count; i++) + { + _affectedMaterialsSelected.Add(true); + } } EditorGUILayout.HelpBox(new GUIContent("Clicking this button will look through your assets to find materials that can be reverted")); @@ -427,9 +471,35 @@ private void RevertTab() using (var scroller = new GUILayout.ScrollViewScope(_affectedMatsScrollPos)) { _affectedMatsScrollPos = scroller.scrollPosition; + var index = 0; foreach (var mat in _affectedMaterials) { - EditorGUILayout.ObjectField(AssetDatabase.LoadAssetAtPath(mat), typeof (Material), false); + using (new GUILayout.HorizontalScope()) + { + _affectedMaterialsSelected[index] = EditorGUILayout.Toggle(_affectedMaterialsSelected[index], GUILayout.Width(16)); + EditorGUILayout.ObjectField(AssetDatabase.LoadAssetAtPath(mat), typeof (Material), false); + } + + index++; + } + } + } + + using (new GUILayout.HorizontalScope()) + { + if (GUILayout.Button("Select All")) + { + for (var i = 0; i < _affectedMaterialsSelected.Count; i++) + { + _affectedMaterialsSelected[i] = true; + } + } + + if (GUILayout.Button("Deselect All")) + { + for (var i = 0; i < _affectedMaterialsSelected.Count; i++) + { + _affectedMaterialsSelected[i] = false; } } } diff --git a/Packages/sh.orels.shaders/Editor/ORLShadersUpgrader.cs b/Packages/sh.orels.shaders/Editor/ORLShadersUpgrader.cs new file mode 100644 index 00000000..8310274d --- /dev/null +++ b/Packages/sh.orels.shaders/Editor/ORLShadersUpgrader.cs @@ -0,0 +1,316 @@ +using UnityEngine; +using UnityEditor; +using ORL.Shaders.UpgradePlans; +using System.Collections.Generic; +using System; +using System.Linq; +using System.IO; + +namespace ORL.Shaders +{ + public class ORLShadersUpgrader : EditorWindow + { + [MenuItem("Tools/orels1/Upgrade Materials")] + private static void ShowWindow() + { + var window = GetWindow(true); + window.titleContent = new GUIContent("ORL Material Upgrader"); + window.Show(); + } + + private UpgradePlanBase _selectedUpgradePlan; + private int _selectedUpgradePlanIndex; + private List _upgradePlans = new List(); + private List _shaders = new List(); + private List _affectedMaterials = new List(); + private List _includedFolders = new List(); + private List _excludedFolders = new List(); + private bool _dryRun; + + private List FindUpgradePlans() + { + var upgradePlans = new List(); + foreach (var type in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()) + { + if (type.IsSubclassOf(typeof(UpgradePlanBase))) + { + var upgradePlan = (UpgradePlanBase)Activator.CreateInstance(type); + upgradePlans.Add(upgradePlan); + } + } + + return upgradePlans; + } + + private List FindShaders() + { + var shaders = new List(); + var results = AssetDatabase.FindAssets("t:Shader", new string[] { "Assets", "Packages" }); + foreach (var guid in results) + { + var path = AssetDatabase.GUIDToAssetPath(guid); + if (path.EndsWith(".orlshader") || path.EndsWith(".orlconfshader")) + { + var shader = AssetDatabase.LoadAssetAtPath(path); + if (shader != null) + { + shaders.Add(shader); + } + } + } + return shaders; + } + + private List FindMaterials() + { + var affectedMaterials = new List(); + EditorUtility.DisplayProgressBar("Looking up Materials", "Please wait...", 0); + var guids = new string[0]; + if (_includedFolders.Count > 0) + { + guids = AssetDatabase.FindAssets("t:Material", _includedFolders.ToArray()); + } + else + { + guids = AssetDatabase.FindAssets("t:Material"); + } + var i = 0f; + foreach (var guid in guids) + { + var path = AssetDatabase.GUIDToAssetPath(guid); + if (_excludedFolders.Any(p => path.StartsWith(p))) continue; + EditorUtility.DisplayProgressBar("Looking up Materials", $"Checking {path}", i / guids.Length); + var material = AssetDatabase.LoadAssetAtPath(path); + if (material == null) + { + i++; + continue; + } + if (material.shader == null) + { + i++; + continue; + } + + if (_shaders.Contains(material.shader)) + { + affectedMaterials.Add(material); + i++; + continue; + } + i++; + } + EditorUtility.ClearProgressBar(); + Debug.Log("Found " + affectedMaterials.Count + " materials"); + + return affectedMaterials; + } + + private string PickPath(string startingPath = "") + { + var newPath = EditorUtility.OpenFolderPanel("Select Folder", startingPath, ""); + if (string.IsNullOrWhiteSpace(newPath)) return null; + var projectRoot = Application.dataPath.Replace("\\", "/").Replace("Assets", ""); + return newPath.Replace(projectRoot, ""); + } + + private Vector2 _materialsScrollPos; + private Vector2 _shadersScrollPos; + private Vector2 _includedFoldersScrollPos; + private Vector2 _excludedFoldersScrollPos; + private bool _showSelectedShaders; + private bool _showIncludedFolders; + private bool _showExcludedFolders; + + private void OnGUI() + { + if (_upgradePlans.Count == 0) + { + _upgradePlans = FindUpgradePlans(); + if (_upgradePlans.Count > 0) + { + _selectedUpgradePlan = _upgradePlans[0]; + _selectedUpgradePlanIndex = 0; + } + } + + if (_shaders.Count == 0) + { + _shaders = FindShaders(); + Debug.Log("Found " + _shaders.Count + " shaders"); + } + + using (var c = new EditorGUI.ChangeCheckScope()) + { + _selectedUpgradePlanIndex = EditorGUILayout.Popup("Upgrade Plan", _selectedUpgradePlanIndex, _upgradePlans.Select(p => p.OldVersion + " -> " + p.NewVersion).ToArray()); + if (c.changed) + { + _selectedUpgradePlan = _upgradePlans[_selectedUpgradePlanIndex]; + } + } + + if (_shaders.Count > 0) + { + _showSelectedShaders = EditorGUILayout.Foldout(_showSelectedShaders, "Selected Shaders"); + if (_showSelectedShaders) + { + using (new GUILayout.VerticalScope(EditorStyles.helpBox)) + { + using (var scroller = new GUILayout.ScrollViewScope(_shadersScrollPos)) + { + _shadersScrollPos = scroller.scrollPosition; + var index = 0; + foreach (var shader in _shaders) + { + using (new GUILayout.HorizontalScope()) + { + EditorGUILayout.ObjectField(shader, typeof(Shader), false); + if (GUILayout.Button("-", GUILayout.Width(20))) + { + _shaders.Remove(shader); + break; + } + } + index++; + } + } + } + if (GUILayout.Button("Add Shader")) + { + _shaders.Add(Shader.Find("orels1/Standard")); + } + } + } + + if (GUILayout.Button("Find Materials using ORL Shaders", GUILayout.Height(30))) + { + _affectedMaterials = FindMaterials(); + } + + _showIncludedFolders = EditorGUILayout.Foldout(_showIncludedFolders, "Only Search These Folders"); + if (_showIncludedFolders) + { + using (new GUILayout.VerticalScope(EditorStyles.helpBox)) + { + using (var scroller = new GUILayout.ScrollViewScope(_includedFoldersScrollPos)) + { + _includedFoldersScrollPos = scroller.scrollPosition; + var index = 0; + foreach (var folder in _includedFolders) + { + using (new GUILayout.HorizontalScope()) + { + EditorGUILayout.TextField(folder); + if (GUILayout.Button("P", GUILayout.Width(20))) + { + var newPath = PickPath(_includedFolders?[index] ?? ""); + if (newPath != null) + { + _includedFolders[index] = newPath; + } + break; + } + if (GUILayout.Button("-", GUILayout.Width(20))) + { + _includedFolders.Remove(folder); + break; + } + } + index++; + } + } + if (GUILayout.Button("Add Folder", GUILayout.Height(30))) + { + var newPath = PickPath(); + if (newPath != null) + { + _includedFolders.Add(newPath); + } + } + } + } + + _showExcludedFolders = EditorGUILayout.Foldout(_showExcludedFolders, "Excluded Folders"); + if (_showExcludedFolders) + { + using (new GUILayout.VerticalScope(EditorStyles.helpBox)) + { + using (var scroller = new GUILayout.ScrollViewScope(_excludedFoldersScrollPos)) + { + _excludedFoldersScrollPos = scroller.scrollPosition; + var index = 0; + foreach (var folder in _excludedFolders) + { + using (new GUILayout.HorizontalScope()) + { + EditorGUILayout.TextField(folder); + if (GUILayout.Button("-", GUILayout.Width(20))) + { + _excludedFolders.Remove(folder); + break; + } + } + index++; + } + + if (GUILayout.Button("Add Folder", GUILayout.Height(30))) + { + var newPath = PickPath(); + if (newPath != null) + { + _excludedFolders.Add(newPath); + } + } + } + } + } + + if (_affectedMaterials.Count > 0) + { + using (new GUILayout.VerticalScope(EditorStyles.helpBox)) + { + using (var scroller = new GUILayout.ScrollViewScope(_materialsScrollPos)) + { + _materialsScrollPos = scroller.scrollPosition; + var index = 0; + foreach (var mat in _affectedMaterials) + { + using (new GUILayout.HorizontalScope()) + { + EditorGUILayout.ObjectField(mat, typeof(Material), false); + if (GUILayout.Button("-", GUILayout.Width(20))) + { + _affectedMaterials.Remove(mat); + break; + } + } + index++; + } + } + } + } + + GUILayout.FlexibleSpace(); + + if (_affectedMaterials.Count > 0 && GUILayout.Button("Upgrade Now", GUILayout.Height(30))) + { + if (_selectedUpgradePlan == null) return; + var success = _selectedUpgradePlan.Upgrade(_affectedMaterials, _dryRun); + if (success && !_dryRun) + { + Debug.Log($"Upgraded materials to {_selectedUpgradePlan.NewVersion}:\n{string.Join("\n", _affectedMaterials.Select(m => " - " + m.name + " (" + AssetDatabase.GetAssetPath(m) + ")"))}"); + if (!EditorUtility.DisplayDialog("Upgrade Successful", "Upgraded " + _affectedMaterials.Count + " materials to " + _selectedUpgradePlan.NewVersion + "\nCheck logs for a full list of materials.\n\nPress Undo to revert\n\nYou can always undo later by pressing Ctrl+Z", "Ok", "Undo")) + { + Undo.RevertAllInCurrentGroup(); + Debug.Log("Reverted all changes"); + } + } + if (!success) + { + EditorUtility.DisplayDialog("Upgrade Failed", "Failed to upgrade " + _affectedMaterials.Count + " materials to " + _selectedUpgradePlan.NewVersion, "Ok"); + } + } + _dryRun = EditorGUILayout.Toggle("Dry run", _dryRun); + } + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Editor/ORLShadersUpgrader.cs.meta b/Packages/sh.orels.shaders/Editor/ORLShadersUpgrader.cs.meta new file mode 100644 index 00000000..936cf226 --- /dev/null +++ b/Packages/sh.orels.shaders/Editor/ORLShadersUpgrader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7750beb9251e174b9d9542862fd4f09 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Editor/UpgradePlans.meta b/Packages/sh.orels.shaders/Editor/UpgradePlans.meta new file mode 100644 index 00000000..e3db5805 --- /dev/null +++ b/Packages/sh.orels.shaders/Editor/UpgradePlans.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a38bf53bc0fad1442b395e5df7b1c8e7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradePlanBase.cs b/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradePlanBase.cs new file mode 100644 index 00000000..f277607b --- /dev/null +++ b/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradePlanBase.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using UnityEditor; +using System; +using System.Collections.Generic; + +namespace ORL.Shaders.UpgradePlans +{ + public class UpgradePlanBase + { + protected string _oldVersion; + public string OldVersion => _oldVersion; + protected string _newVersion; + public string NewVersion => _newVersion; + + public virtual bool Upgrade(IList materials, bool dryRun = false) + { + Debug.Log("Upgrading materials to " + NewVersion); + return true; + } + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradePlanBase.cs.meta b/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradePlanBase.cs.meta new file mode 100644 index 00000000..5e55dfae --- /dev/null +++ b/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradePlanBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e8efb3733236884e99a63dababca730 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradeV6toV7.cs b/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradeV6toV7.cs new file mode 100644 index 00000000..a6ec38b1 --- /dev/null +++ b/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradeV6toV7.cs @@ -0,0 +1,149 @@ +using UnityEngine; +using UnityEditor; +using System; +using System.Collections.Generic; + +namespace ORL.Shaders.UpgradePlans +{ + public class UpgradeV6toV7 : UpgradePlanBase + { + public UpgradeV6toV7() + { + _oldVersion = "6.x.x"; + _newVersion = "7.0.0"; + } + + public override bool Upgrade(IList materials, bool dryRun = false) + { + EditorUtility.DisplayProgressBar("Upgrading Materials", "Please wait...", 0); + var groupId = Undo.GetCurrentGroup(); + Undo.SetCurrentGroupName("Upgraded to " + NewVersion); + var i = 0f; + var success = true; + + try + { + foreach (var mat in materials) + { + var materialShaderVersion = 0; + if (mat.HasProperty("INTERNAL_MaterialShaderVersion")) + { + materialShaderVersion = mat.GetInt("INTERNAL_MaterialShaderVersion"); + } + EditorUtility.DisplayProgressBar("Upgrading Materials", $"Upgrading {mat.name}", i / materials.Count); + // Upgrade emission + if (!dryRun) + { + Undo.RecordObject(mat, "Upgraded to " + NewVersion); + } + if (mat.HasProperty("_EmissionColor")) + { + var currentColor = mat.GetColor("_EmissionColor"); + currentColor.r = Mathf.Pow(currentColor.r, 1.0f / 2.2f); + currentColor.g = Mathf.Pow(currentColor.g, 1.0f / 2.2f); + currentColor.b = Mathf.Pow(currentColor.b, 1.0f / 2.2f); + if (dryRun) + { + Debug.Log("Would have upgraded emission color for " + mat.name + " from " + mat.GetColor("_EmissionColor") + " to " + currentColor); + } + else + { + mat.SetColor("_EmissionColor", currentColor); + } + } + + // Upgrade Specular Occlusion + if (mat.HasProperty("_SpecOcclusion")) + { + var currValue = mat.GetFloat("_SpecOcclusion"); + + // If default value, then upgrade to new default + if (Mathf.Abs(0.075f - currValue) < 0.001f) + { + if (dryRun) + { + Debug.Log("Would have upgraded specular occlusion for " + mat.name + " from " + currValue + " to " + 0.25f); + } + else + { + mat.SetFloat("_SpecOcclusion", 0.25f); + } + } + else // If the value was modified - clone it to the new property + { + if (dryRun) + { + Debug.Log("Would have upgraded specular occlusion for " + mat.name + " from " + currValue + " to " + 0.25f); + } + else + { + // This is the reflection probe occlusiomn + // Leaving it untouched might be too dark, so we'll set it to 0.25 unless it was modified below that (usually 0) + mat.SetFloat("_SpecOcclusion", currValue < 0.25f ? currValue : 0.25f); + + // this is the new lightmap occlusion property + // We can clone here as-is + mat.SetFloat("_BakedSpecularOcclusion", currValue); + } + } + } + + // Enable GSAA normal map contribution + if (materialShaderVersion < 700) + { + if (mat.HasProperty("_GSAAIncludeNormalMaps")) + { + if (dryRun) + { + Debug.Log("Would have enabled GSAA normal map contribution for " + mat.name); + } + else + { + mat.SetInt("_GSAAIncludeNormalMaps", 1); + } + } + } + + // Migrate old parallax offsets to new + if (mat.HasProperty("_HeightRefPlane")) + { + var currValue = mat.GetFloat("_HeightRefPlane"); + if (dryRun) + { + Debug.Log("Would have migrated parallax offset for " + mat.name + " from " + currValue + " to " + Mathf.Clamp(currValue - 0.5f, -1, 1)); + } + else + { + mat.SetFloat("_HeightRefPlane", Mathf.Clamp(currValue - 0.5f, -1, 1)); + } + } + + if (mat.HasProperty("INTERNAL_MaterialShaderVersion")) + { + if (dryRun) + { + Debug.Log("Would have upgraded shader version for " + mat.name + " from " + mat.GetInt("INTERNAL_MaterialShaderVersion") + " to " + 700); + } + else + { + mat.SetInt("INTERNAL_MaterialShaderVersion", 700); + } + } + + i++; + } + } + catch (Exception e) + { + Debug.LogException(e); + success = false; + } + finally + { + EditorUtility.ClearProgressBar(); + } + Undo.CollapseUndoOperations(groupId); + return success; + } + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradeV6toV7.cs.meta b/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradeV6toV7.cs.meta new file mode 100644 index 00000000..9fccdf0f --- /dev/null +++ b/Packages/sh.orels.shaders/Editor/UpgradePlans/UpgradeV6toV7.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a6a1b1247d5c144392b8b56d312708d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets.meta b/Packages/sh.orels.shaders/Runtime/Assets.meta new file mode 100644 index 00000000..596101e3 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 465a806cc1d4d6e449ff86895db42157 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot.meta new file mode 100644 index 00000000..677e86df --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4a54bee6d044a4468c19f11e4c0227e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Main.fbx b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Main.fbx new file mode 100644 index 00000000..8fe15acb Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Main.fbx differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Main.fbx.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Main.fbx.meta new file mode 100644 index 00000000..67a09c14 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Main.fbx.meta @@ -0,0 +1,109 @@ +fileFormatVersion: 2 +guid: 97bac029597f2de4c8572211c324d6f8 +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 0 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Tiling U.fbx b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Tiling U.fbx new file mode 100644 index 00000000..30701a92 Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Tiling U.fbx differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Tiling U.fbx.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Tiling U.fbx.meta new file mode 100644 index 00000000..9b2b1560 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot Tiling U.fbx.meta @@ -0,0 +1,109 @@ +fileFormatVersion: 2 +guid: a9db2102e77cf1247811f2cd142c4ebb +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot_dirt.png b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot_dirt.png new file mode 100644 index 00000000..92801dec Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot_dirt.png differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot_dirt.png.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot_dirt.png.meta new file mode 100644 index 00000000..02a13083 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Hotspot_dirt.png.meta @@ -0,0 +1,153 @@ +fileFormatVersion: 2 +guid: f2a76a708b686904a887c99ae1e15c2e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 2 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: 26 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: 41 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: 41 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_groove_normal.png b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_groove_normal.png new file mode 100644 index 00000000..68215aa3 Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_groove_normal.png differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_groove_normal.png.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_groove_normal.png.meta new file mode 100644 index 00000000..8d2b0396 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_groove_normal.png.meta @@ -0,0 +1,153 @@ +fileFormatVersion: 2 +guid: 210e9dfc91d6b244e9fc35371a2e277a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 1 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: 27 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_sharp.png b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_sharp.png new file mode 100644 index 00000000..6f8050ce Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_sharp.png differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_sharp.png.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_sharp.png.meta new file mode 100644 index 00000000..68d40f59 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_sharp.png.meta @@ -0,0 +1,153 @@ +fileFormatVersion: 2 +guid: 34d4e776ad3a50c4f8cd83e7befc6d03 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 16 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: 9 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: 9 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_smooth.png b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_smooth.png new file mode 100644 index 00000000..794e3998 Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_smooth.png differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_smooth.png.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_smooth.png.meta new file mode 100644 index 00000000..0cbcf375 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_hotspot_map_smooth.png.meta @@ -0,0 +1,153 @@ +fileFormatVersion: 2 +guid: 804b9abb2279e3e4491ab390e70e9f45 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 16 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: 9 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: 9 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_spot_id_grayscale.png b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_spot_id_grayscale.png new file mode 100644 index 00000000..abbfee63 Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_spot_id_grayscale.png differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_spot_id_grayscale.png.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_spot_id_grayscale.png.meta new file mode 100644 index 00000000..02d0dc5c --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Main_spot_id_grayscale.png.meta @@ -0,0 +1,153 @@ +fileFormatVersion: 2 +guid: a5a9e401f98aa2d47bde18ffcf2614a3 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: 63 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_groove_normal.png b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_groove_normal.png new file mode 100644 index 00000000..56e1907a Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_groove_normal.png differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_groove_normal.png.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_groove_normal.png.meta new file mode 100644 index 00000000..2cb49f4d --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_groove_normal.png.meta @@ -0,0 +1,153 @@ +fileFormatVersion: 2 +guid: cbdebc5b0eeded0468e31585c79dcc50 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 1 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: 27 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_sharp.png b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_sharp.png new file mode 100644 index 00000000..1d008f11 Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_sharp.png differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_sharp.png.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_sharp.png.meta new file mode 100644 index 00000000..aa71b654 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_sharp.png.meta @@ -0,0 +1,153 @@ +fileFormatVersion: 2 +guid: f442f02a6e5b7ba488d4b21a4121e486 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: 9 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_smooth.png b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_smooth.png new file mode 100644 index 00000000..d614e18b Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_smooth.png differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_smooth.png.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_smooth.png.meta new file mode 100644 index 00000000..2ea7610f --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_hotspot_map_smooth.png.meta @@ -0,0 +1,153 @@ +fileFormatVersion: 2 +guid: eb11f1dffae3017458e4583b7b9ebf5f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: 9 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_spot_id_grayscale.png b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_spot_id_grayscale.png new file mode 100644 index 00000000..a7d239db Binary files /dev/null and b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_spot_id_grayscale.png differ diff --git a/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_spot_id_grayscale.png.meta b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_spot_id_grayscale.png.meta new file mode 100644 index 00000000..9fef38c7 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Assets/Hotspot/Tiling_U_spot_id_grayscale.png.meta @@ -0,0 +1,153 @@ +fileFormatVersion: 2 +guid: 7503e11e653ea5243a7b4e598e5d64cb +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: 63 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AreaLit.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AreaLit.orlshader new file mode 100644 index 00000000..0efc1ee0 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AreaLit.orlshader @@ -0,0 +1,9 @@ +%ShaderName("orels1/Standard AreaLit") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") + +%Includes() +{ + "@/Shaders/ORL Standard", + "@/Modules/AreaLit", + "self" +} diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AreaLit.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AreaLit.orlshader.meta new file mode 100644 index 00000000..bedb26d7 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AreaLit.orlshader.meta @@ -0,0 +1,56 @@ +fileFormatVersion: 2 +guid: 91a81ae41be85d842bfb6ca5047c9f66 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {instanceID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: + - Name: FunctionErrors + Entry: 7 + Data: 0|System.Collections.Generic.Dictionary`2[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser],[System.String, mscorlib]], mscorlib + - Name: comparer + Entry: 7 + Data: 1|System.Collections.Generic.ObjectEqualityComparer`1[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser]], mscorlib + - Name: + Entry: 8 + Data: + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: Errors + Entry: 7 + Data: 2|System.Collections.Generic.List`1[[ORL.ShaderGenerator.ShaderDefinitionImporter+ShaderError, + ORL.ShaderGenerator]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AudioLink Cutout.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AudioLink Cutout.orlshader index be0472cc..09b54551 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AudioLink Cutout.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AudioLink Cutout.orlshader @@ -9,7 +9,7 @@ %Includes() { - "/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AudioLink" + "@/Shaders/ORL Standard AudioLink", "self" } @@ -21,28 +21,10 @@ %ShaderTags() { - "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" + "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" "ORL_RenderType" = "Cutout" } %Variables() { half _Cutoff; -} - -%Fragment("CutoutFragment") -{ - void CutoutFragment(inout SurfaceData o) { - if (o.Alpha < _Cutoff) { - clip(-1); - } - } -} - -%Shadow("CutoutShadow") -{ - void CutoutShadow(inout SurfaceData o) { - if (o.Alpha < _Cutoff) { - clip(-1); - } - } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AudioLink.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AudioLink.orlshader index 2f37ba09..2b4aeb71 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AudioLink.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard AudioLink.orlshader @@ -4,6 +4,6 @@ %Includes() { "@/Shaders/ORL Standard", - "@/Modules/AudioLinkEffects" + "@/Modules/AudioLinkEffects", "self" } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Color Randomisation.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Color Randomisation.orlshader index d47be2db..f1f59fe4 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Color Randomisation.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Color Randomisation.orlshader @@ -16,13 +16,13 @@ %Includes() { - "ORL Standard" + "@/Shaders/ORL Standard" "self" } %ShaderFeatures() { - #pragma shader_feature_local MASK_MODE_ALBEDO MASK_MODE_MASK_TEXTURE + #pragma shader_feature_local_fragment MASK_MODE_ALBEDO MASK_MODE_MASK_TEXTURE } %ShaderDefines() @@ -50,8 +50,8 @@ { void ColorRandomisationFragment(MeshData d, inout SurfaceData o) { - half3 objPivot = mul(unity_ObjectToWorld, half4(0..xxx, 1)).xyz; - half2 uv = half2(((objPivot.x + objPivot.y + objPivot.z) * 100) % 1, 0); + float3 objPivot = TransformObjectToWorld(0..xxx); + float2 uv = float2(((objPivot.x + objPivot.y + objPivot.z) * 100) % 1, 0); half3 color = SAMPLE_TEXTURE2D(_CRColorPalette, sampler_CRColorPalette, uv).rgb; #if defined(MASK_MODE_MASK_TEXTURE) half mask = SAMPLE_TEXTURE2D(_CRMask, sampler_CRColorPalette, d.uv0.xy).rgb; diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Cutout.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Cutout.orlshader index 94417ee0..7fbd2ba6 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Cutout.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Cutout.orlshader @@ -1,9 +1,9 @@ -%ShaderName("orels1/Standard Cutout") +%ShaderName("orels1/Standard Foliage") %CustomEditor("ORL.ShaderInspector.InspectorGUI") %Properties() { - UI_CutoutHeader("# Cutout", Int) = 1 + UI_CutoutHeader("# Foliage", Int) = 1 _Cutoff("Cutoff", Range(0, 1)) = 0.5 [Toggle(_NATIVE_A2C)]_AlphaToMask("Alpha To Coverage (A2C)", Int) = 0 [Toggle(DITHER_FADE)]_EnableDitherFade("Enable Dither Fade", Int) = 0 @@ -19,7 +19,7 @@ %ShaderFeatures() { - #pragma shader_feature_local _NATIVE_A2C + #pragma shader_feature_local_fragment _NATIVE_A2C } %ShaderDefines() @@ -29,7 +29,7 @@ %ShaderTags() { - "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" + "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" "ORL_RenderType" = "Cutout" } %PassModifiers() @@ -65,7 +65,7 @@ %Shadow("CutoutShadow") { void CutoutShadow(FragmentData i) { - half alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv0.xy).a; + half alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw).a; if (alpha < _Cutoff) { clip(-1); } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Decals.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Decals.orlshader new file mode 100644 index 00000000..d3f32ae4 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Decals.orlshader @@ -0,0 +1,64 @@ +%ShaderName("orels1/Standard Decals") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") + +%Properties() +{ + UI_DecalHeader("# Decals", Int) = 1 + _Cutoff("Cutoff", Range(0, 1)) = 0.2 + _ZOffset("Z Offset", Float) = 0.003 + [ToggleUI]_DecalMultiplyAlphaByVertexColor("Multiply Alpha by Vertex Color", Int) = 1 +} + +%Includes() +{ + "@/Shaders/ORL Standard", + "self" +} + +%ShaderTags() +{ + "RenderType" = "Transparent" "Queue" = "Transparent" "ORL_RenderType" = "Custom" +} + +%ShaderModifiers() +{ + ZWrite Off + Blend SrcAlpha OneMinusSrcAlpha +} + +%AddPassModifiers() +{ + Blend SrcAlpha One +} + +%Variables() +{ + float _Cutoff; + float _ZOffset; + int _DecalMultiplyAlphaByVertexColor; +} + +%ShaderDefines() +{ + #define NEED_ALBEDO_ALPHA + #define NEED_FRAGMENT_IN_SHADOW +} + +%Vertex("DecalVertex") +{ + void DecalVertex(inout VertexData v) + { + float3 worldPos = TransformObjectToWorld(v.vertex.xyz); + worldPos += normalize(_WorldSpaceCameraPos - worldPos) * _ZOffset; + v.vertex.xyz = TransformWorldToObject(worldPos); + } +} + +%Fragment("DecalFragment") +{ + void DecalFragment(MeshData d, inout SurfaceData o) + { + o.Alpha *= lerp(1, d.vertexColor.r, _DecalMultiplyAlphaByVertexColor); + clip(o.Alpha - _Cutoff); + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Decals.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Decals.orlshader.meta new file mode 100644 index 00000000..a102cae6 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Decals.orlshader.meta @@ -0,0 +1,56 @@ +fileFormatVersion: 2 +guid: d20baf3874412194f9a02251e9bb935e +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {instanceID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: + - Name: FunctionErrors + Entry: 7 + Data: 0|System.Collections.Generic.Dictionary`2[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser],[System.String, mscorlib]], mscorlib + - Name: comparer + Entry: 7 + Data: 1|System.Collections.Generic.ObjectEqualityComparer`1[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser]], mscorlib + - Name: + Entry: 8 + Data: + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: Errors + Entry: 7 + Data: 2|System.Collections.Generic.List`1[[ORL.ShaderGenerator.ShaderDefinitionImporter+ShaderError, + ORL.ShaderGenerator]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Glass.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Glass.orlshader index ad97b7a9..c281ef0f 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Glass.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Glass.orlshader @@ -18,13 +18,13 @@ %Includes() { "@/Modules/AudioLink", - "/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard", + "@/Shaders/ORL Standard", "self" } %ShaderTags() { - "Queue" = "Transparent" "RenderType" = "Transparent" + "Queue" = "Transparent" "RenderType" = "Transparent" "ORL_RenderType" = "Transparent" } %ShaderModifiers() @@ -34,7 +34,7 @@ %ShaderFeatures() { - #pragma shader_feature_local BLURRY_GLASS + #pragma shader_feature_local_fragment BLURRY_GLASS } %Variables() @@ -78,13 +78,9 @@ half3 reflDir = reflect(-viewDir, reflect(half3(0, 0, 0), wNormal)); half glassBlurMask = SAMPLE_TEXTURE2D(_GlassBlurryMask, sampler_GlassBlurryMask, d.uv0).r; half rough = _GlassBlurryAmount * o.Smoothness * glassBlurMask; - reflDir = lerp(reflDir, wNormal, rough * rough); + reflDir = lerp(reflDir, wNormal, max(rough * rough, 0.002)); - Unity_GlossyEnvironmentData envData; - envData.roughness = rough; - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - - half3 probe0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData); + half3 probe0 = getEnvReflectionDirect(reflDir, d.worldSpacePosition.xyz, wNormal, rough*(1.7 - 0.7*rough), -1); FinalColor.rgb += probe0 * o.Albedo; #endif } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Glass.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Glass.orlshader.meta index fbca52d7..f7d6f271 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Glass.orlshader.meta +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Glass.orlshader.meta @@ -8,7 +8,49 @@ ScriptedImporter: assetBundleName: assetBundleVariant: script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} - nonModifiableTextures: - - _DFG - nonModifiableTextureAssets: - - {fileID: 2800000, guid: 10777c143c503483c9f7f7f34a0cd77a, type: 3} + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {instanceID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: + - Name: FunctionErrors + Entry: 7 + Data: 0|System.Collections.Generic.Dictionary`2[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser],[System.String, mscorlib]], mscorlib + - Name: comparer + Entry: 7 + Data: 1|System.Collections.Generic.ObjectEqualityComparer`1[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser]], mscorlib + - Name: + Entry: 8 + Data: + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: Errors + Entry: 7 + Data: 2|System.Collections.Generic.List`1[[ORL.ShaderGenerator.ShaderDefinitionImporter+ShaderError, + ORL.ShaderGenerator]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Hotspotting.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Hotspotting.orlshader new file mode 100644 index 00000000..f39ac247 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Hotspotting.orlshader @@ -0,0 +1,271 @@ +%ShaderName("orels1/Standard Hotspotting") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") + +%Properties() +{ + UI_HotspottingHeader("# Hotspotting", Int) = 1 + _HotspotMask("Hotspot Mask > %RequiredTexture(@/Hotspot/Main_hotspot_map_smooth.png)", 2D) = "black" {} + _HotspotNormal("Hotspot Normal > %RequiredTexture(@/Hotspot/Main_hotspot_groove_normal.png)", 2D) = "bump" {} + _HotspotTilingX("Tiling X %CombineWith(_HotspotTilingY)", Float) = 1 + [HideInInspector]_HotspotTilingY("Tiling Y", Float) = 1 + [Enum(0 Degrees, 0, 90 Degrees, 1, 180 Degrees, 2, 270 Degrees, 3)]_HotspotRotation("Hotspot Rotation", Int) = 0 + + UI_HotspottingGrooveDetailHeader("# Hotspot Groove Detail", Int) = 1 + _HotspotDirt("Dirt %RequiredTexture(@/Hotspot/Hotspot_dirt.png)", 2D) = "black" {} + _HotspotDirtMaskParams("Edge Masking %Vector2(Mask Min, Mask Max)", Vector) = (0, 100, 0, 0) + _HotspotDirtMaskNudge("Nudge %CombineWith(_HotspotDirtMaskSharpness)", Float) = 1 + [HideInInspector]_HotspotDirtMaskSharpness("Sharpness", Float) = 1 + _HotspotDirtMaskStrength("Dirt Mask Strength", Range(0, 1)) = 1 + _HotspotDirtColor("Color", Color) = (0.5, 0.5, 0.5, 1) + [Enum(Blend, 0, Add, 1, Multiply, 2, Overlay, 3)]_HotspotDirtBlendMode("Color Blend Mode", Int) = 0 + _HotspotDirtBlendOverlayBoost("Overlay Boost %ShowIf(_HotspotDirtBlendMode == 3)", Float) = 1.0 + _HotspotDirtBlendFactor("Blend Amount", Range(0, 1)) = 1 + [Enum(Add, 0, Multiply, 1)]_HotspotSmoothnessBlendMode("Smoothness Blend Mode", Int) = 0 + _HotspotDirtSmoothnessAddModifier("Smoothness Modifier %ShowIf(_HotspotSmoothnessBlendMode == 0)", Range(-1,1)) = 0 + _HotspotDirtSmoothnessMultiplyModifier("Smoothness Modifier %ShowIf(_HotspotSmoothnessBlendMode == 1)", Range(0, 5)) = 1 + + UI_HotspotGrooveAOHeader("## Groove AO", Int) = 1 + _HotspotGrooveAO("AO Strength", Range(0,1)) = 1.0 + _HotspotGrooveAOMaskParams("Masking %Vector2(Mask Min, Mask Max)", Vector) = (0, 100, 0, 0) + _HotspotGrooveAOMaskNudge("Nudge %CombineWith(_HotspotGrooveAOSharpness)", Float) = 1 + [HideInInspector]_HotspotGrooveAOSharpness("Sharpness", Float) = 1 + + UI_HotspottingPerTileHeader("# Hotspot Per-Tile Variance", Int) = 1 + [Toggle(PER_TILE_VARIANCE)]_HotspotPerTileVariance("Add per-tile variance", Int) = 0 + UI_HotspotPerTileVarianceNote("> Adds simple per-tile material variance", Int) = 0 + _HotspotId("Hotspot Id > %RequiredTexture(@/Hotspot/Main_spot_id_grayscale.png) %ShowIf(PER_TILE_VARIANCE)", 2D) = "black" {} + _HotspotVarianceOffset("Variance Offset %ShowIf(PER_TILE_VARIANCE)", Float) = 0 + _HotspotPerTileAlbedo("Albedo Variance %ShowIf(PER_TILE_VARIANCE)", Range(0, 1)) = 0 + _HotspotPerTileSmoothness("Smoothness Variance %ShowIf(PER_TILE_VARIANCE)", Range(0, 1)) = 0 + + UI_HotspottingDetailsHeader("# Hotspot Details", Int) = 1 + [Toggle(HOTSPOT_DETAILS)]_HostpostDetails("Enable Per-Tile Details", Int) = 0 + UI_HotspotDetailsNote("> Adds a second material layer within individual tiles", Int) = 0 + + UI_HotspotDetailsMasking("## Masking %ShowIf(HOTSPOT_DETAILS)", Int) = 0 + _HotspotDetailMaskParams("Masking %ShowIf(HOTSPOT_DETAILS) %Vector2(Mask Min, Mask Max)", Vector) = (0, 100, 0, 0) + _HotsportDetailMaskSharpness("Mask Sharpness %ShowIf(HOTSPOT_DETAILS)", Float) = 1 + _HotspotDetailMaskDirtInfluence("Dirt Mask Influence %ShowIf(HOTSPOT_DETAILS)", Range(0, 1)) = 0 + [Enum(Subtract, 0, Multiply, 1)]_HotspotDetailMaskDirtInfluenceMode("Dirt Mask Influence Mode %ShowIf(HOTSPOT_DETAILS)", Int) = 0 + [ToggleUI]_HotspotDetailMaskDirtInvertInfleunce("Invert Dirt Mask Influence %ShowIf(HOTSPOT_DETAILS && _HotspotDetailMaskDirtInfluenceMode == 0)", Int) = 0 + + UI_HotspotDetailMaterial("## Material Properties %ShowIf(HOTSPOT_DETAILS)", Int) = 0 + _HotspotDetailTintColor("Color %ShowIf(HOTSPOT_DETAILS)", Color) = (1, 1, 1, 1) + _HotspotDetailAlbedo("Albedo %ShowIf(HOTSPOT_DETAILS)", 2D) = "white" {} + _HotspotDetailMasks("Masks > %ShowIf(HOTSPOT_DETAILS)", 2D) = "black" {} + _HotspotDetailNormal("Normal > %ShowIf(HOTSPOT_DETAILS)", 2D) = "bump" {} + _HotspotDetailNormalScale("Normal Scale %ShowIf(HOTSPOT_DETAILS)", Range(-1, 1)) = 1 + [Enum(Blend, 0, Replace, 1)]_HostpotDetailNormalBlend("Normal Blend Mode %ShowIf(HOTSPOT_DETAILS)", Int) = 0 +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment HOTSPOT_DETAILS + #pragma shader_feature_local_fragment PER_TILE_VARIANCE +} + +%ShaderTags() +{ + "PreviewType" = "Plane" +} + +%Includes() +{ + "@/Shaders/ORL Standard", + "self" +} + +%Variables() +{ + int _HotspotRotation; + float _HotspotTilingX; + float _HotspotTilingY; + + half _HotspotVarianceOffset; + half _HotspotPerTileAlbedo; + half _HotspotPerTileSmoothness; + + half _HotspotGrooveAO; + float4 _HotspotGrooveAOMaskParams; + float _HotspotGrooveAOMaskNudge; + float _HotspotGrooveAOSharpness; + float4 _HotspotDirtMaskParams; + float _HotspotDirtMaskNudge; + float _HotspotDirtMaskSharpness; + half _HotspotDirtMaskStrength; + half4 _HotspotDirtColor; + half4 _HotspotDirt_ST; + int _HotspotDirtBlendMode; + half _HotspotDirtBlendOverlayBoost; + half _HotspotDirtBlendFactor; + int _HotspotSmoothnessBlendMode; + half _HotspotDirtSmoothnessAddModifier; + half _HotspotDirtSmoothnessMultiplyModifier; + + int _HostpostDetails; + half4 _HotspotDetailMaskParams; + half _HotsportDetailMaskSharpness; + half _HotspotDetailMaskDirtInfluence; + int _HotspotDetailMaskDirtInfluenceMode; + int _HotspotDetailMaskDirtInvertInfleunce; + half _HotspotDetailNormalScale; + int _HostpotDetailNormalBlend; + half4 _HotspotDetailTintColor; + half4 _HotspotDetailAlbedo_ST; +} + +%Textures() +{ + TEXTURE2D(_HotspotMask); + SAMPLER(sampler_HotspotMask); + TEXTURE2D(_HotspotNormal); + TEXTURE2D(_HotspotId); + TEXTURE2D(_HotspotDirt); + + TEXTURE2D(_HotspotDetailNormal); + SAMPLER(sampler_HotspotDetailNormal); + TEXTURE2D(_HotspotDetailMasks); + SAMPLER(sampler_HotspotDetailMasks); + TEXTURE2D(_HotspotDetailAlbedo); +} + +%Fragment("HotspottingFragment") +{ + void HotspottingFragment(MeshData d, inout SurfaceData o) + { + #if defined(UNITY_PASS_META) + return; + #endif + + float2 uv = d.uv0.xy; + switch (_HotspotRotation) + { + case 1: + uv = uv.yx; + break; + case 2: + uv.y = 1 - uv.y; + break; + case 3: + uv = uv.yx; + uv.y = 1 - uv.y; + break; + } + + uv.xy -= 0.5; + uv.xy *= float2(_HotspotTilingX, _HotspotTilingY); + uv.xy += 0.5; + + float mask = SAMPLE_TEXTURE2D(_HotspotMask, sampler_HotspotMask, uv).r; + + half grooveMask = 1 - smoothstep(_HotspotGrooveAOMaskParams.x, _HotspotGrooveAOMaskParams.y, saturate(mask * _HotspotGrooveAOMaskNudge) * 100.0); + grooveMask = saturate(pow(grooveMask, 1.0 / _HotspotGrooveAOSharpness)); + half dirtMask = smoothstep(_HotspotDirtMaskParams.x, _HotspotDirtMaskParams.y, mask * 100.0); + dirtMask = saturate(dirtMask * _HotspotDirtMaskNudge); + dirtMask = pow(dirtMask, _HotspotDirtMaskSharpness); + half2 dirtUV = uv.xy * _HotspotDirt_ST.xy + _HotspotDirt_ST.zw; + half3 dirt = SAMPLE_TEXTURE2D(_HotspotDirt, sampler_HotspotMask, dirtUV).r; + dirt = lerp(0, dirt, _HotspotDirtMaskStrength); + + o.Occlusion = lerp(o.Occlusion, lerp(1, 0, _HotspotGrooveAO), grooveMask); + + half3 hotspotNormal = UnpackNormalScale(SAMPLE_TEXTURE2D(_HotspotNormal, sampler_HotspotMask, uv), 1.0); + + // Flip the normals for the rotations + switch (_HotspotRotation) + { + case 1: + hotspotNormal.xy = hotspotNormal.yx; + break; + case 2: + hotspotNormal.y *= -1.0; + break; + case 3: + hotspotNormal.xy = hotspotNormal.yx; + hotspotNormal.x *= -1.0; + break; + } + + o.Normal = BlendNormals(o.Normal, hotspotNormal); + + #if defined(HOTSPOT_DETAILS) + { + half detailsMask = smoothstep(_HotspotDetailMaskParams.x, _HotspotDetailMaskParams.y, mask * 100.0); + if (_HotspotDetailMaskDirtInfluenceMode == 0) { + if (_HotspotDetailMaskDirtInvertInfleunce) { + detailsMask = saturate(detailsMask - lerp(0, dirt, _HotspotDetailMaskDirtInfluence)); + } else { + detailsMask = 1 - saturate(((1 - detailsMask) - lerp(0, dirt, _HotspotDetailMaskDirtInfluence))); + } + } else { + detailsMask = saturate(detailsMask * lerp(1, dirt, _HotspotDetailMaskDirtInfluence)); + } + detailsMask = saturate(pow(detailsMask, _HotsportDetailMaskSharpness)); + + half2 detailNormalUV = uv.xy * _HotspotDetailAlbedo_ST.xy + _HotspotDetailAlbedo_ST.zw; + half4 detailNormal = SAMPLE_TEXTURE2D(_HotspotDetailNormal, sampler_HotspotDetailNormal, detailNormalUV); + + if (_HostpotDetailNormalBlend == 0) { + // Blend the detail normals with the base layer normals + o.Normal = BlendNormals(o.Normal, UnpackNormalScale(detailNormal, _HotspotDetailNormalScale * detailsMask)); + } else { + // Replace the base layer normals with the detail normals blended with the hotspot edges + o.Normal = normalize( + lerp( + o.Normal, + BlendNormals(hotspotNormal, UnpackNormalScale(detailNormal, _HotspotDetailNormalScale)), + detailsMask) + ); + } + + half2 detailMasksUV = uv.xy * _HotspotDetailAlbedo_ST.xy + _HotspotDetailAlbedo_ST.zw; + half4 detailMasks = SAMPLE_TEXTURE2D(_HotspotDetailMasks, sampler_HotspotDetailMasks, detailMasksUV); + o.Metallic = lerp(o.Metallic, detailMasks.r, detailsMask); + o.Smoothness = lerp(o.Smoothness, detailMasks.a, detailsMask); + o.Occlusion = lerp(o.Occlusion, detailMasks.g, detailsMask); + + half2 detailAlbedoUV = uv.xy * _HotspotDetailAlbedo_ST.xy + _HotspotDetailAlbedo_ST.zw; + half3 detailAlbedo = SAMPLE_TEXTURE2D(_HotspotDetailAlbedo, sampler_HotspotDetailMasks, detailAlbedoUV).rgb; + + o.Albedo = lerp(o.Albedo, detailAlbedo * _HotspotDetailTintColor.rgb, detailsMask); + } + #endif + + #if defined(PER_TILE_VARIANCE) + { + half variance = SAMPLE_TEXTURE2D(_HotspotId, sampler_HotspotMask, uv.xy).r * 2.0; + variance = frac(variance + _HotspotVarianceOffset); + variance = variance * 2.0 - 1.0; + o.Albedo = lerp(o.Albedo, saturate(o.Albedo + variance), _HotspotPerTileAlbedo); + o.Smoothness = lerp(o.Smoothness, saturate(o.Smoothness - variance), _HotspotPerTileSmoothness); + } + #endif + + // Dirt is overlayed on top + dirtMask = saturate((1 - dirtMask) - dirt); + + // Perform dirt albedo blending + half3 newAlbedo = lerp(o.Albedo, _HotspotDirtColor, dirtMask * _HotspotDirtBlendFactor); + switch (_HotspotDirtBlendMode) + { + case 1: + newAlbedo = lerp(o.Albedo, saturate(o.Albedo + _HotspotDirtColor), dirtMask * _HotspotDirtBlendFactor); + break; + case 2: + newAlbedo = lerp(o.Albedo, saturate(o.Albedo * _HotspotDirtColor), dirtMask * _HotspotDirtBlendFactor); + break; + case 3: + newAlbedo = lerp(o.Albedo, saturate(BlendOverlay(o.Albedo, _HotspotDirtColor * _HotspotDirtBlendOverlayBoost)), dirtMask * _HotspotDirtBlendFactor); + break; + } + + o.Albedo = newAlbedo; + + // Perform dirt smoothness blending + o.Smoothness = lerp( + lerp(o.Smoothness, saturate(o.Smoothness + _HotspotDirtSmoothnessAddModifier), dirtMask), + lerp(o.Smoothness, saturate(o.Smoothness * _HotspotDirtSmoothnessMultiplyModifier), dirtMask), + _HotspotSmoothnessBlendMode + ); + } +} diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Hotspotting.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Hotspotting.orlshader.meta new file mode 100644 index 00000000..cc364c36 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Hotspotting.orlshader.meta @@ -0,0 +1,56 @@ +fileFormatVersion: 2 +guid: 844fbf30f9fd04348be4debe7aae248d +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {instanceID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: + - Name: FunctionErrors + Entry: 7 + Data: 0|System.Collections.Generic.Dictionary`2[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser],[System.String, mscorlib]], mscorlib + - Name: comparer + Entry: 7 + Data: 1|System.Collections.Generic.ObjectEqualityComparer`1[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser]], mscorlib + - Name: + Entry: 8 + Data: + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: Errors + Entry: 7 + Data: 2|System.Collections.Generic.List`1[[ORL.ShaderGenerator.ShaderDefinitionImporter+ShaderError, + ORL.ShaderGenerator]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + debugBuild: 0 + samplerCount: 11 + textureCount: 14 + featureCount: 16 diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard LTCGI Cutout.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard LTCGI Cutout.orlshader index 731002a9..5694b65e 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard LTCGI Cutout.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard LTCGI Cutout.orlshader @@ -17,7 +17,7 @@ %ShaderFeatures() { - #pragma shader_feature_local _NATIVE_A2C + #pragma shader_feature_local_fragment _NATIVE_A2C } %ShaderDefines() @@ -27,7 +27,7 @@ %ShaderTags() { - "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" + "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" "ORL_RenderType" = "Cutout" } %PassModifiers() diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard LTCGI.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard LTCGI.orlshader index caa72d72..23fdd765 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard LTCGI.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard LTCGI.orlshader @@ -3,7 +3,7 @@ %Includes() { - "/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard", + "@/Shaders/ORL Standard", "@/Modules/LTCGI", "self" } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Layered Material Triplanar Effects.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Layered Material Triplanar Effects.orlshader index a18e3d09..f64b99e2 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Layered Material Triplanar Effects.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Layered Material Triplanar Effects.orlshader @@ -1,4 +1,5 @@ %ShaderName("orels1/Standard Layered Material Triplanar Effects") +%TemplateFeatures("Stencil") %CustomEditor("ORL.ShaderInspector.InspectorGUI") %Includes() diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Layered Material.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Layered Material.orlshader index e5fcf7f1..0886bfba 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Layered Material.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Layered Material.orlshader @@ -1,4 +1,5 @@ %ShaderName("orels1/Standard Layered Material") +%TemplateFeatures("Stencil") %CustomEditor("ORL.ShaderInspector.InspectorGUI") %Includes() diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Neon Light.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Neon Light.orlshader index 1b676f30..ed3d4c7f 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Neon Light.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Neon Light.orlshader @@ -33,7 +33,7 @@ %Includes() { - "/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard", + "@/Shaders/ORL Standard", "self" } @@ -74,7 +74,7 @@ { void NeonFragment(MeshData d, inout SurfaceData o) { - half3 pos = mul(unity_ObjectToWorld, half4(0..xxx, 1)); + half3 pos = TransformObjectToWorld(0..xxx); pos *= _FlickerFrequency; pos += _Time.y * _FlickerSpeed; half noise = getBakedNoise(_BakedNoiseTex, sampler_BakedNoiseTex, pos); @@ -107,11 +107,7 @@ UNITY_BRANCH if (_NeonTubeCapEnabled) { - float3 scale = float3( - length(unity_ObjectToWorld._m00_m10_m20), - length(unity_ObjectToWorld._m01_m11_m21), - length(unity_ObjectToWorld._m02_m12_m22) - ); + float3 scale = GetObjectScale(); half mask = 1; if (_NeonTubeCapSource) { mask = 1 - saturate(length(SAMPLE_TEXTURE2D(_NeonTubeCapMask, sampler_NeonTubeCapMask, d.uv0.xy * _NeonTubeCapMask_ST.xy + _NeonTubeCapMask_ST.zw).rgb)); diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Puddles.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Puddles.orlshader index e3d7d3b7..dd1ebd20 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Puddles.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Puddles.orlshader @@ -4,6 +4,6 @@ %Includes() { "@/Shaders/ORL Standard", - "@/Modules/Puddles" + "@/Modules/Puddles", "self", } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tesselated Displacement.shader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tesselated Displacement.shader deleted file mode 100644 index 60b2c3ec..00000000 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tesselated Displacement.shader +++ /dev/null @@ -1,9201 +0,0 @@ -Shader "orels1/Standard Tesselated Displacement" -{ - Properties - { - UI_MainHeader("# Main Settings", Int) = 1 - _Color("Main Color", Color) = (1, 1, 1, 1) - _MainTex("Albedo", 2D) = "white" { } - [Enum(RGB, 0, R, 1, G, 2, B, 3)][_MainTex] _AlbedoChannel("Albedo Channel %ShowIf(_MainTex)", Int) = 0 - [Enum(UV, 0, Local Space, 1, World Space, 2)] _MappingSpace("Mapping Space", Int) = 0 - [Enum(X, 0, Y, 1, Z, 2)] _PlanarAxisX("X Axis %ShowIf(_MappingSpace > 0) %CombineWith(_PlanarAxisY)", Int) = 0 - [HideInInspector][Enum(X, 0, Y, 1, Z, 2)] _PlanarAxisY("Y Axis %ShowIf(_MappingSpace > 0)", Int) = 2 - [NoScaleOffset] _MaskMap("Masks >", 2D) = "white" { } - [Enum(R, 0, G, 1, B, 2, A, 3)] _MetalChannel("Metal %ShowIf(_MaskMap) %CombineWith(_AOChannel, _DetailMaskChannel, _SmoothChannel)", Int) = 0 - [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)] _AOChannel("AO", Int) = 1 - [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)] _DetailMaskChannel("Detail", Int) = 2 - [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)] _SmoothChannel("Smooth", Int) = 3 - _Smoothness("Smoothness %ShowIf(!_MaskMap)", Range(0, 1)) = 0.5 - [ToggleUI][_MaskMap] _RoughnessMode("Roughness Mode %ShowIf(_MaskMap)", Int) = 0 - _Metallic("Metallic %ShowIf(!_MaskMap)", Range(0, 1)) = 0 - _MetallicRemap("Metallic Remap %ShowIf(_MaskMap) %RemapSlider(0,1)", Vector) = (0, 1, 0, 1) - _SmoothnessRemap("Smoothness Remap %ShowIf(_MaskMap) %RemapSlider(0,1)", Vector) = (0, 1, 0, 1) - _OcclusionStrength("AO Strength %ShowIf(_MaskMap)", Range(0, 1)) = 1 - [ToggleUI]_DetailAsTintMask("Detail as Tint Mask %ShowIf(_MaskMap)", Int) = 0 - [NoScaleOffset] _BumpMap("Normal Map >", 2D) = "bump" { } - _BumpScale("Normal Map Scale %ShowIf(_BumpMap)", Range(-1, 1)) = 1 - [ToggleUI]_FlipBumpY("Flip Y (UE Mode) %ShowIf(_BumpMap)", Int) = 0 - [Toggle(_EMISSION)] _EmissionEnabled("Emission", Int) = 0 - _EmissionMap("Emission Map > %ShowIf(_EMISSION)", 2D) = "white" { } - [HDR]_EmissionColor("Emission Color %ShowIf(_EMISSION)", Color) = (0, 0, 0, 1) - [Enum(RGB, 0, R, 1, G, 2, B, 3)][_EmissionMap] _EmissionChannel("Emission Channel %ShowIf(_EmissionMap)", Int) = 0 - - UI_ParallaxHeader("# Parallax", Int) = 0 - UI_ParallaxDocs("[This module has documentation](https://shaders.orels.sh/docs/orl-standard/base-shader#parallax)", Int) = 0 - [Toggle(PARALLAX)]_EnableParallax("Enable Parallax", Int) = 0 - [NoScaleOffset]_Height("Height > %ShowIf(PARALLAX)", 2D) = "black" {} - _HeightScale("Height Scale %ShowIf(PARALLAX)", Range(0, 0.1)) = 0.006 - _HeightRefPlane("Height Ref Plane %ShowIf(PARALLAX)", Range(-1, 1)) = 0.5 - _HeightStepsMin("Steps Min %ShowIf(PARALLAX)", Range(8, 32)) = 8 - _HeightStepsMax("Steps Max %ShowIf(PARALLAX)", Range(8, 32)) = 16 - - UI_DetailsHeader("# Details", Int) = 0 - UI_DetailsDocs("[This module has documentation](https://shaders.orels.sh/docs/orl-standard/base-shader#details)", Int) = 0 - [Toggle(DETAILS_OVERLAY)]_DetailsOverlay("Enable Details", Int) = 0 - [ToggleUI]_DIgnoreMask("Ignore Mask %ShowIf(DETAILS_OVERLAY)", Int) = 0 - UI_IgnoreMaskNote("> Force-draws the detail effects %ShowIf(DETAILS_OVERLAY)", Int) = 0 - [KeywordEnum(Packed, Separated)]DETAILS_MODE("Detail Map Mode %ShowIf(DETAILS_OVERLAY)", Int) = 0 - _DDetailsMap("Details Map %ShowIf(DETAILS_OVERLAY)", 2D) = "gray" { } - UI_DetailsMapNote("> R: Albedo, G: Normal G, B: Smooth, A: Normal R. Uncheck sRGB! %ShowIf(DETAILS_OVERLAY && DETAILS_MODE_PACKED)", Int) = 0 - UI_DetailsMapNoteSeparate("> RGB: Albedo, A: Smooth. Uncheck sRGB! %ShowIf(DETAILS_OVERLAY && DETAILS_MODE_SEPARATED)", Int) = 0 - [NoScaleOffset]_DDetailsNormal("Details Normal Map > %ShowIf(DETAILS_OVERLAY && DETAILS_MODE_SEPARATED)", 2D) = "bump" { } - [Enum(UV, 0, Local Space, 1, World Space, 2)]_DMappingSpace("Mapping Space %ShowIf(DETAILS_OVERLAY)", Int) = 0 - [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_DUVChannel("UV Set %ShowIf(_DMappingSpace == 0 && DETAILS_OVERLAY)", Int) = 0 - [Enum(X, 0, Y, 1, Z, 2)]_DPlanarAxisX("X Axis %ShowIf(_DMappingSpace > 0 && DETAILS_OVERLAY) %CombineWith(_DPlanarAxisY)", Int) = 0 - [HideInInspector][Enum(X, 0, Y, 1, Z, 2)]_DPlanarAxisY("Y Axis", Int) = 2 - _DAlbedoScale("Albedo Scale %ShowIf(DETAILS_OVERLAY)", Range(0.0, 2.0)) = 1 - UI_DetailAlbedoNote("> Values < 0.5 - darken, > 0.5 - lighten %ShowIf(DETAILS_OVERLAY)", Int) = 0 - _DNormalScale("Normal Scale %ShowIf(DETAILS_OVERLAY)", Range(0.0, 2.0)) = 1 - [ToggleUI]_DNormalFlipY("Flip Y (UE Mode) %ShowIf(DETAILS_OVERLAY)", Int) = 0 - _DSmoothScale("Smooth Scale %ShowIf(DETAILS_OVERLAY)", Range(0.0, 2.0)) = 1 - UI_DetailSmoothNote("> Values < 0.5 - roughen, > 0.5 - smoothen %ShowIf(DETAILS_OVERLAY)", Int) = 0 - - UI_TessellationHeader("# Tessellation", Int) = 0 - UI_TessSHNote("> Bakery SH does not show up correctly on tessellated meshes at this point %ShowIf(BAKERY_SH)", Int) = 0 - [KeywordEnum(DistanceBased, EdgeLength)] TESS_MODE("Tessellation Mode", Int) = 0 - [IntRange]_TessFactor("Tessellation Factor %ShowIf(TESS_MODE_DISTANCEBASED)", Range(3, 64)) = 3 - UI_TessFactorNote("> It is recommended to keep this around or below 16 for performance", Int) = 0 - UI_TessNote("> Some AMD GPUs can have issues with tessellation, be weary when using this", Int) = 0 - _TessMinDist("Start Distance %ShowIf(TESS_MODE_DISTANCEBASED)", Float) = 3 - _TessMaxDist("End Distance %ShowIf(TESS_MODE_DISTANCEBASED)", Float) = 20 - _TessEdgeLength("Max Edge Length %ShowIf(TESS_MODE_EDGELENGTH)", Float) = 80 - _TessMaxDisplacement("Max Displacement %ShowIf(TESS_MODE_EDGELENGTH)", Float) = 0.1 - UI_MaxDisplacementNote("> This defines how much you will be displacing the mesh to help with optimisations %ShowIf(TESS_MODE_EDGELENGTH)", Int) = 0 - [Toggle(PHONG)] _TessPhong("Enable Phong", Int) = 0 - UI_PhongNote("> Phong smoothes the mesh along its normals", Int) = 0 - - UI_VertexHeightHeader("# Displacement", Int) = 0 - _VertexHeight("Displacement Map", 2D) = "gray" {} - _VertexHeightAmount("Displacement Amount", Range(0, 3)) = 0 - _VertexHeightOffset("Displacement Offset", Range(-1, 1)) = 0.5 - - UI_AdvancedSettingsHeader("# Advanced Settings", Int) = 1 - [Enum(UnityEngine.Rendering.CullMode)]_CullMode("Culling Mode", Int) = 2 - [Enum(Off, 0, On, 1)]_ZWrite("Depth Write", Int) = 1 - [Enum(UnityEngine.Rendering.CompareFunction)]_ZTest("Depth Test", Int) = 4 - UI_GSAAHeader("## GSAA", Float) = 0 - [Toggle(GSAA)]_EnableGSAA("GSAA Enabled", Int) = 1 - UI_GSAANote("> GSAA dramatically reduces specular aliasing", Int) = 0 - _GSAAVariance("GSAA Variance %ShowIf(GSAA)", Range(0, 1)) = 0.05 - _GSAAThreshold("GSAA Threshold %ShowIf(GSAA)", Range(0, 1)) = 0.1 - [Toggle(NONLINEAR_SH)]_NonlinearSH("Non-Linear Lightprobe SH", Int) = 0 - [Toggle(FORCE_BOX_PROJECTION)]_ForceBoxProjection("Force Box Projection", Int) = 0 - UI_LightmappingHeader("# Lightmapping", Int) = 1 - UI_LightmappingDocs("[This module has documentation](https://shaders.orels.sh/docs/orl-standard/base-shader#lightmapping)", Int) = 0 - _SpecOcclusion("Specular Occlusion", Range(0, 1)) = 0.75 - _SpecularRoughnessMod("Specular Roughness Mod", Range(0, 1)) = 1 - [Toggle(BICUBIC_LIGHTMAP)]_Bicubic("Bicubic Sampling", Int) = 0 - [Toggle(BAKED_SPECULAR)]_BakedSpecular("Baked Specular", Int) = 0 - UI_BakeryHeader("## Bakery Features", Int) = 0 - [Toggle(BAKERY_ENABLED)]_BakeryEnabled("Enable Bakery Features", Int) = 0 - [KeywordEnum(None, MONOSH, SH, RNM)]BAKERY("Bakery Mode %ShowIf(BAKERY_ENABLED)", Int) = 0 - [Toggle(BAKERY_SHNONLINEAR)]_BakerySHNonLinear("Bakery Non-Linear SH %ShowIf(BAKERY_ENABLED)", Int) = 1 - UI_InternalHeader("# Internal", Int) = 0 - [NonModifiableTextureData]_DFG("DFG > %RequiredTexture(@/dfg-multiscatter.exr)", 2D) = "white" {} - _RNM0("RNM0 >", 2D) = "black" {} - _RNM1("RNM1 >", 2D) = "black" {} - _RNM2("RNM2 >", 2D) = "black" {} - } - SubShader - { - Tags { } - - ZTest[_ZTest] - ZWrite[_ZWrite] - Cull[_CullMode] - - CGINCLUDE - // Credit to Jason Booth for digging this all up - // This originally comes from CoreRP, see Jason's comment below - - // If your looking in here and thinking WTF, yeah, I know. These are taken from the SRPs, to allow us to use the same - // texturing library they use. However, since they are not included in the standard pipeline by default, there is no - // way to include them in and they have to be inlined, since someone could copy this shader onto another machine without - // Better Shaders installed. Unfortunate, but I'd rather do this and have a nice library for texture sampling instead - // of the patchy one Unity provides being inlined/emulated in HDRP/URP. Strangely, PSSL and XBoxOne libraries are not - // included in the standard SRP code, but they are in tons of Unity own projects on the web, so I grabbed them from there. - - #if defined(SHADER_API_XBOXONE) - - // Initialize arbitrary structure with zero values. - // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 - #define ZERO_INITIALIZE(type, name) name = (type)0; - #define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } - - // Texture util abstraction - - #define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2) - - // Texture abstraction - - #define TEXTURE2D(textureName) Texture2D textureName - #define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName - #define TEXTURECUBE(textureName) TextureCube textureName - #define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName - #define TEXTURE3D(textureName) Texture3D textureName - - #define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName) - #define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName) - - #define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName) - #define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName) - - #define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) - - #define RW_TEXTURE2D(type, textureName) RWTexture2D textureName - #define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray textureName - #define RW_TEXTURE3D(type, textureName) RWTexture3D textureName - - #define SAMPLER(samplerName) SamplerState samplerName - #define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName - - #define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName) - #define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName) - - #define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName) - #define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName) - - #define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName - - #define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - - #define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2) - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod) - #define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias) - #define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy) - #define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index)) - #define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod) - #define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias) - #define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy) - #define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - #define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias) - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index)) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias) - #define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - - #define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z) - #define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z) - #define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w) - #define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w) - - #define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0)) - #define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod)) - #define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex) - #define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0)) - #define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex) - #define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod)) - #define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0)) - #define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod)) - - #define PLATFORM_SUPPORT_GATHER - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index)) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index)) - #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2) - #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2) - #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2) - #define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) - - #elif defined(SHADER_API_PSSL) - - // Initialize arbitrary structure with zero values. - // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 - #define ZERO_INITIALIZE(type, name) name = (type)0; - #define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } - - // Texture util abstraction - - #define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.GetLOD(samplerName, coord2) - - // Texture abstraction - - #define TEXTURE2D(textureName) Texture2D textureName - #define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName - #define TEXTURECUBE(textureName) TextureCube textureName - #define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName - #define TEXTURE3D(textureName) Texture3D textureName - - #define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName) - #define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName) - - #define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName) - #define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName) - - #define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) - - #define RW_TEXTURE2D(type, textureName) RW_Texture2D textureName - #define RW_TEXTURE2D_ARRAY(type, textureName) RW_Texture2D_Array textureName - #define RW_TEXTURE3D(type, textureName) RW_Texture3D textureName - - #define SAMPLER(samplerName) SamplerState samplerName - #define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName - - #define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName) - #define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName) - - #define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName) - #define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName) - - #define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName - - #define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - - #define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2) - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod) - #define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias) - #define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy) - #define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index)) - #define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod) - #define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias) - #define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy) - #define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - #define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias) - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index)) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias) - #define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - - #define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z) - #define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z) - #define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w) - #define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w) - - #define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0)) - #define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod)) - #define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex) - #define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0)) - #define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex) - #define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod)) - #define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0)) - #define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod)) - - #define PLATFORM_SUPPORT_GATHER - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index)) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index)) - #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2) - #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2) - #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2) - #define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) - - #elif defined(SHADER_API_D3D11) - - // Initialize arbitrary structure with zero values. - // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 - #define ZERO_INITIALIZE(type, name) name = (type)0; - #define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } - - // Texture util abstraction - - #define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2) - - // Texture abstraction - - #define TEXTURE2D(textureName) Texture2D textureName - #define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName - #define TEXTURECUBE(textureName) TextureCube textureName - #define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName - #define TEXTURE3D(textureName) Texture3D textureName - - #define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName) - #define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName) - - #define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName) - #define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName) - - #define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) - - #define RW_TEXTURE2D(type, textureName) RWTexture2D textureName - #define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray textureName - #define RW_TEXTURE3D(type, textureName) RWTexture3D textureName - - #define SAMPLER(samplerName) SamplerState samplerName - #define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName - - #define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName) - #define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName) - - #define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName) - #define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName) - - #define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName - - #define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - - #define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2) - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod) - #define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias) - #define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy) - #define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index)) - #define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod) - #define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias) - #define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy) - #define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - #define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias) - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index)) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias) - #define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - - #define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z) - #define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z) - #define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w) - #define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w) - - #define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0)) - #define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod)) - #define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex) - #define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0)) - #define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex) - #define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod)) - #define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0)) - #define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod)) - - #define PLATFORM_SUPPORT_GATHER - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index)) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index)) - #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2) - #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2) - #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2) - #define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) - - #elif defined(SHADER_API_METAL) - - // Initialize arbitrary structure with zero values. - // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 - #define ZERO_INITIALIZE(type, name) name = (type)0; - #define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } - - // Texture util abstraction - - #define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2) - - // Texture abstraction - - #define TEXTURE2D(textureName) Texture2D textureName - #define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName - #define TEXTURECUBE(textureName) TextureCube textureName - #define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName - #define TEXTURE3D(textureName) Texture3D textureName - - #define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName - #define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added - #define TEXTURECUBE_FLOAT(textureName) TextureCube_float textureName - #define TEXTURECUBE_ARRAY_FLOAT(textureName) TextureCubeArray textureName // no support to _float on Array, it's being added - #define TEXTURE3D_FLOAT(textureName) Texture3D_float textureName - - #define TEXTURE2D_HALF(textureName) Texture2D_half textureName - #define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added - #define TEXTURECUBE_HALF(textureName) TextureCube_half textureName - #define TEXTURECUBE_ARRAY_HALF(textureName) TextureCubeArray textureName // no support to _float on Array, it's being added - #define TEXTURE3D_HALF(textureName) Texture3D_half textureName - - #define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) - - #define RW_TEXTURE2D(type, textureName) RWTexture2D textureName - #define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray textureName - #define RW_TEXTURE3D(type, textureName) RWTexture3D textureName - - #define SAMPLER(samplerName) SamplerState samplerName - #define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName - - #define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName) - #define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName) - - #define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName) - #define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName) - - #define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName - - #define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - - #define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2) - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod) - #define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias) - #define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy) - #define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index)) - #define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod) - #define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias) - #define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy) - #define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - #define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias) - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index)) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias) - #define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - - #define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z) - #define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z) - #define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w) - #define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w) - - #define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0)) - #define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod)) - #define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex) - #define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0)) - #define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex) - #define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod)) - #define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0)) - #define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod)) - - #define PLATFORM_SUPPORT_GATHER - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index)) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index)) - #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2) - #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2) - #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2) - #define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) - - #elif defined(SHADER_API_VULKAN) - // This file assume SHADER_API_VULKAN is defined - // TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed. - - // Initialize arbitrary structure with zero values. - // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 - #define ZERO_INITIALIZE(type, name) name = (type)0; - #define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } - - // Texture util abstraction - - #define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2) - - // Texture abstraction - - #define TEXTURE2D(textureName) Texture2D textureName - #define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName - #define TEXTURECUBE(textureName) TextureCube textureName - #define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName - #define TEXTURE3D(textureName) Texture3D textureName - - #define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName - #define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added - #define TEXTURECUBE_FLOAT(textureName) TextureCube_float textureName - #define TEXTURECUBE_ARRAY_FLOAT(textureName) TextureCubeArray textureName // no support to _float on Array, it's being added - #define TEXTURE3D_FLOAT(textureName) Texture3D_float textureName - - #define TEXTURE2D_HALF(textureName) Texture2D_half textureName - #define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added - #define TEXTURECUBE_HALF(textureName) TextureCube_half textureName - #define TEXTURECUBE_ARRAY_HALF(textureName) TextureCubeArray textureName // no support to _float on Array, it's being added - #define TEXTURE3D_HALF(textureName) Texture3D_half textureName - - #define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) - - #define RW_TEXTURE2D(type, textureName) RWTexture2D textureName - #define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray textureName - #define RW_TEXTURE3D(type, textureName) RWTexture3D textureName - - #define SAMPLER(samplerName) SamplerState samplerName - #define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName - - #define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName) - #define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName) - - #define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName) - #define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName) - - #define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName - - #define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - - #define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2) - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod) - #define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias) - #define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy) - #define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index)) - #define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod) - #define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias) - #define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy) - #define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - #define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias) - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index)) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias) - #define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - - #define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z) - #define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z) - #define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w) - #define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w) - - #define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0)) - #define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod)) - #define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex) - #define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0)) - #define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex) - #define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod)) - #define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0)) - #define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod)) - - #define PLATFORM_SUPPORT_GATHER - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index)) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index)) - #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2) - #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2) - #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2) - #define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) - - #elif defined(SHADER_API_SWITCH) - // This file assume SHADER_API_SWITCH is defined - - // Initialize arbitrary structure with zero values. - // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 - #define ZERO_INITIALIZE(type, name) name = (type)0; - #define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } - - // Texture util abstraction - - #define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2) - - // Texture abstraction - - #define TEXTURE2D(textureName) Texture2D textureName - #define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName - #define TEXTURECUBE(textureName) TextureCube textureName - #define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName - #define TEXTURE3D(textureName) Texture3D textureName - - #define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName - #define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added - #define TEXTURECUBE_FLOAT(textureName) TextureCube_float textureName - #define TEXTURECUBE_ARRAY_FLOAT(textureName) TextureCubeArray textureName // no support to _float on Array, it's being added - #define TEXTURE3D_FLOAT(textureName) Texture3D_float textureName - - #define TEXTURE2D_HALF(textureName) Texture2D_half textureName - #define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added - #define TEXTURECUBE_HALF(textureName) TextureCube_half textureName - #define TEXTURECUBE_ARRAY_HALF(textureName) TextureCubeArray textureName // no support to _float on Array, it's being added - #define TEXTURE3D_HALF(textureName) Texture3D_half textureName - - #define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) - - #define RW_TEXTURE2D(type, textureName) RWTexture2D textureName - #define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray textureName - #define RW_TEXTURE3D(type, textureName) RWTexture3D textureName - - #define SAMPLER(samplerName) SamplerState samplerName - #define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName - - #define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName) - #define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName) - - #define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName) - #define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName) - - #define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName - - #define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - - #define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2) - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod) - #define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias) - #define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy) - #define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index)) - #define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod) - #define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias) - #define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy) - #define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - #define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias) - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index)) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias) - #define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - - #define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z) - #define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z) - #define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w) - #define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w) - - #define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0)) - #define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod)) - #define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex) - #define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0)) - #define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod)) - #define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0)) - #define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod)) - - #define PLATFORM_SUPPORT_GATHER - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index)) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index)) - #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2) - #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2) - #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2) - #define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) - - #elif defined(SHADER_API_GLCORE) - - // OpenGL 4.1 SM 5.0 https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html - #if (SHADER_TARGET >= 46) - #define OPENGL4_1_SM5 1 - #else - #define OPENGL4_1_SM5 0 - #endif - - // Initialize arbitrary structure with zero values. - // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 - #define ZERO_INITIALIZE(type, name) name = (type)0; - #define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } - - // Texture util abstraction - - #define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2) - - // Texture abstraction - - #define TEXTURE2D(textureName) Texture2D textureName - #define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName - #define TEXTURECUBE(textureName) TextureCube textureName - #define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName - #define TEXTURE3D(textureName) Texture3D textureName - - #define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName) - #define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName) - - #define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName) - #define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName) - - #define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) - - #define RW_TEXTURE2D(type, textureName) RWTexture2D textureName - #define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray textureName - #define RW_TEXTURE3D(type, textureName) RWTexture3D textureName - - #define SAMPLER(samplerName) SamplerState samplerName - #define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName - - #define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName) - #define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName) - - #define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName) - #define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName) - - #define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName - - #define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - - #define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2) - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod) - #define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias) - #define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy) - #define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index)) - #define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod) - #define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias) - #define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy) - #define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - #define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias) - #ifdef UNITY_NO_CUBEMAP_ARRAY - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_LOD) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_LOD) - #else - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index)) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)textureName.SampleBias(samplerName, float4(coord3, index), bias) - #endif - #define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - - #define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z) - #define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z) - #define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w) - #define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w) - - #define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0)) - #define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod)) - #define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex) - #define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0)) - #define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex) - #define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod)) - - #if OPENGL4_1_SM5 - #define PLATFORM_SUPPORT_GATHER - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index)) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index)) - #else - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D_ARRAY) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE_ARRAY) - #endif - - #elif defined(SHADER_API_GLES3) - - // GLES 3.1 + AEP shader feature https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html - #if (SHADER_TARGET >= 40) - #define GLES3_1_AEP 1 - #else - #define GLES3_1_AEP 0 - #endif - - // Initialize arbitrary structure with zero values. - // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 - #define ZERO_INITIALIZE(type, name) name = (type)0; - #define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } - - // Texture util abstraction - - #define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2) - - // Texture abstraction - - #define TEXTURE2D(textureName) Texture2D textureName - #define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName - #define TEXTURECUBE(textureName) TextureCube textureName - #define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName - #define TEXTURE3D(textureName) Texture3D textureName - - #define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName - #define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added - #define TEXTURECUBE_FLOAT(textureName) TextureCube_float textureName - #define TEXTURECUBE_ARRAY_FLOAT(textureName) TextureCubeArray textureName // no support to _float on Array, it's being added - #define TEXTURE3D_FLOAT(textureName) Texture3D_float textureName - - #define TEXTURE2D_HALF(textureName) Texture2D_half textureName - #define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added - #define TEXTURECUBE_HALF(textureName) TextureCube_half textureName - #define TEXTURECUBE_ARRAY_HALF(textureName) TextureCubeArray textureName // no support to _float on Array, it's being added - #define TEXTURE3D_HALF(textureName) Texture3D_half textureName - - #define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName) - #define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName) - #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) - #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) - - #if GLES3_1_AEP - #define RW_TEXTURE2D(type, textureName) RWTexture2D textureName - #define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray textureName - #define RW_TEXTURE3D(type, textureName) RWTexture3D textureName - #else - #define RW_TEXTURE2D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2D) - #define RW_TEXTURE2D_ARRAY(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2DArray) - #define RW_TEXTURE3D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture3D) - #endif - - #define SAMPLER(samplerName) SamplerState samplerName - #define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName - - #define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName) - #define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName) - #define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName) - #define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName) - - #define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName) - #define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName) - #define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName) - - #define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName - - #define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - #define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName - - #define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2) - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod) - #define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias) - #define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy) - #define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index)) - #define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod) - #define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias) - #define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy) - #define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - #define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias) - - #ifdef UNITY_NO_CUBEMAP_ARRAY - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_LOD) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_BIAS) - #else - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index)) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)textureName.SampleBias(samplerName, float4(coord3, index), bias) - #endif - - #define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3) - #define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod) - - #define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z) - #define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z) - #define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w) - #define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w) - - #define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0)) - #define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod)) - #define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex) - #define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0)) - #define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex) - #define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod)) - #define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0)) - #define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod)) - - #if GLES3_1_AEP - #define PLATFORM_SUPPORT_GATHER - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index)) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index)) - #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2) - #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2) - #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2) - #define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) - #else - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D_ARRAY) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE_ARRAY) - #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_RED_TEXTURE2D) - #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_GREEN_TEXTURE2D) - #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_BLUE_TEXTURE2D) - #define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_ALPHA_TEXTURE2D) - #endif - - #elif defined(SHADER_API_GLES) - - #define uint int - - #define rcp(x) 1.0 / (x) - #define ddx_fine ddx - #define ddy_fine ddy - #define asfloat - #define asuint(x) asint(x) - #define f32tof16 - #define f16tof32 - - #define ERROR_ON_UNSUPPORTED_FUNCTION(funcName) #error #funcName is not supported on GLES 2.0 - - // Initialize arbitrary structure with zero values. - // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 - #define ZERO_INITIALIZE(type, name) name = (type)0; - #define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } } - - // Texture util abstraction - - #define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) #error calculate Level of Detail not supported in GLES2 - - // Texture abstraction - - #define TEXTURE2D(textureName) sampler2D textureName - #define TEXTURE2D_ARRAY(textureName) samplerCUBE textureName // No support to texture2DArray - #define TEXTURECUBE(textureName) samplerCUBE textureName - #define TEXTURECUBE_ARRAY(textureName) samplerCUBE textureName // No supoport to textureCubeArray and can't emulate with texture2DArray - #define TEXTURE3D(textureName) sampler3D textureName - - #define TEXTURE2D_FLOAT(textureName) sampler2D_float textureName - #define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURECUBE_FLOAT(textureName) // No support to texture2DArray - #define TEXTURECUBE_FLOAT(textureName) samplerCUBE_float textureName - #define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_FLOAT(textureName) // No support to textureCubeArray - #define TEXTURE3D_FLOAT(textureName) sampler3D_float textureName - - #define TEXTURE2D_HALF(textureName) sampler2D_half textureName - #define TEXTURE2D_ARRAY_HALF(textureName) TEXTURECUBE_HALF(textureName) // No support to texture2DArray - #define TEXTURECUBE_HALF(textureName) samplerCUBE_half textureName - #define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_HALF(textureName) // No support to textureCubeArray - #define TEXTURE3D_HALF(textureName) sampler3D_half textureName - - #define TEXTURE2D_SHADOW(textureName) SHADOW2D_TEXTURE_AND_SAMPLER textureName - #define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURECUBE_SHADOW(textureName) // No support to texture array - #define TEXTURECUBE_SHADOW(textureName) SHADOWCUBE_TEXTURE_AND_SAMPLER textureName - #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_SHADOW(textureName) // No support to texture array - - #define RW_TEXTURE2D(type, textureNam) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2D) - #define RW_TEXTURE2D_ARRAY(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2DArray) - #define RW_TEXTURE3D(type, textureNam) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture3D) - - #define SAMPLER(samplerName) - #define SAMPLER_CMP(samplerName) - - #define TEXTURE2D_PARAM(textureName, samplerName) sampler2D textureName - #define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) samplerCUBE textureName - #define TEXTURECUBE_PARAM(textureName, samplerName) samplerCUBE textureName - #define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) samplerCUBE textureName - #define TEXTURE3D_PARAM(textureName, samplerName) sampler3D textureName - #define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) SHADOW2D_TEXTURE_AND_SAMPLER textureName - #define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) SHADOWCUBE_TEXTURE_AND_SAMPLER textureName - #define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) SHADOWCUBE_TEXTURE_AND_SAMPLER textureName - - #define TEXTURE2D_ARGS(textureName, samplerName) textureName - #define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName - #define TEXTURECUBE_ARGS(textureName, samplerName) textureName - #define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName - #define TEXTURE3D_ARGS(textureName, samplerName) textureName - #define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName - #define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName - #define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName - - #define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) tex2D(textureName, coord2) - - #if (SHADER_TARGET >= 30) - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) tex2Dlod(textureName, float4(coord2, 0, lod)) - #else - // No lod support. Very poor approximation with bias. - #define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, lod) - #endif - - #define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) tex2Dbias(textureName, float4(coord2, 0, bias)) - #define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) SAMPLE_TEXTURE2D(textureName, samplerName, coord2) - #define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY) - #define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_LOD) - #define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_BIAS) - #define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_GRAD) - #define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) texCUBE(textureName, coord3) - // No lod support. Very poor approximation with bias. - #define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, lod) - #define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) texCUBEbias(textureName, float4(coord3, bias)) - #define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY) - #define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_LOD) - #define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_BIAS) - #define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) tex3D(textureName, coord3) - #define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE3D_LOD) - - #define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) SHADOW2D_SAMPLE(textureName, samplerName, coord3) - #define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_SHADOW) - #define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) SHADOWCUBE_SAMPLE(textureName, samplerName, coord4) - #define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_SHADOW) - - // Not supported. Can't define as error because shader library is calling these functions. - #define LOAD_TEXTURE2D(textureName, unCoord2) half4(0, 0, 0, 0) - #define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) half4(0, 0, 0, 0) - #define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) half4(0, 0, 0, 0) - #define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) half4(0, 0, 0, 0) - #define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) half4(0, 0, 0, 0) - #define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) half4(0, 0, 0, 0) - #define LOAD_TEXTURE3D(textureName, unCoord3) ERROR_ON_UNSUPPORTED_FUNCTION(LOAD_TEXTURE3D) - #define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) ERROR_ON_UNSUPPORTED_FUNCTION(LOAD_TEXTURE3D_LOD) - - // Gather not supported. Fallback to regular texture sampling. - #define GATHER_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D) - #define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D_ARRAY) - #define GATHER_TEXTURECUBE(textureName, samplerName, coord3) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE) - #define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE_ARRAY) - #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_RED_TEXTURE2D) - #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_GREEN_TEXTURE2D) - #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_BLUE_TEXTURE2D) - #define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_ALPHA_TEXTURE2D) - - #else - #error unsupported shader api - #endif - - // default flow control attributes - #ifndef UNITY_BRANCH - # define UNITY_BRANCH - #endif - #ifndef UNITY_FLATTEN - # define UNITY_FLATTEN - #endif - #ifndef UNITY_UNROLL - # define UNITY_UNROLL - #endif - #ifndef UNITY_UNROLLX - # define UNITY_UNROLLX(_x) - #endif - #ifndef UNITY_LOOP - # define UNITY_LOOP - #endif - - ENDCG - - Pass - { - Tags { "LightMode" = "ForwardBase" } - - // ForwardBase Pass Start - CGPROGRAM - #pragma target 4.6 - #pragma require tesshw - #pragma multi_compile_instancing - #pragma multi_compile_fwdbase - #pragma multi_compile_fog - #pragma vertex Vertex - #pragma fragment Fragment - #pragma hull Hull - #pragma domain Domain - #pragma shader_feature_local _EMISSION - - #pragma shader_feature_local PARALLAX - - #pragma shader_feature_local DETAILS_OVERLAY - #pragma shader_feature_local _ DETAILS_MODE_PACKED DETAILS_MODE_SEPARATED - - #pragma shader_feature_local _ TESS_MODE_DISTANCEBASED TESS_MODE_EDGELENGTH - #pragma shader_feature_local PHONG - - #pragma shader_feature_local BICUBIC_LIGHTMAP - #pragma shader_feature_local BAKED_SPECULAR - #pragma shader_feature_local GSAA - #pragma shader_feature_local FORCE_BOX_PROJECTION - - // Bakery Stuff - #pragma shader_feature_local BAKERY_ENABLED - #pragma shader_feature_local _ BAKERY_RNM BAKERY_SH BAKERY_MONOSH - #pragma shader_feature_local BAKERY_SHNONLINEAR - - #define UNITY_INSTANCED_LOD_FADE - #define UNITY_INSTANCED_SH - #define UNITY_INSTANCED_LIGHTMAPSTS - - #ifndef UNITY_PASS_FORWARDBASE - #define UNITY_PASS_FORWARDBASE - #endif - - #if defined(SHADER_API_XBOXONE) || defined(SHADER_API_PSSL) - #define MAX_TESSELLATION_FACTORS 15.0 - #else - #define MAX_TESSELLATION_FACTORS 64.0 - #endif - - #include "UnityStandardUtils.cginc" - #include "Lighting.cginc" - #include "AutoLight.cginc" - #include "Tessellation.cginc" - - #define FLT_EPSILON 1.192092896e-07 - - #define _MASKMAP_SAMPLED - - #define _SET_GLOBAL_UVS - - #if !defined(DETAILS_MODE_PACKED) && !defined(DETAILS_MODE_SEPARATED) - #define DETAILS_MODE_PACKED - #endif - - #define TESS_FACTORS_FUNC_DEFINED - - #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) - #define PLAT_QUEST - #else - #ifdef PLAT_QUEST - #undef PLAT_QUEST - #endif - #endif - - #if !defined(LIGHTMAP_ON) || !defined(UNITY_PASS_FORWARDBASE) - #undef BAKERY_SH - #undef BAKERY_RNM - #endif - - #ifdef LIGHTMAP_ON - #undef BAKERY_VOLUME - #endif - - #ifdef LIGHTMAP_ON - #if defined(BAKERY_RNM) || defined(BAKERY_SH) || defined(BAKERY_VERTEXLM) - #define BAKERYLM_ENABLED - #undef DIRLIGHTMAP_COMBINED - #endif - #endif - - #if defined(BAKERY_SH) || defined(BAKERY_RNM) || defined(BAKERY_VOLUME) - #ifdef BAKED_SPECULAR - #define _BAKERY_LMSPEC - #define BAKERY_LMSPEC - #endif - #endif - - #define NEED_SCREEN_POS - - struct VertexData - { - float4 vertex : POSITION; - float3 normal : NORMAL; - float4 tangent : TANGENT; - float4 color : COLOR; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - UNITY_VERTEX_INPUT_INSTANCE_ID - }; - - struct FragmentData - { - #if defined(UNITY_PASS_SHADOWCASTER) - V2F_SHADOW_CASTER; - float2 uv0 : TEXCOORD1; - float2 uv1 : TEXCOORD2; - float2 uv2 : TEXCOORD3; - float2 uv3 : TEXCOORD4; - float3 worldPos : TEXCOORD5; - float3 worldNormal : TEXCOORD6; - float4 worldTangent : TEXCOORD7; - #else - float4 pos : SV_POSITION; - float3 normal : NORMAL; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - float3 worldPos : TEXCOORD4; - float3 worldNormal : TEXCOORD5; - float4 worldTangent : TEXCOORD6; - float4 lightmapUv : TEXCOORD7; - float4 vertexColor : TEXCOORD8; - - #if !defined(UNITY_PASS_META) - UNITY_LIGHTING_COORDS(9, 10) - UNITY_FOG_COORDS(11) - #endif - #endif - - #if defined(EDITOR_VISUALIZATION) - float2 vizUV : TEXCOORD9; - float4 lightCoord : TEXCOORD10; - #endif - - #if defined(NEED_SCREEN_POS) - float4 screenPos: SCREENPOS; - #endif - - #if defined(EXTRA_V2F_0) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F0 : TEXCOORD8; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F0 : TEXCOORD12; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F0 : TEXCOORD11; - #else - float4 extraV2F0 : TEXCOORD9; - #endif - #endif - #endif - #endif - #if defined(EXTRA_V2F_1) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F1 : TEXCOORD9; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F1 : TEXCOORD13; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F1 : TEXCOORD14; - #else - float4 extraV2F1 : TEXCOORD15; - #endif - #endif - #endif - #endif - #if defined(EXTRA_V2F_2) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F2 : TEXCOORD10; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F2 : TEXCOORD14; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F2 : TEXCOORD15 - #else - float4 extraV2F2 : TEXCOORD16; - #endif - #endif - #endif - #endif - - UNITY_VERTEX_INPUT_INSTANCE_ID - UNITY_VERTEX_OUTPUT_STEREO - }; - - struct MeshData - { - half2 uv0; - half2 uv1; - half2 uv2; - half2 uv3; - half4 vertexColor; - half3 normal; - half3 worldNormal; - half3 localSpacePosition; - half3 worldSpacePosition; - half3 worldSpaceViewDir; - half3 tangentSpaceViewDir; - float3x3 TBNMatrix; - float4 extraV2F0; - float4 extraV2F1; - float4 extraV2F2; - float4 screenPos; - }; - - MeshData CreateMeshData(FragmentData i) - { - MeshData m = (MeshData) 0; - m.uv0 = i.uv0; - m.uv1 = i.uv1; - m.uv2 = i.uv2; - m.uv3 = i.uv3; - m.worldNormal = normalize(i.worldNormal); - m.localSpacePosition = mul(unity_WorldToObject, float4(i.worldPos, 1)).xyz; - m.worldSpacePosition = i.worldPos; - m.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos); - - #if !defined(UNITY_PASS_SHADOWCASTER) - m.vertexColor = i.vertexColor; - m.normal = i.normal; - float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * - 1; - m.TBNMatrix = float3x3(normalize(i.worldTangent.xyz), bitangent, m.worldNormal); - m.tangentSpaceViewDir = mul(m.TBNMatrix, m.worldSpaceViewDir); - #endif - - #if defined(EXTRA_V2F_0) - m.extraV2F0 = i.extraV2F0; - #endif - #if defined(EXTRA_V2F_1) - m.extraV2F1 = i.extraV2F1; - #endif - #if defined(EXTRA_V2F_2) - m.extraV2F2 = i.extraV2F2; - #endif - #if defined(NEED_SCREEN_POS) - m.screenPos = i.screenPos; - #endif - - return m; - } - - struct SurfaceData - { - half3 Albedo; - half3 Emission; - half Metallic; - half Smoothness; - half Occlusion; - half3 Normal; - half Alpha; - }; - - struct TessellationFactors - { - float edge[3] : SV_TessFactor; - float inside : SV_InsideTessFactor; - }; - - struct TessVertex - { - float4 vertex : INTERNALTESSPOS; - float3 normal : NORMAL; - float4 tangent : TANGENT; - float4 color : COLOR; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - UNITY_VERTEX_INPUT_INSTANCE_ID - UNITY_VERTEX_OUTPUT_STEREO - }; - - FragmentData FragData; - SurfaceData o; - MeshData d; - VertexData vD; - float4 FinalColor; - - half invLerp(half a, half b, half v) - { - return (v - a) / (b - a); - } - - half getBakedNoise(Texture2D noiseTex, SamplerState noiseTexSampler, half3 p) - { - half3 i = floor(p); p -= i; p *= p * (3. - 2. * p); - half2 uv = (p.xy + i.xy + half2(37, 17) * i.z + .5) / 256.; - uv.y *= -1; - p.xy = noiseTex.SampleLevel(noiseTexSampler, uv, 0).yx; - return lerp(p.x, p.y, p.z); - } - - half3 TransformObjectToWorld(half3 pos) - { - return mul(unity_ObjectToWorld, half4(pos, 1)).xyz; - }; - - // mostly taken from the Amplify shader reference - half2 POM(Texture2D heightMap, SamplerState heightSampler, half2 uvs, half2 dx, half2 dy, half3 normalWorld, half3 viewWorld, half3 viewDirTan, int minSamples, int maxSamples, half parallax, half refPlane, half2 tilling, half2 curv, int index, inout half finalHeight) - { - half3 result = 0; - int stepIndex = 0; - int numSteps = (int)lerp((half)maxSamples, (half)minSamples, saturate(dot(normalWorld, viewWorld))); - half layerHeight = 1.0 / numSteps; - half2 plane = parallax * (viewDirTan.xy / viewDirTan.z); - uvs.xy += refPlane * plane; - half2 deltaTex = -plane * layerHeight; - half2 prevTexOffset = 0; - half prevRayZ = 1.0f; - half prevHeight = 0.0f; - half2 currTexOffset = deltaTex; - half currRayZ = 1.0f - layerHeight; - half currHeight = 0.0f; - half intersection = 0; - half2 finalTexOffset = 0; - while (stepIndex < numSteps + 1) - { - currHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + currTexOffset, dx, dy).r; - if (currHeight > currRayZ) - { - stepIndex = numSteps + 1; - } - else - { - stepIndex++; - prevTexOffset = currTexOffset; - prevRayZ = currRayZ; - prevHeight = currHeight; - currTexOffset += deltaTex; - currRayZ -= layerHeight; - } - } - int sectionSteps = 2; - int sectionIndex = 0; - half newZ = 0; - half newHeight = 0; - while (sectionIndex < sectionSteps) - { - intersection = (prevHeight - prevRayZ) / (prevHeight - currHeight + currRayZ - prevRayZ); - finalTexOffset = prevTexOffset +intersection * deltaTex; - newZ = prevRayZ - intersection * layerHeight; - newHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + finalTexOffset, dx, dy).r; - if (newHeight > newZ) - { - currTexOffset = finalTexOffset; - currHeight = newHeight; - currRayZ = newZ; - deltaTex = intersection * deltaTex; - layerHeight = intersection * layerHeight; - } - else - { - prevTexOffset = finalTexOffset; - prevHeight = newHeight; - prevRayZ = newZ; - deltaTex = (1 - intersection) * deltaTex; - layerHeight = (1 - intersection) * layerHeight; - } - sectionIndex++; - } - finalHeight = newHeight; - return uvs.xy + finalTexOffset; - } - - half remap(half s, half a1, half a2, half b1, half b2) - { - return b1 + (s - a1) * (b2 - b1) / (a2 - a1); - } - - half3 ApplyLut2D(Texture2D LUT2D, SamplerState lutSampler, half3 uvw) - { - half3 scaleOffset = half3(1.0 / 1024.0, 1.0 / 32.0, 31.0); - // Strip format where `height = sqrt(width)` - uvw.z *= scaleOffset.z; - half shift = floor(uvw.z); - uvw.xy = uvw.xy * scaleOffset.z * scaleOffset.xy + scaleOffset.xy * 0.5; - uvw.x += shift * scaleOffset.y; - uvw.xyz = lerp( - SAMPLE_TEXTURE2D(LUT2D, lutSampler, uvw.xy).rgb, - SAMPLE_TEXTURE2D(LUT2D, lutSampler, uvw.xy + half2(scaleOffset.y, 0.0)).rgb, - uvw.z - shift - ); - return uvw; - } - - half3 AdjustContrast(half3 color, half contrast) - { - color = saturate(lerp(half3(0.5, 0.5, 0.5), color, contrast)); - return color; - } - - half3 AdjustSaturation(half3 color, half saturation) - { - half3 intensity = dot(color.rgb, half3(0.299, 0.587, 0.114)); - color = lerp(intensity, color.rgb, saturation); - return color; - } - - half3 AdjustBrightness(half3 color, half brightness) - { - color += brightness; - return color; - } - - struct ParamsLogC - { - half cut; - half a, b, c, d, e, f; - }; - - static const ParamsLogC LogC = { - 0.011361, // cut - 5.555556, // a - 0.047996, // b - 0.244161, // c - 0.386036, // d - 5.301883, // e - 0.092819 // f - - }; - - half LinearToLogC_Precise(half x) - { - half o; - if (x > LogC.cut) - o = LogC.c * log10(LogC.a * x + LogC.b) + LogC.d; - else - o = LogC.e * x + LogC.f; - return o; - } - - half PositivePow(half base, half power) - { - return pow(max(abs(base), half(FLT_EPSILON)), power); - } - - half3 LinearToLogC(half3 x) - { - return LogC.c * log10(LogC.a * x + LogC.b) + LogC.d; - } - - half3 LinerToSRGB(half3 c) - { - return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878); - } - - half3 SRGBToLiner(half3 c) - { - return max(1.055 * PositivePow(c, 0.416666667) - 0.055, 0.0); - } - - half3 LogCToLinear(half3 c) - { - return (pow(10.0, (c - LogC.d) / LogC.c) - LogC.b) / LogC.a; - } - - // Specular stuff taken from https://github.com/z3y/shaders/ - float pow5(float x) - { - float x2 = x * x; - return x2 * x2 * x; - } - - float sq(float x) - { - return x * x; - } - - struct Gradient - { - int type; - int colorsLength; - int alphasLength; - half4 colors[8]; - half2 alphas[8]; - }; - - Gradient NewGradient(int type, int colorsLength, int alphasLength, - half4 colors0, half4 colors1, half4 colors2, half4 colors3, half4 colors4, half4 colors5, half4 colors6, half4 colors7, - half2 alphas0, half2 alphas1, half2 alphas2, half2 alphas3, half2 alphas4, half2 alphas5, half2 alphas6, half2 alphas7) - { - Gradient g; - g.type = type; - g.colorsLength = colorsLength; - g.alphasLength = alphasLength; - g.colors[ 0 ] = colors0; - g.colors[ 1 ] = colors1; - g.colors[ 2 ] = colors2; - g.colors[ 3 ] = colors3; - g.colors[ 4 ] = colors4; - g.colors[ 5 ] = colors5; - g.colors[ 6 ] = colors6; - g.colors[ 7 ] = colors7; - g.alphas[ 0 ] = alphas0; - g.alphas[ 1 ] = alphas1; - g.alphas[ 2 ] = alphas2; - g.alphas[ 3 ] = alphas3; - g.alphas[ 4 ] = alphas4; - g.alphas[ 5 ] = alphas5; - g.alphas[ 6 ] = alphas6; - g.alphas[ 7 ] = alphas7; - return g; - } - - half4 SampleGradient(Gradient gradient, half time) - { - half3 color = gradient.colors[0].rgb; - UNITY_UNROLL - for (int c = 1; c < 8; c++) - { - half colorPos = saturate((time - gradient.colors[c - 1].w) / (0.00001 + (gradient.colors[c].w - gradient.colors[c - 1].w)) * step(c, (half)gradient.colorsLength - 1)); - color = lerp(color, gradient.colors[c].rgb, lerp(colorPos, step(0.01, colorPos), gradient.type)); - } - #ifndef UNITY_COLORSPACE_GAMMA - color = half3(GammaToLinearSpaceExact(color.r), GammaToLinearSpaceExact(color.g), GammaToLinearSpaceExact(color.b)); - #endif - half alpha = gradient.alphas[0].x; - UNITY_UNROLL - for (int a = 1; a < 8; a++) - { - half alphaPos = saturate((time - gradient.alphas[a - 1].y) / (0.00001 + (gradient.alphas[a].y - gradient.alphas[a - 1].y)) * step(a, (half)gradient.alphasLength - 1)); - alpha = lerp(alpha, gradient.alphas[a].x, lerp(alphaPos, step(0.01, alphaPos), gradient.type)); - } - return half4(color, alpha); - } - - float3 RotateAroundAxis(float3 center, float3 original, float3 u, float angle) - { - original -= center; - float C = cos(angle); - float S = sin(angle); - float t = 1 - C; - float m00 = t * u.x * u.x + C; - float m01 = t * u.x * u.y - S * u.z; - float m02 = t * u.x * u.z + S * u.y; - float m10 = t * u.x * u.y + S * u.z; - float m11 = t * u.y * u.y + C; - float m12 = t * u.y * u.z - S * u.x; - float m20 = t * u.x * u.z - S * u.y; - float m21 = t * u.y * u.z + S * u.x; - float m22 = t * u.z * u.z + C; - float3x3 finalMatrix = float3x3(m00, m01, m02, m10, m11, m12, m20, m21, m22); - return mul(finalMatrix, original) + center; - } - - half3 UnpackNormalAG(half4 packedNormal, half scale = 1.0) - { - half3 normal; - normal.xy = packedNormal.ag * 2.0 - 1.0; - normal.z = max(1.0e-16, sqrt(1.0 - saturate(dot(normal.xy, normal.xy)))); - - normal.xy *= scale; - return normal; - } - - half D_GGX(half NoH, half roughness) - { - half a = NoH * roughness; - half k = roughness / (1.0 - NoH * NoH + a * a); - return k * k * (1.0 / UNITY_PI); - } - - half D_GGX_Anisotropic(half NoH, const half3 h, const half3 t, const half3 b, half at, half ab) - { - half ToH = dot(t, h); - half BoH = dot(b, h); - half a2 = at * ab; - half3 v = half3(ab * ToH, at * BoH, a2 * NoH); - half v2 = dot(v, v); - half w2 = a2 / v2; - return a2 * w2 * w2 * (1.0 / UNITY_PI); - } - - half V_SmithGGXCorrelated(half NoV, half NoL, half roughness) - { - half a2 = roughness * roughness; - half GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); - half GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); - return 0.5 / (GGXV + GGXL); - } - - half3 F_Schlick(half u, half3 f0) - { - return f0 + (1.0 - f0) * pow(1.0 - u, 5.0); - } - - half3 F_Schlick(half3 f0, half f90, half VoH) - { - // Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering" - return f0 + (f90 - f0) * pow(1.0 - VoH, 5); - } - - half3 fresnel(half3 f0, half LoH) - { - half f90 = saturate(dot(f0, half(50.0 / 3).xxx)); - return F_Schlick(f0, f90, LoH); - } - - half Fd_Burley(half perceptualRoughness, half NoV, half NoL, half LoH) - { - // Burley 2012, "Physically-Based Shading at Disney" - half f90 = 0.5 + 2.0 * perceptualRoughness * LoH * LoH; - half lightScatter = F_Schlick(1.0, f90, NoL); - half viewScatter = F_Schlick(1.0, f90, NoV); - return lightScatter * viewScatter; - } - - half3 getBoxProjection(half3 direction, half3 position, half4 cubemapPosition, half3 boxMin, half3 boxMax) - { - #if defined(UNITY_SPECCUBE_BOX_PROJECTION) && !defined(UNITY_PBS_USE_BRDF2) || defined(FORCE_BOX_PROJECTION) - if (cubemapPosition.w > 0) - { - half3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction; - half scalar = min(min(factors.x, factors.y), factors.z); - direction = direction * scalar + (position - cubemapPosition.xyz); - } - #endif - - return direction; - } - - half3 getEnvReflection(half3 worldSpaceViewDir, half3 worldSpacePosition, half3 normal, half smoothness, int mip) - { - half3 env = 0; - half3 reflDir = reflect(worldSpaceViewDir, normal); - half perceptualRoughness = 1 - smoothness; - half rough = perceptualRoughness * perceptualRoughness; - reflDir = lerp(reflDir, normal, rough * rough); - - half3 reflectionUV1 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, mip); - half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR); - - half3 indirectSpecular; - half interpolator = unity_SpecCube0_BoxMin.w; - - UNITY_BRANCH - if (interpolator < 0.99999) - { - half3 reflectionUV2 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, mip); - half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR); - indirectSpecular = lerp(probe1sample, probe0sample, interpolator); - } - else - { - indirectSpecular = probe0sample; - } - - env = indirectSpecular; - return env; - } - - half3 EnvBRDFMultiscatter(half2 dfg, half3 f0) - { - return lerp(dfg.xxx, dfg.yyy, f0); - } - - half3 EnvBRDFApprox(half perceptualRoughness, half NoV, half3 f0) - { - half g = 1 - perceptualRoughness; - //https://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - half4 t = half4(1 / 0.96, 0.475, (0.0275 - 0.25 * 0.04) / 0.96, 0.25); - t *= half4(g, g, g, g); - t += half4(0, 0, (0.015 - 0.75 * 0.04) / 0.96, 0.75); - half a0 = t.x * min(t.y, exp2(-9.28 * NoV)) + t.z; - half a1 = t.w; - return saturate(lerp(a0, a1, f0)); - } - - half GSAA_Filament(half3 worldNormal, half perceptualRoughness, half inputVariance, half threshold) - { - // Kaplanyan 2016, "Stable specular highlights" - // Tokuyoshi 2017, "Error Reduction and Simplification for Shading Anti-Aliasing" - // Tokuyoshi and Kaplanyan 2019, "Improved Geometric Specular Antialiasing" - - // This implementation is meant for deferred rendering in the original paper but - // we use it in forward rendering as well (as discussed in Tokuyoshi and Kaplanyan - // 2019). The main reason is that the forward version requires an expensive transform - // of the half vector by the tangent frame for every light. This is therefore an - // approximation but it works well enough for our needs and provides an improvement - // over our original implementation based on Vlachos 2015, "Advanced VR Rendering". - - half3 du = ddx(worldNormal); - half3 dv = ddy(worldNormal); - - half variance = inputVariance * (dot(du, du) + dot(dv, dv)); - - half roughness = perceptualRoughness * perceptualRoughness; - half kernelRoughness = min(2.0 * variance, threshold); - half squareRoughness = saturate(roughness * roughness + kernelRoughness); - - return sqrt(sqrt(squareRoughness)); - } - - // w0, w1, w2, and w3 are the four cubic B-spline basis functions - half w0(half a) - { - // return (1.0f/6.0f)*(-a*a*a + 3.0f*a*a - 3.0f*a + 1.0f); - return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f); // optimized - - } - - half w1(half a) - { - // return (1.0f/6.0f)*(3.0f*a*a*a - 6.0f*a*a + 4.0f); - return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f); - } - - half w2(half a) - { - // return (1.0f/6.0f)*(-3.0f*a*a*a + 3.0f*a*a + 3.0f*a + 1.0f); - return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f); - } - - half w3(half a) - { - return (1.0f / 6.0f) * (a * a * a); - } - - // g0 and g1 are the two amplitude functions - half g0(half a) - { - return w0(a) + w1(a); - } - - half g1(half a) - { - return w2(a) + w3(a); - } - - // h0 and h1 are the two offset functions - half h0(half a) - { - // note +0.5 offset to compensate for CUDA linear filtering convention - return -1.0f + w1(a) / (w0(a) + w1(a)) + 0.5f; - } - - half h1(half a) - { - return 1.0f + w3(a) / (w2(a) + w3(a)) + 0.5f; - } - - //https://ndotl.wordpress.com/2018/08/29/baking-artifact-free-lightmaps - half3 tex2DFastBicubicLightmap(half2 uv, inout half4 bakedColorTex) - { - #if !defined(PLAT_QUEST) && defined(BICUBIC_LIGHTMAP) - half width; - half height; - unity_Lightmap.GetDimensions(width, height); - half x = uv.x * width; - half y = uv.y * height; - - x -= 0.5f; - y -= 0.5f; - half px = floor(x); - half py = floor(y); - half fx = x - px; - half fy = y - py; - - // note: we could store these functions in a lookup table texture, but maths is cheap - half g0x = g0(fx); - half g1x = g1(fx); - half h0x = h0(fx); - half h1x = h1(fx); - half h0y = h0(fy); - half h1y = h1(fy); - - half4 r = g0(fy) * (g0x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h0x, py + h0y) * 1.0f / width)) + - g1x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h1x, py + h0y) * 1.0f / width))) + - g1(fy) * (g0x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h0x, py + h1y) * 1.0f / width)) + - g1x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h1x, py + h1y) * 1.0f / width))); - bakedColorTex = r; - return DecodeLightmap(r); - #else - bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, uv); - return DecodeLightmap(bakedColorTex); - #endif - } - - half3 GetSpecularHighlights(half3 worldNormal, half3 lightColor, half3 lightDirection, half3 f0, half3 viewDir, half clampedRoughness, half NoV, half3 energyCompensation) - { - half3 halfVector = Unity_SafeNormalize(lightDirection + viewDir); - - half NoH = saturate(dot(worldNormal, halfVector)); - half NoL = saturate(dot(worldNormal, lightDirection)); - half LoH = saturate(dot(lightDirection, halfVector)); - - half3 F = F_Schlick(LoH, f0); - half D = D_GGX(NoH, clampedRoughness); - half V = V_SmithGGXCorrelated(NoV, NoL, clampedRoughness); - - #ifndef UNITY_PBS_USE_BRDF2 - F *= energyCompensation; - #endif - - return max(0, (D * V) * F) * lightColor * NoL * UNITY_PI; - } - - #ifdef DYNAMICLIGHTMAP_ON - half3 getRealtimeLightmap(half2 uv, half3 worldNormal) - { - half2 realtimeUV = uv; - half4 bakedCol = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, realtimeUV); - half3 realtimeLightmap = DecodeRealtimeLightmap(bakedCol); - - #ifdef DIRLIGHTMAP_COMBINED - half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, realtimeUV); - realtimeLightmap += DecodeDirectionalLightmap(realtimeLightmap, realtimeDirTex, worldNormal); - #endif - - return realtimeLightmap; - } - #endif - - half computeSpecularAO(half NoV, half ao, half roughness) - { - return clamp(pow(NoV + ao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ao, 0.0, 1.0); - } - - half shEvaluateDiffuseL1Geomerics_local(half L0, half3 L1, half3 n) - { - // average energy - half R0 = L0; - - // avg direction of incoming light - half3 R1 = 0.5f * L1; - - // directional brightness - half lenR1 = length(R1); - - // linear angle between normal and direction 0-1 - //half q = 0.5f * (1.0f + dot(R1 / lenR1, n)); - //half q = dot(R1 / lenR1, n) * 0.5 + 0.5; - half q = dot(normalize(R1), n) * 0.5 + 0.5; - q = saturate(q); // Thanks to ScruffyRuffles for the bug identity. - - // power for q - // lerps from 1 (linear) to 3 (cubic) based on directionality - half p = 1.0f + 2.0f * lenR1 / R0; - - // dynamic range constant - // should vary between 4 (highly directional) and 0 (ambient) - half a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0); - - return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p)); - } - - // https://assetstore.unity.com/packages/tools/level-design/bakery-gpu-lightmapper-122218 - - #if defined(BAKERY_ENABLED) - - //float2 bakeryLightmapSize; - #define BAKERYMODE_DEFAULT 0 - #define BAKERYMODE_VERTEXLM 1.0f - #define BAKERYMODE_RNM 2.0f - #define BAKERYMODE_SH 3.0f - - #define rnmBasis0 float3(0.816496580927726f, 0, 0.5773502691896258f) - #define rnmBasis1 float3(-0.4082482904638631f, 0.7071067811865475f, 0.5773502691896258f) - #define rnmBasis2 float3(-0.4082482904638631f, -0.7071067811865475f, 0.5773502691896258f) - - #if defined(BAKERY_DOMINANT) - #undef BAKERY_RNM - #undef BAKERY_SH - #undef BAKERY_MONOSH - #endif - - #ifdef BICUBIC_LIGHTMAP - #define BAKERY_BICUBIC - #endif - - //#define BAKERY_SSBUMP - - // can't fit vertexLM SH to sm3_0 interpolators - #ifndef SHADER_API_D3D11 - #undef BAKERY_VERTEXLMSH - #endif - - // can't do stuff on sm2_0 due to standard shader alrady taking up all instructions - #if SHADER_TARGET < 30 - #undef BAKERY_BICUBIC - #undef BAKERY_LMSPEC - - #undef BAKERY_RNM - #undef BAKERY_SH - #undef BAKERY_MONOSH - #undef BAKERY_VERTEXLM - #endif - - #if !defined(BAKERY_SH) && !defined(BAKERY_RNM) - #undef BAKERY_BICUBIC - #endif - - #ifndef UNITY_SHOULD_SAMPLE_SH - #undef BAKERY_PROBESHNONLINEAR - #endif - - #if defined(BAKERY_RNM) && defined(BAKERY_LMSPEC) - #define BAKERY_RNMSPEC - #endif - - #ifndef BAKERY_VERTEXLM - #undef BAKERY_VERTEXLMDIR - #undef BAKERY_VERTEXLMSH - #undef BAKERY_VERTEXLMMASK - #endif - - #define lumaConv float3(0.2125f, 0.7154f, 0.0721f) - - #if defined(BAKERY_SH) || defined(BAKERY_MONOSH) || defined(BAKERY_VERTEXLMSH) || defined(BAKERY_PROBESHNONLINEAR) || defined(BAKERY_VOLUME) - float shEvaluateDiffuseL1Geomerics(float L0, float3 L1, float3 n) - { - // average energy - float R0 = L0; - - // avg direction of incoming light - float3 R1 = 0.5f * L1; - - // directional brightness - float lenR1 = length(R1); - - // linear angle between normal and direction 0-1 - //float q = 0.5f * (1.0f + dot(R1 / lenR1, n)); - //float q = dot(R1 / lenR1, n) * 0.5 + 0.5; - float q = dot(normalize(R1), n) * 0.5 + 0.5; - - // power for q - // lerps from 1 (linear) to 3 (cubic) based on directionality - float p = 1.0f + 2.0f * lenR1 / R0; - - // dynamic range constant - // should vary between 4 (highly directional) and 0 (ambient) - float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0); - - return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p)); - } - #endif - - #ifdef BAKERY_VERTEXLM - float4 unpack4NFloats(float src) { - //return fmod(float4(src / 262144.0, src / 4096.0, src / 64.0, src), 64.0)/64.0; - return frac(float4(src / (262144.0*64), src / (4096.0*64), src / (64.0*64), src)); - } - float3 unpack3NFloats(float src) { - float r = frac(src); - float g = frac(src * 256.0); - float b = frac(src * 65536.0); - return float3(r, g, b); - } - #if defined(BAKERY_VERTEXLMDIR) - - #ifdef BAKERY_MONOSH - void BakeryVertexLMMonoSH(inout float3 diffuseColor, inout float3 specularColor, float3 nL1, float3 normalWorld, float3 viewDir, float smoothness) - { - nL1 = nL1; - float3 L0 = diffuseColor; - float3 L1x = nL1.x * L0 * 2; - float3 L1y = nL1.y * L0 * 2; - float3 L1z = nL1.z * L0 * 2; - - float3 sh; - #if BAKERY_SHNONLINEAR - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - float lumaL0 = dot(L0, 1); - float lumaL1x = dot(L1x, 1); - float lumaL1y = dot(L1y, 1); - float lumaL1z = dot(L1z, 1); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = nL1; - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - - void BakeryVertexLMDirection(inout float3 diffuseColor, inout float3 specularColor, float3 lightDirection, float3 vertexNormalWorld, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 dominantDir = Unity_SafeNormalize(lightDirection); - half halfLambert = dot(normalWorld, dominantDir) * 0.5 + 0.5; - half flatNormalHalfLambert = dot(vertexNormalWorld, dominantDir) * 0.5 + 0.5; - - #ifdef BAKERY_LMSPEC - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = spec * diffuseColor; - #endif - - diffuseColor *= halfLambert / max(1e-4h, flatNormalHalfLambert); - } - #elif defined(BAKERY_VERTEXLMSH) - void BakeryVertexLMSH(inout float3 diffuseColor, inout float3 specularColor, float3 shL1x, float3 shL1y, float3 shL1z, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 L0 = diffuseColor; - float3 nL1x = shL1x; - float3 nL1y = shL1y; - float3 nL1z = shL1z; - float3 L1x = nL1x * L0 * 2; - float3 L1y = nL1y * L0 * 2; - float3 L1z = nL1z * L0 * 2; - - float3 sh; - #ifdef BAKERY_SHNONLINEAR - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - float lumaL0 = dot(L0, 1); - float lumaL1x = dot(L1x, 1); - float lumaL1y = dot(L1y, 1); - float lumaL1z = dot(L1z, 1); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - #endif - - #ifdef BAKERY_BICUBIC - float BakeryBicubic_w0(float a) - { - return (1.0f/6.0f)*(a*(a*(-a + 3.0f) - 3.0f) + 1.0f); - } - - float BakeryBicubic_w1(float a) - { - return (1.0f/6.0f)*(a*a*(3.0f*a - 6.0f) + 4.0f); - } - - float BakeryBicubic_w2(float a) - { - return (1.0f/6.0f)*(a*(a*(-3.0f*a + 3.0f) + 3.0f) + 1.0f); - } - - float BakeryBicubic_w3(float a) - { - return (1.0f/6.0f)*(a*a*a); - } - - float BakeryBicubic_g0(float a) - { - return BakeryBicubic_w0(a) + BakeryBicubic_w1(a); - } - - float BakeryBicubic_g1(float a) - { - return BakeryBicubic_w2(a) + BakeryBicubic_w3(a); - } - - float BakeryBicubic_h0(float a) - { - return -1.0f + BakeryBicubic_w1(a) / (BakeryBicubic_w0(a) + BakeryBicubic_w1(a)) + 0.5f; - } - - float BakeryBicubic_h1(float a) - { - return 1.0f + BakeryBicubic_w3(a) / (BakeryBicubic_w2(a) + BakeryBicubic_w3(a)) + 0.5f; - } - #endif - - #if defined(BAKERY_RNM) || defined(BAKERY_SH) - sampler2D _RNM0, _RNM1, _RNM2; - float4 _RNM0_TexelSize; - #endif - - #ifdef BAKERY_VOLUME - Texture3D _Volume0, _Volume1, _Volume2, _VolumeMask; - SamplerState sampler_Volume0; - - #ifndef PROPERTIES_DEFINED - float3 _VolumeMin, _VolumeInvSize; - float3 _GlobalVolumeMin, _GlobalVolumeInvSize; - #endif - - #endif - - #ifdef BAKERY_BICUBIC - // Bicubic - float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) - { - float x = uv.x * texelSize.z; - float y = uv.y * texelSize.z; - - x -= 0.5f; - y -= 0.5f; - - float px = floor(x); - float py = floor(y); - - float fx = x - px; - float fy = y - py; - - float g0x = BakeryBicubic_g0(fx); - float g1x = BakeryBicubic_g1(fx); - float h0x = BakeryBicubic_h0(fx); - float h1x = BakeryBicubic_h1(fx); - float h0y = BakeryBicubic_h0(fy); - float h1y = BakeryBicubic_h1(fy); - - return BakeryBicubic_g0(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h0y) * texelSize.x)) + - g1x * tex2D(tex, (float2(px + h1x, py + h0y) * texelSize.x))) + - - BakeryBicubic_g1(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h1y) * texelSize.x)) + - g1x * tex2D(tex, (float2(px + h1x, py + h1y) * texelSize.x))); - } - float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) - { - float x = uv.x * texelSize.z; - float y = uv.y * texelSize.z; - - x -= 0.5f; - y -= 0.5f; - - float px = floor(x); - float py = floor(y); - - float fx = x - px; - float fy = y - py; - - float g0x = BakeryBicubic_g0(fx); - float g1x = BakeryBicubic_g1(fx); - float h0x = BakeryBicubic_h0(fx); - float h1x = BakeryBicubic_h1(fx); - float h0y = BakeryBicubic_h0(fy); - float h1y = BakeryBicubic_h1(fy); - - return BakeryBicubic_g0(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h0y) * texelSize.x)) + - g1x * tex.Sample(s, (float2(px + h1x, py + h0y) * texelSize.x))) + - - BakeryBicubic_g1(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h1y) * texelSize.x)) + - g1x * tex.Sample(s, (float2(px + h1x, py + h1y) * texelSize.x))); - } - #else - // Bilinear - float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) - { - return tex2D(tex, uv); - } - float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) - { - return tex.Sample(s, uv); - } - #endif - - #ifdef DIRLIGHTMAP_COMBINED - #ifdef BAKERY_LMSPEC - float BakeryDirectionalLightmapSpecular(float2 lmUV, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 dominantDir = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lmUV).xyz * 2 - 1; - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - return spec; - } - #endif - #endif - - #ifdef BAKERY_RNM - void BakeryRNM(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalMap, float perceptualRoughness, float3 viewDirT) - { - normalMap.g *= -1; - float3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize)); - float3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize)); - float3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize)); - - #ifdef BAKERY_SSBUMP - diffuseColor = normalMap.x * rnm0 - + normalMap.z * rnm1 - + normalMap.y * rnm2; - diffuseColor *= 2; - #else - diffuseColor = saturate(dot(rnmBasis0, normalMap)) * rnm0 - + saturate(dot(rnmBasis1, normalMap)) * rnm1 - + saturate(dot(rnmBasis2, normalMap)) * rnm2; - #endif - - #ifdef BAKERY_LMSPEC - float3 dominantDirT = rnmBasis0 * dot(rnm0, lumaConv) + - rnmBasis1 * dot(rnm1, lumaConv) + - rnmBasis2 * dot(rnm2, lumaConv); - - float3 dominantDirTN = normalize(dominantDirT); - float3 specColor = saturate(dot(rnmBasis0, dominantDirTN)) * rnm0 + - saturate(dot(rnmBasis1, dominantDirTN)) * rnm1 + - saturate(dot(rnmBasis2, dominantDirTN)) * rnm2; - - half3 halfDir = Unity_SafeNormalize(dominantDirTN - viewDirT); - half nh = saturate(dot(normalMap, halfDir)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = spec * specColor; - #endif - } - #endif - - #ifdef BAKERY_SH - void BakerySH(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalWorld, float3 viewDir, float perceptualRoughness) - { - #ifdef SHADER_API_D3D11 - float3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, samplerunity_Lightmap, lmUV, _RNM0_TexelSize)); - #else - float3 L0 = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, lmUV)); - #endif - float3 nL1x = BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 nL1y = BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 nL1z = BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 L1x = nL1x * L0 * 2; - float3 L1y = nL1y * L0 * 2; - float3 L1z = nL1z * L0 * 2; - - float3 sh; - #ifdef BAKERY_SHNONLINEAR - float lumaL0 = dot(L0, float(1)); - float lumaL1x = dot(L1x, float(1)); - float lumaL1y = dot(L1y, float(1)); - float lumaL1z = dot(L1z, float(1)); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - - sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - - #endif - //BAKERY_ENABLED - - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - - half _Smoothness; - half _Metallic; - half _OcclusionStrength; - half _BumpScale; - half _HeightScale; - half _HeightRefPlane; - half _HeightStepsMin; - half _HeightStepsMax; - half _DAlbedoScale; - half _DNormalScale; - half _DSmoothScale; - half _VertexHeightAmount; - half _VertexHeightOffset; - half _TessFactor; - half _TessMinDist; - half _TessMaxDist; - half _TessEdgeLength; - half _TessMaxDisplacement; - half _SpecOcclusion; - half _SpecularRoughnessMod; - half2 GLOBAL_uv; - half4 _Color; - half4 _MainTex_ST; - half4 _MetallicRemap; - half4 _SmoothnessRemap; - half4 _MaskMap_TexelSize; - half4 _EmissionColor; - half4 GLOBAL_maskMap; - half4 _DDetailsMap_ST; - float _GSAAVariance; - float _GSAAThreshold; - int _AlbedoChannel; - int _MappingSpace; - int _PlanarAxisX; - int _PlanarAxisY; - int _MetalChannel; - int _AOChannel; - int _DetailMaskChannel; - int _SmoothChannel; - int _RoughnessMode; - int _DetailAsTintMask; - int _FlipBumpY; - int _EmissionChannel; - TEXTURE2D(_MainTex); - SAMPLER(sampler_MainTex); - TEXTURE2D(_MaskMap); - SAMPLER(sampler_MaskMap); - TEXTURE2D(_BumpMap); - SAMPLER(sampler_BumpMap); - TEXTURE2D(_EmissionMap); - SAMPLER(sampler_EmissionMap); - TEXTURE2D(_Height); - SAMPLER(sampler_Height); - int _DIgnoreMask; - int _DMappingSpace; - int _DUVChannel; - int _DPlanarAxisX; - int _DPlanarAxisY; - int _DNormalFlipY; - TEXTURE2D(_DDetailsMap); - SAMPLER(sampler_DDetailsMap); - TEXTURE2D(_DDetailsNormal); - SAMPLER(sampler_DDetailsNormal); - TEXTURE2D(_VertexHeight); - SAMPLER(sampler_VertexHeight); - TEXTURE2D(_DFG); - SAMPLER(sampler_DFG); - - void VHVertex() { - half2 uv = vD.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - half height = (SAMPLE_TEXTURE2D_LOD(_VertexHeight, sampler_VertexHeight, uv, 0).r * 2 - 1); - half3 mainOffset = vD.vertex.xyz + vD.normal * (height + _VertexHeightOffset) * _VertexHeightAmount; - vD.vertex.xyz = mainOffset; - } - - void ParallaxFragment() - { - GLOBAL_uv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - #if PARALLAX && !defined(PLAT_QUEST) - half customHeight = 0; - GLOBAL_uv = POM(_Height, sampler_Height, GLOBAL_uv, ddx(GLOBAL_uv), ddy(GLOBAL_uv), d.worldNormal, d.worldSpaceViewDir, d.tangentSpaceViewDir, _HeightStepsMin, _HeightStepsMax, _HeightScale, _HeightRefPlane, half2(1, 1), half2(0, 0), 0, customHeight); - #endif - } - - void BaseFragmentFunction() - { - #if !defined(_SET_GLOBAL_UVS) - GLOBAL_uv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - #endif - if (_MappingSpace > 0) - { - GLOBAL_uv = (_MappingSpace - 1) ? half2(d.worldSpacePosition[_PlanarAxisX], d.worldSpacePosition[_PlanarAxisY]) : half2(d.localSpacePosition[_PlanarAxisX], d.localSpacePosition[_PlanarAxisY]); - GLOBAL_uv = GLOBAL_uv * _MainTex_ST.xy + _MainTex_ST.zw; - } - half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, GLOBAL_uv); - if (_AlbedoChannel > 0) - { - albedo.rgb = albedo[_AlbedoChannel].xxx; - } - half4 masks = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, GLOBAL_uv); - half4 normalTex = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, GLOBAL_uv); - if (_FlipBumpY) - { - normalTex.y = 1 - normalTex.y; - } - half3 normal = UnpackScaleNormal(normalTex, _BumpScale); - half3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, GLOBAL_uv).rgb; - if (_EmissionChannel > 0) - { - emission.rgb = emission[_EmissionChannel].xxx; - } - int hasMasks = _MaskMap_TexelSize.z > 8; - half metal = masks[_MetalChannel]; - half smooth = masks[_SmoothChannel]; - if (_RoughnessMode) - { - smooth = 1 - smooth; - } - half detailMask = masks[_DetailMaskChannel]; - half occlusion = masks[_AOChannel]; - metal = remap(metal, 0, 1, _MetallicRemap.x, _MetallicRemap.y); - smooth = remap(smooth, 0, 1, _SmoothnessRemap.x, _SmoothnessRemap.y); - GLOBAL_maskMap = half4(metal, occlusion, detailMask, smooth); - o.Metallic = lerp(_Metallic, metal, hasMasks); - o.Smoothness = lerp(_Smoothness, smooth, hasMasks); - o.Occlusion = lerp(1, occlusion, _OcclusionStrength); - o.Normal = normal; - if (!_DetailAsTintMask) - { - o.Albedo = albedo.rgb * _Color.rgb; - } - else - { - o.Albedo = lerp(albedo, albedo.rgb * _Color.rgb, detailMask); - } - o.Alpha = albedo.a * _Color.a; - #if defined(_EMISSION) - o.Emission = emission * _EmissionColor; - #endif - } - - void DetailsFragment() - { - #if defined(DETAILS_OVERLAY) - half masks = 0; - #if defined(_MASKMAP_SAMPLED) - masks = GLOBAL_maskMap.b; - #else - masks = 1; - #endif - half mask = lerp(masks, 1, _DIgnoreMask); - half2 uv = d.uv0.xy; - switch(_DUVChannel) - { - case 1: uv = d.uv1.xy; break; - case 2: uv = d.uv2.xy; break; - case 3: uv = d.uv3.xy; break; - default: uv = d.uv0.xy; break; - } - uv = uv * _DDetailsMap_ST.xy + _DDetailsMap_ST.zw; - if (_DMappingSpace > 0) - { - uv = (_DMappingSpace - 1) ? half2(d.worldSpacePosition[_DPlanarAxisX], d.worldSpacePosition[_DPlanarAxisY]) : half2(d.localSpacePosition[_DPlanarAxisX], d.localSpacePosition[_DPlanarAxisY]); - uv = uv * _DDetailsMap_ST.xy + _DDetailsMap_ST.zw; - } - - half4 detailsMap = SAMPLE_TEXTURE2D(_DDetailsMap, sampler_DDetailsMap, uv); - - #if defined(DETAILS_MODE_PACKED) - half detailAlbedo = detailsMap.r * 2.0 - 1.0; - half detailSmooth = detailsMap.b * 2.0 - 1.0; - half3 detailNormal = 0; - if (_DNormalFlipY) - { - detailsMap.g = 1 - detailsMap.g; - } - detailNormal = UnpackNormalAG(detailsMap, _DNormalScale); - half detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); - #elif defined(DETAILS_MODE_SEPARATED) - half3 detailAlbedo = detailsMap.rgb * 2.0 - 1.0; - half detailSmooth = detailsMap.a * 2.0 - 1.0; - - half4 packedNormal = SAMPLE_TEXTURE2D(_DDetailsNormal, sampler_DDetailsNormal, uv); - if (_DNormalFlipY) - { - packedNormal.g = 1 - packedNormal.g; - } - half3 detailNormal = UnpackScaleNormal(packedNormal, _DNormalScale); - - half3 detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); - #endif - - half3 albedoOverlay = lerp(sqrt(o.Albedo), (detailAlbedo < 0.0) ? 0.0.xxx : 1.0.xxx, detailAlbedoSpeed * detailAlbedoSpeed); - albedoOverlay *= albedoOverlay; - o.Albedo = lerp(o.Albedo, saturate(albedoOverlay), mask); - - half detailSmoothSpeed = saturate(abs(detailSmooth) * _DSmoothScale); - half smoothOverlay = lerp(o.Smoothness, (detailSmooth < 0.0) ? 0.0 : 1.0, detailSmoothSpeed * detailSmoothSpeed); - o.Smoothness = lerp(o.Smoothness, saturate(smoothOverlay), mask); - - o.Normal = lerp(o.Normal, BlendNormals(o.Normal, detailNormal), mask); - #endif - } - - void ORLLighting() - { - #if !defined(UNITY_PASS_SHADOWCASTER) - half reflectance = 0.5; - half3 f0 = 0.16 * reflectance * reflectance * (1 - o.Metallic) + o.Albedo * o.Metallic; - half3 pixelLight = 0; - half3 indirectDiffuse = 1; - half3 indirectSpecular = 0; - half3 directSpecular = 0; - half occlusion = o.Occlusion; - half perceptualRoughness = 1 - o.Smoothness; - half3 tangentNormal = o.Normal; - o.Normal = normalize(mul(o.Normal, d.TBNMatrix)); - - #ifndef USING_DIRECTIONAL_LIGHT - fixed3 lightDir = normalize(UnityWorldSpaceLightDir(d.worldSpacePosition)); - #else - fixed3 lightDir = _WorldSpaceLightPos0.xyz; - #endif - - #if defined(GSAA) - perceptualRoughness = GSAA_Filament(o.Normal, perceptualRoughness, _GSAAVariance, _GSAAThreshold); - #endif - - UNITY_LIGHT_ATTENUATION(lightAttenuation, FragData, d.worldSpacePosition); - half3 lightColor = lightAttenuation * _LightColor0.rgb; - - half3 lightHalfVector = Unity_SafeNormalize(lightDir + d.worldSpaceViewDir); - half lightNoL = saturate(dot(o.Normal, lightDir)); - half lightLoH = saturate(dot(lightDir, lightHalfVector)); - - half NoV = abs(dot(o.Normal, d.worldSpaceViewDir)) + 1e-5; - pixelLight = lightNoL * lightColor * Fd_Burley(perceptualRoughness, NoV, lightNoL, lightLoH); - - // READ THE LIGHTMAP - #if defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) - half3 lightMap = 0; - half4 bakedColorTex = 0; - half2 lightmapUV = FragData.lightmapUv.xy; - - // UNITY LIGHTMAPPING - #if !defined(BAKERYLM_ENABLED) || !defined(BAKERY_ENABLED) - lightMap = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); - #endif - - // BAKERY RNM MODE (why do we even support it??) - #if defined(BAKERY_RNM) && defined(BAKERY_ENABLED) - half3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, lightmapUV, _RNM0_TexelSize)); - half3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, lightmapUV, _RNM0_TexelSize)); - half3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, lightmapUV, _RNM0_TexelSize)); - - lightMap = saturate(dot(rnmBasis0, tangentNormal)) * rnm0 + - saturate(dot(rnmBasis1, tangentNormal)) * rnm1 + - saturate(dot(rnmBasis2, tangentNormal)) * rnm2; - #endif - - // BAKERY SH MODE (these are also used for the specular) - #if defined(BAKERY_SH) && defined(BAKERY_ENABLED) - half3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, samplerunity_Lightmap, lightmapUV, _RNM0_TexelSize)); - - half3 nL1x = BakeryTex2D(_RNM0, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 nL1y = BakeryTex2D(_RNM1, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 nL1z = BakeryTex2D(_RNM2, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 L1x = nL1x * L0 * 2.0; - half3 L1y = nL1y * L0 * 2.0; - half3 L1z = nL1z * L0 * 2.0; - - // Non-Linear mode - #if defined(BAKERY_SHNONLINEAR) - half lumaL0 = dot(L0, half(1)); - half lumaL1x = dot(L1x, half(1)); - half lumaL1y = dot(L1y, half(1)); - half lumaL1z = dot(L1z, half(1)); - half lumaSH = shEvaluateDiffuseL1Geomerics_local(lumaL0, half3(lumaL1x, lumaL1y, lumaL1z), o.Normal); - - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - half regularLumaSH = dot(lightMap, 1.0); - lightMap *= lerp(1.0, lumaSH / regularLumaSH, saturate(regularLumaSH * 16.0)); - #else - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - #endif - - #endif - - #if defined(DIRLIGHTMAP_COMBINED) - half4 lightMapDirection = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lightmapUV); - #if !defined(BAKERY_MONOSH) - lightMap = DecodeDirectionalLightmap(lightMap, lightMapDirection, o.Normal); - #endif - #endif - - #if defined(BAKERY_MONOSH) && defined(BAKERY_ENABLED) && defined(DIRLIGHTMAP_COMBINED) - half3 L0 = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); - half3 nL1 = lightMapDirection.xyz * 2.0 - 1.0; - half3 L1x = nL1.x * L0 * 2.0; - half3 L1y = nL1.y * L0 * 2.0; - half3 L1z = nL1.z * L0 * 2.0; - - #if defined(BAKERY_SHNONLINEAR) - half lumaL0 = dot(L0, 1); - half lumaL1x = dot(L1x, 1); - half lumaL1y = dot(L1y, 1); - half lumaL1z = dot(L1z, 1); - half lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, half3(lumaL1x, lumaL1y, lumaL1z), o.Normal); - - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - half regularLumaSH = dot(lightMap, 1); - lightMap *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - #else - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - #endif - - lightMap = max(lightMap, 0.0); - #endif - - #if defined(DYNAMICLIGHTMAP_ON) && !defined(UNITY_PBS_USE_BRDF2) - half3 realtimeLightMap = getRealtimeLightmap(FragData.lightmapUv.zw, o.Normal); - lightMap += realtimeLightMap; - #endif - - #if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) - pixelLight = 0; - lightMap = SubtractMainLightWithRealtimeAttenuationFrowmLightmap(lightMap, lightAttenuation, bakedColorTex, o.Normal); - #endif - indirectDiffuse = lightMap; - #else - #if UNITY_LIGHT_PROBE_PROXY_VOLUME - UNITY_BRANCH - if (unity_ProbeVolumeParams.x == 1) - { - indirectDiffuse = SHEvalLinearL0L1_SampleProbeVolume(half4(o.Normal, 1), FragData.worldPos); - } - else - { - #endif - indirectDiffuse = max(0, ShadeSH9(half4(o.Normal, 1))); - #if UNITY_LIGHT_PROBE_PROXY_VOLUME - } - #endif - #endif - - #if defined(LIGHTMAP_SHADOW_MIXING) && defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) && defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) - pixelLight *= UnityComputeForwardShadows(FragData.lightmapUv.xy, d.worldSpacePosition, d.screenPos); - #endif - - half3 dfguv = half3(NoV, perceptualRoughness, 0); - half2 dfg = SAMPLE_TEXTURE2D(_DFG, sampler_DFG, dfguv).xy; - half3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0); - - half rough = perceptualRoughness * perceptualRoughness; - half clampedRoughness = max(rough, 0.002); - - #if !defined(SPECULAR_HIGHLIGHTS_OFF) && defined(USING_LIGHT_MULTI_COMPILE) - half NoH = saturate(dot(o.Normal, lightHalfVector)); - half3 F = F_Schlick(lightLoH, f0); - half D = D_GGX(NoH, clampedRoughness); - half V = V_SmithGGXCorrelated(NoV, lightNoL, clampedRoughness); - - F *= energyCompensation; - - directSpecular = max(0, D * V * F) * pixelLight * UNITY_PI; - #endif - - // BAKED SPECULAR - #if defined(BAKED_SPECULAR) && !defined(BAKERYLM_ENABLED) && !defined(UNITY_PASS_FORWARDADD) - { - half3 bakedDominantDirection = 1; - half3 bakedSpecularColor = 0; - - // only do it if we have a directional lightmap - #if defined(DIRLIGHTMAP_COMBINED) && defined(LIGHTMAP_ON) - bakedDominantDirection = (lightMapDirection.xyz) * 2 - 1; - half directionality = max(0.001, length(bakedDominantDirection)); - bakedDominantDirection /= directionality; - bakedSpecularColor = indirectDiffuse; - #endif - - // if we do not have lightmap - derive the specular from probes - //#ifndef LIGHTMAP_ON - //bakedSpecularColor = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); - //bakedDominantDirection = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz; - // #endif - - bakedDominantDirection = normalize(bakedDominantDirection); - directSpecular += GetSpecularHighlights(o.Normal, bakedSpecularColor, bakedDominantDirection, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); - } - #endif - - half3 fresnel = F_Schlick(NoV, f0); - - // BAKERY DIRECT SPECULAR - #if defined(BAKERY_LMSPEC) && defined(BAKERY_ENABLED) && !defined(UNITY_PASS_FORWARDADD) - #if defined(BAKERY_RNM) - { - half3 viewDirTangent = -normalize(d.tangentSpaceViewDir); - half3 dominantDirTangent = rnmBasis0 * dot(rnm0, lumaConv) + - rnmBasis1 * dot(rnm1, lumaConv) + - rnmBasis2 * dot(rnm2, lumaConv); - - half3 dominantDirTangentNormalized = normalize(dominantDirTangent); - half3 specColor = saturate(dot(rnmBasis0, dominantDirTangentNormalized)) * rnm0 + - saturate(dot(rnmBasis1, dominantDirTangentNormalized)) * rnm1 + - saturate(dot(rnmBasis2, dominantDirTangentNormalized)) * rnm2; - half3 halfDir = Unity_SafeNormalize(dominantDirTangentNormalized - viewDirTangent); - half NoH = saturate(dot(tangentNormal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - directSpecular += spec * specColor * fresnel; - } - #endif - - #if defined(BAKERY_SH) - { - half3 dominantDir = half3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(L1z, lumaConv)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) + d.worldSpaceViewDir); - half NoH = saturate(dot(o.Normal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - dominantDir = normalize(dominantDir); - directSpecular += max(spec * sh, 0.0) * fresnel; - } - #endif - - #if defined(BAKERY_MONOSH) - { - half3 dominantDir = nL1; - half focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - d.worldSpaceViewDir); - half NoH = saturate(dot(o.Normal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - dominantDir = normalize(dominantDir); - directSpecular += max(spec * sh, 0.0) * fresnel; - } - #endif - #endif - - // REFLECTIONS - #if !defined(UNITY_PASS_FORWARDADD) - half3 reflDir = reflect(-d.worldSpaceViewDir, o.Normal); - reflDir = lerp(reflDir, o.Normal, rough * rough); - - Unity_GlossyEnvironmentData envData; - envData.roughness = perceptualRoughness; - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - - half3 probe0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData); - indirectSpecular = probe0; - - #if defined(UNITY_SPECCUBE_BLENDING) - UNITY_BRANCH - if (unity_SpecCube0_BoxMin.w < 0.99999) - { - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half3 probe1 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0), unity_SpecCube1_HDR, envData); - indirectSpecular = lerp(probe1, probe0, unity_SpecCube0_BoxMin.w); - } - #endif - - half horizon = min(1 + dot(reflDir, o.Normal), 1); - dfg.x *= saturate(pow(dot(indirectDiffuse, 1), _SpecOcclusion)); - indirectSpecular = indirectSpecular * horizon * horizon * energyCompensation * EnvBRDFMultiscatter(dfg, f0); - - #if defined(_MASKMAP_SAMPLED) - indirectSpecular *= computeSpecularAO(NoV, o.Occlusion, perceptualRoughness * perceptualRoughness); - #endif - #endif - - #if defined(_INTEGRATE_CUSTOMGI) && !defined(UNITY_PASS_FORWARDADD) - IntegrateCustomGI(d, o, indirectSpecular, indirectDiffuse); - #endif - - // FINAL COLOR - FinalColor = half4(o.Albedo.rgb * (1 - o.Metallic) * (indirectDiffuse * occlusion + (pixelLight)) + indirectSpecular + directSpecular, o.Alpha); - - FinalColor.rgb += o.Emission; - #endif - } - - // ForwardBase Vertex - TessVertex Vertex(VertexData v) - { - UNITY_SETUP_INSTANCE_ID(v); - TessVertex o = (TessVertex) 0; - UNITY_TRANSFER_INSTANCE_ID(v, o); - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - - o.vertex = v.vertex; - o.normal = v.normal; - o.tangent = v.tangent; - o.color = v.color; - o.uv0 = v.uv0; - o.uv1 = v.uv1; - o.uv2 = v.uv2; - o.uv3 = v.uv3; - - return o; - } - - // ForwardBase Hull - [maxtessfactor(MAX_TESSELLATION_FACTORS)] - [UNITY_domain("tri")] - [UNITY_outputcontrolpoints(3)] - [UNITY_outputtopology("triangle_cw")] - [UNITY_partitioning("integer")] - [UNITY_patchconstantfunc("TessFactorsFunction")] - TessVertex Hull(InputPatch patch, uint id : SV_OutputControlPointID) - { - return patch[id]; - } - - float4 GetTessFactors(InputPatch patch) - { - #if defined(TESS_MODE_DISTANCEBASED) - float4 tessFactors = UnityDistanceBasedTess( - patch[0].vertex, - patch[1].vertex, - patch[2].vertex, - _TessMinDist, - _TessMaxDist, - _TessFactor - ); - return tessFactors; - #elif defined(TESS_MODE_EDGELENGTH) - float4 tessFactors = UnityEdgeLengthBasedTessCull( - patch[0].vertex, - patch[1].vertex, - patch[2].vertex, - _TessEdgeLength, - _TessMaxDisplacement - ); - return tessFactors; - #endif - - return 1..xxxx; - } - - // ForwardBase TessFactor - TessellationFactors TessFactorsFunction(InputPatch patch) - { - TessellationFactors f; - float4 TessFactorsOutput = 0; - #if defined(TESS_FACTORS_FUNC_DEFINED) - TessFactorsOutput = GetTessFactors(patch); - #else - TessFactorsOutput = 1..xxxx; - #endif - f.edge[0] = TessFactorsOutput.x; - f.edge[1] = TessFactorsOutput.y; - f.edge[2] = TessFactorsOutput.z; - f.inside = TessFactorsOutput.w; - return f; - } - - // ForwardBase Domain - [UNITY_domain("tri")] - FragmentData Domain(TessellationFactors factors, OutputPatch patch, float3 baryCoords : SV_DomainLocation) - { - VertexData v = (VertexData) 0; - UNITY_TRANSFER_INSTANCE_ID(patch[0], v); - v.vertex = patch[0].vertex * baryCoords.x + patch[1].vertex * baryCoords.y + patch[2].vertex * baryCoords.z; - - #if defined(PHONG) - float3 pp[3]; - for (int index = 0; index < 3; ++index) - { - pp[index] = v.vertex.xyz - patch[index].normal * (dot(v.vertex.xyz, patch[index].normal) - dot(patch[index].vertex.xyz, patch[index].normal)); - } - v.vertex.xyz = 0.5 * (pp[0]*baryCoords.x + pp[1]*baryCoords.y + pp[2]*baryCoords.z) + (0.5) * v.vertex.xyz; - #endif - - v.normal = patch[0].normal * baryCoords.x + patch[1].normal * baryCoords.y + patch[2].normal * baryCoords.z; - v.tangent = patch[0].tangent * baryCoords.x + patch[1].tangent * baryCoords.y + patch[2].tangent * baryCoords.z; - v.color = patch[0].color * baryCoords.x + patch[1].color * baryCoords.y + patch[2].color * baryCoords.z; - v.uv0 = patch[0].uv0 * baryCoords.x + patch[1].uv0 * baryCoords.y + patch[2].uv0 * baryCoords.z; - v.uv1 = patch[0].uv1 * baryCoords.x + patch[1].uv1 * baryCoords.y + patch[2].uv1 * baryCoords.z; - v.uv2 = patch[0].uv2 * baryCoords.x + patch[1].uv2 * baryCoords.y + patch[2].uv2 * baryCoords.z; - v.uv3 = patch[0].uv3 * baryCoords.x + patch[1].uv3 * baryCoords.y + patch[2].uv3 * baryCoords.z; - - FragmentData i; - UNITY_INITIALIZE_OUTPUT(FragmentData, i); - UNITY_TRANSFER_INSTANCE_ID(patch[0], i); - - vD = v; - FragData = i; - VHVertex(); - - i = FragData; - v = vD; - #if defined(UNITY_PASS_SHADOWCASTER) - i.worldNormal = UnityObjectToWorldNormal(v.normal); - i.worldPos = mul(unity_ObjectToWorld, v.vertex); - i.uv0 = v.uv0; - i.uv1 = v.uv1; - i.uv2 = v.uv2; - i.uv3 = v.uv3; - i.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz); - i.worldTangent.w = v.tangent.w * unity_WorldTransformParams.w; - #else - #if defined(UNITY_PASS_META) - i.pos = UnityMetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST); - #else - i.pos = UnityObjectToClipPos(v.vertex); - #endif - i.normal = v.normal; - i.worldNormal = UnityObjectToWorldNormal(v.normal); - i.worldPos = mul(unity_ObjectToWorld, v.vertex); - i.uv0 = v.uv0; - i.uv1 = v.uv1; - i.uv2 = v.uv2; - i.uv3 = v.uv3; - i.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz); - i.worldTangent.w = v.tangent.w * unity_WorldTransformParams.w; - i.vertexColor = v.color; - - #if defined(EDITOR_VISUALIZATION) - i.vizUV = 0; - i.lightCoord = 0; - if (unity_VisualizationMode == EDITORVIZ_TEXTURE) - i.vizUV = UnityMetaVizUV(unity_EditorViz_UVIndex, v.uv0.xy, v.uv1.xy, v.uv2.xy, unity_EditorViz_Texture_ST); - else if (unity_VisualizationMode == EDITORVIZ_SHOWLIGHTMASK) - { - i.vizUV = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; - i.lightCoord = mul(unity_EditorViz_WorldToLight, mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1))); - } - #endif - - #if defined(NEED_SCREEN_POS) - i.screenPos = ComputeScreenPos(i.pos); - #endif - - #if !defined(UNITY_PASS_META) - #if defined(LIGHTMAP_ON) - i.lightmapUv.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; - #endif - #if defined(DYNAMICLIGHTMAP_ON) - i.lightmapUv.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; - #endif - - UNITY_TRANSFER_LIGHTING(i, v.uv1.xy); - - #if !defined(UNITY_PASS_FORWARDADD) - // unity does some funky stuff for different platforms with these macros - #ifdef FOG_COMBINED_WITH_TSPACE - UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(i, i.pos); - #elif defined(FOG_COMBINED_WITH_WORLD_POS) - UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(i, i.pos); - #else - UNITY_TRANSFER_FOG(i, i.pos); - #endif - #else - UNITY_TRANSFER_FOG(i, i.pos); - #endif - #endif - #endif - - return i; - } - - // ForwardBase Fragment - half4 Fragment(FragmentData i) : SV_TARGET - { - UNITY_SETUP_INSTANCE_ID(i); - #ifdef FOG_COMBINED_WITH_TSPACE - UNITY_EXTRACT_FOG_FROM_TSPACE(i); - #elif defined(FOG_COMBINED_WITH_WORLD_POS) - UNITY_EXTRACT_FOG_FROM_WORLD_POS(i); - #else - UNITY_EXTRACT_FOG(i); - #endif - - FragData = i; - o = (SurfaceData) 0; - d = CreateMeshData(i); - o.Albedo = half3(0.5, 0.5, 0.5); - o.Normal = half3(0, 0, 1); - o.Smoothness = 0.5; - o.Occlusion = 1; - o.Alpha = 1; - FinalColor = half4(o.Albedo, o.Alpha); - - ParallaxFragment(); - BaseFragmentFunction(); - DetailsFragment(); - - ORLLighting(); - - UNITY_APPLY_FOG(_unity_fogCoord, FinalColor); - - return FinalColor; - } - - ENDCG - // ForwardBase Pass End - - } - - Pass - { - Tags { "LightMode" = "ForwardAdd" } - ZWrite Off - Blend One One - - // ForwardAdd Pass Start - CGPROGRAM - #pragma target 4.6 - #pragma require tesshw - #pragma multi_compile_instancing - #pragma multi_compile_fog - #pragma multi_compile_fwdadd_fullshadows - #pragma vertex Vertex - #pragma fragment Fragment - #pragma hull Hull - #pragma domain Domain - - #define UNITY_INSTANCED_LOD_FADE - #define UNITY_INSTANCED_SH - #define UNITY_INSTANCED_LIGHTMAPSTS - - #ifndef UNITY_PASS_FORWARDADD - #define UNITY_PASS_FORWARDADD - #endif - - #if defined(SHADER_API_XBOXONE) || defined(SHADER_API_PSSL) - #define MAX_TESSELLATION_FACTORS 15.0 - #else - #define MAX_TESSELLATION_FACTORS 64.0 - #endif - - #include "UnityStandardUtils.cginc" - #include "Lighting.cginc" - #include "AutoLight.cginc" - #include "Tessellation.cginc" - - #define FLT_EPSILON 1.192092896e-07 - - #define _MASKMAP_SAMPLED - - #define _SET_GLOBAL_UVS - - #if !defined(DETAILS_MODE_PACKED) && !defined(DETAILS_MODE_SEPARATED) - #define DETAILS_MODE_PACKED - #endif - - #define TESS_FACTORS_FUNC_DEFINED - - #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) - #define PLAT_QUEST - #else - #ifdef PLAT_QUEST - #undef PLAT_QUEST - #endif - #endif - - #if !defined(LIGHTMAP_ON) || !defined(UNITY_PASS_FORWARDBASE) - #undef BAKERY_SH - #undef BAKERY_RNM - #endif - - #ifdef LIGHTMAP_ON - #undef BAKERY_VOLUME - #endif - - #ifdef LIGHTMAP_ON - #if defined(BAKERY_RNM) || defined(BAKERY_SH) || defined(BAKERY_VERTEXLM) - #define BAKERYLM_ENABLED - #undef DIRLIGHTMAP_COMBINED - #endif - #endif - - #if defined(BAKERY_SH) || defined(BAKERY_RNM) || defined(BAKERY_VOLUME) - #ifdef BAKED_SPECULAR - #define _BAKERY_LMSPEC - #define BAKERY_LMSPEC - #endif - #endif - - #define NEED_SCREEN_POS - - struct VertexData - { - float4 vertex : POSITION; - float3 normal : NORMAL; - float4 tangent : TANGENT; - float4 color : COLOR; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - UNITY_VERTEX_INPUT_INSTANCE_ID - }; - - struct FragmentData - { - #if defined(UNITY_PASS_SHADOWCASTER) - V2F_SHADOW_CASTER; - float2 uv0 : TEXCOORD1; - float2 uv1 : TEXCOORD2; - float2 uv2 : TEXCOORD3; - float2 uv3 : TEXCOORD4; - float3 worldPos : TEXCOORD5; - float3 worldNormal : TEXCOORD6; - float4 worldTangent : TEXCOORD7; - #else - float4 pos : SV_POSITION; - float3 normal : NORMAL; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - float3 worldPos : TEXCOORD4; - float3 worldNormal : TEXCOORD5; - float4 worldTangent : TEXCOORD6; - float4 lightmapUv : TEXCOORD7; - float4 vertexColor : TEXCOORD8; - - #if !defined(UNITY_PASS_META) - UNITY_LIGHTING_COORDS(9, 10) - UNITY_FOG_COORDS(11) - #endif - #endif - - #if defined(EDITOR_VISUALIZATION) - float2 vizUV : TEXCOORD9; - float4 lightCoord : TEXCOORD10; - #endif - - #if defined(NEED_SCREEN_POS) - float4 screenPos: SCREENPOS; - #endif - - #if defined(EXTRA_V2F_0) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F0 : TEXCOORD8; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F0 : TEXCOORD12; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F0 : TEXCOORD11; - #else - float4 extraV2F0 : TEXCOORD9; - #endif - #endif - #endif - #endif - #if defined(EXTRA_V2F_1) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F1 : TEXCOORD9; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F1 : TEXCOORD13; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F1 : TEXCOORD14; - #else - float4 extraV2F1 : TEXCOORD15; - #endif - #endif - #endif - #endif - #if defined(EXTRA_V2F_2) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F2 : TEXCOORD10; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F2 : TEXCOORD14; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F2 : TEXCOORD15 - #else - float4 extraV2F2 : TEXCOORD16; - #endif - #endif - #endif - #endif - - UNITY_VERTEX_INPUT_INSTANCE_ID - UNITY_VERTEX_OUTPUT_STEREO - }; - - struct MeshData - { - half2 uv0; - half2 uv1; - half2 uv2; - half2 uv3; - half4 vertexColor; - half3 normal; - half3 worldNormal; - half3 localSpacePosition; - half3 worldSpacePosition; - half3 worldSpaceViewDir; - half3 tangentSpaceViewDir; - float3x3 TBNMatrix; - float4 extraV2F0; - float4 extraV2F1; - float4 extraV2F2; - float4 screenPos; - }; - - MeshData CreateMeshData(FragmentData i) - { - MeshData m = (MeshData) 0; - m.uv0 = i.uv0; - m.uv1 = i.uv1; - m.uv2 = i.uv2; - m.uv3 = i.uv3; - m.worldNormal = normalize(i.worldNormal); - m.localSpacePosition = mul(unity_WorldToObject, float4(i.worldPos, 1)).xyz; - m.worldSpacePosition = i.worldPos; - m.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos); - - #if !defined(UNITY_PASS_SHADOWCASTER) - m.vertexColor = i.vertexColor; - m.normal = i.normal; - float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * - 1; - m.TBNMatrix = float3x3(normalize(i.worldTangent.xyz), bitangent, m.worldNormal); - m.tangentSpaceViewDir = mul(m.TBNMatrix, m.worldSpaceViewDir); - #endif - - #if defined(EXTRA_V2F_0) - m.extraV2F0 = i.extraV2F0; - #endif - #if defined(EXTRA_V2F_1) - m.extraV2F1 = i.extraV2F1; - #endif - #if defined(EXTRA_V2F_2) - m.extraV2F2 = i.extraV2F2; - #endif - #if defined(NEED_SCREEN_POS) - m.screenPos = i.screenPos; - #endif - - return m; - } - - struct SurfaceData - { - half3 Albedo; - half3 Emission; - half Metallic; - half Smoothness; - half Occlusion; - half3 Normal; - half Alpha; - }; - - struct TessellationFactors - { - float edge[3] : SV_TessFactor; - float inside : SV_InsideTessFactor; - }; - - struct TessVertex - { - float4 vertex : INTERNALTESSPOS; - float3 normal : NORMAL; - float4 tangent : TANGENT; - float4 color : COLOR; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - UNITY_VERTEX_INPUT_INSTANCE_ID - UNITY_VERTEX_OUTPUT_STEREO - }; - - FragmentData FragData; - SurfaceData o; - MeshData d; - VertexData vD; - float4 FinalColor; - - half invLerp(half a, half b, half v) - { - return (v - a) / (b - a); - } - - half getBakedNoise(Texture2D noiseTex, SamplerState noiseTexSampler, half3 p) - { - half3 i = floor(p); p -= i; p *= p * (3. - 2. * p); - half2 uv = (p.xy + i.xy + half2(37, 17) * i.z + .5) / 256.; - uv.y *= -1; - p.xy = noiseTex.SampleLevel(noiseTexSampler, uv, 0).yx; - return lerp(p.x, p.y, p.z); - } - - half3 TransformObjectToWorld(half3 pos) - { - return mul(unity_ObjectToWorld, half4(pos, 1)).xyz; - }; - - // mostly taken from the Amplify shader reference - half2 POM(Texture2D heightMap, SamplerState heightSampler, half2 uvs, half2 dx, half2 dy, half3 normalWorld, half3 viewWorld, half3 viewDirTan, int minSamples, int maxSamples, half parallax, half refPlane, half2 tilling, half2 curv, int index, inout half finalHeight) - { - half3 result = 0; - int stepIndex = 0; - int numSteps = (int)lerp((half)maxSamples, (half)minSamples, saturate(dot(normalWorld, viewWorld))); - half layerHeight = 1.0 / numSteps; - half2 plane = parallax * (viewDirTan.xy / viewDirTan.z); - uvs.xy += refPlane * plane; - half2 deltaTex = -plane * layerHeight; - half2 prevTexOffset = 0; - half prevRayZ = 1.0f; - half prevHeight = 0.0f; - half2 currTexOffset = deltaTex; - half currRayZ = 1.0f - layerHeight; - half currHeight = 0.0f; - half intersection = 0; - half2 finalTexOffset = 0; - while (stepIndex < numSteps + 1) - { - currHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + currTexOffset, dx, dy).r; - if (currHeight > currRayZ) - { - stepIndex = numSteps + 1; - } - else - { - stepIndex++; - prevTexOffset = currTexOffset; - prevRayZ = currRayZ; - prevHeight = currHeight; - currTexOffset += deltaTex; - currRayZ -= layerHeight; - } - } - int sectionSteps = 2; - int sectionIndex = 0; - half newZ = 0; - half newHeight = 0; - while (sectionIndex < sectionSteps) - { - intersection = (prevHeight - prevRayZ) / (prevHeight - currHeight + currRayZ - prevRayZ); - finalTexOffset = prevTexOffset +intersection * deltaTex; - newZ = prevRayZ - intersection * layerHeight; - newHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + finalTexOffset, dx, dy).r; - if (newHeight > newZ) - { - currTexOffset = finalTexOffset; - currHeight = newHeight; - currRayZ = newZ; - deltaTex = intersection * deltaTex; - layerHeight = intersection * layerHeight; - } - else - { - prevTexOffset = finalTexOffset; - prevHeight = newHeight; - prevRayZ = newZ; - deltaTex = (1 - intersection) * deltaTex; - layerHeight = (1 - intersection) * layerHeight; - } - sectionIndex++; - } - finalHeight = newHeight; - return uvs.xy + finalTexOffset; - } - - half remap(half s, half a1, half a2, half b1, half b2) - { - return b1 + (s - a1) * (b2 - b1) / (a2 - a1); - } - - half3 ApplyLut2D(Texture2D LUT2D, SamplerState lutSampler, half3 uvw) - { - half3 scaleOffset = half3(1.0 / 1024.0, 1.0 / 32.0, 31.0); - // Strip format where `height = sqrt(width)` - uvw.z *= scaleOffset.z; - half shift = floor(uvw.z); - uvw.xy = uvw.xy * scaleOffset.z * scaleOffset.xy + scaleOffset.xy * 0.5; - uvw.x += shift * scaleOffset.y; - uvw.xyz = lerp( - SAMPLE_TEXTURE2D(LUT2D, lutSampler, uvw.xy).rgb, - SAMPLE_TEXTURE2D(LUT2D, lutSampler, uvw.xy + half2(scaleOffset.y, 0.0)).rgb, - uvw.z - shift - ); - return uvw; - } - - half3 AdjustContrast(half3 color, half contrast) - { - color = saturate(lerp(half3(0.5, 0.5, 0.5), color, contrast)); - return color; - } - - half3 AdjustSaturation(half3 color, half saturation) - { - half3 intensity = dot(color.rgb, half3(0.299, 0.587, 0.114)); - color = lerp(intensity, color.rgb, saturation); - return color; - } - - half3 AdjustBrightness(half3 color, half brightness) - { - color += brightness; - return color; - } - - struct ParamsLogC - { - half cut; - half a, b, c, d, e, f; - }; - - static const ParamsLogC LogC = { - 0.011361, // cut - 5.555556, // a - 0.047996, // b - 0.244161, // c - 0.386036, // d - 5.301883, // e - 0.092819 // f - - }; - - half LinearToLogC_Precise(half x) - { - half o; - if (x > LogC.cut) - o = LogC.c * log10(LogC.a * x + LogC.b) + LogC.d; - else - o = LogC.e * x + LogC.f; - return o; - } - - half PositivePow(half base, half power) - { - return pow(max(abs(base), half(FLT_EPSILON)), power); - } - - half3 LinearToLogC(half3 x) - { - return LogC.c * log10(LogC.a * x + LogC.b) + LogC.d; - } - - half3 LinerToSRGB(half3 c) - { - return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878); - } - - half3 SRGBToLiner(half3 c) - { - return max(1.055 * PositivePow(c, 0.416666667) - 0.055, 0.0); - } - - half3 LogCToLinear(half3 c) - { - return (pow(10.0, (c - LogC.d) / LogC.c) - LogC.b) / LogC.a; - } - - // Specular stuff taken from https://github.com/z3y/shaders/ - float pow5(float x) - { - float x2 = x * x; - return x2 * x2 * x; - } - - float sq(float x) - { - return x * x; - } - - struct Gradient - { - int type; - int colorsLength; - int alphasLength; - half4 colors[8]; - half2 alphas[8]; - }; - - Gradient NewGradient(int type, int colorsLength, int alphasLength, - half4 colors0, half4 colors1, half4 colors2, half4 colors3, half4 colors4, half4 colors5, half4 colors6, half4 colors7, - half2 alphas0, half2 alphas1, half2 alphas2, half2 alphas3, half2 alphas4, half2 alphas5, half2 alphas6, half2 alphas7) - { - Gradient g; - g.type = type; - g.colorsLength = colorsLength; - g.alphasLength = alphasLength; - g.colors[ 0 ] = colors0; - g.colors[ 1 ] = colors1; - g.colors[ 2 ] = colors2; - g.colors[ 3 ] = colors3; - g.colors[ 4 ] = colors4; - g.colors[ 5 ] = colors5; - g.colors[ 6 ] = colors6; - g.colors[ 7 ] = colors7; - g.alphas[ 0 ] = alphas0; - g.alphas[ 1 ] = alphas1; - g.alphas[ 2 ] = alphas2; - g.alphas[ 3 ] = alphas3; - g.alphas[ 4 ] = alphas4; - g.alphas[ 5 ] = alphas5; - g.alphas[ 6 ] = alphas6; - g.alphas[ 7 ] = alphas7; - return g; - } - - half4 SampleGradient(Gradient gradient, half time) - { - half3 color = gradient.colors[0].rgb; - UNITY_UNROLL - for (int c = 1; c < 8; c++) - { - half colorPos = saturate((time - gradient.colors[c - 1].w) / (0.00001 + (gradient.colors[c].w - gradient.colors[c - 1].w)) * step(c, (half)gradient.colorsLength - 1)); - color = lerp(color, gradient.colors[c].rgb, lerp(colorPos, step(0.01, colorPos), gradient.type)); - } - #ifndef UNITY_COLORSPACE_GAMMA - color = half3(GammaToLinearSpaceExact(color.r), GammaToLinearSpaceExact(color.g), GammaToLinearSpaceExact(color.b)); - #endif - half alpha = gradient.alphas[0].x; - UNITY_UNROLL - for (int a = 1; a < 8; a++) - { - half alphaPos = saturate((time - gradient.alphas[a - 1].y) / (0.00001 + (gradient.alphas[a].y - gradient.alphas[a - 1].y)) * step(a, (half)gradient.alphasLength - 1)); - alpha = lerp(alpha, gradient.alphas[a].x, lerp(alphaPos, step(0.01, alphaPos), gradient.type)); - } - return half4(color, alpha); - } - - float3 RotateAroundAxis(float3 center, float3 original, float3 u, float angle) - { - original -= center; - float C = cos(angle); - float S = sin(angle); - float t = 1 - C; - float m00 = t * u.x * u.x + C; - float m01 = t * u.x * u.y - S * u.z; - float m02 = t * u.x * u.z + S * u.y; - float m10 = t * u.x * u.y + S * u.z; - float m11 = t * u.y * u.y + C; - float m12 = t * u.y * u.z - S * u.x; - float m20 = t * u.x * u.z - S * u.y; - float m21 = t * u.y * u.z + S * u.x; - float m22 = t * u.z * u.z + C; - float3x3 finalMatrix = float3x3(m00, m01, m02, m10, m11, m12, m20, m21, m22); - return mul(finalMatrix, original) + center; - } - - half3 UnpackNormalAG(half4 packedNormal, half scale = 1.0) - { - half3 normal; - normal.xy = packedNormal.ag * 2.0 - 1.0; - normal.z = max(1.0e-16, sqrt(1.0 - saturate(dot(normal.xy, normal.xy)))); - - normal.xy *= scale; - return normal; - } - - half D_GGX(half NoH, half roughness) - { - half a = NoH * roughness; - half k = roughness / (1.0 - NoH * NoH + a * a); - return k * k * (1.0 / UNITY_PI); - } - - half D_GGX_Anisotropic(half NoH, const half3 h, const half3 t, const half3 b, half at, half ab) - { - half ToH = dot(t, h); - half BoH = dot(b, h); - half a2 = at * ab; - half3 v = half3(ab * ToH, at * BoH, a2 * NoH); - half v2 = dot(v, v); - half w2 = a2 / v2; - return a2 * w2 * w2 * (1.0 / UNITY_PI); - } - - half V_SmithGGXCorrelated(half NoV, half NoL, half roughness) - { - half a2 = roughness * roughness; - half GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); - half GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); - return 0.5 / (GGXV + GGXL); - } - - half3 F_Schlick(half u, half3 f0) - { - return f0 + (1.0 - f0) * pow(1.0 - u, 5.0); - } - - half3 F_Schlick(half3 f0, half f90, half VoH) - { - // Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering" - return f0 + (f90 - f0) * pow(1.0 - VoH, 5); - } - - half3 fresnel(half3 f0, half LoH) - { - half f90 = saturate(dot(f0, half(50.0 / 3).xxx)); - return F_Schlick(f0, f90, LoH); - } - - half Fd_Burley(half perceptualRoughness, half NoV, half NoL, half LoH) - { - // Burley 2012, "Physically-Based Shading at Disney" - half f90 = 0.5 + 2.0 * perceptualRoughness * LoH * LoH; - half lightScatter = F_Schlick(1.0, f90, NoL); - half viewScatter = F_Schlick(1.0, f90, NoV); - return lightScatter * viewScatter; - } - - half3 getBoxProjection(half3 direction, half3 position, half4 cubemapPosition, half3 boxMin, half3 boxMax) - { - #if defined(UNITY_SPECCUBE_BOX_PROJECTION) && !defined(UNITY_PBS_USE_BRDF2) || defined(FORCE_BOX_PROJECTION) - if (cubemapPosition.w > 0) - { - half3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction; - half scalar = min(min(factors.x, factors.y), factors.z); - direction = direction * scalar + (position - cubemapPosition.xyz); - } - #endif - - return direction; - } - - half3 getEnvReflection(half3 worldSpaceViewDir, half3 worldSpacePosition, half3 normal, half smoothness, int mip) - { - half3 env = 0; - half3 reflDir = reflect(worldSpaceViewDir, normal); - half perceptualRoughness = 1 - smoothness; - half rough = perceptualRoughness * perceptualRoughness; - reflDir = lerp(reflDir, normal, rough * rough); - - half3 reflectionUV1 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, mip); - half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR); - - half3 indirectSpecular; - half interpolator = unity_SpecCube0_BoxMin.w; - - UNITY_BRANCH - if (interpolator < 0.99999) - { - half3 reflectionUV2 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, mip); - half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR); - indirectSpecular = lerp(probe1sample, probe0sample, interpolator); - } - else - { - indirectSpecular = probe0sample; - } - - env = indirectSpecular; - return env; - } - - half3 EnvBRDFMultiscatter(half2 dfg, half3 f0) - { - return lerp(dfg.xxx, dfg.yyy, f0); - } - - half3 EnvBRDFApprox(half perceptualRoughness, half NoV, half3 f0) - { - half g = 1 - perceptualRoughness; - //https://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - half4 t = half4(1 / 0.96, 0.475, (0.0275 - 0.25 * 0.04) / 0.96, 0.25); - t *= half4(g, g, g, g); - t += half4(0, 0, (0.015 - 0.75 * 0.04) / 0.96, 0.75); - half a0 = t.x * min(t.y, exp2(-9.28 * NoV)) + t.z; - half a1 = t.w; - return saturate(lerp(a0, a1, f0)); - } - - half GSAA_Filament(half3 worldNormal, half perceptualRoughness, half inputVariance, half threshold) - { - // Kaplanyan 2016, "Stable specular highlights" - // Tokuyoshi 2017, "Error Reduction and Simplification for Shading Anti-Aliasing" - // Tokuyoshi and Kaplanyan 2019, "Improved Geometric Specular Antialiasing" - - // This implementation is meant for deferred rendering in the original paper but - // we use it in forward rendering as well (as discussed in Tokuyoshi and Kaplanyan - // 2019). The main reason is that the forward version requires an expensive transform - // of the half vector by the tangent frame for every light. This is therefore an - // approximation but it works well enough for our needs and provides an improvement - // over our original implementation based on Vlachos 2015, "Advanced VR Rendering". - - half3 du = ddx(worldNormal); - half3 dv = ddy(worldNormal); - - half variance = inputVariance * (dot(du, du) + dot(dv, dv)); - - half roughness = perceptualRoughness * perceptualRoughness; - half kernelRoughness = min(2.0 * variance, threshold); - half squareRoughness = saturate(roughness * roughness + kernelRoughness); - - return sqrt(sqrt(squareRoughness)); - } - - // w0, w1, w2, and w3 are the four cubic B-spline basis functions - half w0(half a) - { - // return (1.0f/6.0f)*(-a*a*a + 3.0f*a*a - 3.0f*a + 1.0f); - return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f); // optimized - - } - - half w1(half a) - { - // return (1.0f/6.0f)*(3.0f*a*a*a - 6.0f*a*a + 4.0f); - return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f); - } - - half w2(half a) - { - // return (1.0f/6.0f)*(-3.0f*a*a*a + 3.0f*a*a + 3.0f*a + 1.0f); - return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f); - } - - half w3(half a) - { - return (1.0f / 6.0f) * (a * a * a); - } - - // g0 and g1 are the two amplitude functions - half g0(half a) - { - return w0(a) + w1(a); - } - - half g1(half a) - { - return w2(a) + w3(a); - } - - // h0 and h1 are the two offset functions - half h0(half a) - { - // note +0.5 offset to compensate for CUDA linear filtering convention - return -1.0f + w1(a) / (w0(a) + w1(a)) + 0.5f; - } - - half h1(half a) - { - return 1.0f + w3(a) / (w2(a) + w3(a)) + 0.5f; - } - - //https://ndotl.wordpress.com/2018/08/29/baking-artifact-free-lightmaps - half3 tex2DFastBicubicLightmap(half2 uv, inout half4 bakedColorTex) - { - #if !defined(PLAT_QUEST) && defined(BICUBIC_LIGHTMAP) - half width; - half height; - unity_Lightmap.GetDimensions(width, height); - half x = uv.x * width; - half y = uv.y * height; - - x -= 0.5f; - y -= 0.5f; - half px = floor(x); - half py = floor(y); - half fx = x - px; - half fy = y - py; - - // note: we could store these functions in a lookup table texture, but maths is cheap - half g0x = g0(fx); - half g1x = g1(fx); - half h0x = h0(fx); - half h1x = h1(fx); - half h0y = h0(fy); - half h1y = h1(fy); - - half4 r = g0(fy) * (g0x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h0x, py + h0y) * 1.0f / width)) + - g1x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h1x, py + h0y) * 1.0f / width))) + - g1(fy) * (g0x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h0x, py + h1y) * 1.0f / width)) + - g1x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h1x, py + h1y) * 1.0f / width))); - bakedColorTex = r; - return DecodeLightmap(r); - #else - bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, uv); - return DecodeLightmap(bakedColorTex); - #endif - } - - half3 GetSpecularHighlights(half3 worldNormal, half3 lightColor, half3 lightDirection, half3 f0, half3 viewDir, half clampedRoughness, half NoV, half3 energyCompensation) - { - half3 halfVector = Unity_SafeNormalize(lightDirection + viewDir); - - half NoH = saturate(dot(worldNormal, halfVector)); - half NoL = saturate(dot(worldNormal, lightDirection)); - half LoH = saturate(dot(lightDirection, halfVector)); - - half3 F = F_Schlick(LoH, f0); - half D = D_GGX(NoH, clampedRoughness); - half V = V_SmithGGXCorrelated(NoV, NoL, clampedRoughness); - - #ifndef UNITY_PBS_USE_BRDF2 - F *= energyCompensation; - #endif - - return max(0, (D * V) * F) * lightColor * NoL * UNITY_PI; - } - - #ifdef DYNAMICLIGHTMAP_ON - half3 getRealtimeLightmap(half2 uv, half3 worldNormal) - { - half2 realtimeUV = uv; - half4 bakedCol = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, realtimeUV); - half3 realtimeLightmap = DecodeRealtimeLightmap(bakedCol); - - #ifdef DIRLIGHTMAP_COMBINED - half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, realtimeUV); - realtimeLightmap += DecodeDirectionalLightmap(realtimeLightmap, realtimeDirTex, worldNormal); - #endif - - return realtimeLightmap; - } - #endif - - half computeSpecularAO(half NoV, half ao, half roughness) - { - return clamp(pow(NoV + ao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ao, 0.0, 1.0); - } - - half shEvaluateDiffuseL1Geomerics_local(half L0, half3 L1, half3 n) - { - // average energy - half R0 = L0; - - // avg direction of incoming light - half3 R1 = 0.5f * L1; - - // directional brightness - half lenR1 = length(R1); - - // linear angle between normal and direction 0-1 - //half q = 0.5f * (1.0f + dot(R1 / lenR1, n)); - //half q = dot(R1 / lenR1, n) * 0.5 + 0.5; - half q = dot(normalize(R1), n) * 0.5 + 0.5; - q = saturate(q); // Thanks to ScruffyRuffles for the bug identity. - - // power for q - // lerps from 1 (linear) to 3 (cubic) based on directionality - half p = 1.0f + 2.0f * lenR1 / R0; - - // dynamic range constant - // should vary between 4 (highly directional) and 0 (ambient) - half a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0); - - return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p)); - } - - // https://assetstore.unity.com/packages/tools/level-design/bakery-gpu-lightmapper-122218 - - #if defined(BAKERY_ENABLED) - - //float2 bakeryLightmapSize; - #define BAKERYMODE_DEFAULT 0 - #define BAKERYMODE_VERTEXLM 1.0f - #define BAKERYMODE_RNM 2.0f - #define BAKERYMODE_SH 3.0f - - #define rnmBasis0 float3(0.816496580927726f, 0, 0.5773502691896258f) - #define rnmBasis1 float3(-0.4082482904638631f, 0.7071067811865475f, 0.5773502691896258f) - #define rnmBasis2 float3(-0.4082482904638631f, -0.7071067811865475f, 0.5773502691896258f) - - #if defined(BAKERY_DOMINANT) - #undef BAKERY_RNM - #undef BAKERY_SH - #undef BAKERY_MONOSH - #endif - - #ifdef BICUBIC_LIGHTMAP - #define BAKERY_BICUBIC - #endif - - //#define BAKERY_SSBUMP - - // can't fit vertexLM SH to sm3_0 interpolators - #ifndef SHADER_API_D3D11 - #undef BAKERY_VERTEXLMSH - #endif - - // can't do stuff on sm2_0 due to standard shader alrady taking up all instructions - #if SHADER_TARGET < 30 - #undef BAKERY_BICUBIC - #undef BAKERY_LMSPEC - - #undef BAKERY_RNM - #undef BAKERY_SH - #undef BAKERY_MONOSH - #undef BAKERY_VERTEXLM - #endif - - #if !defined(BAKERY_SH) && !defined(BAKERY_RNM) - #undef BAKERY_BICUBIC - #endif - - #ifndef UNITY_SHOULD_SAMPLE_SH - #undef BAKERY_PROBESHNONLINEAR - #endif - - #if defined(BAKERY_RNM) && defined(BAKERY_LMSPEC) - #define BAKERY_RNMSPEC - #endif - - #ifndef BAKERY_VERTEXLM - #undef BAKERY_VERTEXLMDIR - #undef BAKERY_VERTEXLMSH - #undef BAKERY_VERTEXLMMASK - #endif - - #define lumaConv float3(0.2125f, 0.7154f, 0.0721f) - - #if defined(BAKERY_SH) || defined(BAKERY_MONOSH) || defined(BAKERY_VERTEXLMSH) || defined(BAKERY_PROBESHNONLINEAR) || defined(BAKERY_VOLUME) - float shEvaluateDiffuseL1Geomerics(float L0, float3 L1, float3 n) - { - // average energy - float R0 = L0; - - // avg direction of incoming light - float3 R1 = 0.5f * L1; - - // directional brightness - float lenR1 = length(R1); - - // linear angle between normal and direction 0-1 - //float q = 0.5f * (1.0f + dot(R1 / lenR1, n)); - //float q = dot(R1 / lenR1, n) * 0.5 + 0.5; - float q = dot(normalize(R1), n) * 0.5 + 0.5; - - // power for q - // lerps from 1 (linear) to 3 (cubic) based on directionality - float p = 1.0f + 2.0f * lenR1 / R0; - - // dynamic range constant - // should vary between 4 (highly directional) and 0 (ambient) - float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0); - - return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p)); - } - #endif - - #ifdef BAKERY_VERTEXLM - float4 unpack4NFloats(float src) { - //return fmod(float4(src / 262144.0, src / 4096.0, src / 64.0, src), 64.0)/64.0; - return frac(float4(src / (262144.0*64), src / (4096.0*64), src / (64.0*64), src)); - } - float3 unpack3NFloats(float src) { - float r = frac(src); - float g = frac(src * 256.0); - float b = frac(src * 65536.0); - return float3(r, g, b); - } - #if defined(BAKERY_VERTEXLMDIR) - - #ifdef BAKERY_MONOSH - void BakeryVertexLMMonoSH(inout float3 diffuseColor, inout float3 specularColor, float3 nL1, float3 normalWorld, float3 viewDir, float smoothness) - { - nL1 = nL1; - float3 L0 = diffuseColor; - float3 L1x = nL1.x * L0 * 2; - float3 L1y = nL1.y * L0 * 2; - float3 L1z = nL1.z * L0 * 2; - - float3 sh; - #if BAKERY_SHNONLINEAR - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - float lumaL0 = dot(L0, 1); - float lumaL1x = dot(L1x, 1); - float lumaL1y = dot(L1y, 1); - float lumaL1z = dot(L1z, 1); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = nL1; - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - - void BakeryVertexLMDirection(inout float3 diffuseColor, inout float3 specularColor, float3 lightDirection, float3 vertexNormalWorld, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 dominantDir = Unity_SafeNormalize(lightDirection); - half halfLambert = dot(normalWorld, dominantDir) * 0.5 + 0.5; - half flatNormalHalfLambert = dot(vertexNormalWorld, dominantDir) * 0.5 + 0.5; - - #ifdef BAKERY_LMSPEC - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = spec * diffuseColor; - #endif - - diffuseColor *= halfLambert / max(1e-4h, flatNormalHalfLambert); - } - #elif defined(BAKERY_VERTEXLMSH) - void BakeryVertexLMSH(inout float3 diffuseColor, inout float3 specularColor, float3 shL1x, float3 shL1y, float3 shL1z, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 L0 = diffuseColor; - float3 nL1x = shL1x; - float3 nL1y = shL1y; - float3 nL1z = shL1z; - float3 L1x = nL1x * L0 * 2; - float3 L1y = nL1y * L0 * 2; - float3 L1z = nL1z * L0 * 2; - - float3 sh; - #ifdef BAKERY_SHNONLINEAR - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - float lumaL0 = dot(L0, 1); - float lumaL1x = dot(L1x, 1); - float lumaL1y = dot(L1y, 1); - float lumaL1z = dot(L1z, 1); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - #endif - - #ifdef BAKERY_BICUBIC - float BakeryBicubic_w0(float a) - { - return (1.0f/6.0f)*(a*(a*(-a + 3.0f) - 3.0f) + 1.0f); - } - - float BakeryBicubic_w1(float a) - { - return (1.0f/6.0f)*(a*a*(3.0f*a - 6.0f) + 4.0f); - } - - float BakeryBicubic_w2(float a) - { - return (1.0f/6.0f)*(a*(a*(-3.0f*a + 3.0f) + 3.0f) + 1.0f); - } - - float BakeryBicubic_w3(float a) - { - return (1.0f/6.0f)*(a*a*a); - } - - float BakeryBicubic_g0(float a) - { - return BakeryBicubic_w0(a) + BakeryBicubic_w1(a); - } - - float BakeryBicubic_g1(float a) - { - return BakeryBicubic_w2(a) + BakeryBicubic_w3(a); - } - - float BakeryBicubic_h0(float a) - { - return -1.0f + BakeryBicubic_w1(a) / (BakeryBicubic_w0(a) + BakeryBicubic_w1(a)) + 0.5f; - } - - float BakeryBicubic_h1(float a) - { - return 1.0f + BakeryBicubic_w3(a) / (BakeryBicubic_w2(a) + BakeryBicubic_w3(a)) + 0.5f; - } - #endif - - #if defined(BAKERY_RNM) || defined(BAKERY_SH) - sampler2D _RNM0, _RNM1, _RNM2; - float4 _RNM0_TexelSize; - #endif - - #ifdef BAKERY_VOLUME - Texture3D _Volume0, _Volume1, _Volume2, _VolumeMask; - SamplerState sampler_Volume0; - - #ifndef PROPERTIES_DEFINED - float3 _VolumeMin, _VolumeInvSize; - float3 _GlobalVolumeMin, _GlobalVolumeInvSize; - #endif - - #endif - - #ifdef BAKERY_BICUBIC - // Bicubic - float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) - { - float x = uv.x * texelSize.z; - float y = uv.y * texelSize.z; - - x -= 0.5f; - y -= 0.5f; - - float px = floor(x); - float py = floor(y); - - float fx = x - px; - float fy = y - py; - - float g0x = BakeryBicubic_g0(fx); - float g1x = BakeryBicubic_g1(fx); - float h0x = BakeryBicubic_h0(fx); - float h1x = BakeryBicubic_h1(fx); - float h0y = BakeryBicubic_h0(fy); - float h1y = BakeryBicubic_h1(fy); - - return BakeryBicubic_g0(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h0y) * texelSize.x)) + - g1x * tex2D(tex, (float2(px + h1x, py + h0y) * texelSize.x))) + - - BakeryBicubic_g1(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h1y) * texelSize.x)) + - g1x * tex2D(tex, (float2(px + h1x, py + h1y) * texelSize.x))); - } - float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) - { - float x = uv.x * texelSize.z; - float y = uv.y * texelSize.z; - - x -= 0.5f; - y -= 0.5f; - - float px = floor(x); - float py = floor(y); - - float fx = x - px; - float fy = y - py; - - float g0x = BakeryBicubic_g0(fx); - float g1x = BakeryBicubic_g1(fx); - float h0x = BakeryBicubic_h0(fx); - float h1x = BakeryBicubic_h1(fx); - float h0y = BakeryBicubic_h0(fy); - float h1y = BakeryBicubic_h1(fy); - - return BakeryBicubic_g0(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h0y) * texelSize.x)) + - g1x * tex.Sample(s, (float2(px + h1x, py + h0y) * texelSize.x))) + - - BakeryBicubic_g1(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h1y) * texelSize.x)) + - g1x * tex.Sample(s, (float2(px + h1x, py + h1y) * texelSize.x))); - } - #else - // Bilinear - float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) - { - return tex2D(tex, uv); - } - float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) - { - return tex.Sample(s, uv); - } - #endif - - #ifdef DIRLIGHTMAP_COMBINED - #ifdef BAKERY_LMSPEC - float BakeryDirectionalLightmapSpecular(float2 lmUV, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 dominantDir = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lmUV).xyz * 2 - 1; - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - return spec; - } - #endif - #endif - - #ifdef BAKERY_RNM - void BakeryRNM(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalMap, float perceptualRoughness, float3 viewDirT) - { - normalMap.g *= -1; - float3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize)); - float3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize)); - float3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize)); - - #ifdef BAKERY_SSBUMP - diffuseColor = normalMap.x * rnm0 - + normalMap.z * rnm1 - + normalMap.y * rnm2; - diffuseColor *= 2; - #else - diffuseColor = saturate(dot(rnmBasis0, normalMap)) * rnm0 - + saturate(dot(rnmBasis1, normalMap)) * rnm1 - + saturate(dot(rnmBasis2, normalMap)) * rnm2; - #endif - - #ifdef BAKERY_LMSPEC - float3 dominantDirT = rnmBasis0 * dot(rnm0, lumaConv) + - rnmBasis1 * dot(rnm1, lumaConv) + - rnmBasis2 * dot(rnm2, lumaConv); - - float3 dominantDirTN = normalize(dominantDirT); - float3 specColor = saturate(dot(rnmBasis0, dominantDirTN)) * rnm0 + - saturate(dot(rnmBasis1, dominantDirTN)) * rnm1 + - saturate(dot(rnmBasis2, dominantDirTN)) * rnm2; - - half3 halfDir = Unity_SafeNormalize(dominantDirTN - viewDirT); - half nh = saturate(dot(normalMap, halfDir)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = spec * specColor; - #endif - } - #endif - - #ifdef BAKERY_SH - void BakerySH(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalWorld, float3 viewDir, float perceptualRoughness) - { - #ifdef SHADER_API_D3D11 - float3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, samplerunity_Lightmap, lmUV, _RNM0_TexelSize)); - #else - float3 L0 = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, lmUV)); - #endif - float3 nL1x = BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 nL1y = BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 nL1z = BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 L1x = nL1x * L0 * 2; - float3 L1y = nL1y * L0 * 2; - float3 L1z = nL1z * L0 * 2; - - float3 sh; - #ifdef BAKERY_SHNONLINEAR - float lumaL0 = dot(L0, float(1)); - float lumaL1x = dot(L1x, float(1)); - float lumaL1y = dot(L1y, float(1)); - float lumaL1z = dot(L1z, float(1)); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - - sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - - #endif - //BAKERY_ENABLED - - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - - half _Smoothness; - half _Metallic; - half _OcclusionStrength; - half _BumpScale; - half _HeightScale; - half _HeightRefPlane; - half _HeightStepsMin; - half _HeightStepsMax; - half _DAlbedoScale; - half _DNormalScale; - half _DSmoothScale; - half _VertexHeightAmount; - half _VertexHeightOffset; - half _TessFactor; - half _TessMinDist; - half _TessMaxDist; - half _TessEdgeLength; - half _TessMaxDisplacement; - half _SpecOcclusion; - half _SpecularRoughnessMod; - half2 GLOBAL_uv; - half4 _Color; - half4 _MainTex_ST; - half4 _MetallicRemap; - half4 _SmoothnessRemap; - half4 _MaskMap_TexelSize; - half4 _EmissionColor; - half4 GLOBAL_maskMap; - half4 _DDetailsMap_ST; - float _GSAAVariance; - float _GSAAThreshold; - int _AlbedoChannel; - int _MappingSpace; - int _PlanarAxisX; - int _PlanarAxisY; - int _MetalChannel; - int _AOChannel; - int _DetailMaskChannel; - int _SmoothChannel; - int _RoughnessMode; - int _DetailAsTintMask; - int _FlipBumpY; - int _EmissionChannel; - TEXTURE2D(_MainTex); - SAMPLER(sampler_MainTex); - TEXTURE2D(_MaskMap); - SAMPLER(sampler_MaskMap); - TEXTURE2D(_BumpMap); - SAMPLER(sampler_BumpMap); - TEXTURE2D(_EmissionMap); - SAMPLER(sampler_EmissionMap); - TEXTURE2D(_Height); - SAMPLER(sampler_Height); - int _DIgnoreMask; - int _DMappingSpace; - int _DUVChannel; - int _DPlanarAxisX; - int _DPlanarAxisY; - int _DNormalFlipY; - TEXTURE2D(_DDetailsMap); - SAMPLER(sampler_DDetailsMap); - TEXTURE2D(_DDetailsNormal); - SAMPLER(sampler_DDetailsNormal); - TEXTURE2D(_VertexHeight); - SAMPLER(sampler_VertexHeight); - TEXTURE2D(_DFG); - SAMPLER(sampler_DFG); - - void VHVertex() { - half2 uv = vD.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - half height = (SAMPLE_TEXTURE2D_LOD(_VertexHeight, sampler_VertexHeight, uv, 0).r * 2 - 1); - half3 mainOffset = vD.vertex.xyz + vD.normal * (height + _VertexHeightOffset) * _VertexHeightAmount; - vD.vertex.xyz = mainOffset; - } - - void ParallaxFragment() - { - GLOBAL_uv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - #if PARALLAX && !defined(PLAT_QUEST) - half customHeight = 0; - GLOBAL_uv = POM(_Height, sampler_Height, GLOBAL_uv, ddx(GLOBAL_uv), ddy(GLOBAL_uv), d.worldNormal, d.worldSpaceViewDir, d.tangentSpaceViewDir, _HeightStepsMin, _HeightStepsMax, _HeightScale, _HeightRefPlane, half2(1, 1), half2(0, 0), 0, customHeight); - #endif - } - - void BaseFragmentFunction() - { - #if !defined(_SET_GLOBAL_UVS) - GLOBAL_uv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - #endif - if (_MappingSpace > 0) - { - GLOBAL_uv = (_MappingSpace - 1) ? half2(d.worldSpacePosition[_PlanarAxisX], d.worldSpacePosition[_PlanarAxisY]) : half2(d.localSpacePosition[_PlanarAxisX], d.localSpacePosition[_PlanarAxisY]); - GLOBAL_uv = GLOBAL_uv * _MainTex_ST.xy + _MainTex_ST.zw; - } - half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, GLOBAL_uv); - if (_AlbedoChannel > 0) - { - albedo.rgb = albedo[_AlbedoChannel].xxx; - } - half4 masks = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, GLOBAL_uv); - half4 normalTex = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, GLOBAL_uv); - if (_FlipBumpY) - { - normalTex.y = 1 - normalTex.y; - } - half3 normal = UnpackScaleNormal(normalTex, _BumpScale); - half3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, GLOBAL_uv).rgb; - if (_EmissionChannel > 0) - { - emission.rgb = emission[_EmissionChannel].xxx; - } - int hasMasks = _MaskMap_TexelSize.z > 8; - half metal = masks[_MetalChannel]; - half smooth = masks[_SmoothChannel]; - if (_RoughnessMode) - { - smooth = 1 - smooth; - } - half detailMask = masks[_DetailMaskChannel]; - half occlusion = masks[_AOChannel]; - metal = remap(metal, 0, 1, _MetallicRemap.x, _MetallicRemap.y); - smooth = remap(smooth, 0, 1, _SmoothnessRemap.x, _SmoothnessRemap.y); - GLOBAL_maskMap = half4(metal, occlusion, detailMask, smooth); - o.Metallic = lerp(_Metallic, metal, hasMasks); - o.Smoothness = lerp(_Smoothness, smooth, hasMasks); - o.Occlusion = lerp(1, occlusion, _OcclusionStrength); - o.Normal = normal; - if (!_DetailAsTintMask) - { - o.Albedo = albedo.rgb * _Color.rgb; - } - else - { - o.Albedo = lerp(albedo, albedo.rgb * _Color.rgb, detailMask); - } - o.Alpha = albedo.a * _Color.a; - #if defined(_EMISSION) - o.Emission = emission * _EmissionColor; - #endif - } - - void DetailsFragment() - { - #if defined(DETAILS_OVERLAY) - half masks = 0; - #if defined(_MASKMAP_SAMPLED) - masks = GLOBAL_maskMap.b; - #else - masks = 1; - #endif - half mask = lerp(masks, 1, _DIgnoreMask); - half2 uv = d.uv0.xy; - switch(_DUVChannel) - { - case 1: uv = d.uv1.xy; break; - case 2: uv = d.uv2.xy; break; - case 3: uv = d.uv3.xy; break; - default: uv = d.uv0.xy; break; - } - uv = uv * _DDetailsMap_ST.xy + _DDetailsMap_ST.zw; - if (_DMappingSpace > 0) - { - uv = (_DMappingSpace - 1) ? half2(d.worldSpacePosition[_DPlanarAxisX], d.worldSpacePosition[_DPlanarAxisY]) : half2(d.localSpacePosition[_DPlanarAxisX], d.localSpacePosition[_DPlanarAxisY]); - uv = uv * _DDetailsMap_ST.xy + _DDetailsMap_ST.zw; - } - - half4 detailsMap = SAMPLE_TEXTURE2D(_DDetailsMap, sampler_DDetailsMap, uv); - - #if defined(DETAILS_MODE_PACKED) - half detailAlbedo = detailsMap.r * 2.0 - 1.0; - half detailSmooth = detailsMap.b * 2.0 - 1.0; - half3 detailNormal = 0; - if (_DNormalFlipY) - { - detailsMap.g = 1 - detailsMap.g; - } - detailNormal = UnpackNormalAG(detailsMap, _DNormalScale); - half detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); - #elif defined(DETAILS_MODE_SEPARATED) - half3 detailAlbedo = detailsMap.rgb * 2.0 - 1.0; - half detailSmooth = detailsMap.a * 2.0 - 1.0; - - half4 packedNormal = SAMPLE_TEXTURE2D(_DDetailsNormal, sampler_DDetailsNormal, uv); - if (_DNormalFlipY) - { - packedNormal.g = 1 - packedNormal.g; - } - half3 detailNormal = UnpackScaleNormal(packedNormal, _DNormalScale); - - half3 detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); - #endif - - half3 albedoOverlay = lerp(sqrt(o.Albedo), (detailAlbedo < 0.0) ? 0.0.xxx : 1.0.xxx, detailAlbedoSpeed * detailAlbedoSpeed); - albedoOverlay *= albedoOverlay; - o.Albedo = lerp(o.Albedo, saturate(albedoOverlay), mask); - - half detailSmoothSpeed = saturate(abs(detailSmooth) * _DSmoothScale); - half smoothOverlay = lerp(o.Smoothness, (detailSmooth < 0.0) ? 0.0 : 1.0, detailSmoothSpeed * detailSmoothSpeed); - o.Smoothness = lerp(o.Smoothness, saturate(smoothOverlay), mask); - - o.Normal = lerp(o.Normal, BlendNormals(o.Normal, detailNormal), mask); - #endif - } - - void ORLLighting() - { - #if !defined(UNITY_PASS_SHADOWCASTER) - half reflectance = 0.5; - half3 f0 = 0.16 * reflectance * reflectance * (1 - o.Metallic) + o.Albedo * o.Metallic; - half3 pixelLight = 0; - half3 indirectDiffuse = 1; - half3 indirectSpecular = 0; - half3 directSpecular = 0; - half occlusion = o.Occlusion; - half perceptualRoughness = 1 - o.Smoothness; - half3 tangentNormal = o.Normal; - o.Normal = normalize(mul(o.Normal, d.TBNMatrix)); - - #ifndef USING_DIRECTIONAL_LIGHT - fixed3 lightDir = normalize(UnityWorldSpaceLightDir(d.worldSpacePosition)); - #else - fixed3 lightDir = _WorldSpaceLightPos0.xyz; - #endif - - #if defined(GSAA) - perceptualRoughness = GSAA_Filament(o.Normal, perceptualRoughness, _GSAAVariance, _GSAAThreshold); - #endif - - UNITY_LIGHT_ATTENUATION(lightAttenuation, FragData, d.worldSpacePosition); - half3 lightColor = lightAttenuation * _LightColor0.rgb; - - half3 lightHalfVector = Unity_SafeNormalize(lightDir + d.worldSpaceViewDir); - half lightNoL = saturate(dot(o.Normal, lightDir)); - half lightLoH = saturate(dot(lightDir, lightHalfVector)); - - half NoV = abs(dot(o.Normal, d.worldSpaceViewDir)) + 1e-5; - pixelLight = lightNoL * lightColor * Fd_Burley(perceptualRoughness, NoV, lightNoL, lightLoH); - - // READ THE LIGHTMAP - #if defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) - half3 lightMap = 0; - half4 bakedColorTex = 0; - half2 lightmapUV = FragData.lightmapUv.xy; - - // UNITY LIGHTMAPPING - #if !defined(BAKERYLM_ENABLED) || !defined(BAKERY_ENABLED) - lightMap = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); - #endif - - // BAKERY RNM MODE (why do we even support it??) - #if defined(BAKERY_RNM) && defined(BAKERY_ENABLED) - half3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, lightmapUV, _RNM0_TexelSize)); - half3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, lightmapUV, _RNM0_TexelSize)); - half3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, lightmapUV, _RNM0_TexelSize)); - - lightMap = saturate(dot(rnmBasis0, tangentNormal)) * rnm0 + - saturate(dot(rnmBasis1, tangentNormal)) * rnm1 + - saturate(dot(rnmBasis2, tangentNormal)) * rnm2; - #endif - - // BAKERY SH MODE (these are also used for the specular) - #if defined(BAKERY_SH) && defined(BAKERY_ENABLED) - half3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, samplerunity_Lightmap, lightmapUV, _RNM0_TexelSize)); - - half3 nL1x = BakeryTex2D(_RNM0, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 nL1y = BakeryTex2D(_RNM1, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 nL1z = BakeryTex2D(_RNM2, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 L1x = nL1x * L0 * 2.0; - half3 L1y = nL1y * L0 * 2.0; - half3 L1z = nL1z * L0 * 2.0; - - // Non-Linear mode - #if defined(BAKERY_SHNONLINEAR) - half lumaL0 = dot(L0, half(1)); - half lumaL1x = dot(L1x, half(1)); - half lumaL1y = dot(L1y, half(1)); - half lumaL1z = dot(L1z, half(1)); - half lumaSH = shEvaluateDiffuseL1Geomerics_local(lumaL0, half3(lumaL1x, lumaL1y, lumaL1z), o.Normal); - - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - half regularLumaSH = dot(lightMap, 1.0); - lightMap *= lerp(1.0, lumaSH / regularLumaSH, saturate(regularLumaSH * 16.0)); - #else - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - #endif - - #endif - - #if defined(DIRLIGHTMAP_COMBINED) - half4 lightMapDirection = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lightmapUV); - #if !defined(BAKERY_MONOSH) - lightMap = DecodeDirectionalLightmap(lightMap, lightMapDirection, o.Normal); - #endif - #endif - - #if defined(BAKERY_MONOSH) && defined(BAKERY_ENABLED) && defined(DIRLIGHTMAP_COMBINED) - half3 L0 = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); - half3 nL1 = lightMapDirection.xyz * 2.0 - 1.0; - half3 L1x = nL1.x * L0 * 2.0; - half3 L1y = nL1.y * L0 * 2.0; - half3 L1z = nL1.z * L0 * 2.0; - - #if defined(BAKERY_SHNONLINEAR) - half lumaL0 = dot(L0, 1); - half lumaL1x = dot(L1x, 1); - half lumaL1y = dot(L1y, 1); - half lumaL1z = dot(L1z, 1); - half lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, half3(lumaL1x, lumaL1y, lumaL1z), o.Normal); - - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - half regularLumaSH = dot(lightMap, 1); - lightMap *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - #else - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - #endif - - lightMap = max(lightMap, 0.0); - #endif - - #if defined(DYNAMICLIGHTMAP_ON) && !defined(UNITY_PBS_USE_BRDF2) - half3 realtimeLightMap = getRealtimeLightmap(FragData.lightmapUv.zw, o.Normal); - lightMap += realtimeLightMap; - #endif - - #if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) - pixelLight = 0; - lightMap = SubtractMainLightWithRealtimeAttenuationFrowmLightmap(lightMap, lightAttenuation, bakedColorTex, o.Normal); - #endif - indirectDiffuse = lightMap; - #else - #if UNITY_LIGHT_PROBE_PROXY_VOLUME - UNITY_BRANCH - if (unity_ProbeVolumeParams.x == 1) - { - indirectDiffuse = SHEvalLinearL0L1_SampleProbeVolume(half4(o.Normal, 1), FragData.worldPos); - } - else - { - #endif - indirectDiffuse = max(0, ShadeSH9(half4(o.Normal, 1))); - #if UNITY_LIGHT_PROBE_PROXY_VOLUME - } - #endif - #endif - - #if defined(LIGHTMAP_SHADOW_MIXING) && defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) && defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) - pixelLight *= UnityComputeForwardShadows(FragData.lightmapUv.xy, d.worldSpacePosition, d.screenPos); - #endif - - half3 dfguv = half3(NoV, perceptualRoughness, 0); - half2 dfg = SAMPLE_TEXTURE2D(_DFG, sampler_DFG, dfguv).xy; - half3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0); - - half rough = perceptualRoughness * perceptualRoughness; - half clampedRoughness = max(rough, 0.002); - - #if !defined(SPECULAR_HIGHLIGHTS_OFF) && defined(USING_LIGHT_MULTI_COMPILE) - half NoH = saturate(dot(o.Normal, lightHalfVector)); - half3 F = F_Schlick(lightLoH, f0); - half D = D_GGX(NoH, clampedRoughness); - half V = V_SmithGGXCorrelated(NoV, lightNoL, clampedRoughness); - - F *= energyCompensation; - - directSpecular = max(0, D * V * F) * pixelLight * UNITY_PI; - #endif - - // BAKED SPECULAR - #if defined(BAKED_SPECULAR) && !defined(BAKERYLM_ENABLED) && !defined(UNITY_PASS_FORWARDADD) - { - half3 bakedDominantDirection = 1; - half3 bakedSpecularColor = 0; - - // only do it if we have a directional lightmap - #if defined(DIRLIGHTMAP_COMBINED) && defined(LIGHTMAP_ON) - bakedDominantDirection = (lightMapDirection.xyz) * 2 - 1; - half directionality = max(0.001, length(bakedDominantDirection)); - bakedDominantDirection /= directionality; - bakedSpecularColor = indirectDiffuse; - #endif - - // if we do not have lightmap - derive the specular from probes - //#ifndef LIGHTMAP_ON - //bakedSpecularColor = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); - //bakedDominantDirection = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz; - // #endif - - bakedDominantDirection = normalize(bakedDominantDirection); - directSpecular += GetSpecularHighlights(o.Normal, bakedSpecularColor, bakedDominantDirection, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); - } - #endif - - half3 fresnel = F_Schlick(NoV, f0); - - // BAKERY DIRECT SPECULAR - #if defined(BAKERY_LMSPEC) && defined(BAKERY_ENABLED) && !defined(UNITY_PASS_FORWARDADD) - #if defined(BAKERY_RNM) - { - half3 viewDirTangent = -normalize(d.tangentSpaceViewDir); - half3 dominantDirTangent = rnmBasis0 * dot(rnm0, lumaConv) + - rnmBasis1 * dot(rnm1, lumaConv) + - rnmBasis2 * dot(rnm2, lumaConv); - - half3 dominantDirTangentNormalized = normalize(dominantDirTangent); - half3 specColor = saturate(dot(rnmBasis0, dominantDirTangentNormalized)) * rnm0 + - saturate(dot(rnmBasis1, dominantDirTangentNormalized)) * rnm1 + - saturate(dot(rnmBasis2, dominantDirTangentNormalized)) * rnm2; - half3 halfDir = Unity_SafeNormalize(dominantDirTangentNormalized - viewDirTangent); - half NoH = saturate(dot(tangentNormal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - directSpecular += spec * specColor * fresnel; - } - #endif - - #if defined(BAKERY_SH) - { - half3 dominantDir = half3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(L1z, lumaConv)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) + d.worldSpaceViewDir); - half NoH = saturate(dot(o.Normal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - dominantDir = normalize(dominantDir); - directSpecular += max(spec * sh, 0.0) * fresnel; - } - #endif - - #if defined(BAKERY_MONOSH) - { - half3 dominantDir = nL1; - half focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - d.worldSpaceViewDir); - half NoH = saturate(dot(o.Normal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - dominantDir = normalize(dominantDir); - directSpecular += max(spec * sh, 0.0) * fresnel; - } - #endif - #endif - - // REFLECTIONS - #if !defined(UNITY_PASS_FORWARDADD) - half3 reflDir = reflect(-d.worldSpaceViewDir, o.Normal); - reflDir = lerp(reflDir, o.Normal, rough * rough); - - Unity_GlossyEnvironmentData envData; - envData.roughness = perceptualRoughness; - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - - half3 probe0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData); - indirectSpecular = probe0; - - #if defined(UNITY_SPECCUBE_BLENDING) - UNITY_BRANCH - if (unity_SpecCube0_BoxMin.w < 0.99999) - { - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half3 probe1 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0), unity_SpecCube1_HDR, envData); - indirectSpecular = lerp(probe1, probe0, unity_SpecCube0_BoxMin.w); - } - #endif - - half horizon = min(1 + dot(reflDir, o.Normal), 1); - dfg.x *= saturate(pow(dot(indirectDiffuse, 1), _SpecOcclusion)); - indirectSpecular = indirectSpecular * horizon * horizon * energyCompensation * EnvBRDFMultiscatter(dfg, f0); - - #if defined(_MASKMAP_SAMPLED) - indirectSpecular *= computeSpecularAO(NoV, o.Occlusion, perceptualRoughness * perceptualRoughness); - #endif - #endif - - #if defined(_INTEGRATE_CUSTOMGI) && !defined(UNITY_PASS_FORWARDADD) - IntegrateCustomGI(d, o, indirectSpecular, indirectDiffuse); - #endif - - // FINAL COLOR - FinalColor = half4(o.Albedo.rgb * (1 - o.Metallic) * (indirectDiffuse * occlusion + (pixelLight)) + indirectSpecular + directSpecular, o.Alpha); - - FinalColor.rgb += o.Emission; - #endif - } - - // ForwardAdd Vertex - TessVertex Vertex(VertexData v) - { - UNITY_SETUP_INSTANCE_ID(v); - TessVertex o = (TessVertex) 0; - UNITY_TRANSFER_INSTANCE_ID(v, o); - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - - o.vertex = v.vertex; - o.normal = v.normal; - o.tangent = v.tangent; - o.color = v.color; - o.uv0 = v.uv0; - o.uv1 = v.uv1; - o.uv2 = v.uv2; - o.uv3 = v.uv3; - - return o; - } - - // ForwardAdd Hull - [maxtessfactor(MAX_TESSELLATION_FACTORS)] - [UNITY_domain("tri")] - [UNITY_outputcontrolpoints(3)] - [UNITY_outputtopology("triangle_cw")] - [UNITY_partitioning("integer")] - [UNITY_patchconstantfunc("TessFactorsFunction")] - TessVertex Hull(InputPatch patch, uint id : SV_OutputControlPointID) - { - return patch[id]; - } - - float4 GetTessFactors(InputPatch patch) - { - #if defined(TESS_MODE_DISTANCEBASED) - float4 tessFactors = UnityDistanceBasedTess( - patch[0].vertex, - patch[1].vertex, - patch[2].vertex, - _TessMinDist, - _TessMaxDist, - _TessFactor - ); - return tessFactors; - #elif defined(TESS_MODE_EDGELENGTH) - float4 tessFactors = UnityEdgeLengthBasedTessCull( - patch[0].vertex, - patch[1].vertex, - patch[2].vertex, - _TessEdgeLength, - _TessMaxDisplacement - ); - return tessFactors; - #endif - - return 1..xxxx; - } - - // ForwardAdd TessFactor - TessellationFactors TessFactorsFunction(InputPatch patch) - { - TessellationFactors f; - float4 TessFactorsOutput = 0; - #if defined(TESS_FACTORS_FUNC_DEFINED) - TessFactorsOutput = GetTessFactors(patch); - #else - TessFactorsOutput = 1..xxxx; - #endif - f.edge[0] = TessFactorsOutput.x; - f.edge[1] = TessFactorsOutput.y; - f.edge[2] = TessFactorsOutput.z; - f.inside = TessFactorsOutput.w; - return f; - } - - // ForwardAdd Domain - [UNITY_domain("tri")] - FragmentData Domain(TessellationFactors factors, OutputPatch patch, float3 baryCoords : SV_DomainLocation) - { - VertexData v = (VertexData) 0; - UNITY_TRANSFER_INSTANCE_ID(patch[0], v); - v.vertex = patch[0].vertex * baryCoords.x + patch[1].vertex * baryCoords.y + patch[2].vertex * baryCoords.z; - - #if defined(PHONG) - float3 pp[3]; - for (int index = 0; index < 3; ++index) - { - pp[index] = v.vertex.xyz - patch[index].normal * (dot(v.vertex.xyz, patch[index].normal) - dot(patch[index].vertex.xyz, patch[index].normal)); - } - v.vertex.xyz = 0.5 * (pp[0]*baryCoords.x + pp[1]*baryCoords.y + pp[2]*baryCoords.z) + (0.5) * v.vertex.xyz; - #endif - - v.normal = patch[0].normal * baryCoords.x + patch[1].normal * baryCoords.y + patch[2].normal * baryCoords.z; - v.tangent = patch[0].tangent * baryCoords.x + patch[1].tangent * baryCoords.y + patch[2].tangent * baryCoords.z; - v.color = patch[0].color * baryCoords.x + patch[1].color * baryCoords.y + patch[2].color * baryCoords.z; - v.uv0 = patch[0].uv0 * baryCoords.x + patch[1].uv0 * baryCoords.y + patch[2].uv0 * baryCoords.z; - v.uv1 = patch[0].uv1 * baryCoords.x + patch[1].uv1 * baryCoords.y + patch[2].uv1 * baryCoords.z; - v.uv2 = patch[0].uv2 * baryCoords.x + patch[1].uv2 * baryCoords.y + patch[2].uv2 * baryCoords.z; - v.uv3 = patch[0].uv3 * baryCoords.x + patch[1].uv3 * baryCoords.y + patch[2].uv3 * baryCoords.z; - - FragmentData i; - UNITY_INITIALIZE_OUTPUT(FragmentData, i); - UNITY_TRANSFER_INSTANCE_ID(patch[0], i); - - vD = v; - FragData = i; - VHVertex(); - - i = FragData; - v = vD; - #if defined(UNITY_PASS_SHADOWCASTER) - i.worldNormal = UnityObjectToWorldNormal(v.normal); - i.worldPos = mul(unity_ObjectToWorld, v.vertex); - i.uv0 = v.uv0; - i.uv1 = v.uv1; - i.uv2 = v.uv2; - i.uv3 = v.uv3; - i.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz); - i.worldTangent.w = v.tangent.w * unity_WorldTransformParams.w; - #else - #if defined(UNITY_PASS_META) - i.pos = UnityMetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST); - #else - i.pos = UnityObjectToClipPos(v.vertex); - #endif - i.normal = v.normal; - i.worldNormal = UnityObjectToWorldNormal(v.normal); - i.worldPos = mul(unity_ObjectToWorld, v.vertex); - i.uv0 = v.uv0; - i.uv1 = v.uv1; - i.uv2 = v.uv2; - i.uv3 = v.uv3; - i.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz); - i.worldTangent.w = v.tangent.w * unity_WorldTransformParams.w; - i.vertexColor = v.color; - - #if defined(EDITOR_VISUALIZATION) - i.vizUV = 0; - i.lightCoord = 0; - if (unity_VisualizationMode == EDITORVIZ_TEXTURE) - i.vizUV = UnityMetaVizUV(unity_EditorViz_UVIndex, v.uv0.xy, v.uv1.xy, v.uv2.xy, unity_EditorViz_Texture_ST); - else if (unity_VisualizationMode == EDITORVIZ_SHOWLIGHTMASK) - { - i.vizUV = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; - i.lightCoord = mul(unity_EditorViz_WorldToLight, mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1))); - } - #endif - - #if defined(NEED_SCREEN_POS) - i.screenPos = ComputeScreenPos(i.pos); - #endif - - #if !defined(UNITY_PASS_META) - #if defined(LIGHTMAP_ON) - i.lightmapUv.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; - #endif - #if defined(DYNAMICLIGHTMAP_ON) - i.lightmapUv.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; - #endif - - UNITY_TRANSFER_LIGHTING(i, v.uv1.xy); - - #if !defined(UNITY_PASS_FORWARDADD) - // unity does some funky stuff for different platforms with these macros - #ifdef FOG_COMBINED_WITH_TSPACE - UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(i, i.pos); - #elif defined(FOG_COMBINED_WITH_WORLD_POS) - UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(i, i.pos); - #else - UNITY_TRANSFER_FOG(i, i.pos); - #endif - #else - UNITY_TRANSFER_FOG(i, i.pos); - #endif - #endif - #endif - - return i; - } - - // ForwardAdd Fragment - half4 Fragment(FragmentData i) : SV_TARGET - { - UNITY_SETUP_INSTANCE_ID(i); - #ifdef FOG_COMBINED_WITH_TSPACE - UNITY_EXTRACT_FOG_FROM_TSPACE(i); - #elif defined(FOG_COMBINED_WITH_WORLD_POS) - UNITY_EXTRACT_FOG_FROM_WORLD_POS(i); - #else - UNITY_EXTRACT_FOG(i); - #endif - - FragData = i; - o = (SurfaceData) 0; - d = CreateMeshData(i); - o.Albedo = half3(0.5, 0.5, 0.5); - o.Normal = half3(0, 0, 1); - o.Smoothness = 0.5; - o.Occlusion = 1; - o.Alpha = 1; - FinalColor = half4(o.Albedo, o.Alpha); - - ParallaxFragment(); - BaseFragmentFunction(); - DetailsFragment(); - - ORLLighting(); - - UNITY_APPLY_FOG(_unity_fogCoord, FinalColor); - - return FinalColor; - } - - ENDCG - // ForwardAdd Pass End - - } - - Pass - { - Name "META" - Tags { "LightMode" = "Meta" } - Cull Off - - // Meta Pass Start - CGPROGRAM - #pragma target 4.6 - #pragma require tesshw - #pragma multi_compile_instancing - #pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2 - #pragma shader_feature EDITOR_VISUALISATION - #pragma vertex Vertex - #pragma fragment Fragment - #pragma hull Hull - #pragma domain Domain - - #define UNITY_INSTANCED_LOD_FADE - #define UNITY_INSTANCED_SH - #define UNITY_INSTANCED_LIGHTMAPSTS - - #ifndef UNITY_PASS_META - #define UNITY_PASS_META - #endif - - #if defined(SHADER_API_XBOXONE) || defined(SHADER_API_PSSL) - #define MAX_TESSELLATION_FACTORS 15.0 - #else - #define MAX_TESSELLATION_FACTORS 64.0 - #endif - - #include "UnityStandardUtils.cginc" - #include "Lighting.cginc" - #include "AutoLight.cginc" - #include "Tessellation.cginc" - #include "UnityPBSLighting.cginc" - #include "UnityMetaPass.cginc" - - #define FLT_EPSILON 1.192092896e-07 - - #define _MASKMAP_SAMPLED - - #define _SET_GLOBAL_UVS - - #if !defined(DETAILS_MODE_PACKED) && !defined(DETAILS_MODE_SEPARATED) - #define DETAILS_MODE_PACKED - #endif - - #define TESS_FACTORS_FUNC_DEFINED - - #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) - #define PLAT_QUEST - #else - #ifdef PLAT_QUEST - #undef PLAT_QUEST - #endif - #endif - - #if !defined(LIGHTMAP_ON) || !defined(UNITY_PASS_FORWARDBASE) - #undef BAKERY_SH - #undef BAKERY_RNM - #endif - - #ifdef LIGHTMAP_ON - #undef BAKERY_VOLUME - #endif - - #ifdef LIGHTMAP_ON - #if defined(BAKERY_RNM) || defined(BAKERY_SH) || defined(BAKERY_VERTEXLM) - #define BAKERYLM_ENABLED - #undef DIRLIGHTMAP_COMBINED - #endif - #endif - - #if defined(BAKERY_SH) || defined(BAKERY_RNM) || defined(BAKERY_VOLUME) - #ifdef BAKED_SPECULAR - #define _BAKERY_LMSPEC - #define BAKERY_LMSPEC - #endif - #endif - - #define NEED_SCREEN_POS - - struct VertexData - { - float4 vertex : POSITION; - float3 normal : NORMAL; - float4 tangent : TANGENT; - float4 color : COLOR; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - UNITY_VERTEX_INPUT_INSTANCE_ID - }; - - struct FragmentData - { - #if defined(UNITY_PASS_SHADOWCASTER) - V2F_SHADOW_CASTER; - float2 uv0 : TEXCOORD1; - float2 uv1 : TEXCOORD2; - float2 uv2 : TEXCOORD3; - float2 uv3 : TEXCOORD4; - float3 worldPos : TEXCOORD5; - float3 worldNormal : TEXCOORD6; - float4 worldTangent : TEXCOORD7; - #else - float4 pos : SV_POSITION; - float3 normal : NORMAL; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - float3 worldPos : TEXCOORD4; - float3 worldNormal : TEXCOORD5; - float4 worldTangent : TEXCOORD6; - float4 lightmapUv : TEXCOORD7; - float4 vertexColor : TEXCOORD8; - - #if !defined(UNITY_PASS_META) - UNITY_LIGHTING_COORDS(9, 10) - UNITY_FOG_COORDS(11) - #endif - #endif - - #if defined(EDITOR_VISUALIZATION) - float2 vizUV : TEXCOORD9; - float4 lightCoord : TEXCOORD10; - #endif - - #if defined(NEED_SCREEN_POS) - float4 screenPos: SCREENPOS; - #endif - - #if defined(EXTRA_V2F_0) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F0 : TEXCOORD8; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F0 : TEXCOORD12; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F0 : TEXCOORD11; - #else - float4 extraV2F0 : TEXCOORD9; - #endif - #endif - #endif - #endif - #if defined(EXTRA_V2F_1) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F1 : TEXCOORD9; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F1 : TEXCOORD13; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F1 : TEXCOORD14; - #else - float4 extraV2F1 : TEXCOORD15; - #endif - #endif - #endif - #endif - #if defined(EXTRA_V2F_2) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F2 : TEXCOORD10; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F2 : TEXCOORD14; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F2 : TEXCOORD15 - #else - float4 extraV2F2 : TEXCOORD16; - #endif - #endif - #endif - #endif - - UNITY_VERTEX_INPUT_INSTANCE_ID - UNITY_VERTEX_OUTPUT_STEREO - }; - - struct MeshData - { - half2 uv0; - half2 uv1; - half2 uv2; - half2 uv3; - half4 vertexColor; - half3 normal; - half3 worldNormal; - half3 localSpacePosition; - half3 worldSpacePosition; - half3 worldSpaceViewDir; - half3 tangentSpaceViewDir; - float3x3 TBNMatrix; - float4 extraV2F0; - float4 extraV2F1; - float4 extraV2F2; - float4 screenPos; - }; - - MeshData CreateMeshData(FragmentData i) - { - MeshData m = (MeshData) 0; - m.uv0 = i.uv0; - m.uv1 = i.uv1; - m.uv2 = i.uv2; - m.uv3 = i.uv3; - m.worldNormal = normalize(i.worldNormal); - m.localSpacePosition = mul(unity_WorldToObject, float4(i.worldPos, 1)).xyz; - m.worldSpacePosition = i.worldPos; - m.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos); - - #if !defined(UNITY_PASS_SHADOWCASTER) - m.vertexColor = i.vertexColor; - m.normal = i.normal; - float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * - 1; - m.TBNMatrix = float3x3(normalize(i.worldTangent.xyz), bitangent, m.worldNormal); - m.tangentSpaceViewDir = mul(m.TBNMatrix, m.worldSpaceViewDir); - #endif - - #if defined(EXTRA_V2F_0) - m.extraV2F0 = i.extraV2F0; - #endif - #if defined(EXTRA_V2F_1) - m.extraV2F1 = i.extraV2F1; - #endif - #if defined(EXTRA_V2F_2) - m.extraV2F2 = i.extraV2F2; - #endif - #if defined(NEED_SCREEN_POS) - m.screenPos = i.screenPos; - #endif - - return m; - } - - struct SurfaceData - { - half3 Albedo; - half3 Emission; - half Metallic; - half Smoothness; - half Occlusion; - half3 Normal; - half Alpha; - }; - - struct TessellationFactors - { - float edge[3] : SV_TessFactor; - float inside : SV_InsideTessFactor; - }; - - struct TessVertex - { - float4 vertex : INTERNALTESSPOS; - float3 normal : NORMAL; - float4 tangent : TANGENT; - float4 color : COLOR; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - UNITY_VERTEX_INPUT_INSTANCE_ID - UNITY_VERTEX_OUTPUT_STEREO - }; - - FragmentData FragData; - SurfaceData o; - MeshData d; - VertexData vD; - float4 FinalColor; - - half invLerp(half a, half b, half v) - { - return (v - a) / (b - a); - } - - half getBakedNoise(Texture2D noiseTex, SamplerState noiseTexSampler, half3 p) - { - half3 i = floor(p); p -= i; p *= p * (3. - 2. * p); - half2 uv = (p.xy + i.xy + half2(37, 17) * i.z + .5) / 256.; - uv.y *= -1; - p.xy = noiseTex.SampleLevel(noiseTexSampler, uv, 0).yx; - return lerp(p.x, p.y, p.z); - } - - half3 TransformObjectToWorld(half3 pos) - { - return mul(unity_ObjectToWorld, half4(pos, 1)).xyz; - }; - - // mostly taken from the Amplify shader reference - half2 POM(Texture2D heightMap, SamplerState heightSampler, half2 uvs, half2 dx, half2 dy, half3 normalWorld, half3 viewWorld, half3 viewDirTan, int minSamples, int maxSamples, half parallax, half refPlane, half2 tilling, half2 curv, int index, inout half finalHeight) - { - half3 result = 0; - int stepIndex = 0; - int numSteps = (int)lerp((half)maxSamples, (half)minSamples, saturate(dot(normalWorld, viewWorld))); - half layerHeight = 1.0 / numSteps; - half2 plane = parallax * (viewDirTan.xy / viewDirTan.z); - uvs.xy += refPlane * plane; - half2 deltaTex = -plane * layerHeight; - half2 prevTexOffset = 0; - half prevRayZ = 1.0f; - half prevHeight = 0.0f; - half2 currTexOffset = deltaTex; - half currRayZ = 1.0f - layerHeight; - half currHeight = 0.0f; - half intersection = 0; - half2 finalTexOffset = 0; - while (stepIndex < numSteps + 1) - { - currHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + currTexOffset, dx, dy).r; - if (currHeight > currRayZ) - { - stepIndex = numSteps + 1; - } - else - { - stepIndex++; - prevTexOffset = currTexOffset; - prevRayZ = currRayZ; - prevHeight = currHeight; - currTexOffset += deltaTex; - currRayZ -= layerHeight; - } - } - int sectionSteps = 2; - int sectionIndex = 0; - half newZ = 0; - half newHeight = 0; - while (sectionIndex < sectionSteps) - { - intersection = (prevHeight - prevRayZ) / (prevHeight - currHeight + currRayZ - prevRayZ); - finalTexOffset = prevTexOffset +intersection * deltaTex; - newZ = prevRayZ - intersection * layerHeight; - newHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + finalTexOffset, dx, dy).r; - if (newHeight > newZ) - { - currTexOffset = finalTexOffset; - currHeight = newHeight; - currRayZ = newZ; - deltaTex = intersection * deltaTex; - layerHeight = intersection * layerHeight; - } - else - { - prevTexOffset = finalTexOffset; - prevHeight = newHeight; - prevRayZ = newZ; - deltaTex = (1 - intersection) * deltaTex; - layerHeight = (1 - intersection) * layerHeight; - } - sectionIndex++; - } - finalHeight = newHeight; - return uvs.xy + finalTexOffset; - } - - half remap(half s, half a1, half a2, half b1, half b2) - { - return b1 + (s - a1) * (b2 - b1) / (a2 - a1); - } - - half3 ApplyLut2D(Texture2D LUT2D, SamplerState lutSampler, half3 uvw) - { - half3 scaleOffset = half3(1.0 / 1024.0, 1.0 / 32.0, 31.0); - // Strip format where `height = sqrt(width)` - uvw.z *= scaleOffset.z; - half shift = floor(uvw.z); - uvw.xy = uvw.xy * scaleOffset.z * scaleOffset.xy + scaleOffset.xy * 0.5; - uvw.x += shift * scaleOffset.y; - uvw.xyz = lerp( - SAMPLE_TEXTURE2D(LUT2D, lutSampler, uvw.xy).rgb, - SAMPLE_TEXTURE2D(LUT2D, lutSampler, uvw.xy + half2(scaleOffset.y, 0.0)).rgb, - uvw.z - shift - ); - return uvw; - } - - half3 AdjustContrast(half3 color, half contrast) - { - color = saturate(lerp(half3(0.5, 0.5, 0.5), color, contrast)); - return color; - } - - half3 AdjustSaturation(half3 color, half saturation) - { - half3 intensity = dot(color.rgb, half3(0.299, 0.587, 0.114)); - color = lerp(intensity, color.rgb, saturation); - return color; - } - - half3 AdjustBrightness(half3 color, half brightness) - { - color += brightness; - return color; - } - - struct ParamsLogC - { - half cut; - half a, b, c, d, e, f; - }; - - static const ParamsLogC LogC = { - 0.011361, // cut - 5.555556, // a - 0.047996, // b - 0.244161, // c - 0.386036, // d - 5.301883, // e - 0.092819 // f - - }; - - half LinearToLogC_Precise(half x) - { - half o; - if (x > LogC.cut) - o = LogC.c * log10(LogC.a * x + LogC.b) + LogC.d; - else - o = LogC.e * x + LogC.f; - return o; - } - - half PositivePow(half base, half power) - { - return pow(max(abs(base), half(FLT_EPSILON)), power); - } - - half3 LinearToLogC(half3 x) - { - return LogC.c * log10(LogC.a * x + LogC.b) + LogC.d; - } - - half3 LinerToSRGB(half3 c) - { - return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878); - } - - half3 SRGBToLiner(half3 c) - { - return max(1.055 * PositivePow(c, 0.416666667) - 0.055, 0.0); - } - - half3 LogCToLinear(half3 c) - { - return (pow(10.0, (c - LogC.d) / LogC.c) - LogC.b) / LogC.a; - } - - // Specular stuff taken from https://github.com/z3y/shaders/ - float pow5(float x) - { - float x2 = x * x; - return x2 * x2 * x; - } - - float sq(float x) - { - return x * x; - } - - struct Gradient - { - int type; - int colorsLength; - int alphasLength; - half4 colors[8]; - half2 alphas[8]; - }; - - Gradient NewGradient(int type, int colorsLength, int alphasLength, - half4 colors0, half4 colors1, half4 colors2, half4 colors3, half4 colors4, half4 colors5, half4 colors6, half4 colors7, - half2 alphas0, half2 alphas1, half2 alphas2, half2 alphas3, half2 alphas4, half2 alphas5, half2 alphas6, half2 alphas7) - { - Gradient g; - g.type = type; - g.colorsLength = colorsLength; - g.alphasLength = alphasLength; - g.colors[ 0 ] = colors0; - g.colors[ 1 ] = colors1; - g.colors[ 2 ] = colors2; - g.colors[ 3 ] = colors3; - g.colors[ 4 ] = colors4; - g.colors[ 5 ] = colors5; - g.colors[ 6 ] = colors6; - g.colors[ 7 ] = colors7; - g.alphas[ 0 ] = alphas0; - g.alphas[ 1 ] = alphas1; - g.alphas[ 2 ] = alphas2; - g.alphas[ 3 ] = alphas3; - g.alphas[ 4 ] = alphas4; - g.alphas[ 5 ] = alphas5; - g.alphas[ 6 ] = alphas6; - g.alphas[ 7 ] = alphas7; - return g; - } - - half4 SampleGradient(Gradient gradient, half time) - { - half3 color = gradient.colors[0].rgb; - UNITY_UNROLL - for (int c = 1; c < 8; c++) - { - half colorPos = saturate((time - gradient.colors[c - 1].w) / (0.00001 + (gradient.colors[c].w - gradient.colors[c - 1].w)) * step(c, (half)gradient.colorsLength - 1)); - color = lerp(color, gradient.colors[c].rgb, lerp(colorPos, step(0.01, colorPos), gradient.type)); - } - #ifndef UNITY_COLORSPACE_GAMMA - color = half3(GammaToLinearSpaceExact(color.r), GammaToLinearSpaceExact(color.g), GammaToLinearSpaceExact(color.b)); - #endif - half alpha = gradient.alphas[0].x; - UNITY_UNROLL - for (int a = 1; a < 8; a++) - { - half alphaPos = saturate((time - gradient.alphas[a - 1].y) / (0.00001 + (gradient.alphas[a].y - gradient.alphas[a - 1].y)) * step(a, (half)gradient.alphasLength - 1)); - alpha = lerp(alpha, gradient.alphas[a].x, lerp(alphaPos, step(0.01, alphaPos), gradient.type)); - } - return half4(color, alpha); - } - - float3 RotateAroundAxis(float3 center, float3 original, float3 u, float angle) - { - original -= center; - float C = cos(angle); - float S = sin(angle); - float t = 1 - C; - float m00 = t * u.x * u.x + C; - float m01 = t * u.x * u.y - S * u.z; - float m02 = t * u.x * u.z + S * u.y; - float m10 = t * u.x * u.y + S * u.z; - float m11 = t * u.y * u.y + C; - float m12 = t * u.y * u.z - S * u.x; - float m20 = t * u.x * u.z - S * u.y; - float m21 = t * u.y * u.z + S * u.x; - float m22 = t * u.z * u.z + C; - float3x3 finalMatrix = float3x3(m00, m01, m02, m10, m11, m12, m20, m21, m22); - return mul(finalMatrix, original) + center; - } - - half3 UnpackNormalAG(half4 packedNormal, half scale = 1.0) - { - half3 normal; - normal.xy = packedNormal.ag * 2.0 - 1.0; - normal.z = max(1.0e-16, sqrt(1.0 - saturate(dot(normal.xy, normal.xy)))); - - normal.xy *= scale; - return normal; - } - - half D_GGX(half NoH, half roughness) - { - half a = NoH * roughness; - half k = roughness / (1.0 - NoH * NoH + a * a); - return k * k * (1.0 / UNITY_PI); - } - - half D_GGX_Anisotropic(half NoH, const half3 h, const half3 t, const half3 b, half at, half ab) - { - half ToH = dot(t, h); - half BoH = dot(b, h); - half a2 = at * ab; - half3 v = half3(ab * ToH, at * BoH, a2 * NoH); - half v2 = dot(v, v); - half w2 = a2 / v2; - return a2 * w2 * w2 * (1.0 / UNITY_PI); - } - - half V_SmithGGXCorrelated(half NoV, half NoL, half roughness) - { - half a2 = roughness * roughness; - half GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); - half GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); - return 0.5 / (GGXV + GGXL); - } - - half3 F_Schlick(half u, half3 f0) - { - return f0 + (1.0 - f0) * pow(1.0 - u, 5.0); - } - - half3 F_Schlick(half3 f0, half f90, half VoH) - { - // Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering" - return f0 + (f90 - f0) * pow(1.0 - VoH, 5); - } - - half3 fresnel(half3 f0, half LoH) - { - half f90 = saturate(dot(f0, half(50.0 / 3).xxx)); - return F_Schlick(f0, f90, LoH); - } - - half Fd_Burley(half perceptualRoughness, half NoV, half NoL, half LoH) - { - // Burley 2012, "Physically-Based Shading at Disney" - half f90 = 0.5 + 2.0 * perceptualRoughness * LoH * LoH; - half lightScatter = F_Schlick(1.0, f90, NoL); - half viewScatter = F_Schlick(1.0, f90, NoV); - return lightScatter * viewScatter; - } - - half3 getBoxProjection(half3 direction, half3 position, half4 cubemapPosition, half3 boxMin, half3 boxMax) - { - #if defined(UNITY_SPECCUBE_BOX_PROJECTION) && !defined(UNITY_PBS_USE_BRDF2) || defined(FORCE_BOX_PROJECTION) - if (cubemapPosition.w > 0) - { - half3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction; - half scalar = min(min(factors.x, factors.y), factors.z); - direction = direction * scalar + (position - cubemapPosition.xyz); - } - #endif - - return direction; - } - - half3 getEnvReflection(half3 worldSpaceViewDir, half3 worldSpacePosition, half3 normal, half smoothness, int mip) - { - half3 env = 0; - half3 reflDir = reflect(worldSpaceViewDir, normal); - half perceptualRoughness = 1 - smoothness; - half rough = perceptualRoughness * perceptualRoughness; - reflDir = lerp(reflDir, normal, rough * rough); - - half3 reflectionUV1 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, mip); - half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR); - - half3 indirectSpecular; - half interpolator = unity_SpecCube0_BoxMin.w; - - UNITY_BRANCH - if (interpolator < 0.99999) - { - half3 reflectionUV2 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, mip); - half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR); - indirectSpecular = lerp(probe1sample, probe0sample, interpolator); - } - else - { - indirectSpecular = probe0sample; - } - - env = indirectSpecular; - return env; - } - - half3 EnvBRDFMultiscatter(half2 dfg, half3 f0) - { - return lerp(dfg.xxx, dfg.yyy, f0); - } - - half3 EnvBRDFApprox(half perceptualRoughness, half NoV, half3 f0) - { - half g = 1 - perceptualRoughness; - //https://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - half4 t = half4(1 / 0.96, 0.475, (0.0275 - 0.25 * 0.04) / 0.96, 0.25); - t *= half4(g, g, g, g); - t += half4(0, 0, (0.015 - 0.75 * 0.04) / 0.96, 0.75); - half a0 = t.x * min(t.y, exp2(-9.28 * NoV)) + t.z; - half a1 = t.w; - return saturate(lerp(a0, a1, f0)); - } - - half GSAA_Filament(half3 worldNormal, half perceptualRoughness, half inputVariance, half threshold) - { - // Kaplanyan 2016, "Stable specular highlights" - // Tokuyoshi 2017, "Error Reduction and Simplification for Shading Anti-Aliasing" - // Tokuyoshi and Kaplanyan 2019, "Improved Geometric Specular Antialiasing" - - // This implementation is meant for deferred rendering in the original paper but - // we use it in forward rendering as well (as discussed in Tokuyoshi and Kaplanyan - // 2019). The main reason is that the forward version requires an expensive transform - // of the half vector by the tangent frame for every light. This is therefore an - // approximation but it works well enough for our needs and provides an improvement - // over our original implementation based on Vlachos 2015, "Advanced VR Rendering". - - half3 du = ddx(worldNormal); - half3 dv = ddy(worldNormal); - - half variance = inputVariance * (dot(du, du) + dot(dv, dv)); - - half roughness = perceptualRoughness * perceptualRoughness; - half kernelRoughness = min(2.0 * variance, threshold); - half squareRoughness = saturate(roughness * roughness + kernelRoughness); - - return sqrt(sqrt(squareRoughness)); - } - - // w0, w1, w2, and w3 are the four cubic B-spline basis functions - half w0(half a) - { - // return (1.0f/6.0f)*(-a*a*a + 3.0f*a*a - 3.0f*a + 1.0f); - return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f); // optimized - - } - - half w1(half a) - { - // return (1.0f/6.0f)*(3.0f*a*a*a - 6.0f*a*a + 4.0f); - return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f); - } - - half w2(half a) - { - // return (1.0f/6.0f)*(-3.0f*a*a*a + 3.0f*a*a + 3.0f*a + 1.0f); - return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f); - } - - half w3(half a) - { - return (1.0f / 6.0f) * (a * a * a); - } - - // g0 and g1 are the two amplitude functions - half g0(half a) - { - return w0(a) + w1(a); - } - - half g1(half a) - { - return w2(a) + w3(a); - } - - // h0 and h1 are the two offset functions - half h0(half a) - { - // note +0.5 offset to compensate for CUDA linear filtering convention - return -1.0f + w1(a) / (w0(a) + w1(a)) + 0.5f; - } - - half h1(half a) - { - return 1.0f + w3(a) / (w2(a) + w3(a)) + 0.5f; - } - - //https://ndotl.wordpress.com/2018/08/29/baking-artifact-free-lightmaps - half3 tex2DFastBicubicLightmap(half2 uv, inout half4 bakedColorTex) - { - #if !defined(PLAT_QUEST) && defined(BICUBIC_LIGHTMAP) - half width; - half height; - unity_Lightmap.GetDimensions(width, height); - half x = uv.x * width; - half y = uv.y * height; - - x -= 0.5f; - y -= 0.5f; - half px = floor(x); - half py = floor(y); - half fx = x - px; - half fy = y - py; - - // note: we could store these functions in a lookup table texture, but maths is cheap - half g0x = g0(fx); - half g1x = g1(fx); - half h0x = h0(fx); - half h1x = h1(fx); - half h0y = h0(fy); - half h1y = h1(fy); - - half4 r = g0(fy) * (g0x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h0x, py + h0y) * 1.0f / width)) + - g1x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h1x, py + h0y) * 1.0f / width))) + - g1(fy) * (g0x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h0x, py + h1y) * 1.0f / width)) + - g1x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h1x, py + h1y) * 1.0f / width))); - bakedColorTex = r; - return DecodeLightmap(r); - #else - bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, uv); - return DecodeLightmap(bakedColorTex); - #endif - } - - half3 GetSpecularHighlights(half3 worldNormal, half3 lightColor, half3 lightDirection, half3 f0, half3 viewDir, half clampedRoughness, half NoV, half3 energyCompensation) - { - half3 halfVector = Unity_SafeNormalize(lightDirection + viewDir); - - half NoH = saturate(dot(worldNormal, halfVector)); - half NoL = saturate(dot(worldNormal, lightDirection)); - half LoH = saturate(dot(lightDirection, halfVector)); - - half3 F = F_Schlick(LoH, f0); - half D = D_GGX(NoH, clampedRoughness); - half V = V_SmithGGXCorrelated(NoV, NoL, clampedRoughness); - - #ifndef UNITY_PBS_USE_BRDF2 - F *= energyCompensation; - #endif - - return max(0, (D * V) * F) * lightColor * NoL * UNITY_PI; - } - - #ifdef DYNAMICLIGHTMAP_ON - half3 getRealtimeLightmap(half2 uv, half3 worldNormal) - { - half2 realtimeUV = uv; - half4 bakedCol = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, realtimeUV); - half3 realtimeLightmap = DecodeRealtimeLightmap(bakedCol); - - #ifdef DIRLIGHTMAP_COMBINED - half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, realtimeUV); - realtimeLightmap += DecodeDirectionalLightmap(realtimeLightmap, realtimeDirTex, worldNormal); - #endif - - return realtimeLightmap; - } - #endif - - half computeSpecularAO(half NoV, half ao, half roughness) - { - return clamp(pow(NoV + ao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ao, 0.0, 1.0); - } - - half shEvaluateDiffuseL1Geomerics_local(half L0, half3 L1, half3 n) - { - // average energy - half R0 = L0; - - // avg direction of incoming light - half3 R1 = 0.5f * L1; - - // directional brightness - half lenR1 = length(R1); - - // linear angle between normal and direction 0-1 - //half q = 0.5f * (1.0f + dot(R1 / lenR1, n)); - //half q = dot(R1 / lenR1, n) * 0.5 + 0.5; - half q = dot(normalize(R1), n) * 0.5 + 0.5; - q = saturate(q); // Thanks to ScruffyRuffles for the bug identity. - - // power for q - // lerps from 1 (linear) to 3 (cubic) based on directionality - half p = 1.0f + 2.0f * lenR1 / R0; - - // dynamic range constant - // should vary between 4 (highly directional) and 0 (ambient) - half a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0); - - return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p)); - } - - // https://assetstore.unity.com/packages/tools/level-design/bakery-gpu-lightmapper-122218 - - #if defined(BAKERY_ENABLED) - - //float2 bakeryLightmapSize; - #define BAKERYMODE_DEFAULT 0 - #define BAKERYMODE_VERTEXLM 1.0f - #define BAKERYMODE_RNM 2.0f - #define BAKERYMODE_SH 3.0f - - #define rnmBasis0 float3(0.816496580927726f, 0, 0.5773502691896258f) - #define rnmBasis1 float3(-0.4082482904638631f, 0.7071067811865475f, 0.5773502691896258f) - #define rnmBasis2 float3(-0.4082482904638631f, -0.7071067811865475f, 0.5773502691896258f) - - #if defined(BAKERY_DOMINANT) - #undef BAKERY_RNM - #undef BAKERY_SH - #undef BAKERY_MONOSH - #endif - - #ifdef BICUBIC_LIGHTMAP - #define BAKERY_BICUBIC - #endif - - //#define BAKERY_SSBUMP - - // can't fit vertexLM SH to sm3_0 interpolators - #ifndef SHADER_API_D3D11 - #undef BAKERY_VERTEXLMSH - #endif - - // can't do stuff on sm2_0 due to standard shader alrady taking up all instructions - #if SHADER_TARGET < 30 - #undef BAKERY_BICUBIC - #undef BAKERY_LMSPEC - - #undef BAKERY_RNM - #undef BAKERY_SH - #undef BAKERY_MONOSH - #undef BAKERY_VERTEXLM - #endif - - #if !defined(BAKERY_SH) && !defined(BAKERY_RNM) - #undef BAKERY_BICUBIC - #endif - - #ifndef UNITY_SHOULD_SAMPLE_SH - #undef BAKERY_PROBESHNONLINEAR - #endif - - #if defined(BAKERY_RNM) && defined(BAKERY_LMSPEC) - #define BAKERY_RNMSPEC - #endif - - #ifndef BAKERY_VERTEXLM - #undef BAKERY_VERTEXLMDIR - #undef BAKERY_VERTEXLMSH - #undef BAKERY_VERTEXLMMASK - #endif - - #define lumaConv float3(0.2125f, 0.7154f, 0.0721f) - - #if defined(BAKERY_SH) || defined(BAKERY_MONOSH) || defined(BAKERY_VERTEXLMSH) || defined(BAKERY_PROBESHNONLINEAR) || defined(BAKERY_VOLUME) - float shEvaluateDiffuseL1Geomerics(float L0, float3 L1, float3 n) - { - // average energy - float R0 = L0; - - // avg direction of incoming light - float3 R1 = 0.5f * L1; - - // directional brightness - float lenR1 = length(R1); - - // linear angle between normal and direction 0-1 - //float q = 0.5f * (1.0f + dot(R1 / lenR1, n)); - //float q = dot(R1 / lenR1, n) * 0.5 + 0.5; - float q = dot(normalize(R1), n) * 0.5 + 0.5; - - // power for q - // lerps from 1 (linear) to 3 (cubic) based on directionality - float p = 1.0f + 2.0f * lenR1 / R0; - - // dynamic range constant - // should vary between 4 (highly directional) and 0 (ambient) - float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0); - - return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p)); - } - #endif - - #ifdef BAKERY_VERTEXLM - float4 unpack4NFloats(float src) { - //return fmod(float4(src / 262144.0, src / 4096.0, src / 64.0, src), 64.0)/64.0; - return frac(float4(src / (262144.0*64), src / (4096.0*64), src / (64.0*64), src)); - } - float3 unpack3NFloats(float src) { - float r = frac(src); - float g = frac(src * 256.0); - float b = frac(src * 65536.0); - return float3(r, g, b); - } - #if defined(BAKERY_VERTEXLMDIR) - - #ifdef BAKERY_MONOSH - void BakeryVertexLMMonoSH(inout float3 diffuseColor, inout float3 specularColor, float3 nL1, float3 normalWorld, float3 viewDir, float smoothness) - { - nL1 = nL1; - float3 L0 = diffuseColor; - float3 L1x = nL1.x * L0 * 2; - float3 L1y = nL1.y * L0 * 2; - float3 L1z = nL1.z * L0 * 2; - - float3 sh; - #if BAKERY_SHNONLINEAR - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - float lumaL0 = dot(L0, 1); - float lumaL1x = dot(L1x, 1); - float lumaL1y = dot(L1y, 1); - float lumaL1z = dot(L1z, 1); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = nL1; - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - - void BakeryVertexLMDirection(inout float3 diffuseColor, inout float3 specularColor, float3 lightDirection, float3 vertexNormalWorld, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 dominantDir = Unity_SafeNormalize(lightDirection); - half halfLambert = dot(normalWorld, dominantDir) * 0.5 + 0.5; - half flatNormalHalfLambert = dot(vertexNormalWorld, dominantDir) * 0.5 + 0.5; - - #ifdef BAKERY_LMSPEC - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = spec * diffuseColor; - #endif - - diffuseColor *= halfLambert / max(1e-4h, flatNormalHalfLambert); - } - #elif defined(BAKERY_VERTEXLMSH) - void BakeryVertexLMSH(inout float3 diffuseColor, inout float3 specularColor, float3 shL1x, float3 shL1y, float3 shL1z, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 L0 = diffuseColor; - float3 nL1x = shL1x; - float3 nL1y = shL1y; - float3 nL1z = shL1z; - float3 L1x = nL1x * L0 * 2; - float3 L1y = nL1y * L0 * 2; - float3 L1z = nL1z * L0 * 2; - - float3 sh; - #ifdef BAKERY_SHNONLINEAR - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - float lumaL0 = dot(L0, 1); - float lumaL1x = dot(L1x, 1); - float lumaL1y = dot(L1y, 1); - float lumaL1z = dot(L1z, 1); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - #endif - - #ifdef BAKERY_BICUBIC - float BakeryBicubic_w0(float a) - { - return (1.0f/6.0f)*(a*(a*(-a + 3.0f) - 3.0f) + 1.0f); - } - - float BakeryBicubic_w1(float a) - { - return (1.0f/6.0f)*(a*a*(3.0f*a - 6.0f) + 4.0f); - } - - float BakeryBicubic_w2(float a) - { - return (1.0f/6.0f)*(a*(a*(-3.0f*a + 3.0f) + 3.0f) + 1.0f); - } - - float BakeryBicubic_w3(float a) - { - return (1.0f/6.0f)*(a*a*a); - } - - float BakeryBicubic_g0(float a) - { - return BakeryBicubic_w0(a) + BakeryBicubic_w1(a); - } - - float BakeryBicubic_g1(float a) - { - return BakeryBicubic_w2(a) + BakeryBicubic_w3(a); - } - - float BakeryBicubic_h0(float a) - { - return -1.0f + BakeryBicubic_w1(a) / (BakeryBicubic_w0(a) + BakeryBicubic_w1(a)) + 0.5f; - } - - float BakeryBicubic_h1(float a) - { - return 1.0f + BakeryBicubic_w3(a) / (BakeryBicubic_w2(a) + BakeryBicubic_w3(a)) + 0.5f; - } - #endif - - #if defined(BAKERY_RNM) || defined(BAKERY_SH) - sampler2D _RNM0, _RNM1, _RNM2; - float4 _RNM0_TexelSize; - #endif - - #ifdef BAKERY_VOLUME - Texture3D _Volume0, _Volume1, _Volume2, _VolumeMask; - SamplerState sampler_Volume0; - - #ifndef PROPERTIES_DEFINED - float3 _VolumeMin, _VolumeInvSize; - float3 _GlobalVolumeMin, _GlobalVolumeInvSize; - #endif - - #endif - - #ifdef BAKERY_BICUBIC - // Bicubic - float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) - { - float x = uv.x * texelSize.z; - float y = uv.y * texelSize.z; - - x -= 0.5f; - y -= 0.5f; - - float px = floor(x); - float py = floor(y); - - float fx = x - px; - float fy = y - py; - - float g0x = BakeryBicubic_g0(fx); - float g1x = BakeryBicubic_g1(fx); - float h0x = BakeryBicubic_h0(fx); - float h1x = BakeryBicubic_h1(fx); - float h0y = BakeryBicubic_h0(fy); - float h1y = BakeryBicubic_h1(fy); - - return BakeryBicubic_g0(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h0y) * texelSize.x)) + - g1x * tex2D(tex, (float2(px + h1x, py + h0y) * texelSize.x))) + - - BakeryBicubic_g1(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h1y) * texelSize.x)) + - g1x * tex2D(tex, (float2(px + h1x, py + h1y) * texelSize.x))); - } - float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) - { - float x = uv.x * texelSize.z; - float y = uv.y * texelSize.z; - - x -= 0.5f; - y -= 0.5f; - - float px = floor(x); - float py = floor(y); - - float fx = x - px; - float fy = y - py; - - float g0x = BakeryBicubic_g0(fx); - float g1x = BakeryBicubic_g1(fx); - float h0x = BakeryBicubic_h0(fx); - float h1x = BakeryBicubic_h1(fx); - float h0y = BakeryBicubic_h0(fy); - float h1y = BakeryBicubic_h1(fy); - - return BakeryBicubic_g0(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h0y) * texelSize.x)) + - g1x * tex.Sample(s, (float2(px + h1x, py + h0y) * texelSize.x))) + - - BakeryBicubic_g1(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h1y) * texelSize.x)) + - g1x * tex.Sample(s, (float2(px + h1x, py + h1y) * texelSize.x))); - } - #else - // Bilinear - float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) - { - return tex2D(tex, uv); - } - float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) - { - return tex.Sample(s, uv); - } - #endif - - #ifdef DIRLIGHTMAP_COMBINED - #ifdef BAKERY_LMSPEC - float BakeryDirectionalLightmapSpecular(float2 lmUV, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 dominantDir = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lmUV).xyz * 2 - 1; - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - return spec; - } - #endif - #endif - - #ifdef BAKERY_RNM - void BakeryRNM(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalMap, float perceptualRoughness, float3 viewDirT) - { - normalMap.g *= -1; - float3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize)); - float3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize)); - float3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize)); - - #ifdef BAKERY_SSBUMP - diffuseColor = normalMap.x * rnm0 - + normalMap.z * rnm1 - + normalMap.y * rnm2; - diffuseColor *= 2; - #else - diffuseColor = saturate(dot(rnmBasis0, normalMap)) * rnm0 - + saturate(dot(rnmBasis1, normalMap)) * rnm1 - + saturate(dot(rnmBasis2, normalMap)) * rnm2; - #endif - - #ifdef BAKERY_LMSPEC - float3 dominantDirT = rnmBasis0 * dot(rnm0, lumaConv) + - rnmBasis1 * dot(rnm1, lumaConv) + - rnmBasis2 * dot(rnm2, lumaConv); - - float3 dominantDirTN = normalize(dominantDirT); - float3 specColor = saturate(dot(rnmBasis0, dominantDirTN)) * rnm0 + - saturate(dot(rnmBasis1, dominantDirTN)) * rnm1 + - saturate(dot(rnmBasis2, dominantDirTN)) * rnm2; - - half3 halfDir = Unity_SafeNormalize(dominantDirTN - viewDirT); - half nh = saturate(dot(normalMap, halfDir)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = spec * specColor; - #endif - } - #endif - - #ifdef BAKERY_SH - void BakerySH(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalWorld, float3 viewDir, float perceptualRoughness) - { - #ifdef SHADER_API_D3D11 - float3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, samplerunity_Lightmap, lmUV, _RNM0_TexelSize)); - #else - float3 L0 = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, lmUV)); - #endif - float3 nL1x = BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 nL1y = BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 nL1z = BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 L1x = nL1x * L0 * 2; - float3 L1y = nL1y * L0 * 2; - float3 L1z = nL1z * L0 * 2; - - float3 sh; - #ifdef BAKERY_SHNONLINEAR - float lumaL0 = dot(L0, float(1)); - float lumaL1x = dot(L1x, float(1)); - float lumaL1y = dot(L1y, float(1)); - float lumaL1z = dot(L1z, float(1)); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - - sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - - #endif - //BAKERY_ENABLED - - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - - half _Smoothness; - half _Metallic; - half _OcclusionStrength; - half _BumpScale; - half _HeightScale; - half _HeightRefPlane; - half _HeightStepsMin; - half _HeightStepsMax; - half _DAlbedoScale; - half _DNormalScale; - half _DSmoothScale; - half _VertexHeightAmount; - half _VertexHeightOffset; - half _TessFactor; - half _TessMinDist; - half _TessMaxDist; - half _TessEdgeLength; - half _TessMaxDisplacement; - half _SpecOcclusion; - half _SpecularRoughnessMod; - half2 GLOBAL_uv; - half4 _Color; - half4 _MainTex_ST; - half4 _MetallicRemap; - half4 _SmoothnessRemap; - half4 _MaskMap_TexelSize; - half4 _EmissionColor; - half4 GLOBAL_maskMap; - half4 _DDetailsMap_ST; - float _GSAAVariance; - float _GSAAThreshold; - int _AlbedoChannel; - int _MappingSpace; - int _PlanarAxisX; - int _PlanarAxisY; - int _MetalChannel; - int _AOChannel; - int _DetailMaskChannel; - int _SmoothChannel; - int _RoughnessMode; - int _DetailAsTintMask; - int _FlipBumpY; - int _EmissionChannel; - TEXTURE2D(_MainTex); - SAMPLER(sampler_MainTex); - TEXTURE2D(_MaskMap); - SAMPLER(sampler_MaskMap); - TEXTURE2D(_BumpMap); - SAMPLER(sampler_BumpMap); - TEXTURE2D(_EmissionMap); - SAMPLER(sampler_EmissionMap); - TEXTURE2D(_Height); - SAMPLER(sampler_Height); - int _DIgnoreMask; - int _DMappingSpace; - int _DUVChannel; - int _DPlanarAxisX; - int _DPlanarAxisY; - int _DNormalFlipY; - TEXTURE2D(_DDetailsMap); - SAMPLER(sampler_DDetailsMap); - TEXTURE2D(_DDetailsNormal); - SAMPLER(sampler_DDetailsNormal); - TEXTURE2D(_VertexHeight); - SAMPLER(sampler_VertexHeight); - TEXTURE2D(_DFG); - SAMPLER(sampler_DFG); - - void VHVertex() { - half2 uv = vD.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - half height = (SAMPLE_TEXTURE2D_LOD(_VertexHeight, sampler_VertexHeight, uv, 0).r * 2 - 1); - half3 mainOffset = vD.vertex.xyz + vD.normal * (height + _VertexHeightOffset) * _VertexHeightAmount; - vD.vertex.xyz = mainOffset; - } - - void ParallaxFragment() - { - GLOBAL_uv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - #if PARALLAX && !defined(PLAT_QUEST) - half customHeight = 0; - GLOBAL_uv = POM(_Height, sampler_Height, GLOBAL_uv, ddx(GLOBAL_uv), ddy(GLOBAL_uv), d.worldNormal, d.worldSpaceViewDir, d.tangentSpaceViewDir, _HeightStepsMin, _HeightStepsMax, _HeightScale, _HeightRefPlane, half2(1, 1), half2(0, 0), 0, customHeight); - #endif - } - - void BaseFragmentFunction() - { - #if !defined(_SET_GLOBAL_UVS) - GLOBAL_uv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - #endif - if (_MappingSpace > 0) - { - GLOBAL_uv = (_MappingSpace - 1) ? half2(d.worldSpacePosition[_PlanarAxisX], d.worldSpacePosition[_PlanarAxisY]) : half2(d.localSpacePosition[_PlanarAxisX], d.localSpacePosition[_PlanarAxisY]); - GLOBAL_uv = GLOBAL_uv * _MainTex_ST.xy + _MainTex_ST.zw; - } - half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, GLOBAL_uv); - if (_AlbedoChannel > 0) - { - albedo.rgb = albedo[_AlbedoChannel].xxx; - } - half4 masks = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, GLOBAL_uv); - half4 normalTex = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, GLOBAL_uv); - if (_FlipBumpY) - { - normalTex.y = 1 - normalTex.y; - } - half3 normal = UnpackScaleNormal(normalTex, _BumpScale); - half3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, GLOBAL_uv).rgb; - if (_EmissionChannel > 0) - { - emission.rgb = emission[_EmissionChannel].xxx; - } - int hasMasks = _MaskMap_TexelSize.z > 8; - half metal = masks[_MetalChannel]; - half smooth = masks[_SmoothChannel]; - if (_RoughnessMode) - { - smooth = 1 - smooth; - } - half detailMask = masks[_DetailMaskChannel]; - half occlusion = masks[_AOChannel]; - metal = remap(metal, 0, 1, _MetallicRemap.x, _MetallicRemap.y); - smooth = remap(smooth, 0, 1, _SmoothnessRemap.x, _SmoothnessRemap.y); - GLOBAL_maskMap = half4(metal, occlusion, detailMask, smooth); - o.Metallic = lerp(_Metallic, metal, hasMasks); - o.Smoothness = lerp(_Smoothness, smooth, hasMasks); - o.Occlusion = lerp(1, occlusion, _OcclusionStrength); - o.Normal = normal; - if (!_DetailAsTintMask) - { - o.Albedo = albedo.rgb * _Color.rgb; - } - else - { - o.Albedo = lerp(albedo, albedo.rgb * _Color.rgb, detailMask); - } - o.Alpha = albedo.a * _Color.a; - #if defined(_EMISSION) - o.Emission = emission * _EmissionColor; - #endif - } - - void DetailsFragment() - { - #if defined(DETAILS_OVERLAY) - half masks = 0; - #if defined(_MASKMAP_SAMPLED) - masks = GLOBAL_maskMap.b; - #else - masks = 1; - #endif - half mask = lerp(masks, 1, _DIgnoreMask); - half2 uv = d.uv0.xy; - switch(_DUVChannel) - { - case 1: uv = d.uv1.xy; break; - case 2: uv = d.uv2.xy; break; - case 3: uv = d.uv3.xy; break; - default: uv = d.uv0.xy; break; - } - uv = uv * _DDetailsMap_ST.xy + _DDetailsMap_ST.zw; - if (_DMappingSpace > 0) - { - uv = (_DMappingSpace - 1) ? half2(d.worldSpacePosition[_DPlanarAxisX], d.worldSpacePosition[_DPlanarAxisY]) : half2(d.localSpacePosition[_DPlanarAxisX], d.localSpacePosition[_DPlanarAxisY]); - uv = uv * _DDetailsMap_ST.xy + _DDetailsMap_ST.zw; - } - - half4 detailsMap = SAMPLE_TEXTURE2D(_DDetailsMap, sampler_DDetailsMap, uv); - - #if defined(DETAILS_MODE_PACKED) - half detailAlbedo = detailsMap.r * 2.0 - 1.0; - half detailSmooth = detailsMap.b * 2.0 - 1.0; - half3 detailNormal = 0; - if (_DNormalFlipY) - { - detailsMap.g = 1 - detailsMap.g; - } - detailNormal = UnpackNormalAG(detailsMap, _DNormalScale); - half detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); - #elif defined(DETAILS_MODE_SEPARATED) - half3 detailAlbedo = detailsMap.rgb * 2.0 - 1.0; - half detailSmooth = detailsMap.a * 2.0 - 1.0; - - half4 packedNormal = SAMPLE_TEXTURE2D(_DDetailsNormal, sampler_DDetailsNormal, uv); - if (_DNormalFlipY) - { - packedNormal.g = 1 - packedNormal.g; - } - half3 detailNormal = UnpackScaleNormal(packedNormal, _DNormalScale); - - half3 detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); - #endif - - half3 albedoOverlay = lerp(sqrt(o.Albedo), (detailAlbedo < 0.0) ? 0.0.xxx : 1.0.xxx, detailAlbedoSpeed * detailAlbedoSpeed); - albedoOverlay *= albedoOverlay; - o.Albedo = lerp(o.Albedo, saturate(albedoOverlay), mask); - - half detailSmoothSpeed = saturate(abs(detailSmooth) * _DSmoothScale); - half smoothOverlay = lerp(o.Smoothness, (detailSmooth < 0.0) ? 0.0 : 1.0, detailSmoothSpeed * detailSmoothSpeed); - o.Smoothness = lerp(o.Smoothness, saturate(smoothOverlay), mask); - - o.Normal = lerp(o.Normal, BlendNormals(o.Normal, detailNormal), mask); - #endif - } - - void ORLLighting() - { - #if !defined(UNITY_PASS_SHADOWCASTER) - half reflectance = 0.5; - half3 f0 = 0.16 * reflectance * reflectance * (1 - o.Metallic) + o.Albedo * o.Metallic; - half3 pixelLight = 0; - half3 indirectDiffuse = 1; - half3 indirectSpecular = 0; - half3 directSpecular = 0; - half occlusion = o.Occlusion; - half perceptualRoughness = 1 - o.Smoothness; - half3 tangentNormal = o.Normal; - o.Normal = normalize(mul(o.Normal, d.TBNMatrix)); - - #ifndef USING_DIRECTIONAL_LIGHT - fixed3 lightDir = normalize(UnityWorldSpaceLightDir(d.worldSpacePosition)); - #else - fixed3 lightDir = _WorldSpaceLightPos0.xyz; - #endif - - #if defined(GSAA) - perceptualRoughness = GSAA_Filament(o.Normal, perceptualRoughness, _GSAAVariance, _GSAAThreshold); - #endif - - UNITY_LIGHT_ATTENUATION(lightAttenuation, FragData, d.worldSpacePosition); - half3 lightColor = lightAttenuation * _LightColor0.rgb; - - half3 lightHalfVector = Unity_SafeNormalize(lightDir + d.worldSpaceViewDir); - half lightNoL = saturate(dot(o.Normal, lightDir)); - half lightLoH = saturate(dot(lightDir, lightHalfVector)); - - half NoV = abs(dot(o.Normal, d.worldSpaceViewDir)) + 1e-5; - pixelLight = lightNoL * lightColor * Fd_Burley(perceptualRoughness, NoV, lightNoL, lightLoH); - - // READ THE LIGHTMAP - #if defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) - half3 lightMap = 0; - half4 bakedColorTex = 0; - half2 lightmapUV = FragData.lightmapUv.xy; - - // UNITY LIGHTMAPPING - #if !defined(BAKERYLM_ENABLED) || !defined(BAKERY_ENABLED) - lightMap = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); - #endif - - // BAKERY RNM MODE (why do we even support it??) - #if defined(BAKERY_RNM) && defined(BAKERY_ENABLED) - half3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, lightmapUV, _RNM0_TexelSize)); - half3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, lightmapUV, _RNM0_TexelSize)); - half3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, lightmapUV, _RNM0_TexelSize)); - - lightMap = saturate(dot(rnmBasis0, tangentNormal)) * rnm0 + - saturate(dot(rnmBasis1, tangentNormal)) * rnm1 + - saturate(dot(rnmBasis2, tangentNormal)) * rnm2; - #endif - - // BAKERY SH MODE (these are also used for the specular) - #if defined(BAKERY_SH) && defined(BAKERY_ENABLED) - half3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, samplerunity_Lightmap, lightmapUV, _RNM0_TexelSize)); - - half3 nL1x = BakeryTex2D(_RNM0, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 nL1y = BakeryTex2D(_RNM1, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 nL1z = BakeryTex2D(_RNM2, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 L1x = nL1x * L0 * 2.0; - half3 L1y = nL1y * L0 * 2.0; - half3 L1z = nL1z * L0 * 2.0; - - // Non-Linear mode - #if defined(BAKERY_SHNONLINEAR) - half lumaL0 = dot(L0, half(1)); - half lumaL1x = dot(L1x, half(1)); - half lumaL1y = dot(L1y, half(1)); - half lumaL1z = dot(L1z, half(1)); - half lumaSH = shEvaluateDiffuseL1Geomerics_local(lumaL0, half3(lumaL1x, lumaL1y, lumaL1z), o.Normal); - - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - half regularLumaSH = dot(lightMap, 1.0); - lightMap *= lerp(1.0, lumaSH / regularLumaSH, saturate(regularLumaSH * 16.0)); - #else - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - #endif - - #endif - - #if defined(DIRLIGHTMAP_COMBINED) - half4 lightMapDirection = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lightmapUV); - #if !defined(BAKERY_MONOSH) - lightMap = DecodeDirectionalLightmap(lightMap, lightMapDirection, o.Normal); - #endif - #endif - - #if defined(BAKERY_MONOSH) && defined(BAKERY_ENABLED) && defined(DIRLIGHTMAP_COMBINED) - half3 L0 = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); - half3 nL1 = lightMapDirection.xyz * 2.0 - 1.0; - half3 L1x = nL1.x * L0 * 2.0; - half3 L1y = nL1.y * L0 * 2.0; - half3 L1z = nL1.z * L0 * 2.0; - - #if defined(BAKERY_SHNONLINEAR) - half lumaL0 = dot(L0, 1); - half lumaL1x = dot(L1x, 1); - half lumaL1y = dot(L1y, 1); - half lumaL1z = dot(L1z, 1); - half lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, half3(lumaL1x, lumaL1y, lumaL1z), o.Normal); - - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - half regularLumaSH = dot(lightMap, 1); - lightMap *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - #else - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - #endif - - lightMap = max(lightMap, 0.0); - #endif - - #if defined(DYNAMICLIGHTMAP_ON) && !defined(UNITY_PBS_USE_BRDF2) - half3 realtimeLightMap = getRealtimeLightmap(FragData.lightmapUv.zw, o.Normal); - lightMap += realtimeLightMap; - #endif - - #if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) - pixelLight = 0; - lightMap = SubtractMainLightWithRealtimeAttenuationFrowmLightmap(lightMap, lightAttenuation, bakedColorTex, o.Normal); - #endif - indirectDiffuse = lightMap; - #else - #if UNITY_LIGHT_PROBE_PROXY_VOLUME - UNITY_BRANCH - if (unity_ProbeVolumeParams.x == 1) - { - indirectDiffuse = SHEvalLinearL0L1_SampleProbeVolume(half4(o.Normal, 1), FragData.worldPos); - } - else - { - #endif - indirectDiffuse = max(0, ShadeSH9(half4(o.Normal, 1))); - #if UNITY_LIGHT_PROBE_PROXY_VOLUME - } - #endif - #endif - - #if defined(LIGHTMAP_SHADOW_MIXING) && defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) && defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) - pixelLight *= UnityComputeForwardShadows(FragData.lightmapUv.xy, d.worldSpacePosition, d.screenPos); - #endif - - half3 dfguv = half3(NoV, perceptualRoughness, 0); - half2 dfg = SAMPLE_TEXTURE2D(_DFG, sampler_DFG, dfguv).xy; - half3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0); - - half rough = perceptualRoughness * perceptualRoughness; - half clampedRoughness = max(rough, 0.002); - - #if !defined(SPECULAR_HIGHLIGHTS_OFF) && defined(USING_LIGHT_MULTI_COMPILE) - half NoH = saturate(dot(o.Normal, lightHalfVector)); - half3 F = F_Schlick(lightLoH, f0); - half D = D_GGX(NoH, clampedRoughness); - half V = V_SmithGGXCorrelated(NoV, lightNoL, clampedRoughness); - - F *= energyCompensation; - - directSpecular = max(0, D * V * F) * pixelLight * UNITY_PI; - #endif - - // BAKED SPECULAR - #if defined(BAKED_SPECULAR) && !defined(BAKERYLM_ENABLED) && !defined(UNITY_PASS_FORWARDADD) - { - half3 bakedDominantDirection = 1; - half3 bakedSpecularColor = 0; - - // only do it if we have a directional lightmap - #if defined(DIRLIGHTMAP_COMBINED) && defined(LIGHTMAP_ON) - bakedDominantDirection = (lightMapDirection.xyz) * 2 - 1; - half directionality = max(0.001, length(bakedDominantDirection)); - bakedDominantDirection /= directionality; - bakedSpecularColor = indirectDiffuse; - #endif - - // if we do not have lightmap - derive the specular from probes - //#ifndef LIGHTMAP_ON - //bakedSpecularColor = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); - //bakedDominantDirection = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz; - // #endif - - bakedDominantDirection = normalize(bakedDominantDirection); - directSpecular += GetSpecularHighlights(o.Normal, bakedSpecularColor, bakedDominantDirection, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); - } - #endif - - half3 fresnel = F_Schlick(NoV, f0); - - // BAKERY DIRECT SPECULAR - #if defined(BAKERY_LMSPEC) && defined(BAKERY_ENABLED) && !defined(UNITY_PASS_FORWARDADD) - #if defined(BAKERY_RNM) - { - half3 viewDirTangent = -normalize(d.tangentSpaceViewDir); - half3 dominantDirTangent = rnmBasis0 * dot(rnm0, lumaConv) + - rnmBasis1 * dot(rnm1, lumaConv) + - rnmBasis2 * dot(rnm2, lumaConv); - - half3 dominantDirTangentNormalized = normalize(dominantDirTangent); - half3 specColor = saturate(dot(rnmBasis0, dominantDirTangentNormalized)) * rnm0 + - saturate(dot(rnmBasis1, dominantDirTangentNormalized)) * rnm1 + - saturate(dot(rnmBasis2, dominantDirTangentNormalized)) * rnm2; - half3 halfDir = Unity_SafeNormalize(dominantDirTangentNormalized - viewDirTangent); - half NoH = saturate(dot(tangentNormal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - directSpecular += spec * specColor * fresnel; - } - #endif - - #if defined(BAKERY_SH) - { - half3 dominantDir = half3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(L1z, lumaConv)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) + d.worldSpaceViewDir); - half NoH = saturate(dot(o.Normal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - dominantDir = normalize(dominantDir); - directSpecular += max(spec * sh, 0.0) * fresnel; - } - #endif - - #if defined(BAKERY_MONOSH) - { - half3 dominantDir = nL1; - half focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - d.worldSpaceViewDir); - half NoH = saturate(dot(o.Normal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - dominantDir = normalize(dominantDir); - directSpecular += max(spec * sh, 0.0) * fresnel; - } - #endif - #endif - - // REFLECTIONS - #if !defined(UNITY_PASS_FORWARDADD) - half3 reflDir = reflect(-d.worldSpaceViewDir, o.Normal); - reflDir = lerp(reflDir, o.Normal, rough * rough); - - Unity_GlossyEnvironmentData envData; - envData.roughness = perceptualRoughness; - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - - half3 probe0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData); - indirectSpecular = probe0; - - #if defined(UNITY_SPECCUBE_BLENDING) - UNITY_BRANCH - if (unity_SpecCube0_BoxMin.w < 0.99999) - { - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half3 probe1 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0), unity_SpecCube1_HDR, envData); - indirectSpecular = lerp(probe1, probe0, unity_SpecCube0_BoxMin.w); - } - #endif - - half horizon = min(1 + dot(reflDir, o.Normal), 1); - dfg.x *= saturate(pow(dot(indirectDiffuse, 1), _SpecOcclusion)); - indirectSpecular = indirectSpecular * horizon * horizon * energyCompensation * EnvBRDFMultiscatter(dfg, f0); - - #if defined(_MASKMAP_SAMPLED) - indirectSpecular *= computeSpecularAO(NoV, o.Occlusion, perceptualRoughness * perceptualRoughness); - #endif - #endif - - #if defined(_INTEGRATE_CUSTOMGI) && !defined(UNITY_PASS_FORWARDADD) - IntegrateCustomGI(d, o, indirectSpecular, indirectDiffuse); - #endif - - // FINAL COLOR - FinalColor = half4(o.Albedo.rgb * (1 - o.Metallic) * (indirectDiffuse * occlusion + (pixelLight)) + indirectSpecular + directSpecular, o.Alpha); - - FinalColor.rgb += o.Emission; - #endif - } - - // Meta Vertex - TessVertex Vertex(VertexData v) - { - UNITY_SETUP_INSTANCE_ID(v); - TessVertex o = (TessVertex) 0; - UNITY_TRANSFER_INSTANCE_ID(v, o); - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - - o.vertex = v.vertex; - o.normal = v.normal; - o.tangent = v.tangent; - o.color = v.color; - o.uv0 = v.uv0; - o.uv1 = v.uv1; - o.uv2 = v.uv2; - o.uv3 = v.uv3; - - return o; - } - - // Meta Hull - [maxtessfactor(MAX_TESSELLATION_FACTORS)] - [UNITY_domain("tri")] - [UNITY_outputcontrolpoints(3)] - [UNITY_outputtopology("triangle_cw")] - [UNITY_partitioning("integer")] - [UNITY_patchconstantfunc("TessFactorsFunction")] - TessVertex Hull(InputPatch patch, uint id : SV_OutputControlPointID) - { - return patch[id]; - } - - float4 GetTessFactors(InputPatch patch) - { - #if defined(TESS_MODE_DISTANCEBASED) - float4 tessFactors = UnityDistanceBasedTess( - patch[0].vertex, - patch[1].vertex, - patch[2].vertex, - _TessMinDist, - _TessMaxDist, - _TessFactor - ); - return tessFactors; - #elif defined(TESS_MODE_EDGELENGTH) - float4 tessFactors = UnityEdgeLengthBasedTessCull( - patch[0].vertex, - patch[1].vertex, - patch[2].vertex, - _TessEdgeLength, - _TessMaxDisplacement - ); - return tessFactors; - #endif - - return 1..xxxx; - } - - // Meta TessFactor - TessellationFactors TessFactorsFunction(InputPatch patch) - { - TessellationFactors f; - float4 TessFactorsOutput = 0; - #if defined(TESS_FACTORS_FUNC_DEFINED) - TessFactorsOutput = GetTessFactors(patch); - #else - TessFactorsOutput = 1..xxxx; - #endif - f.edge[0] = TessFactorsOutput.x; - f.edge[1] = TessFactorsOutput.y; - f.edge[2] = TessFactorsOutput.z; - f.inside = TessFactorsOutput.w; - return f; - } - - // Meta Domain - [UNITY_domain("tri")] - FragmentData Domain(TessellationFactors factors, OutputPatch patch, float3 baryCoords : SV_DomainLocation) - { - VertexData v = (VertexData) 0; - UNITY_TRANSFER_INSTANCE_ID(patch[0], v); - v.vertex = patch[0].vertex * baryCoords.x + patch[1].vertex * baryCoords.y + patch[2].vertex * baryCoords.z; - - #if defined(PHONG) - float3 pp[3]; - for (int index = 0; index < 3; ++index) - { - pp[index] = v.vertex.xyz - patch[index].normal * (dot(v.vertex.xyz, patch[index].normal) - dot(patch[index].vertex.xyz, patch[index].normal)); - } - v.vertex.xyz = 0.5 * (pp[0]*baryCoords.x + pp[1]*baryCoords.y + pp[2]*baryCoords.z) + (0.5) * v.vertex.xyz; - #endif - - v.normal = patch[0].normal * baryCoords.x + patch[1].normal * baryCoords.y + patch[2].normal * baryCoords.z; - v.tangent = patch[0].tangent * baryCoords.x + patch[1].tangent * baryCoords.y + patch[2].tangent * baryCoords.z; - v.color = patch[0].color * baryCoords.x + patch[1].color * baryCoords.y + patch[2].color * baryCoords.z; - v.uv0 = patch[0].uv0 * baryCoords.x + patch[1].uv0 * baryCoords.y + patch[2].uv0 * baryCoords.z; - v.uv1 = patch[0].uv1 * baryCoords.x + patch[1].uv1 * baryCoords.y + patch[2].uv1 * baryCoords.z; - v.uv2 = patch[0].uv2 * baryCoords.x + patch[1].uv2 * baryCoords.y + patch[2].uv2 * baryCoords.z; - v.uv3 = patch[0].uv3 * baryCoords.x + patch[1].uv3 * baryCoords.y + patch[2].uv3 * baryCoords.z; - - FragmentData i; - UNITY_INITIALIZE_OUTPUT(FragmentData, i); - UNITY_TRANSFER_INSTANCE_ID(patch[0], i); - - vD = v; - FragData = i; - VHVertex(); - - i = FragData; - v = vD; - #if defined(UNITY_PASS_SHADOWCASTER) - i.worldNormal = UnityObjectToWorldNormal(v.normal); - i.worldPos = mul(unity_ObjectToWorld, v.vertex); - i.uv0 = v.uv0; - i.uv1 = v.uv1; - i.uv2 = v.uv2; - i.uv3 = v.uv3; - i.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz); - i.worldTangent.w = v.tangent.w * unity_WorldTransformParams.w; - #else - #if defined(UNITY_PASS_META) - i.pos = UnityMetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST); - #else - i.pos = UnityObjectToClipPos(v.vertex); - #endif - i.normal = v.normal; - i.worldNormal = UnityObjectToWorldNormal(v.normal); - i.worldPos = mul(unity_ObjectToWorld, v.vertex); - i.uv0 = v.uv0; - i.uv1 = v.uv1; - i.uv2 = v.uv2; - i.uv3 = v.uv3; - i.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz); - i.worldTangent.w = v.tangent.w * unity_WorldTransformParams.w; - i.vertexColor = v.color; - - #if defined(EDITOR_VISUALIZATION) - i.vizUV = 0; - i.lightCoord = 0; - if (unity_VisualizationMode == EDITORVIZ_TEXTURE) - i.vizUV = UnityMetaVizUV(unity_EditorViz_UVIndex, v.uv0.xy, v.uv1.xy, v.uv2.xy, unity_EditorViz_Texture_ST); - else if (unity_VisualizationMode == EDITORVIZ_SHOWLIGHTMASK) - { - i.vizUV = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; - i.lightCoord = mul(unity_EditorViz_WorldToLight, mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1))); - } - #endif - - #if defined(NEED_SCREEN_POS) - i.screenPos = ComputeScreenPos(i.pos); - #endif - - #if !defined(UNITY_PASS_META) - #if defined(LIGHTMAP_ON) - i.lightmapUv.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; - #endif - #if defined(DYNAMICLIGHTMAP_ON) - i.lightmapUv.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; - #endif - - UNITY_TRANSFER_LIGHTING(i, v.uv1.xy); - - #if !defined(UNITY_PASS_FORWARDADD) - // unity does some funky stuff for different platforms with these macros - #ifdef FOG_COMBINED_WITH_TSPACE - UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(i, i.pos); - #elif defined(FOG_COMBINED_WITH_WORLD_POS) - UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(i, i.pos); - #else - UNITY_TRANSFER_FOG(i, i.pos); - #endif - #else - UNITY_TRANSFER_FOG(i, i.pos); - #endif - #endif - #endif - - return i; - } - - // Meta Fragment - half4 Fragment(FragmentData i) : SV_TARGET - { - UNITY_SETUP_INSTANCE_ID(i); - - FragData = i; - o = (SurfaceData) 0; - d = CreateMeshData(i); - o.Albedo = half3(0.5, 0.5, 0.5); - o.Normal = half3(0, 0, 1); - o.Smoothness = 0.5; - o.Occlusion = 1; - o.Alpha = 1; - - ParallaxFragment(); - BaseFragmentFunction(); - DetailsFragment(); - - FinalColor = half4(o.Albedo, o.Alpha); - - UnityMetaInput metaIN; - UNITY_INITIALIZE_OUTPUT(UnityMetaInput, metaIN); - - metaIN.Albedo = FinalColor; - metaIN.Emission = o.Emission; - - #if defined(EDITOR_VISUALISATION) - metaIN.VizUV = i.vizUV; - metaIN.LightCoord = i.lightCoord; - #endif - - return UnityMetaFragment(metaIN); - } - - ENDCG - // Meta Pass End - - } - - Pass - { - Tags { "LightMode" = "ShadowCaster" } - - // Shadow Pass Start - CGPROGRAM - #pragma target 4.6 - #pragma require tesshw - #pragma multi_compile_instancing - #pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2 - #pragma multi_compile_shadowcaster - #pragma vertex Vertex - #pragma fragment Fragment - #pragma hull Hull - #pragma domain Domain - #pragma shader_feature_local _EMISSION - - #pragma shader_feature_local PARALLAX - - #pragma shader_feature_local DETAILS_OVERLAY - #pragma shader_feature_local _ DETAILS_MODE_PACKED DETAILS_MODE_SEPARATED - - #pragma shader_feature_local _ TESS_MODE_DISTANCEBASED TESS_MODE_EDGELENGTH - #pragma shader_feature_local PHONG - - #pragma shader_feature_local BICUBIC_LIGHTMAP - #pragma shader_feature_local BAKED_SPECULAR - #pragma shader_feature_local GSAA - #pragma shader_feature_local FORCE_BOX_PROJECTION - - // Bakery Stuff - #pragma shader_feature_local BAKERY_ENABLED - #pragma shader_feature_local _ BAKERY_RNM BAKERY_SH BAKERY_MONOSH - #pragma shader_feature_local BAKERY_SHNONLINEAR - - #define UNITY_INSTANCED_LOD_FADE - #define UNITY_INSTANCED_SH - #define UNITY_INSTANCED_LIGHTMAPSTS - - #ifndef UNITY_PASS_SHADOWCASTER - #define UNITY_PASS_SHADOWCASTER - #endif - - #if defined(SHADER_API_XBOXONE) || defined(SHADER_API_PSSL) - #define MAX_TESSELLATION_FACTORS 15.0 - #else - #define MAX_TESSELLATION_FACTORS 64.0 - #endif - - #include "UnityStandardUtils.cginc" - #include "Lighting.cginc" - #include "UnityPBSLighting.cginc" - #include "Tessellation.cginc" - - #define FLT_EPSILON 1.192092896e-07 - - #define _MASKMAP_SAMPLED - - #define _SET_GLOBAL_UVS - - #if !defined(DETAILS_MODE_PACKED) && !defined(DETAILS_MODE_SEPARATED) - #define DETAILS_MODE_PACKED - #endif - - #define TESS_FACTORS_FUNC_DEFINED - - #if defined(UNITY_PBS_USE_BRDF2) || defined(SHADER_API_MOBILE) - #define PLAT_QUEST - #else - #ifdef PLAT_QUEST - #undef PLAT_QUEST - #endif - #endif - - #if !defined(LIGHTMAP_ON) || !defined(UNITY_PASS_FORWARDBASE) - #undef BAKERY_SH - #undef BAKERY_RNM - #endif - - #ifdef LIGHTMAP_ON - #undef BAKERY_VOLUME - #endif - - #ifdef LIGHTMAP_ON - #if defined(BAKERY_RNM) || defined(BAKERY_SH) || defined(BAKERY_VERTEXLM) - #define BAKERYLM_ENABLED - #undef DIRLIGHTMAP_COMBINED - #endif - #endif - - #if defined(BAKERY_SH) || defined(BAKERY_RNM) || defined(BAKERY_VOLUME) - #ifdef BAKED_SPECULAR - #define _BAKERY_LMSPEC - #define BAKERY_LMSPEC - #endif - #endif - - #define NEED_SCREEN_POS - - struct VertexData - { - float4 vertex : POSITION; - float3 normal : NORMAL; - float4 tangent : TANGENT; - float4 color : COLOR; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - UNITY_VERTEX_INPUT_INSTANCE_ID - }; - - struct FragmentData - { - #if defined(UNITY_PASS_SHADOWCASTER) - V2F_SHADOW_CASTER; - float2 uv0 : TEXCOORD1; - float2 uv1 : TEXCOORD2; - float2 uv2 : TEXCOORD3; - float2 uv3 : TEXCOORD4; - float3 worldPos : TEXCOORD5; - float3 worldNormal : TEXCOORD6; - float4 worldTangent : TEXCOORD7; - #else - float4 pos : SV_POSITION; - float3 normal : NORMAL; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - float3 worldPos : TEXCOORD4; - float3 worldNormal : TEXCOORD5; - float4 worldTangent : TEXCOORD6; - float4 lightmapUv : TEXCOORD7; - float4 vertexColor : TEXCOORD8; - - #if !defined(UNITY_PASS_META) - UNITY_LIGHTING_COORDS(9, 10) - UNITY_FOG_COORDS(11) - #endif - #endif - - #if defined(EDITOR_VISUALIZATION) - float2 vizUV : TEXCOORD9; - float4 lightCoord : TEXCOORD10; - #endif - - #if defined(NEED_SCREEN_POS) - float4 screenPos: SCREENPOS; - #endif - - #if defined(EXTRA_V2F_0) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F0 : TEXCOORD8; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F0 : TEXCOORD12; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F0 : TEXCOORD11; - #else - float4 extraV2F0 : TEXCOORD9; - #endif - #endif - #endif - #endif - #if defined(EXTRA_V2F_1) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F1 : TEXCOORD9; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F1 : TEXCOORD13; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F1 : TEXCOORD14; - #else - float4 extraV2F1 : TEXCOORD15; - #endif - #endif - #endif - #endif - #if defined(EXTRA_V2F_2) - #if defined(UNITY_PASS_SHADOWCASTER) - float4 extraV2F2 : TEXCOORD10; - #else - #if !defined(UNITY_PASS_META) - float4 extraV2F2 : TEXCOORD14; - #else - #if defined(EDITOR_VISUALIZATION) - float4 extraV2F2 : TEXCOORD15 - #else - float4 extraV2F2 : TEXCOORD16; - #endif - #endif - #endif - #endif - - UNITY_VERTEX_INPUT_INSTANCE_ID - UNITY_VERTEX_OUTPUT_STEREO - }; - - struct MeshData - { - half2 uv0; - half2 uv1; - half2 uv2; - half2 uv3; - half4 vertexColor; - half3 normal; - half3 worldNormal; - half3 localSpacePosition; - half3 worldSpacePosition; - half3 worldSpaceViewDir; - half3 tangentSpaceViewDir; - float3x3 TBNMatrix; - float4 extraV2F0; - float4 extraV2F1; - float4 extraV2F2; - float4 screenPos; - }; - - MeshData CreateMeshData(FragmentData i) - { - MeshData m = (MeshData) 0; - m.uv0 = i.uv0; - m.uv1 = i.uv1; - m.uv2 = i.uv2; - m.uv3 = i.uv3; - m.worldNormal = normalize(i.worldNormal); - m.localSpacePosition = mul(unity_WorldToObject, float4(i.worldPos, 1)).xyz; - m.worldSpacePosition = i.worldPos; - m.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos); - - #if !defined(UNITY_PASS_SHADOWCASTER) - m.vertexColor = i.vertexColor; - m.normal = i.normal; - float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * - 1; - m.TBNMatrix = float3x3(normalize(i.worldTangent.xyz), bitangent, m.worldNormal); - m.tangentSpaceViewDir = mul(m.TBNMatrix, m.worldSpaceViewDir); - #endif - - #if defined(EXTRA_V2F_0) - m.extraV2F0 = i.extraV2F0; - #endif - #if defined(EXTRA_V2F_1) - m.extraV2F1 = i.extraV2F1; - #endif - #if defined(EXTRA_V2F_2) - m.extraV2F2 = i.extraV2F2; - #endif - #if defined(NEED_SCREEN_POS) - m.screenPos = i.screenPos; - #endif - - return m; - } - - struct SurfaceData - { - half3 Albedo; - half3 Emission; - half Metallic; - half Smoothness; - half Occlusion; - half3 Normal; - half Alpha; - }; - - struct TessellationFactors - { - float edge[3] : SV_TessFactor; - float inside : SV_InsideTessFactor; - }; - - struct TessVertex - { - float4 vertex : INTERNALTESSPOS; - float3 normal : NORMAL; - float4 tangent : TANGENT; - float4 color : COLOR; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; - float2 uv2 : TEXCOORD2; - float2 uv3 : TEXCOORD3; - UNITY_VERTEX_INPUT_INSTANCE_ID - UNITY_VERTEX_OUTPUT_STEREO - }; - - FragmentData FragData; - SurfaceData o; - MeshData d; - VertexData vD; - float4 FinalColor; - - half invLerp(half a, half b, half v) - { - return (v - a) / (b - a); - } - - half getBakedNoise(Texture2D noiseTex, SamplerState noiseTexSampler, half3 p) - { - half3 i = floor(p); p -= i; p *= p * (3. - 2. * p); - half2 uv = (p.xy + i.xy + half2(37, 17) * i.z + .5) / 256.; - uv.y *= -1; - p.xy = noiseTex.SampleLevel(noiseTexSampler, uv, 0).yx; - return lerp(p.x, p.y, p.z); - } - - half3 TransformObjectToWorld(half3 pos) - { - return mul(unity_ObjectToWorld, half4(pos, 1)).xyz; - }; - - // mostly taken from the Amplify shader reference - half2 POM(Texture2D heightMap, SamplerState heightSampler, half2 uvs, half2 dx, half2 dy, half3 normalWorld, half3 viewWorld, half3 viewDirTan, int minSamples, int maxSamples, half parallax, half refPlane, half2 tilling, half2 curv, int index, inout half finalHeight) - { - half3 result = 0; - int stepIndex = 0; - int numSteps = (int)lerp((half)maxSamples, (half)minSamples, saturate(dot(normalWorld, viewWorld))); - half layerHeight = 1.0 / numSteps; - half2 plane = parallax * (viewDirTan.xy / viewDirTan.z); - uvs.xy += refPlane * plane; - half2 deltaTex = -plane * layerHeight; - half2 prevTexOffset = 0; - half prevRayZ = 1.0f; - half prevHeight = 0.0f; - half2 currTexOffset = deltaTex; - half currRayZ = 1.0f - layerHeight; - half currHeight = 0.0f; - half intersection = 0; - half2 finalTexOffset = 0; - while (stepIndex < numSteps + 1) - { - currHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + currTexOffset, dx, dy).r; - if (currHeight > currRayZ) - { - stepIndex = numSteps + 1; - } - else - { - stepIndex++; - prevTexOffset = currTexOffset; - prevRayZ = currRayZ; - prevHeight = currHeight; - currTexOffset += deltaTex; - currRayZ -= layerHeight; - } - } - int sectionSteps = 2; - int sectionIndex = 0; - half newZ = 0; - half newHeight = 0; - while (sectionIndex < sectionSteps) - { - intersection = (prevHeight - prevRayZ) / (prevHeight - currHeight + currRayZ - prevRayZ); - finalTexOffset = prevTexOffset +intersection * deltaTex; - newZ = prevRayZ - intersection * layerHeight; - newHeight = SAMPLE_TEXTURE2D_GRAD(heightMap, heightSampler, uvs + finalTexOffset, dx, dy).r; - if (newHeight > newZ) - { - currTexOffset = finalTexOffset; - currHeight = newHeight; - currRayZ = newZ; - deltaTex = intersection * deltaTex; - layerHeight = intersection * layerHeight; - } - else - { - prevTexOffset = finalTexOffset; - prevHeight = newHeight; - prevRayZ = newZ; - deltaTex = (1 - intersection) * deltaTex; - layerHeight = (1 - intersection) * layerHeight; - } - sectionIndex++; - } - finalHeight = newHeight; - return uvs.xy + finalTexOffset; - } - - half remap(half s, half a1, half a2, half b1, half b2) - { - return b1 + (s - a1) * (b2 - b1) / (a2 - a1); - } - - half3 ApplyLut2D(Texture2D LUT2D, SamplerState lutSampler, half3 uvw) - { - half3 scaleOffset = half3(1.0 / 1024.0, 1.0 / 32.0, 31.0); - // Strip format where `height = sqrt(width)` - uvw.z *= scaleOffset.z; - half shift = floor(uvw.z); - uvw.xy = uvw.xy * scaleOffset.z * scaleOffset.xy + scaleOffset.xy * 0.5; - uvw.x += shift * scaleOffset.y; - uvw.xyz = lerp( - SAMPLE_TEXTURE2D(LUT2D, lutSampler, uvw.xy).rgb, - SAMPLE_TEXTURE2D(LUT2D, lutSampler, uvw.xy + half2(scaleOffset.y, 0.0)).rgb, - uvw.z - shift - ); - return uvw; - } - - half3 AdjustContrast(half3 color, half contrast) - { - color = saturate(lerp(half3(0.5, 0.5, 0.5), color, contrast)); - return color; - } - - half3 AdjustSaturation(half3 color, half saturation) - { - half3 intensity = dot(color.rgb, half3(0.299, 0.587, 0.114)); - color = lerp(intensity, color.rgb, saturation); - return color; - } - - half3 AdjustBrightness(half3 color, half brightness) - { - color += brightness; - return color; - } - - struct ParamsLogC - { - half cut; - half a, b, c, d, e, f; - }; - - static const ParamsLogC LogC = { - 0.011361, // cut - 5.555556, // a - 0.047996, // b - 0.244161, // c - 0.386036, // d - 5.301883, // e - 0.092819 // f - - }; - - half LinearToLogC_Precise(half x) - { - half o; - if (x > LogC.cut) - o = LogC.c * log10(LogC.a * x + LogC.b) + LogC.d; - else - o = LogC.e * x + LogC.f; - return o; - } - - half PositivePow(half base, half power) - { - return pow(max(abs(base), half(FLT_EPSILON)), power); - } - - half3 LinearToLogC(half3 x) - { - return LogC.c * log10(LogC.a * x + LogC.b) + LogC.d; - } - - half3 LinerToSRGB(half3 c) - { - return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878); - } - - half3 SRGBToLiner(half3 c) - { - return max(1.055 * PositivePow(c, 0.416666667) - 0.055, 0.0); - } - - half3 LogCToLinear(half3 c) - { - return (pow(10.0, (c - LogC.d) / LogC.c) - LogC.b) / LogC.a; - } - - // Specular stuff taken from https://github.com/z3y/shaders/ - float pow5(float x) - { - float x2 = x * x; - return x2 * x2 * x; - } - - float sq(float x) - { - return x * x; - } - - struct Gradient - { - int type; - int colorsLength; - int alphasLength; - half4 colors[8]; - half2 alphas[8]; - }; - - Gradient NewGradient(int type, int colorsLength, int alphasLength, - half4 colors0, half4 colors1, half4 colors2, half4 colors3, half4 colors4, half4 colors5, half4 colors6, half4 colors7, - half2 alphas0, half2 alphas1, half2 alphas2, half2 alphas3, half2 alphas4, half2 alphas5, half2 alphas6, half2 alphas7) - { - Gradient g; - g.type = type; - g.colorsLength = colorsLength; - g.alphasLength = alphasLength; - g.colors[ 0 ] = colors0; - g.colors[ 1 ] = colors1; - g.colors[ 2 ] = colors2; - g.colors[ 3 ] = colors3; - g.colors[ 4 ] = colors4; - g.colors[ 5 ] = colors5; - g.colors[ 6 ] = colors6; - g.colors[ 7 ] = colors7; - g.alphas[ 0 ] = alphas0; - g.alphas[ 1 ] = alphas1; - g.alphas[ 2 ] = alphas2; - g.alphas[ 3 ] = alphas3; - g.alphas[ 4 ] = alphas4; - g.alphas[ 5 ] = alphas5; - g.alphas[ 6 ] = alphas6; - g.alphas[ 7 ] = alphas7; - return g; - } - - half4 SampleGradient(Gradient gradient, half time) - { - half3 color = gradient.colors[0].rgb; - UNITY_UNROLL - for (int c = 1; c < 8; c++) - { - half colorPos = saturate((time - gradient.colors[c - 1].w) / (0.00001 + (gradient.colors[c].w - gradient.colors[c - 1].w)) * step(c, (half)gradient.colorsLength - 1)); - color = lerp(color, gradient.colors[c].rgb, lerp(colorPos, step(0.01, colorPos), gradient.type)); - } - #ifndef UNITY_COLORSPACE_GAMMA - color = half3(GammaToLinearSpaceExact(color.r), GammaToLinearSpaceExact(color.g), GammaToLinearSpaceExact(color.b)); - #endif - half alpha = gradient.alphas[0].x; - UNITY_UNROLL - for (int a = 1; a < 8; a++) - { - half alphaPos = saturate((time - gradient.alphas[a - 1].y) / (0.00001 + (gradient.alphas[a].y - gradient.alphas[a - 1].y)) * step(a, (half)gradient.alphasLength - 1)); - alpha = lerp(alpha, gradient.alphas[a].x, lerp(alphaPos, step(0.01, alphaPos), gradient.type)); - } - return half4(color, alpha); - } - - float3 RotateAroundAxis(float3 center, float3 original, float3 u, float angle) - { - original -= center; - float C = cos(angle); - float S = sin(angle); - float t = 1 - C; - float m00 = t * u.x * u.x + C; - float m01 = t * u.x * u.y - S * u.z; - float m02 = t * u.x * u.z + S * u.y; - float m10 = t * u.x * u.y + S * u.z; - float m11 = t * u.y * u.y + C; - float m12 = t * u.y * u.z - S * u.x; - float m20 = t * u.x * u.z - S * u.y; - float m21 = t * u.y * u.z + S * u.x; - float m22 = t * u.z * u.z + C; - float3x3 finalMatrix = float3x3(m00, m01, m02, m10, m11, m12, m20, m21, m22); - return mul(finalMatrix, original) + center; - } - - half3 UnpackNormalAG(half4 packedNormal, half scale = 1.0) - { - half3 normal; - normal.xy = packedNormal.ag * 2.0 - 1.0; - normal.z = max(1.0e-16, sqrt(1.0 - saturate(dot(normal.xy, normal.xy)))); - - normal.xy *= scale; - return normal; - } - - half D_GGX(half NoH, half roughness) - { - half a = NoH * roughness; - half k = roughness / (1.0 - NoH * NoH + a * a); - return k * k * (1.0 / UNITY_PI); - } - - half D_GGX_Anisotropic(half NoH, const half3 h, const half3 t, const half3 b, half at, half ab) - { - half ToH = dot(t, h); - half BoH = dot(b, h); - half a2 = at * ab; - half3 v = half3(ab * ToH, at * BoH, a2 * NoH); - half v2 = dot(v, v); - half w2 = a2 / v2; - return a2 * w2 * w2 * (1.0 / UNITY_PI); - } - - half V_SmithGGXCorrelated(half NoV, half NoL, half roughness) - { - half a2 = roughness * roughness; - half GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); - half GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); - return 0.5 / (GGXV + GGXL); - } - - half3 F_Schlick(half u, half3 f0) - { - return f0 + (1.0 - f0) * pow(1.0 - u, 5.0); - } - - half3 F_Schlick(half3 f0, half f90, half VoH) - { - // Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering" - return f0 + (f90 - f0) * pow(1.0 - VoH, 5); - } - - half3 fresnel(half3 f0, half LoH) - { - half f90 = saturate(dot(f0, half(50.0 / 3).xxx)); - return F_Schlick(f0, f90, LoH); - } - - half Fd_Burley(half perceptualRoughness, half NoV, half NoL, half LoH) - { - // Burley 2012, "Physically-Based Shading at Disney" - half f90 = 0.5 + 2.0 * perceptualRoughness * LoH * LoH; - half lightScatter = F_Schlick(1.0, f90, NoL); - half viewScatter = F_Schlick(1.0, f90, NoV); - return lightScatter * viewScatter; - } - - half3 getBoxProjection(half3 direction, half3 position, half4 cubemapPosition, half3 boxMin, half3 boxMax) - { - #if defined(UNITY_SPECCUBE_BOX_PROJECTION) && !defined(UNITY_PBS_USE_BRDF2) || defined(FORCE_BOX_PROJECTION) - if (cubemapPosition.w > 0) - { - half3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction; - half scalar = min(min(factors.x, factors.y), factors.z); - direction = direction * scalar + (position - cubemapPosition.xyz); - } - #endif - - return direction; - } - - half3 getEnvReflection(half3 worldSpaceViewDir, half3 worldSpacePosition, half3 normal, half smoothness, int mip) - { - half3 env = 0; - half3 reflDir = reflect(worldSpaceViewDir, normal); - half perceptualRoughness = 1 - smoothness; - half rough = perceptualRoughness * perceptualRoughness; - reflDir = lerp(reflDir, normal, rough * rough); - - half3 reflectionUV1 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, mip); - half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR); - - half3 indirectSpecular; - half interpolator = unity_SpecCube0_BoxMin.w; - - UNITY_BRANCH - if (interpolator < 0.99999) - { - half3 reflectionUV2 = getBoxProjection(reflDir, worldSpacePosition, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, mip); - half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR); - indirectSpecular = lerp(probe1sample, probe0sample, interpolator); - } - else - { - indirectSpecular = probe0sample; - } - - env = indirectSpecular; - return env; - } - - half3 EnvBRDFMultiscatter(half2 dfg, half3 f0) - { - return lerp(dfg.xxx, dfg.yyy, f0); - } - - half3 EnvBRDFApprox(half perceptualRoughness, half NoV, half3 f0) - { - half g = 1 - perceptualRoughness; - //https://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - half4 t = half4(1 / 0.96, 0.475, (0.0275 - 0.25 * 0.04) / 0.96, 0.25); - t *= half4(g, g, g, g); - t += half4(0, 0, (0.015 - 0.75 * 0.04) / 0.96, 0.75); - half a0 = t.x * min(t.y, exp2(-9.28 * NoV)) + t.z; - half a1 = t.w; - return saturate(lerp(a0, a1, f0)); - } - - half GSAA_Filament(half3 worldNormal, half perceptualRoughness, half inputVariance, half threshold) - { - // Kaplanyan 2016, "Stable specular highlights" - // Tokuyoshi 2017, "Error Reduction and Simplification for Shading Anti-Aliasing" - // Tokuyoshi and Kaplanyan 2019, "Improved Geometric Specular Antialiasing" - - // This implementation is meant for deferred rendering in the original paper but - // we use it in forward rendering as well (as discussed in Tokuyoshi and Kaplanyan - // 2019). The main reason is that the forward version requires an expensive transform - // of the half vector by the tangent frame for every light. This is therefore an - // approximation but it works well enough for our needs and provides an improvement - // over our original implementation based on Vlachos 2015, "Advanced VR Rendering". - - half3 du = ddx(worldNormal); - half3 dv = ddy(worldNormal); - - half variance = inputVariance * (dot(du, du) + dot(dv, dv)); - - half roughness = perceptualRoughness * perceptualRoughness; - half kernelRoughness = min(2.0 * variance, threshold); - half squareRoughness = saturate(roughness * roughness + kernelRoughness); - - return sqrt(sqrt(squareRoughness)); - } - - // w0, w1, w2, and w3 are the four cubic B-spline basis functions - half w0(half a) - { - // return (1.0f/6.0f)*(-a*a*a + 3.0f*a*a - 3.0f*a + 1.0f); - return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f); // optimized - - } - - half w1(half a) - { - // return (1.0f/6.0f)*(3.0f*a*a*a - 6.0f*a*a + 4.0f); - return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f); - } - - half w2(half a) - { - // return (1.0f/6.0f)*(-3.0f*a*a*a + 3.0f*a*a + 3.0f*a + 1.0f); - return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f); - } - - half w3(half a) - { - return (1.0f / 6.0f) * (a * a * a); - } - - // g0 and g1 are the two amplitude functions - half g0(half a) - { - return w0(a) + w1(a); - } - - half g1(half a) - { - return w2(a) + w3(a); - } - - // h0 and h1 are the two offset functions - half h0(half a) - { - // note +0.5 offset to compensate for CUDA linear filtering convention - return -1.0f + w1(a) / (w0(a) + w1(a)) + 0.5f; - } - - half h1(half a) - { - return 1.0f + w3(a) / (w2(a) + w3(a)) + 0.5f; - } - - //https://ndotl.wordpress.com/2018/08/29/baking-artifact-free-lightmaps - half3 tex2DFastBicubicLightmap(half2 uv, inout half4 bakedColorTex) - { - #if !defined(PLAT_QUEST) && defined(BICUBIC_LIGHTMAP) - half width; - half height; - unity_Lightmap.GetDimensions(width, height); - half x = uv.x * width; - half y = uv.y * height; - - x -= 0.5f; - y -= 0.5f; - half px = floor(x); - half py = floor(y); - half fx = x - px; - half fy = y - py; - - // note: we could store these functions in a lookup table texture, but maths is cheap - half g0x = g0(fx); - half g1x = g1(fx); - half h0x = h0(fx); - half h1x = h1(fx); - half h0y = h0(fy); - half h1y = h1(fy); - - half4 r = g0(fy) * (g0x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h0x, py + h0y) * 1.0f / width)) + - g1x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h1x, py + h0y) * 1.0f / width))) + - g1(fy) * (g0x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h0x, py + h1y) * 1.0f / width)) + - g1x * UNITY_SAMPLE_TEX2D(unity_Lightmap, (half2(px + h1x, py + h1y) * 1.0f / width))); - bakedColorTex = r; - return DecodeLightmap(r); - #else - bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, uv); - return DecodeLightmap(bakedColorTex); - #endif - } - - half3 GetSpecularHighlights(half3 worldNormal, half3 lightColor, half3 lightDirection, half3 f0, half3 viewDir, half clampedRoughness, half NoV, half3 energyCompensation) - { - half3 halfVector = Unity_SafeNormalize(lightDirection + viewDir); - - half NoH = saturate(dot(worldNormal, halfVector)); - half NoL = saturate(dot(worldNormal, lightDirection)); - half LoH = saturate(dot(lightDirection, halfVector)); - - half3 F = F_Schlick(LoH, f0); - half D = D_GGX(NoH, clampedRoughness); - half V = V_SmithGGXCorrelated(NoV, NoL, clampedRoughness); - - #ifndef UNITY_PBS_USE_BRDF2 - F *= energyCompensation; - #endif - - return max(0, (D * V) * F) * lightColor * NoL * UNITY_PI; - } - - #ifdef DYNAMICLIGHTMAP_ON - half3 getRealtimeLightmap(half2 uv, half3 worldNormal) - { - half2 realtimeUV = uv; - half4 bakedCol = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, realtimeUV); - half3 realtimeLightmap = DecodeRealtimeLightmap(bakedCol); - - #ifdef DIRLIGHTMAP_COMBINED - half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, realtimeUV); - realtimeLightmap += DecodeDirectionalLightmap(realtimeLightmap, realtimeDirTex, worldNormal); - #endif - - return realtimeLightmap; - } - #endif - - half computeSpecularAO(half NoV, half ao, half roughness) - { - return clamp(pow(NoV + ao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ao, 0.0, 1.0); - } - - half shEvaluateDiffuseL1Geomerics_local(half L0, half3 L1, half3 n) - { - // average energy - half R0 = L0; - - // avg direction of incoming light - half3 R1 = 0.5f * L1; - - // directional brightness - half lenR1 = length(R1); - - // linear angle between normal and direction 0-1 - //half q = 0.5f * (1.0f + dot(R1 / lenR1, n)); - //half q = dot(R1 / lenR1, n) * 0.5 + 0.5; - half q = dot(normalize(R1), n) * 0.5 + 0.5; - q = saturate(q); // Thanks to ScruffyRuffles for the bug identity. - - // power for q - // lerps from 1 (linear) to 3 (cubic) based on directionality - half p = 1.0f + 2.0f * lenR1 / R0; - - // dynamic range constant - // should vary between 4 (highly directional) and 0 (ambient) - half a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0); - - return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p)); - } - - // https://assetstore.unity.com/packages/tools/level-design/bakery-gpu-lightmapper-122218 - - #if defined(BAKERY_ENABLED) - - //float2 bakeryLightmapSize; - #define BAKERYMODE_DEFAULT 0 - #define BAKERYMODE_VERTEXLM 1.0f - #define BAKERYMODE_RNM 2.0f - #define BAKERYMODE_SH 3.0f - - #define rnmBasis0 float3(0.816496580927726f, 0, 0.5773502691896258f) - #define rnmBasis1 float3(-0.4082482904638631f, 0.7071067811865475f, 0.5773502691896258f) - #define rnmBasis2 float3(-0.4082482904638631f, -0.7071067811865475f, 0.5773502691896258f) - - #if defined(BAKERY_DOMINANT) - #undef BAKERY_RNM - #undef BAKERY_SH - #undef BAKERY_MONOSH - #endif - - #ifdef BICUBIC_LIGHTMAP - #define BAKERY_BICUBIC - #endif - - //#define BAKERY_SSBUMP - - // can't fit vertexLM SH to sm3_0 interpolators - #ifndef SHADER_API_D3D11 - #undef BAKERY_VERTEXLMSH - #endif - - // can't do stuff on sm2_0 due to standard shader alrady taking up all instructions - #if SHADER_TARGET < 30 - #undef BAKERY_BICUBIC - #undef BAKERY_LMSPEC - - #undef BAKERY_RNM - #undef BAKERY_SH - #undef BAKERY_MONOSH - #undef BAKERY_VERTEXLM - #endif - - #if !defined(BAKERY_SH) && !defined(BAKERY_RNM) - #undef BAKERY_BICUBIC - #endif - - #ifndef UNITY_SHOULD_SAMPLE_SH - #undef BAKERY_PROBESHNONLINEAR - #endif - - #if defined(BAKERY_RNM) && defined(BAKERY_LMSPEC) - #define BAKERY_RNMSPEC - #endif - - #ifndef BAKERY_VERTEXLM - #undef BAKERY_VERTEXLMDIR - #undef BAKERY_VERTEXLMSH - #undef BAKERY_VERTEXLMMASK - #endif - - #define lumaConv float3(0.2125f, 0.7154f, 0.0721f) - - #if defined(BAKERY_SH) || defined(BAKERY_MONOSH) || defined(BAKERY_VERTEXLMSH) || defined(BAKERY_PROBESHNONLINEAR) || defined(BAKERY_VOLUME) - float shEvaluateDiffuseL1Geomerics(float L0, float3 L1, float3 n) - { - // average energy - float R0 = L0; - - // avg direction of incoming light - float3 R1 = 0.5f * L1; - - // directional brightness - float lenR1 = length(R1); - - // linear angle between normal and direction 0-1 - //float q = 0.5f * (1.0f + dot(R1 / lenR1, n)); - //float q = dot(R1 / lenR1, n) * 0.5 + 0.5; - float q = dot(normalize(R1), n) * 0.5 + 0.5; - - // power for q - // lerps from 1 (linear) to 3 (cubic) based on directionality - float p = 1.0f + 2.0f * lenR1 / R0; - - // dynamic range constant - // should vary between 4 (highly directional) and 0 (ambient) - float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0); - - return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p)); - } - #endif - - #ifdef BAKERY_VERTEXLM - float4 unpack4NFloats(float src) { - //return fmod(float4(src / 262144.0, src / 4096.0, src / 64.0, src), 64.0)/64.0; - return frac(float4(src / (262144.0*64), src / (4096.0*64), src / (64.0*64), src)); - } - float3 unpack3NFloats(float src) { - float r = frac(src); - float g = frac(src * 256.0); - float b = frac(src * 65536.0); - return float3(r, g, b); - } - #if defined(BAKERY_VERTEXLMDIR) - - #ifdef BAKERY_MONOSH - void BakeryVertexLMMonoSH(inout float3 diffuseColor, inout float3 specularColor, float3 nL1, float3 normalWorld, float3 viewDir, float smoothness) - { - nL1 = nL1; - float3 L0 = diffuseColor; - float3 L1x = nL1.x * L0 * 2; - float3 L1y = nL1.y * L0 * 2; - float3 L1z = nL1.z * L0 * 2; - - float3 sh; - #if BAKERY_SHNONLINEAR - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - float lumaL0 = dot(L0, 1); - float lumaL1x = dot(L1x, 1); - float lumaL1y = dot(L1y, 1); - float lumaL1z = dot(L1z, 1); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = nL1; - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - - void BakeryVertexLMDirection(inout float3 diffuseColor, inout float3 specularColor, float3 lightDirection, float3 vertexNormalWorld, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 dominantDir = Unity_SafeNormalize(lightDirection); - half halfLambert = dot(normalWorld, dominantDir) * 0.5 + 0.5; - half flatNormalHalfLambert = dot(vertexNormalWorld, dominantDir) * 0.5 + 0.5; - - #ifdef BAKERY_LMSPEC - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = spec * diffuseColor; - #endif - - diffuseColor *= halfLambert / max(1e-4h, flatNormalHalfLambert); - } - #elif defined(BAKERY_VERTEXLMSH) - void BakeryVertexLMSH(inout float3 diffuseColor, inout float3 specularColor, float3 shL1x, float3 shL1y, float3 shL1z, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 L0 = diffuseColor; - float3 nL1x = shL1x; - float3 nL1y = shL1y; - float3 nL1z = shL1z; - float3 L1x = nL1x * L0 * 2; - float3 L1y = nL1y * L0 * 2; - float3 L1z = nL1z * L0 * 2; - - float3 sh; - #ifdef BAKERY_SHNONLINEAR - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - float lumaL0 = dot(L0, 1); - float lumaL1x = dot(L1x, 1); - float lumaL1y = dot(L1y, 1); - float lumaL1z = dot(L1z, 1); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - #endif - - #ifdef BAKERY_BICUBIC - float BakeryBicubic_w0(float a) - { - return (1.0f/6.0f)*(a*(a*(-a + 3.0f) - 3.0f) + 1.0f); - } - - float BakeryBicubic_w1(float a) - { - return (1.0f/6.0f)*(a*a*(3.0f*a - 6.0f) + 4.0f); - } - - float BakeryBicubic_w2(float a) - { - return (1.0f/6.0f)*(a*(a*(-3.0f*a + 3.0f) + 3.0f) + 1.0f); - } - - float BakeryBicubic_w3(float a) - { - return (1.0f/6.0f)*(a*a*a); - } - - float BakeryBicubic_g0(float a) - { - return BakeryBicubic_w0(a) + BakeryBicubic_w1(a); - } - - float BakeryBicubic_g1(float a) - { - return BakeryBicubic_w2(a) + BakeryBicubic_w3(a); - } - - float BakeryBicubic_h0(float a) - { - return -1.0f + BakeryBicubic_w1(a) / (BakeryBicubic_w0(a) + BakeryBicubic_w1(a)) + 0.5f; - } - - float BakeryBicubic_h1(float a) - { - return 1.0f + BakeryBicubic_w3(a) / (BakeryBicubic_w2(a) + BakeryBicubic_w3(a)) + 0.5f; - } - #endif - - #if defined(BAKERY_RNM) || defined(BAKERY_SH) - sampler2D _RNM0, _RNM1, _RNM2; - float4 _RNM0_TexelSize; - #endif - - #ifdef BAKERY_VOLUME - Texture3D _Volume0, _Volume1, _Volume2, _VolumeMask; - SamplerState sampler_Volume0; - - #ifndef PROPERTIES_DEFINED - float3 _VolumeMin, _VolumeInvSize; - float3 _GlobalVolumeMin, _GlobalVolumeInvSize; - #endif - - #endif - - #ifdef BAKERY_BICUBIC - // Bicubic - float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) - { - float x = uv.x * texelSize.z; - float y = uv.y * texelSize.z; - - x -= 0.5f; - y -= 0.5f; - - float px = floor(x); - float py = floor(y); - - float fx = x - px; - float fy = y - py; - - float g0x = BakeryBicubic_g0(fx); - float g1x = BakeryBicubic_g1(fx); - float h0x = BakeryBicubic_h0(fx); - float h1x = BakeryBicubic_h1(fx); - float h0y = BakeryBicubic_h0(fy); - float h1y = BakeryBicubic_h1(fy); - - return BakeryBicubic_g0(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h0y) * texelSize.x)) + - g1x * tex2D(tex, (float2(px + h1x, py + h0y) * texelSize.x))) + - - BakeryBicubic_g1(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h1y) * texelSize.x)) + - g1x * tex2D(tex, (float2(px + h1x, py + h1y) * texelSize.x))); - } - float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) - { - float x = uv.x * texelSize.z; - float y = uv.y * texelSize.z; - - x -= 0.5f; - y -= 0.5f; - - float px = floor(x); - float py = floor(y); - - float fx = x - px; - float fy = y - py; - - float g0x = BakeryBicubic_g0(fx); - float g1x = BakeryBicubic_g1(fx); - float h0x = BakeryBicubic_h0(fx); - float h1x = BakeryBicubic_h1(fx); - float h0y = BakeryBicubic_h0(fy); - float h1y = BakeryBicubic_h1(fy); - - return BakeryBicubic_g0(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h0y) * texelSize.x)) + - g1x * tex.Sample(s, (float2(px + h1x, py + h0y) * texelSize.x))) + - - BakeryBicubic_g1(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h1y) * texelSize.x)) + - g1x * tex.Sample(s, (float2(px + h1x, py + h1y) * texelSize.x))); - } - #else - // Bilinear - float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) - { - return tex2D(tex, uv); - } - float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) - { - return tex.Sample(s, uv); - } - #endif - - #ifdef DIRLIGHTMAP_COMBINED - #ifdef BAKERY_LMSPEC - float BakeryDirectionalLightmapSpecular(float2 lmUV, float3 normalWorld, float3 viewDir, float smoothness) - { - float3 dominantDir = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lmUV).xyz * 2 - 1; - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - return spec; - } - #endif - #endif - - #ifdef BAKERY_RNM - void BakeryRNM(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalMap, float perceptualRoughness, float3 viewDirT) - { - normalMap.g *= -1; - float3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize)); - float3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize)); - float3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize)); - - #ifdef BAKERY_SSBUMP - diffuseColor = normalMap.x * rnm0 - + normalMap.z * rnm1 - + normalMap.y * rnm2; - diffuseColor *= 2; - #else - diffuseColor = saturate(dot(rnmBasis0, normalMap)) * rnm0 - + saturate(dot(rnmBasis1, normalMap)) * rnm1 - + saturate(dot(rnmBasis2, normalMap)) * rnm2; - #endif - - #ifdef BAKERY_LMSPEC - float3 dominantDirT = rnmBasis0 * dot(rnm0, lumaConv) + - rnmBasis1 * dot(rnm1, lumaConv) + - rnmBasis2 * dot(rnm2, lumaConv); - - float3 dominantDirTN = normalize(dominantDirT); - float3 specColor = saturate(dot(rnmBasis0, dominantDirTN)) * rnm0 + - saturate(dot(rnmBasis1, dominantDirTN)) * rnm1 + - saturate(dot(rnmBasis2, dominantDirTN)) * rnm2; - - half3 halfDir = Unity_SafeNormalize(dominantDirTN - viewDirT); - half nh = saturate(dot(normalMap, halfDir)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - specularColor = spec * specColor; - #endif - } - #endif - - #ifdef BAKERY_SH - void BakerySH(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalWorld, float3 viewDir, float perceptualRoughness) - { - #ifdef SHADER_API_D3D11 - float3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, samplerunity_Lightmap, lmUV, _RNM0_TexelSize)); - #else - float3 L0 = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, lmUV)); - #endif - float3 nL1x = BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 nL1y = BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 nL1z = BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize) * 2 - 1; - float3 L1x = nL1x * L0 * 2; - float3 L1y = nL1y * L0 * 2; - float3 L1z = nL1z * L0 * 2; - - float3 sh; - #ifdef BAKERY_SHNONLINEAR - float lumaL0 = dot(L0, float(1)); - float lumaL1x = dot(L1x, float(1)); - float lumaL1y = dot(L1y, float(1)); - float lumaL1z = dot(L1z, float(1)); - float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); - - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - float regularLumaSH = dot(sh, 1); - //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); - sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - - //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); - //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); - //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); - - #else - sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; - #endif - - diffuseColor = max(sh, 0.0); - - #ifdef BAKERY_LMSPEC - float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); - float focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); - half nh = saturate(dot(normalWorld, halfDir)); - half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); - half spec = GGXTerm(nh, roughness); - - sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - - specularColor = max(spec * sh, 0.0); - #endif - } - #endif - - #endif - //BAKERY_ENABLED - - #if defined(NEED_DEPTH) - UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); - #endif - - half _Smoothness; - half _Metallic; - half _OcclusionStrength; - half _BumpScale; - half _HeightScale; - half _HeightRefPlane; - half _HeightStepsMin; - half _HeightStepsMax; - half _DAlbedoScale; - half _DNormalScale; - half _DSmoothScale; - half _VertexHeightAmount; - half _VertexHeightOffset; - half _TessFactor; - half _TessMinDist; - half _TessMaxDist; - half _TessEdgeLength; - half _TessMaxDisplacement; - half _SpecOcclusion; - half _SpecularRoughnessMod; - half2 GLOBAL_uv; - half4 _Color; - half4 _MainTex_ST; - half4 _MetallicRemap; - half4 _SmoothnessRemap; - half4 _MaskMap_TexelSize; - half4 _EmissionColor; - half4 GLOBAL_maskMap; - half4 _DDetailsMap_ST; - float _GSAAVariance; - float _GSAAThreshold; - int _AlbedoChannel; - int _MappingSpace; - int _PlanarAxisX; - int _PlanarAxisY; - int _MetalChannel; - int _AOChannel; - int _DetailMaskChannel; - int _SmoothChannel; - int _RoughnessMode; - int _DetailAsTintMask; - int _FlipBumpY; - int _EmissionChannel; - TEXTURE2D(_MainTex); - SAMPLER(sampler_MainTex); - TEXTURE2D(_MaskMap); - SAMPLER(sampler_MaskMap); - TEXTURE2D(_BumpMap); - SAMPLER(sampler_BumpMap); - TEXTURE2D(_EmissionMap); - SAMPLER(sampler_EmissionMap); - TEXTURE2D(_Height); - SAMPLER(sampler_Height); - int _DIgnoreMask; - int _DMappingSpace; - int _DUVChannel; - int _DPlanarAxisX; - int _DPlanarAxisY; - int _DNormalFlipY; - TEXTURE2D(_DDetailsMap); - SAMPLER(sampler_DDetailsMap); - TEXTURE2D(_DDetailsNormal); - SAMPLER(sampler_DDetailsNormal); - TEXTURE2D(_VertexHeight); - SAMPLER(sampler_VertexHeight); - TEXTURE2D(_DFG); - SAMPLER(sampler_DFG); - - void VHVertex() { - half2 uv = vD.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - half height = (SAMPLE_TEXTURE2D_LOD(_VertexHeight, sampler_VertexHeight, uv, 0).r * 2 - 1); - half3 mainOffset = vD.vertex.xyz + vD.normal * (height + _VertexHeightOffset) * _VertexHeightAmount; - vD.vertex.xyz = mainOffset; - } - - void ParallaxFragment() - { - GLOBAL_uv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - #if PARALLAX && !defined(PLAT_QUEST) - half customHeight = 0; - GLOBAL_uv = POM(_Height, sampler_Height, GLOBAL_uv, ddx(GLOBAL_uv), ddy(GLOBAL_uv), d.worldNormal, d.worldSpaceViewDir, d.tangentSpaceViewDir, _HeightStepsMin, _HeightStepsMax, _HeightScale, _HeightRefPlane, half2(1, 1), half2(0, 0), 0, customHeight); - #endif - } - - void BaseFragmentFunction() - { - #if !defined(_SET_GLOBAL_UVS) - GLOBAL_uv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - #endif - if (_MappingSpace > 0) - { - GLOBAL_uv = (_MappingSpace - 1) ? half2(d.worldSpacePosition[_PlanarAxisX], d.worldSpacePosition[_PlanarAxisY]) : half2(d.localSpacePosition[_PlanarAxisX], d.localSpacePosition[_PlanarAxisY]); - GLOBAL_uv = GLOBAL_uv * _MainTex_ST.xy + _MainTex_ST.zw; - } - half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, GLOBAL_uv); - if (_AlbedoChannel > 0) - { - albedo.rgb = albedo[_AlbedoChannel].xxx; - } - half4 masks = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, GLOBAL_uv); - half4 normalTex = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, GLOBAL_uv); - if (_FlipBumpY) - { - normalTex.y = 1 - normalTex.y; - } - half3 normal = UnpackScaleNormal(normalTex, _BumpScale); - half3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, GLOBAL_uv).rgb; - if (_EmissionChannel > 0) - { - emission.rgb = emission[_EmissionChannel].xxx; - } - int hasMasks = _MaskMap_TexelSize.z > 8; - half metal = masks[_MetalChannel]; - half smooth = masks[_SmoothChannel]; - if (_RoughnessMode) - { - smooth = 1 - smooth; - } - half detailMask = masks[_DetailMaskChannel]; - half occlusion = masks[_AOChannel]; - metal = remap(metal, 0, 1, _MetallicRemap.x, _MetallicRemap.y); - smooth = remap(smooth, 0, 1, _SmoothnessRemap.x, _SmoothnessRemap.y); - GLOBAL_maskMap = half4(metal, occlusion, detailMask, smooth); - o.Metallic = lerp(_Metallic, metal, hasMasks); - o.Smoothness = lerp(_Smoothness, smooth, hasMasks); - o.Occlusion = lerp(1, occlusion, _OcclusionStrength); - o.Normal = normal; - if (!_DetailAsTintMask) - { - o.Albedo = albedo.rgb * _Color.rgb; - } - else - { - o.Albedo = lerp(albedo, albedo.rgb * _Color.rgb, detailMask); - } - o.Alpha = albedo.a * _Color.a; - #if defined(_EMISSION) - o.Emission = emission * _EmissionColor; - #endif - } - - void DetailsFragment() - { - #if defined(DETAILS_OVERLAY) - half masks = 0; - #if defined(_MASKMAP_SAMPLED) - masks = GLOBAL_maskMap.b; - #else - masks = 1; - #endif - half mask = lerp(masks, 1, _DIgnoreMask); - half2 uv = d.uv0.xy; - switch(_DUVChannel) - { - case 1: uv = d.uv1.xy; break; - case 2: uv = d.uv2.xy; break; - case 3: uv = d.uv3.xy; break; - default: uv = d.uv0.xy; break; - } - uv = uv * _DDetailsMap_ST.xy + _DDetailsMap_ST.zw; - if (_DMappingSpace > 0) - { - uv = (_DMappingSpace - 1) ? half2(d.worldSpacePosition[_DPlanarAxisX], d.worldSpacePosition[_DPlanarAxisY]) : half2(d.localSpacePosition[_DPlanarAxisX], d.localSpacePosition[_DPlanarAxisY]); - uv = uv * _DDetailsMap_ST.xy + _DDetailsMap_ST.zw; - } - - half4 detailsMap = SAMPLE_TEXTURE2D(_DDetailsMap, sampler_DDetailsMap, uv); - - #if defined(DETAILS_MODE_PACKED) - half detailAlbedo = detailsMap.r * 2.0 - 1.0; - half detailSmooth = detailsMap.b * 2.0 - 1.0; - half3 detailNormal = 0; - if (_DNormalFlipY) - { - detailsMap.g = 1 - detailsMap.g; - } - detailNormal = UnpackNormalAG(detailsMap, _DNormalScale); - half detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); - #elif defined(DETAILS_MODE_SEPARATED) - half3 detailAlbedo = detailsMap.rgb * 2.0 - 1.0; - half detailSmooth = detailsMap.a * 2.0 - 1.0; - - half4 packedNormal = SAMPLE_TEXTURE2D(_DDetailsNormal, sampler_DDetailsNormal, uv); - if (_DNormalFlipY) - { - packedNormal.g = 1 - packedNormal.g; - } - half3 detailNormal = UnpackScaleNormal(packedNormal, _DNormalScale); - - half3 detailAlbedoSpeed = saturate(abs(detailAlbedo) * _DAlbedoScale); - #endif - - half3 albedoOverlay = lerp(sqrt(o.Albedo), (detailAlbedo < 0.0) ? 0.0.xxx : 1.0.xxx, detailAlbedoSpeed * detailAlbedoSpeed); - albedoOverlay *= albedoOverlay; - o.Albedo = lerp(o.Albedo, saturate(albedoOverlay), mask); - - half detailSmoothSpeed = saturate(abs(detailSmooth) * _DSmoothScale); - half smoothOverlay = lerp(o.Smoothness, (detailSmooth < 0.0) ? 0.0 : 1.0, detailSmoothSpeed * detailSmoothSpeed); - o.Smoothness = lerp(o.Smoothness, saturate(smoothOverlay), mask); - - o.Normal = lerp(o.Normal, BlendNormals(o.Normal, detailNormal), mask); - #endif - } - - void ORLLighting() - { - #if !defined(UNITY_PASS_SHADOWCASTER) - half reflectance = 0.5; - half3 f0 = 0.16 * reflectance * reflectance * (1 - o.Metallic) + o.Albedo * o.Metallic; - half3 pixelLight = 0; - half3 indirectDiffuse = 1; - half3 indirectSpecular = 0; - half3 directSpecular = 0; - half occlusion = o.Occlusion; - half perceptualRoughness = 1 - o.Smoothness; - half3 tangentNormal = o.Normal; - o.Normal = normalize(mul(o.Normal, d.TBNMatrix)); - - #ifndef USING_DIRECTIONAL_LIGHT - fixed3 lightDir = normalize(UnityWorldSpaceLightDir(d.worldSpacePosition)); - #else - fixed3 lightDir = _WorldSpaceLightPos0.xyz; - #endif - - #if defined(GSAA) - perceptualRoughness = GSAA_Filament(o.Normal, perceptualRoughness, _GSAAVariance, _GSAAThreshold); - #endif - - UNITY_LIGHT_ATTENUATION(lightAttenuation, FragData, d.worldSpacePosition); - half3 lightColor = lightAttenuation * _LightColor0.rgb; - - half3 lightHalfVector = Unity_SafeNormalize(lightDir + d.worldSpaceViewDir); - half lightNoL = saturate(dot(o.Normal, lightDir)); - half lightLoH = saturate(dot(lightDir, lightHalfVector)); - - half NoV = abs(dot(o.Normal, d.worldSpaceViewDir)) + 1e-5; - pixelLight = lightNoL * lightColor * Fd_Burley(perceptualRoughness, NoV, lightNoL, lightLoH); - - // READ THE LIGHTMAP - #if defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) - half3 lightMap = 0; - half4 bakedColorTex = 0; - half2 lightmapUV = FragData.lightmapUv.xy; - - // UNITY LIGHTMAPPING - #if !defined(BAKERYLM_ENABLED) || !defined(BAKERY_ENABLED) - lightMap = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); - #endif - - // BAKERY RNM MODE (why do we even support it??) - #if defined(BAKERY_RNM) && defined(BAKERY_ENABLED) - half3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, lightmapUV, _RNM0_TexelSize)); - half3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, lightmapUV, _RNM0_TexelSize)); - half3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, lightmapUV, _RNM0_TexelSize)); - - lightMap = saturate(dot(rnmBasis0, tangentNormal)) * rnm0 + - saturate(dot(rnmBasis1, tangentNormal)) * rnm1 + - saturate(dot(rnmBasis2, tangentNormal)) * rnm2; - #endif - - // BAKERY SH MODE (these are also used for the specular) - #if defined(BAKERY_SH) && defined(BAKERY_ENABLED) - half3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, samplerunity_Lightmap, lightmapUV, _RNM0_TexelSize)); - - half3 nL1x = BakeryTex2D(_RNM0, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 nL1y = BakeryTex2D(_RNM1, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 nL1z = BakeryTex2D(_RNM2, lightmapUV, _RNM0_TexelSize) * 2.0 - 1.0; - half3 L1x = nL1x * L0 * 2.0; - half3 L1y = nL1y * L0 * 2.0; - half3 L1z = nL1z * L0 * 2.0; - - // Non-Linear mode - #if defined(BAKERY_SHNONLINEAR) - half lumaL0 = dot(L0, half(1)); - half lumaL1x = dot(L1x, half(1)); - half lumaL1y = dot(L1y, half(1)); - half lumaL1z = dot(L1z, half(1)); - half lumaSH = shEvaluateDiffuseL1Geomerics_local(lumaL0, half3(lumaL1x, lumaL1y, lumaL1z), o.Normal); - - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - half regularLumaSH = dot(lightMap, 1.0); - lightMap *= lerp(1.0, lumaSH / regularLumaSH, saturate(regularLumaSH * 16.0)); - #else - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - #endif - - #endif - - #if defined(DIRLIGHTMAP_COMBINED) - half4 lightMapDirection = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lightmapUV); - #if !defined(BAKERY_MONOSH) - lightMap = DecodeDirectionalLightmap(lightMap, lightMapDirection, o.Normal); - #endif - #endif - - #if defined(BAKERY_MONOSH) && defined(BAKERY_ENABLED) && defined(DIRLIGHTMAP_COMBINED) - half3 L0 = tex2DFastBicubicLightmap(lightmapUV, bakedColorTex); - half3 nL1 = lightMapDirection.xyz * 2.0 - 1.0; - half3 L1x = nL1.x * L0 * 2.0; - half3 L1y = nL1.y * L0 * 2.0; - half3 L1z = nL1.z * L0 * 2.0; - - #if defined(BAKERY_SHNONLINEAR) - half lumaL0 = dot(L0, 1); - half lumaL1x = dot(L1x, 1); - half lumaL1y = dot(L1y, 1); - half lumaL1z = dot(L1z, 1); - half lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, half3(lumaL1x, lumaL1y, lumaL1z), o.Normal); - - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - half regularLumaSH = dot(lightMap, 1); - lightMap *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); - #else - lightMap = L0 + o.Normal.x * L1x + o.Normal.y * L1y + o.Normal.z * L1z; - #endif - - lightMap = max(lightMap, 0.0); - #endif - - #if defined(DYNAMICLIGHTMAP_ON) && !defined(UNITY_PBS_USE_BRDF2) - half3 realtimeLightMap = getRealtimeLightmap(FragData.lightmapUv.zw, o.Normal); - lightMap += realtimeLightMap; - #endif - - #if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) - pixelLight = 0; - lightMap = SubtractMainLightWithRealtimeAttenuationFrowmLightmap(lightMap, lightAttenuation, bakedColorTex, o.Normal); - #endif - indirectDiffuse = lightMap; - #else - #if UNITY_LIGHT_PROBE_PROXY_VOLUME - UNITY_BRANCH - if (unity_ProbeVolumeParams.x == 1) - { - indirectDiffuse = SHEvalLinearL0L1_SampleProbeVolume(half4(o.Normal, 1), FragData.worldPos); - } - else - { - #endif - indirectDiffuse = max(0, ShadeSH9(half4(o.Normal, 1))); - #if UNITY_LIGHT_PROBE_PROXY_VOLUME - } - #endif - #endif - - #if defined(LIGHTMAP_SHADOW_MIXING) && defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN) && defined(LIGHTMAP_ON) && !defined(UNITY_PASS_FORWARDADD) - pixelLight *= UnityComputeForwardShadows(FragData.lightmapUv.xy, d.worldSpacePosition, d.screenPos); - #endif - - half3 dfguv = half3(NoV, perceptualRoughness, 0); - half2 dfg = SAMPLE_TEXTURE2D(_DFG, sampler_DFG, dfguv).xy; - half3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0); - - half rough = perceptualRoughness * perceptualRoughness; - half clampedRoughness = max(rough, 0.002); - - #if !defined(SPECULAR_HIGHLIGHTS_OFF) && defined(USING_LIGHT_MULTI_COMPILE) - half NoH = saturate(dot(o.Normal, lightHalfVector)); - half3 F = F_Schlick(lightLoH, f0); - half D = D_GGX(NoH, clampedRoughness); - half V = V_SmithGGXCorrelated(NoV, lightNoL, clampedRoughness); - - F *= energyCompensation; - - directSpecular = max(0, D * V * F) * pixelLight * UNITY_PI; - #endif - - // BAKED SPECULAR - #if defined(BAKED_SPECULAR) && !defined(BAKERYLM_ENABLED) && !defined(UNITY_PASS_FORWARDADD) - { - half3 bakedDominantDirection = 1; - half3 bakedSpecularColor = 0; - - // only do it if we have a directional lightmap - #if defined(DIRLIGHTMAP_COMBINED) && defined(LIGHTMAP_ON) - bakedDominantDirection = (lightMapDirection.xyz) * 2 - 1; - half directionality = max(0.001, length(bakedDominantDirection)); - bakedDominantDirection /= directionality; - bakedSpecularColor = indirectDiffuse; - #endif - - // if we do not have lightmap - derive the specular from probes - //#ifndef LIGHTMAP_ON - //bakedSpecularColor = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); - //bakedDominantDirection = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz; - // #endif - - bakedDominantDirection = normalize(bakedDominantDirection); - directSpecular += GetSpecularHighlights(o.Normal, bakedSpecularColor, bakedDominantDirection, f0, d.worldSpaceViewDir, lerp(1, clampedRoughness, _SpecularRoughnessMod), NoV, energyCompensation); - } - #endif - - half3 fresnel = F_Schlick(NoV, f0); - - // BAKERY DIRECT SPECULAR - #if defined(BAKERY_LMSPEC) && defined(BAKERY_ENABLED) && !defined(UNITY_PASS_FORWARDADD) - #if defined(BAKERY_RNM) - { - half3 viewDirTangent = -normalize(d.tangentSpaceViewDir); - half3 dominantDirTangent = rnmBasis0 * dot(rnm0, lumaConv) + - rnmBasis1 * dot(rnm1, lumaConv) + - rnmBasis2 * dot(rnm2, lumaConv); - - half3 dominantDirTangentNormalized = normalize(dominantDirTangent); - half3 specColor = saturate(dot(rnmBasis0, dominantDirTangentNormalized)) * rnm0 + - saturate(dot(rnmBasis1, dominantDirTangentNormalized)) * rnm1 + - saturate(dot(rnmBasis2, dominantDirTangentNormalized)) * rnm2; - half3 halfDir = Unity_SafeNormalize(dominantDirTangentNormalized - viewDirTangent); - half NoH = saturate(dot(tangentNormal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - directSpecular += spec * specColor * fresnel; - } - #endif - - #if defined(BAKERY_SH) - { - half3 dominantDir = half3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(L1z, lumaConv)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) + d.worldSpaceViewDir); - half NoH = saturate(dot(o.Normal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - dominantDir = normalize(dominantDir); - directSpecular += max(spec * sh, 0.0) * fresnel; - } - #endif - - #if defined(BAKERY_MONOSH) - { - half3 dominantDir = nL1; - half focus = saturate(length(dominantDir)); - half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - d.worldSpaceViewDir); - half NoH = saturate(dot(o.Normal, halfDir)); - half spec = D_GGX(NoH, lerp(1, clampedRoughness, _SpecularRoughnessMod)); - half3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; - dominantDir = normalize(dominantDir); - directSpecular += max(spec * sh, 0.0) * fresnel; - } - #endif - #endif - - // REFLECTIONS - #if !defined(UNITY_PASS_FORWARDADD) - half3 reflDir = reflect(-d.worldSpaceViewDir, o.Normal); - reflDir = lerp(reflDir, o.Normal, rough * rough); - - Unity_GlossyEnvironmentData envData; - envData.roughness = perceptualRoughness; - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); - - half3 probe0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData); - indirectSpecular = probe0; - - #if defined(UNITY_SPECCUBE_BLENDING) - UNITY_BRANCH - if (unity_SpecCube0_BoxMin.w < 0.99999) - { - envData.reflUVW = getBoxProjection(reflDir, d.worldSpacePosition.xyz, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin.xyz, unity_SpecCube1_BoxMax.xyz); - half3 probe1 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0), unity_SpecCube1_HDR, envData); - indirectSpecular = lerp(probe1, probe0, unity_SpecCube0_BoxMin.w); - } - #endif - - half horizon = min(1 + dot(reflDir, o.Normal), 1); - dfg.x *= saturate(pow(dot(indirectDiffuse, 1), _SpecOcclusion)); - indirectSpecular = indirectSpecular * horizon * horizon * energyCompensation * EnvBRDFMultiscatter(dfg, f0); - - #if defined(_MASKMAP_SAMPLED) - indirectSpecular *= computeSpecularAO(NoV, o.Occlusion, perceptualRoughness * perceptualRoughness); - #endif - #endif - - #if defined(_INTEGRATE_CUSTOMGI) && !defined(UNITY_PASS_FORWARDADD) - IntegrateCustomGI(d, o, indirectSpecular, indirectDiffuse); - #endif - - // FINAL COLOR - FinalColor = half4(o.Albedo.rgb * (1 - o.Metallic) * (indirectDiffuse * occlusion + (pixelLight)) + indirectSpecular + directSpecular, o.Alpha); - - FinalColor.rgb += o.Emission; - #endif - } - - // Shadow Vertex - TessVertex Vertex(VertexData v) - { - UNITY_SETUP_INSTANCE_ID(v); - TessVertex o = (TessVertex) 0; - UNITY_TRANSFER_INSTANCE_ID(v, o); - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - - o.vertex = v.vertex; - o.normal = v.normal; - o.tangent = v.tangent; - o.color = v.color; - o.uv0 = v.uv0; - o.uv1 = v.uv1; - o.uv2 = v.uv2; - o.uv3 = v.uv3; - - return o; - } - - // Shadow Hull - [maxtessfactor(MAX_TESSELLATION_FACTORS)] - [UNITY_domain("tri")] - [UNITY_outputcontrolpoints(3)] - [UNITY_outputtopology("triangle_cw")] - [UNITY_partitioning("integer")] - [UNITY_patchconstantfunc("TessFactorsFunction")] - TessVertex Hull(InputPatch patch, uint id : SV_OutputControlPointID) - { - return patch[id]; - } - - float4 GetTessFactors(InputPatch patch) - { - #if defined(TESS_MODE_DISTANCEBASED) - float4 tessFactors = UnityDistanceBasedTess( - patch[0].vertex, - patch[1].vertex, - patch[2].vertex, - _TessMinDist, - _TessMaxDist, - _TessFactor - ); - return tessFactors; - #elif defined(TESS_MODE_EDGELENGTH) - float4 tessFactors = UnityEdgeLengthBasedTessCull( - patch[0].vertex, - patch[1].vertex, - patch[2].vertex, - _TessEdgeLength, - _TessMaxDisplacement - ); - return tessFactors; - #endif - - return 1..xxxx; - } - - // Shadow TessFactor - TessellationFactors TessFactorsFunction(InputPatch patch) - { - TessellationFactors f; - float4 TessFactorsOutput = 0; - #if defined(TESS_FACTORS_FUNC_DEFINED) - TessFactorsOutput = GetTessFactors(patch); - #else - TessFactorsOutput = 1..xxxx; - #endif - f.edge[0] = TessFactorsOutput.x; - f.edge[1] = TessFactorsOutput.y; - f.edge[2] = TessFactorsOutput.z; - f.inside = TessFactorsOutput.w; - return f; - } - - // Shadow Domain - [UNITY_domain("tri")] - FragmentData Domain(TessellationFactors factors, OutputPatch patch, float3 baryCoords : SV_DomainLocation) - { - VertexData v = (VertexData) 0; - UNITY_TRANSFER_INSTANCE_ID(patch[0], v); - v.vertex = patch[0].vertex * baryCoords.x + patch[1].vertex * baryCoords.y + patch[2].vertex * baryCoords.z; - - #if defined(PHONG) - float3 pp[3]; - for (int index = 0; index < 3; ++index) - { - pp[index] = v.vertex.xyz - patch[index].normal * (dot(v.vertex.xyz, patch[index].normal) - dot(patch[index].vertex.xyz, patch[index].normal)); - } - v.vertex.xyz = 0.5 * (pp[0]*baryCoords.x + pp[1]*baryCoords.y + pp[2]*baryCoords.z) + (0.5) * v.vertex.xyz; - #endif - - v.normal = patch[0].normal * baryCoords.x + patch[1].normal * baryCoords.y + patch[2].normal * baryCoords.z; - v.tangent = patch[0].tangent * baryCoords.x + patch[1].tangent * baryCoords.y + patch[2].tangent * baryCoords.z; - v.color = patch[0].color * baryCoords.x + patch[1].color * baryCoords.y + patch[2].color * baryCoords.z; - v.uv0 = patch[0].uv0 * baryCoords.x + patch[1].uv0 * baryCoords.y + patch[2].uv0 * baryCoords.z; - v.uv1 = patch[0].uv1 * baryCoords.x + patch[1].uv1 * baryCoords.y + patch[2].uv1 * baryCoords.z; - v.uv2 = patch[0].uv2 * baryCoords.x + patch[1].uv2 * baryCoords.y + patch[2].uv2 * baryCoords.z; - v.uv3 = patch[0].uv3 * baryCoords.x + patch[1].uv3 * baryCoords.y + patch[2].uv3 * baryCoords.z; - - FragmentData i; - UNITY_INITIALIZE_OUTPUT(FragmentData, i); - UNITY_TRANSFER_INSTANCE_ID(patch[0], i); - - vD = v; - FragData = i; - VHVertex(); - - i = FragData; - v = vD; - #if defined(UNITY_PASS_SHADOWCASTER) - i.worldNormal = UnityObjectToWorldNormal(v.normal); - i.worldPos = mul(unity_ObjectToWorld, v.vertex); - i.uv0 = v.uv0; - i.uv1 = v.uv1; - i.uv2 = v.uv2; - i.uv3 = v.uv3; - i.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz); - i.worldTangent.w = v.tangent.w * unity_WorldTransformParams.w; - #else - #if defined(UNITY_PASS_META) - i.pos = UnityMetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST); - #else - i.pos = UnityObjectToClipPos(v.vertex); - #endif - i.normal = v.normal; - i.worldNormal = UnityObjectToWorldNormal(v.normal); - i.worldPos = mul(unity_ObjectToWorld, v.vertex); - i.uv0 = v.uv0; - i.uv1 = v.uv1; - i.uv2 = v.uv2; - i.uv3 = v.uv3; - i.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz); - i.worldTangent.w = v.tangent.w * unity_WorldTransformParams.w; - i.vertexColor = v.color; - - #if defined(EDITOR_VISUALIZATION) - i.vizUV = 0; - i.lightCoord = 0; - if (unity_VisualizationMode == EDITORVIZ_TEXTURE) - i.vizUV = UnityMetaVizUV(unity_EditorViz_UVIndex, v.uv0.xy, v.uv1.xy, v.uv2.xy, unity_EditorViz_Texture_ST); - else if (unity_VisualizationMode == EDITORVIZ_SHOWLIGHTMASK) - { - i.vizUV = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; - i.lightCoord = mul(unity_EditorViz_WorldToLight, mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1))); - } - #endif - - #if defined(NEED_SCREEN_POS) - i.screenPos = ComputeScreenPos(i.pos); - #endif - - #if !defined(UNITY_PASS_META) - #if defined(LIGHTMAP_ON) - i.lightmapUv.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; - #endif - #if defined(DYNAMICLIGHTMAP_ON) - i.lightmapUv.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; - #endif - - UNITY_TRANSFER_LIGHTING(i, v.uv1.xy); - - #if !defined(UNITY_PASS_FORWARDADD) - // unity does some funky stuff for different platforms with these macros - #ifdef FOG_COMBINED_WITH_TSPACE - UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(i, i.pos); - #elif defined(FOG_COMBINED_WITH_WORLD_POS) - UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(i, i.pos); - #else - UNITY_TRANSFER_FOG(i, i.pos); - #endif - #else - UNITY_TRANSFER_FOG(i, i.pos); - #endif - #endif - #endif - - TRANSFER_SHADOW_CASTER_NORMALOFFSET(i); - return i; - } - - // Shadow Fragment - half4 Fragment(FragmentData i) : SV_TARGET - { - UNITY_SETUP_INSTANCE_ID(i); - - #if defined(NEED_FRAGMENT_IN_SHADOW) - FragData = i; - o = (SurfaceData) 0; - d = CreateMeshData(i); - o.Albedo = half3(0.5, 0.5, 0.5); - o.Normal = half3(0, 0, 1); - o.Smoothness = 0.5; - o.Occlusion = 1; - o.Alpha = 1; - FinalColor = half4(o.Albedo, o.Alpha); - - ParallaxFragment(); - BaseFragmentFunction(); - DetailsFragment(); - - #endif - - SHADOW_CASTER_FRAGMENT(i); - } - - ENDCG - // Shadow Pass End - - } - - } - CustomEditor "ORL.ShaderInspector.InspectorGUI" -} diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tessellated Displacement.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tessellated Displacement.orlshader new file mode 100644 index 00000000..1439d304 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tessellated Displacement.orlshader @@ -0,0 +1,10 @@ +%ShaderName("orels1/Standard Tessellated Displacement") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") + +%Includes() +{ + "@/Shaders/ORL Standard", + "@/Modules/Tessellation", + "@/Modules/Displacement", + "self", +} diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tessellated Displacement.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tessellated Displacement.orlshader.meta new file mode 100644 index 00000000..95c6c83c --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Tessellated Displacement.orlshader.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 09e7e0cd1d5730140b52f4296dc3a4ac +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Triplanar Effects.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Triplanar Effects.orlshader index 54248743..a407b46e 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Triplanar Effects.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Triplanar Effects.orlshader @@ -3,7 +3,7 @@ %Includes() { - "/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard", + "@/Shaders/ORL Standard", "@/Modules/TriplanarEffects" "self" } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard VRSLGI.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard VRSLGI.orlshader new file mode 100644 index 00000000..5d55c5c0 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard VRSLGI.orlshader @@ -0,0 +1,9 @@ +%ShaderName("orels1/Standard VRSL GI") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") + +%Includes() +{ + "@/Shaders/ORL Standard", + "@/Modules/VRSLGI", + "self" +} diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard VRSLGI.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard VRSLGI.orlshader.meta new file mode 100644 index 00000000..e2311a7c --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard VRSLGI.orlshader.meta @@ -0,0 +1,56 @@ +fileFormatVersion: 2 +guid: dfff91bf0b4fd5240b0482e2908e0ca7 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {instanceID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: + - Name: FunctionErrors + Entry: 7 + Data: 0|System.Collections.Generic.Dictionary`2[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser],[System.String, mscorlib]], mscorlib + - Name: comparer + Entry: 7 + Data: 1|System.Collections.Generic.ObjectEqualityComparer`1[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser]], mscorlib + - Name: + Entry: 8 + Data: + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: Errors + Entry: 7 + Data: 2|System.Collections.Generic.List`1[[ORL.ShaderGenerator.ShaderDefinitionImporter+ShaderError, + ORL.ShaderGenerator]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Vertex Animation.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Vertex Animation.orlshader index 069614a7..5af85a16 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Vertex Animation.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Vertex Animation.orlshader @@ -3,7 +3,7 @@ %Includes() { - "/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard", + "@/Shaders/ORL Standard", "@/Modules/VertexAnimation", "self" } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Vertical Fog.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Vertical Fog.orlshader index 683d7cd3..fa193d5b 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Vertical Fog.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard Vertical Fog.orlshader @@ -3,7 +3,7 @@ %Includes() { - "/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard", + "@/Shaders/ORL Standard", "@/Modules/VerticalFog", "self" } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard.orlshader index cf06b613..699b5dcf 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Standard.orlshader @@ -1,34 +1,35 @@ %ShaderName("orels1/Standard") +%TemplateFeatures("Stencil") %CustomEditor("ORL.ShaderInspector.InspectorGUI") %Properties() { UI_MainHeader("# Main Settings", Int) = 1 - _Color("Main Color", Color) = (1, 1, 1, 1) - _MainTex("Albedo", 2D) = "white" { } - [Enum(RGB, 0, R, 1, G, 2, B, 3)][_MainTex] _AlbedoChannel("Albedo Channel %ShowIf(_MainTex)", Int) = 0 - [Enum(UV, 0, Local Space, 1, World Space, 2)] _MappingSpace("Mapping Space", Int) = 0 - [Enum(X, 0, Y, 1, Z, 2)] _PlanarAxisX("X Axis %ShowIf(_MappingSpace > 0) %CombineWith(_PlanarAxisY)", Int) = 0 - [HideInInspector][Enum(X, 0, Y, 1, Z, 2)] _PlanarAxisY("Y Axis %ShowIf(_MappingSpace > 0)", Int) = 2 - [NoScaleOffset] _MaskMap("Masks >", 2D) = "white" { } - [Enum(R, 0, G, 1, B, 2, A, 3)] _MetalChannel("Metal %ShowIf(_MaskMap) %CombineWith(_AOChannel, _DetailMaskChannel, _SmoothChannel)", Int) = 0 - [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)] _AOChannel("AO", Int) = 1 - [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)] _DetailMaskChannel("Detail", Int) = 2 - [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)] _SmoothChannel("Smooth", Int) = 3 - _Smoothness("Smoothness %ShowIf(!_MaskMap)", Range(0, 1)) = 0.5 - [ToggleUI][_MaskMap] _RoughnessMode("Roughness Mode %ShowIf(_MaskMap)", Int) = 0 - _Metallic("Metallic %ShowIf(!_MaskMap)", Range(0, 1)) = 0 - _MetallicRemap("Metallic Remap %ShowIf(_MaskMap) %RemapSlider(0,1)", Vector) = (0, 1, 0, 1) - _SmoothnessRemap("Smoothness Remap %ShowIf(_MaskMap) %RemapSlider(0,1)", Vector) = (0, 1, 0, 1) - _OcclusionStrength("AO Strength %ShowIf(_MaskMap)", Range(0, 1)) = 1 + _Color("Main Color", Color) = (1, 1, 1, 1) + _MainTex("Albedo", 2D) = "white" { } + [Enum(RGB, 0, R, 1, G, 2, B, 3)][_MainTex]_AlbedoChannel("Albedo Channel %ShowIf(_MainTex)", Int) = 0 + [Enum(UV, 0, Local Space, 1, World Space, 2, Triplanar, 3)]_MappingSpace("Mapping Space", Int) = 0 + [Enum(X, 0, Y, 1, Z, 2)]_PlanarAxisX("X Axis %ShowIf(_MappingSpace > 0 && _MappingSpace < 3) %CombineWith(_PlanarAxisY)", Int) = 0 + [HideInInspector][Enum(X, 0, Y, 1, Z, 2)]_PlanarAxisY("Y Axis %ShowIf(_MappingSpace > 0 && _MappingSpace < 3)", Int) = 2 + [NoScaleOffset]_MaskMap("Masks >", 2D) = "white" { } + [Enum(R, 0, G, 1, B, 2, A, 3)]_MetalChannel("Metal %ShowIf(_MaskMap) %CombineWith(_AOChannel, _DetailMaskChannel, _SmoothChannel)", Int) = 0 + [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)]_AOChannel("AO", Int) = 1 + [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)]_DetailMaskChannel("Detail", Int) = 2 + [HideInInspector][Enum(R, 0, G, 1, B, 2, A, 3)]_SmoothChannel("Smooth", Int) = 3 + _Smoothness("Smoothness %ShowIf(!_MaskMap)", Range(0, 1)) = 0.5 + [ToggleUI][_MaskMap]_RoughnessMode("Roughness Mode %ShowIf(_MaskMap)", Int) = 0 + _Metallic("Metallic %ShowIf(!_MaskMap)", Range(0, 1)) = 0 + _MetallicRemap("Metallic Remap %ShowIf(_MaskMap) %RemapSlider(0,1)", Vector) = (0, 1, 0, 1) + _SmoothnessRemap("Smoothness Remap %ShowIf(_MaskMap) %RemapSlider(0,1)", Vector) = (0, 1, 0, 1) + _OcclusionStrength("AO Strength %ShowIf(_MaskMap)", Range(0, 1)) = 1 [ToggleUI]_DetailAsTintMask("Detail as Tint Mask %ShowIf(_MaskMap)", Int) = 0 - [NoScaleOffset] _BumpMap("Normal Map >", 2D) = "bump" { } - _BumpScale("Normal Map Scale %ShowIf(_BumpMap)", Range(-1, 1)) = 1 - [ToggleUI]_FlipBumpY("Flip Y (UE Mode) %ShowIf(_BumpMap)", Int) = 0 - [Toggle(_EMISSION)] _EmissionEnabled("Emission", Int) = 0 - _EmissionMap("Emission Map > %ShowIf(_EMISSION)", 2D) = "white" { } - [HDR]_EmissionColor("Emission Color %ShowIf(_EMISSION)", Color) = (0, 0, 0, 1) - [Enum(RGB, 0, R, 1, G, 2, B, 3)][_EmissionMap] _EmissionChannel("Emission Channel %ShowIf(_EmissionMap)", Int) = 0 + [NoScaleOffset]_BumpMap("Normal Map >", 2D) = "bump" { } + _BumpScale("Normal Map Scale %ShowIf(_BumpMap)", Range(-1, 1)) = 1 + [ToggleUI]_FlipBumpY("Flip Y (UE Mode) %ShowIf(_BumpMap)", Int) = 0 + [Toggle(_EMISSION)]_EmissionEnabled("Emission", Int) = 0 + _EmissionMap("Emission Map > %ShowIf(_EMISSION)", 2D) = "white" { } + [HDR]_EmissionColor("Emission Color %ShowIf(_EMISSION)", Color) = (0, 0, 0, 1) + [Enum(RGB, 0, R, 1, G, 2, B, 3)][_EmissionMap]_EmissionChannel("Emission Channel %ShowIf(_EmissionMap)", Int) = 0 } %ShaderTags() @@ -38,7 +39,7 @@ %ShaderFeatures() { - #pragma shader_feature_local _EMISSION + #pragma shader_feature_local_fragment _EMISSION } %ShaderDefines() @@ -81,7 +82,7 @@ half4 _EmissionColor; int _EmissionChannel; - half2 GLOBAL_uv; + float2 GLOBAL_uv; half4 GLOBAL_maskMap; } @@ -107,7 +108,23 @@ GLOBAL_uv = d.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; #endif - if (_MappingSpace > 0) + // Do Triplanar + if (_MappingSpace == 3) + { + float3 axisProjection = mul(float3(0.0001, 0.0001, 1), d.TBNMatrix); + axisProjection = abs(axisProjection); + axisProjection = pow(axisProjection, 160); + axisProjection /= axisProjection.x + axisProjection.y + axisProjection.z; + axisProjection = saturate(invLerp(axisProjection, 0.5, 0.5001)); + axisProjection.z += saturate(1 - length(axisProjection)); + + float3 pos = d.worldSpacePosition * _MainTex_ST.x; + GLOBAL_uv = pos.yx; + GLOBAL_uv *= axisProjection.x; + GLOBAL_uv += pos.y * axisProjection.y; + GLOBAL_uv += pos.z * axisProjection.z; + } + else if (_MappingSpace > 0) { GLOBAL_uv = (_MappingSpace - 1) ? half2(d.worldSpacePosition[_PlanarAxisX], d.worldSpacePosition[_PlanarAxisY]) : half2(d.localSpacePosition[_PlanarAxisX], d.localSpacePosition[_PlanarAxisY]); GLOBAL_uv *= _MainTex_ST.xy + _MainTex_ST.zw; @@ -115,19 +132,21 @@ half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, GLOBAL_uv); if (_AlbedoChannel > 0) { - albedo.rgb = albedo[_AlbedoChannel].xxx; + albedo.rgb = albedo[_AlbedoChannel - 1].xxx; } half4 masks = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, GLOBAL_uv); - half4 normalTex = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, GLOBAL_uv); + float4 normalTex = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, GLOBAL_uv); if (_FlipBumpY) { normalTex.y = 1 - normalTex.y; } - half3 normal = UnpackScaleNormal(normalTex, _BumpScale); + + float3 normal = UnpackNormalScale(normalTex, _BumpScale); + half3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, GLOBAL_uv).rgb; if (_EmissionChannel > 0) { - emission.rgb = emission[_EmissionChannel].xxx; + emission.rgb = emission[_EmissionChannel - 1].xxx; } int hasMasks = _MaskMap_TexelSize.z > 8; half metal = masks[_MetalChannel]; @@ -153,9 +172,17 @@ { o.Albedo *= lerp(albedo, albedo.rgb * _Color.rgb, detailMask); } + // Fix BC7 compression issues, unity PLS fix + { + uint a = uint(o.Alpha * 255.0); + a = a > 254 ? 255 : a; + a = a < 5 ? 0 : a; + o.Alpha = a / 255.0; + } + o.Alpha *= albedo.a * _Color.a; #if defined(_EMISSION) - o.Emission = emission * _EmissionColor; + o.Emission = emission * pow(_EmissionColor,2.2); #endif } } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Toon Cutout.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Toon Cutout.orlshader index 0e4494f9..44c05af2 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Toon Cutout.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Toon Cutout.orlshader @@ -18,7 +18,7 @@ %ShaderFeatures() { - #pragma shader_feature_local _NATIVE_A2C + #pragma shader_feature_local_fragment _NATIVE_A2C } %ShaderDefines() diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Toon Transparent PrePass.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Toon Transparent PrePass.orlshader index f8e042a6..b082b6b5 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/ORL Toon Transparent PrePass.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/ORL Toon Transparent PrePass.orlshader @@ -4,8 +4,8 @@ %Includes() { - "@/Shaders/ORL Toon Transparent", "self", + "@/Shaders/ORL Toon Transparent", } %ShaderModifiers() diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/Toon.meta b/Packages/sh.orels.shaders/Runtime/Shaders/Toon.meta new file mode 100644 index 00000000..bc6722d8 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/Toon.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eeb722b6bad34914aa279a72856ed777 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Cutout.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Cutout.orlshader new file mode 100644 index 00000000..5fc9d9f8 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Cutout.orlshader @@ -0,0 +1,73 @@ +%ShaderName("orels1/Toon/v2/Cutout") +%LightingModel("@/LightingModels/Toon") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") + +%Properties() +{ + UI_CutoutHeader("# Cutout", Int) = 0 + _Cutoff("Cutoff", Range(0, 1)) = 0.5 + [Toggle(_NATIVE_A2C)]_AlphaToMask("Alpha To Coverage (A2C)", Int) = 0 +} + + +%Includes() +{ + "@/Shaders/Toon/ORL Toon v2", + "self", +} + +%ShaderFeatures() +{ + #pragma shader_feature_local_fragment _NATIVE_A2C +} + +%ShaderDefines() +{ + #define NEED_FRAGMENT_IN_SHADOW + #define NEED_ALBEDO_ALPHA +} + +%ShaderTags() +{ + "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" +} + +%PassModifiers() +{ + AlphaToMask [_AlphaToMask] +} + +%Variables() +{ + half _Cutoff; +} + +%Fragment("CutoutFragment") +{ + void CutoutFragment(inout SurfaceData o) { + #if defined(_NATIVE_A2C) && defined(UNITY_PASS_FORWARDBASE) + + half antiAliased = o.Alpha - 0.5; + antiAliased /= max(0.0001, fwidth(o.Alpha)); + antiAliased += 0.5; + o.Alpha = saturate(antiAliased); + + #endif + + #if !defined(_NATIVE_A2C) || !defined(UNITY_PASS_FORWARDBASE) + if (o.Alpha < _Cutoff) { + clip(-1); + } + #endif + } +} + +%Shadow("CutoutShadow") +{ + void CutoutShadow(FragmentData i) { + half alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv0.xy).a; + if (alpha < _Cutoff) { + clip(-1); + } + } +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Cutout.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Cutout.orlshader.meta new file mode 100644 index 00000000..13ccfc71 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Cutout.orlshader.meta @@ -0,0 +1,19 @@ +fileFormatVersion: 2 +guid: d38f81adf72cfc144b441a7a3a387ee1 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 + Errors: [] + ShaderName: '"orels1/Toon/v2/Cutout"' + LightingModel: '@/LightingModels/Toon_v2' + IncludedModules: + - Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2.orlshader diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent PrePass.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent PrePass.orlshader new file mode 100644 index 00000000..c5054b67 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent PrePass.orlshader @@ -0,0 +1,24 @@ +%ShaderName("orels1/Toon/v2/Transparent PrePass") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") +%TemplateFeatures("PrePass") + +%Includes() +{ + "self", + "@/Shaders/Toon/ORL Toon v2 Transparent", +} + +%ShaderModifiers() +{ + ZWrite On +} + +%PrePassModifiers() +{ + Cull Front +} + +%ShaderDefines() +{ + #define NEED_FRAGMENT_IN_PREPASS +} \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent PrePass.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent PrePass.orlshader.meta new file mode 100644 index 00000000..dccf0916 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent PrePass.orlshader.meta @@ -0,0 +1,19 @@ +fileFormatVersion: 2 +guid: 03d4f1b63f179364f950e5b0d8a22666 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 + Errors: [] + ShaderName: '"orels1/Toon/v2/Transparent PrePass"' + LightingModel: '@/LightingModels/Toon_v2' + IncludedModules: + - Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent.orlshader diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent.orlshader new file mode 100644 index 00000000..1a9053ff --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent.orlshader @@ -0,0 +1,25 @@ +%ShaderName("orels1/Toon/v2/Transparent") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") + +%Includes() +{ + "@/Shaders/Toon/ORL Toon v2", + "self", +} + +%ShaderTags() +{ + "Queue" = "AlphaTest+10" "RenderType" = "TransparentCutout" +} + +%ShaderModifiers() +{ + BlendOp Add, Max + Blend SrcAlpha OneMinusSrcAlpha, One One + ZWrite Off +} + +%ShaderDefines() +{ + #define NEED_ALBEDO_ALPHA +} diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent.orlshader.meta new file mode 100644 index 00000000..d3ba6734 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2 Transparent.orlshader.meta @@ -0,0 +1,19 @@ +fileFormatVersion: 2 +guid: c000dec77810f4c48905c173200c631c +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 + Errors: [] + ShaderName: '"orels1/Toon/v2/Transparent"' + LightingModel: '@/LightingModels/Toon_v2' + IncludedModules: + - Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2.orlshader diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2.orlshader new file mode 100644 index 00000000..ca1bd462 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2.orlshader @@ -0,0 +1,33 @@ +%ShaderName("orels1/Toon/v2/Main") +%LightingModel("@/LightingModels/Toon_v2") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") + +%Properties() +{ + UI_ToonDocs("[This shader has documentation](https://shaders.orels.sh/docs/toon/v2)", Int) = 0 +} + +%ShaderTags() +{ + "RenderType" = "Opaque" "Queue" = "Geometry" +} + +%Includes() +{ + "@/Modules/AudioLink", + "self", + "@/Modules/Toon/v2/Main" + "@/Modules/Toon/v2/Shading", + "@/Modules/Toon/v2/Occlusion", + "@/Modules/Toon/v2/Normals", + "@/Modules/Toon/v2/Specular", + "@/Modules/Toon/v2/Matcaps", + "@/Modules/Toon/v2/Decals", + "@/Modules/Toon/v2/RimLight", + "@/Modules/Toon/v2/RimShadow", + "@/Modules/Toon/v2/Reflections", + "@/Modules/Toon/AudioLink", + "@/Modules/Toon/v2/Emission", + "@/Modules/Toon/v2/Outline", + "@/Modules/Toon/UVDiscard" +} diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2.orlshader.meta new file mode 100644 index 00000000..5bd80391 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/Toon/ORL Toon v2.orlshader.meta @@ -0,0 +1,30 @@ +fileFormatVersion: 2 +guid: 06c49d025f6563242bfcc028dccff3d5 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 + Errors: [] + ShaderName: '"orels1/Toon/v2/Main"' + LightingModel: '@/LightingModels/Toon_v2' + IncludedModules: + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/AudioLink.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Main.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Shading.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Occlusion.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Normals.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Specular.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Matcaps.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Decals.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimLight.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/RimShadow.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/AudioLink.orlsource + - Packages/sh.orels.shaders.generator/Runtime/Sources/Modules/Toon/v2/Emission.orlsource diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Layered Parallax.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Layered Parallax.orlshader index 1d048961..b20ee94c 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Layered Parallax.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Layered Parallax.orlshader @@ -156,7 +156,7 @@ half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer1UV - 2)), saturate(_LPLayer1UV - 1)), saturate(_LPLayer1UV)); _LPLayer1Direction = _LPLayer1Direction / 10.0; layerUv = layerUv * _LPLayer1_ST.xy + _LPLayer1_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer1Depth, d.tangentSpaceViewDir); + half2 offset = ParallaxOffset1Step(-1, _LPLayer1Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer1Mode) { @@ -196,7 +196,7 @@ half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer2UV - 2)), saturate(_LPLayer2UV - 1)), saturate(_LPLayer2UV)); _LPLayer2Direction = _LPLayer2Direction / 10.0; layerUv = layerUv * _LPLayer2_ST.xy + _LPLayer2_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer2Depth, d.tangentSpaceViewDir); + half2 offset = ParallaxOffset1Step(-1, _LPLayer2Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer2Mode) { @@ -236,7 +236,7 @@ half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer3UV - 2)), saturate(_LPLayer3UV - 1)), saturate(_LPLayer3UV)); _LPLayer3Direction = _LPLayer3Direction / 10.0; layerUv = layerUv * _LPLayer3_ST.xy + _LPLayer3_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer3Depth, d.tangentSpaceViewDir); + half2 offset = ParallaxOffset1Step(-1, _LPLayer3Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer3Mode) { @@ -276,7 +276,7 @@ half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer4UV - 2)), saturate(_LPLayer4UV - 1)), saturate(_LPLayer4UV)); _LPLayer4Direction = _LPLayer4Direction / 10.0; layerUv = layerUv * _LPLayer4_ST.xy + _LPLayer4_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer4Depth, d.tangentSpaceViewDir); + half2 offset = ParallaxOffset1Step(-1, _LPLayer4Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer4Mode) { @@ -316,7 +316,7 @@ half2 layerUv = lerp(d.uv0.xy, lerp(d.uv1.xy, lerp(d.uv2.xy, d.uv3.xy, saturate(_LPLayer5UV - 2)), saturate(_LPLayer5UV - 1)), saturate(_LPLayer5UV)); _LPLayer5Direction = _LPLayer5Direction / 10.0; layerUv = layerUv * _LPLayer5_ST.xy + _LPLayer5_ST.zw; - half2 offset = ParallaxOffset(-1, _LPLayer5Depth, d.tangentSpaceViewDir); + half2 offset = ParallaxOffset1Step(-1, _LPLayer5Depth, d.tangentSpaceViewDir); half uvFactor = 1; switch(_LPLayer5Mode) { diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Scrolling Texture.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Scrolling Texture.orlshader index a0ffff8e..068eac63 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Scrolling Texture.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Scrolling Texture.orlshader @@ -50,7 +50,7 @@ void UI_ScrollerFragment(MeshData d, inout SurfaceData o) { GLOBAL_uv_scale = _ScrollTiling; GLOBAL_uv_offset = _Time.y * _ScrollSpeed.xy; - GLOBAL_uv_offset += ParallaxOffset(-1, _ScrollParallaxOffset, d.tangentSpaceViewDir); + GLOBAL_uv_offset += ParallaxOffset1Step(-1, _ScrollParallaxOffset, d.tangentSpaceViewDir); if (_EdgeFade) { half dist = RoundedBox(d.uv0 - 0.5, half2(_EdgeFadeScale, _EdgeFadeScale), _EdgeFadeRounding - 0.1); o.Alpha = smoothstep(dist - _EdgeFadeAmount, dist + _EdgeFadeAmount, 0.0); diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Sheen.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Sheen.orlshader index 6d59e175..dd41ae5e 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Sheen.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI Sheen.orlshader @@ -12,6 +12,7 @@ _SheenAlbedoTint("Albedo Tint", Range(0,1)) = 1 [Enum(Overlay, 0, Lighten, 1, Screen, 2, Multiply, 3)]_SheenBlendType("Blending Type", Int) = 0 UI_SheenBlendTypeNote("> The blend types match the ones provided by Photoshop", Int) = 0 + [ToggleUI]_SheenForceDiscard("Force Discard", Int) = 0 } %Includes() @@ -27,11 +28,15 @@ half4 _SheenTint; half _SheenAlbedoTint; int _SheenBlendType; + int _SheenForceDiscard; } %Fragment("UI_SheenFragment", 10) { void UI_SheenFragment(MeshData d, inout SurfaceData o) { + if (_SheenForceDiscard && o.Alpha < 0.999) { + discard; + } half NoV = saturate(dot(d.worldNormal, d.worldSpaceViewDir)); NoV = saturate(pow(NoV, _SheenPower)); half3 blendSource = lerp(_SheenTint, o.Albedo, _SheenAlbedoTint); diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI.orlshader index a44eba03..a57e56cf 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/UI/ORL UI.orlshader @@ -13,8 +13,8 @@ { half4 _Glow; half4 _MainTex_ST; - half2 GLOBAL_uv_offset; - half2 GLOBAL_uv_scale; + float2 GLOBAL_uv_offset; + float2 GLOBAL_uv_scale; } %Textures() @@ -27,7 +27,7 @@ { void UIFragment(MeshData d, inout SurfaceData o) { - half2 uv = d.uv0 * _MainTex_ST.xy + _MainTex_ST.zw; + float2 uv = d.uv0 * _MainTex_ST.xy + _MainTex_ST.zw; #if defined(GLOBAL_UV_SCALE) uv *= GLOBAL_uv_scale; #endif @@ -36,7 +36,7 @@ #endif half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv); color *= d.vertexColor.rgba; - o.Albedo = lerp(o.Albedo, color.rgb, color.a); + o.Albedo = lerp(o.Albedo, color.rgb, color.a) * color.a; o.Alpha = o.Alpha * color.a; } } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Block Fader.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Block Fader.orlshader index b10c333e..30bc7a4a 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Block Fader.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Block Fader.orlshader @@ -14,7 +14,7 @@ %ShaderTags() { - "Queue" = "Transparent" "RenderType" = "Transparent" + "Queue" = "Transparent" "RenderType" = "Transparent" "ORL_RenderType" = "Transparent" } %PassModifications() @@ -24,7 +24,7 @@ %Includes() { - "../ORL Standard", + "@/Shaders/ORL Standard", "self" } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds Tessellated.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds Tessellated.orlshader new file mode 100644 index 00000000..40e2b194 --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds Tessellated.orlshader @@ -0,0 +1,9 @@ +%ShaderName("orels1/VFX/Clouds Tessellated") +%CustomEditor("ORL.ShaderInspector.InspectorGUI") + +%Includes() +{ + "@/Shaders/VFX/ORL VFX Clouds", + "@/Modules/Tessellation", + "self", +} diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds Tessellated.orlshader.meta b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds Tessellated.orlshader.meta new file mode 100644 index 00000000..dce8ba9b --- /dev/null +++ b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds Tessellated.orlshader.meta @@ -0,0 +1,56 @@ +fileFormatVersion: 2 +guid: eb720ed76da30d647b3dc10ce37e6a75 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 14030a0b230d45068f811d1ad116f246, type: 3} + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {instanceID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: + - Name: FunctionErrors + Entry: 7 + Data: 0|System.Collections.Generic.Dictionary`2[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser],[System.String, mscorlib]], mscorlib + - Name: comparer + Entry: 7 + Data: 1|System.Collections.Generic.ObjectEqualityComparer`1[[UnityShaderParser.HLSL.FunctionDefinitionNode, + UnityShaderParser]], mscorlib + - Name: + Entry: 8 + Data: + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: Errors + Entry: 7 + Data: 2|System.Collections.Generic.List`1[[ORL.ShaderGenerator.ShaderDefinitionImporter+ShaderError, + ORL.ShaderGenerator]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + debugBuild: 0 + samplerCount: 0 + textureCount: 0 + featureCount: 0 diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds.orlshader index f0091b8f..02ca8e30 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Clouds.orlshader @@ -2,18 +2,41 @@ %LightingModel("@/LightingModels/VFX") %CustomEditor("ORL.ShaderInspector.InspectorGUI") + %Properties() { UI_CloudsDocs("[This shader has documentation](https://shaders.orels.sh/docs/vfx/clouds)", Int) = 0 + + UI_ShadingHeader("# Shading", Int) = 1 + [ToggleUI]_EnableDepthBlending("Enable Depth Blending", Int) = 1 + _DepthTransp("Depth Transparency %ShowIf(_EnableDepthBlending)", Float) = 36 + [Toggle(APPLY_SHADING)]_ApplyShading("Apply Shading", Int) = 0 + _ShadeRamp("Shade Ramp %ShowIf(APPLY_SHADING) %Gradient()", 2D) = "grayscaleRamp" {} + _Tint("Tint %ShowIf(APPLY_SHADING)", Color) = (1,1,1,1) + [Toggle(RECALCULATE_NORMALS)]_RecalculateNormals("Recalculate Normals %ShowIf(APPLY_SHADING)", Int) = 0 + _NormalPrecision("Normal Precision %ShowIf(APPLY_SHADING && RECALCULATE_NORMALS)", Float) = 0.1 + [ToggleUI]_HeightGradient("Add Height Gradient %ShowIf(APPLY_SHADING)", Int) = 0 + _ColorBottom("Color Bottom %ShowIf(!APPLY_SHADING || _HeightGradient)", Color) = (0.5680403, 0.5980207, 0.6509434, 1) + _ColorTop("Color Top %ShowIf(!APPLY_SHADING || _HeightGradient)", Color) = (0.8066038, 0.9495488, 1, 1) + _HeightBottom("Height Bottom %ShowIf(!APPLY_SHADING || _HeightGradient)", Float) = 0.12 + _HeightTop("Height Top %ShowIf(!APPLY_SHADING || _HeightGradient)", Float) = 1 + + UI_NoiseHeader("# Noise", Int) = 1 + [NonModifiableTextureData][NoScaleOffset]_BakedNoiseTex("Noise Tex > %RequiredTexture(@/BakedNoise.png)", 2D) = "white" { } - _DepthTransp("Depth Transparency", Float) = 36 - _ColorBottom("Color Bottom", Color) = (0.5680403, 0.5980207, 0.6509434, 1) - _ColorTop("Color Top", Color) = (0.8066038, 0.9495488, 1, 1) - _HeightBottom("Height Bottom", Float) = 0.12 - _HeightTop("Height Top", Float) = 1 + UI_ExtrusionHeader("## Extrusion", Int) = 0 [Enum(Normal, 0, World Space, 1)]_ExtrusionMode("Extrusion Mode", Int) = 0 _ExtrusionDirection("Extrusion Direction %ShowIf(_ExtrusionMode > 0)", Vector) = (0, 1, 0, 1) [Toggle(ONLY_TOP)]_OnlyTop("Only Top %ShowIf(_ExtrusionMode > 0)", Int) = 0 + [Enum(None, 0, Texture, 1, Vertex Color, 2)]_ExtrusionMaskMode("Mask Mode", Int) = 0 + _ExtrusionMask("Mask %ShowIf(_ExtrusionMaskMode == 1)", 2D) = "white" {} + [Enum(UV, 0, Local Space, 1, World Space, 2)] _ExtrusionMaskMappingSpace("Mapping Space %ShowIf(_ExtrusionMaskMode == 1)", Int) = 0 + [Enum(UV1, 0, UV2, 1, UV3, 2, UV4, 3)]_ExtrusionMaskUVChannel("UV Set %ShowIf(_ExtrusionMaskMode == 1 && _ExtrusionMaskMappingSpace == 0)", Int) = 0 + [Enum(X, 0, Y, 1, Z, 2)] _ExtrusionMaskPlanarAxisX("X Axis %ShowIf(_ExtrusionMaskMappingSpace > 0) %CombineWith(_ExtrusionMaskPlanarAxisY)", Int) = 0 + [HideInInspector][Enum(X, 0, Y, 1, Z, 2)] _ExtrusionMaskPlanarAxisY("Y Axis %ShowIf(_ExtrusionMaskMappingSpace > 0)", Int) = 02 + [Enum(R, 0, G, 1, B, 2, A, 3)]_ExtrusionMaskChannel("Mask Channel %ShowIf(_ExtrusionMaskMode > 0)", Int) = 0 + _ExtrusionMaskStrentgh("Mask Strength %ShowIf(_ExtrusionMaskMode > 0)", Range(0, 1)) = 1 + UI_Level1Header("## Level 1", Int) = 0 _L1NoiseScale("Noise Scale", Float) = 1.7 @@ -33,12 +56,14 @@ %ShaderFeatures() { - #pragma shader_feature_local ONLY_TOP + #pragma shader_feature_local_vertex ONLY_TOP + #pragma shader_feature_local APPLY_SHADING + #pragma shader_feature_local_vertex RECALCULATE_NORMALS } %ShaderTags() { - "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" + "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" "ORL_RenderType" = "Fade" } %PassModifiers() @@ -46,16 +71,20 @@ Blend SrcAlpha OneMinusSrcAlpha } + %ShaderDefines() { #define EXTRA_V2F_0 - #define NEED_DEPTH + #define EXTRA_V2F_1 } %Variables() { + float _NormalPrecision; + half4 _Tint; + half _ExtrusionMode; - half _ExtrusionDirection; + half4 _ExtrusionDirection; half _L1NoiseScale; half _L1NoiseStrength; half4 _L1NoiseDirection; @@ -66,75 +95,184 @@ half _L3NoiseStrength; half4 _L3NoiseDirection; + int _EnableDepthBlending; half _DepthTransp; half4 _ColorBottom; half4 _ColorTop; half _HeightBottom; half _HeightTop; + int _HeightGradient; + + int _ExtrusionMaskMode; + int _ExtrusionMaskMappingSpace; + int _ExtrusionMaskUVChannel; + int _ExtrusionMaskPlanarAxisX; + int _ExtrusionMaskPlanarAxisY; + int _ExtrusionMaskChannel; + half4 _ExtrusionMask_ST; + half _ExtrusionMaskStrentgh; + + float4 _BakedNoiseTex_TexelSize; } %Textures() { TEXTURE2D(_BakedNoiseTex); SAMPLER(sampler_BakedNoiseTex); + + TEXTURE2D(_ExtrusionMask); + SAMPLER(sampler_ExtrusionMask); + + TEXTURE2D(_ShadeRamp); + SAMPLER(sampler_ShadeRamp); } %Vertex("CloudsVertex") { - void CloudsVertex(inout VertexData v, inout FragmentData o) + float3 CloudExtrusion(VertexData v, float3 vertexPos, float3 wNormal, float3 exDir) { - half4 wPos = mul(unity_ObjectToWorld, v.vertex); - half3 wNormal = mul(unity_ObjectToWorld, float4(v.normal, 0.0)).xyz; - half3 pos = wPos.xyz / 100; - half3 exDir = _ExtrusionMode == 0 ? v.normal.xyz : _ExtrusionDirection; + float3 wPos = TransformObjectToWorld(vertexPos); + float3 pos = wPos.xyz / 100; + + float3 vertOffset = 0; + + [branch] + if (_ExtrusionMaskMode > 0) + { + half mask = 1; + if (_ExtrusionMaskMode == 1) + { + float2 maskUv = v.uv0.xy; + + if (_ExtrusionMaskMappingSpace == 0) + { + switch (_ExtrusionMaskUVChannel) + { + case 1: maskUv = v.uv1.xy; break; + case 2: maskUv = v.uv2.xy; break; + case 3: maskUv = v.uv3.xy; break; + } + } + if (_ExtrusionMaskMappingSpace > 0) + { + maskUv = float2( + lerp(v.vertex[_ExtrusionMaskPlanarAxisX], wPos[_ExtrusionMaskPlanarAxisX], floor(_ExtrusionMaskMappingSpace - 1)), + lerp(v.vertex[_ExtrusionMaskPlanarAxisY], wPos[_ExtrusionMaskPlanarAxisY], floor(_ExtrusionMaskMappingSpace - 1)) + ); + } + + mask = SAMPLE_TEXTURE2D_LOD(_ExtrusionMask, sampler_ExtrusionMask, maskUv.xy * _ExtrusionMask_ST.xy + _ExtrusionMask_ST.zw, 0)[_ExtrusionMaskChannel]; + } else { + mask = v.color[_ExtrusionMaskChannel]; + } + + exDir = lerp(exDir, exDir * mask, _ExtrusionMaskStrentgh); + } #if defined(ONLY_TOP) if (dot(wNormal, half3(0, 1, 0)) > 0) { - v.vertex.xyz += exDir * (0.7 * getBakedNoise(_BakedNoiseTex, sampler_BakedNoiseTex, pos * _L1NoiseScale + _Time.y * (_L1NoiseDirection / 100)) * _L1NoiseStrength); + vertOffset += exDir * (0.7 * getBakedNoiseBilinear(_BakedNoiseTex, sampler_BakedNoiseTex, _BakedNoiseTex_TexelSize, pos * _L1NoiseScale + _Time.y * (_L1NoiseDirection / 100)) * _L1NoiseStrength); half3 pos2 = pos * _L2NoiseScale; pos2.z /= 2; - v.vertex.xyz += exDir * (0.3 * getBakedNoise(_BakedNoiseTex, sampler_BakedNoiseTex, pos2 * _L2NoiseScale + _Time.y * (_L2NoiseDirection / 100)) * _L2NoiseStrength); + vertOffset += exDir * (0.3 * getBakedNoiseBilinear(_BakedNoiseTex, sampler_BakedNoiseTex, _BakedNoiseTex_TexelSize, pos2 * _L2NoiseScale + _Time.y * (_L2NoiseDirection / 100)) * _L2NoiseStrength); half3 pos3 = pos * _L3NoiseScale; - v.vertex.xyz += exDir * (0.5 * 0.3 * getBakedNoise(_BakedNoiseTex, sampler_BakedNoiseTex, pos3 + _Time.y * (_L3NoiseDirection / 100)) * _L3NoiseStrength); + vertOffset += exDir * (0.5 * 0.3 * getBakedNoiseBilinear(_BakedNoiseTex, sampler_BakedNoiseTex, _BakedNoiseTex_TexelSize, pos3 + _Time.y * (_L3NoiseDirection / 100)) * _L3NoiseStrength); pos3 *= 2.01; - v.vertex.xyz += exDir * (0.5 * 0.3 * getBakedNoise(_BakedNoiseTex, sampler_BakedNoiseTex, pos3 + _Time.y * (_L3NoiseDirection / 100)) * _L3NoiseStrength); + vertOffset += exDir * (0.5 * 0.3 * getBakedNoiseBilinear(_BakedNoiseTex, sampler_BakedNoiseTex, _BakedNoiseTex_TexelSize, pos3 + _Time.y * (_L3NoiseDirection / 100)) * _L3NoiseStrength); } #else - v.vertex.xyz += exDir * (0.7 * getBakedNoise(_BakedNoiseTex, sampler_BakedNoiseTex, pos * _L1NoiseScale + _Time.y * (_L1NoiseDirection / 100)) * _L1NoiseStrength); + vertOffset += exDir * (0.7 * getBakedNoiseBilinear(_BakedNoiseTex, sampler_BakedNoiseTex, _BakedNoiseTex_TexelSize, pos * _L1NoiseScale + _Time.y * (_L1NoiseDirection / 100)) * _L1NoiseStrength); half3 pos2 = pos * _L2NoiseScale; pos2.z /= 2; - v.vertex.xyz += exDir * (0.3 * getBakedNoise(_BakedNoiseTex, sampler_BakedNoiseTex, pos2 * _L2NoiseScale + _Time.y * (_L2NoiseDirection / 100)) * _L2NoiseStrength); + vertOffset += exDir * (0.3 * getBakedNoiseBilinear(_BakedNoiseTex, sampler_BakedNoiseTex, _BakedNoiseTex_TexelSize, pos2 * _L2NoiseScale + _Time.y * (_L2NoiseDirection / 100)) * _L2NoiseStrength); half3 pos3 = pos * _L3NoiseScale; - v.vertex.xyz += exDir * (0.5 * 0.3 * getBakedNoise(_BakedNoiseTex, sampler_BakedNoiseTex, pos3 + _Time.y * (_L3NoiseDirection / 100)) * _L3NoiseStrength); + vertOffset += exDir * (0.5 * 0.3 * getBakedNoiseBilinear(_BakedNoiseTex, sampler_BakedNoiseTex, _BakedNoiseTex_TexelSize, pos3 + _Time.y * (_L3NoiseDirection / 100)) * _L3NoiseStrength); pos3 *= 2.01; - v.vertex.xyz += exDir * (0.5 * 0.3 * getBakedNoise(_BakedNoiseTex, sampler_BakedNoiseTex, pos3 + _Time.y * (_L3NoiseDirection / 100)) * _L3NoiseStrength); + vertOffset += exDir * (0.5 * 0.3 * getBakedNoiseBilinear(_BakedNoiseTex, sampler_BakedNoiseTex, _BakedNoiseTex_TexelSize, pos3 + _Time.y * (_L3NoiseDirection / 100)) * _L3NoiseStrength); + + #endif + + return vertOffset; + } + void CloudsVertex(inout VertexData v, inout FragmentData o) + { + // half4 wPos = mul(unity_ObjectToWorld, v.vertex); + float3 wNormal = TransformObjectToWorldDir(v.normal, 0.0).xyz; + // half3 pos = wPos.xyz / 100; + float3 exDir = _ExtrusionMode == 0 ? v.normal.xyz : normalize(_ExtrusionDirection.xyz); + + #if defined(RECALCULATE_NORMALS) && defined(APPLY_SHADING) + { + float3 vertOffset = CloudExtrusion(v, v.vertex, wNormal, exDir); + float3 newVertPos = v.vertex.xyz + vertOffset; + + float3 bitangent = cross(v.normal.xyz, v.tangent.xyz); + + float3 newTangent = v.vertex.xyz + v.tangent.xyz * _NormalPrecision; + newTangent = (newTangent + CloudExtrusion(v, newTangent, wNormal, exDir)) - newVertPos; + + float3 newBitangent = v.vertex.xyz + bitangent.xyz * _NormalPrecision; + newBitangent = (newBitangent + CloudExtrusion(v, newBitangent, wNormal, exDir)) - newVertPos; + + v.normal.xyz = cross(newTangent, newBitangent); + v.tangent.xyz = newTangent; + v.vertex.xyz = newVertPos; + } + #else + { + float3 vertOffset = CloudExtrusion(v, v.vertex, wNormal, exDir); + v.vertex.xyz += vertOffset; + } #endif - o.extraV2F0 = ComputeScreenPos(UnityObjectToClipPos(v.vertex)); - // COMPUTE_EYEDEPTH macro - o.extraV2F0.z = -UnityObjectToViewPos(v.vertex).z; + + o.extraV2F0 = GetScreenPosition(TransformObjectToHClip(v.vertex)); + o.extraV2F0.z = -TransformWorldToView(TransformObjectToWorld(v.vertex)).z; } } %Fragment("CloudsFragment") { - void CloudsFragment(MeshData d, inout SurfaceData o) + void CloudsFragment(MeshData d, inout SurfaceData o, FragmentData i) { - float sceneZ = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(d.extraV2F0))); - float depth = sceneZ - d.extraV2F0.z; - + float sceneZ = LinearEyeDepth(SampleSceneDepth(d.extraV2F0.xy / d.extraV2F0.w)); + float depth = sceneZ - d.extraV2F0.z; depth = saturate(invLerp(0, _DepthTransp, depth)); + depth = lerp(1, depth, _EnableDepthBlending); half heightAlpha = saturate(invLerp(_HeightBottom, _HeightTop, d.localSpacePosition.y)); - half4 color = 0; - color.rgb = lerp(_ColorBottom, _ColorTop, heightAlpha); - o.Albedo = lerp(_ColorBottom, _ColorTop, heightAlpha); o.Alpha = depth; + + #if defined(APPLY_SHADING) + { + Light mainLight = GetMainLight(i._ShadowCoord, d.worldSpacePosition, 0..xxxx); + + half3 lightAttenuation = mainLight.shadowAttenuation; + half3 lightColor = mainLight.color * mainLight.shadowAttenuation; + float3 lightDir = mainLight.direction; + + half lightNoL = dot(d.worldNormal, lightDir); + half2 rampUv = half2(lightNoL * 0.5 + 0.5, 0); + half3 ramp = SAMPLE_TEXTURE2D(_ShadeRamp, sampler_ShadeRamp, rampUv).rgb; + o.Albedo = ramp * lightColor * _Tint.rgb; + o.Alpha *= _Tint.a; + if (_HeightGradient) { + o.Albedo *= lerp(_ColorBottom, _ColorTop, heightAlpha); + o.Alpha *= lerp(_ColorBottom.a, _ColorTop.a, heightAlpha); + } + } + #else + { + o.Albedo = lerp(_ColorBottom, _ColorTop, heightAlpha); + o.Alpha *= lerp(_ColorBottom.a, _ColorTop.a, heightAlpha); + } + #endif + } } \ No newline at end of file diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Cubemap Screen.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Cubemap Screen.orlshader index 99b6116c..25dd8cfb 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Cubemap Screen.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Cubemap Screen.orlshader @@ -41,7 +41,7 @@ %Includes() { - "../ORL Standard", + "@/Shaders/ORL Standard", "self" } diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Holographic Parallax.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Holographic Parallax.orlshader index abf11697..f59f6507 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Holographic Parallax.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Holographic Parallax.orlshader @@ -36,12 +36,15 @@ %ShaderTags() { - "Queue" = "Transparent" "RenderType" = "Transparent" + "Queue" = "Transparent" "RenderType" = "Transparent" "ORL_RenderType" = "Fade" } %ShaderFeatures() { - #pragma shader_feature_local HOLOGRAPHIC_PARALLAX_LAYERS_TEN HOLOGRAPHIC_PARALLAX_LAYERS_SIX HOLOGRAPHIC_PARALLAX_LAYERS_FOUR HOLOGRAPHIC_PARALLAX_LAYERS_TWO + #pragma shader_feature_local_fragment HOLOGRAPHIC_PARALLAX_LAYERS_TEN HOLOGRAPHIC_PARALLAX_LAYERS_SIX HOLOGRAPHIC_PARALLAX_LAYERS_FOUR HOLOGRAPHIC_PARALLAX_LAYERS_TWO + #if !defined(HOLOGRAPHIC_PARALLAX_LAYERS_TEN) && !defined(HOLOGRAPHIC_PARALLAX_LAYERS_SIX) && !defined(HOLOGRAPHIC_PARALLAX_LAYERS_FOUR) && !defined(HOLOGRAPHIC_PARALLAX_LAYERS_TWO) + #define HOLOGRAPHIC_PARALLAX_LAYERS_TEN + #endif } %ShaderDefines() @@ -105,22 +108,21 @@ void SPFragment(MeshData d, inout SurfaceData o) { o.Albedo = 0; o.Alpha = 0; - d.worldNormal = -d.worldNormal; // angle falloff - half NoV = 1 - saturate(dot(d.worldNormal, normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, half4(0,0,0,1))))); + half NoV = 1 - saturate(dot(d.worldNormal, normalize(_WorldSpaceCameraPos.xyz - TransformObjectToWorld(0..xxx)))); NoV = saturate(pow(NoV, 3)); NoV = saturate(remap(NoV, 0, 1, 0.3, 2)); NoV = lerp(1, NoV, _HPGlancingFalloff); - half2 baseUv = d.uv0 * _HPStackedTexture_ST.xy + _HPStackedTexture_ST.zw; + float2 baseUv = d.uv0 * _HPStackedTexture_ST.xy + _HPStackedTexture_ST.zw; half4 stacked = 0; - half2 layerOffset = ParallaxOffset(1, _HPBarsLayerStep / 100.0, d.tangentSpaceViewDir); + float2 layerOffset = ParallaxOffset1Step(1, _HPBarsLayerStep / 100.0, d.tangentSpaceViewDir); [unroll(SP_LAYERS_COUNT)] for (int i = SP_LAYERS_COUNT; i > 0; i--) { - half2 localUv = baseUv + layerOffset * i; + float2 localUv = baseUv + layerOffset * i; if (_HPUVClamp) { localUv = saturate(localUv); diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Laser.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Laser.orlshader index d00170fc..3f34f8e9 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Laser.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Laser.orlshader @@ -8,6 +8,7 @@ [ToggleUI]_UseTrailColor("Use Trail Color", Int) = 0 UI_UseTrailColorNote("> This will ignore the Color option above and use the trail gradient", Int) = 0 _ColorBoost("Color Boost %ShowIf(_UseTrailColor)", Float) = 1 + [ToggleUI]_LinearColor("Linear Trail Color %ShowIf(_UseTrailColor)", Int) = 0 UI_NoiseControlHeader("# Noise Control", Int) = 1 [Enum(World, 0, Local, 1, UV, 2)]_NoiseSpace("Noise Coordinate Space", Int) = 0 @@ -39,7 +40,7 @@ %ShaderTags() { - "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" + "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" "ORL_RenderType" = "Fade" } %ShaderModifiers() @@ -53,6 +54,7 @@ { half4 _Color; int _UseTrailColor; + int _LinearColor; half _ColorBoost; half _Scale; half _ScaleY; @@ -88,13 +90,9 @@ -0.80, 0.36, -0.48, -0.60, -0.48, 0.64 }; - half3 scale = float3( - length(unity_ObjectToWorld._m00_m10_m20), - length(unity_ObjectToWorld._m01_m11_m21), - length(unity_ObjectToWorld._m02_m12_m22) - ); - half3 pos = _NoiseSpace ? (_NoiseSpace == 2 ? d.uv0.xyx : d.localSpacePosition) : d.worldSpacePosition; - half3 convertedScroll1Dir = _Noise1ScrollSpace ? (_Noise1ScrollSpace == 2 ? _Noise1Scroll.xyz : mul(unity_ObjectToWorld, half4(_Noise1Scroll.xyz / scale, 0)).xyz) : _Noise1Scroll.xyz; + float3 scale = GetObjectScale(); + float3 pos = _NoiseSpace ? (_NoiseSpace == 2 ? d.uv0.xyx : d.localSpacePosition) : d.worldSpacePosition; + half3 convertedScroll1Dir = _Noise1ScrollSpace ? (_Noise1ScrollSpace == 2 ? _Noise1Scroll.xyz : TransformObjectToWorld(_Noise1Scroll.xyz / scale)) : _Noise1Scroll.xyz; pos += _Time.y * convertedScroll1Dir; pos *= _Scale; if (_Noise1ScrollSpace == 2) { @@ -107,7 +105,7 @@ noise += 0.125 * getBakedNoise(_NoiseTex, sampler_NoiseTex, pos); pos = _NoiseSpace ? (_NoiseSpace == 2 ? d.uv0.xyx : d.localSpacePosition) : d.worldSpacePosition; - half3 convertedScroll2Dir = _Noise2ScrollSpace ? (_Noise2ScrollSpace == 2 ? _Noise2Scroll.xyz : mul(unity_ObjectToWorld, half4(_Noise2Scroll.xyz / scale , 0)).xyz) : _Noise2Scroll.xyz; + half3 convertedScroll2Dir = _Noise2ScrollSpace ? (_Noise2ScrollSpace == 2 ? _Noise2Scroll.xyz : TransformObjectToWorld(_Noise2Scroll.xyz / scale)) : _Noise2Scroll.xyz; pos += _Time.y * convertedScroll2Dir; pos *= _Scale2; if (_Noise1ScrollSpace == 2) { @@ -130,6 +128,9 @@ half waviness = SAMPLE_TEXTURE2D(_WavinessTex, sampler_WavinessTex, waveUv); waviness = saturate(invLerp(_WavinessContrast.x, _WavinessContrast.y, waviness)); + if (_LinearColor) { + d.vertexColor.rgb = pow(d.vertexColor.rgb, 2.2); + } o.Albedo = blended * lerp(_Color.rgb, d.vertexColor.rgb * _ColorBoost, _UseTrailColor); o.Alpha = blended * lerp(1, d.vertexColor.a, _UseTrailColor); o.Alpha *= waviness; diff --git a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Shield.orlshader b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Shield.orlshader index f795f6ed..c3cc53ab 100644 --- a/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Shield.orlshader +++ b/Packages/sh.orels.shaders/Runtime/Shaders/VFX/ORL VFX Shield.orlshader @@ -27,7 +27,7 @@ %ShaderTags() { - "Queue" = "Transparent" "RenderType" = "Transparent" + "Queue" = "Transparent" "RenderType" = "Transparent" "ORL_RenderType" = "Fade" } %ShaderFeatures() @@ -85,9 +85,8 @@ void ShieldVertex(inout VertexData v, inout FragmentData o) { #if defined(DEPTH_BLEND) - o.extraV2F0 = ComputeScreenPos(UnityObjectToClipPos(v.vertex)); - // COMPUTE_EYEDEPTH macro - o.extraV2F0.z = -UnityObjectToViewPos(v.vertex).z; + o.extraV2F0 = GetScreenPosition(TransformObjectToHClip(v.vertex)); + o.extraV2F0.z = -TransformWorldToView(TransformObjectToWorld(v.vertex)).z; #endif } } @@ -127,7 +126,7 @@ #if defined(DEPTH_BLEND) { - float sceneZ = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(d.extraV2F0))); + float sceneZ = LinearEyeDepth(SampleSceneDepth(d.extraV2F0.xy / d.extraV2F0.w)); float depth = sceneZ - d.extraV2F0.z; half3 pos = (_NoiseSpace ? d.localSpacePosition : d.worldSpacePosition.xyz) * 8; diff --git a/Packages/sh.orels.shaders/package.json b/Packages/sh.orels.shaders/package.json old mode 100644 new mode 100755 index 1b7437d5..dc5872db --- a/Packages/sh.orels.shaders/package.json +++ b/Packages/sh.orels.shaders/package.json @@ -2,13 +2,14 @@ "name": "sh.orels.shaders", "displayName": "ORL Shaders", "description": "PBR Unity shaders for the Built-In pipeline built with ORL Shader Generator", - "version": "6.3.0", + "version": "7.0.0-dev.11", "unity": "2019.4", "author": { "name": "orels1", "url": "https://github.com/orels1" }, "documentationUrl": "https://shaders.orels.sh/docs/", + "changelogUrl": "https://shaders.orels.sh/docs/changelog", "keywords": [ "shaders", "pbr", @@ -17,7 +18,7 @@ "license": "MIT", "type": "assets", "vpmDependencies": { - "sh.orels.shaders.generator": "^6.3.0", - "sh.orels.shaders.inspector": "^6.3.0" + "sh.orels.shaders.generator": "^7.0.0-dev.11", + "sh.orels.shaders.inspector": "^7.0.0-dev.11" } } \ No newline at end of file diff --git a/Packages/vpm-manifest.json b/Packages/vpm-manifest.json index 09adb364..86b28e08 100644 --- a/Packages/vpm-manifest.json +++ b/Packages/vpm-manifest.json @@ -1,12 +1,12 @@ { "dependencies": { "com.llealloo.audiolink": { - "version": "0.3.2" + "version": "2.0.0" } }, "locked": { "com.llealloo.audiolink": { - "version": "0.3.2", + "version": "2.0.0", "dependencies": {} } } diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index 0147887e..ab301dfc 100644 --- a/ProjectSettings/EditorBuildSettings.asset +++ b/ProjectSettings/EditorBuildSettings.asset @@ -5,4 +5,8 @@ EditorBuildSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_Scenes: [] - m_configObjects: {} + m_configObjects: + com.unity.xr.management.loader_settings: {fileID: 11400000, guid: d055be91edde58346858a256fc48b9bc, + type: 2} + xr.sdk.mock-hmd.settings: {fileID: 11400000, guid: 523de982ffb222948805e0b3022cc817, + type: 2} diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index a869f3d8..1939c5f5 100644 --- a/ProjectSettings/GraphicsSettings.asset +++ b/ProjectSettings/GraphicsSettings.asset @@ -3,7 +3,7 @@ --- !u!30 &1 GraphicsSettings: m_ObjectHideFlags: 0 - serializedVersion: 13 + serializedVersion: 15 m_Deferred: m_Mode: 1 m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} @@ -13,9 +13,6 @@ GraphicsSettings: m_ScreenSpaceShadows: m_Mode: 1 m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} - m_LegacyDeferred: - m_Mode: 1 - m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} m_DepthNormals: m_Mode: 1 m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} @@ -28,6 +25,7 @@ GraphicsSettings: m_LensFlare: m_Mode: 1 m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_VideoShadersIncludeMode: 2 m_AlwaysIncludedShaders: - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} @@ -35,7 +33,9 @@ GraphicsSettings: - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 4800000, guid: 24cc1c5665e5606448a9c668e2d6811e, type: 3} m_PreloadedShaders: [] + m_PreloadShadersBatchTimeLimit: -1 m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} m_CustomRenderPipeline: {fileID: 0} @@ -47,6 +47,7 @@ GraphicsSettings: m_LightmapStripping: 0 m_FogStripping: 0 m_InstancingStripping: 0 + m_BrgStripping: 0 m_LightmapKeepPlain: 1 m_LightmapKeepDirCombined: 1 m_LightmapKeepDynamicPlain: 1 @@ -59,5 +60,11 @@ GraphicsSettings: m_AlbedoSwatchInfos: [] m_LightsUseLinearIntensity: 1 m_LightsUseColorTemperature: 1 + m_DefaultRenderingLayerMask: 1 m_LogWhenShaderIsCompiled: 0 - m_AllowEnlightenSupportForUpgradedProject: 0 + m_SRPDefaultSettings: + UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: df45d3f5579f7b94fad9cadc76a704de, + type: 2} + m_LightProbeOutsideHullStrategy: 0 + m_CameraRelativeLightCulling: 0 + m_CameraRelativeShadowCulling: 0 diff --git a/ProjectSettings/InputManager.asset b/ProjectSettings/InputManager.asset index 17c8f538..6a65192d 100644 --- a/ProjectSettings/InputManager.asset +++ b/ProjectSettings/InputManager.asset @@ -293,3 +293,196 @@ InputManager: type: 0 axis: 0 joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: joystick button 8 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: backspace + altNegativeButton: + altPositiveButton: joystick button 9 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Reset + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Next + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page down + altNegativeButton: + altPositiveButton: joystick button 5 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Previous + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page up + altNegativeButton: + altPositiveButton: joystick button 4 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Validate + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Persistent + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: right shift + altNegativeButton: + altPositiveButton: joystick button 2 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Multiplier + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: joystick button 3 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 6 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 5 + joyNum: 0 + m_UsePhysicalKeys: 1 diff --git a/ProjectSettings/MemorySettings.asset b/ProjectSettings/MemorySettings.asset new file mode 100755 index 00000000..5b5facec --- /dev/null +++ b/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset old mode 100644 new mode 100755 index 7eecddb3..32ae2630 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 20 + serializedVersion: 26 productGUID: b3c5e0f91eedeff44a33fc4ff58cec69 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -48,12 +48,15 @@ PlayerSettings: defaultScreenHeightWeb: 600 m_StereoRenderingPath: 1 m_ActiveColorSpace: 1 + m_SpriteBatchVertexThreshold: 300 m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 iosUseCustomAppBackgroundBehavior: 0 - iosAllowHTTPDownload: 1 allowedAutorotateToPortrait: 1 allowedAutorotateToPortraitUpsideDown: 1 allowedAutorotateToLandscapeRight: 1 @@ -117,19 +120,19 @@ PlayerSettings: switchNVNShaderPoolsGranularity: 33554432 switchNVNDefaultPoolsGranularity: 16777216 switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 switchNVNMaxPublicTextureIDCount: 0 switchNVNMaxPublicSamplerIDCount: 0 + switchNVNGraphicsFirmwareMemory: 32 stadiaPresentMode: 0 stadiaTargetFramerate: 0 vulkanNumSwapchainBuffers: 3 vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 0 vulkanEnableLateAcquireNextImage: 0 - m_SupportedAspectRatios: - 4:3: 1 - 5:4: 1 - 16:10: 1 - 16:9: 1 - Others: 1 + vulkanEnableCommandBufferRecycling: 1 + loadStoreDebugModeEnabled: 0 bundleVersion: 0.1 preloadedAssets: [] metroInputSource: 0 @@ -138,45 +141,28 @@ PlayerSettings: xboxOneDisableKinectGpuReservation: 1 xboxOneEnable7thCore: 1 vrSettings: - cardboard: - depthFormat: 0 - enableTransitionView: 0 - daydream: - depthFormat: 0 - useSustainedPerformanceMode: 0 - enableVideoLayer: 0 - useProtectedVideoMemory: 0 - minimumSupportedHeadTracking: 0 - maximumSupportedHeadTracking: 1 - hololens: - depthFormat: 1 - depthBufferSharingEnabled: 1 - lumin: - depthFormat: 0 - frameTiming: 2 - enableGLCache: 0 - glCacheMaxBlobSize: 524288 - glCacheMaxFileSize: 8388608 - oculus: - sharedDepthBuffer: 1 - dashSupport: 1 - lowOverheadMode: 0 - protectedContext: 0 - v2Signing: 1 enable360StereoCapture: 0 isWsaHolographicRemotingEnabled: 0 enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 useHDRDisplay: 0 - D3DHDRBitDepth: 0 + hdrBitDepth: 0 m_ColorGamuts: 00000000 targetPixelDensity: 30 resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 - applicationIdentifier: {} - buildNumber: {} + applicationIdentifier: + Standalone: com.VRChat.vpm-package-maker + buildNumber: + Standalone: 0 + VisionOS: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 0 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 19 + AndroidMinSdkVersion: 22 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 aotOptions: @@ -189,12 +175,15 @@ PlayerSettings: APKExpansionFiles: 0 keepLoadedShadersAlive: 0 StripUnusedMeshComponents: 1 + strictShaderVariantMatching: 0 VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 - iOSTargetOSVersionString: 10.0 + iOSTargetOSVersionString: 12.0 tvOSSdkVersion: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 10.0 + tvOSTargetOSVersionString: 12.0 + VisionOSSdkVersion: 0 + VisionOSTargetOSVersionString: 1.0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 @@ -228,10 +217,11 @@ PlayerSettings: iOSLaunchScreeniPadFillPct: 100 iOSLaunchScreeniPadSize: 100 iOSLaunchScreeniPadCustomXibPath: - iOSUseLaunchScreenStoryboard: 0 iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: iOSDeviceRequirements: [] iOSURLSchemes: [] + macOSURLSchemes: [] iOSBackgroundModes: 0 iOSMetalForceHardShadows: 0 metalEditorSupport: 1 @@ -241,21 +231,33 @@ PlayerSettings: appleDeveloperTeamID: iOSManualSigningProvisioningProfileID: tvOSManualSigningProvisioningProfileID: + VisionOSManualSigningProvisioningProfileID: iOSManualSigningProvisioningProfileType: 0 tvOSManualSigningProvisioningProfileType: 0 + VisionOSManualSigningProvisioningProfileType: 0 appleEnableAutomaticSigning: 0 iOSRequireARKit: 0 iOSAutomaticallyDetectAndAddCapabilities: 1 appleEnableProMotion: 0 + shaderPrecisionModel: 0 clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea templatePackageId: com.unity.template.3d@4.2.8 templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 + useCustomProguardFile: 0 AndroidTargetArchitectures: 1 AndroidTargetDevices: 0 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} AndroidKeystoreName: AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 AndroidBuildApkPerCpuArchitecture: 0 AndroidTVCompatibility: 0 AndroidIsGame: 1 @@ -269,10 +271,201 @@ PlayerSettings: banner: {fileID: 0} androidGamepadSupportLevel: 0 chromeosInputEmulation: 1 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 AndroidValidateAppBundleSize: 1 AndroidAppBundleSizeToValidate: 150 m_BuildTargetIcons: [] - m_BuildTargetPlatformIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: iPhone + m_Icons: + - m_Textures: [] + m_Width: 180 + m_Height: 180 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 167 + m_Height: 167 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 152 + m_Height: 152 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 76 + m_Height: 76 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 87 + m_Height: 87 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 60 + m_Height: 60 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 20 + m_Height: 20 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 1024 + m_Height: 1024 + m_Kind: 4 + m_SubKind: App Store + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: m_BuildTargetBatching: - m_BuildTarget: Standalone m_StaticBatching: 1 @@ -289,6 +482,7 @@ PlayerSettings: - m_BuildTarget: WebGL m_StaticBatching: 0 m_DynamicBatching: 0 + m_BuildTargetShaderSettings: [] m_BuildTargetGraphicsJobs: - m_BuildTarget: MacStandaloneSupport m_GraphicsJobs: 0 @@ -330,7 +524,7 @@ PlayerSettings: m_Automatic: 1 - m_BuildTarget: AppleTVSupport m_APIs: 10000000 - m_Automatic: 0 + m_Automatic: 1 - m_BuildTarget: WebGLSupport m_APIs: 0b000000 m_Automatic: 1 @@ -345,6 +539,8 @@ PlayerSettings: - None - OpenVR - Oculus + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 openGLRequireES31: 0 openGLRequireES31AEP: 0 openGLRequireES32: 0 @@ -354,7 +550,11 @@ PlayerSettings: iPhone: 1 tvOS: 1 m_BuildTargetGroupLightmapEncodingQuality: [] + m_BuildTargetGroupHDRCubemapEncodingQuality: [] m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] + m_BuildTargetNormalMapEncoding: [] + m_BuildTargetDefaultTextureCompressionFormat: [] playModeTestRunnerEnabled: 0 runPlayModeTestAsEditModeTest: 0 actionOnDotNetUnhandledException: 1 @@ -364,14 +564,20 @@ PlayerSettings: cameraUsageDescription: locationUsageDescription: microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: 10.13.0 + switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 switchSocketAllocatorPoolSize: 128 switchSocketConcurrencyLimit: 14 switchScreenResolutionBehavior: 2 switchUseCPUProfiler: 0 + switchUseGOLDLinker: 0 + switchLTOSetting: 0 switchApplicationID: 0x01004b9000490000 switchNSODependencies: + switchCompilerFlags: switchTitleNames_0: switchTitleNames_1: switchTitleNames_2: @@ -445,7 +651,6 @@ PlayerSettings: switchReleaseVersion: 0 switchDisplayVersion: 1.0.0 switchStartupUserAccount: 0 - switchTouchScreenUsage: 0 switchSupportedLanguagesMask: 0 switchLogoType: 0 switchApplicationErrorCodeCategory: @@ -487,6 +692,7 @@ PlayerSettings: switchNativeFsCacheSize: 32 switchIsHoldTypeHorizontal: 0 switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 switchSocketConfigEnabled: 0 switchTcpInitialSendBufferSize: 32 switchTcpInitialReceiveBufferSize: 64 @@ -498,8 +704,12 @@ PlayerSettings: switchSocketInitializeEnabled: 1 switchNetworkInterfaceManagerInitializeEnabled: 1 switchPlayerConnectionEnabled: 1 + switchUseNewStyleFilepaths: 1 + switchUseLegacyFmodPriorities: 0 switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 ps4NPAgeRating: 12 ps4NPTitleSecret: ps4NPTrophyPackPath: @@ -575,31 +785,6 @@ PlayerSettings: ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] ps4attribVROutputEnabled: 0 - ps5ParamFilePath: - ps5VideoOutPixelFormat: 0 - ps5VideoOutInitialWidth: 1920 - ps5VideoOutOutputMode: 1 - ps5BackgroundImagePath: - ps5StartupImagePath: - ps5Pic2Path: - ps5StartupImagesFolder: - ps5IconImagesFolder: - ps5SaveDataImagePath: - ps5SdkOverride: - ps5BGMPath: - ps5ShareOverlayImagePath: - ps5NPConfigZipPath: - ps5Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ - ps5UseResolutionFallback: 0 - ps5UseAudio3dBackend: 0 - ps5ScriptOptimizationLevel: 2 - ps5Audio3dVirtualSpeakerCount: 14 - ps5UpdateReferencePackage: - ps5disableAutoHideSplash: 0 - ps5OperatingSystemCanDisableSplashScreen: 0 - ps5IncludedModules: [] - ps5SharedBinaryContentLabels: [] - ps5SharedBinarySystemFolders: [] monoEnv: splashScreenBackgroundSourceLandscape: {fileID: 0} splashScreenBackgroundSourcePortrait: {fileID: 0} @@ -608,6 +793,7 @@ PlayerSettings: webGLMemorySize: 16 webGLExceptionSupport: 1 webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 webGLDataCaching: 1 webGLDebugSymbols: 0 webGLEmscriptenArgs: @@ -616,34 +802,60 @@ PlayerSettings: webGLAnalyzeBuildSize: 0 webGLUseEmbeddedResources: 0 webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 webGLLinkerTarget: 1 webGLThreadsSupport: 0 - webGLWasmStreaming: 0 + webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 + webGLPowerPreference: 2 scriptingDefineSymbols: - 1: BAKERY_INCLUDED;UNITY_POST_PROCESSING_STACK_V2;AUDIOLINK;LTCGI_INCLUDED - 7: UNITY_POST_PROCESSING_STACK_V2 - 13: UNITY_POST_PROCESSING_STACK_V2 - 14: UNITY_POST_PROCESSING_STACK_V2 - 19: UNITY_POST_PROCESSING_STACK_V2 - 21: UNITY_POST_PROCESSING_STACK_V2 - 25: UNITY_POST_PROCESSING_STACK_V2 - 27: UNITY_POST_PROCESSING_STACK_V2 - 28: UNITY_POST_PROCESSING_STACK_V2 - 29: UNITY_POST_PROCESSING_STACK_V2 - 30: UNITY_POST_PROCESSING_STACK_V2 - 32: UNITY_POST_PROCESSING_STACK_V2 - 33: UNITY_POST_PROCESSING_STACK_V2 + Android: UNITY_POST_PROCESSING_STACK_V2 + EmbeddedLinux: UNITY_POST_PROCESSING_STACK_V2 + GameCoreXboxOne: UNITY_POST_PROCESSING_STACK_V2 + LinuxHeadlessSimulation: UNITY_POST_PROCESSING_STACK_V2 + Nintendo Switch: UNITY_POST_PROCESSING_STACK_V2 + PS4: UNITY_POST_PROCESSING_STACK_V2 + PS5: UNITY_POST_PROCESSING_STACK_V2 + QNX: UNITY_POST_PROCESSING_STACK_V2 + Stadia: UNITY_POST_PROCESSING_STACK_V2 + Standalone: BAKERY_INCLUDED;UNITY_POST_PROCESSING_STACK_V2;AUDIOLINK;LTCGI_INCLUDED;AUDIOLINK_V1;AMPLIFY_SHADER_EDITOR;DECALERY_INCLUDED + VisionOS: UNITY_POST_PROCESSING_STACK_V2 + WebGL: UNITY_POST_PROCESSING_STACK_V2 + Windows Store Apps: UNITY_POST_PROCESSING_STACK_V2 + XboxOne: UNITY_POST_PROCESSING_STACK_V2 + tvOS: UNITY_POST_PROCESSING_STACK_V2 + additionalCompilerArguments: {} platformArchitecture: {} scriptingBackend: {} il2cppCompilerConfiguration: {} - managedStrippingLevel: {} + il2cppCodeGeneration: {} + managedStrippingLevel: + EmbeddedLinux: 1 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + QNX: 1 + Stadia: 1 + VisionOS: 1 + WebGL: 1 + Windows Store Apps: 1 + XboxOne: 1 + iPhone: 1 + tvOS: 1 incrementalIl2cppBuild: {} suppressCommonWarnings: 1 allowUnsafeCode: 0 + useDeterministicCompilation: 1 additionalIl2CppArgs: scriptingRuntimeVersion: 1 gcIncremental: 1 - assemblyVersionValidation: 1 gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: Standalone: 3 @@ -676,6 +888,7 @@ PlayerSettings: metroFTAName: metroFTAFileTypes: [] metroProtocolName: + vcxProjDefaultLanguage: XboxOneProductId: XboxOneUpdateKey: XboxOneSandboxId: @@ -703,10 +916,7 @@ PlayerSettings: XboxOneXTitleMemory: 8 XboxOneOverrideIdentityName: XboxOneOverrideIdentityPublisher: - vrEditorSettings: - daydream: - daydreamIconForeground: {fileID: 0} - daydreamIconBackground: {fileID: 0} + vrEditorSettings: {} cloudServicesEnabled: UNet: 1 luminIcon: @@ -720,12 +930,22 @@ PlayerSettings: luminVersion: m_VersionCode: 1 m_VersionName: + hmiPlayerDataPath: + hmiForceSRGBBlit: 1 + embeddedLinuxEnableGamepadInput: 1 + hmiLogStartupTiming: 0 + hmiCpuConfiguration: apiCompatibilityLevel: 6 + activeInputHandler: 0 + windowsGamepadBackendHint: 0 cloudProjectId: framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] projectName: organizationId: cloudEnabled: 0 - enableNativePlatformBackendsForNewInputSystem: 0 - disableOldInputManagerSupport: 0 legacyClampBlendShapeWeights: 0 + hmiLoadingImage: {fileID: 0} + platformRequiresReadableAssets: 0 + virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt old mode 100644 new mode 100755 index 5549a7fd..c47c8be7 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2019.4.31f1 -m_EditorVersionWithRevision: 2019.4.31f1 (bd5abf232a62) +m_EditorVersion: 2022.3.22f1 +m_EditorVersionWithRevision: 2022.3.22f1 (887be4894c44) diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset index 92428a34..7cf3bafd 100644 --- a/ProjectSettings/QualitySettings.asset +++ b/ProjectSettings/QualitySettings.asset @@ -6,7 +6,7 @@ QualitySettings: serializedVersion: 5 m_CurrentQuality: 3 m_QualitySettings: - - serializedVersion: 2 + - serializedVersion: 3 name: VRC Low pixelLightCount: 4 shadows: 2 @@ -19,16 +19,20 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 skinWeights: 4 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 2 antiAliasing: 0 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 vSyncCount: 0 + realtimeGICPUUsage: 25 lodBias: 1 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -41,9 +45,18 @@ QualitySettings: asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: - Android - - serializedVersion: 2 + - serializedVersion: 3 name: VRC Medium pixelLightCount: 4 shadows: 2 @@ -56,16 +69,20 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 skinWeights: 4 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 2 antiAliasing: 4 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 vSyncCount: 0 + realtimeGICPUUsage: 25 lodBias: 1.5 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -78,9 +95,18 @@ QualitySettings: asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: - Android - - serializedVersion: 2 + - serializedVersion: 3 name: VRC High pixelLightCount: 8 shadows: 2 @@ -93,16 +119,20 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 skinWeights: 4 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 2 antiAliasing: 4 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 vSyncCount: 0 + realtimeGICPUUsage: 25 lodBias: 2 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -115,31 +145,44 @@ QualitySettings: asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: - Android - - serializedVersion: 2 + - serializedVersion: 3 name: VRC Ultra pixelLightCount: 8 shadows: 2 shadowResolution: 3 shadowProjection: 1 shadowCascades: 4 - shadowDistance: 150 + shadowDistance: 1000 shadowNearPlaneOffset: 2 shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 skinWeights: 4 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 2 antiAliasing: 4 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 vSyncCount: 0 + realtimeGICPUUsage: 50 lodBias: 2 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -152,9 +195,18 @@ QualitySettings: asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: - Android - - serializedVersion: 2 + - serializedVersion: 3 name: VRC Mobile pixelLightCount: 4 shadows: 0 @@ -167,16 +219,20 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 skinWeights: 4 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 2 antiAliasing: 2 softParticles: 0 softVegetation: 0 realtimeReflectionProbes: 0 billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 vSyncCount: 0 + realtimeGICPUUsage: 50 lodBias: 2 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -189,8 +245,20 @@ QualitySettings: asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: - Standalone + m_TextureMipmapLimitGroupNames: [] m_PerPlatformDefaultQuality: Android: 0 + Server: 0 Standalone: 0 + iPhone: 0 diff --git a/ProjectSettings/SceneTemplateSettings.json b/ProjectSettings/SceneTemplateSettings.json new file mode 100755 index 00000000..5e97f839 --- /dev/null +++ b/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,121 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicMaterial", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "defaultInstantiationMode": 0 + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "defaultInstantiationMode": 1 + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/ProjectSettings/ShaderGraphSettings.asset b/ProjectSettings/ShaderGraphSettings.asset new file mode 100644 index 00000000..9b43acd4 --- /dev/null +++ b/ProjectSettings/ShaderGraphSettings.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 53 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de02f9e1d18f588468e474319d09a723, type: 3} + m_Name: + m_EditorClassIdentifier: + shaderVariantLimit: 128 + customInterpolatorErrorThreshold: 32 + customInterpolatorWarningThreshold: 16 diff --git a/ProjectSettings/TimelineSettings.asset b/ProjectSettings/TimelineSettings.asset new file mode 100644 index 00000000..b21943ab --- /dev/null +++ b/ProjectSettings/TimelineSettings.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 53 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a287be6c49135cd4f9b2b8666c39d999, type: 3} + m_Name: + m_EditorClassIdentifier: + assetDefaultFramerate: 60 + m_DefaultFrameRate: 60 diff --git a/ProjectSettings/VersionControlSettings.asset b/ProjectSettings/VersionControlSettings.asset new file mode 100755 index 00000000..dca28814 --- /dev/null +++ b/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/ProjectSettings/XRPackageSettings.asset b/ProjectSettings/XRPackageSettings.asset new file mode 100644 index 00000000..7e791e17 --- /dev/null +++ b/ProjectSettings/XRPackageSettings.asset @@ -0,0 +1,5 @@ +{ + "m_Settings": [ + "RemoveLegacyInputHelpersForReload" + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 375dfe21..7f2d696a 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ You should grab the top `.unitypackage` file from the latest release. It contains all the shaders and tools. It should be named like ``` -sh.orels.shaders-full-X.X.X.unitypackage +sh.orels.shaders-combined-X.X.X.unitypackage ``` ## For VCC users diff --git a/Scripts/BundleShaderParser.ps1 b/Scripts/BundleShaderParser.ps1 new file mode 100755 index 00000000..ad302927 --- /dev/null +++ b/Scripts/BundleShaderParser.ps1 @@ -0,0 +1,4 @@ +dotnet-combine single-file ..\UnityShaderParser\UnityShaderParser --output ./Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/UnityShaderParser.cs --overwrite + +Copy-Item ..\UnityShaderParser\LICENSE ./Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/LICENSE.txt +Copy-Item ..\UnityShaderParser\README.md ./Packages/sh.orels.shaders.generator/Editor/Dependencies/UnityShaderParser/README.md \ No newline at end of file diff --git a/Scripts/SetVersion.csx b/Scripts/SetVersion.csx index f28e9123..569e459a 100644 --- a/Scripts/SetVersion.csx +++ b/Scripts/SetVersion.csx @@ -1,6 +1,8 @@ #r "nuget: CommandLineParser, 2.9.1" +#r "nuget: SemanticVersioning, 3.0.0-beta2" using CommandLine; +using SemanticVersioning; using System.Text.Json; using System.Text.Json.Nodes; @@ -33,6 +35,8 @@ public class Options [Value(0)] public string Version { get; set; } + [Option("deps", HelpText = "Updates dependencies to use the new version (lockstep release)")] + public bool UpdateDependencies { get; set; } } Dictionary PackageIds = new() { @@ -92,6 +96,39 @@ Parser.Default.ParseArguments(Args) if (settingExactVersion) { Console.WriteLine($" -> {o.Version}"); packageJSON["version"] = o.Version; + + // Update lockstep deps + if (o.UpdateDependencies && packageJSON!["name"]!.ToString() == "sh.orels.shaders") { + Console.WriteLine($"Updating dependencies to {o.Version} as well"); + packageJSON["vpmDependencies"]["sh.orels.shaders.generator"] = $"^{o.Version}"; + packageJSON["vpmDependencies"]["sh.orels.shaders.inspector"] = $"^{o.Version}"; + } + } else if (!string.IsNullOrWhiteSpace(o.NewBetaVersion)) { + var newVersion = $"{version}-{o.NewBetaVersion}.1"; + Console.WriteLine($" -> {newVersion}"); + packageJSON["version"] = newVersion; + + if (o.UpdateDependencies && packageJSON!["name"]!.ToString() == "sh.orels.shaders") { + Console.WriteLine($"Updating dependencies to {newVersion} as well"); + packageJSON["vpmDependencies"]["sh.orels.shaders.generator"] = $"^{newVersion}"; + packageJSON["vpmDependencies"]["sh.orels.shaders.inspector"] = $"^{newVersion}"; + } + } else if (o.Beta) { + var parsed = new Version(version.ToString()); + if (!parsed.IsPreRelease) { + Console.WriteLine($"\nVersion {version} is not a pre-release, cannot bump"); + return; + } + var preReleaseSplit = parsed.PreRelease.Split('.'); + var newVersion = $"{parsed.Major}.{parsed.Minor}.{parsed.Patch}-{preReleaseSplit[0]}.{int.Parse(preReleaseSplit[1]) + 1}"; + packageJSON["version"] = newVersion; + Console.WriteLine($" -> {newVersion}"); + + if (o.UpdateDependencies && packageJSON!["name"]!.ToString() == "sh.orels.shaders") { + Console.WriteLine($"Updating dependencies to {newVersion} as well"); + packageJSON["vpmDependencies"]["sh.orels.shaders.generator"] = $"^{newVersion}"; + packageJSON["vpmDependencies"]["sh.orels.shaders.inspector"] = $"^{newVersion}"; + } } File.WriteAllText(packagePath, packageJSON!.ToJsonString(new JsonSerializerOptions { WriteIndented = true })); } diff --git a/UserSettings/.gitkeep b/UserSettings/.gitkeep new file mode 100644 index 00000000..e69de29b