├── .gitattributes ├── .gitignore ├── Assets ├── GPUGraph.meta └── GPUGraph │ ├── Editor.meta │ ├── Editor │ ├── Applications.meta │ ├── Applications │ │ ├── ShaderGenerator.cs │ │ ├── ShaderGenerator.cs.meta │ │ ├── TerrainGenerator.cs │ │ ├── TerrainGenerator.cs.meta │ │ ├── Texture2DGenerator.cs │ │ ├── Texture2DGenerator.cs.meta │ │ ├── Texture3DGenerator.cs │ │ ├── Texture3DGenerator.cs.meta │ │ ├── TextureGenerator.cs │ │ └── TextureGenerator.cs.meta │ ├── GUIUtil.cs │ ├── GUIUtil.cs.meta │ ├── Graph System.meta │ ├── Graph System │ │ ├── Editor.meta │ │ ├── Editor │ │ │ ├── GraphEditor.cs │ │ │ ├── GraphEditor.cs.meta │ │ │ ├── NodeOptionsGenerator.cs │ │ │ └── NodeOptionsGenerator.cs.meta │ │ ├── GpuRand.cginc │ │ ├── GpuRand.cginc.meta │ │ ├── Graph.cs │ │ ├── Graph.cs.meta │ │ ├── GraphEditorUtils.cs │ │ ├── GraphEditorUtils.cs.meta │ │ ├── GraphParamCollection.cs │ │ ├── GraphParamCollection.cs.meta │ │ ├── Node.cs │ │ ├── Node.cs.meta │ │ ├── NodeInput.cs │ │ ├── NodeInput.cs.meta │ │ ├── Nodes.meta │ │ ├── Nodes │ │ │ ├── CustomExprNode.cs │ │ │ ├── CustomExprNode.cs.meta │ │ │ ├── NoiseNode.cs │ │ │ ├── NoiseNode.cs.meta │ │ │ ├── ParamNode_Float.cs │ │ │ ├── ParamNode_Float.cs.meta │ │ │ ├── ParamNode_Texture2D.cs │ │ │ ├── ParamNode_Texture2D.cs.meta │ │ │ ├── SimpleNode.cs │ │ │ ├── SimpleNode.cs.meta │ │ │ ├── SubGraphNode.cs │ │ │ ├── SubGraphNode.cs.meta │ │ │ ├── TexCoordNode.cs │ │ │ └── TexCoordNode.cs.meta │ │ ├── ShaderDefs.cs │ │ └── ShaderDefs.cs.meta │ ├── RunTimeGraphEditor.cs │ ├── RunTimeGraphEditor.cs.meta │ ├── StringUtils.cs │ └── StringUtils.cs.meta │ ├── GpuRand.cginc │ ├── GpuRand.cginc.meta │ ├── GpuRandWithState.cginc │ ├── GpuRandWithState.cginc.meta │ ├── LICENSE.txt │ ├── LICENSE.txt.meta │ ├── README.md │ ├── README.md.meta │ ├── Runtime.meta │ ├── Runtime │ ├── GraphUtils.cs │ ├── GraphUtils.cs.meta │ ├── RuntimeGraph.cs │ └── RuntimeGraph.cs.meta │ ├── Sample.meta │ └── Sample │ ├── SampleGPUGScript.cs │ ├── SampleGPUGScript.cs.meta │ ├── SampleGraph.gpug │ ├── SampleGraph.gpug.meta │ ├── SampleScene.unity │ └── SampleScene.unity.meta ├── GPUGraph.unitypackage ├── LICENSE.txt ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── Physics2DSettings.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset ├── UnityAdsSettings.asset └── UnityConnectSettings.asset ├── README.md └── Readme Images ├── BigIcon.png ├── BigIcon2.png ├── SmallIcon.png ├── TinyIcon.png └── WhiteNoise.png /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | [Ll]ibrary/ 2 | [Tt]emp/ 3 | [Oo]bj/ 4 | [Bb]uild/ 5 | 6 | # Autogenerated VS/MD solution and project files 7 | .vs/ 8 | /*.csproj 9 | /*.unityproj 10 | /*.sln 11 | /*.suo 12 | *.suo 13 | /*.user 14 | /*.userprefs 15 | /*.pidb 16 | /*.booproj 17 | 18 | #Unity3D Generated File On Crash Reports 19 | sysinfo.txt 20 | 21 | # ========================= 22 | # Operating System Files 23 | # ========================= 24 | 25 | # OSX 26 | # ========================= 27 | 28 | .DS_Store 29 | .AppleDouble 30 | .LSOverride 31 | 32 | # Thumbnails 33 | ._* 34 | 35 | # Files that might appear on external disk 36 | .Spotlight-V100 37 | .Trashes 38 | 39 | # Directories potentially created on remote AFP share 40 | .AppleDB 41 | .AppleDesktop 42 | Network Trash Folder 43 | Temporary Items 44 | .apdisk 45 | 46 | # Windows 47 | # ========================= 48 | 49 | # Windows image file caches 50 | Thumbs.db 51 | ehthumbs.db 52 | 53 | # Folder config file 54 | Desktop.ini 55 | 56 | # Recycle Bin used on file shares 57 | $RECYCLE.BIN/ 58 | 59 | # Windows Installer files 60 | *.cab 61 | *.msi 62 | *.msm 63 | *.msp 64 | 65 | # Windows shortcuts 66 | *.lnk 67 | 68 | 69 | # Custom 70 | Assets/UnityVS 71 | Assets/UnityVS.meta 72 | Assets/AssetStoreTools* 73 | Assets/GPUGraph/Resources/ -------------------------------------------------------------------------------- /Assets/GPUGraph.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 58ba3f1ec1ef330418027d62c21f2593 3 | folderAsset: yes 4 | timeCreated: 1455837384 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 14da2d9540b13c4449b2c741ee6f91a1 3 | folderAsset: yes 4 | timeCreated: 1444260070 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5cdffd8243acf59449728155dc8f42a6 3 | folderAsset: yes 4 | timeCreated: 1444256280 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/ShaderGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Collections.Generic; 5 | using UnityEngine; 6 | using UnityEngine.Rendering; 7 | using UnityEditor; 8 | using GPUGraph; 9 | 10 | 11 | namespace GPUGraph.Applications 12 | { 13 | public class ShaderGenerator : EditorWindow 14 | { 15 | [MenuItem("Assets/GPU Graph/Generate Shader", false, 2)] 16 | public static void GenerateTexture() 17 | { 18 | ScriptableObject.CreateInstance().Show(); 19 | } 20 | 21 | 22 | private bool useRed = true, 23 | useGreen = true, 24 | useBlue = true, 25 | useAlpha = false; 26 | private float unusedColor = 1.0f; 27 | private string shaderName = "Noise/My Noise"; 28 | private int selectedGraphIndex = 0; 29 | 30 | private List graphPaths = new List(); 31 | private GUIContent[] graphNameOptions; 32 | 33 | 34 | void OnEnable() 35 | { 36 | graphPaths.Clear(); 37 | graphPaths = GraphEditorUtils.GetAllGraphsInProject(); 38 | 39 | Func selector = (gp => new GUIContent(Path.GetFileNameWithoutExtension(gp), gp)); 40 | graphNameOptions = graphPaths.Select(selector).ToArray(); 41 | 42 | this.titleContent = new GUIContent("Shader Gen"); 43 | this.minSize = new Vector2(200.0f, 250.0f); 44 | 45 | selectedGraphIndex = 0; 46 | } 47 | 48 | void OnGUI() 49 | { 50 | useRed = GUILayout.Toggle(useRed, "Use Red?"); 51 | useGreen = GUILayout.Toggle(useGreen, "Use Green?"); 52 | useBlue = GUILayout.Toggle(useBlue, "Use Blue?"); 53 | useAlpha = GUILayout.Toggle(useAlpha, "Use Alpha?"); 54 | if (!useRed && !useGreen && !useBlue && !useAlpha) 55 | { 56 | useRed = true; 57 | } 58 | 59 | unusedColor = EditorGUILayout.FloatField("Unused color value", unusedColor); 60 | 61 | GUILayout.Space(10.0f); 62 | 63 | int oldIndex = selectedGraphIndex; 64 | selectedGraphIndex = EditorGUILayout.Popup(selectedGraphIndex, graphNameOptions); 65 | if (oldIndex != selectedGraphIndex) 66 | { 67 | Graph g = new Graph(graphPaths[selectedGraphIndex]); 68 | string err = g.Load(); 69 | if (err.Length > 0) 70 | { 71 | selectedGraphIndex = oldIndex; 72 | Debug.LogError("Error reading graph: " + err); 73 | } 74 | } 75 | 76 | GUILayout.Space(10.0f); 77 | 78 | GUILayout.BeginHorizontal(); 79 | GUILayout.Label("Shader name:"); 80 | shaderName = GUILayout.TextField(shaderName); 81 | GUILayout.EndHorizontal(); 82 | 83 | if (graphPaths.Count > 0) 84 | { 85 | if (GUILayout.Button("Generate Shader")) 86 | { 87 | string savePath = EditorUtility.SaveFilePanel("Choose where to save the shader.", 88 | Application.dataPath, 89 | "MyNoiseShader.shader", "shader"); 90 | if (savePath.Length > 0) 91 | { 92 | Graph g = new Graph(graphPaths[selectedGraphIndex]); 93 | if (g.Load().Length == 0) 94 | { 95 | string outComponents = ""; 96 | if (useRed) 97 | outComponents += "r"; 98 | if (useGreen) 99 | outComponents += "g"; 100 | if (useBlue) 101 | outComponents += "b"; 102 | if (useAlpha) 103 | outComponents += "a"; 104 | 105 | GraphEditorUtils.SaveShader(g, savePath, shaderName, 106 | outComponents, unusedColor); 107 | } 108 | } 109 | } 110 | } 111 | else 112 | { 113 | GUILayout.Space(25.0f); 114 | GUILayout.Label("No graph files detected in the project!"); 115 | } 116 | 117 | EditorGUILayout.Space(); 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/ShaderGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7576dbb2e396d9a46b5f7505169e2722 3 | timeCreated: 1447718829 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/TerrainGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using UnityEngine; 6 | using UnityEditor; 7 | using Assert = UnityEngine.Assertions.Assert; 8 | 9 | 10 | namespace GPUGraph.Applications 11 | { 12 | public class TerrainGenerator : EditorWindow 13 | { 14 | [MenuItem("Assets/GPU Graph/Generate Terrain Heightmap", false, 3)] 15 | public static void GenerateHeightmap() 16 | { 17 | CreateInstance().Show(); 18 | } 19 | 20 | 21 | private List graphPaths = new List(); 22 | private GUIContent[] graphNameOptions; 23 | private int selectedGraphIndex = 0; 24 | 25 | private Vector2 scrollPos = Vector2.zero; 26 | private float heightScale = 1.0f, 27 | uvz = 0.0f; 28 | 29 | private Graph graph; 30 | private GraphParamCollection gParams; 31 | private Texture2D previewTex; 32 | 33 | 34 | void OnEnable() 35 | { 36 | graphPaths.Clear(); 37 | graphPaths = GraphEditorUtils.GetAllGraphsInProject(); 38 | 39 | Func selector = (gp => new GUIContent(Path.GetFileNameWithoutExtension(gp), gp)); 40 | graphNameOptions = graphPaths.Select(selector).ToArray(); 41 | 42 | this.titleContent = new GUIContent("Terrain Gen"); 43 | this.minSize = new Vector2(200.0f, 250.0f); 44 | 45 | selectedGraphIndex = 0; 46 | if (graphPaths.Count > 0) 47 | { 48 | graph = new Graph(graphPaths[selectedGraphIndex]); 49 | if (graph.Load().Length == 0) 50 | { 51 | gParams = new GraphParamCollection(graph); 52 | GeneratePreview(); 53 | } 54 | else 55 | { 56 | graph = null; 57 | } 58 | } 59 | } 60 | 61 | void OnGUI() 62 | { 63 | GUILayout.Space(10.0f); 64 | scrollPos = GUILayout.BeginScrollView(scrollPos); 65 | 66 | if (Selection.activeGameObject == null || 67 | Selection.activeGameObject.GetComponent() == null) 68 | { 69 | EditorGUILayout.LabelField("No terrain is selected in the editor."); 70 | } 71 | else 72 | { 73 | //Graph selection. 74 | GUILayout.BeginHorizontal(); 75 | GUILayout.Label("Graph:"); 76 | int oldIndex = selectedGraphIndex; 77 | selectedGraphIndex = EditorGUILayout.Popup(selectedGraphIndex, graphNameOptions); 78 | if (oldIndex != selectedGraphIndex) 79 | { 80 | var newGraph = new Graph(graphPaths[selectedGraphIndex]); 81 | var errMsg = newGraph.Load(); 82 | if (errMsg.Length > 0) 83 | { 84 | Debug.LogError(errMsg); 85 | selectedGraphIndex = oldIndex; 86 | } 87 | else 88 | { 89 | gParams = new GraphParamCollection(newGraph); 90 | graph = newGraph; 91 | } 92 | } 93 | GUILayout.EndHorizontal(); 94 | 95 | GUILayout.Space(15.0f); 96 | 97 | //Graph params. 98 | if (graphPaths.Count > 0) 99 | { 100 | gParams.ParamEditorGUI(); 101 | } 102 | 103 | GUILayout.Space(15.0f); 104 | 105 | //Other params. 106 | EditorGUILayout.BeginHorizontal(); 107 | EditorGUILayout.LabelField("Height scale:"); 108 | heightScale = EditorGUILayout.FloatField(heightScale); 109 | EditorGUILayout.EndHorizontal(); 110 | EditorGUILayout.BeginHorizontal(); 111 | uvz = EditorGUILayout.Slider("UV.z", uvz, 0, 1); 112 | EditorGUILayout.EndHorizontal(); 113 | 114 | GUILayout.Space(15.0f); 115 | 116 | //Button to generate heightmap. 117 | if (graphPaths.Count > 0) 118 | { 119 | if (GUILayout.Button("Generate Heightmap")) 120 | { 121 | Generate(); 122 | } 123 | } 124 | else 125 | { 126 | GUILayout.Space(15.0f); 127 | GUILayout.Label("No graph files detected in the project!"); 128 | } 129 | 130 | //Preview texture. 131 | if (GUILayout.Button("Update Preview")) 132 | GeneratePreview(); 133 | if (previewTex != null) 134 | GUILayout.Box(previewTex, GUILayout.Width(256), GUILayout.Height(256)); 135 | } 136 | 137 | GUILayout.EndScrollView(); 138 | } 139 | 140 | private void GeneratePreview() 141 | { 142 | previewTex = GraphEditorUtils.GenerateToTexture(graph, gParams, 1024, 1024, uvz, 143 | "rgb", 1.0f, TextureFormat.RGBAFloat); 144 | } 145 | private void Generate() 146 | { 147 | Terrain terr = Selection.activeGameObject.GetComponent(); 148 | TerrainData dat = terr.terrainData; 149 | 150 | float[,] heights = GraphEditorUtils.GenerateToArray(graph, gParams, 151 | dat.heightmapWidth, 152 | dat.heightmapHeight); 153 | if (heights == null) 154 | { 155 | return; 156 | } 157 | 158 | for (int x = 0; x < heights.GetLength(0); ++x) 159 | for (int y = 0; y < heights.GetLength(1); ++y) 160 | heights[x, y] *= heightScale; 161 | dat.SetHeights(0, 0, heights); 162 | } 163 | } 164 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/TerrainGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2927bbefc96100f4b8eea691540c397b 3 | timeCreated: 1446676800 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/Texture2DGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Collections.Generic; 5 | using UnityEngine; 6 | using UnityEngine.Rendering; 7 | using UnityEditor; 8 | using GPUGraph; 9 | 10 | 11 | namespace GPUGraph.Applications 12 | { 13 | [Serializable] 14 | public class Texture2DGenerator : TextureGenerator 15 | { 16 | [MenuItem("Assets/GPU Graph/Generate 2D Texture", false, 4)] 17 | public static void ShowWindow() 18 | { 19 | ScriptableObject.CreateInstance().Show(); 20 | } 21 | 22 | 23 | public int X = 128, 24 | Y = 128; 25 | 26 | 27 | protected override void OnEnable() 28 | { 29 | base.OnEnable(); 30 | 31 | titleContent = new GUIContent("2D Tex"); 32 | minSize = new Vector2(200.0f, 300.0f + Y); 33 | 34 | if (HasGraph) 35 | GetPreview(true); 36 | } 37 | 38 | protected override void DoCustomGUI() 39 | { 40 | EditorGUI.BeginChangeCheck(); 41 | { 42 | X = EditorGUILayout.DelayedIntField("Width", X); 43 | Y = EditorGUILayout.DelayedIntField("Height", Y); 44 | } 45 | if (EditorGUI.EndChangeCheck()) 46 | GetPreview(false); 47 | 48 | GUILayout.Space(15.0f); 49 | } 50 | 51 | protected override void GeneratePreview(ref Texture2D outTex, Material noiseMat) 52 | { 53 | if (outTex == null || outTex.width != X || outTex.height != Y) 54 | { 55 | outTex = new Texture2D(X, Y, TextureFormat.ARGB32, false); 56 | outTex.wrapMode = TextureWrapMode.Clamp; 57 | outTex.filterMode = FilterMode.Point; 58 | } 59 | 60 | GraphUtils.GenerateToTexture(RenderTexture.GetTemporary(outTex.width, outTex.height), 61 | noiseMat, outTex, true); 62 | } 63 | protected override void GenerateTexture() 64 | { 65 | string savePath = EditorUtility.SaveFilePanel("Choose where to save the texture.", 66 | Application.dataPath, "MyTex.png", "png"); 67 | if (savePath.Length == 0) 68 | return; 69 | 70 | //Write out the texture as a PNG. 71 | Texture2D noiseTex = GetPreview(false); 72 | try 73 | { 74 | File.WriteAllBytes(savePath, noiseTex.EncodeToPNG()); 75 | } 76 | catch (Exception e) 77 | { 78 | Debug.LogError("Unable to save texture to file: " + e.Message); 79 | } 80 | 81 | //Finally, open explorer to show the user the texture. 82 | EditorUtility.RevealInFinder(StringUtils.FixDirectorySeparators(savePath)); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/Texture2DGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d5e6a5e6d74d254ba6f2249d3937fad 3 | timeCreated: 1444256451 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/Texture3DGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Collections.Generic; 5 | using UnityEngine; 6 | using UnityEngine.Rendering; 7 | using UnityEditor; 8 | using GPUGraph; 9 | 10 | 11 | namespace GPUGraph.Applications 12 | { 13 | [Serializable] 14 | public class Texture3DGenerator : TextureGenerator 15 | { 16 | [MenuItem("Assets/GPU Graph/Generate 3D Texture", false, 4)] 17 | public static void ShowWindow() 18 | { 19 | ScriptableObject.CreateInstance().Show(); 20 | } 21 | 22 | 23 | public int X = 128, Y = 128, Z = 128; 24 | public TextureFormat Format = TextureFormat.ARGB32; 25 | public FilterMode Filtering = FilterMode.Bilinear; 26 | public TextureWrapMode Wrapping = TextureWrapMode.Repeat; 27 | public bool UseMipmaps = false, 28 | LeaveReadable = true; 29 | 30 | public bool GenerateNormals = true; 31 | public int Normals_X = 128, Normals_Y = 128, Normals_Z = 128; 32 | public TextureFormat Normals_Format = TextureFormat.ARGB32; 33 | public FilterMode Normals_Filtering = FilterMode.Bilinear; 34 | public TextureWrapMode Normals_Wrapping = TextureWrapMode.Repeat; 35 | public bool Normals_UseMipmaps = false, 36 | Normals_LeaveReadable = true; 37 | 38 | 39 | protected override void OnEnable() 40 | { 41 | base.OnEnable(); 42 | 43 | titleContent = new GUIContent("Texture Gen"); 44 | minSize = new Vector2(200.0f, 450.0f + Y); 45 | 46 | if (HasGraph) 47 | GetPreview(true); 48 | } 49 | 50 | protected override void DoCustomGUI() 51 | { 52 | EditorGUI.BeginChangeCheck(); 53 | { 54 | EditTextureGUI(ref X, ref Y, ref Z, ref Format, ref Filtering, ref Wrapping, 55 | ref UseMipmaps, ref LeaveReadable); 56 | 57 | GUILayout.Space(7.5f); 58 | 59 | GenerateNormals = GUILayout.Toggle(GenerateNormals, "Also Generate Normals"); 60 | if (GenerateNormals) 61 | { 62 | EditTextureGUI(ref Normals_X, ref Normals_Y, ref Normals_Z, ref Normals_Format, 63 | ref Normals_Filtering, ref Normals_Wrapping, 64 | ref Normals_UseMipmaps, ref Normals_LeaveReadable); 65 | } 66 | } 67 | if (EditorGUI.EndChangeCheck()) 68 | GetPreview(false); 69 | 70 | GUILayout.Space(15.0f); 71 | } 72 | 73 | protected override void GeneratePreview(ref Texture2D outTex, Material noiseMat) 74 | { 75 | if (outTex == null || outTex.width != X || outTex.height != Y) 76 | { 77 | outTex = new Texture2D(X, Y, TextureFormat.ARGB32, false); 78 | outTex.wrapMode = TextureWrapMode.Clamp; 79 | outTex.filterMode = FilterMode.Point; 80 | } 81 | 82 | GraphUtils.GenerateToTexture(RenderTexture.GetTemporary(outTex.width, outTex.height), 83 | noiseMat, outTex, true); 84 | } 85 | protected override void GenerateTexture() 86 | { 87 | string savePath = EditorUtility.SaveFilePanelInProject( 88 | "Save Noise Texture", "MyTex.asset", "asset", 89 | "Choose where to save the noise texture.", Application.dataPath); 90 | if (savePath.Length > 0) 91 | { 92 | string normalsSavePath = null; 93 | if (GenerateNormals) 94 | { 95 | normalsSavePath = EditorUtility.SaveFilePanelInProject( 96 | "Save Normal Texture", 97 | "Normal_" + Path.GetFileName(savePath), "asset", 98 | "Choose where to save the normal texture.", 99 | Path.GetDirectoryName(savePath)); 100 | } 101 | 102 | if (GenerateTextures(savePath, normalsSavePath)) 103 | EditorUtility.RevealInFinder(savePath); 104 | } 105 | } 106 | 107 | private void EditTextureGUI(ref int sizeX, ref int sizeY, ref int sizeZ, 108 | ref TextureFormat format, 109 | ref FilterMode filtering, ref TextureWrapMode wrapping, 110 | ref bool useMips, ref bool leaveReadable) 111 | { 112 | sizeX = EditorGUILayout.IntField("Width", sizeX); 113 | sizeY = EditorGUILayout.IntField("Height", sizeY); 114 | sizeZ = EditorGUILayout.IntField("Depth", sizeZ); 115 | 116 | GUILayout.Space(5.0f); 117 | 118 | format = (TextureFormat)EditorGUILayout.EnumPopup("Format", format); 119 | filtering = (FilterMode)EditorGUILayout.EnumPopup("Filtering", filtering); 120 | wrapping = (TextureWrapMode)EditorGUILayout.EnumPopup("Wrapping", wrapping); 121 | 122 | GUILayout.Space(5.0f); 123 | 124 | useMips = EditorGUILayout.Toggle("Use Mipmaps?", useMips); 125 | leaveReadable = EditorGUILayout.Toggle("Leave Readable?", leaveReadable); 126 | } 127 | /// 128 | /// Generates both textures and saves them to the given file paths. 129 | /// Returns whether the operation succeeded. 130 | /// 131 | private bool GenerateTextures(string texPath, string normalTexPath = null) 132 | { 133 | //The base data set should be large enough for both textures. 134 | int baseDataSizeX = X, 135 | baseDataSizeY = Y, 136 | baseDataSizeZ = Z; 137 | if (GenerateNormals) 138 | { 139 | baseDataSizeX = Math.Max(baseDataSizeX, Normals_X); 140 | baseDataSizeY = Math.Max(baseDataSizeY, Normals_Y); 141 | baseDataSizeZ = Math.Max(baseDataSizeZ, Normals_Z); 142 | } 143 | 144 | //TODO: Support other modes. 145 | if (OutputMode != ColorModes.Gradient) 146 | throw new NotImplementedException("Don't support non-Gradient modes yet!"); 147 | 148 | var graphs = LoadGraphs(); 149 | if (graphs == null) 150 | return false; 151 | var graph = graphs[0]; 152 | 153 | GraphParamCollection graphParams = GetParams(0); 154 | 155 | //Generate the initial data. 156 | float[,,] baseData = GraphEditorUtils.GenerateToArray(graph, graphParams, 157 | baseDataSizeX, 158 | baseDataSizeY, 159 | baseDataSizeZ); 160 | 161 | 162 | //Generate the value texture. 163 | 164 | float[,,] valueTexData = baseData.ResampleFull(Mathf.Lerp, X, Y, Z); 165 | Gradient colorGradient = MakeGradient(); 166 | Color[] valueTexPixels = new Color[X * Y * Z]; 167 | 168 | for (int z = 0; z < Z; ++z) 169 | { 170 | for (int y = 0; y < Y; ++y) 171 | { 172 | for (int x = 0; x < X; ++x) 173 | { 174 | float value = valueTexData[x, y, z]; 175 | int index = x + 176 | (y * X) + 177 | (z * X * Y); 178 | 179 | valueTexPixels[index] = colorGradient.Evaluate(value); 180 | } 181 | } 182 | } 183 | 184 | Texture3D valueTex = new Texture3D(X, Y, Z, Format, UseMipmaps); 185 | valueTex.wrapMode = Wrapping; 186 | valueTex.filterMode = Filtering; 187 | valueTex.SetPixels(valueTexPixels); 188 | valueTex.Apply(UseMipmaps, !LeaveReadable); 189 | AssetDatabase.CreateAsset(valueTex, StringUtils.GetRelativePath(texPath, "Assets")); 190 | 191 | 192 | //Generate the normals texture. 193 | 194 | if (normalTexPath == null) 195 | return true; 196 | 197 | float[,,] normalsValueData = baseData.ResampleFull(Mathf.Lerp, 198 | Normals_X, Normals_Y, Normals_Z); 199 | Color[] normalsPixels = new Color[Normals_X * Normals_Y * Normals_Z]; 200 | 201 | for (int z = 0; z < Normals_Z; ++z) 202 | { 203 | for (int y = 0; y < Normals_Y; ++y) 204 | { 205 | for (int x = 0; x < Normals_X; ++x) 206 | { 207 | //The first digit is the X, the second is the Y, the third is the Z. 208 | float _000, _100, _010, _110, _001, _101, _011, _111; 209 | normalsValueData.Sample(x, y, z, true, 210 | out _000, out _100, out _010, out _110, 211 | out _001, out _101, out _011, out _111); 212 | 213 | Vector3 gradient = new Vector3(); 214 | gradient.x = (_100 - _000) + 215 | (_110 - _010) + 216 | (_101 - _001) + 217 | (_111 - _011); 218 | gradient.y = (_010 - _000) + 219 | (_110 - _100) + 220 | (_011 - _001) + 221 | (_111 - _101); 222 | gradient.z = (_001 - _000) + 223 | (_101 - _100) + 224 | (_011 - _010) + 225 | (_111 - _110); 226 | 227 | //Normalize. 228 | if (gradient == Vector3.zero) 229 | gradient = Vector3.up; 230 | else 231 | gradient = gradient.normalized; 232 | 233 | //Pack into a color. 234 | int index = x + (y * Normals_X) + (z * Normals_X * Normals_Y); 235 | normalsPixels[index] = new Color(0.5f + (0.5f * gradient.x), 236 | 0.5f + (0.5f * gradient.y), 237 | 0.5f + (0.5f * gradient.z)); 238 | } 239 | } 240 | } 241 | 242 | Texture3D normalsTex = new Texture3D(Normals_X, Normals_Y, Normals_Z, 243 | Normals_Format, Normals_UseMipmaps); 244 | normalsTex.wrapMode = Normals_Wrapping; 245 | normalsTex.filterMode = Normals_Filtering; 246 | normalsTex.SetPixels(normalsPixels); 247 | normalsTex.Apply(Normals_UseMipmaps, !Normals_LeaveReadable); 248 | AssetDatabase.CreateAsset(normalsTex, StringUtils.GetRelativePath(normalTexPath, "Assets")); 249 | 250 | 251 | return true; 252 | } 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/Texture3DGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6cf6d4374bfc85a49897c579be500cac 3 | timeCreated: 1497396387 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/TextureGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Collections.Generic; 5 | using UnityEngine; 6 | using UnityEngine.Rendering; 7 | using UnityEditor; 8 | using GPUGraph; 9 | 10 | 11 | namespace GPUGraph.Applications 12 | { 13 | public enum ColorModes 14 | { 15 | Gradient, 16 | Make2DVec, 17 | Custom 18 | } 19 | 20 | [Serializable] 21 | public abstract class TextureGenerator : EditorWindow 22 | { 23 | [Serializable] 24 | private class GraphSelection 25 | { 26 | public int Index = 0; 27 | public GraphParamCollection Params; 28 | 29 | /// 30 | /// Does the GUI for this graph. 31 | /// Returns what changed. 32 | /// 33 | public ChangeTypes DoGUILayout(string label, List graphPaths, GUIContent[] graphOptions) 34 | { 35 | var changes = ChangeTypes.None; 36 | 37 | GUILayout.BeginHorizontal(); 38 | GUILayout.Label(label); 39 | int oldIndex = Index; 40 | Index = EditorGUILayout.Popup(oldIndex, graphOptions); 41 | if (oldIndex != Index) 42 | { 43 | Graph g = new Graph(graphPaths[Index]); 44 | if (g.Load().Length > 0) 45 | { 46 | Index = oldIndex; 47 | } 48 | else 49 | { 50 | Params = new GraphParamCollection(g); 51 | changes = ChangeTypes.Everything; 52 | } 53 | } 54 | GUILayout.EndHorizontal(); 55 | 56 | GUILayout_TabIn(25.0f); 57 | 58 | if (Params != null && Params.ParamEditorGUI() && changes != ChangeTypes.Everything) 59 | changes = ChangeTypes.Params; 60 | 61 | GUILayout_TabOut(25.0f); 62 | 63 | return changes; 64 | } 65 | 66 | /// 67 | /// The different aspects of this graph selection that can change. 68 | /// 69 | public enum ChangeTypes 70 | { 71 | None, Params, Everything 72 | } 73 | } 74 | 75 | 76 | public ColorModes OutputMode = ColorModes.Gradient; 77 | 78 | public List Output_Gradient_Colors = new List() 79 | { Color.black, Color.white }; 80 | public List Output_Gradient_Times = new List() 81 | { 0, 1 }; 82 | 83 | public bool Output_AngleTo2DVec_Pack01 = true; 84 | 85 | public string Output_Custom_CodeBody = "//Put 3 white noise values in the GBA channels\n// based on the R channel.\n" + 86 | "return float4(graphResult1, hashTo3(graphResult1));"; 87 | 88 | 89 | private List chosenGraphs = new List(); 90 | private bool isLoaded = false; 91 | 92 | private List graphPaths = new List(); 93 | private GUIContent[] graphNameOptions; 94 | 95 | private Texture2D previewTex = null; 96 | private Material previewMat = null; 97 | private float previewScale = 1.0f; 98 | private float previewUVz = 0.0f, 99 | previewUVzMin = 0.0f, 100 | previewUVzMax = 1.0f; 101 | 102 | [SerializeField] 103 | private Vector2 scrollPos = Vector2.zero; 104 | 105 | 106 | protected bool HasGraph { get { return graphPaths.Count > 0; } } 107 | 108 | protected Graph[] LoadGraphs() 109 | { 110 | var graphs = new Graph[chosenGraphs.Count]; 111 | 112 | for (int i = 0; i < graphs.Length; ++i) 113 | { 114 | var path = graphPaths[chosenGraphs[i].Index]; 115 | graphs[i] = new Graph(path); 116 | string errMsg = graphs[i].Load(); 117 | if (errMsg.Length > 0) 118 | { 119 | Debug.LogError("Error loading graph " + path + ": " + errMsg); 120 | return null; 121 | } 122 | } 123 | 124 | return graphs; 125 | } 126 | protected GraphParamCollection GetParams(int graphI) 127 | { 128 | return chosenGraphs[graphI].Params; 129 | } 130 | 131 | protected Gradient MakeGradient() 132 | { 133 | Gradient gradient = new Gradient(); 134 | gradient.SetKeys(Output_Gradient_Colors.Select( 135 | (c, i) => new GradientColorKey(c, Output_Gradient_Times[i])) 136 | .ToArray(), 137 | new GradientAlphaKey[] { new GradientAlphaKey(1.0f, 0.0f) }); 138 | return gradient; 139 | } 140 | 141 | 142 | /// 143 | /// Properly updates the preview texture for this window. 144 | /// Returns it in case anybody wants it (returns null if there was a problem loading the graph). 145 | /// 146 | public Texture2D GetPreview(bool regenerateShader) 147 | { 148 | //Regenerate shader. 149 | if (regenerateShader || previewMat == null) 150 | { 151 | var graphs = LoadGraphs(); 152 | if (graphs == null) 153 | return null; 154 | 155 | switch (OutputMode) 156 | { 157 | case ColorModes.Gradient: { 158 | 159 | //Render the gradient ramp to a texture. 160 | Gradient gradient = MakeGradient(); 161 | Texture2D myRamp = new Texture2D(1024, 1, TextureFormat.RGBA32, false); 162 | myRamp.wrapMode = TextureWrapMode.Clamp; 163 | Color[] cols = new Color[myRamp.width]; 164 | for (int i = 0; i < cols.Length; ++i) 165 | cols[i] = gradient.Evaluate((float)i / (float)(cols.Length - 1)); 166 | myRamp.SetPixels(cols); 167 | myRamp.Apply(false, true); 168 | 169 | //Generate a shader that uses the gradient. 170 | var shader = ShaderUtil.CreateShaderAsset( 171 | graphs[0].GenerateShader("Graph editor temp shader", 172 | "_textureGeneratorWindowGradient")); 173 | previewMat = new Material(shader); 174 | previewMat.SetTexture("_textureGeneratorWindowGradient", myRamp); 175 | } break; 176 | 177 | case ColorModes.Make2DVec: { 178 | var shaderStr = Graph.GenerateShader( 179 | "GraphEditorTempShader", graphs, 180 | (fragBody) => 181 | { 182 | fragBody.Append(@" 183 | const float PI_2 = 3.14159265359 * 2.0; 184 | float angle = PI_2 * graphResult1, 185 | magnitude = graphResult2; 186 | float2 dir = magnitude * float2(cos(angle), sin(angle));"); 187 | if (Output_AngleTo2DVec_Pack01) 188 | fragBody.AppendLine(@" 189 | dir = 0.5 + (0.5 * dir);"); 190 | fragBody.AppendLine(@" 191 | return float4(dir, 0, 1);"); 192 | }); 193 | var shader = UnityEditor.ShaderUtil.CreateShaderAsset(shaderStr); 194 | previewMat = new Material(shader); 195 | } break; 196 | 197 | case ColorModes.Custom: { 198 | var shaderStr = Graph.GenerateShader( 199 | "GraphEditorTempShader", graphs, 200 | (fragBody) => 201 | { 202 | fragBody.AppendLine(Output_Custom_CodeBody); 203 | }); 204 | var shader = UnityEditor.ShaderUtil.CreateShaderAsset(shaderStr); 205 | previewMat = new Material(shader); 206 | } break; 207 | 208 | default: throw new NotImplementedException(OutputMode.ToString()); 209 | } 210 | } 211 | 212 | //Set parameters. 213 | for (int graphI = 0; graphI < chosenGraphs.Count; ++graphI) 214 | { 215 | var paramPrefix = (chosenGraphs.Count > 1) ? 216 | ("p" + (graphI + 1)) : 217 | ""; 218 | chosenGraphs[graphI].Params.SetParams(previewMat, paramPrefix); 219 | } 220 | previewMat.SetFloat(GraphUtils.Param_UVz, previewUVz); 221 | 222 | //Generate. 223 | GeneratePreview(ref previewTex, previewMat); 224 | return previewTex; 225 | } 226 | 227 | protected virtual void OnEnable() 228 | { 229 | graphPaths.Clear(); 230 | graphPaths = GraphEditorUtils.GetAllGraphsInProject(); 231 | 232 | Func selector = (gp => new GUIContent(Path.GetFileNameWithoutExtension(gp), gp)); 233 | graphNameOptions = graphPaths.Select(selector).ToArray(); 234 | 235 | if (!isLoaded) 236 | { 237 | isLoaded = true; 238 | chosenGraphs.Clear(); 239 | if (graphPaths.Count > 0) 240 | { 241 | var graph = new Graph(graphPaths[0]); 242 | if (graph.Load().Length == 0) 243 | chosenGraphs.Add(new GraphSelection() { Index = 0, Params = new GraphParamCollection(graph) }); 244 | } 245 | } 246 | } 247 | protected virtual void OnFocus() 248 | { 249 | OnEnable(); 250 | } 251 | 252 | /// 253 | /// Generates a preview into the given texture with the given noise material. 254 | /// 255 | /// 256 | /// The texture to generate into. 257 | /// NOTE: the child class is responsible for making sure the texture exists and is the right size. 258 | /// 259 | protected abstract void GeneratePreview(ref Texture2D outTex, Material noiseMat); 260 | /// 261 | /// Generates the full texture to a file. 262 | /// 263 | protected abstract void GenerateTexture(); 264 | 265 | protected virtual void DoCustomGUI() { } 266 | 267 | 268 | private void OnGUI() 269 | { 270 | GUILayout.Space(15.0f); 271 | 272 | scrollPos = GUILayout.BeginScrollView(scrollPos); 273 | 274 | //Make sure we have enough graphs. 275 | int nGraphs = -1; 276 | switch (OutputMode) 277 | { 278 | case ColorModes.Custom: 279 | nGraphs = EditorGUILayout.DelayedIntField("# Graphs", chosenGraphs.Count); 280 | break; 281 | 282 | case ColorModes.Gradient: 283 | nGraphs = 1; 284 | break; 285 | 286 | case ColorModes.Make2DVec: 287 | nGraphs = 2; 288 | break; 289 | 290 | default: throw new NotImplementedException(OutputMode.ToString()); 291 | } 292 | while (nGraphs > chosenGraphs.Count) 293 | chosenGraphs.Add(new GraphSelection()); 294 | while (nGraphs < chosenGraphs.Count) 295 | chosenGraphs.RemoveAt(chosenGraphs.Count - 1); 296 | 297 | for (int graphI = 0; graphI < nGraphs; ++graphI) 298 | { 299 | GUILayout_TabIn(25.0f); 300 | 301 | var graph = chosenGraphs[graphI]; 302 | var changes = graph.DoGUILayout("Graph " + (graphI + 1), 303 | graphPaths, graphNameOptions); 304 | 305 | switch (changes) 306 | { 307 | case GraphSelection.ChangeTypes.None: 308 | break; 309 | case GraphSelection.ChangeTypes.Params: 310 | GetPreview(false); 311 | break; 312 | case GraphSelection.ChangeTypes.Everything: 313 | GetPreview(true); 314 | break; 315 | 316 | default: throw new NotImplementedException(changes.ToString()); 317 | } 318 | 319 | GUILayout_TabOut(); 320 | 321 | GUILayout.Space(25.0f); 322 | } 323 | 324 | //Do color-mode-specific UI. 325 | OutputMode = (ColorModes)EditorGUILayout.EnumPopup("Mode", OutputMode); 326 | switch (OutputMode) 327 | { 328 | case ColorModes.Gradient: 329 | //Choose the color gradient. 330 | GUILayout.Label("Gradient"); 331 | GUILayout.BeginHorizontal(); 332 | GUILayout.Space(15.0f); 333 | GUILayout.BeginVertical(); 334 | for (int i = 0; i < Output_Gradient_Colors.Count; ++i) 335 | { 336 | GUILayout.BeginHorizontal(); 337 | 338 | //Edit the color value. 339 | EditorGUI.BeginChangeCheck(); 340 | Output_Gradient_Colors[i] = EditorGUILayout.ColorField(Output_Gradient_Colors[i]); 341 | if (i > 0) 342 | Output_Gradient_Times[i] = EditorGUILayout.Slider(Output_Gradient_Times[i], 343 | 0.0f, 1.0f); 344 | if (EditorGUI.EndChangeCheck()) 345 | GetPreview(true); 346 | 347 | //Button to insert a new element. 348 | if (i > 0 && GUILayout.Button("+")) 349 | { 350 | Output_Gradient_Colors.Insert(i, Output_Gradient_Colors[i]); 351 | Output_Gradient_Times.Insert(i, Output_Gradient_Times[i] - 0.00000001f); 352 | 353 | GetPreview(true); 354 | } 355 | //Button to remove this element. 356 | if (i > 0 && Output_Gradient_Colors.Count > 2 && GUILayout.Button("-")) 357 | { 358 | Output_Gradient_Colors.RemoveAt(i); 359 | Output_Gradient_Times.RemoveAt(i); 360 | i -= 1; 361 | 362 | GetPreview(true); 363 | } 364 | GUILayout.EndHorizontal(); 365 | 366 | //Make sure elements are in order. 367 | if (i > 0 && Output_Gradient_Times[i] < Output_Gradient_Times[i - 1]) 368 | { 369 | Output_Gradient_Times[i] = Output_Gradient_Times[i - 1] + 0.000001f; 370 | GetPreview(true); 371 | } 372 | else if (i < Output_Gradient_Colors.Count - 1 && 373 | Output_Gradient_Times[i] > Output_Gradient_Times[i + 1]) 374 | { 375 | Output_Gradient_Times[i] = Output_Gradient_Times[i + 1] - 0.00001f; 376 | GetPreview(true); 377 | } 378 | } 379 | GUILayout.EndVertical(); 380 | GUILayout.EndHorizontal(); 381 | break; 382 | 383 | case ColorModes.Make2DVec: 384 | GUILayout.BeginHorizontal(); 385 | GUILayout.Space(30.0f); 386 | GUILayout.BeginVertical(); 387 | EditorGUI.BeginChangeCheck(); 388 | Output_AngleTo2DVec_Pack01 = EditorGUILayout.Toggle("Pack into range [0,1]", 389 | Output_AngleTo2DVec_Pack01); 390 | if (EditorGUI.EndChangeCheck()) 391 | GetPreview(true); 392 | GUILayout.EndVertical(); 393 | GUILayout.EndHorizontal(); 394 | break; 395 | 396 | case ColorModes.Custom: 397 | GUILayout.BeginHorizontal(); 398 | GUILayout.Space(30.0f); 399 | GUILayout.BeginVertical(); 400 | 401 | if (GUILayout.Button("Regenerate preview")) 402 | GetPreview(true); 403 | string args = ""; 404 | for (int graphI = 0; graphI < chosenGraphs.Count; ++graphI) 405 | { 406 | if (graphI > 0) 407 | args += ", "; 408 | args += "float graphResult" + (graphI + 1); 409 | } 410 | GUILayout.Label("float4 getTexOutputColor(" + args + ")"); 411 | GUILayout.Label("{"); 412 | 413 | GUILayout.BeginHorizontal(); 414 | GUILayout.Space(30.0f); 415 | GUILayout.BeginVertical(); 416 | Output_Custom_CodeBody = EditorGUILayout.TextArea(Output_Custom_CodeBody); 417 | GUILayout.EndVertical(); 418 | GUILayout.EndHorizontal(); 419 | 420 | GUILayout.Label("}"); 421 | 422 | GUILayout.EndVertical(); 423 | GUILayout.EndHorizontal(); 424 | break; 425 | 426 | default: throw new NotImplementedException(OutputMode.ToString()); 427 | } 428 | 429 | GUILayout.Space(15.0f); 430 | 431 | DoCustomGUI(); 432 | 433 | GUILayout.Space(15.0f); 434 | 435 | //Show the preview texture. 436 | if (previewTex != null) 437 | { 438 | //Preview scale slider. 439 | GUILayout.BeginHorizontal(); 440 | { 441 | GUILayout.Label("Preview Scale"); 442 | 443 | //Use a nonlinear scale for the slider. 444 | float t = Mathf.Log10(previewScale); 445 | float resultT = GUILayout.HorizontalSlider(t, -2.0f, 2.0f, 446 | GUILayout.Width(position.width - 40.0f)); 447 | previewScale = Mathf.Pow(10.0f, resultT); 448 | } 449 | GUILayout.EndHorizontal(); 450 | 451 | GUILayout.BeginHorizontal(); 452 | { 453 | //Slider for preview UV z. 454 | GUILayout.BeginVertical(); 455 | { 456 | float oldZ = previewUVz; 457 | 458 | GUILayout.Label("Z"); 459 | previewUVzMax = EditorGUILayout.FloatField(previewUVzMax, GUILayout.Width(20.0f)); 460 | previewUVz = GUILayout.VerticalSlider(previewUVz, previewUVzMin, previewUVzMax, 461 | GUILayout.Height(previewTex.height * previewScale - (15.0f * 3))); 462 | previewUVzMin = EditorGUILayout.FloatField(previewUVzMin, GUILayout.Width(20.0f)); 463 | 464 | if (oldZ != previewUVz) 465 | GetPreview(false); 466 | } 467 | GUILayout.EndVertical(); 468 | 469 | Rect texPos = EditorGUILayout.GetControlRect(GUILayout.Width(previewTex.width * previewScale), 470 | GUILayout.Height(previewTex.height * previewScale)); 471 | EditorGUI.DrawPreviewTexture(texPos, previewTex); 472 | 473 | GUILayout.FlexibleSpace(); 474 | } 475 | GUILayout.EndHorizontal(); 476 | } 477 | 478 | //If a graph is selected, display a button to generate the texture. 479 | if (graphPaths.Count > 0) 480 | { 481 | if (GUILayout.Button("Generate Texture")) 482 | GenerateTexture(); 483 | } 484 | else 485 | { 486 | GUILayout.Space(15.0f); 487 | GUILayout.Label("No graph files detected in the project!"); 488 | } 489 | 490 | GUILayout.EndScrollView(); 491 | } 492 | 493 | private static void GUILayout_TabIn(float spaceBefore) 494 | { 495 | GUILayout.BeginHorizontal(); 496 | if (spaceBefore < 0.0f) 497 | GUILayout.FlexibleSpace(); 498 | else if (spaceBefore > 0.0f) 499 | GUILayout.Space(spaceBefore); 500 | GUILayout.BeginVertical(); 501 | } 502 | private static void GUILayout_TabOut(float spaceAfter = 0.0f) 503 | { 504 | GUILayout.EndVertical(); 505 | if (spaceAfter < 0.0f) 506 | GUILayout.FlexibleSpace(); 507 | else if (spaceAfter > 0.0f) 508 | GUILayout.Space(spaceAfter); 509 | GUILayout.EndHorizontal(); 510 | } 511 | } 512 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Applications/TextureGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff680db92372efe4bb024ce74dd2a025 3 | timeCreated: 1497407095 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/GUIUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | 7 | namespace GPUGraph 8 | { 9 | public static class GUIUtil 10 | { 11 | private static Texture2D whitePixelTex = null; 12 | 13 | public static Texture2D WhitePixel 14 | { 15 | get 16 | { 17 | //Generate the texture if it doesn't exist. 18 | if (whitePixelTex == null) 19 | { 20 | whitePixelTex = new Texture2D(1, 1); 21 | whitePixelTex.SetPixel(0, 0, Color.white); 22 | whitePixelTex.Apply(); 23 | } 24 | 25 | return whitePixelTex; 26 | } 27 | } 28 | 29 | public static void DrawLine(Vector2 a, Vector2 b, float thickness, Color col) 30 | { 31 | //Taken from: http://wiki.unity3d.com/index.php?title=DrawLine 32 | 33 | // Save the current GUI matrix, since we're going to make changes to it. 34 | Matrix4x4 matrix = GUI.matrix; 35 | 36 | // Store current GUI color, so we can switch it back later, 37 | // and set the GUI color to the color parameter 38 | Color savedColor = GUI.color; 39 | GUI.color = col; 40 | 41 | // Determine the angle of the line. 42 | float angle = Vector3.Angle(b - a, Vector2.right); 43 | 44 | // Vector3.Angle always returns a positive number. 45 | // If pointB is above pointA, then angle needs to be negative. 46 | if (a.y > b.y) 47 | { 48 | angle = -angle; 49 | } 50 | 51 | // Use ScaleAroundPivot to adjust the size of the line. 52 | // We could do this when we draw the texture, but by scaling it here we can use 53 | // non-integer values for the width and length (such as sub 1 pixel widths). 54 | // Note that the pivot point is at 0.5 ahead of a.y, this is so that the width of the line 55 | // is centered on the origin at point a. 56 | GUIUtility.ScaleAroundPivot(new Vector2((b - a).magnitude, thickness), 57 | new Vector2(a.x, a.y + 0.5f)); 58 | 59 | // Set the rotation for the line. 60 | // The angle was calculated with point a as the origin. 61 | GUIUtility.RotateAroundPivot(angle, a); 62 | 63 | // Finally, draw the actual line. 64 | // We're really only drawing a 1x1 texture from point a. 65 | // The matrix operations done with ScaleAroundPivot and RotateAroundPivot will make this 66 | // render with the proper width, length, and angle. 67 | GUI.DrawTexture(new Rect(a.x, a.y, 1.0f, 1.0f), whitePixelTex); 68 | 69 | // We're done. Restore the GUI matrix and GUI color to whatever they were before. 70 | GUI.matrix = matrix; 71 | GUI.color = savedColor; 72 | } 73 | 74 | 75 | /// 76 | /// Gets the index of the first element to satisfy the given predicate. 77 | /// Returns -1 if none were found. 78 | /// 79 | public static int IndexOf(this IEnumerable en, Predicate p) 80 | { 81 | int i = 0; 82 | foreach (T t in en) 83 | { 84 | if (p(t)) 85 | return i; 86 | i += 1; 87 | } 88 | return -1; 89 | } 90 | 91 | public static T Accumulate(this IEnumerable en, 92 | Func accumulator, 93 | T initial) 94 | { 95 | foreach (ElementType el in en) 96 | initial = accumulator(el, initial); 97 | return initial; 98 | } 99 | 100 | public static IEnumerable SelectSome(this IEnumerable en, Func converter) 101 | where DestT : struct 102 | { 103 | foreach (SrcT srcT in en) 104 | { 105 | DestT? destT = converter(srcT); 106 | if (destT.HasValue) 107 | yield return destT.Value; 108 | } 109 | } 110 | public static IEnumerable SelectSome(this IEnumerable en, Func converter) 111 | where DestT : class 112 | { 113 | foreach (SrcT srcT in en) 114 | { 115 | DestT destT = converter(srcT); 116 | if (destT != null) 117 | yield return destT; 118 | } 119 | } 120 | 121 | 122 | public static int WrapNegative(this int i, int maxExclusive) 123 | { 124 | return (i % maxExclusive) + maxExclusive; 125 | } 126 | public static int Wrap(this int _i, int maxExclusive) 127 | { 128 | //http://stackoverflow.com/questions/3417183/modulo-of-negative-numbers 129 | int i = _i % maxExclusive; 130 | return (i < 0) ? (i + maxExclusive) : i; 131 | } 132 | 133 | /// 134 | /// Samples 8 nearby values from an array given the UV coordinate. 135 | /// Nicely handles wrapping or clamping behavior. 136 | /// Returns the interpolant between the 8 values. 137 | /// 138 | /// The position in the array to sample from, from 0 to 1. 139 | /// 140 | /// If true, positions wrap around the ends of the array. If false, positions are clamped to the bounds of the array. 141 | /// 142 | public static void Sample(this T[,,] array, int x, int y, int z, bool wrap, 143 | out T out_minXYZ, out T out_maxXminYZ, 144 | out T out_minXmaxYminZ, out T out_maxXYminZ, 145 | out T out_minXYmaxZ, out T out_maxXminYmaxZ, 146 | out T out_minXmaxYZ, out T out_maxXYZ) 147 | { 148 | int sizeX = array.GetLength(0), 149 | sizeY = array.GetLength(1), 150 | sizeZ = array.GetLength(2); 151 | 152 | //Wrap/clamp the pos. 153 | if (x < 0) 154 | x = (wrap ? x.WrapNegative(sizeX) : 0); 155 | else if (x >= sizeX) 156 | x = (wrap ? (x % sizeX) : 0); 157 | if (y < 0) 158 | y = (wrap ? y.WrapNegative(sizeY) : 0); 159 | else if (y >= sizeY) 160 | y = (wrap ? (y % sizeY) : 0); 161 | if (z < 0) 162 | z = (wrap ? z.WrapNegative(sizeZ) : 0); 163 | else if (z >= sizeZ) 164 | z = (wrap ? (z % sizeZ) : 0); 165 | 166 | //Get the index of the next elements. 167 | int? moreX = (x < sizeX - 1) ? (x + 1) : (wrap ? 0 : new int?()), 168 | moreY = (y < sizeY - 1) ? (y + 1) : (wrap ? 0 : new int?()), 169 | moreZ = (z < sizeZ - 1) ? (z + 1) : (wrap ? 0 : new int?()); 170 | 171 | //Get the elements. 172 | out_minXYZ = array[x, y, z]; 173 | out_minXYmaxZ = moreZ.HasValue ? 174 | array[x, y, (int)moreZ] : 175 | out_minXYZ; 176 | out_minXmaxYminZ = moreY.HasValue ? 177 | array[x, (int)moreY, z] : 178 | out_minXYZ; 179 | out_minXmaxYZ = (moreY.HasValue & moreZ.HasValue) ? 180 | array[x, (int)moreY, (int)moreZ] : 181 | out_minXYZ; 182 | out_maxXminYZ = moreX.HasValue ? 183 | array[(int)moreX, y, z] : 184 | out_minXYZ; 185 | out_maxXminYmaxZ = (moreX.HasValue & moreZ.HasValue) ? 186 | array[(int)moreX, y, (int)moreZ] : 187 | out_minXYZ; 188 | out_maxXYminZ = (moreX.HasValue & moreY.HasValue) ? 189 | array[(int)moreX, (int)moreY, z] : 190 | out_minXYZ; 191 | out_maxXYZ = (moreX.HasValue & moreY.HasValue & moreZ.HasValue) ? 192 | array[(int)moreX, (int)moreY, (int)moreZ] : 193 | out_minXYZ; 194 | } 195 | /// 196 | /// Samples from a 3D array using trilinear filtering. 197 | /// 198 | public static T Sample(this T[,,] array, Vector3 uv, Func lerp, bool wrap) 199 | { 200 | int sizeX = array.GetLength(0), 201 | sizeY = array.GetLength(1), 202 | sizeZ = array.GetLength(2); 203 | 204 | uv = new Vector3(uv.x * sizeX, uv.y * sizeY, uv.z * sizeZ); 205 | 206 | int x = (int)uv.x, 207 | y = (int)uv.y, 208 | z = (int)uv.z; 209 | Vector3 t = new Vector3(uv.x - x, 210 | uv.y - y, 211 | uv.z - z); 212 | 213 | //Get the elements to interpolate between. 214 | T minXYZ, minXYmaxZ, minXmaxYminZ, minXmaxYZ, maxXminYZ, maxXminYmaxZ, maxXYminZ, maxXYZ; 215 | Sample(array, x, y, z, wrap, 216 | out minXYZ, out maxXminYZ, out minXmaxYminZ, out maxXYminZ, 217 | out minXYmaxZ, out maxXminYmaxZ, out minXmaxYZ, out maxXYZ); 218 | 219 | //Interpolate. 220 | return lerp(lerp(lerp(minXYZ, maxXminYZ, t.x), 221 | lerp(minXmaxYminZ, maxXYminZ, t.x), 222 | t.y), 223 | lerp(lerp(minXYmaxZ, maxXminYmaxZ, t.x), 224 | lerp(minXmaxYZ, maxXYZ, t.x), 225 | t.y), 226 | t.z); 227 | } 228 | 229 | /// 230 | /// Up- or down-samples the given 3D array, 231 | /// assuming that the change in size isn't more than 2x along each axis. 232 | /// 233 | public static T[,,] Resample(this T[,,] original, Func lerp, 234 | int newSizeX, int newSizeY, int newSizeZ) 235 | { 236 | T[,,] newVals = new T[newSizeX, newSizeY, newSizeZ]; 237 | Vector3 scale = new Vector3(1.0f / newSizeX, 1.0f / newSizeY, 1.0f / newSizeZ); 238 | for (int z = 0; z < newSizeZ; ++z) 239 | { 240 | for (int y = 0; y < newSizeY; ++y) 241 | { 242 | for (int x = 0; x < newSizeX; ++x) 243 | { 244 | Vector3 uv = new Vector3(x * scale.x, y * scale.y, z * scale.z); 245 | newVals[x, y, z] = original.Sample(uv, lerp, false); 246 | } 247 | } 248 | } 249 | 250 | return newVals; 251 | } 252 | /// 253 | /// Up- or down-samples the given 3D array to any new size. 254 | /// 255 | public static T[,,] ResampleFull(this T[,,] original, Func lerp, 256 | int targetSizeX, int targetSizeY, int targetSizeZ) 257 | { 258 | //Keep doubling/halving the array until we get to the target. 259 | while (original.GetLength(0) != targetSizeX || 260 | original.GetLength(1) != targetSizeY || 261 | original.GetLength(2) != targetSizeZ) 262 | { 263 | //If the target size is too big/small, clamp it. 264 | int newSizeX = Mathf.Clamp(targetSizeX, 265 | original.GetLength(0) / 2, 266 | original.GetLength(0) * 2), 267 | newSizeY = Mathf.Clamp(targetSizeY, 268 | original.GetLength(1) / 2, 269 | original.GetLength(1) * 2), 270 | newSizeZ = Mathf.Clamp(targetSizeZ, 271 | original.GetLength(2) / 2, 272 | original.GetLength(2) * 2); 273 | 274 | original = Resample(original, lerp, newSizeX, newSizeY, newSizeZ); 275 | } 276 | 277 | return original; 278 | } 279 | } 280 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/GUIUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5ba6ae81b33bcb1449b805bc7625f664 3 | timeCreated: 1444941823 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9cc282332258dc84bb1e1c3a61654289 3 | folderAsset: yes 4 | timeCreated: 1444256280 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a1a11faf58476d9449325e96aee3500f 3 | folderAsset: yes 4 | timeCreated: 1457244425 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Editor/GraphEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c8bf111703688b4787b8d142407204f 3 | timeCreated: 1444262169 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Editor/NodeOptionsGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | using UnityEditor; 6 | 7 | using P = GPUGraph.SimpleNode.Param; 8 | using Category = GPUGraph.Editor.NodeTree_Element_Category; 9 | using Option = GPUGraph.Editor.NodeTree_Element_Option; 10 | 11 | 12 | namespace GPUGraph.Editor 13 | { 14 | //TODO: ParamNode_Texture3D and Cube (http://docs.unity3d.com/432/Documentation/Components/SL-Properties.html). 15 | //TODO: CustomFunction node, like a fuller version of CustomExpression. 16 | //TODO: Add buttons to addition, subtraction, min/max, etc. nodes for an arbitrary number of inputs. 17 | //TODO: Optionally have more than one output. Use for noise, texture nodes, and TexCoordNode. 18 | 19 | 20 | /// 21 | /// A tree of node types to choose from. 22 | /// Each element is either an option or a branch leading to more elements of the same category. 23 | /// 24 | public abstract class NodeTree_Element 25 | { 26 | /// 27 | /// Draws this element as a selectable option in an editor window. 28 | /// Returns the element that was selected, or "null" if nothing was selected. 29 | /// 30 | public abstract NodeTree_Element_Option OnGUI(); 31 | } 32 | 33 | 34 | public class NodeTree_Element_Category : NodeTree_Element 35 | { 36 | public string Title, Tooltip; 37 | public NodeTree_Element[] SubItems; 38 | 39 | public NodeTree_Element_Category(string title, params NodeTree_Element[] subItems) 40 | { 41 | Title = title; 42 | SubItems = subItems; 43 | } 44 | public NodeTree_Element_Category(string title, string tooltip, params NodeTree_Element[] subItems) 45 | { 46 | Title = title; 47 | Tooltip = tooltip; 48 | SubItems = subItems; 49 | } 50 | 51 | private bool foldout = false; 52 | public override NodeTree_Element_Option OnGUI() 53 | { 54 | NodeTree_Element_Option option = null; 55 | 56 | foldout = EditorGUILayout.Foldout(foldout, Title); 57 | if (foldout) 58 | { 59 | GUILayout.BeginHorizontal(); 60 | GUILayout.Space(25.0f); 61 | GUILayout.BeginVertical(); 62 | 63 | foreach (NodeTree_Element el in SubItems) 64 | { 65 | NodeTree_Element_Option temp = el.OnGUI(); 66 | if (temp != null) 67 | option = temp; 68 | } 69 | 70 | GUILayout.EndVertical(); 71 | GUILayout.EndHorizontal(); 72 | } 73 | 74 | return option; 75 | } 76 | } 77 | public class NodeTree_Element_Option : NodeTree_Element 78 | { 79 | public static NodeTree_Element_Option OneVarFunc(string func, string title, string tooltip, 80 | string var = "f", float defVal = float.NaN) 81 | { 82 | return new Option((g, r) => new SimpleNode(r, func + "('" + var + "')", title, new P(var, defVal)), 83 | title, tooltip); 84 | } 85 | public static NodeTree_Element_Option TwoVarFunc(string func, string title, string tooltip, 86 | string var1 = "x", float defVal1 = float.NaN, 87 | string var2 = "y", float defVal2 = float.NaN) 88 | { 89 | return new Option((g, r) => new SimpleNode(r, func + "('" + var1 + "', '" + var2 + "')", title, 90 | new P(var1, defVal1), new P(var2, defVal2)), 91 | title, tooltip); 92 | } 93 | public static NodeTree_Element_Option ThreeVarFunc(string func, string title, string tooltip, 94 | string var1 = "x", float defVal1 = float.NaN, 95 | string var2 = "y", float defVal2 = float.NaN, 96 | string var3 = "t", float defVal3 = float.NaN) 97 | { 98 | return new Option((g, r) => new SimpleNode(r, func + "('" + var1 + "', '" + var2 + "', '" + var3 + "')", title, 99 | new P(var1, defVal1), new P(var2, defVal2), new P(var3, defVal3)), 100 | title, tooltip); 101 | } 102 | 103 | public Func NodeFactory; 104 | public string Name, Tooltip; 105 | 106 | public NodeTree_Element_Option(Func nodeFactory, 107 | string name, string tooltip = "") 108 | { 109 | NodeFactory = nodeFactory; 110 | Name = name; 111 | Tooltip = tooltip; 112 | } 113 | 114 | public override NodeTree_Element_Option OnGUI() 115 | { 116 | GUILayout.BeginHorizontal(); 117 | 118 | bool pressed = GUILayout.Button(new GUIContent(Name, Tooltip)); 119 | GUILayout.FlexibleSpace(); 120 | 121 | GUILayout.EndHorizontal(); 122 | 123 | return (pressed ? this : null); 124 | } 125 | } 126 | 127 | 128 | public static class NodeOptionsGenerator 129 | { 130 | /// 131 | /// Returns the root of the option list. 132 | /// 133 | public static List GenerateList() 134 | { 135 | return new List() { 136 | new Category("Noise", "Noise-generation functions", 137 | new Option((g, r) => new NoiseNode(r, NoiseNode.NoiseTypes.White, 3), 138 | "White Noise", "Fast, completely chaotic noise"), 139 | new Option((g, r) => new NoiseNode(r, NoiseNode.NoiseTypes.Blocky, 3), 140 | "Grid Noise", "White noise that's broken up into square blocks"), 141 | new Option((g, r) => new NoiseNode(r, NoiseNode.NoiseTypes.Linear, 3), 142 | "Linear Noise", "Low-quality but fast coherent noise"), 143 | new Option((g, r) => new NoiseNode(r, NoiseNode.NoiseTypes.Smooth, 3), 144 | "Smooth Noise", "Medium-quality, fairly fast coherent noise"), 145 | new Option((g, r) => new NoiseNode(r, NoiseNode.NoiseTypes.Smoother, 3), 146 | "Smoother Noise", "High-quality but slow coherent noise"), 147 | new Option((g, r) => new NoiseNode(r, NoiseNode.NoiseTypes.Perlin, 3), 148 | "Perlin Noise", "Beautiful but very slow coherent noise"), 149 | new Option((g, r) => new NoiseNode(r, NoiseNode.NoiseTypes.Worley, 2), 150 | "Worley Noise", "Generates noise that looks like Voroni diagrams")), 151 | new Category("Interpolation", "Ways of transitioning from one value to another", 152 | Option.TwoVarFunc("step", "Step", "Returns 0 if X is less than Y and 1 if X is more than Y", 153 | "y", 0.5f, "x"), 154 | Option.ThreeVarFunc("lerp", "Lerp", "Linearly interpolates between a and b based on t", 155 | "a", float.NaN, "b", float.NaN, "t"), 156 | Option.ThreeVarFunc("smoothstep", "Smoothstep", "Like \"Lerp\" but pushed out to the edges of the range", 157 | "a", 0.0f, "b", 1.0f, "t"), 158 | new Option((g, r) => new SimpleNode(r, "smoothstep('x', 'y', smoothstep(0.0, 1.0, 't'))", 159 | "Smoothstep", 160 | new P("x", 0.0f), new P("y", 0.0f), new P("t")), 161 | "Smootherstep", "Like \"Smoothstep\" but even more pushed outwards"), 162 | new Option((g, r) => new SimpleNode(r, "lerp('destMin', 'destMax', " + 163 | "('srcVal' - 'srcMin') / ('srcMax' - 'srcMin'))", 164 | "Remap", 165 | new P("destMin", 0.0f), new P("destMax", 1.0f), 166 | new P("srcMin", -1.0f), new P("srcMax", 1.0f), 167 | new P("srcVal")), 168 | "Remap", "Remaps a value from a source range to a destination range")), 169 | new Category("Basic Math", "Add/subtract/multiply/divide", 170 | new Option((g, r) => new SimpleNode(r, "'f1' + 'f2'", "Add", new P("f1"), new P("f2")), 171 | "Add", "Adds two values together"), 172 | new Option((g, r) => new SimpleNode(r, "'f1' - 'f2'", "Subtract", new P("f1"), new P("f2")), 173 | "Subtract", "Subtracts the second value from the first"), 174 | new Option((g, r) => new SimpleNode(r, "'f1' * 'f2'", "Multiply", new P("f1"), new P("f2")), 175 | "Multiply", "Multiplies two values together"), 176 | new Option((g, r) => new SimpleNode(r, "'f1' / 'f2'", "Divide", new P("f1"), new P("f2")), 177 | "Divide", "Divides the first value by the second"), 178 | Option.TwoVarFunc("pow", "Pow", "Raises a value to an exponent", 179 | "value", float.NaN, "exponent", 1.0f), 180 | Option.OneVarFunc("sqrt", "Square Root", "Square root"), 181 | Option.OneVarFunc("log", "Logarithm", "Logarithm base e")), 182 | new Category("Trig", 183 | Option.OneVarFunc("sin", "Sin", "A sine wave"), 184 | Option.OneVarFunc("cos", "Cos", "A cosine wave"), 185 | Option.OneVarFunc("tan", "Tan", "Tangent"), 186 | Option.OneVarFunc("acos", "Inverse Cos", "Inverse of the cosine wave"), 187 | Option.OneVarFunc("asin", "Inverse Sin", "Inverse of the sine wave"), 188 | Option.OneVarFunc("atan", "Inverse Tan", "Inverse of \"tan\""), 189 | Option.TwoVarFunc("atan2", "Inverse Tan 2", "Inverse of \"tan\" that takes individual x and y", 190 | "y", float.NaN, "x")), 191 | new Category("Numeric", 192 | Option.OneVarFunc("frac", "Fractional Part", "The fractional part of a value"), 193 | Option.OneVarFunc("trunc", "Integer Part", "The integer part of a value"), 194 | Option.OneVarFunc("ceil", "Ceiling", "Rounds a value up towards positive infinity"), 195 | Option.OneVarFunc("floor", "Floor", "Rounds a value down towards negative infinity"), 196 | Option.OneVarFunc("round", "Round to Integer", "Rounds a value to the nearest integer"), 197 | Option.OneVarFunc("sign", "Sign", "Returns -1, 0, or 1 depending on the value's sign"), 198 | Option.OneVarFunc("abs", "Abs", "Absolute value"), 199 | Option.TwoVarFunc("max", "Max", "Gets the largest of two values"), 200 | Option.TwoVarFunc("min", "Min", "Gets the smallest of two values"), 201 | Option.ThreeVarFunc("clamp", "Clamp", "Keeps a value between a min and a max", 202 | "f", float.NaN, "low", 0.0f, "high", 1.0f)), 203 | new Option((g, r) => new CustomExprNode(r, "$1"), "Custom Expression"), 204 | new Option((g, r) => new TexCoordNode(r, 0), "Tex Coord", "UV x/y/z"), 205 | new Option((g, r) => new ParamNode_Float(r, new FloatParamInfo("MyVar")), "Scalar Parameter"), 206 | new Option((g, r) => new ParamNode_Texture2D(r, new Texture2DParamInfo("MyTex")), 207 | "Tex2D Parameter", "Gets the Red value of a texture"), 208 | new Option((g, r) => new SubGraphNode(r), "Sub-graph", "Get the output of another graph"), 209 | }; 210 | } 211 | } 212 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Editor/NodeOptionsGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 33365d145ff8db1459ae2c0b636e0037 3 | timeCreated: 1457243267 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/GpuRand.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ae693ad6aa37c2e408068c493d01198b 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Graph.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b385099094842b14785f3f0919722aa7 3 | timeCreated: 1457244725 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/GraphEditorUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using System.Runtime.Serialization.Formatters.Binary; 7 | using UnityEngine; 8 | using UnityEditor; 9 | 10 | 11 | namespace GPUGraph 12 | { 13 | public static class GraphEditorUtils 14 | { 15 | /// 16 | /// The standard file extension for Graphs. 17 | /// 18 | public static readonly string Extension = "gpug"; 19 | 20 | 21 | /// 22 | /// Gets the full paths for all graphs in this Unity project. 23 | /// 24 | public static List GetAllGraphsInProject(string excludeGraph = null, 25 | bool makeRelativeToAssets = false) 26 | { 27 | DirectoryInfo inf = new DirectoryInfo(Application.dataPath); 28 | FileInfo[] files = inf.GetFiles("*." + Extension, SearchOption.AllDirectories); 29 | return files 30 | .Select(f => (makeRelativeToAssets ? 31 | StringUtils.GetRelativePath(f.FullName, "Assets") : 32 | f.FullName)) 33 | .Where(f => (f != excludeGraph)) 34 | .ToList(); 35 | } 36 | 37 | /// 38 | /// Saves the shader for the given graph to the given file with the given name. 39 | /// Also forces Unity to immediately recognize and compile the shader 40 | /// so that it can be immediately used after calling this function. 41 | /// If the shader fails to load for some reason, an error is output to the Unity console 42 | /// and "null" is returned. 43 | /// 44 | /// 45 | /// The texture output. 46 | /// For example, pass "rgb" or "xyz" to output the noise into the red, green, and blue channels 47 | /// but not the alpha channel. 48 | /// 49 | /// 50 | /// The color (generally 0-1) of the color components which aren't set by the noise. 51 | /// 52 | public static Shader SaveShader(Graph g, string filePath, string shaderName, 53 | string outputComponents, float defaultColor) 54 | { 55 | string relativePath = StringUtils.GetRelativePath(filePath, "Assets"); 56 | 57 | try 58 | { 59 | //Get the shader code. 60 | string shad = g.GenerateShader(shaderName, outputComponents, defaultColor); 61 | if (shad == null) 62 | { 63 | return null; 64 | } 65 | 66 | //Write to the file. 67 | DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(filePath)); 68 | if (!dir.Exists) 69 | dir.Create(); 70 | File.WriteAllText(filePath, shad); 71 | 72 | 73 | //Tell Unity to load/compile it. 74 | AssetDatabase.ImportAsset(relativePath, ImportAssetOptions.ForceSynchronousImport); 75 | } 76 | catch (Exception e) 77 | { 78 | Debug.LogError("Error saving/loading shader to/from file: " + e.Message); 79 | } 80 | 81 | return AssetDatabase.LoadAssetAtPath(relativePath); 82 | } 83 | /// 84 | /// Saves the shader for the given graph to the given file with the given name. 85 | /// Also forces Unity to immediately recognize and compile the shader 86 | /// so that it can be immediately used after calling this function. 87 | /// If the shader fails to load for some reason, an error is output to the Unity console 88 | /// and "null" is returned. 89 | /// 90 | /// The name of the gradient ramp texture param. 91 | public static Shader SaveShader(Graph g, string filePath, string shaderName, 92 | string gradientRampName) 93 | { 94 | string relativePath = StringUtils.GetRelativePath(filePath, "Assets"); 95 | 96 | try 97 | { 98 | //Get the shader code. 99 | string shad = g.GenerateShader(shaderName, gradientRampName); 100 | if (shad == null) 101 | { 102 | return null; 103 | } 104 | 105 | //Write to the file. 106 | DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(filePath)); 107 | if (!dir.Exists) 108 | dir.Create(); 109 | File.WriteAllText(filePath, shad); 110 | 111 | 112 | //Tell Unity to load/compile it. 113 | AssetDatabase.ImportAsset(relativePath, ImportAssetOptions.ForceSynchronousImport); 114 | } 115 | catch (Exception e) 116 | { 117 | Debug.LogError("Error saving/loading shader to/from file: " + e.Message); 118 | } 119 | 120 | return AssetDatabase.LoadAssetAtPath(relativePath); 121 | } 122 | 123 | /// 124 | /// Generates a texture containing the given graph's noise output. 125 | /// If this is being called very often, create a permanent render target and material and 126 | /// use the other version of this method instead for much better performance. 127 | /// If an error occurred, outputs to the Unity debug console and returns "null". 128 | /// 129 | /// 130 | /// The texture output. 131 | /// For example, pass "rgb" or "xyz" to output the noise into the red, green, and blue channels 132 | /// but not the alpha channel. 133 | /// 134 | /// 135 | /// The color (generally 0-1) of the color components which aren't set by the noise. 136 | /// 137 | /// The Z coordinate of the UVs, in case the graph uses it for 3D noise. 138 | /// 139 | /// Whether the texture's pixel data can still be read from the CPU after this operation. 140 | /// 141 | public static Texture2D GenerateToTexture(Graph g, GraphParamCollection c, 142 | int width, int height, float uvZ, 143 | string outputComponents, float defaultColor, 144 | TextureFormat format = TextureFormat.RGBAFloat, 145 | bool leaveReadable = false) 146 | { 147 | //Generate a shader/material from the graph. 148 | Shader shader = ShaderUtil.CreateShaderAsset(g.GenerateShader("TempGPUNoiseShader", 149 | outputComponents, 150 | defaultColor)); 151 | if (shader == null) 152 | return null; 153 | Material mat = new Material(shader); 154 | c.SetParams(mat); 155 | mat.SetFloat(GraphUtils.Param_UVz, uvZ); 156 | 157 | //Render the shader's output into a render texture and copy the data to a Texture2D. 158 | RenderTexture target = RenderTexture.GetTemporary(width, height, 16, 159 | RenderTextureFormat.ARGBFloat); 160 | Texture2D resultTex = new Texture2D(width, height, format, false, true); 161 | 162 | //Generate. 163 | GraphUtils.GenerateToTexture(target, mat, resultTex, leaveReadable); 164 | 165 | //Clean up. 166 | RenderTexture.ReleaseTemporary(target); 167 | 168 | return resultTex; 169 | } 170 | /// 171 | /// Generates a texture containing the given graph's noise output. 172 | /// If this is being called very often, create a permanent render target and material and 173 | /// use the other version of this method instead for much better performance. 174 | /// If an error occurred, outputs to the Unity debug console and returns "null". 175 | /// 176 | /// The name of the gradient ramp texture param. 177 | /// The Z coordinate of the UVs, in case the graph uses it for 3D noise. 178 | /// 179 | /// Whether to leave the texture data readable on the CPU after the operation. 180 | /// 181 | public static Texture2D GenerateToTexture(Graph g, GraphParamCollection c, 182 | int width, int height, float uvZ, 183 | Gradient gradientRamp, 184 | TextureFormat format = TextureFormat.RGBAFloat, 185 | bool leaveReadable = false) 186 | { 187 | //Generate a shader/material from the graph. 188 | Shader shader = ShaderUtil.CreateShaderAsset(g.GenerateShader("TempGPUNoiseShader", 189 | "_MyGradientRamp14123")); 190 | if (shader == null) 191 | return null; 192 | Material mat = new Material(shader); 193 | c.SetParams(mat); 194 | mat.SetFloat(GraphUtils.Param_UVz, uvZ); 195 | 196 | //Generate a texture from the gradient. 197 | Texture2D myRamp = new Texture2D(1024, 1, TextureFormat.RGBA32, false); 198 | Color[] cols = new Color[myRamp.width]; 199 | for (int i = 0; i < cols.Length; ++i) 200 | cols[i] = gradientRamp.Evaluate((float)i / (float)(cols.Length - 1)); 201 | myRamp.SetPixels(cols); 202 | myRamp.Apply(false, true); 203 | mat.SetTexture("_MyGradientRamp14123", myRamp); 204 | 205 | //Render the shader's output into a render texture and copy the data to a Texture2D. 206 | RenderTexture target = RenderTexture.GetTemporary(width, height, 16, 207 | RenderTextureFormat.ARGBFloat); 208 | Texture2D resultTex = new Texture2D(width, height, format, false, true); 209 | 210 | //Generate. 211 | GraphUtils.GenerateToTexture(target, mat, resultTex, leaveReadable); 212 | 213 | //Clean up. 214 | RenderTexture.ReleaseTemporary(target); 215 | 216 | return resultTex; 217 | } 218 | 219 | /// 220 | /// Generates a 3D texture containing the given graph's noise output. 221 | /// 222 | /// 223 | /// The texture output. 224 | /// For example, pass "rgb" or "xyz" to output the noise into the red, green, and blue channels 225 | /// but not the alpha channel. 226 | /// 227 | /// 228 | /// The color (generally 0-1) of the color components which aren't set by the noise. 229 | /// 230 | /// Whether the 3D texture object uses mipmapping. 231 | /// 232 | /// Whether to let the texture keep a CPU copy of its data on hand for later reading. 233 | /// 234 | public static Texture3D GenerateToTexture(Graph g, GraphParamCollection c, 235 | int width, int height, int depth, 236 | string outputComponents, float defaultColor, 237 | bool useMipmaps, bool leaveTextureReadable, 238 | TextureFormat format = TextureFormat.RGBA32) 239 | { 240 | //Generate a shader/material from the graph. 241 | Shader shader = ShaderUtil.CreateShaderAsset(g.GenerateShader("TempGPUNoiseShader", 242 | outputComponents, 243 | defaultColor)); 244 | if (shader == null) 245 | return null; 246 | Material mat = new Material(shader); 247 | c.SetParams(mat); 248 | 249 | 250 | //For every Z layer in the texture, generate a 2D texture representing that layer. 251 | 252 | Color32[] finalPixels = new Color32[width * height * depth]; 253 | 254 | RenderTexture target = RenderTexture.GetTemporary(width, height, 16, 255 | RenderTextureFormat.ARGBFloat); 256 | Texture2D resultTex = new Texture2D(width, height, TextureFormat.RGBAFloat, false, true); 257 | 258 | 259 | for (int depthI = 0; depthI < depth; ++depthI) 260 | { 261 | //Get the UV.z coordinate. 262 | float uvZ = (float)depthI / depth; 263 | mat.SetFloat(GraphUtils.Param_UVz, uvZ); 264 | 265 | GraphUtils.GenerateToTexture(target, mat, resultTex, true); 266 | 267 | //Copy the resulting data into part of the 3D texture. 268 | Color32[] layerPixels = resultTex.GetPixels32(); 269 | int pixelOffset = depthI * (width * height); 270 | for (int pixelI = 0; pixelI < (width * height); ++pixelI) 271 | finalPixels[pixelI + pixelOffset] = layerPixels[pixelI]; 272 | } 273 | 274 | 275 | //Create the actual texture object. 276 | Texture3D finalTex = new Texture3D(width, height, depth, format, useMipmaps); 277 | finalTex.SetPixels32(finalPixels); 278 | finalTex.Apply(useMipmaps, !leaveTextureReadable); 279 | 280 | //Clean up. 281 | RenderTexture.ReleaseTemporary(target); 282 | 283 | return finalTex; 284 | } 285 | /// 286 | /// Generates a 3D texture containing the given graph's noise output. 287 | /// 288 | /// Whether the 3D texture object uses mipmapping. 289 | /// 290 | /// Whether to let the texture keep a CPU copy of its data on hand for later reading. 291 | /// 292 | public static Texture3D GenerateToTexture(Graph g, GraphParamCollection c, 293 | int width, int height, int depth, Gradient gradientRamp, 294 | bool useMipmaps, bool leaveTextureReadable, 295 | TextureFormat format = TextureFormat.RGBA32) 296 | { 297 | //Generate a shader/material from the graph. 298 | Shader shader = ShaderUtil.CreateShaderAsset(g.GenerateShader("TempGPUNoiseShader", 299 | "_MyGradientRamp14123")); 300 | if (shader == null) 301 | return null; 302 | Material mat = new Material(shader); 303 | c.SetParams(mat); 304 | 305 | //Generate a texture from the gradient. 306 | Texture2D myRamp = new Texture2D(1024, 1, TextureFormat.RGBA32, false); 307 | Color[] cols = new Color[myRamp.width]; 308 | for (int i = 0; i < cols.Length; ++i) 309 | cols[i] = gradientRamp.Evaluate((float)i / (float)(cols.Length - 1)); 310 | myRamp.SetPixels(cols); 311 | myRamp.Apply(false, true); 312 | mat.SetTexture("_MyGradientRamp14123", myRamp); 313 | 314 | //For every Z layer in the texture, generate a 2D texture representing that layer. 315 | 316 | Color32[] finalPixels = new Color32[width * height * depth]; 317 | 318 | RenderTexture target = RenderTexture.GetTemporary(width, height, 16, 319 | RenderTextureFormat.ARGBFloat); 320 | Texture2D resultTex = new Texture2D(width, height, TextureFormat.RGBAFloat, false, true); 321 | 322 | 323 | for (int depthI = 0; depthI < depth; ++depthI) 324 | { 325 | //Get the UV.z coordinate. 326 | float uvZ = (float)depthI / depth; 327 | mat.SetFloat(GraphUtils.Param_UVz, uvZ); 328 | 329 | GraphUtils.GenerateToTexture(target, mat, resultTex, true); 330 | 331 | //Copy the resulting data into part of the 3D texture. 332 | Color32[] layerPixels = resultTex.GetPixels32(); 333 | int pixelOffset = depthI * (width * height); 334 | for (int pixelI = 0; pixelI < (width * height); ++pixelI) 335 | finalPixels[pixelI + pixelOffset] = layerPixels[pixelI]; 336 | } 337 | 338 | 339 | //Create the actual texture object. 340 | Texture3D finalTex = new Texture3D(width, height, depth, format, useMipmaps); 341 | finalTex.SetPixels32(finalPixels); 342 | finalTex.Apply(useMipmaps, !leaveTextureReadable); 343 | 344 | //Clean up. 345 | RenderTexture.ReleaseTemporary(target); 346 | 347 | return finalTex; 348 | } 349 | 350 | /// 351 | /// Generates a 2D grid of noise from the given graph. 352 | /// If an error occurred, outputs to the Unity debug console and returns "null". 353 | /// 354 | public static float[,] GenerateToArray(Graph g, GraphParamCollection c, int width, int height) 355 | { 356 | Texture2D t = GenerateToTexture(g, c, width, height, 0.0f, "r", 0.0f, 357 | TextureFormat.RGBAFloat, true); 358 | if (t == null) 359 | { 360 | return null; 361 | } 362 | 363 | Color[] cols = t.GetPixels(); 364 | float[,] vals = new float[width, height]; 365 | for (int i = 0; i < cols.Length; ++i) 366 | { 367 | int x = i % width, 368 | y = i / width; 369 | 370 | vals[x, y] = cols[i].r; 371 | } 372 | 373 | return vals; 374 | } 375 | /// 376 | /// Generates a 3D grid of noise from the given graph. 377 | /// If an error occurred, outputs to the Unity debug console and returns "null". 378 | /// 379 | public static float[,,] GenerateToArray(Graph g, GraphParamCollection c, 380 | int width, int height, int depth) 381 | { 382 | //Generate a 3D texture using the graph's shader. 383 | Texture3D t = GenerateToTexture(g, c, width, height, depth, "r", 0.0f, false, true, 384 | TextureFormat.RGBA32); 385 | if (t == null) 386 | { 387 | return null; 388 | } 389 | 390 | //Read the texture data and put it into a 3D array. 391 | Color[] cols = t.GetPixels(); 392 | float[,,] vals = new float[width, height, depth]; 393 | int i = 0; 394 | for (int z = 0; z < depth; ++z) 395 | for (int y = 0; y < height; ++y) 396 | for (int x = 0; x < width; ++x) 397 | vals[x, y, z] = cols[i++].r; 398 | 399 | return vals; 400 | } 401 | } 402 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/GraphEditorUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da0a7c4d8e225394eb0caaa3500e722a 3 | timeCreated: 1455839013 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/GraphParamCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | using UnityEditor; 6 | 7 | 8 | namespace GPUGraph 9 | { 10 | /// 11 | /// A collection of all parameters in a Graph. 12 | /// 13 | [Serializable] 14 | public class GraphParamCollection 15 | { 16 | public List FloatParams; 17 | public List Tex2DParams; 18 | 19 | 20 | public GraphParamCollection() 21 | { 22 | FloatParams = new List(); 23 | Tex2DParams = new List(); 24 | } 25 | /// 26 | /// Gets all the parameters in the given Graph. 27 | /// 28 | public GraphParamCollection(Graph g) 29 | : this() 30 | { 31 | Graph gCopy = g.Clone(); 32 | gCopy.PreProcess(); 33 | 34 | foreach (Node n in gCopy.Nodes) 35 | { 36 | if (n is ParamNode_Float) 37 | FloatParams.Add(((ParamNode_Float)n).Param); 38 | else if (n is ParamNode_Texture2D) 39 | Tex2DParams.Add(((ParamNode_Texture2D)n).Param); 40 | } 41 | } 42 | /// 43 | /// Gets all parameters from the given collection and recreates them for the given graph. 44 | /// 45 | public GraphParamCollection(Graph otherG, GraphParamCollection c) 46 | : this(otherG) 47 | { 48 | //Needed for lambdas. 49 | List myFloatParams = FloatParams; 50 | List myTex2DParams = Tex2DParams; 51 | 52 | for (int i = 0; i < FloatParams.Count; ++i) 53 | { 54 | int otherPMIndex = c.FloatParams.FindIndex(param2 => param2.Name == myFloatParams[i].Name); 55 | if (otherPMIndex == -1) 56 | Debug.LogError("Couldn't find an original value for scalar var '" + FloatParams[i].Name + "'"); 57 | else 58 | FloatParams[i] = new FloatParamInfo(FloatParams[i], 59 | c.FloatParams[otherPMIndex].DefaultValue); 60 | } 61 | for (int i = 0; i < Tex2DParams.Count; ++i) 62 | { 63 | int otherPMIndex = c.Tex2DParams.FindIndex(param2 => param2.Name == myTex2DParams[i].Name); 64 | if (otherPMIndex == -1) 65 | Debug.LogError("Couldn't find an original value for Tex2D var '" + Tex2DParams[i].Name + "'"); 66 | else 67 | Tex2DParams[i] = new Texture2DParamInfo(Tex2DParams[i].Name, 68 | c.Tex2DParams[otherPMIndex].DefaultVal); 69 | } 70 | } 71 | 72 | 73 | public FloatParamInfo? FindFloatParam(string name) 74 | { 75 | foreach (var param in FloatParams) 76 | if (param.Name == name) 77 | return param; 78 | return null; 79 | } 80 | public Texture2DParamInfo? FindTex2DParam(string name) 81 | { 82 | foreach (var param in Tex2DParams) 83 | if (param.Name == name) 84 | return param; 85 | return null; 86 | } 87 | 88 | /// 89 | /// Sets the given material to use these parameters, with their default values. 90 | /// 91 | public void SetParams(Material m, string prefix = null) 92 | { 93 | foreach (FloatParamInfo dat in FloatParams) 94 | { 95 | string datName = (prefix == null) ? 96 | dat.Name : 97 | (prefix + dat.Name); 98 | 99 | if (!m.HasProperty(datName)) 100 | { 101 | Debug.LogWarning("Couldn't find property '" + datName + 102 | "'; Unity may have optimized it out"); 103 | } 104 | else 105 | { 106 | m.SetFloat(datName, 107 | (dat.IsSlider ? 108 | Mathf.Lerp(dat.SliderMin, dat.SliderMax, dat.DefaultValue) : 109 | dat.DefaultValue)); 110 | } 111 | } 112 | foreach (Texture2DParamInfo dat in Tex2DParams) 113 | { 114 | string datName = (prefix == null) ? 115 | dat.Name : 116 | (prefix + dat.Name); 117 | 118 | if (!m.HasProperty(datName)) 119 | { 120 | Debug.LogWarning("Couldn't find property '" + datName + 121 | "'; Unity may have optimized it out"); 122 | } 123 | else 124 | { 125 | m.SetTexture(datName, dat.DefaultVal); 126 | } 127 | } 128 | } 129 | /// 130 | /// Sets this collection's parameter values from the given collection. 131 | /// Ignores parameters that don't exist on this collection. 132 | /// 133 | public void SetParams(GraphParamCollection from) 134 | { 135 | for (int i = 0; i < FloatParams.Count; ++i) 136 | { 137 | var toParam = FloatParams[i]; 138 | var fromParam = from.FindFloatParam(toParam.Name); 139 | if (fromParam.HasValue) 140 | FloatParams[i] = new FloatParamInfo(toParam, fromParam.Value.DefaultValue); 141 | } 142 | for (int i = 0; i < Tex2DParams.Count; ++i) 143 | { 144 | var toParam = Tex2DParams[i]; 145 | var fromParam = from.FindTex2DParam(toParam.Name); 146 | if (fromParam.HasValue) 147 | Tex2DParams[i] = new Texture2DParamInfo(toParam.Name, fromParam.Value.DefaultVal); 148 | } 149 | } 150 | 151 | /// 152 | /// Runs a GUI using EditorGUILayout for these parameters. 153 | /// This GUI can be used to modify each parameter's "default value" fields. 154 | /// Returns whether any values have been changed. 155 | /// 156 | public bool ParamEditorGUI() 157 | { 158 | bool changed = false; 159 | 160 | for (int i = 0; i < FloatParams.Count; ++i) 161 | { 162 | GUILayout.BeginHorizontal(); 163 | GUILayout.Label(StringUtils.PrettifyVarName(FloatParams[i].Name)); 164 | float oldVal = FloatParams[i].DefaultValue; 165 | if (FloatParams[i].IsSlider) 166 | { 167 | GUILayout.Label(FloatParams[i].SliderMin.ToString()); 168 | FloatParams[i] = new FloatParamInfo(FloatParams[i], 169 | Mathf.InverseLerp(FloatParams[i].SliderMin, FloatParams[i].SliderMax, 170 | GUILayout.HorizontalSlider(Mathf.Lerp(FloatParams[i].SliderMin, 171 | FloatParams[i].SliderMax, 172 | FloatParams[i].DefaultValue), 173 | FloatParams[i].SliderMin, 174 | FloatParams[i].SliderMax, 175 | GUILayout.MinWidth(50.0f)))); 176 | GUILayout.Label(FloatParams[i].SliderMax.ToString()); 177 | } 178 | else 179 | { 180 | FloatParams[i] = new FloatParamInfo(FloatParams[i], 181 | EditorGUILayout.FloatField(FloatParams[i].DefaultValue)); 182 | } 183 | 184 | changed = (changed || Node.AreFloatsDifferent(oldVal, FloatParams[i].DefaultValue)); 185 | 186 | GUILayout.EndHorizontal(); 187 | } 188 | for (int i = 0; i < Tex2DParams.Count; ++i) 189 | { 190 | GUILayout.BeginHorizontal(); 191 | 192 | GUILayout.Label(StringUtils.PrettifyVarName(Tex2DParams[i].Name)); 193 | 194 | Texture2D oldVal = Tex2DParams[i].DefaultVal; 195 | Tex2DParams[i] = new Texture2DParamInfo(Tex2DParams[i].Name, 196 | (Texture2D)EditorGUILayout.ObjectField(Tex2DParams[i].DefaultVal, 197 | typeof(Texture2D), false)); 198 | 199 | changed = (oldVal != Tex2DParams[i].DefaultVal); 200 | 201 | GUILayout.EndHorizontal(); 202 | } 203 | 204 | return changed; 205 | } 206 | } 207 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/GraphParamCollection.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 67c747941f9e12940b4427f7cca4d37d 3 | timeCreated: 1446182957 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Node.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using UnityEngine; 7 | using UnityEditor; 8 | 9 | 10 | namespace GPUGraph 11 | { 12 | /// 13 | /// A shader operation that takes in several floats and outputs a single float. 14 | /// Note that this class implements ISerializable, 15 | /// so sub-classes *must* implement the constructor that goes with it. 16 | /// 17 | [Serializable] 18 | public abstract class Node : ISerializable 19 | { 20 | /// 21 | /// Positioning constants for the GUI window. 22 | /// 23 | private static readonly float OutputHeight = 30.0f, 24 | TitleBarHeight = 30.0f, 25 | InputSpacing = 20.0f; 26 | 27 | /// 28 | /// Compares two floats like normal, except that if they are both NaN, they are considered to be *equal*. 29 | /// 30 | public static bool AreFloatsDifferent(float f1, float f2) 31 | { 32 | bool nan1 = float.IsNaN(f1), 33 | nan2 = float.IsNaN(f2); 34 | return (nan1 && !nan2) || 35 | (!nan1 && nan2) || 36 | (!nan1 && !nan2 && f1 != f2); 37 | } 38 | 39 | 40 | 41 | /// 42 | /// A unique identifier in the graph. 43 | /// 44 | public int UID = -1; 45 | 46 | 47 | /// 48 | /// The graph that owns this instance. 49 | /// 50 | public Graph Owner; 51 | 52 | /// 53 | /// This node's window's position in the editor. 54 | /// 55 | public Rect Pos; 56 | 57 | /// 58 | /// The inputs into this node. 59 | /// Anyone outside this class should never modify it! 60 | /// Any child classes should take care that "InputNames" and "InputDefaultVals" 61 | /// always have the same number of elements as this list. 62 | /// 63 | public List Inputs = new List(); 64 | protected List InputNames = new List(); 65 | protected List InputDefaultVals = new List(); 66 | 67 | 68 | public virtual Color GUIColor { get { return Color.white; } } 69 | 70 | /// 71 | /// Gets the name of the output variable this node computes. 72 | /// 73 | public virtual string OutputName 74 | { 75 | get { return GetType().ToString().RemoveEverythingBefore('.') + UID; } 76 | } 77 | 78 | /// 79 | /// A display name for this node in the editor. 80 | /// 81 | public abstract string PrettyName { get; } 82 | 83 | 84 | public Node(Rect pos, List inputs, List inputNames, List inputDefaultVals) 85 | { 86 | Pos = pos; 87 | Inputs = inputs; 88 | InputNames = inputNames; 89 | InputDefaultVals = inputDefaultVals; 90 | } 91 | protected Node() { } 92 | 93 | 94 | public string GetInputName(int index) { return InputNames[index]; } 95 | public float GetInputDefaultValue(int index) { return InputDefaultVals[index]; } 96 | 97 | /// 98 | /// Generates a new node identical to this one, including the UID, 99 | /// but with a different graph owner. 100 | /// 101 | public Node Clone(Graph newOwner, bool addToOwner, int idOffset = 0) 102 | { 103 | Node n = MakeClone(); 104 | n.UID = UID + idOffset; 105 | n.Owner = newOwner; 106 | n.Pos = Pos; 107 | n.Inputs = Inputs.ToList(); 108 | n.InputNames = InputNames.ToList(); 109 | n.InputDefaultVals = InputDefaultVals.ToList(); 110 | 111 | for (int i = 0; i < n.Inputs.Count; ++i) 112 | if (!n.Inputs[i].IsAConstant) 113 | n.Inputs[i] = new NodeInput(n.Inputs[i].NodeID + idOffset); 114 | 115 | if (addToOwner) 116 | newOwner.AddNode(this); 117 | return n; 118 | } 119 | /// 120 | /// Generates a new node identical to this one, including the UID, 121 | /// but with no graph owner. 122 | /// 123 | public Node Clone() { return Clone(null, false); } 124 | /// 125 | /// Should create the right type of node with the same properties as this one. 126 | /// The base properties of all nodes don't need to be filled in by this method. 127 | /// 128 | protected abstract Node MakeClone(); 129 | 130 | /// 131 | /// Called when this node's owner/uid is set. 132 | /// 133 | public virtual void OnAddedToGraph() { } 134 | /// 135 | /// Called after this node's owner is done loading from a file. 136 | /// This is better than a method with OnDeserializedAttribute 137 | /// because this method is only called *after* the graph itself is fully loaded. 138 | /// 139 | public virtual void OnGraphLoaded() { } 140 | 141 | 142 | /// 143 | /// Called right before the graph generates a shader. 144 | /// Special nodes can take this opportunity to modify the graph however they want. 145 | /// Returns any new nodes that have been added to the graph. 146 | /// 147 | public virtual IEnumerable OnPreProcess() { yield break; } 148 | 149 | /// 150 | /// Appends any necessary Shaderlab property definitions to the given shader. 151 | /// 152 | /// 153 | /// A prefix that should be applied to all Property names. 154 | /// 155 | public virtual void EmitProperties(StringBuilder outCode) { } 156 | /// 157 | /// Appends any necessary definitions to the given shader. 158 | /// 159 | /// 160 | /// A prefix that should be applied to all Property names. 161 | /// 162 | public virtual void EmitDefs(StringBuilder outCode) { } 163 | /// 164 | /// Appends the actual shader code that computes the output variable. 165 | /// 166 | /// 167 | /// A prefix that should be applied to all Property names. 168 | /// 169 | public virtual void EmitCode(StringBuilder outCode) { } 170 | 171 | 172 | public enum GUIResults 173 | { 174 | /// 175 | /// Nothing happened. 176 | /// 177 | Nothing, 178 | /// 179 | /// One of the input buttons was clicked. 180 | /// 181 | ClickInput, 182 | /// 183 | /// The output button was clicked. 184 | /// 185 | ClickOutput, 186 | /// 187 | /// The "Duplicate" button was clicked. 188 | /// 189 | Duplicate, 190 | /// 191 | /// The "Delete" button was clicked. 192 | /// 193 | Delete, 194 | /// 195 | /// This node was changed in some other way. 196 | /// 197 | Other, 198 | } 199 | /// 200 | /// Runs the GUI display window for this node. 201 | /// Returns what happened. 202 | /// 203 | /// 204 | /// If the user clicked an input, 205 | /// the index of that input will be stored in this variable. 206 | /// 207 | /// 208 | /// If this node's output was previously selected, pass -1. 209 | /// If an input was selected, pass the index of that input. 210 | /// Otherwise, pass anything else. 211 | /// 212 | public GUIResults OnGUI(ref int clickedInput, int isSelected) 213 | { 214 | GUIResults result = GUIResults.Nothing; 215 | 216 | GUILayout.BeginHorizontal(); 217 | 218 | GUILayout.BeginVertical(); 219 | 220 | for (int i = 0; i < Inputs.Count; ++i) 221 | { 222 | GUILayout.BeginHorizontal(); 223 | 224 | GUILayout.Label(InputNames[i]); 225 | 226 | //Button to select input. 227 | string buttStr = (isSelected == i ? "x" : "X"); 228 | if (GUILayout.Button(buttStr)) 229 | { 230 | result = GUIResults.ClickInput; 231 | clickedInput = i; 232 | } 233 | 234 | //If this input is a constant, expose a text box to edit it. 235 | if (Inputs[i].IsAConstant) 236 | { 237 | float newVal = EditorGUILayout.FloatField(Inputs[i].ConstantValue); 238 | if (AreFloatsDifferent(newVal, Inputs[i].ConstantValue)) 239 | { 240 | result = GUIResults.Other; 241 | Inputs[i] = new NodeInput(newVal); 242 | } 243 | } 244 | //Otherwise, expose a button to release the connection. 245 | else 246 | { 247 | Rect otherPos = Owner.GetNode(Inputs[i].NodeID).Pos; 248 | Vector2 endPos = new Vector2(otherPos.xMax, otherPos.yMin + OutputHeight) - Pos.min; 249 | 250 | GUIUtil.DrawLine(new Vector2(0.0f, TitleBarHeight + ((float)i * InputSpacing)), 251 | endPos, 2.0f, Color.white); 252 | 253 | if (GUILayout.Button("Disconnect")) 254 | { 255 | Inputs[i] = new NodeInput(InputDefaultVals[i]); 256 | 257 | result = GUIResults.Other; 258 | } 259 | } 260 | 261 | GUILayout.EndHorizontal(); 262 | } 263 | 264 | if (CustomGUI()) 265 | { 266 | result = GUIResults.Other; 267 | } 268 | 269 | GUILayout.EndVertical(); 270 | GUILayout.FlexibleSpace(); 271 | GUILayout.BeginVertical(); 272 | 273 | //Output button. 274 | if (GUILayout.Button(isSelected == -1 ? "o" : "O")) 275 | { 276 | result = GUIResults.ClickOutput; 277 | } 278 | 279 | GUILayout.EndVertical(); 280 | 281 | GUILayout.EndHorizontal(); 282 | 283 | //"Duplicate" button. 284 | GUILayout.BeginHorizontal(); 285 | if (GUILayout.Button("Duplicate")) 286 | { 287 | result = GUIResults.Duplicate; 288 | } 289 | 290 | GUILayout.FlexibleSpace(); 291 | 292 | //"Delete" button. 293 | if (GUILayout.Button("Delete")) 294 | { 295 | result = GUIResults.Delete; 296 | } 297 | 298 | GUILayout.EndHorizontal(); 299 | 300 | return result; 301 | } 302 | /// 303 | /// Child nodes can add custom GUI stuff through this method. 304 | /// Must return whether anything has actually changed. 305 | /// 306 | protected virtual bool CustomGUI() { return false; } 307 | 308 | 309 | //Serialization stuff: 310 | 311 | /// 312 | /// Outputs class data to a serializer. 313 | /// 314 | public virtual void GetObjectData(SerializationInfo info, StreamingContext context) 315 | { 316 | info.AddValue("UID", UID); 317 | info.AddValue("PosX", Pos.x); 318 | info.AddValue("PosY", Pos.y); 319 | info.AddValue("PosWidth", Pos.width); 320 | info.AddValue("PosHeight", Pos.height); 321 | 322 | info.AddValue("NInputs", Inputs.Count); 323 | for (int i = 0; i < Inputs.Count; ++i) 324 | { 325 | info.AddValue("Input" + i.ToString(), Inputs[i], typeof(NodeInput)); 326 | info.AddValue("InputName" + i.ToString(), InputNames[i]); 327 | info.AddValue("InputDefaultVal" + i.ToString(), InputDefaultVals[i]); 328 | } 329 | } 330 | public Node(SerializationInfo info, StreamingContext context) 331 | { 332 | UID = info.GetInt32("UID"); 333 | Pos = new Rect(); 334 | Pos.x = info.GetSingle("PosX"); 335 | Pos.y = info.GetSingle("PosY"); 336 | Pos.width = info.GetSingle("PosWidth"); 337 | Pos.height = info.GetSingle("PosHeight"); 338 | 339 | int nIns = info.GetInt32("NInputs"); 340 | for (int i = 0; i < nIns; ++i) 341 | { 342 | Inputs.Add((NodeInput)info.GetValue("Input" + i.ToString(), typeof(NodeInput))); 343 | InputNames.Add(info.GetString("InputName" + i.ToString())); 344 | InputDefaultVals.Add(info.GetSingle("InputDefaultVal" + i.ToString())); 345 | } 346 | } 347 | } 348 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Node.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9dac662a5a947ae41af2b6b4c65fc394 3 | timeCreated: 1457244725 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/NodeInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace GPUGraph 5 | { 6 | /// 7 | /// A float value for inputting into a Node. 8 | /// Either a constant value or the output from a different Node. 9 | /// Nodes are stored by their UID. 10 | /// 11 | [Serializable] 12 | public struct NodeInput 13 | { 14 | private float constValue; 15 | private int nodeID; 16 | 17 | 18 | public bool IsValid { get { return Graph.IsValidUID(nodeID) || !Single.IsNaN(constValue); } } 19 | 20 | public bool IsAConstant { get { return !Graph.IsValidUID(nodeID); } } 21 | 22 | 23 | public float ConstantValue { get { return constValue; } } 24 | public int NodeID { get { return nodeID; } } 25 | 26 | 27 | public NodeInput(float constVal) { constValue = constVal; nodeID = -1; } 28 | 29 | public NodeInput(int _nodeID) { nodeID = _nodeID; constValue = float.NaN; } 30 | public NodeInput(Node n) { nodeID = n.UID; constValue = float.NaN; } 31 | 32 | 33 | /// 34 | /// Returns an expession that evaluates to what this input represents. 35 | /// 36 | public string GetExpression(Graph g) 37 | { 38 | if (IsAConstant) 39 | { 40 | if (float.IsNaN(ConstantValue)) 41 | { 42 | return "0.0"; 43 | } 44 | else 45 | { 46 | return ConstantValue.ToCodeString(); 47 | } 48 | } 49 | else 50 | { 51 | return g.GetNode(nodeID).OutputName; 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/NodeInput.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 72e8fc6fe5819174ca1ba85751821013 3 | timeCreated: 1457244725 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1a6075e2d466e5b4a91deef3386d5e01 3 | folderAsset: yes 4 | timeCreated: 1457245395 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/CustomExprNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using UnityEngine; 7 | using UnityEditor; 8 | 9 | 10 | namespace GPUGraph 11 | { 12 | /// 13 | /// A node whose output is a custom expression typed in by the user. 14 | /// Inputs are specified as variables starting like $1, $2, $3, etc. 15 | /// Optionally, this node can become a whole function instead of a one-line expression. 16 | /// 17 | [Serializable] 18 | public class CustomExprNode : Node 19 | { 20 | public bool IsLongForm = false; 21 | public string Expr = "$1"; 22 | 23 | 24 | public override string PrettyName { get { return "Custom " + (IsLongForm ? "Function" : "Expression"); } } 25 | 26 | 27 | public CustomExprNode(Rect pos, string expr, bool isLongForm = false) 28 | : base(pos, new List(), new List(), new List()) 29 | { 30 | Expr = expr; 31 | IsLongForm = isLongForm; 32 | SetUpInputs(); 33 | } 34 | 35 | 36 | protected override Node MakeClone() 37 | { 38 | return new CustomExprNode(new Rect(), Expr, IsLongForm); 39 | } 40 | protected override bool CustomGUI() 41 | { 42 | GUILayout.BeginHorizontal(); 43 | GUILayout.Label("Expr"); 44 | GUILayout.Space(15.0f); 45 | string newExpr; 46 | if (IsLongForm) 47 | newExpr = EditorGUILayout.TextArea(Expr); 48 | else 49 | newExpr = EditorGUILayout.TextField(Expr); 50 | GUILayout.EndHorizontal(); 51 | 52 | bool newIsLongForm = EditorGUILayout.Toggle("Is full function", IsLongForm); 53 | 54 | if (newExpr != Expr || newIsLongForm != IsLongForm) 55 | { 56 | Expr = newExpr; 57 | IsLongForm = newIsLongForm; 58 | 59 | Pos.size = Vector2.one; 60 | 61 | SetUpInputs(); 62 | return true; 63 | } 64 | return false; 65 | } 66 | 67 | public override void EmitDefs(StringBuilder outCode) 68 | { 69 | if (IsLongForm) 70 | { 71 | string expr = Expr; 72 | 73 | outCode.Append("float CustomFunc_"); 74 | outCode.Append(UID); 75 | outCode.Append("("); 76 | for (int i = 0; i < Inputs.Count; ++i) 77 | { 78 | if (i > 0) 79 | outCode.Append(", "); 80 | outCode.Append("float in"); 81 | outCode.Append(i); 82 | 83 | expr = expr.Replace("$" + (i + 1).ToString(), "in" + i.ToString()); 84 | } 85 | outCode.AppendLine(")"); 86 | outCode.AppendLine("{"); 87 | outCode.AppendLine(expr); 88 | outCode.AppendLine("}"); 89 | } 90 | } 91 | public override void EmitCode(StringBuilder outCode) 92 | { 93 | outCode.Append("float "); 94 | outCode.Append(OutputName); 95 | outCode.Append(" = "); 96 | 97 | if (IsLongForm) 98 | { 99 | outCode.Append("CustomFunc_"); 100 | outCode.Append(UID); 101 | outCode.Append("("); 102 | for (int i = 0; i < Inputs.Count; ++i) 103 | { 104 | if (i > 0) 105 | outCode.Append(", "); 106 | outCode.Append(Inputs[i].GetExpression(Owner)); 107 | } 108 | 109 | outCode.AppendLine(");"); 110 | } 111 | else 112 | { 113 | outCode.Append("("); 114 | string expr = Expr; 115 | for (int i = 0; i < Inputs.Count; ++i) 116 | { 117 | expr = expr.Replace("$" + (i + 1), 118 | Inputs[i].GetExpression(Owner)); 119 | } 120 | outCode.Append(expr); 121 | outCode.AppendLine(");"); 122 | } 123 | } 124 | 125 | private void SetUpInputs() 126 | { 127 | //Get all new inputs. 128 | 129 | List inps = new List(); 130 | List inpNames = new List(); 131 | List inpDefaultVals = new List(); 132 | 133 | int varI = 1; 134 | while (Expr.Contains("$" + varI.ToString())) 135 | { 136 | inps.Add(new NodeInput(0.0f)); 137 | inpNames.Add("In" + varI.ToString()); 138 | inpDefaultVals.Add(0.0f); 139 | 140 | varI += 1; 141 | } 142 | 143 | //If any old inputs are left, use their values. 144 | for (int i = 0; i < inps.Count && i < Inputs.Count; ++i) 145 | inps[i] = Inputs[i]; 146 | 147 | Inputs = inps; 148 | InputNames = inpNames; 149 | InputDefaultVals = inpDefaultVals; 150 | } 151 | 152 | 153 | //Serialization: 154 | public override void GetObjectData(SerializationInfo info, StreamingContext context) 155 | { 156 | base.GetObjectData(info, context); 157 | info.AddValue("Expr", Expr); 158 | info.AddValue("IsLongForm", IsLongForm); 159 | } 160 | public CustomExprNode(SerializationInfo info, StreamingContext context) 161 | : base(info, context) 162 | { 163 | Expr = info.GetString("Expr"); 164 | IsLongForm = info.GetBoolean("IsLongForm"); 165 | } 166 | } 167 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/CustomExprNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5b21b8e29c6116143b94884d1064aee1 3 | timeCreated: 1470464779 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/NoiseNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6caff9540984aba4a9c475a39810906a 3 | timeCreated: 1457245395 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/ParamNode_Float.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using UnityEngine; 7 | using UnityEditor; 8 | 9 | 10 | namespace GPUGraph 11 | { 12 | [Serializable] 13 | public struct FloatParamInfo 14 | { 15 | public string Name; 16 | 17 | public bool IsSlider; 18 | public float SliderMin, SliderMax; 19 | 20 | /// 21 | /// If this parameter is a slider, this is actually the t value (between 0 and 1). 22 | /// 23 | public float DefaultValue; 24 | 25 | 26 | public FloatParamInfo(string name, float defaultVal = 0.0f) 27 | { 28 | Name = name; 29 | DefaultValue = defaultVal; 30 | IsSlider = false; 31 | SliderMin = 0.0f; 32 | SliderMax = 1.0f; 33 | } 34 | public FloatParamInfo(string name, float sliderMin, float sliderMax, float currentValue) 35 | { 36 | Name = name; 37 | 38 | IsSlider = true; 39 | SliderMin = sliderMin; 40 | SliderMax = sliderMax; 41 | 42 | DefaultValue = 0.0f; 43 | } 44 | 45 | public FloatParamInfo(FloatParamInfo original, float newDefaultVal) 46 | { 47 | Name = original.Name; 48 | IsSlider = original.IsSlider; 49 | SliderMin = original.SliderMin; 50 | SliderMax = original.SliderMax; 51 | DefaultValue = newDefaultVal; 52 | } 53 | public FloatParamInfo(FloatParamInfo original, string newName) 54 | { 55 | Name = newName; 56 | IsSlider = original.IsSlider; 57 | SliderMin = original.SliderMin; 58 | SliderMax = original.SliderMax; 59 | DefaultValue = original.DefaultValue; 60 | } 61 | } 62 | 63 | 64 | /// 65 | /// A node whose output is the value of a shader parameter. 66 | /// 67 | [Serializable] 68 | public class ParamNode_Float : Node 69 | { 70 | public FloatParamInfo Param; 71 | 72 | 73 | public override Color GUIColor { get { return new Color(0.85f, 1.0f, 1.0f); } } 74 | public override string OutputName { get { return Param.Name; } } 75 | public override string PrettyName { get { return "Scalar Param"; } } 76 | 77 | 78 | public ParamNode_Float(Rect pos, FloatParamInfo param) 79 | : base(pos, new List(), new List(), new List()) 80 | { 81 | Param = param; 82 | } 83 | private ParamNode_Float() { } 84 | 85 | 86 | protected override Node MakeClone() 87 | { 88 | ParamNode_Float fl = new ParamNode_Float(); 89 | fl.Param = Param; 90 | return fl; 91 | } 92 | 93 | public override void EmitProperties(StringBuilder outCode) 94 | { 95 | outCode.Append("\t\t\t"); 96 | outCode.Append(Param.Name); 97 | outCode.Append(" (\""); 98 | outCode.Append(StringUtils.PrettifyVarName(Param.Name)); 99 | outCode.Append("\", "); 100 | if (Param.IsSlider) 101 | { 102 | outCode.Append("Range("); 103 | outCode.Append(Param.SliderMin); 104 | outCode.Append(", "); 105 | outCode.Append(Param.SliderMax); 106 | outCode.Append(")) = "); 107 | outCode.Append(Mathf.Lerp(Param.SliderMin, Param.SliderMax, 108 | Param.DefaultValue).ToCodeString()); 109 | } 110 | else 111 | { 112 | outCode.Append("Float) = "); 113 | outCode.Append(Param.DefaultValue); 114 | } 115 | outCode.AppendLine(); 116 | } 117 | public override void EmitDefs(StringBuilder outCode) 118 | { 119 | outCode.Append("\t\t\t\tfloat "); 120 | outCode.Append(Param.Name); 121 | outCode.AppendLine(";"); 122 | } 123 | 124 | protected override bool CustomGUI() 125 | { 126 | string _name = Param.Name; 127 | float _defVal = Param.DefaultValue; 128 | bool _isSlider = Param.IsSlider; 129 | float _min = Param.SliderMin; 130 | float _max = Param.SliderMax; 131 | 132 | Param.Name = GUILayout.TextField(Param.Name); 133 | 134 | if (Param.IsSlider) 135 | { 136 | GUILayout.BeginHorizontal(); 137 | GUILayout.Label("Min:"); 138 | Param.SliderMin = EditorGUILayout.FloatField(Param.SliderMin); 139 | GUILayout.EndHorizontal(); 140 | 141 | GUILayout.BeginHorizontal(); 142 | GUILayout.Label("Max:"); 143 | Param.SliderMax = EditorGUILayout.FloatField(Param.SliderMax); 144 | GUILayout.EndHorizontal(); 145 | 146 | GUILayout.BeginHorizontal(); 147 | GUILayout.Label("Default value:"); 148 | Param.DefaultValue = Mathf.InverseLerp(Param.SliderMin, Param.SliderMax, 149 | GUILayout.HorizontalSlider(Mathf.Lerp(Param.SliderMin, 150 | Param.SliderMax, 151 | Param.DefaultValue), 152 | Param.SliderMin, 153 | Param.SliderMax, 154 | GUILayout.ExpandWidth(true))); 155 | GUILayout.EndHorizontal(); 156 | 157 | Param.IsSlider = !GUILayout.Button("Remove slider"); 158 | } 159 | else 160 | { 161 | GUILayout.BeginHorizontal(); 162 | GUILayout.Label("Default value:"); 163 | Param.DefaultValue = EditorGUILayout.FloatField(Param.DefaultValue); 164 | GUILayout.EndHorizontal(); 165 | 166 | Param.IsSlider = GUILayout.Button("Make slider"); 167 | } 168 | 169 | return Param.Name != _name || 170 | AreFloatsDifferent(Param.DefaultValue, _defVal) || 171 | _isSlider != Param.IsSlider || 172 | AreFloatsDifferent(_min, Param.SliderMin) || 173 | AreFloatsDifferent(_max, Param.SliderMax); 174 | } 175 | 176 | 177 | public override void GetObjectData(SerializationInfo info, StreamingContext context) 178 | { 179 | base.GetObjectData(info, context); 180 | 181 | info.AddValue("VarName", Param.Name); 182 | info.AddValue("DefaultVal", Param.DefaultValue); 183 | info.AddValue("IsSlider", Param.IsSlider); 184 | if (Param.IsSlider) 185 | { 186 | info.AddValue("SliderMin", Param.SliderMin); 187 | info.AddValue("SliderMax", Param.SliderMax); 188 | } 189 | } 190 | public ParamNode_Float(SerializationInfo info, StreamingContext context) 191 | : base(info, context) 192 | { 193 | Param.Name = info.GetString("VarName"); 194 | Param.DefaultValue = info.GetSingle("DefaultVal"); 195 | Param.IsSlider = info.GetBoolean("IsSlider"); 196 | if (Param.IsSlider) 197 | { 198 | Param.SliderMin = info.GetSingle("SliderMin"); 199 | Param.SliderMax = info.GetSingle("SliderMax"); 200 | } 201 | } 202 | } 203 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/ParamNode_Float.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 280324585b96bc949945badd5f058980 3 | timeCreated: 1457245395 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/ParamNode_Texture2D.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using UnityEngine; 7 | using UnityEditor; 8 | 9 | 10 | namespace GPUGraph 11 | { 12 | [Serializable] 13 | public struct Texture2DParamInfo 14 | { 15 | public string Name; 16 | public Texture2D DefaultVal; 17 | 18 | public Texture2DParamInfo(string name, Texture2D defaultVal = null) { Name = name; DefaultVal = defaultVal; } 19 | } 20 | 21 | 22 | /// 23 | /// A node whose output is the Red component of a 2D texture. 24 | /// 25 | [Serializable] 26 | public class ParamNode_Texture2D : Node 27 | { 28 | private static List startInputs = new List() 29 | { 30 | new NodeInput(float.NaN), new NodeInput(float.NaN), 31 | new NodeInput(1.0f), new NodeInput(1.0f), 32 | new NodeInput(0.0f), new NodeInput(0.0f), 33 | }; 34 | private static List startInputNames = new List() 35 | { 36 | "x", "y", "Scale X", "Scale Y", "Offset X", "Offset Y", 37 | }; 38 | private static List startInputDefaultVals = new List() 39 | { 40 | float.NaN, float.NaN, 1.0f, 1.0f, 0.0f, 0.0f, 41 | }; 42 | 43 | 44 | public Texture2DParamInfo Param; 45 | 46 | 47 | public override Color GUIColor { get { return new Color(0.85f, 1.0f, 0.85f); } } 48 | public override string PrettyName { get { return "2D Texture Parameter"; } } 49 | 50 | 51 | public ParamNode_Texture2D(Rect pos, Texture2DParamInfo param) 52 | : base(pos, startInputs, startInputNames, startInputDefaultVals) 53 | { 54 | Param = param; 55 | } 56 | private ParamNode_Texture2D() { } 57 | 58 | 59 | protected override Node MakeClone() 60 | { 61 | ParamNode_Texture2D tx = new ParamNode_Texture2D(); 62 | tx.Param = Param; 63 | return tx; 64 | } 65 | 66 | public override void EmitProperties(StringBuilder outCode) 67 | { 68 | outCode.Append("\t\t\t"); 69 | outCode.Append(Param.Name); 70 | outCode.Append(" (\""); 71 | outCode.Append(StringUtils.PrettifyVarName(Param.Name)); 72 | outCode.Append("\", 2D) = \"\" {}"); 73 | } 74 | public override void EmitDefs(StringBuilder outCode) 75 | { 76 | outCode.Append("\t\t\t\tsampler2D "); 77 | outCode.Append(Param.Name); 78 | outCode.AppendLine(";"); 79 | } 80 | public override void EmitCode(StringBuilder outCode) 81 | { 82 | outCode.Append("float "); 83 | outCode.Append(OutputName); 84 | outCode.Append(" = tex2D("); 85 | outCode.Append(Param.Name); 86 | outCode.Append(", (float2("); 87 | outCode.Append(Inputs[0].GetExpression(Owner)); 88 | outCode.Append(", "); 89 | outCode.Append(Inputs[1].GetExpression(Owner)); 90 | outCode.Append(") * float2("); 91 | outCode.Append(Inputs[2].GetExpression(Owner)); 92 | outCode.Append(", "); 93 | outCode.Append(Inputs[3].GetExpression(Owner)); 94 | outCode.Append(")) + float2("); 95 | outCode.Append(Inputs[4].GetExpression(Owner)); 96 | outCode.Append(", "); 97 | outCode.Append(Inputs[5].GetExpression(Owner)); 98 | outCode.AppendLine(")).r;"); 99 | } 100 | 101 | protected override bool CustomGUI() 102 | { 103 | string _name = Param.Name; 104 | Texture2D _defVal = Param.DefaultVal; 105 | 106 | Param.Name = GUILayout.TextField(Param.Name); 107 | Param.DefaultVal = (Texture2D)EditorGUILayout.ObjectField("Default value:", Param.DefaultVal, 108 | typeof(Texture2D), false); 109 | if (Param.DefaultVal != _defVal) 110 | { 111 | string newPath = AssetDatabase.GetAssetPath(Param.DefaultVal); 112 | if (newPath == "Resources/unity_builtin_extra" || 113 | newPath == "Resources\\unity_builtin_extra") 114 | { 115 | Debug.LogWarning("Built-in Unity textures cannot be used as Tex2D parameter default values!"); 116 | } 117 | } 118 | 119 | return Param.DefaultVal != _defVal || 120 | _name != Param.Name; 121 | } 122 | 123 | 124 | public override void GetObjectData(SerializationInfo info, StreamingContext context) 125 | { 126 | base.GetObjectData(info, context); 127 | info.AddValue("VarName", Param.Name); 128 | info.AddValue("DefaultVal", AssetDatabase.GetAssetPath(Param.DefaultVal)); 129 | } 130 | public ParamNode_Texture2D(SerializationInfo info, StreamingContext context) 131 | : base(info, context) 132 | { 133 | Param.Name = info.GetString("VarName"); 134 | 135 | string path = info.GetString("DefaultVal"); 136 | Param.DefaultVal = AssetDatabase.LoadAssetAtPath(path); 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/ParamNode_Texture2D.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bec723d81731a45448732c39ffa6a906 3 | timeCreated: 1457245395 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/SimpleNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using UnityEngine; 7 | using UnityEditor; 8 | 9 | 10 | namespace GPUGraph 11 | { 12 | /// 13 | /// A node whose output can be expressed as a single expression like "sin(x)" or "a + b". 14 | /// 15 | [Serializable] 16 | public class SimpleNode : Node 17 | { 18 | public struct Param 19 | { 20 | public string Name; 21 | public float DefaultValue; 22 | 23 | public Param(string name, float defaultVal = float.NaN) 24 | { 25 | Name = name; 26 | DefaultValue = defaultVal; 27 | } 28 | } 29 | 30 | 31 | public string Expr, Name; 32 | 33 | 34 | public override string PrettyName 35 | { 36 | get { return Name; } 37 | } 38 | 39 | 40 | /// 41 | /// Creates a new node that calls a function with a constant number of inputs. 42 | /// 43 | /// 44 | /// An expression using the given inputs. 45 | /// NOTE: in the expression, an input should be surrounded by apostrophes 46 | /// to distinguish it from the rest of the code. 47 | /// 48 | /// The inputs used by the given expression. 49 | public SimpleNode(Rect pos, string expr, string name, params Param[] inputs) 50 | : base(pos, 51 | inputs.Select(p => new NodeInput(p.DefaultValue)).ToList(), 52 | inputs.Select(p => p.Name).ToList(), 53 | inputs.Select(p => p.DefaultValue).ToList()) 54 | { 55 | Expr = expr; 56 | Name = name; 57 | } 58 | 59 | private SimpleNode(string expr, string name) { Expr = expr; Name = name; } 60 | 61 | 62 | protected override Node MakeClone() 63 | { 64 | return new SimpleNode(Expr, Name); 65 | } 66 | 67 | public override void EmitCode(StringBuilder outCode) 68 | { 69 | outCode.Append("float "); 70 | outCode.Append(OutputName); 71 | outCode.Append(" = ("); 72 | string expr = Expr; 73 | for (int i = 0; i < Inputs.Count; ++i) 74 | expr = expr.Replace("'" + GetInputName(i) + "'", Inputs[i].GetExpression(Owner)); 75 | outCode.Append(expr); 76 | outCode.AppendLine(");"); 77 | } 78 | 79 | 80 | public override void GetObjectData(SerializationInfo info, StreamingContext context) 81 | { 82 | base.GetObjectData(info, context); 83 | info.AddValue("Expression", Expr); 84 | info.AddValue("MyName", Name); 85 | } 86 | public SimpleNode(SerializationInfo info, StreamingContext context) 87 | : base(info, context) 88 | { 89 | Expr = info.GetString("Expression"); 90 | Name = info.GetString("MyName"); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/SimpleNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fc049a7f555d98145aaefecdb0006d7f 3 | timeCreated: 1457245396 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/SubGraphNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.Serialization; 5 | using System.Text; 6 | using UnityEngine; 7 | using UnityEditor; 8 | 9 | 10 | namespace GPUGraph 11 | { 12 | [Serializable] 13 | public class SubGraphNode : Node 14 | { 15 | public string GraphGUID = null; 16 | 17 | 18 | private List guids = null; 19 | private string[] names = null; 20 | private int selected = -1; 21 | private bool convertParamsToInputs = true; 22 | 23 | 24 | private string ThisGraphGUID 25 | { 26 | get 27 | { 28 | return AssetDatabase.AssetPathToGUID(StringUtils.GetRelativePath(Owner.FilePath, 29 | "Assets")); 30 | } 31 | } 32 | 33 | private void UpdateNameArray() 34 | { 35 | names = guids 36 | .Select(g => AssetDatabase.GUIDToAssetPath(g)) 37 | .Select(p => System.IO.Path.GetFileNameWithoutExtension(p)) 38 | .ToArray(); 39 | } 40 | private void UpdateGraphPaths() 41 | { 42 | guids = GraphEditorUtils.GetAllGraphsInProject(null, true) 43 | .Select(p => AssetDatabase.AssetPathToGUID(p)) 44 | .ToList(); 45 | //Remove this graph from the list of possible selections. 46 | if (Owner != null) 47 | { 48 | string thisGraphGUID = ThisGraphGUID; 49 | int i = (Owner == null ? -1 : guids.IndexOf(g => (g == thisGraphGUID))); 50 | if (i >= 0) 51 | { 52 | guids.RemoveAt(i); 53 | } 54 | } 55 | 56 | UpdateNameArray(); 57 | } 58 | 59 | private Graph TryLoadGraph() 60 | { 61 | Graph g = new Graph(GraphGUID, true); 62 | string err = g.Load(); 63 | if (err.Length > 0) 64 | { 65 | Debug.LogError("Error opening graph " + g.FilePath + ": " + err); 66 | return null; 67 | } 68 | else 69 | { 70 | return g; 71 | } 72 | } 73 | 74 | 75 | public override Color GUIColor { get { return new Color(1.0f, 0.85f, 0.85f); } } 76 | 77 | public override string PrettyName 78 | { 79 | get 80 | { 81 | return "Sub-Graph: " + 82 | System.IO.Path.GetFileNameWithoutExtension(AssetDatabase.GUIDToAssetPath(GraphGUID)); 83 | } 84 | } 85 | 86 | 87 | public SubGraphNode(Rect pos) 88 | : base(pos, new List(), new List(), new List()) { } 89 | private SubGraphNode() { } 90 | 91 | 92 | public override void OnGraphLoaded() 93 | { 94 | CheckOutGraphs(true); 95 | } 96 | public override void OnAddedToGraph() 97 | { 98 | CheckOutGraphs(false); 99 | } 100 | 101 | /// 102 | /// Refreshes the list of graphs and makes sure this node is still valid. 103 | /// Returns whether anything changed. 104 | /// 105 | private bool CheckOutGraphs(bool warnIfNotFound) 106 | { 107 | UpdateGraphPaths(); 108 | 109 | //See if the current sub-graph being used still exists. 110 | selected = guids.IndexOf(GraphGUID); 111 | if (selected >= 0) 112 | { 113 | Graph g = TryLoadGraph(); 114 | if (g == null) 115 | { 116 | selected = -1; 117 | ChangeGraph(); 118 | return true; 119 | } 120 | else 121 | { 122 | //See if the number of inputs changed. 123 | GraphParamCollection gParams = new GraphParamCollection(g); 124 | if (convertParamsToInputs && Inputs.Count != gParams.FloatParams.Count) 125 | { 126 | SetInputsFrom(gParams.FloatParams); 127 | return true; 128 | } 129 | } 130 | } 131 | else 132 | { 133 | //Couldn't find the sub-graph anymore! 134 | if (warnIfNotFound) 135 | { 136 | Debug.LogWarning("Couldn't find sub-graph at " + 137 | AssetDatabase.GUIDToAssetPath(GraphGUID)); 138 | } 139 | selected = -1; 140 | ChangeGraph(); 141 | return true; 142 | } 143 | 144 | return false; 145 | } 146 | 147 | /// 148 | /// Updates this node based on the value of "selected". 149 | /// 150 | private void ChangeGraph() 151 | { 152 | if (selected < 0) 153 | { 154 | GraphGUID = null; 155 | Inputs = new List(); 156 | InputNames = new List(); 157 | InputDefaultVals = new List(); 158 | } 159 | else 160 | { 161 | GraphGUID = guids[selected]; 162 | 163 | Graph g = TryLoadGraph(); 164 | if (g != null) 165 | { 166 | if (convertParamsToInputs) 167 | { 168 | SetInputsFrom(new GraphParamCollection(g).FloatParams); 169 | } 170 | else 171 | { 172 | Inputs.Clear(); 173 | InputNames.Clear(); 174 | InputDefaultVals.Clear(); 175 | } 176 | } 177 | 178 | UpdateGraphPaths(); 179 | selected = guids.IndexOf(GraphGUID); 180 | } 181 | } 182 | 183 | 184 | protected override Node MakeClone() 185 | { 186 | SubGraphNode sgn = new SubGraphNode(); 187 | sgn.GraphGUID = GraphGUID; 188 | sgn.guids = guids.ToList(); 189 | sgn.names = names.ToArray(); 190 | sgn.convertParamsToInputs = convertParamsToInputs; 191 | sgn.selected = selected; 192 | return sgn; 193 | } 194 | 195 | public override IEnumerable OnPreProcess() 196 | { 197 | //Don't do anything if this node isn't valid. 198 | if (selected < 0) 199 | return new List(); 200 | 201 | 202 | //Load the sub-graph. 203 | Graph g = TryLoadGraph(); 204 | if (g == null) 205 | { 206 | return new List(); 207 | } 208 | 209 | //Clone the sub-graph's nodes. 210 | List floatParams = new List(); 211 | List newNodes = new List(g.Nodes.Select(n => n.Clone())); 212 | 213 | //Add the new nodes to the graph, with new UID's. 214 | //Keep track of the float param nodes because they map to this node's inputs. 215 | int baseUID = Owner.NextUID; 216 | Owner.NextUID += newNodes.Count; 217 | foreach (Node n in newNodes) 218 | { 219 | //Offset all the UID's so there's no conflicts with the rest of the graph. 220 | n.UID = baseUID + n.UID; 221 | Owner.NextUID = Mathf.Max(Owner.NextUID, n.UID + 1); 222 | for (int i = 0; i < n.Inputs.Count; ++i) 223 | if (!n.Inputs[i].IsAConstant) 224 | n.Inputs[i] = new NodeInput(n.Inputs[i].NodeID + baseUID); 225 | 226 | Owner.AddNode(n, false); 227 | 228 | //If this node is another sub-graph, make sure there's no infinite loop. 229 | if (convertParamsToInputs && n is ParamNode_Float) 230 | { 231 | floatParams.Add((ParamNode_Float)n); 232 | } 233 | } 234 | 235 | //Error-checking. 236 | if (floatParams.Count != Inputs.Count) 237 | { 238 | Debug.LogError("Expected " + Inputs.Count + " float params in the graph but found " + 239 | floatParams.Count); 240 | return new List(); 241 | } 242 | 243 | //Sort the float params so they line up with this node's inputs. 244 | { 245 | List sortedFloatParams = new List(); 246 | for (int i = 0; i < InputNames.Count; ++i) 247 | { 248 | for (int j = 0; j < floatParams.Count; ++j) 249 | { 250 | if (floatParams[j].Param.Name == InputNames[i]) 251 | { 252 | sortedFloatParams.Add(floatParams[j]); 253 | break; 254 | } 255 | } 256 | if (sortedFloatParams.Count <= i) 257 | { 258 | Debug.LogError("This sub-graph had an unnecessary input \"" + 259 | InputNames[i] + "\""); 260 | } 261 | } 262 | floatParams = sortedFloatParams; 263 | } 264 | 265 | //Replace all references to those float params with this node's inputs. 266 | foreach (Node n in newNodes) 267 | { 268 | for (int i = 0; i < n.Inputs.Count; ++i) 269 | { 270 | for (int j = 0; j < floatParams.Count; ++j) 271 | { 272 | if (!n.Inputs[i].IsAConstant && n.Inputs[i].NodeID == floatParams[j].UID) 273 | { 274 | n.Inputs[i] = Inputs[j]; 275 | } 276 | } 277 | } 278 | } 279 | 280 | //Remove the float params. 281 | foreach (Node n in floatParams) 282 | Owner.RemoveNode(n); 283 | 284 | //Replace any references to this node with references to the output of the sub-graph. 285 | NodeInput gOut = (g.Output.IsAConstant ? 286 | g.Output : 287 | new NodeInput(g.Output.NodeID + baseUID)); 288 | if (!Owner.Output.IsAConstant && Owner.Output.NodeID == UID) 289 | Owner.Output = gOut; 290 | foreach (Node nd in Owner.Nodes) 291 | for (int i = 0; i < nd.Inputs.Count; ++i) 292 | if (!nd.Inputs[i].IsAConstant && nd.Inputs[i].NodeID == UID) 293 | nd.Inputs[i] = gOut; 294 | 295 | //Finally, remove this node. 296 | Owner.RemoveNode(this); 297 | 298 | return newNodes; 299 | } 300 | 301 | protected override bool CustomGUI() 302 | { 303 | bool changed = false; 304 | 305 | { 306 | bool oldConverted = convertParamsToInputs; 307 | convertParamsToInputs = GUILayout.Toggle(convertParamsToInputs, "Convert params to inputs"); 308 | if (oldConverted && !convertParamsToInputs) 309 | { 310 | changed = true; 311 | Inputs.Clear(); 312 | InputNames.Clear(); 313 | InputDefaultVals.Clear(); 314 | } 315 | else if (!oldConverted && convertParamsToInputs) 316 | { 317 | changed = true; 318 | Graph g = TryLoadGraph(); 319 | if (g == null) 320 | { 321 | convertParamsToInputs = false; 322 | } 323 | else 324 | { 325 | SetInputsFrom(new GraphParamCollection(g).FloatParams); 326 | } 327 | } 328 | } 329 | 330 | Vector2 textDims = GUI.skin.label.CalcSize(new GUIContent("Graph:")); 331 | EditorGUIUtility.labelWidth = textDims.x; 332 | int newIndex = EditorGUILayout.Popup("Graph:", selected, names, GUILayout.MinWidth(100.0f)); 333 | 334 | if (selected != newIndex) 335 | { 336 | selected = newIndex; 337 | ChangeGraph(); 338 | changed = true; 339 | } 340 | 341 | if (GUILayout.Button("Refresh graphs")) 342 | { 343 | changed = CheckOutGraphs(true) || changed; 344 | } 345 | 346 | return changed; 347 | } 348 | 349 | public override void EmitCode(StringBuilder outCode) 350 | { 351 | //This should only be called if there was an error when pre-processing. 352 | outCode.Append("float "); 353 | outCode.Append(OutputName); 354 | outCode.AppendLine(" = 0.0; //ERROR"); 355 | } 356 | 357 | private void SetInputsFrom(List floatParams) 358 | { 359 | Inputs = floatParams.Select(fn => 360 | { 361 | return new NodeInput(fn.IsSlider ? 362 | Mathf.Lerp(fn.SliderMin, fn.SliderMax, fn.DefaultValue) : 363 | fn.DefaultValue); 364 | }).ToList(); 365 | 366 | InputNames = floatParams.Select(fn => fn.Name).ToList(); 367 | 368 | InputDefaultVals = floatParams.Select(fn => 369 | { 370 | return (fn.IsSlider ? 371 | Mathf.Lerp(fn.SliderMin, fn.SliderMax, fn.DefaultValue) : 372 | fn.DefaultValue); 373 | }).ToList(); 374 | } 375 | 376 | 377 | public override void GetObjectData(SerializationInfo info, StreamingContext context) 378 | { 379 | base.GetObjectData(info, context); 380 | info.AddValue("GraphGUID", GraphGUID); 381 | info.AddValue("ConvertParamsToInputs", convertParamsToInputs); 382 | } 383 | public SubGraphNode(SerializationInfo info, StreamingContext context) 384 | : base(info, context) 385 | { 386 | convertParamsToInputs = info.GetBoolean("ConvertParamsToInputs"); 387 | 388 | GraphGUID = info.GetString("GraphGUID"); 389 | UpdateGraphPaths(); 390 | selected = guids.IndexOf(GraphGUID); 391 | } 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/SubGraphNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8631bcf8d006b694aa0847dd64950195 3 | timeCreated: 1457245422 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/TexCoordNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using UnityEngine; 7 | using UnityEditor; 8 | 9 | 10 | namespace GPUGraph 11 | { 12 | /// 13 | /// A node whose output is the X or Y value of the UV. 14 | /// 15 | [Serializable] 16 | public class TexCoordNode : Node 17 | { 18 | /// 19 | /// 0 for X, 1 for Y, 2 for Z. 20 | /// Z is a special index that is only used for generating 3D textures. 21 | /// 22 | public byte Index; 23 | private static readonly string[] indexChars = { "X", "Y", "Z" }; 24 | 25 | 26 | public override Color GUIColor { get { return new Color(0.85f, 0.85f, 1.0f); } } 27 | public override string OutputName 28 | { 29 | get 30 | { 31 | if (Index == 2) 32 | return GraphUtils.Param_UVz; 33 | else 34 | return "IN.texcoord." + indexChars[Index].ToLower(); 35 | } 36 | } 37 | public override string PrettyName { get { return "UV " + indexChars[Index]; } } 38 | 39 | 40 | /// 41 | /// Creates a new instance. 42 | /// 43 | /// 0 for X, 1 for Y, 2 for Z. 44 | public TexCoordNode(Rect pos, byte index) 45 | : base(pos, new List(), new List(), new List()) 46 | { 47 | Index = index; 48 | } 49 | private TexCoordNode(byte index) { Index = index; } 50 | 51 | 52 | protected override Node MakeClone() 53 | { 54 | return new TexCoordNode(Index); 55 | } 56 | 57 | protected override bool CustomGUI() 58 | { 59 | byte oldIndex = Index; 60 | Index = (byte)EditorGUILayout.Popup(Index, indexChars); 61 | return oldIndex != Index; 62 | } 63 | public override void EmitProperties(StringBuilder outCode) 64 | { 65 | //Don't emit the same property twice! 66 | if (!outCode.ToString().Contains(GraphUtils.Param_UVz)) 67 | { 68 | outCode.Append('\t'); 69 | outCode.Append(GraphUtils.Param_UVz); 70 | outCode.AppendLine(" (\"UV z\", Float) = 0.0"); 71 | } 72 | } 73 | public override void EmitDefs(StringBuilder outCode) 74 | { 75 | //Don't emit the same uniform twice! 76 | string def = "float " + GraphUtils.Param_UVz; 77 | if (!outCode.ToString().Contains(def)) 78 | { 79 | outCode.Append(def); 80 | outCode.AppendLine(";"); 81 | } 82 | } 83 | 84 | public override void GetObjectData(SerializationInfo info, StreamingContext context) 85 | { 86 | base.GetObjectData(info, context); 87 | info.AddValue("Index", Index); 88 | } 89 | public TexCoordNode(SerializationInfo info, StreamingContext context) 90 | : base(info, context) 91 | { 92 | //Older versions of graph files used a "IsX" bool to choose between X and Y. 93 | //Newer versions that also support Z use the "Index" byte. 94 | 95 | foreach (SerializationEntry entry in info) 96 | { 97 | switch (entry.Name) 98 | { 99 | case "Index": 100 | Index = (byte)entry.Value; 101 | break; 102 | 103 | case "IsX": 104 | Index = (bool)entry.Value ? (byte)1 : (byte)0; 105 | break; 106 | } 107 | } 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/Nodes/TexCoordNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aade750250d58604fa5917f3f09d93f8 3 | timeCreated: 1457245395 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/Graph System/ShaderDefs.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5cf19a0757bac344dbfef61ad9b7bbb5 3 | timeCreated: 1457244725 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/RunTimeGraphEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a15ea1383b024f74f94dfbd65d489844 3 | timeCreated: 1468892831 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/StringUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Path = System.IO.Path; 3 | using System.Text; 4 | 5 | 6 | /// 7 | /// Some extra helper methods to complement the Path class. 8 | /// 9 | public static class StringUtils 10 | { 11 | /// 12 | /// Turns the given full path into a relative one starting just above the given directory. 13 | /// For example, "GetRelativePath("C:/A/B/C", "B")" returns "B/C". 14 | /// Returns "null" if the given folder can't be found. 15 | /// 16 | /// 17 | /// As a side effect, all '/' or '\' slashes will be changed 18 | /// to the correct directory separator char for this platform. 19 | /// 20 | /// 21 | /// The folder that will appear at the top of the returned path. 22 | /// 23 | public static string GetRelativePath(string fullPath, string startFolder) 24 | { 25 | StringBuilder sb = new StringBuilder(fullPath); 26 | if ('/' != Path.DirectorySeparatorChar) 27 | { 28 | sb.Replace('/', Path.DirectorySeparatorChar); 29 | } 30 | if ('\\' != Path.DirectorySeparatorChar) 31 | { 32 | sb.Replace('\\', Path.DirectorySeparatorChar); 33 | } 34 | 35 | //Get the start of the given folder in the path string. 36 | int folderLoc = sb.ToString().IndexOf(Path.DirectorySeparatorChar + 37 | startFolder + 38 | Path.DirectorySeparatorChar); 39 | if (folderLoc < 0 && sb.ToString().StartsWith(startFolder + Path.DirectorySeparatorChar)) 40 | { 41 | folderLoc = 0; 42 | } 43 | 44 | //If the given folder was found, cut out everything before that. 45 | if (folderLoc >= 0) 46 | { 47 | sb.Remove(0, folderLoc); 48 | if (sb[0] == Path.DirectorySeparatorChar) 49 | sb.Remove(0, 1); 50 | return sb.ToString(); 51 | } 52 | else 53 | { 54 | return null; 55 | } 56 | } 57 | 58 | /// 59 | /// Replaces all directory separators with the correct one for the current platform (either / or \). 60 | /// 61 | public static string FixDirectorySeparators(string path) 62 | { 63 | StringBuilder sb = new StringBuilder(path); 64 | sb.Replace('/', Path.DirectorySeparatorChar); 65 | sb.Replace('\\', Path.DirectorySeparatorChar); 66 | return sb.ToString(); 67 | } 68 | 69 | /// 70 | /// If the given string ends in a number, increments that number. 71 | /// Otherwise, appends a "2" to it. 72 | /// 73 | public static string IncrementNumberPostfix(string str) 74 | { 75 | StringBuilder number = new StringBuilder(); 76 | int i; 77 | for (i = str.Length - 1; i >= 0; --i) 78 | { 79 | if (str[i] < '0' || str[i] > '9') 80 | break; 81 | number.Append(str[i]); 82 | } 83 | 84 | if (number.Length == 0) 85 | return str + "2"; 86 | else 87 | return str.Substring(0, i + 1) + (int.Parse(number.ToString())).ToString(); 88 | } 89 | 90 | /// 91 | /// Turns the given variable name into a nice display name. 92 | /// 93 | public static string PrettifyVarName(string name) 94 | { 95 | StringBuilder sb = new StringBuilder(name); 96 | for (int i = 0; i < sb.Length; ++i) 97 | { 98 | if (sb[i] == '_') 99 | { 100 | sb[i] = ' '; 101 | 102 | //Make the next letter uppercase. 103 | if (i + 1 < sb.Length && sb[i + 1] >= 'a' && sb[i + 1] <= 'z') 104 | { 105 | sb[i + 1] -= (char)('a' - 'A'); 106 | } 107 | } 108 | } 109 | 110 | return sb.ToString().Trim(); 111 | } 112 | 113 | /// 114 | /// Finds the last instance of the given char and removes it 115 | /// along with everything that came before it. 116 | /// 117 | public static string RemoveEverythingBefore(this string str, char c) 118 | { 119 | int i = str.Length - 1; 120 | while (i >= 0 && str[i] != c) 121 | i -= 1; 122 | return str.Substring(i + 1, str.Length - i - 1); 123 | } 124 | 125 | /// 126 | /// Gets this float as a code-parseable string. 127 | /// In other words, if this float's default string representation is scientific notation, 128 | /// this method automatically fixes that. 129 | /// 130 | public static string ToCodeString(this float f) 131 | { 132 | string str = f.ToString(); 133 | 134 | int i = str.IndexOf("E"); 135 | if (i >= 0) 136 | { 137 | if (str[i + 1] == '-') 138 | { 139 | return "0.0"; 140 | } 141 | else 142 | { 143 | if (str[0] == '-') 144 | { 145 | return "-99999999999.0"; 146 | } 147 | else 148 | { 149 | return "9999999999.0"; 150 | } 151 | } 152 | } 153 | else 154 | { 155 | //Make sure it's parsed as a float value and not an integer. 156 | if (!str.Contains(".")) 157 | { 158 | return str + ".0"; 159 | } 160 | else 161 | { 162 | return str; 163 | } 164 | } 165 | } 166 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Editor/StringUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a545f7eb23b5bf142b9be1d780b42f33 3 | timeCreated: 1444281303 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/GpuRand.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5f458a0296be4104eb8a9442d84ef449 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/GpuRandWithState.cginc: -------------------------------------------------------------------------------- 1 | //A RNG system that behaves more like a CPU RNG library, 2 | // with global state that is modified each time some numbers are generated. 3 | //This isn't actually used by GPUGraph, but is provided as a utility for others. 4 | //The initial state is set by the float parameter "_Seed". 5 | 6 | //Based on: https://www.shadertoy.com/view/4djSRW 7 | //TODO: Test integer XORshift performance as an alternative to this float-hashing. 8 | 9 | //These values work best when the seed values are small, e.x. UVs. 10 | #define HASH_CONSTS float4(443.897, 441.423, 437.195, 444.129) 11 | #define HASH_OFFSET 19.19 12 | //These values work best when the seed values are large, e.x. world or pixel coordinates. 13 | /* 14 | #define HASH_CONSTS float4(1.031, .1030, .0973, .1099) 15 | #define HASH_OFFSET 19.19 16 | */ 17 | 18 | 19 | uniform float _Seed; 20 | static float Seed; 21 | 22 | void initRNG() { Seed = _Seed; } 23 | 24 | //The following functions incorporate multiple given floats 25 | // into the RNG system. 26 | //The floats are assumed to be small values (usually [0, 1]). 27 | //Values outside that range are fine, but may yield worse results. 28 | //Note that the current value of "Seed" still affects the result; 29 | // to completely reset the seed, just set "Seed" directly. 30 | void addRandSeed(float f) 31 | { 32 | float2 p2 = frac(float2(f, Seed) * HASH_CONSTS.x); 33 | p2 += dot(p2, p2.yx + HASH_OFFSET); 34 | Seed = frac((p2.x + p2.y) * p2.x); 35 | } 36 | void addRandSeed(float2 f) 37 | { 38 | float3 p3 = frac(float3(f, Seed) * HASH_CONSTS.x); 39 | p3 += dot(p3, p3.yzx + HASH_OFFSET); 40 | Seed = frac((p3.x + p3.y) * p3.z); 41 | } 42 | void addRandSeed(float3 f) 43 | { 44 | float4 p4 = frac(float4(f, Seed) * HASH_CONSTS.x); 45 | p4 += dot(p4, p4.wzyx + HASH_OFFSET); 46 | Seed = frac((p4.x + p4.y + p4.z) * p4.w); 47 | } 48 | 49 | 50 | //The following functions generate some amount of uniform random numbers between 0 and 1. 51 | float rand1() 52 | { 53 | float f = frac(Seed * HASH_CONSTS.x); 54 | f += f * (f + HASH_OFFSET); 55 | Seed = frac((f + f) * f); 56 | return Seed; 57 | } 58 | float2 rand2() 59 | { 60 | float3 f = frac(Seed * HASH_CONSTS.xyz); 61 | f += dot(f, f.yzx + HASH_OFFSET); 62 | float2 val = frac((f.xx + f.yz) * f.zy); 63 | Seed = val.x; 64 | return val; 65 | } 66 | float3 rand3() 67 | { 68 | float3 f = frac(Seed * HASH_CONSTS.xyz); 69 | f += dot(f, f.yzx + HASH_OFFSET); 70 | f = frac((f.xxy + f.yzz) * f.zyx); 71 | Seed = f.y; 72 | return f; 73 | } 74 | float4 rand4() 75 | { 76 | float4 f = frac(Seed * HASH_CONSTS); 77 | f += dot(f, f.wzxy + HASH_OFFSET); 78 | f = frac((f.xxyz + f.yzzw) * f.zywx); 79 | Seed = f.z; 80 | return f; 81 | } 82 | 83 | //The following functions generate 2 gaussian random numbers 84 | // using 2 uniform random numbers in the range [0, 1]. 85 | float2 randGaussian2(float2 randUniform2) 86 | { 87 | //Box-Muller method. 88 | 89 | const float epsilon = 0.000001, 90 | twoPi = (3.14159265359 * 2.0); 91 | 92 | float d1 = sqrt(-2.0 * log(randUniform2.x + epsilon)), 93 | d2 = twoPi * randUniform2.y; 94 | 95 | return float2(d1 * cos(d2), d1 * sin(d2)); 96 | } 97 | float2 randGaussian2(float2 randUniform2, float mean, float deviation) 98 | { 99 | return mean + (deviation * randGaussian2(randUniform2)); 100 | } 101 | float2 randGaussian2(float mean, float deviation) 102 | { 103 | return randGaussian2(rand2(), mean, deviation); 104 | } 105 | float2 randGaussian2() 106 | { 107 | return randGaussian2(rand2()); 108 | } 109 | 110 | //The following functions generate 1 gaussian random number 111 | // using 3 uniform random numbers in the range [0, 1]. 112 | float randGaussian1(float3 randUniform3) 113 | { 114 | //Box-Muller method. 115 | 116 | const float epsilon = 0.000001, 117 | twoPi = (3.14159265359 * 2.0); 118 | 119 | float d1 = sqrt(-2.0 * log(randUniform3.x + epsilon)), 120 | d2 = twoPi * randUniform3.y; 121 | 122 | return (randUniform3.z > 0.5) ? 123 | (d1 * cos(d2)) : 124 | (d1 * sin(d2)); 125 | } 126 | float randGaussian1(float3 randUniform3, float mean, float deviation) 127 | { 128 | return mean + (deviation * randGaussian1(randUniform3)); 129 | } 130 | float randGaussian1(float mean, float deviation) 131 | { 132 | return randGaussian1(rand3(), mean, deviation); 133 | } 134 | float1 randGaussian1() 135 | { 136 | return randGaussian1(rand3()); 137 | } 138 | 139 | 140 | //Generating a position on/in a sphere using uniform random numbers. 141 | //https://math.stackexchange.com/questions/87230/picking-random-points-in-the-volume-of-sphere-with-uniform-probability 142 | float3 posOnUnitSphere(float yPos01, float angle01) 143 | { 144 | float yPos = -1.0 + (2.0 * yPos01), 145 | angle = 3.14159265359 * 2.0 * angle01; 146 | float horizontalness = sqrt(1.0 - (yPos * yPos)); 147 | return float3(horizontalness * cos(angle), 148 | yPos, 149 | horizontalness * sin(angle)); 150 | } 151 | float3 randomPosOnUnitSphere() 152 | { 153 | float2 r2 = rand2(); 154 | return posOnUnitSphere(r2.x, r2.y); 155 | } 156 | float3 randomPosInUnitSphere() 157 | { 158 | //Note that a uniform random radius actually yields a non-uniform distribution. 159 | //To get a uniform distribution, we must take the cube root of a uniform value. 160 | float3 r3 = rand3(); 161 | return posOnUnitSphere(r3.x, r3.y) * pow(r3.z, 1.0/3.0); 162 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/GpuRandWithState.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 968dcac975b36e046a1e30c200fcb107 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 William Manning 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/LICENSE.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3931e5ea2c981ef499c534dea1ebe817 3 | timeCreated: 1470471234 4 | licenseType: Free 5 | TextScriptImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/GPUGraph/README.md: -------------------------------------------------------------------------------- 1 | # GPUGraph 2 | 3 | An open-source Unity plugin for generating coherent noise on the GPU, for both editor and runtime uses. The source is available [here](http://www.github.com/heyx3/GPUNoiseForUnity), on Github. It is also available on [the Asset Store](https://www.assetstore.unity3d.com/#!/content/68911). 4 | 5 | Editor tools for this plugin are available in the "Assets/GPU Graph" section on the Unity editor's toolbar. The *.unitypackage* file for this plugin is stored in the root of this repo: *GPUGraph.unitypackage*. 6 | 7 | 8 | # Overview 9 | 10 | This repo contains the GPUGraph plugin for Unity, which provides classes and editors for generating floating-point noise on the GPU with shaders. 11 | This leads to extremely fast noise generation compared to traditional CPU methods. 12 | 13 | Note that because Unity no longer supports runtime compilation of shaders, Graphs can only really be used in the editor. However, shaders can be generated from the graph in the editor then used in real-time (graphs can expose float and Tex2D parameters which are changeable at run-time). A serializable class "RuntimeGraph" is provided to greatly simplify use of run-time graphs; see "SampleScene.unity" and "SampleGPUGScript.cs" for an example of how to use it (note that you need to look at the SampleGPUGScript component in the Inspector to regenerate shaders before the scene will work). 14 | 15 | The basic structure behind GPUGraph is a "Directed Acyclic Graph" (essentially a tree whose nodes can have multiple parents) of commands that represents shader code. Every node in the graph takes some number of floats as inputs and outputs a single float as a result. 16 | 17 | Graphs are created in a custom editor window and saved as ".gpug" files into the "Assets" folder. The editor is accessed by selecting "Assets/GPU Graph/Editor" in the Unity editor's toolbar. Here is an example of a very simple graph that generates pure white noise: 18 | 19 | ![White Noise](https://github.com/heyx3/GPUNoiseForUnity/blob/master/Readme%20Images/WhiteNoise.png) 20 | 21 | A side utility is also provided for easy random number generation on the GPU: "Assets/GPUGraph/GpuRandWithState.cginc". 22 | 23 | 24 | # Editor 25 | 26 | In the above image, note the various aspects of the graph editor: 27 | 28 | * On the far left is a section for choosing nodes to place down in the graph. 29 | * To the right of that is a set of options for the graph, and for loading/creating other ones. 30 | * On the top of this "options" section is the specific graph file being edited. This dropdown box lists all the .gpug files in your Unity project. 31 | * Below the "New Graph", "Save Changes", and "Discard Changes" buttons is the preview window, which shows what would happen if you rendered your noise graph to a 2D texture. You can check the "Auto-Update Preview" box to automatically update the preview every time the graph is edited. 32 | * On the right side of the window, is the graph area. This displays all your nodes. The right-most node, "Output", represents the final output of the graph. You can right-click and drag to pan the area. 33 | 34 | In order to add a new node, click the button for the node you want to place, then left-click in the graph to place it. Right-click in the graph to cancel. A node's inputs are on the left side, and its output is on the right side. Note that some nodes have no inputs at all. Each input to a node is either the output of a different node or a constant value entered in a text box. 35 | 36 | You can add the basic arithmetic nodes by pressing their respective keys (`+`, `-`, `*`, and `/`). 37 | 38 | 39 | # Nodes 40 | 41 | All the nodes this plugin currently offers are listed here: 42 | 43 | * Noise: Exposes a variety of 1D, 2D, 3D, or 4D noise algorithms (all of which return a value between 0 and 1) with a scale/weight value for convenience when combining multiple octaves of noise. They can all optionally wrap around their edges so that the resulting noise tiles every 1 units. 44 | * White noise: a pseudo-random value. 45 | * Grid noise: Creates 1x1 square blocks of noise by getting White Noise for the `floor` of the seed value. 46 | * Linear noise: Like Grid noise but with a linear interpolation between values, yielding smooth diamond shapes instead of square blocks. 47 | * Smooth noise: Like Linear noise but smoother and a bit more expensive. 48 | * Smoother noise: Like Smooth noise but even smoother and a bit more expensive. 49 | * Perlin noise: Like Smooth noise but with fewer blocky artifacts, and much more expensive. 50 | * Worley noise: Generates a random point in every 1x1 block of space and outputs noise based on how far away the given value is from the nearest point. Note that Worley noise only tiles properly if the scale is a power of two. 51 | * UV: The X, Y, or Z coordinate (from 0 to 1) of the pixel in the render texture currently being generated. The Z coordinate is useful when generating 3D textures. It can also be thought of as a seed value for 2D noise. 52 | * Custom Expression: A custom HLSL expression with any number of inputs. 53 | * Float Parameter: A shader parameter that can be easily changed after the graph has been compiled into a Material. 54 | * Tex2D Parameter: A texture parameter that can be easily changed after the graph has been compiled into a Material. 55 | * Sub-graph: Represents the output of another graph file. 56 | * Ceil: rounds the input to the next largest integer. 57 | * Floor: rounds the input to the next smallest integer. 58 | * Truncate: gets the non-fractional part of an input. 59 | * Fract: gets the fractional part of an input. 60 | * RoundToInt: rounds the input to the nearest integer. 61 | * Sign: Returns -1 if the input is negative, 0 if it's zero, and +1 if it's positive. 62 | * Abs: Returns the absolute value of the input. 63 | * Cos: Returns the cosine of the input. 64 | * Sin: Returns the sine of the input. 65 | * Tan: Returns the tangent of the input. 66 | * Acos: Returns the inverse cosine of the input. 67 | * ASin: Returns the inverse sine of the input. 68 | * Atan: Returns the inverse tangent of the input. 69 | * Sqrt: Returns the square root of the input. 70 | * Log: Returns the logarithm base *e* of the input. 71 | * Add: Adds two inputs together. 72 | * Subtract: Subtracts the second input from the first. 73 | * Multiply: Multiplies two inputs together. 74 | * Divide: Divides the first input by the second. 75 | * Max: Gets the largest of two inputs. 76 | * Min: Gets the smallest of two inputs. 77 | * Pow: Raises the first input to the power of the second input. 78 | * Step: Returns 0 if the second input is less than the first one, or 1 if it is larger. 79 | * Atan2: A version of atan that takes the individual X and Y components. 80 | * Clamp: Forces the third input to be no smaller than the first one and no larger than the second. 81 | * Lerp: Linearly interpolates between the first and second inputs using the third input. 82 | * Smoothstep: Like `Lerp` but with a smooth, third-order curve instead of a line. 83 | * Remap: Remaps a value from the "source" min and max range to the "destination" min and max range. 84 | 85 | 86 | # Applications 87 | 88 | Several example applications are built into the editor; they are all accessible through the "Assets/GPU Graph" category in the Unity editor's toolbar. 89 | 90 | ## Shader Generator 91 | 92 | This tool generates a shader that outputs the graph's noise. You could then create a material that uses this shader and use it in the editor or at runtime to generate noise via the `GPUGraph.GraphUtils` and `GPUGraph.GraphEditorUtils` classes. Fortunately, a helper class `RuntimeGraph` has already been created to make this easier for you, complete with custom Inspector code, but this utility is still useful if you want to further mess with the shader after generating it. 93 | 94 | ## Texture 2D Generator 95 | 96 | This tool generates a 2D texture file using a graph. 97 | 98 | ## Texture 3D Generator 99 | 100 | This tool generates a 3D texture file (and, optionally, an accompanying normal texture) using a graph. 101 | 102 | ## Texture Generator 103 | 104 | This is the abstract base class for Texture2DGenerator and Texture3DGenerator. It provides the bulk of their GUI. 105 | 106 | 107 | ## Terrain Generator 108 | 109 | This tool uses a graph to generate a heightmap for whichever terrain object is currently selected in the scene view. 110 | 111 | 112 | # Code 113 | 114 | Code is organized in the following way inside the "GPU Noise" folder: 115 | 116 | * Runtime: Scripts for using graphs at run-time. Take a look at "SampleGPUGScript.cs" for an example of how to use these. 117 | * Editor: Scripts for using graphs in the editor. 118 | * **Graph System**: The code for representing/editing a graph. 119 | * **Nodes**: Specific kinds of nodes that can be placed in a graph. 120 | * **Editor**: The Unity editor window for creating/modifying graphs. 121 | * **Applications**: The above-metioned sample utilities: texture, shader, and terrain generators. 122 | 123 | ## Graph System 124 | 125 | *namespace: GPUGraph* 126 | 127 | The basic system for creating and manipulating graph data. This system uses C#'s built-in serialization system to save/load graphs to/from a file. 128 | 129 | A graph node is an instance of a class inheriting from `Node`. A node is given a unique UID by the graph it is added to, which is used when serializing/deserializing node references. It also has a rectangle representing its visual position in the graph editor. 130 | 131 | A node's inputs are stored as a list of `NodeInput` instances. Each `NodeInput` is either a constant float (in which case `IsAConstant` returns `true` and `ConstantValue` is well-defined) or it is the output of another node (in which case `IsAConstant` returns `false` and `NodeID` contains the UID of the node whose output is being read). 132 | 133 | Graphs are represented by the `Graph` class, which has a collection of nodes, the file path of the graph, and the final output of the graph (a `NodeInput` instance). It exposes `Save()` and `Load()` methods, as well as `GenerateShader()` to get shader code, and the more abstract `InsertShaderCode()` to use the graph's noise output as part of a more complex shader. 134 | 135 | The `GraphEditorUtils` class provides various ways to interact with a graph in the editor, including `GetAllGraphsInProject()`, `SaveShader()`, `GenerateToTexture()`, and `GenerateToArray()`. There is a similar class `GraphUtils` that can be used at runtime. 136 | 137 | The number of `Node` child classes is actually fairly small: 138 | * `SimpleNode` handles any kind of one-line expression, including all the built-in shader functions like `sin`, `lerp`, `abs`, etc. The vast majority of nodes are instances of `SimpleNode`. 139 | * `CustomExprNode` allows the user to type a custom shader expression using any number of inputs (`$1`, `$2`, `$3`, etc). 140 | * `NoiseNode` is a node that generates 1D, 2D, 3D, or 4D noise. The noise can be "White", "Blocky", "Linear", "Smooth", "Smoother", "Perlin", or "Worley". Note that "Worley" has special editing options that the other noise types don't need. 141 | * `TexCoordNode` represents the UV coordinates of the texture the graph noise is being rendered into. This is generally how you get the input values for a noise function. It can output the X, Y, or Z coordinate. Z coordinate is used when you want to generate a 3D texture from the graph. 142 | * `ParamNode_Float` is a float parameter, represented as either a text box or a slider. 143 | * `ParamNode_Texture2D` is a 2D texture parameter. 144 | * `SubGraphNode` allows graphs to be used inside other graphs. 145 | 146 | ## Applications 147 | 148 | *namespace: GPUGraph.Applications* 149 | 150 | This folder contains the various built-in utilities mentioned above: *ShaderGenerator*, *Texture2DGenerator*, *Texture3DGenerator*, and *TerrainGenerator*. 151 | 152 | # Known Issues 153 | 154 | If anybody wants to help out with these issues (or contribute to the codebase in any other way), feel free to send a pull request or email me at manning.w27@gmail.com. 155 | 156 | * When you first click on the editor after creating a new graph, it goes back to a state of not editing anything for some reason. 157 | 158 | * The editor window's UI is pretty rough; you get what you pay for :P. You can pan the view, but you can't zoom in or out. Adding zoom functionality can most likely be done somehow with the use of the GUIUtility.ScaleAroundPivot() method. 159 | * Additionally, the lines connecting nodes don't get drawn if they go off the right side of the graph area, and they get drawn over the other panes if they go off the left side. 160 | * Features like multi-node selection/movement, comments, and pressing Ctrl+S to save would be nice. 161 | 162 | * Terrain Generator should show a preview of the generated image. 163 | 164 | * UnityEditor's `Undo` class just didn't seem to work at all with the graph editor window, so I don't use it at all (although I at least got it to work with RuntimeGraph's custom inspector). However, the editor closely tracks any unsaved changes and makes sure to tell you if you're about to discard them. 165 | 166 | * There are some bugs with drawing textures in RuntimeGraph's custom Inspector code; sometimes the textures aren't visible. As far as I can tell, this is Unity's problem. 167 | 168 | * It seems impossible to use one of Unity's built-in textures as a "default" value for a Texture2D parameter because I can't serialize its asset path (they all have the same file path, "Resources/unity_buitin_extra"). Currently I log a warning if you try to use one of them. 169 | 170 | # License 171 | 172 | All code belongs to William Manning. Released under the MIT License (TL;DR: use it for literally any purpose, including commercially!) 173 | 174 | ````Copyright (c) 2016 William Manning 175 | 176 | ````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: 177 | 178 | ````The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 179 | 180 | ````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. 181 | -------------------------------------------------------------------------------- /Assets/GPUGraph/README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a4efdd9f1c8fd5f43ba8510a27b14596 3 | timeCreated: 1470474299 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 116b1e734bb4709469248ea7f709d8fe 3 | folderAsset: yes 4 | timeCreated: 1470473983 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Runtime/GraphUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using UnityEngine; 5 | 6 | 7 | namespace GPUGraph 8 | { 9 | /// 10 | /// Provides support for saving/loading things like Graphs and shaders. 11 | /// It is recommended to just use RuntimeGraph instead of using this class directly. 12 | /// 13 | public static class GraphUtils 14 | { 15 | //TODO: Allow setting UVz when making 2D texture, or scaling/offsetting the UVz when making 3D texture. 16 | 17 | public static readonly string Param_UVz = "__UV_z__"; 18 | 19 | 20 | /// 21 | /// Renders the given material into given texture. 22 | /// Assumes the material uses a shader generated from a Graph. 23 | /// 24 | /// 25 | /// Whether to leave the texture data readable on the CPU after the operation. 26 | /// 27 | public static void GenerateToTexture(Material noiseMat, Texture2D dest, bool leaveReadable = false) 28 | { 29 | var tempTarget = RenderTexture.GetTemporary(dest.width, dest.height, 16, 30 | RenderTextureFormat.ARGB32); 31 | GenerateToTexture(tempTarget, noiseMat, dest, leaveReadable); 32 | RenderTexture.ReleaseTemporary(tempTarget); 33 | } 34 | /// 35 | /// Renders the given material into the given render target using a full-screen quad. 36 | /// Assumes the material uses a shader generated from a Graph. 37 | /// Optionally copies the resulting texture data into a Texture2D for further processing. 38 | /// 39 | /// 40 | /// If set to "null", the noise will be rendered onto the screen. 41 | /// 42 | /// 43 | /// Whether to leave the texture data readable on the CPU after the operation. 44 | /// 45 | public static void GenerateToTexture(RenderTexture rendTarget, Material noiseMat, 46 | Texture2D copyTo = null, bool leaveReadable = false) 47 | { 48 | int width = (rendTarget == null ? Screen.width : rendTarget.width), 49 | height = (rendTarget == null ? Screen.height : rendTarget.height); 50 | 51 | //Set up rendering state. 52 | RenderTexture activeTarget = RenderTexture.active; 53 | RenderTexture.active = rendTarget; 54 | noiseMat.SetPass(0); 55 | 56 | //Render a quad using immediate mode. 57 | GL.PushMatrix(); 58 | GL.LoadIdentity(); 59 | GL.Viewport(new Rect(0, 0, width, height)); 60 | GL.Begin(GL.TRIANGLE_STRIP); 61 | GL.Color(Color.white); 62 | GL.TexCoord(new Vector3(0.0f, 0.0f, 0.0f)); 63 | GL.Vertex3(-1.0f, -1.0f, 0.0f); 64 | GL.TexCoord(new Vector3(1.0f, 0.0f, 0.0f)); 65 | GL.Vertex3(1.0f, -1.0f, 0.0f); 66 | GL.TexCoord(new Vector3(0.0f, 1.0f, 0.0f)); 67 | GL.Vertex3(-1.0f, 1.0f, 0.0f); 68 | GL.TexCoord(new Vector3(1.0f, 1.0f, 0.0f)); 69 | GL.Vertex3(1.0f, 1.0f, 0.0f); 70 | GL.End(); 71 | GL.PopMatrix(); 72 | 73 | //Copy the results into the Texture2D. 74 | if (copyTo != null) 75 | { 76 | if (copyTo.width != width || copyTo.height != height) 77 | copyTo.Resize(width, height); 78 | 79 | copyTo.ReadPixels(new Rect(0, 0, width, height), 0, 0); 80 | copyTo.Apply(true, !leaveReadable); 81 | } 82 | 83 | //Reset rendering state. 84 | RenderTexture.active = activeTarget; 85 | } 86 | 87 | /// 88 | /// Renders the given material into the given 3D texture. 89 | /// 90 | /// 91 | /// Whether to let the texture keep a CPU copy of its data on hand for later reading. 92 | /// 93 | /// The depth of the 3D texture (i.e. its size along the Z axis). 94 | public static void GenerateToTexture(int depth, Material noiseMat, Texture3D copyTo, 95 | bool leaveTextureReadable) 96 | { 97 | var rendTarget = RenderTexture.GetTemporary(copyTo.width, copyTo.height, 98 | 16, RenderTextureFormat.ARGB32); 99 | int width = (rendTarget == null ? Screen.width : rendTarget.width), 100 | height = (rendTarget == null ? Screen.height : rendTarget.height); 101 | 102 | //For every Z layer in the texture, generate a 2D texture representing that layer. 103 | 104 | Color32[] finalPixels = new Color32[width * height * depth]; 105 | SetUpColorTex(width, height); 106 | for (int depthI = 0; depthI < depth; ++depthI) 107 | { 108 | //Get the UV.z coordinate. 109 | float uvZ = (float)depthI / depth; 110 | noiseMat.SetFloat(Param_UVz, uvZ); 111 | 112 | GenerateToTexture(rendTarget, noiseMat, colorTex, true); 113 | 114 | //Copy the resulting data into part of the 3D texture. 115 | Color32[] layerPixels = colorTex.GetPixels32(); 116 | int pixelOffset = depthI * (width * height); 117 | for (int pixelI = 0; pixelI < (width * height); ++pixelI) 118 | finalPixels[pixelI + pixelOffset] = layerPixels[pixelI]; 119 | } 120 | 121 | 122 | //Create the actual texture object. 123 | copyTo.SetPixels32(finalPixels); 124 | copyTo.Apply(true, !leaveTextureReadable); 125 | 126 | //Clean up. 127 | RenderTexture.ReleaseTemporary(rendTarget); 128 | } 129 | 130 | /// 131 | /// Uses the given noise material to generate noise into the given array. 132 | /// 133 | public static void GenerateToArray(float[,] outData, Material noiseMat) 134 | { 135 | RenderTexture rendTex = RenderTexture.GetTemporary(outData.GetLength(0), outData.GetLength(1)); 136 | 137 | //Generate the noise. 138 | SetUpColorTex(outData.GetLength(0), outData.GetLength(1)); 139 | GenerateToTexture(rendTex, noiseMat, colorTex, true); 140 | 141 | //Read the noise into the array. 142 | Color[] cols = colorTex.GetPixels(); 143 | for (int y = 0; y < outData.GetLength(1); ++y) 144 | for (int x = 0; x < outData.GetLength(0); ++x) 145 | outData[x, y] = cols[x + (outData.GetLength(0) * y)].r; 146 | 147 | RenderTexture.ReleaseTemporary(rendTex); 148 | } 149 | /// 150 | /// Uses the given noise material to generate noise into the given array. 151 | /// 152 | public static void GenerateToArray(float[,,] outData, Material noiseMat) 153 | { 154 | //Generate the noise. 155 | SetUpColorTex3(outData.GetLength(0), outData.GetLength(1), outData.GetLength(2)); 156 | GenerateToTexture(outData.GetLength(2), noiseMat, colorTex3, true); 157 | 158 | //Read the noise into the array. 159 | Color[] cols = colorTex.GetPixels(); 160 | int i = 0; 161 | for (int z = 0; z < outData.GetLength(2); ++z) 162 | for (int y = 0; y < outData.GetLength(1); ++y) 163 | for (int x = 0; x < outData.GetLength(0); ++x) 164 | outData[x, y, z] = cols[i++].r; 165 | } 166 | 167 | 168 | private static Texture2D colorTex = null; 169 | private static void SetUpColorTex(int width, int height) 170 | { 171 | if (colorTex == null) 172 | { 173 | //Find the best-possible supported format for this. 174 | TextureFormat[] fmts = new TextureFormat[] 175 | { TextureFormat.RFloat, TextureFormat.RGBAFloat, 176 | TextureFormat.RHalf, TextureFormat.RGBAHalf, 177 | TextureFormat.BGRA32, TextureFormat.RGBA32, TextureFormat.ARGB32 }; 178 | TextureFormat? fmt = null; 179 | for (int i = 0; i < fmts.Length; ++i) 180 | { 181 | if (SystemInfo.SupportsTextureFormat(fmts[i])) 182 | { 183 | fmt = fmts[i]; 184 | break; 185 | } 186 | } 187 | if (!fmt.HasValue) 188 | { 189 | Debug.LogError("Couldn't find a reasonable texture format for GPUG"); 190 | return; 191 | } 192 | 193 | colorTex = new Texture2D(width, height, fmt.Value, false); 194 | } 195 | else if (colorTex.width != width || colorTex.height != height) 196 | { 197 | colorTex.Resize(width, height); 198 | } 199 | } 200 | 201 | private static Texture3D colorTex3 = null; 202 | private static void SetUpColorTex3(int width, int height, int depth) 203 | { 204 | if (colorTex3 == null) 205 | { 206 | //Find the best-possible supported format for this. 207 | TextureFormat[] fmts = new TextureFormat[] 208 | { TextureFormat.RFloat, TextureFormat.RGBAFloat, 209 | TextureFormat.RHalf, TextureFormat.RGBAHalf, 210 | TextureFormat.BGRA32, TextureFormat.RGBA32, TextureFormat.ARGB32 }; 211 | TextureFormat? fmt = null; 212 | for (int i = 0; i < fmts.Length; ++i) 213 | { 214 | if (SystemInfo.SupportsTextureFormat(fmts[i])) 215 | { 216 | fmt = fmts[i]; 217 | break; 218 | } 219 | } 220 | if (!fmt.HasValue) 221 | { 222 | Debug.LogError("Couldn't find a reasonable texture format for GPUG"); 223 | return; 224 | } 225 | 226 | colorTex3 = new Texture3D(width, height, depth, fmt.Value, false); 227 | } 228 | else if (colorTex3.width != width || colorTex3.height != height || colorTex3.depth != depth) 229 | { 230 | colorTex3 = new Texture3D(width, height, depth, colorTex3.format, false); 231 | } 232 | } 233 | } 234 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Runtime/GraphUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b96008a41f7858499e30e2083bc18b1 3 | timeCreated: 1444256280 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Runtime/RuntimeGraph.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | 6 | 7 | namespace GPUGraph 8 | { 9 | /// 10 | /// Stores a graph at run-time in the form of a Shader/Material. 11 | /// Note that modifying parameters is best done with the built-in methods, 12 | /// not by modifying the param lists directly. 13 | /// 14 | [Serializable] 15 | public class RuntimeGraph 16 | { 17 | public Shader GraphShader; 18 | public List FloatParams = new List(); 19 | public List Tex2DParams = new List(); 20 | public float UVz = 0.0f; 21 | 22 | 23 | public Material GraphMat 24 | { 25 | get 26 | { 27 | if (graphMat == null) 28 | { 29 | if (GraphShader == null) 30 | { 31 | throw new InvalidOperationException("Something happened to a RuntimeGraph's shader! " + 32 | "View the RuntimeGraph in the Inspector to regenerate it."); 33 | } 34 | else 35 | { 36 | graphMat = new Material(GraphShader); 37 | UpdateAllParams(); 38 | } 39 | } 40 | 41 | return graphMat; 42 | } 43 | } 44 | private Material graphMat = null; 45 | 46 | 47 | /// 48 | /// Outputs noise into the screen or whatever RenderTexture is currently active. 49 | /// 50 | public void GenerateToCurrentFramebuffer() 51 | { 52 | UpdateAllParams(); 53 | GraphUtils.GenerateToTexture(RenderTexture.active, GraphMat); 54 | } 55 | /// 56 | /// Outputs noise into the given RenderTexture. 57 | /// 58 | public void GenerateToFramebuffer(RenderTexture outTex) 59 | { 60 | UpdateAllParams(); 61 | GraphUtils.GenerateToTexture(outTex, GraphMat); 62 | } 63 | 64 | /// 65 | /// Outputs noise into the given Texture2D. 66 | /// 67 | /// 68 | /// Whether to leave the texture data readable on the CPU after the operation. 69 | /// 70 | public void GenerateToTexture(Texture2D outTex, bool leaveReadable = false) 71 | { 72 | UpdateAllParams(); 73 | RenderTexture tempTex = RenderTexture.GetTemporary(outTex.width, outTex.height); 74 | GraphUtils.GenerateToTexture(tempTex, GraphMat, outTex, leaveReadable); 75 | RenderTexture.ReleaseTemporary(tempTex); 76 | } 77 | /// 78 | /// Generates to a texture of the given size. 79 | /// 80 | /// 81 | /// Whether to leave the texture data readable on the CPU after the operation. 82 | /// 83 | public Texture2D GenerateToTexture(int width, int height, 84 | TextureFormat fmt = TextureFormat.RGBAFloat, 85 | FilterMode filtering = FilterMode.Bilinear, 86 | bool mipmaps = true, 87 | bool leaveReadable = false) 88 | { 89 | UpdateAllParams(); 90 | Texture2D t = new Texture2D(width, height, fmt, mipmaps); 91 | t.filterMode = filtering; 92 | GenerateToTexture(t, leaveReadable); 93 | return t; 94 | } 95 | 96 | /// 97 | /// Outputs noise into the given array. 98 | /// 99 | public void GenerateToArray(float[,] outData) 100 | { 101 | UpdateAllParams(); 102 | GraphUtils.GenerateToArray(outData, GraphMat); 103 | } 104 | 105 | 106 | #region Param getters/setters 107 | 108 | /// 109 | /// Returns -1 if the param doesn't exist. 110 | /// 111 | public int IndexOfParam_Float(string name) 112 | { 113 | for (int i = 0; i < FloatParams.Count; ++i) 114 | if (FloatParams[i].Key == name) 115 | return i; 116 | return -1; 117 | } 118 | /// 119 | /// Returns -1 if the param doesn't exist. 120 | /// 121 | public int IndexOfParam_Tex2D(string name) 122 | { 123 | for (int i = 0; i < Tex2DParams.Count; ++i) 124 | if (Tex2DParams[i].Key == name) 125 | return i; 126 | return -1; 127 | } 128 | 129 | public float GetParam_Float(string name) 130 | { 131 | return FloatParams[IndexOfParam_Float(name)].Value; 132 | } 133 | public Texture2D GetParam_Tex2D(string name) 134 | { 135 | for (int i = 0; i < Tex2DParams.Count; ++i) 136 | if (Tex2DParams[i].Key == name) 137 | return Tex2DParams[i].Value; 138 | 139 | UnityEngine.Assertions.Assert.IsTrue(false); 140 | return null; 141 | } 142 | 143 | public bool SetParam_Float(string name, float val) 144 | { 145 | int i = IndexOfParam_Float(name); 146 | if (i >= 0) 147 | SetParam_Float(i, val); 148 | return i >= 0; 149 | } 150 | public bool SetParam_Tex2D(string name, Texture2D val) 151 | { 152 | int i = IndexOfParam_Tex2D(name); 153 | if (i >= 0) 154 | SetParam_Tex2D(i, val); 155 | return i >= 0; 156 | } 157 | 158 | public void SetParam_Float(int index, float val) 159 | { 160 | FloatParams[index].Value = val; 161 | graphMat.SetFloat(FloatParams[index].Key, val); 162 | } 163 | public void SetParam_Tex2D(int index, Texture2D val) 164 | { 165 | Tex2DParams[index].Value = val; 166 | graphMat.SetTexture(Tex2DParams[index].Key, val); 167 | } 168 | 169 | /// 170 | /// Should be called if changes are made to this instance's parameter lists by external code. 171 | /// Otherwise, those new parameter values won't actually be used when generating noise. 172 | /// 173 | private void UpdateAllParams() 174 | { 175 | Material m = GraphMat; 176 | foreach (FloatParamKVP floatParam in FloatParams) 177 | m.SetFloat(floatParam.Key, floatParam.Value); 178 | foreach (Tex2DParamKVP texParam in Tex2DParams) 179 | m.SetTexture(texParam.Key, texParam.Value); 180 | m.SetFloat(GraphUtils.Param_UVz, UVz); 181 | } 182 | 183 | #endregion 184 | 185 | 186 | #region Editor-only fields 187 | #if UNITY_EDITOR 188 | 189 | //The following should all be ignored; it's only used by the Inspector window. 190 | 191 | #region Helper classes 192 | 193 | [Serializable] 194 | public class _SerializableFloatParamInfo 195 | { 196 | public bool IsSlider; 197 | public float SliderMin, SliderMax; 198 | public float DefaultValue; 199 | } 200 | [Serializable] 201 | public class _SerializableTex2DParamInfo 202 | { 203 | public Texture2D DefaultValue; 204 | } 205 | 206 | [Serializable] 207 | public class _SerializableFloatParamKVP 208 | { 209 | public string Key; 210 | public _SerializableFloatParamInfo Value; 211 | 212 | public _SerializableFloatParamKVP() { } 213 | public _SerializableFloatParamKVP(string key, _SerializableFloatParamInfo value) 214 | { Key = key; Value = value; } 215 | } 216 | [Serializable] 217 | public class _SerializableTex2DParamKVP 218 | { 219 | public string Key; 220 | public _SerializableTex2DParamInfo Value; 221 | 222 | public _SerializableTex2DParamKVP() { } 223 | public _SerializableTex2DParamKVP(string key, _SerializableTex2DParamInfo value) 224 | { Key = key; Value = value; } 225 | } 226 | 227 | #endregion 228 | 229 | public string _ShaderFile = null; 230 | public string _GraphFile = null; 231 | public Material _PreviewMat = null; 232 | public Texture2D _PreviewTex = null; 233 | public float _PreviewTexScale = 1.0f; 234 | public int _PreviewTexWidth = 256, 235 | _PreviewTexHeight = 256; 236 | public List<_SerializableFloatParamKVP> _FloatParams = new List<_SerializableFloatParamKVP>(); 237 | public List<_SerializableTex2DParamKVP> _Tex2DParams = new List<_SerializableTex2DParamKVP>(); 238 | 239 | #endif 240 | #endregion 241 | } 242 | 243 | 244 | /// 245 | /// A float parameter's name and value. 246 | /// 247 | [Serializable] 248 | public class FloatParamKVP 249 | { 250 | public string Key; 251 | public float Value; 252 | 253 | public FloatParamKVP() { } 254 | public FloatParamKVP(string key, float value) { Key = key; Value = value; } 255 | } 256 | /// 257 | /// A 2D texture parameter's name and value. 258 | /// 259 | [Serializable] 260 | public class Tex2DParamKVP 261 | { 262 | public string Key; 263 | public Texture2D Value; 264 | 265 | public Tex2DParamKVP() { } 266 | public Tex2DParamKVP(string key, Texture2D value) { Key = key; Value = value; } 267 | } 268 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Runtime/RuntimeGraph.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c776a72f3692c614986bbda0a40b0675 3 | timeCreated: 1468892831 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Sample.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3cb74aef6966bc447811f33b9c056ff9 3 | folderAsset: yes 4 | timeCreated: 1470701177 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Sample/SampleGPUGScript.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | 6 | 7 | namespace GPUGraph.Examples 8 | { 9 | /// 10 | /// An example of how to use GPUGraphs at runtime. 11 | /// Generates one texture each from two graphs, 12 | /// then displays them and their parameters in the GUI. 13 | /// 14 | public class SampleGPUGScript : MonoBehaviour 15 | { 16 | //Note that these objects are serializable, and can be edited in the Inspector. 17 | public GPUGraph.RuntimeGraph MyGraph = new GPUGraph.RuntimeGraph(); 18 | public GPUGraph.RuntimeGraph MyGraph2 = new GPUGraph.RuntimeGraph(); 19 | 20 | private Texture2D myTex1, myTex2; 21 | 22 | 23 | void Start() 24 | { 25 | //Generate the textures. 26 | myTex1 = MyGraph.GenerateToTexture(512, 512, TextureFormat.RGB24, 27 | FilterMode.Bilinear, false, true); 28 | myTex2 = MyGraph2.GenerateToTexture(512, 512, TextureFormat.RGB24, 29 | FilterMode.Bilinear, false, true); 30 | } 31 | private void OnGUI() 32 | { 33 | //If something went wrong with generating the textures, don't try to draw them. 34 | if (myTex1 == null || myTex2 == null) 35 | return; 36 | 37 | //Draw the textures. 38 | float borderPercent = 0.1f, 39 | borderW = Screen.width * borderPercent, 40 | borderH = Screen.height * borderPercent, 41 | screenHalfW = Screen.width * 0.5f; 42 | GUI.DrawTexture(new Rect(borderW, borderH, 43 | screenHalfW - (borderW * 2.0f), 44 | Screen.height - (borderH * 2.0f)), 45 | myTex1, 46 | ScaleMode.ScaleToFit); 47 | GUI.DrawTexture(new Rect(screenHalfW + borderW, borderH, 48 | screenHalfW - (borderW * 2.0f), 49 | Screen.height - (borderH * 2.0f)), 50 | myTex2, 51 | ScaleMode.ScaleToFit); 52 | 53 | 54 | //Expose a UI for editing float parameters. 55 | //If any values changed, regenerate the texture. 56 | 57 | GUILayout.BeginArea(new Rect(0.0f, 0.0f, borderW, Screen.height)); 58 | { 59 | bool changed = false; 60 | foreach (var param in MyGraph.FloatParams) 61 | changed = ParamGUILayout(param) | changed; 62 | if (changed) 63 | MyGraph.GenerateToTexture(myTex1, true); 64 | } 65 | GUILayout.EndArea(); 66 | 67 | GUILayout.BeginArea(new Rect(Screen.width - borderW, 0.0f, borderW, Screen.height)); 68 | { 69 | bool changed = false; 70 | foreach (var param in MyGraph2.FloatParams) 71 | changed = ParamGUILayout(param) | changed; 72 | if (changed) 73 | MyGraph2.GenerateToTexture(myTex2, true); 74 | } 75 | GUILayout.EndArea(); 76 | } 77 | 78 | /// 79 | /// Shows a GUILayout widget for the given graph parameter. 80 | /// Returns whether the parameter's value changed. 81 | /// 82 | private bool ParamGUILayout(FloatParamKVP param) 83 | { 84 | GUILayout.BeginHorizontal(); 85 | 86 | GUILayout.Label(param.Key); 87 | 88 | float oldVal = param.Value; 89 | param.Value = GUILayout.HorizontalSlider(param.Value, 0.0f, 10.0f, 90 | GUILayout.MinWidth(50.0f)); 91 | 92 | GUILayout.EndHorizontal(); 93 | 94 | return oldVal != param.Value; 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /Assets/GPUGraph/Sample/SampleGPUGScript.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe28074abd7a3074382845faf1885ae5 3 | timeCreated: 1468981071 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Sample/SampleGraph.gpug: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/Assets/GPUGraph/Sample/SampleGraph.gpug -------------------------------------------------------------------------------- /Assets/GPUGraph/Sample/SampleGraph.gpug.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40dbdfdde1ea5694b97ca0c3f219937c 3 | timeCreated: 1470472697 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/GPUGraph/Sample/SampleScene.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/Assets/GPUGraph/Sample/SampleScene.unity -------------------------------------------------------------------------------- /Assets/GPUGraph/Sample/SampleScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2e48ad06856ca8640997b6f791f6940a 3 | timeCreated: 1470474621 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /GPUGraph.unitypackage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/GPUGraph.unitypackage -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Assets/GPU Noise/LICENSE.txt -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.6.1f1 2 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityAdsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/UnityAdsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/ProjectSettings/UnityConnectSettings.asset -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GPUGraph 2 | 3 | An open-source Unity plugin for generating coherent noise on the GPU, for both editor and runtime uses. The source is available [here](http://www.github.com/heyx3/GPUNoiseForUnity), on Github. It is also available on [the Asset Store](https://www.assetstore.unity3d.com/#!/content/68911), but that version is currently out of date. 4 | 5 | Editor tools for this plugin are available in the "Assets/GPU Graph" section on the Unity editor's toolbar. The *.unitypackage* file for this plugin is stored in the root of this repo: *GPUGraph.unitypackage*. 6 | 7 | 8 | # Overview 9 | 10 | This repo contains the GPUGraph plugin for Unity, which provides classes and editors for generating floating-point noise on the GPU with shaders. 11 | This leads to extremely fast noise generation compared to traditional CPU methods. 12 | 13 | Note that because Unity no longer supports runtime compilation of shaders, Graphs can only really be used in the editor. However, shaders can be generated from the graph in the editor then used in real-time (graphs can expose float and Tex2D parameters which are changeable at run-time). A serializable class "RuntimeGraph" is provided to greatly simplify use of run-time graphs; see "SampleScene.unity" and "SampleGPUGScript.cs" for an example of how to use it (note that you need to look at the SampleGPUGScript component in the Inspector to regenerate shaders before the scene will work). 14 | 15 | The basic structure behind GPUGraph is a "Directed Acyclic Graph" (essentially a tree whose nodes can have multiple parents) of commands that represents shader code. Every node in the graph takes some number of floats as inputs and outputs a single float as a result. 16 | 17 | Graphs are created in a custom editor window and saved as ".gpug" files into the "Assets" folder. The editor is accessed by selecting "Assets/GPU Graph/Editor" in the Unity editor's toolbar. Here is an example of a very simple graph that generates pure white noise: 18 | 19 | ![White Noise](https://github.com/heyx3/GPUNoiseForUnity/blob/master/Readme%20Images/WhiteNoise.png) 20 | 21 | A side utility is also provided for easy random number generation on the GPU: "Assets/GPUGraph/GpuRandWithState.cginc". 22 | 23 | 24 | # Editor 25 | 26 | In the above image, note the various aspects of the graph editor: 27 | 28 | * On the far left is a section for choosing nodes to place down in the graph. 29 | * To the right of that is a set of options for the graph, and for loading/creating other ones. 30 | * On the top of this "options" section is the specific graph file being edited. This dropdown box lists all the .gpug files in your Unity project. 31 | * Below the "New Graph", "Save Changes", and "Discard Changes" buttons is the preview window, which shows what would happen if you rendered your noise graph to a 2D texture. You can check the "Auto-Update Preview" box to automatically update the preview every time the graph is edited. 32 | * On the right side of the window, is the graph area. This displays all your nodes. The right-most node, "Output", represents the final output of the graph. You can right-click and drag to pan the area. 33 | 34 | In order to add a new node, click the button for the node you want to place, then left-click in the graph to place it. Right-click in the graph to cancel. A node's inputs are on the left side, and its output is on the right side. Note that some nodes have no inputs at all. Each input to a node is either the output of a different node or a constant value entered in a text box. 35 | 36 | You can add the basic arithmetic nodes by pressing their respective keys (`+`, `-`, `*`, and `/`). 37 | 38 | 39 | # Nodes 40 | 41 | All the nodes this plugin currently offers are listed here: 42 | 43 | * Noise: Exposes a variety of 1D, 2D, 3D, or 4D noise algorithms (all of which return a value between 0 and 1) with a scale/weight value for convenience when combining multiple octaves of noise. They can all optionally wrap around their edges so that the resulting noise tiles every 1 units. 44 | * White noise: a pseudo-random value. 45 | * Grid noise: Creates 1x1 square blocks of noise by getting White Noise for the `floor` of the seed value. 46 | * Linear noise: Like Grid noise but with a linear interpolation between values, yielding smooth diamond shapes instead of square blocks. 47 | * Smooth noise: Like Linear noise but smoother and a bit more expensive. 48 | * Smoother noise: Like Smooth noise but even smoother and a bit more expensive. 49 | * Perlin noise: Like Smooth noise but with fewer blocky artifacts, and much more expensive. 50 | * Worley noise: Generates a random point in every 1x1 block of space and outputs noise based on how far away the given value is from the nearest point. Note that Worley noise only tiles properly if the scale is a power of two. 51 | * UV: The X, Y, or Z coordinate (from 0 to 1) of the pixel in the render texture currently being generated. The Z coordinate is useful when generating 3D textures. It can also be thought of as a seed value for 2D noise. 52 | * Custom Expression: A custom HLSL expression with any number of inputs. 53 | * Float Parameter: A shader parameter that can be easily changed after the graph has been compiled into a Material. 54 | * Tex2D Parameter: A texture parameter that can be easily changed after the graph has been compiled into a Material. 55 | * Sub-graph: Represents the output of another graph file. 56 | * Ceil: rounds the input to the next largest integer. 57 | * Floor: rounds the input to the next smallest integer. 58 | * Truncate: gets the non-fractional part of an input. 59 | * Fract: gets the fractional part of an input. 60 | * RoundToInt: rounds the input to the nearest integer. 61 | * Sign: Returns -1 if the input is negative, 0 if it's zero, and +1 if it's positive. 62 | * Abs: Returns the absolute value of the input. 63 | * Cos: Returns the cosine of the input. 64 | * Sin: Returns the sine of the input. 65 | * Tan: Returns the tangent of the input. 66 | * Acos: Returns the inverse cosine of the input. 67 | * ASin: Returns the inverse sine of the input. 68 | * Atan: Returns the inverse tangent of the input. 69 | * Sqrt: Returns the square root of the input. 70 | * Log: Returns the logarithm base *e* of the input. 71 | * Add: Adds two inputs together. 72 | * Subtract: Subtracts the second input from the first. 73 | * Multiply: Multiplies two inputs together. 74 | * Divide: Divides the first input by the second. 75 | * Max: Gets the largest of two inputs. 76 | * Min: Gets the smallest of two inputs. 77 | * Pow: Raises the first input to the power of the second input. 78 | * Step: Returns 0 if the second input is less than the first one, or 1 if it is larger. 79 | * Atan2: A version of atan that takes the individual X and Y components. 80 | * Clamp: Forces the third input to be no smaller than the first one and no larger than the second. 81 | * Lerp: Linearly interpolates between the first and second inputs using the third input. 82 | * Smoothstep: Like `Lerp` but with a smooth, third-order curve instead of a line. 83 | * Remap: Remaps a value from the "source" min and max range to the "destination" min and max range. 84 | 85 | 86 | # Applications 87 | 88 | Several example applications are built into the editor; they are all accessible through the "Assets/GPU Graph" category in the Unity editor's toolbar. 89 | 90 | ## Shader Generator 91 | 92 | This tool generates a shader that outputs the graph's noise. You could then create a material that uses this shader and use it in the editor or at runtime to generate noise via the `GPUGraph.GraphUtils` and `GPUGraph.GraphEditorUtils` classes. Fortunately, a helper class `RuntimeGraph` has already been created to make this easier for you, complete with custom Inspector code, but this utility is still useful if you want to further mess with the shader after generating it. 93 | 94 | ## Texture 2D Generator 95 | 96 | This tool generates a 2D texture file using a graph. 97 | 98 | ## Texture 3D Generator 99 | 100 | This tool generates a 3D texture file (and, optionally, an accompanying normal texture) using a graph. 101 | 102 | ## Texture Generator 103 | 104 | This is the abstract base class for Texture2DGenerator and Texture3DGenerator. It provides the bulk of their GUI. 105 | 106 | 107 | ## Terrain Generator 108 | 109 | This tool uses a graph to generate a heightmap for whichever terrain object is currently selected in the scene view. 110 | 111 | 112 | # Code 113 | 114 | Code is organized in the following way inside the "GPU Noise" folder: 115 | 116 | * Runtime: Scripts for using graphs at run-time. Take a look at "SampleGPUGScript.cs" for an example of how to use these. 117 | * Editor: Scripts for using graphs in the editor. 118 | * **Graph System**: The code for representing/editing a graph. 119 | * **Nodes**: Specific kinds of nodes that can be placed in a graph. 120 | * **Editor**: The Unity editor window for creating/modifying graphs. 121 | * **Applications**: The above-metioned sample utilities: texture, shader, and terrain generators. 122 | 123 | ## Graph System 124 | 125 | *namespace: GPUGraph* 126 | 127 | The basic system for creating and manipulating graph data. This system uses C#'s built-in serialization system to save/load graphs to/from a file. 128 | 129 | A graph node is an instance of a class inheriting from `Node`. A node is given a unique UID by the graph it is added to, which is used when serializing/deserializing node references. It also has a rectangle representing its visual position in the graph editor. 130 | 131 | A node's inputs are stored as a list of `NodeInput` instances. Each `NodeInput` is either a constant float (in which case `IsAConstant` returns `true` and `ConstantValue` is well-defined) or it is the output of another node (in which case `IsAConstant` returns `false` and `NodeID` contains the UID of the node whose output is being read). 132 | 133 | Graphs are represented by the `Graph` class, which has a collection of nodes, the file path of the graph, and the final output of the graph (a `NodeInput` instance). It exposes `Save()` and `Load()` methods, as well as `GenerateShader()` to get shader code, and the more abstract `InsertShaderCode()` to use the graph's noise output as part of a more complex shader. 134 | 135 | The `GraphEditorUtils` class provides various ways to interact with a graph in the editor, including `GetAllGraphsInProject()`, `SaveShader()`, `GenerateToTexture()`, and `GenerateToArray()`. There is a similar class `GraphUtils` that can be used at runtime. 136 | 137 | The number of `Node` child classes is actually fairly small: 138 | * `SimpleNode` handles any kind of one-line expression, including all the built-in shader functions like `sin`, `lerp`, `abs`, etc. The vast majority of nodes are instances of `SimpleNode`. 139 | * `CustomExprNode` allows the user to type a custom shader expression using any number of inputs (`$1`, `$2`, `$3`, etc). 140 | * `NoiseNode` is a node that generates 1D, 2D, 3D, or 4D noise. The noise can be "White", "Blocky", "Linear", "Smooth", "Smoother", "Perlin", or "Worley". Note that "Worley" has special editing options that the other noise types don't need. 141 | * `TexCoordNode` represents the UV coordinates of the texture the graph noise is being rendered into. This is generally how you get the input values for a noise function. It can output the X, Y, or Z coordinate. Z coordinate is used when you want to generate a 3D texture from the graph. 142 | * `ParamNode_Float` is a float parameter, represented as either a text box or a slider. 143 | * `ParamNode_Texture2D` is a 2D texture parameter. 144 | * `SubGraphNode` allows graphs to be used inside other graphs. 145 | 146 | ## Applications 147 | 148 | *namespace: GPUGraph.Applications* 149 | 150 | This folder contains the various built-in utilities mentioned above: *ShaderGenerator*, *Texture2DGenerator*, *Texture3DGenerator*, and *TerrainGenerator*. 151 | 152 | # Known Issues 153 | 154 | If anybody wants to help out with these issues (or contribute to the codebase in any other way), feel free to send a pull request or email me at manning.w27@gmail.com. 155 | 156 | * When you first click on the editor after creating a new graph, it goes back to a state of not editing anything for some reason. 157 | 158 | * The editor window's UI is pretty rough; you get what you pay for :P. You can pan the view, but you can't zoom in or out. Adding zoom functionality can most likely be done somehow with the use of the GUIUtility.ScaleAroundPivot() method. 159 | * Additionally, the lines connecting nodes don't get drawn if they go off the right side of the graph area, and they get drawn over the other panes if they go off the left side. 160 | * Features like multi-node selection/movement, comments, and pressing Ctrl+S to save would be nice. 161 | 162 | * Terrain Generator should show a preview of the generated image. 163 | 164 | * UnityEditor's `Undo` class just didn't seem to work at all with the graph editor window, so I don't use it at all (although I at least got it to work with RuntimeGraph's custom inspector). However, the editor closely tracks any unsaved changes and makes sure to tell you if you're about to discard them. 165 | 166 | * There are some bugs with drawing textures in RuntimeGraph's custom Inspector code; sometimes the textures aren't visible. As far as I can tell, this is Unity's problem. 167 | 168 | * It seems impossible to use one of Unity's built-in textures as a "default" value for a Texture2D parameter because I can't serialize its asset path (they all have the same file path, "Resources/unity_buitin_extra"). Currently I log a warning if you try to use one of them. 169 | 170 | # License 171 | 172 | All code belongs to William Manning. Released under the MIT License (TL;DR: use it for literally any purpose, including commercially!) 173 | 174 | ````Copyright (c) 2016 William Manning 175 | 176 | ````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: 177 | 178 | ````The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 179 | 180 | ````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. 181 | -------------------------------------------------------------------------------- /Readme Images/BigIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/Readme Images/BigIcon.png -------------------------------------------------------------------------------- /Readme Images/BigIcon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/Readme Images/BigIcon2.png -------------------------------------------------------------------------------- /Readme Images/SmallIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/Readme Images/SmallIcon.png -------------------------------------------------------------------------------- /Readme Images/TinyIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/Readme Images/TinyIcon.png -------------------------------------------------------------------------------- /Readme Images/WhiteNoise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyx3/GPUNoiseForUnity/eb769ce715522f776166d010f2c5998dc9b8f547/Readme Images/WhiteNoise.png --------------------------------------------------------------------------------