├── .github
└── workflows
│ └── main.yml
├── .idea
└── .idea.shadergraphenhancer.dir
│ └── .idea
│ ├── .gitignore
│ ├── encodings.xml
│ ├── indexLayout.xml
│ └── vcs.xml
├── Editor.meta
├── Editor
├── KeyboardShortcut.cs
├── KeyboardShortcut.cs.meta
├── PackageCacheOverrider.cs
├── PackageCacheOverrider.cs.meta
├── Seonghwan.ShaderGraph.Enhancer.Editor.asmdef
└── Seonghwan.ShaderGraph.Enhancer.Editor.asmdef.meta
├── LICENSE
├── LICENSE.meta
├── README.md
├── README.md.meta
├── package.json
└── package.json.meta
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Publish to npm
2 |
3 | # Controls when the action will run.
4 | # In this case, I'm saying on each release event when it's specifically a new release publish, the types: [published] is required here,
5 | # since releases could also be updated or deleted, we only want to publish to npm when a new release is created (published).
6 | on:
7 | release:
8 | types: [published]
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
15 | - uses: actions/checkout@v2
16 | #Install Node.js, with the version 12 and using the registry URL of npm, this could be changed to a custom registry or the GitHub registry.
17 | - uses: actions/setup-node@v1
18 | with:
19 | node-version: 12
20 | registry-url: https://registry.npmjs.org/
21 |
22 | # Command to install the package dependencies
23 | - run: yarn install
24 |
25 | # Publish to npm
26 | - run: npm publish --access public
27 | env:
28 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
29 |
--------------------------------------------------------------------------------
/.idea/.idea.shadergraphenhancer.dir/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /modules.xml
6 | /contentModel.xml
7 | /projectSettingsUpdater.xml
8 | /.idea.shadergraphenhancer.iml
9 | # Datasource local storage ignored files
10 | /dataSources/
11 | /dataSources.local.xml
12 | # Editor-based HTTP Client requests
13 | /httpRequests/
14 |
--------------------------------------------------------------------------------
/.idea/.idea.shadergraphenhancer.dir/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/.idea.shadergraphenhancer.dir/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/.idea.shadergraphenhancer.dir/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 30a0af1b4f1035543a062a3f9ca9a6e7
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/KeyboardShortcut.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using System.Reflection.Emit;
5 | using System.Runtime.CompilerServices;
6 | using UnityEditor;
7 | using UnityEngine;
8 | using UnityEngine.Assertions;
9 | using UnityEngine.UIElements;
10 |
11 | namespace ShaderGraphEnhancer
12 | {
13 | #if SGE_INSTALLED
14 | using UnityEditor.ShaderGraph;
15 | using UnityEditor.ShaderGraph.Drawing;
16 | #else
17 | public class MaterialGraphView {}
18 | public class GraphData { }
19 |
20 | public class AbstractMaterialNode { }
21 | #endif
22 |
23 | internal class KeyboardShortcutHelper
24 | {
25 | private MaterialGraphView GraphView { get; }
26 | private GraphData GraphData { get; }
27 |
28 | public KeyboardShortcutHelper(MaterialGraphView graphView, GraphData graph)
29 | {
30 | #if SGE_INSTALLED
31 | GraphView = graphView;
32 | GraphData = graph;
33 |
34 | GraphView.RegisterCallback(OnKeyDown);
35 | #endif
36 | }
37 |
38 | void OnKeyDown(KeyDownEvent evt) {
39 | #if SGE_INSTALLED
40 |
41 |
42 | if (GraphData == null) return;
43 |
44 | Vector2 pos = evt.originalMousePosition;
45 |
46 | switch (evt.keyCode) {
47 | case KeyCode.O:
48 | CreateNode(() => new OneMinusNode(), pos);
49 | break;
50 | case KeyCode.M:
51 | CreateNode(() => new MultiplyNode(), pos);
52 | break;
53 | case KeyCode.L:
54 | CreateNode(() => new LerpNode(), pos);
55 | break;
56 | case KeyCode.D:
57 | CreateNode(() => new DivideNode(), pos);
58 | break;
59 | case KeyCode.S:
60 | CreateNode(() => new SubtractNode(), pos);
61 | break;
62 | case KeyCode.A:
63 | CreateNode(() => new AddNode(), pos);
64 | break;
65 | case KeyCode.F:
66 | CreateNode(() => new FractionNode(), pos);
67 | break;
68 | case KeyCode.Alpha1:
69 | CreateNode(() => new Vector1Node(), pos);
70 | break;
71 | case KeyCode.Alpha2:
72 | CreateNode(() => new Vector2Node(), pos);
73 | break;
74 | case KeyCode.Alpha3:
75 | CreateNode(() => new Vector3Node(), pos);
76 | break;
77 | case KeyCode.Alpha4:
78 | CreateNode(() => new Vector4Node(), pos);
79 | break;
80 | case KeyCode.Alpha5:
81 | CreateNode(() => new ColorNode(), pos);
82 | break;
83 | }
84 | #endif
85 | }
86 |
87 | private void CreateNode(Func createNode, Vector2 pos) {
88 | #if SGE_INSTALLED
89 | AbstractMaterialNode multiplyNode = createNode();
90 |
91 | var drawState = multiplyNode.drawState;
92 | Vector2 p = GraphView.contentViewContainer.WorldToLocal(pos);
93 |
94 | drawState.position = new Rect(p.x, p.y, drawState.position.width, drawState.position.height);
95 | multiplyNode.drawState = drawState;
96 | GraphData.AddNode(multiplyNode);
97 | #endif
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/Editor/KeyboardShortcut.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3b5538db0b4781c4da1fe30e06739089
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/PackageCacheOverrider.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 | using UnityEditor;
4 | using UnityEngine;
5 | using UnityEngine.Assertions;
6 | using UnityEngine.Rendering;
7 |
8 | namespace ShaderGraphEnhancer
9 | {
10 | public class PackageCacheOverrider
11 | {
12 | const string pre =
13 | "[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(\"Seonghwan.ShaderGraph.Enhancer.Editor\")]";
14 |
15 | [InitializeOnLoadMethod]
16 | private static void Override()
17 | {
18 | string packageCachePath = Application.dataPath.Replace("/Assets", "/Library/PackageCache");
19 | DirectoryInfo packageCache = new DirectoryInfo(packageCachePath);
20 |
21 | DirectoryInfo shaderGraphPackage = null;
22 | foreach (DirectoryInfo directoryInfo in packageCache.GetDirectories())
23 | {
24 | if (directoryInfo.Name.Contains("com.unity.shadergraph@"))
25 | {
26 | shaderGraphPackage = directoryInfo;
27 | break;
28 | }
29 | else
30 | {
31 | // Debug.Log(directoryInfo.Name);
32 | }
33 | }
34 |
35 | Assert.IsNotNull(shaderGraphPackage);
36 |
37 | string filePath = shaderGraphPackage.FullName + "/Editor/Drawing/Views/GraphEditorView.cs";
38 | FileInfo file = new FileInfo(filePath);
39 |
40 | Assert.IsTrue(file.Exists);
41 |
42 | var defines =
43 | PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings
44 | .selectedBuildTargetGroup);
45 |
46 | string text = File.ReadAllText(filePath);
47 | string[] lines = File.ReadAllLines(filePath);
48 | if (text.Contains(pre))
49 | {
50 | Run();
51 | }
52 | else
53 | {
54 | var removed = defines.Replace("SGE_INSTALLED", "");
55 | PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup,
56 | removed);
57 |
58 | Install();
59 | }
60 |
61 |
62 | if(!defines.Contains("SGE_INSTALLED"))
63 | PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup,
64 | defines + ";SGE_INSTALLED");
65 |
66 | EditorApplication.wantsToQuit += () =>
67 | {
68 | var defines =
69 | PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings
70 | .selectedBuildTargetGroup);
71 | var removed = defines.Replace("SGE_INSTALLED", "");
72 | PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup,
73 | removed);
74 |
75 | return true;
76 | };
77 |
78 | void Install()
79 | {
80 | StringBuilder sb = new StringBuilder(text.Length + 256);
81 | sb.AppendLine("#define SG_HOOKED");
82 | for (int i = 0; i < lines.Length; i++)
83 | {
84 | if (lines[i].StartsWith("using")) { }
85 | }
86 |
87 | text = text.Replace("namespace UnityEditor.ShaderGraph.Drawing",
88 | $"{pre}\n\nnamespace UnityEditor.ShaderGraph.Drawing")
89 | .Replace("MaterialGraphView m_GraphView;",
90 | "public static Action installedCallback;\n\t\t\t\tMaterialGraphView m_GraphView;")
91 | .Replace("m_InspectorView.InitializeGraphSettings();",
92 | "m_InspectorView.InitializeGraphSettings();\n\t\t\t\tinstalledCallback?.Invoke(graphView, graph);")
93 | ;
94 | File.WriteAllText(filePath, text);
95 |
96 | var defines =
97 | PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings
98 | .selectedBuildTargetGroup);
99 |
100 | if(!defines.Contains("SGE_INSTALLED"))
101 | PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup,
102 | defines + ";SGE_INSTALLED");
103 | }
104 |
105 | void Run()
106 | {
107 | #if SGE_INSTALLED
108 | UnityEditor.ShaderGraph.Drawing.GraphEditorView.installedCallback += (v, g) =>
109 | {
110 | KeyboardShortcutHelper keyboardShortcutHelper = new KeyboardShortcutHelper(v, g);
111 | };
112 | #endif
113 | }
114 | }
115 |
116 | [MenuItem("Tools/ShaderGraph Key2Node/Force Resolve")]
117 | static void ForceInstall()
118 | {
119 | bool yes = EditorUtility.DisplayDialog("Force Resolve", "Resolve ShaderGraph Enhancer",
120 | "Resolve", "Cancel");
121 |
122 | if (!yes) return;
123 |
124 | string packageCachePath = Application.dataPath.Replace("/Assets", "/Library/PackageCache");
125 | DirectoryInfo packageCache = new DirectoryInfo(packageCachePath);
126 |
127 | DirectoryInfo shaderGraphPackage = null;
128 | foreach (DirectoryInfo directoryInfo in packageCache.GetDirectories())
129 | {
130 | if (directoryInfo.Name.Contains("com.unity.shadergraph@"))
131 | {
132 | shaderGraphPackage = directoryInfo;
133 | break;
134 | }
135 | else
136 | {
137 | Debug.Log(directoryInfo.Name);
138 | }
139 | }
140 |
141 | Assert.IsNotNull(shaderGraphPackage);
142 |
143 | string filePath = shaderGraphPackage.FullName + "/Editor/Drawing/Views/GraphEditorView.cs";
144 |
145 | string text = File.ReadAllText(filePath);
146 | string[] lines = File.ReadAllLines(filePath);
147 |
148 | StringBuilder sb = new StringBuilder(text.Length + 256);
149 | sb.AppendLine("#define SG_HOOKED");
150 | for (int i = 0; i < lines.Length; i++)
151 | {
152 | if (lines[i].StartsWith("using")) { }
153 | }
154 |
155 | text = text.Replace("namespace UnityEditor.ShaderGraph.Drawing",
156 | $"{pre}\n\nnamespace UnityEditor.ShaderGraph.Drawing")
157 | .Replace("MaterialGraphView m_GraphView;",
158 | "public static Action installedCallback;\n\t\t\t\tMaterialGraphView m_GraphView;")
159 | .Replace("m_InspectorView.InitializeGraphSettings();",
160 | "m_InspectorView.InitializeGraphSettings();\n\t\t\t\tinstalledCallback?.Invoke(graphView, graph);")
161 | ;
162 | File.WriteAllText(filePath, text);
163 |
164 | var defines =
165 | PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings
166 | .selectedBuildTargetGroup);
167 | if(!defines.Contains("SGE_INSTALLED"))
168 | PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup,
169 | defines + ";SGE_INSTALLED");
170 |
171 | EditorApplication.wantsToQuit += () =>
172 | {
173 | var defines =
174 | PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings
175 | .selectedBuildTargetGroup);
176 | var removed = defines.Replace("SGE_INSTALLED", "");
177 | PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup,
178 | removed);
179 |
180 | return true;
181 | };
182 | }
183 |
184 | [MenuItem("Tools/ShaderGraph Key2Node/Clean Uninstall")]
185 | static void CleanRemove()
186 | {
187 | bool yes = EditorUtility.DisplayDialog("Uninstall", "Uninstalling ShaderGraph Enhancer package",
188 | "Uninstall", "Cancel");
189 |
190 | if (!yes) return;
191 |
192 | var defines =
193 | PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings
194 | .selectedBuildTargetGroup);
195 | var removed = defines.Replace("SGE_INSTALLED", "");
196 | PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup,
197 | removed);
198 | UnityEditor.PackageManager.Client.Remove("com.unity.seonghwan.shadergraph-enhancer");
199 | }
200 | }
201 | }
--------------------------------------------------------------------------------
/Editor/PackageCacheOverrider.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d92b52974c1c4af8bf7230c659d6b299
3 | timeCreated: 1620037281
--------------------------------------------------------------------------------
/Editor/Seonghwan.ShaderGraph.Enhancer.Editor.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Seonghwan.ShaderGraph.Enhancer.Editor",
3 | "rootNamespace": "",
4 | "references": [
5 | "GUID:ade7125e800904674ba0c115208f7ed5",
6 | "GUID:be0903cd8e1546f498710afdc59db5eb",
7 | "GUID:df380645f10b7bc4b97d4f5eb6303d95",
8 | "GUID:3eae0364be2026648bf74846acb8a731",
9 | "GUID:de1079f91ae5b43499b7c7e4f1269884"
10 | ],
11 | "includePlatforms": [
12 | "Editor"
13 | ],
14 | "excludePlatforms": [],
15 | "allowUnsafeCode": false,
16 | "overrideReferences": false,
17 | "precompiledReferences": [],
18 | "autoReferenced": true,
19 | "defineConstraints": [],
20 | "versionDefines": [],
21 | "noEngineReferences": false
22 | }
--------------------------------------------------------------------------------
/Editor/Seonghwan.ShaderGraph.Enhancer.Editor.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 41edab38ebfb92441a3b24991f9e7cd6
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 seonghwan-dev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: db1596a08e63b4c4aad23d6d5a0ad39f
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ShaderGraph Key2Node
2 | Simple shortcut system into unity shader graph without modifying package by hacking style.
3 |
4 | Reference - [Unity Forum Thread](https://forum.unity.com/threads/keyboard-shortcuts-are-an-essential-and-missing-feature.852154/) by DigitalSalmon.
5 |
6 | ### Installation
7 | #### way 1. unity-package
8 | this repo can be imported as open unity package.
9 | add https://github.com/seonghwan-dev/shadergraph-key2node.git in package manager.
10 | #### way 2. npmjs
11 | in `Packages/manifest.json` ...
12 |
13 | ```json
14 | {
15 | "dependencies": {
16 | "kr.seonghwan.shadergraph-key2node": "1.0.0"
17 | }
18 | }
19 | ```
20 |
21 | ```json
22 | {
23 | "scopedRegistries": [
24 | {
25 | "name": "NPM",
26 | "url": "https://registry.npmjs.org",
27 | "scopes": [
28 | "kr.seonghwan"
29 | ]
30 | }
31 | ]
32 | }
33 | ```
34 |
35 |
36 |
37 | ### Uninstallation
38 | use menuitem `Tools/ShaderGraph Key2Node/Clean Uninstall`
39 |
40 | ### Trouble shooting
41 | run menuitem `Tools/ShaderGraph Key2Node/Force Resolve`
42 |
43 | ### Why should I use in this way?
44 | You don't have to. this is an expedient to avoid modifying the Shader Graph packge in every project. We can mofidy the original package caches in appdata, but it's local way so its not fit. I tried to implement this feature without editing original package by hooking several functions in loaded assembly on unity editor but it requires lots of things to consider.
45 |
46 | ### How this works?
47 | 1. script installs static delegates at the source file in `ProjectRoot`/Library/PackageCache/com.unity.shadergraph@x.x.x/editor/drawing/views/grapheditorview.cs
48 | 2. add callbacks to installed delegate when domain reloaded. (`[InitializedOnLoad]`)
49 | 3. when constructor of grapheditorview is called, installed delegates invoked.
50 |
51 | ### Warning
52 | - takes more time after compilation because of InitializeOnLoad
53 | - takes more time in starting unity editor because of installing delegates and callbacks every unity editor instance.
54 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9d5342a50bbf8864d9f38c924df09389
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kr.seonghwan.shadergraph-key2node",
3 | "displayName": "Shader Graph Key To Node",
4 | "version": "1.0.0",
5 | "unity": "2019.3",
6 | "description": "Foundation package allows to use node shorcut in hacky-style.",
7 | "homepage": "https://github.com/seonghwan-dev/shadergraph-key2node",
8 | "bugs": {
9 | "url": "https://github.com/seonghwan-dev/shadergraph-key2node/issues"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "ssh://git@github.com:seonghwan-dev/shadergraph-key2node.git"
14 | },
15 | "license":"MIT",
16 | "author": {
17 | "name": "Seonghwan",
18 | "url": "https://github.com/seonghwan-dev"
19 | },
20 | "keywords": [
21 | "shadergraph",
22 | "shortcut",
23 | "utility",
24 | "unity"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: be877fdde47c01047b65f8330c03a8b8
3 | PackageManifestImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------