├── Resources ├── Logos.ai └── Logos.ai.meta ├── Pictures~ ├── CustomPropertyAttribute.png └── CustomPropertyAttribute.png.meta ├── CHANGELOG.md.meta ├── README.md.meta ├── package.json.meta ├── .github ├── ISSUE_TEMPLATE │ ├── custom.md │ ├── new_feature.md │ ├── feature_request.md │ └── bug_report.md └── FUNDING.yml ├── Editor.meta ├── Resources.meta ├── Runtime.meta ├── Tests.meta ├── Editor ├── Tools.meta ├── Views.meta ├── EditorBase.meta ├── EditorList.meta ├── EditorUtils.meta ├── VX.Util.Editor.asmdef.meta ├── PropertyDrawers.meta ├── Views │ ├── SplitView.cs │ ├── InspectorView.cs.meta │ ├── SplitView.cs.meta │ └── InspectorView.cs ├── EditorList │ ├── GroupableList.cs.meta │ ├── EditorListConfig.cs.meta │ ├── EditorListUtil.cs.meta │ ├── EditorListConfig.cs │ ├── GroupableList.cs │ └── EditorListUtil.cs ├── EditorUtils │ ├── VXEditorUtil.cs.meta │ ├── VXEditorStyles.cs.meta │ ├── VXEditorUtil.cs │ └── VXEditorStyles.cs ├── Tools │ ├── VoxellMenuItem.cs.meta │ ├── ShowSelectedMeshInfo.cs.meta │ ├── VoxellMenuItem.cs │ └── ShowSelectedMeshInfo.cs ├── EditorBase │ ├── AbstractVXEditor.cs.meta │ ├── VXDefaultEditor.cs.meta │ ├── AbstractVXEditor.cs │ └── VXDefaultEditor.cs ├── PropertyDrawers │ ├── SceneDrawer.cs.meta │ ├── InspectOnlyDrawer.cs.meta │ ├── StreamingAssetDrawer.cs.meta │ ├── InspectOnlyDrawer.cs │ ├── SceneDrawer.cs │ └── StreamingAssetDrawer.cs └── VX.Util.Editor.asmdef ├── Runtime ├── Jobx.meta ├── Mathx.meta ├── Graphics.meta ├── Jobx │ ├── Scan.meta │ ├── Jobx.cs.meta │ ├── RadixSortJob.cs.meta │ ├── ReverseJob.cs.meta │ ├── Scan │ │ ├── SumScanJob.cs.meta │ │ ├── Float3MaxScanJob.cs.meta │ │ ├── Float3MinScanJob.cs.meta │ │ ├── SumScanJob.cs │ │ ├── Float3MaxScanJob.cs │ │ └── Float3MinScanJob.cs │ ├── Jobx.cs │ ├── ReverseJob.cs │ └── RadixSortJob.cs ├── Graphics │ ├── Scan.meta │ ├── Resources.meta │ ├── Resources │ │ ├── Scan.meta │ │ ├── Util.meta │ │ ├── RadixSort.compute.meta │ │ ├── Util │ │ │ ├── Util.UInt.compute.meta │ │ │ ├── Util.Float3.compute.meta │ │ │ ├── Util.Float3.compute │ │ │ └── Util.UInt.compute │ │ ├── Scan │ │ │ ├── BlellochSumScan.compute.meta │ │ │ ├── HillisSteeleSumScan.compute.meta │ │ │ ├── HillisSteeleFloat3MaxScan.compute.meta │ │ │ ├── HillisSteeleFloat3MinScan.compute.meta │ │ │ ├── HillisSteeleSumScan.compute │ │ │ ├── HillisSteeleFloat3MaxScan.compute │ │ │ ├── HillisSteeleFloat3MinScan.compute │ │ │ └── BlellochSumScan.compute │ │ └── RadixSort.compute │ ├── Graphics.cs │ ├── Graphics.cs.meta │ ├── RadixSort.cs.meta │ ├── StrideSize.cs.meta │ ├── ComputeShaderUtil.cs.meta │ ├── Scan │ │ ├── AbstractScan.cs.meta │ │ ├── BlellochSumScan.cs.meta │ │ ├── HillisSteeleSumScan.cs.meta │ │ ├── HillisSteeleFloat3MaxScan.cs.meta │ │ ├── HillisSteeleFloat3MinScan.cs.meta │ │ ├── AbstractScan.cs │ │ ├── HillisSteeleSumScan.cs │ │ ├── HillisSteeleFloat3MaxScan.cs │ │ ├── HillisSteeleFloat3MinScan.cs │ │ └── BlellochSumScan.cs │ ├── ComputeShaderUtil.cs │ ├── StrideSize.cs │ └── RadixSort.cs ├── Mathx │ ├── Extensions.meta │ ├── MathUtil.cs.meta │ ├── Extensions │ │ ├── mathx.cs.meta │ │ ├── float2x.cs.meta │ │ ├── float3x.cs.meta │ │ ├── float3x.cs │ │ ├── float2x.cs │ │ └── mathx.cs │ └── MathUtil.cs ├── VX.Util.Runtime.asmdef.meta ├── MeshUtil.cs.meta ├── FileUtilx.cs.meta ├── VXAttributes.cs.meta ├── RefreshMonoBehaviour.cs.meta ├── RefreshMonoBehaviour.cs ├── VX.Util.Runtime.asmdef ├── VXAttributes.cs ├── FileUtilx.cs └── MeshUtil.cs ├── Tests ├── Editor.meta └── Editor │ ├── VX.Util.Tests.Editor.asmdef.meta │ ├── GraphicsTests.cs.meta │ ├── JobxTests.cs.meta │ ├── VX.Util.Tests.Editor.asmdef │ ├── JobxTests.cs │ └── GraphicsTests.cs ├── package.json ├── .gitignore ├── README.md ├── CHANGELOG.md └── LICENSE /Resources/Logos.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nixon-voxell/UnityUtil/HEAD/Resources/Logos.ai -------------------------------------------------------------------------------- /Pictures~/CustomPropertyAttribute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nixon-voxell/UnityUtil/HEAD/Pictures~/CustomPropertyAttribute.png -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 747e9f8a830b89041894594639745fe0 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a00b342f86160af4c9d41e27f3cfd7bd 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Resources/Logos.ai.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f8ea7f3668a050e4c8a5e6778713e6b4 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 53fdd223244bc4d41a11fcf85dc9f6a9 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 271b19a543d65e94f9335425bff1fc21 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b56a14370587d254eba391eb4b897528 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b7554f33ae0fde4cb37245a56d7c6e7 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ab649170b5dfb3f4384ff9d6d7b04566 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Tools.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e7343d9629e2f3f419b20afdf3cd4c21 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Views.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e2c928feb1baa14b882137256715aa3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Jobx.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c975a4f60cd24ce4ea6afea61952eefc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Mathx.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed91bac67c27f61478789e808b84d71b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5742dba8ce5fcf8468bae1aaf68177eb 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/EditorBase.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e2f998eb97a8d8f4ba05ed6e4e88d517 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/EditorList.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed4918903cba41d4196d5c19605ca159 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/EditorUtils.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7da96415bde57d44bb7a4ec31db5dacc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/VX.Util.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6de75c8c8333464eb7d3caa037de423 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/Graphics.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7f963db650f4a72498c353507021ef3a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Jobx/Scan.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bb867ebaa651d39419265ed7f2d6d91f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/PropertyDrawers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2ec2f6c83255ddc4d8a19d6641389f58 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Graphics/Scan.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0c2ecc17ffac3641bf40867717e4994 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Mathx/Extensions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3965cc672c887964b8bf234248c13d94 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/VX.Util.Runtime.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b23efe0d0bd83184681bd63517e3c327 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 599dd16fa209d99498f1ce5e0325c841 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Scan.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad377e28e66f80c41a62257b45c27e5b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Util.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8c5b095be0348964389327415b3cb817 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor/VX.Util.Tests.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bdc3155a87dbe4f46b77121b754ac77e 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/RadixSort.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bcd1c096e095c6546b245949d681abc4 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Util/Util.UInt.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1b73bebfc5e682749ab40a215d18b608 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Views/SplitView.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.UIElements; 2 | 3 | namespace Voxell.Inspector 4 | { 5 | public class SplitView : TwoPaneSplitView 6 | { 7 | public new class UxmlFactory : UxmlFactory {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Util/Util.Float3.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c4e1a6c49da2d9a4eb8db6909a6a71ad 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Scan/BlellochSumScan.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20dfc71037aa9b04fa0f920db1200127 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Scan/HillisSteeleSumScan.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c61627c304f36546ae0c74b62b3ce4f 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Scan/HillisSteeleFloat3MaxScan.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 521d2342bfef1c544bc16c9fb384b3e3 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Scan/HillisSteeleFloat3MinScan.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a2cdd167b5ca12e46ab84f2070d5eaab 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Graphics/Graphics.cs: -------------------------------------------------------------------------------- 1 | namespace Voxell.Graphics 2 | { 3 | public static class Graphics 4 | { 5 | public static int S_BLOCK_SZ = 32; 6 | public static int M_BLOCK_SZ = 64; 7 | public static int L_BLOCK_SZ = 128; 8 | public static int XL_BLOCK_SZ = 512; 9 | } 10 | } -------------------------------------------------------------------------------- /Runtime/MeshUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5c72783ea488b124cb21e720c6df2fa2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/FileUtilx.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: efdde89f957b0794caa7f2213c3b112c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Jobx/Jobx.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe417a8e3165adb44802a1b2c0ba8a24 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/VXAttributes.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 360af78dadc1ca5459068357e64668ce 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Views/InspectorView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8e132f7d64bd16a44954f40707648aba 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Views/SplitView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b13070ba8c8cc2a4883e50288d655cd6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/Graphics.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5c5bf09e09c4e1f4cbef2a53e0a3013a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/RadixSort.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f8721f8686c846f47abee3131bc131e1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Jobx/RadixSortJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f7a81846c198aba448287b6b68483b92 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Jobx/ReverseJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cc2f3d90f8b116044bc1f0f7c2dec845 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Mathx/MathUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f4303df1142c5d8498d2cac93698e2da 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/GraphicsTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c0a83dcafabdc04e8af524242089b63 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/JobxTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 565a72e57c43a674cbb1c794eb1eefab 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/EditorList/GroupableList.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec74389ca64781f46b12f9a91e4f6cdb 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/EditorUtils/VXEditorUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2063d3bf7e82b544fb27728e92710018 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Tools/VoxellMenuItem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c3f596d32bf7b3c41b4a74e60bfc80f6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/StrideSize.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: add2ea565d178e2418e6d55c11230389 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Jobx/Scan/SumScanJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 17edd1d280ca99343bfd9cc231f1820b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Mathx/Extensions/mathx.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9a347507501ef2a43b92fe0305b85d3f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/RefreshMonoBehaviour.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6ccbcc227e6933a40ab9e287b4ae263e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/EditorBase/AbstractVXEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 02d3d050d274f844eabd1c88b3bdc720 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/EditorBase/VXDefaultEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 03fa54a0505b3cb4291910212df5b4c0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/EditorList/EditorListConfig.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 87647c931c2419542b20e9db5f42ca10 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/EditorList/EditorListUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f0ca383f87021f84d96b477285c2e516 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/EditorUtils/VXEditorStyles.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23d5a1597ed630742ba7283f591dc5bc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/PropertyDrawers/SceneDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e85f6afa4c2e6a4ea6fa216c41f7cd7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Tools/ShowSelectedMeshInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5402fa82c0223f74ea17b098bbbc5645 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/ComputeShaderUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e42d24669854ef4587f00b5b4a09600 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/AbstractScan.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70c268e75a796cb4f9314327ac779f79 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Jobx/Scan/Float3MaxScanJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ee49262b97f720848b4b5281e0eecba4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Jobx/Scan/Float3MinScanJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 244f724139990234ab91b554ddf96d1e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Mathx/Extensions/float2x.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: acd46621e2b78ac44b5c6c0088404118 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Mathx/Extensions/float3x.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 803a23622da44324ba8530670d71b05b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/PropertyDrawers/InspectOnlyDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 07ddce5298e882247bd9b29a0bf5d07c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/BlellochSumScan.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c2154061625acbf43ab040169f59198e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/HillisSteeleSumScan.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9852799d63dc4af42a5ab162bbd27eaa 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/PropertyDrawers/StreamingAssetDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a75afe6cb804d69479c3249220e43c1d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/HillisSteeleFloat3MaxScan.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6db8bc0a55531c54fadc68d076a313ba 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/HillisSteeleFloat3MinScan.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9a5c9f7aa60cdac43b5179f970446603 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Util/Util.Float3.compute: -------------------------------------------------------------------------------- 1 | #define BLOCK_SZ 128 2 | 3 | StructuredBuffer cb_in; 4 | RWStructuredBuffer cb_out; 5 | 6 | uniform uint _dataSize; 7 | 8 | #pragma kernel CopyBufferFloat3 9 | [numthreads(BLOCK_SZ, 1, 1)] 10 | void CopyBufferFloat3(uint DTid : SV_DISPATCHTHREADID) 11 | { 12 | if (DTid >= _dataSize) return; 13 | cb_out[DTid] = cb_in[DTid]; 14 | } -------------------------------------------------------------------------------- /Editor/VX.Util.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VX.Util.Editor", 3 | "rootNamespace": "Voxell.Inspector", 4 | "references": [ 5 | "GUID:b23efe0d0bd83184681bd63517e3c327" 6 | ], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Scan/HillisSteeleSumScan.compute: -------------------------------------------------------------------------------- 1 | // hillis steele inclusive sum scan 2 | 3 | #define BLOCK_SZ 64 4 | 5 | RWStructuredBuffer cb_in; 6 | RWStructuredBuffer cb_prev; 7 | 8 | uniform uint _len; 9 | uniform uint _offset; 10 | 11 | #pragma kernel HillisSteeleSumScan 12 | [numthreads(BLOCK_SZ, 1, 1)] 13 | void HillisSteeleSumScan(uint DTid : SV_DISPATCHTHREADID) 14 | { 15 | if (DTid >= _len) return; 16 | 17 | int sumIdx = DTid - _offset; 18 | if (sumIdx >= 0) cb_in[DTid] += cb_prev[sumIdx]; 19 | } -------------------------------------------------------------------------------- /Editor/Tools/VoxellMenuItem.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using System.Reflection; 3 | 4 | namespace Voxell.Inspector.Tools 5 | { 6 | public static class CustomMenuItem 7 | { 8 | [MenuItem ("Shortcuts/Clear Console %#d")] // CTRL + SHIFT + D 9 | public static void ClearConsole() 10 | { 11 | Assembly assembly = Assembly.GetAssembly(typeof(SceneView)); 12 | System.Type type = assembly.GetType("UnityEditor.LogEntries"); 13 | MethodInfo method = type.GetMethod("Clear"); 14 | method.Invoke(new object(), null); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Runtime/RefreshMonoBehaviour.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Voxell 4 | { 5 | [ExecuteAlways] 6 | public abstract class RefreshMonoBehaviour : MonoBehaviour 7 | { 8 | #if UNITY_EDITOR 9 | [HideInInspector] public bool _refresh = true; 10 | #endif 11 | public virtual void OnDrawGizmos() 12 | { 13 | #if UNITY_EDITOR 14 | if (_refresh) 15 | { 16 | UnityEditor.EditorApplication.QueuePlayerLoopUpdate(); 17 | UnityEditor.SceneView.RepaintAll(); 18 | } 19 | #endif 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new_feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New Feature 3 | about: Creating a new feature for this project. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Summary** 11 | 12 | A quick intro or summary on the feature you want to create. 13 | 14 | **Intended Outcome** 15 | 16 | - What is the use case of this? 17 | - How will it affect/benefit the project? 18 | 19 | **How will it work?** 20 | 21 | - How to use this feature? 22 | 23 | *finally, please assign yourself to this issue if you intend to work on this new feature thanks!* 24 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Scan/HillisSteeleFloat3MaxScan.compute: -------------------------------------------------------------------------------- 1 | // hillis steele inclusive float3 max scan 2 | 3 | #define BLOCK_SZ 64 4 | 5 | RWStructuredBuffer cb_in; 6 | StructuredBuffer cb_prev; 7 | 8 | uniform uint _len; 9 | uniform uint _offset; 10 | 11 | #pragma kernel HillisSteeleFloat3MaxScan 12 | [numthreads(BLOCK_SZ, 1, 1)] 13 | void HillisSteeleFloat3MaxScan(uint DTid : SV_DISPATCHTHREADID) 14 | { 15 | if (DTid >= _len) return; 16 | 17 | int sumIdx = DTid - _offset; 18 | if (sumIdx >= 0) cb_in[DTid] = max(cb_prev[sumIdx], cb_in[DTid]); 19 | } -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Scan/HillisSteeleFloat3MinScan.compute: -------------------------------------------------------------------------------- 1 | // hillis steele inclusive float3 min scan 2 | 3 | #define BLOCK_SZ 64 4 | 5 | RWStructuredBuffer cb_in; 6 | StructuredBuffer cb_prev; 7 | 8 | uniform uint _len; 9 | uniform uint _offset; 10 | 11 | #pragma kernel HillisSteeleFloat3MinScan 12 | [numthreads(BLOCK_SZ, 1, 1)] 13 | void HillisSteeleFloat3MinScan(uint DTid : SV_DISPATCHTHREADID) 14 | { 15 | if (DTid >= _len) return; 16 | 17 | int sumIdx = DTid - _offset; 18 | if (sumIdx >= 0) cb_in[DTid] = min(cb_prev[sumIdx], cb_in[DTid]); 19 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "voxell.util", 3 | "displayName": "VX Util", 4 | "author": "Nixon", 5 | "description": "Unity utilities to speed things up!", 6 | "keywords": [ 7 | "util", 8 | "voxell" 9 | ], 10 | "license": "Apache 2.0", 11 | "unity": "2020.3", 12 | "version": "1.4.3", 13 | "dependencies": { 14 | "com.unity.mathematics": "1.2.6", 15 | "com.unity.collections": "1.2.3", 16 | "com.unity.jobs": "0.50.0-preview.9", 17 | "com.unity.burst": "1.6.5", 18 | "com.unity.test-framework": "1.1.30" 19 | }, 20 | "hideInEditor": false 21 | } -------------------------------------------------------------------------------- /Runtime/Jobx/Jobx.cs: -------------------------------------------------------------------------------- 1 | namespace Voxell.Jobx 2 | { 3 | public static class Jobx 4 | { 5 | // how to use?? 6 | // if the computation of each element is fairly simple, 7 | // use a larger batch size and vice versa 8 | 9 | // obviously, there are lots of factors playing here, 10 | // so use the unity's profiler to benchmark your algorithm 11 | // running on different batch sizes 12 | public const int XS_BATCH_SIZE = 64; 13 | public const int S_BATCH_SIZE = 128; 14 | public const int M_BATCH_SIZE = 256; 15 | public const int L_BATCH_SIZE = 512; 16 | public const int XL_BATCH_SIZE = 1024; 17 | } 18 | } -------------------------------------------------------------------------------- /Editor/EditorBase/AbstractVXEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | 4 | namespace Voxell.Inspector 5 | { 6 | public abstract class AbstractVXEditor : Editor 7 | { 8 | public abstract void OnEnable(); 9 | 10 | public virtual void OnRender() => base.OnInspectorGUI(); 11 | 12 | public override void OnInspectorGUI() 13 | { 14 | serializedObject.Update(); 15 | EditorGUI.BeginChangeCheck(); 16 | 17 | OnRender(); 18 | 19 | if (EditorGUI.EndChangeCheck()) OnChange(); 20 | serializedObject.ApplyModifiedProperties(); 21 | } 22 | 23 | public virtual void OnChange() {} 24 | } 25 | } -------------------------------------------------------------------------------- /Runtime/VX.Util.Runtime.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VX.Util.Runtime", 3 | "rootNamespace": "Voxell", 4 | "references": [ 5 | "GUID:d8b63aba1907145bea998dd612889d6b", 6 | "GUID:e0cd26848372d4e5c891c569017e11f1", 7 | "GUID:8a2eafa29b15f444eb6d74f94a930e1d", 8 | "GUID:2665a8d13d1b3f18800f46e256720795" 9 | ], 10 | "includePlatforms": [], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": false, 13 | "overrideReferences": false, 14 | "precompiledReferences": [], 15 | "autoReferenced": true, 16 | "defineConstraints": [], 17 | "versionDefines": [], 18 | "noEngineReferences": false 19 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: voxelltech 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: voxelltech 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ["paypal.me/voxelltechnologies"] -------------------------------------------------------------------------------- /Runtime/VXAttributes.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | 4 | namespace Voxell.Inspector 5 | { 6 | public class InspectOnlyAttribute : PropertyAttribute {} 7 | public class SceneAttribute : PropertyAttribute {} 8 | 9 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 10 | public class ButtonAttribute : Attribute 11 | { 12 | public string buttonName { get; private set; } 13 | public ButtonAttribute(string buttonName="") => this.buttonName = buttonName; 14 | } 15 | 16 | public class StreamingAssetFilePathAttribute : PropertyAttribute {} 17 | public class StreamingAssetFolderPathAttribute : PropertyAttribute {} 18 | } -------------------------------------------------------------------------------- /Editor/PropertyDrawers/InspectOnlyDrawer.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace Voxell.Inspector 5 | { 6 | [CustomPropertyDrawer(typeof(InspectOnlyAttribute))] 7 | public class InspectOnlyDrawer : PropertyDrawer 8 | { 9 | public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) 10 | { 11 | bool guiEnabled = GUI.enabled; 12 | GUI.enabled = false; 13 | EditorGUI.PropertyField(rect, property, label, true); 14 | GUI.enabled = guiEnabled; 15 | } 16 | 17 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label) 18 | => EditorGUI.GetPropertyHeight(property, true); 19 | } 20 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /Editor/EditorList/EditorListConfig.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | 3 | namespace Voxell.Inspector.List 4 | { 5 | public struct EditorListConfig 6 | { 7 | public static readonly EditorListConfig Default = new EditorListConfig 8 | { 9 | draggable = true, 10 | displayHeader = true, 11 | displayAddButton = true, 12 | displayRemoveButton = true, 13 | multiSelect = true, 14 | 15 | prefix = "", 16 | header = "", 17 | emptyMsg = "", 18 | }; 19 | 20 | public bool draggable; 21 | public bool displayHeader; 22 | public bool displayAddButton; 23 | public bool displayRemoveButton; 24 | public bool multiSelect; 25 | 26 | public string prefix; 27 | public string header; 28 | public string emptyMsg; 29 | } 30 | } -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Util/Util.UInt.compute: -------------------------------------------------------------------------------- 1 | #define BLOCK_SZ 128 2 | 3 | StructuredBuffer cb_in; 4 | RWStructuredBuffer cb_out; 5 | 6 | uniform uint _dataSize; 7 | 8 | #pragma kernel CopyBuffer 9 | [numthreads(BLOCK_SZ, 1, 1)] 10 | void CopyBuffer(uint DTid : SV_DISPATCHTHREADID) 11 | { 12 | if (DTid >= _dataSize) return; 13 | cb_out[DTid] = cb_in[DTid]; 14 | } 15 | 16 | #pragma kernel ZeroOut 17 | [numthreads(BLOCK_SZ, 1, 1)] 18 | void ZeroOut(uint DTid : SV_DISPATCHTHREADID) 19 | { 20 | if (DTid >= _dataSize) return; 21 | cb_out[DTid] = 0; 22 | } 23 | 24 | #pragma kernel SetBufferAsThreadIdx 25 | [numthreads(BLOCK_SZ, 1, 1)] 26 | void SetBufferAsThreadIdx(uint DTid : SV_DISPATCHTHREADID) 27 | { 28 | if (DTid >= _dataSize) return; 29 | cb_out[DTid] = DTid; 30 | } -------------------------------------------------------------------------------- /Tests/Editor/VX.Util.Tests.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VX.Util.Tests.Editor", 3 | "rootNamespace": "Voxell", 4 | "references": [ 5 | "UnityEngine.TestRunner", 6 | "UnityEditor.TestRunner", 7 | "VX.Util.Runtime", 8 | "Unity.Mathematics", 9 | "Unity.Collections", 10 | "Unity.Jobs", 11 | "Unity.Burst" 12 | ], 13 | "includePlatforms": [ 14 | "Editor" 15 | ], 16 | "excludePlatforms": [], 17 | "allowUnsafeCode": false, 18 | "overrideReferences": true, 19 | "precompiledReferences": [ 20 | "nunit.framework.dll" 21 | ], 22 | "autoReferenced": false, 23 | "defineConstraints": [ 24 | "UNITY_INCLUDE_TESTS" 25 | ], 26 | "versionDefines": [], 27 | "noEngineReferences": false 28 | } -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/AbstractScan.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Voxell.Graphics 4 | { 5 | public abstract class AbstractScan : System.IDisposable 6 | { 7 | private protected static class PropertyID 8 | { 9 | public static readonly int len = Shader.PropertyToID("_len"); 10 | public static readonly int offset = Shader.PropertyToID("_offset"); 11 | } 12 | 13 | private protected static class BufferID 14 | { 15 | public static readonly int cb_in = Shader.PropertyToID("cb_in"); 16 | public static readonly int cb_out = Shader.PropertyToID("cb_out"); 17 | public static readonly int cb_prev = Shader.PropertyToID("cb_prev"); 18 | public static readonly int cb_blockSums = Shader.PropertyToID("cb_blockSums"); 19 | } 20 | 21 | public abstract void Dispose(); 22 | } 23 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /Runtime/Mathx/Extensions/float3x.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Unity.Mathematics; 3 | 4 | namespace Voxell.Mathx 5 | { 6 | public static class float3x 7 | { 8 | /// Shorthand for writing float3(0, 0, 1). 9 | public static readonly float3 one = new float3(1.0f, 1.0f, 1.0f); 10 | 11 | /// Shorthand for writing float3(0, 0, 1). 12 | public static readonly float3 forward = new float3(0.0f, 0.0f, 1.0f); 13 | 14 | /// Shorthand for writing float3(0, 0, -1). 15 | public static readonly float3 back = new float3(0.0f, 0.0f, -1.0f); 16 | 17 | /// Shorthand for writing float3(-1, 0, 0). 18 | public static readonly float3 left = new float3(-1.0f, 0.0f, 0.0f); 19 | 20 | /// Shorthand for writing float3(1, 0, 0). 21 | public static readonly float3 right = new float3(1.0f, 0.0f, 0.0f); 22 | 23 | /// Shorthand for writing float3(0, 1, 0). 24 | public static readonly float3 up = new float3(0.0f, 1.0f, 0.0f); 25 | 26 | /// Shorthand for writing float3(0, -1, 0). 27 | public static readonly float3 down = new float3(0.0f, -1.0f, 0.0f); 28 | } 29 | } -------------------------------------------------------------------------------- /Runtime/Mathx/Extensions/float2x.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using UnityEngine; 3 | using Unity.Mathematics; 4 | 5 | namespace Voxell.Mathx 6 | { 7 | public static class float2x 8 | { 9 | /// Shorthand for writing float2(-1, 0). 10 | public static readonly float2 left = new float2(-1.0f, 0.0f); 11 | 12 | /// Shorthand for writing float2(1, 0). 13 | public static readonly float2 right = new float2(1.0f, 0.0f); 14 | 15 | /// Shorthand for writing float2(0, 1). 16 | public static readonly float2 up = new float2(0.0f, 1.0f); 17 | 18 | /// Shorthand for writing float2(0, -1). 19 | public static readonly float2 down = new float2(0.0f, -1.0f); 20 | 21 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 22 | public static float2 perpendicular(this float2 vector) => new float2(-vector.y, vector.x); 23 | 24 | // Returns the angle in degrees between /from/ and /to/. 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static float angle(this float2 from, float2 to) 27 | { 28 | // sqrt(a) * sqrt(b) = sqrt(a * b) -- valid for real numbers 29 | float denominator = (float)math.sqrt(math.lengthsq(from) * math.lengthsq(to)); 30 | if (denominator < Vector2.kEpsilonNormalSqrt) return 0.0f; 31 | 32 | float dot = math.clamp(math.dot(from, to) / denominator, -1.0f, 1.0f); 33 | return math.acos(dot) * Mathf.Rad2Deg; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Runtime/Jobx/ReverseJob.cs: -------------------------------------------------------------------------------- 1 | using Unity.Collections; 2 | using Unity.Jobs; 3 | using Unity.Burst; 4 | 5 | namespace Voxell.Jobx 6 | { 7 | public class ReverseJob where T : struct 8 | { 9 | private int _arraySize; 10 | private int _jobSize; 11 | 12 | private NativeArray na_array; 13 | private ReverseArrayJob reverseArrayJob; 14 | 15 | public ReverseJob(ref NativeArray na_array) 16 | { 17 | this._arraySize = na_array.Length; 18 | this._jobSize = na_array.Length/2; 19 | this.na_array = na_array; 20 | 21 | reverseArrayJob = new ReverseArrayJob(ref na_array, _arraySize); 22 | } 23 | 24 | /// Reverse native array in parallel. 25 | public void ReverseArray() 26 | { 27 | JobHandle jobHandle = reverseArrayJob.Schedule(_jobSize, Jobx.XL_BATCH_SIZE); 28 | jobHandle.Complete(); 29 | } 30 | 31 | [BurstCompile] 32 | private struct ReverseArrayJob : IJobParallelFor 33 | { 34 | public int arraySize; 35 | [NativeDisableParallelForRestriction] public NativeArray na_array; 36 | 37 | public ReverseArrayJob(ref NativeArray na_array, int arraySize) 38 | { 39 | this.na_array = na_array; 40 | this.arraySize = arraySize; 41 | } 42 | 43 | public void Execute(int index) 44 | { 45 | T elem = na_array[index]; 46 | na_array[index] = na_array[arraySize - index]; 47 | na_array[arraySize - index] = elem; 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Editor/PropertyDrawers/SceneDrawer.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace Voxell.Inspector 5 | { 6 | [CustomPropertyDrawer(typeof(SceneAttribute))] 7 | public class SceneDrawer : PropertyDrawer 8 | { 9 | public override void OnGUI (Rect rect, SerializedProperty property, GUIContent label) 10 | { 11 | if (property.propertyType == SerializedPropertyType.String) 12 | { 13 | SceneAsset sceneObject = GetSceneObject(property.stringValue); 14 | SceneAsset scene = EditorGUI.ObjectField(rect, label, sceneObject, typeof(SceneAsset), true) as SceneAsset; 15 | if (scene == null) 16 | { 17 | property.stringValue = ""; 18 | } else if (scene.name != property.stringValue) 19 | { 20 | SceneAsset sceneObj = GetSceneObject(scene.name); 21 | if (sceneObj == null) 22 | Debug.LogWarning($"The scene {scene.name} cannot be used. To use this scene add it to the build settings for the project"); 23 | else property.stringValue = scene.name; 24 | } 25 | } 26 | else EditorGUI.LabelField(rect, label.text, "Use [Scene] with strings."); 27 | } 28 | 29 | private SceneAsset GetSceneObject(string sceneObjectName) 30 | { 31 | if (string.IsNullOrEmpty(sceneObjectName)) return null; 32 | 33 | foreach (EditorBuildSettingsScene editorScene in EditorBuildSettings.scenes) 34 | { 35 | if (editorScene.path.IndexOf(sceneObjectName) != -1) 36 | return AssetDatabase.LoadAssetAtPath(editorScene.path); 37 | } 38 | Debug.LogWarning($"Scene [{sceneObjectName}] cannot be used. Add this scene to the 'Scenes in the Build' in build settings."); 39 | return null; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/HillisSteeleSumScan.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Profiling; 3 | 4 | namespace Voxell.Graphics 5 | { 6 | using Mathx; 7 | 8 | public sealed class HillisSteeleSumScan : AbstractScan 9 | { 10 | private static ComputeShader cs_hillisSteeleSumScan; 11 | private static int kn_hillisSteeleSumScan; 12 | 13 | private readonly int _dataSize; 14 | private readonly int _gridSize; 15 | 16 | private ComputeBuffer cb_prev; 17 | 18 | public HillisSteeleSumScan(int dataSize) 19 | { 20 | _dataSize = dataSize; 21 | _gridSize = MathUtil.CalculateGrids(_dataSize, Graphics.M_BLOCK_SZ); 22 | cb_prev = new ComputeBuffer(dataSize, StrideSize.s_uint); 23 | } 24 | 25 | public static void InitKernels() 26 | { 27 | if (cs_hillisSteeleSumScan != null) return; 28 | cs_hillisSteeleSumScan = Resources.Load("Scan/HillisSteeleSumScan"); 29 | kn_hillisSteeleSumScan = cs_hillisSteeleSumScan.FindKernel("HillisSteeleSumScan"); 30 | } 31 | 32 | public void Scan(ref ComputeBuffer cb_in) 33 | { 34 | Profiler.BeginSample("HillisSteeleSumScan"); 35 | cs_hillisSteeleSumScan.SetInt(PropertyID.len, _dataSize); 36 | cs_hillisSteeleSumScan.SetBuffer(kn_hillisSteeleSumScan, BufferID.cb_in, cb_in); 37 | cs_hillisSteeleSumScan.SetBuffer(kn_hillisSteeleSumScan, BufferID.cb_prev, cb_prev); 38 | 39 | for (int offset=1; offset < _dataSize; offset <<= 1) 40 | { 41 | ComputeShaderUtil.CopyBuffer(ref cb_in, ref cb_prev, _dataSize); 42 | cs_hillisSteeleSumScan.SetInt(PropertyID.offset, offset); 43 | cs_hillisSteeleSumScan.Dispatch(kn_hillisSteeleSumScan, _gridSize, 1, 1); 44 | } 45 | Profiler.EndSample(); 46 | } 47 | 48 | public override void Dispose() 49 | { 50 | cb_prev.Dispose(); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Editor/EditorList/GroupableList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using UnityEditor; 4 | using UnityEditorInternal; 5 | 6 | namespace Voxell.Inspector.List 7 | { 8 | public sealed class GroupableList : ReorderableList 9 | { 10 | public readonly int GroupIdx; 11 | 12 | public GroupableList( 13 | SerializedObject serializedObject, SerializedProperty elements, int groupIdx 14 | ) : base(serializedObject, elements) => GroupIdx = groupIdx; 15 | 16 | public GroupableList( 17 | IList elements, Type elementType, int groupIdx 18 | ) : base(elements, elementType) => GroupIdx = groupIdx; 19 | 20 | public GroupableList( 21 | SerializedObject serializedObject, SerializedProperty elements, int groupIdx, 22 | bool draggable, bool displayHeader, bool displayAddButton, bool displayRemoveButton 23 | ) : base ( 24 | serializedObject, elements, draggable, displayHeader, displayAddButton, displayRemoveButton 25 | ) => GroupIdx = groupIdx; 26 | 27 | public GroupableList( 28 | IList elements, Type elementType, int groupIdx, 29 | bool draggable, bool displayHeader, bool displayAddButton, bool displayRemoveButton 30 | ) : base ( 31 | elements, elementType, draggable, displayHeader, displayAddButton, displayRemoveButton 32 | ) => GroupIdx = groupIdx; 33 | 34 | public static GroupableList Create( 35 | SerializedObject serializedObject, SerializedProperty property, int groupIdx, EditorListConfig listConfig 36 | ) 37 | { 38 | GroupableList groupableList = new GroupableList( 39 | serializedObject, property, groupIdx, 40 | listConfig.draggable, listConfig.displayHeader, 41 | listConfig.displayAddButton, listConfig.displayRemoveButton 42 | ); 43 | 44 | EditorListUtil.InitializeReorderableList(groupableList, listConfig); 45 | 46 | return groupableList; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Editor/Views/InspectorView.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UIElements; 3 | using UnityEditor; 4 | 5 | namespace Voxell.Inspector 6 | { 7 | public class InspectorView : VisualElement 8 | { 9 | public new class UxmlFactory : UxmlFactory {} 10 | private Editor _editor; 11 | 12 | public Editor InitializeInspector(Object obj) => InitializeInspector(obj, null); 13 | public Editor InitializeInspector(Object obj, System.Type editorType) 14 | { 15 | ClearEditor(); 16 | 17 | _editor = CreateEditor(obj, editorType); 18 | IMGUIContainer container = new IMGUIContainer(_editor.OnInspectorGUI); 19 | ScrollView scrollView = new ScrollView(); 20 | scrollView.Add(container); 21 | Add(scrollView); 22 | 23 | return _editor; 24 | } 25 | 26 | public Editor InitializeInspector(Object[] objs) => InitializeInspector(objs, null); 27 | public Editor InitializeInspector(Object[] objs, System.Type editorType) 28 | { 29 | ClearEditor(); 30 | 31 | _editor = CreateEditor(objs, editorType); 32 | IMGUIContainer container = new IMGUIContainer(_editor.OnInspectorGUI); 33 | ScrollView scrollView = new ScrollView(); 34 | scrollView.Add(container); 35 | Add(scrollView); 36 | 37 | return _editor; 38 | } 39 | 40 | public void ClearEditor() 41 | { 42 | Clear(); 43 | Object.DestroyImmediate(_editor); 44 | } 45 | 46 | private static Editor CreateEditor(Object[] objs, System.Type editorType) 47 | { 48 | if (editorType == null) return Editor.CreateEditor(objs); 49 | return Editor.CreateEditor(objs, editorType); 50 | } 51 | 52 | private static Editor CreateEditor(Object obj, System.Type editorType) 53 | { 54 | if (editorType == null) return Editor.CreateEditor(obj); 55 | return Editor.CreateEditor(obj, editorType); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/HillisSteeleFloat3MaxScan.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Profiling; 3 | 4 | namespace Voxell.Graphics 5 | { 6 | using Mathx; 7 | 8 | public sealed class HillisSteeleFloat3MaxScan : AbstractScan 9 | { 10 | private static ComputeShader cs_hillisSteeleFloat3MaxScan; 11 | private static int kn_hillisSteeleFloat3MaxScan; 12 | 13 | private readonly int _dataSize; 14 | private readonly int _gridSize; 15 | 16 | private ComputeBuffer cb_prev; 17 | 18 | public HillisSteeleFloat3MaxScan(int dataSize) 19 | { 20 | _dataSize = dataSize; 21 | _gridSize = MathUtil.CalculateGrids(_dataSize, Graphics.M_BLOCK_SZ); 22 | cb_prev = new ComputeBuffer(dataSize, StrideSize.s_float3); 23 | } 24 | 25 | public static void InitKernels() 26 | { 27 | if (cs_hillisSteeleFloat3MaxScan != null) return; 28 | cs_hillisSteeleFloat3MaxScan = Resources.Load("Scan/HillisSteeleFloat3MaxScan"); 29 | kn_hillisSteeleFloat3MaxScan = cs_hillisSteeleFloat3MaxScan.FindKernel("HillisSteeleFloat3MaxScan"); 30 | } 31 | 32 | public void Scan(ref ComputeBuffer cb_in) 33 | { 34 | Profiler.BeginSample("HillisSteeleFloat3MaxScan"); 35 | cs_hillisSteeleFloat3MaxScan.SetInt(PropertyID.len, _dataSize); 36 | cs_hillisSteeleFloat3MaxScan.SetBuffer(kn_hillisSteeleFloat3MaxScan, BufferID.cb_in, cb_in); 37 | cs_hillisSteeleFloat3MaxScan.SetBuffer(kn_hillisSteeleFloat3MaxScan, BufferID.cb_prev, cb_prev); 38 | 39 | for (int offset=1; offset < _dataSize; offset <<= 1) 40 | { 41 | ComputeShaderUtil.CopyBufferFloat3(ref cb_in, ref cb_prev, _dataSize); 42 | cs_hillisSteeleFloat3MaxScan.SetInt(PropertyID.offset, offset); 43 | cs_hillisSteeleFloat3MaxScan.Dispatch(kn_hillisSteeleFloat3MaxScan, _gridSize, 1, 1); 44 | } 45 | Profiler.EndSample(); 46 | } 47 | 48 | public override void Dispose() 49 | { 50 | cb_prev.Dispose(); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/HillisSteeleFloat3MinScan.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Profiling; 3 | 4 | namespace Voxell.Graphics 5 | { 6 | using Mathx; 7 | 8 | public sealed class HillisSteeleFloat3MinScan : AbstractScan 9 | { 10 | private static ComputeShader cs_hillisSteeleFloat3MinScan; 11 | private static int kn_hillisSteeleFloat3MinScan; 12 | 13 | private readonly int _dataSize; 14 | private readonly int _gridSize; 15 | 16 | private ComputeBuffer cb_prev; 17 | 18 | public HillisSteeleFloat3MinScan(int dataSize) 19 | { 20 | _dataSize = dataSize; 21 | _gridSize = MathUtil.CalculateGrids(_dataSize, Graphics.M_BLOCK_SZ); 22 | cb_prev = new ComputeBuffer(dataSize, StrideSize.s_float3); 23 | } 24 | 25 | public static void InitKernels() 26 | { 27 | if (cs_hillisSteeleFloat3MinScan != null) return; 28 | cs_hillisSteeleFloat3MinScan = Resources.Load("Scan/HillisSteeleFloat3MinScan"); 29 | kn_hillisSteeleFloat3MinScan = cs_hillisSteeleFloat3MinScan.FindKernel("HillisSteeleFloat3MinScan"); 30 | } 31 | 32 | public void Scan(ref ComputeBuffer cb_in) 33 | { 34 | Profiler.BeginSample("HillisSteeleFloat3MinScan"); 35 | cs_hillisSteeleFloat3MinScan.SetInt(PropertyID.len, _dataSize); 36 | cs_hillisSteeleFloat3MinScan.SetBuffer(kn_hillisSteeleFloat3MinScan, BufferID.cb_in, cb_in); 37 | cs_hillisSteeleFloat3MinScan.SetBuffer(kn_hillisSteeleFloat3MinScan, BufferID.cb_prev, cb_prev); 38 | 39 | for (int offset=1; offset < _dataSize; offset <<= 1) 40 | { 41 | ComputeShaderUtil.CopyBufferFloat3(ref cb_in, ref cb_prev, _dataSize); 42 | cs_hillisSteeleFloat3MinScan.SetInt(PropertyID.offset, offset); 43 | cs_hillisSteeleFloat3MinScan.Dispatch(kn_hillisSteeleFloat3MinScan, _gridSize, 1, 1); 44 | } 45 | Profiler.EndSample(); 46 | } 47 | 48 | public override void Dispose() 49 | { 50 | cb_prev.Dispose(); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Editor/EditorUtils/VXEditorUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEngine; 6 | using UnityEditor; 7 | 8 | namespace Voxell.Inspector 9 | { 10 | public static class VXEditorUtil 11 | { 12 | public static readonly Color DefaultBackgroundColor = GUI.backgroundColor; 13 | public static readonly Color DefaultContentColor = GUI.contentColor; 14 | public static readonly float DefaultLabelWidth = EditorGUIUtility.labelWidth; 15 | public static readonly float DefaultFieldWidth = EditorGUIUtility.fieldWidth; 16 | 17 | public static IEnumerable GetAllMethods(object target, Func predicate) 18 | { 19 | if (target == null) 20 | { 21 | Debug.LogError("The target object is null. Check for missing scripts."); 22 | yield break; 23 | } 24 | 25 | List types = GetSelfAndBaseTypes(target); 26 | 27 | for (int i = types.Count - 1; i >= 0; i--) 28 | { 29 | IEnumerable methodInfos = types[i] 30 | .GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly) 31 | .Where(predicate); 32 | 33 | foreach (MethodInfo methodInfo in methodInfos) 34 | { 35 | yield return methodInfo; 36 | } 37 | } 38 | } 39 | 40 | /// 41 | /// Get type and all base types of target, sorted as following: 42 | /// [target's type, base type, base's base type, ...] 43 | /// 44 | /// 45 | /// 46 | private static List GetSelfAndBaseTypes(object target) 47 | { 48 | List types = new List() 49 | { 50 | target.GetType() 51 | }; 52 | 53 | while (types.Last().BaseType != null) 54 | { 55 | types.Add(types.Last().BaseType); 56 | } 57 | 58 | return types; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Runtime/Mathx/Extensions/mathx.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Unity.Mathematics; 3 | 4 | namespace Voxell.Mathx 5 | { 6 | public static class mathx 7 | { 8 | public const float ONE_THIRD = 1.0f/3.0f; 9 | 10 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 11 | public static bool approximately(float a, float b) 12 | { 13 | // If a or b is zero, compare that the other is less or equal to epsilon. 14 | // If neither a or b are 0, then find an epsilon that is good for 15 | // comparing numbers at the maximum magnitude of a and b. 16 | // Floating points have about 7 significant digits, so 17 | // 1.000001f can be represented while 1.0000001f is rounded to zero, 18 | // thus we could use an epsilon of 0.000001f for comparing values close to 1. 19 | // We multiply this epsilon by the biggest magnitude of a and b. 20 | return math.abs(b - a) < math.max(0.000001f * math.max(math.abs(a), math.abs(b)), math.EPSILON * 8); 21 | } 22 | 23 | /// Check if number is close to zero. 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static bool approximately_zero(float a) => math.abs(a) < 0.000001f; 26 | 27 | /// Inverse lerp. 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | public static float invlerp(float from, float to, float value) => (value - from) / (to - from); 30 | 31 | /// Inverse lerp. 32 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 33 | public static float2 invlerp(float2 from, float2 to, float2 value) => (value - from) / (to - from); 34 | 35 | /// Inverse lerp. 36 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 37 | public static float3 invlerp(float3 from, float3 to, float3 value) => (value - from) / (to - from); 38 | 39 | /// Inverse lerp. 40 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 41 | public static float4 invlerp(float4 from, float4 to, float4 value) => (value - from) / (to - from); 42 | } 43 | } -------------------------------------------------------------------------------- /Runtime/Jobx/Scan/SumScanJob.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.Profiling; 2 | using Unity.Collections; 3 | using Unity.Jobs; 4 | using Unity.Burst; 5 | 6 | namespace Voxell.Jobx 7 | { 8 | public class SumScanJob : System.IDisposable 9 | { 10 | private int _arrayLength; 11 | private NativeArray na_array; 12 | private NativeArray na_prevArray; 13 | private HillisSteeleSumScanJob sumScanJob; 14 | 15 | public SumScanJob(ref NativeArray na_array) 16 | { 17 | this._arrayLength = na_array.Length; 18 | this.na_array = na_array; 19 | this.na_prevArray = new NativeArray(na_array, Allocator.Persistent); 20 | this.sumScanJob = new HillisSteeleSumScanJob(ref na_array, ref na_prevArray); 21 | } 22 | 23 | /// Perform a Hillis Steele inclusive sum scan. 24 | public void InclusiveSumScan() 25 | { 26 | Profiler.BeginSample("InclusiveSumScan"); 27 | JobHandle jobHandle; 28 | 29 | for (int offset=1; offset < _arrayLength; offset <<= 1) 30 | { 31 | na_prevArray.CopyFrom(na_array); 32 | sumScanJob.offset = offset; 33 | jobHandle = sumScanJob.Schedule(_arrayLength, Jobx.XL_BATCH_SIZE); 34 | jobHandle.Complete(); 35 | } 36 | Profiler.EndSample(); 37 | } 38 | 39 | [BurstCompile(CompileSynchronously = true)] 40 | private struct HillisSteeleSumScanJob : IJobParallelFor 41 | { 42 | public int offset; 43 | 44 | public NativeArray na_array; 45 | [NativeDisableParallelForRestriction, ReadOnly] 46 | public NativeArray na_prevArray; 47 | 48 | public HillisSteeleSumScanJob(ref NativeArray na_array, ref NativeArray na_prevArray) 49 | { 50 | this.na_array = na_array; 51 | this.na_prevArray = na_prevArray; 52 | this.offset = 1; 53 | } 54 | 55 | public void Execute(int index) 56 | { 57 | int sumIdx = index - offset; 58 | if (sumIdx >= 0) na_array[index] += na_prevArray[sumIdx]; 59 | } 60 | } 61 | 62 | public void Dispose() => na_prevArray.Dispose(); 63 | } 64 | } -------------------------------------------------------------------------------- /Runtime/Jobx/Scan/Float3MaxScanJob.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.Profiling; 2 | using Unity.Mathematics; 3 | using Unity.Collections; 4 | using Unity.Jobs; 5 | using Unity.Burst; 6 | 7 | namespace Voxell.Jobx 8 | { 9 | public sealed class Float3MaxScanJob : System.IDisposable 10 | { 11 | private int _valueCount; 12 | private NativeArray na_values; 13 | private NativeArray na_prevValues; 14 | private HillisSteeleFloat3MaxScanJob maxScanJob; 15 | 16 | public Float3MaxScanJob(ref NativeArray na_values) 17 | { 18 | this._valueCount = na_values.Length; 19 | this.na_values = na_values; 20 | this.na_prevValues = new NativeArray(na_values, Allocator.Persistent); 21 | 22 | this.maxScanJob = new HillisSteeleFloat3MaxScanJob( 23 | ref na_values, ref na_prevValues 24 | ); 25 | } 26 | 27 | /// Perform a Hillis Steele inclusive max scan. 28 | public void InclusiveMaxScan() 29 | { 30 | Profiler.BeginSample("InclusiveMaxScan"); 31 | JobHandle jobHandle; 32 | for (int offset=1; offset < _valueCount; offset <<= 1) 33 | { 34 | na_prevValues.CopyFrom(na_values); 35 | maxScanJob.offset = offset; 36 | jobHandle = maxScanJob.Schedule(_valueCount, Jobx.XL_BATCH_SIZE); 37 | jobHandle.Complete(); 38 | } 39 | Profiler.EndSample(); 40 | } 41 | 42 | [BurstCompile(CompileSynchronously = true)] 43 | private struct HillisSteeleFloat3MaxScanJob : IJobParallelFor 44 | { 45 | public int offset; 46 | 47 | public NativeArray na_values; 48 | [NativeDisableParallelForRestriction, ReadOnly] 49 | public NativeArray na_prevValues; 50 | 51 | public HillisSteeleFloat3MaxScanJob( 52 | ref NativeArray na_values, ref NativeArray na_prevValues 53 | ) 54 | { 55 | this.na_values = na_values; 56 | this.na_prevValues = na_prevValues; 57 | this.offset = 1; 58 | } 59 | 60 | public void Execute(int index) 61 | { 62 | int sumIdx = index - offset; 63 | if (sumIdx >= 0) na_values[index] = math.max(na_values[index], na_prevValues[sumIdx]); 64 | } 65 | } 66 | 67 | public void Dispose() => na_prevValues.Dispose(); 68 | } 69 | } -------------------------------------------------------------------------------- /Runtime/Jobx/Scan/Float3MinScanJob.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.Profiling; 2 | using Unity.Mathematics; 3 | using Unity.Collections; 4 | using Unity.Jobs; 5 | using Unity.Burst; 6 | 7 | namespace Voxell.Jobx 8 | { 9 | public sealed class Float3MinScanJob : System.IDisposable 10 | { 11 | private int _valueCount; 12 | private NativeArray na_values; 13 | private NativeArray na_prevValues; 14 | private HillisSteeleFloat3MinScanJob minScanJob; 15 | 16 | public Float3MinScanJob(ref NativeArray na_values) 17 | { 18 | this._valueCount = na_values.Length; 19 | this.na_values = na_values; 20 | this.na_prevValues = new NativeArray(na_values, Allocator.Persistent); 21 | 22 | this.minScanJob = new HillisSteeleFloat3MinScanJob( 23 | ref na_values, ref na_prevValues 24 | ); 25 | } 26 | 27 | /// Perform a Hillis Steele inclusive max scan. 28 | public void InclusiveMinScan() 29 | { 30 | Profiler.BeginSample("InclusiveMinScan"); 31 | JobHandle jobHandle; 32 | 33 | for (int offset=1; offset < _valueCount; offset <<= 1) 34 | { 35 | na_prevValues.CopyFrom(na_values); 36 | minScanJob.offset = offset; 37 | jobHandle = minScanJob.Schedule(_valueCount, Jobx.XL_BATCH_SIZE); 38 | jobHandle.Complete(); 39 | } 40 | Profiler.EndSample(); 41 | } 42 | 43 | [BurstCompile(CompileSynchronously = true)] 44 | private struct HillisSteeleFloat3MinScanJob : IJobParallelFor 45 | { 46 | public int offset; 47 | 48 | public NativeArray na_values; 49 | [NativeDisableParallelForRestriction, ReadOnly] 50 | public NativeArray na_prevValues; 51 | 52 | public HillisSteeleFloat3MinScanJob( 53 | ref NativeArray na_values, ref NativeArray na_prevValues 54 | ) 55 | { 56 | this.na_values = na_values; 57 | this.na_prevValues = na_prevValues; 58 | this.offset = 1; 59 | } 60 | 61 | public void Execute(int index) 62 | { 63 | int sumIdx = index - offset; 64 | if (sumIdx >= 0) na_values[index] = math.min(na_values[index], na_prevValues[sumIdx]); 65 | } 66 | } 67 | 68 | public void Dispose() => na_prevValues.Dispose(); 69 | } 70 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | __pycache__/ 3 | checkpoints/ 4 | inference/ 5 | env/ 6 | temp/ 7 | build/ 8 | 9 | # This .gitignore file should be placed at the root of your Unity project directory 10 | # 11 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 12 | # 13 | /[Ll]ibrary/ 14 | /[Tt]emp/ 15 | /[Oo]bj/ 16 | /[Bb]uild/ 17 | /[Bb]uilds/ 18 | /[Ll]ogs/ 19 | /[Uu]ser[Ss]ettings/ 20 | /[Rr]ecordings/ 21 | /[Rr]eleases/ 22 | /[Rr]elease/ 23 | 24 | 25 | # MemoryCaptures can get excessive in size. 26 | # They also could contain extremely sensitive data 27 | /[Mm]emoryCaptures/ 28 | 29 | # Asset meta data should only be ignored when the corresponding asset is also ignored 30 | !/[Aa]ssets/**/*.meta 31 | 32 | # Uncomment this line if you wish to ignore the asset store tools plugin 33 | # /[Aa]ssets/AssetStoreTools* 34 | 35 | # Autogenerated Jetbrains Rider plugin 36 | /[Aa]ssets/Plugins/Editor/JetBrains* 37 | 38 | # Visual Studio cache directory 39 | .vs/ 40 | 41 | # Gradle cache directory 42 | .gradle/ 43 | 44 | # Autogenerated VS/MD/Consulo solution and project files 45 | ExportedObj/ 46 | .consulo/ 47 | *.csproj 48 | *.unityproj 49 | *.sln 50 | *.suo 51 | *.tmp 52 | *.user 53 | *.userprefs 54 | *.pidb 55 | *.booproj 56 | *.svd 57 | *.pdb 58 | *.mdb 59 | *.opendb 60 | *.VC.db 61 | 62 | # Unity3D generated meta files 63 | *.pidb.meta 64 | *.pdb.meta 65 | *.mdb.meta 66 | 67 | # Unity3D generated file on crash reports 68 | sysinfo.txt 69 | 70 | # Builds 71 | *.apk 72 | *.aab 73 | *.unitypackage 74 | *.unitypackage.meta 75 | *.exe 76 | 77 | # Crashlytics generated file 78 | crashlytics-build.properties 79 | 80 | # Packed Addressables 81 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* 82 | 83 | # Temporary auto-generated Android Assets 84 | /[Aa]ssets/[Ss]treamingAssets/aa.meta 85 | /[Aa]ssets/[Ss]treamingAssets/aa/* 86 | 87 | # Tensorflow trained checkpoints and weights 88 | *.h5 89 | *.h5.meta 90 | *.pbmm 91 | *.pbmm.meta 92 | *.tflite 93 | *.tflite.meta 94 | 95 | # API keys 96 | *.apikey 97 | 98 | # pycaches 99 | *.pyc 100 | 101 | # audio files 102 | AudioClips/ 103 | *.mp3 104 | *.wav 105 | *.audio 106 | 107 | # license 108 | LICENSE.meta 109 | 110 | # large libraries 111 | native/ 112 | tensorflow.dll 113 | tensorflow.dll.meta -------------------------------------------------------------------------------- /Editor/EditorBase/VXDefaultEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEngine; 6 | using UnityEditor; 7 | using UnityEditor.SceneManagement; 8 | 9 | namespace Voxell.Inspector 10 | { 11 | [CanEditMultipleObjects] 12 | [CustomEditor(typeof(UnityEngine.Object), true)] 13 | public class VXDefaultEditor : Editor 14 | { 15 | private IEnumerable _methods; 16 | 17 | protected virtual void OnEnable() 18 | { 19 | _methods = VXEditorUtil.GetAllMethods( 20 | target, m => m.GetCustomAttributes(typeof(ButtonAttribute), true).Length > 0); 21 | } 22 | 23 | public override void OnInspectorGUI() 24 | { 25 | base.DrawDefaultInspector(); 26 | DrawButtons(); 27 | } 28 | 29 | protected void DrawButtons() 30 | { 31 | if (_methods.Any()) 32 | { 33 | EditorGUILayout.Space(); 34 | 35 | foreach (MethodInfo method in _methods) 36 | MethodButton(serializedObject.targetObject, method); 37 | } 38 | } 39 | 40 | public static void MethodButton(UnityEngine.Object target, MethodInfo methodInfo) 41 | { 42 | ButtonAttribute buttonAttribute = (ButtonAttribute)methodInfo.GetCustomAttributes(typeof(ButtonAttribute), true)[0]; 43 | string buttonName = string.IsNullOrEmpty(buttonAttribute.buttonName) ? ObjectNames.NicifyVariableName(methodInfo.Name) : buttonAttribute.buttonName; 44 | 45 | if (GUILayout.Button(buttonName)) 46 | { 47 | object[] defaultParams = methodInfo.GetParameters().Select(p => p.DefaultValue).ToArray(); 48 | IEnumerator methodResult = methodInfo.Invoke(target, defaultParams) as IEnumerator; 49 | if (!Application.isPlaying) 50 | { 51 | // Set target object and scene dirty to serialize changes to disk 52 | EditorUtility.SetDirty(target); 53 | 54 | PrefabStage stage = PrefabStageUtility.GetCurrentPrefabStage(); 55 | // Prefab mode 56 | if (stage != null) EditorSceneManager.MarkSceneDirty(stage.scene); 57 | // Normal scene 58 | else EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); 59 | } else if (methodResult != null && target is MonoBehaviour behaviour) 60 | behaviour.StartCoroutine(methodResult); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Editor/EditorUtils/VXEditorStyles.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using UnityEditorInternal; 4 | 5 | namespace Voxell.Inspector 6 | { 7 | public static class VXEditorStyles 8 | { 9 | public const int SPACE_A = 20, SPACE_B = 10; 10 | 11 | public static readonly GUIStyleState foldoutNormal = new GUIStyleState { textColor = Color.gray }; 12 | public static readonly GUIStyleState foldoutOnNormal= new GUIStyleState { textColor = new Color(0.7f, 1f, 1f, 1f) }; 13 | 14 | public static readonly GUIStyleState subFoldoutNormal = new GUIStyleState { textColor = Color.gray * Color.cyan }; 15 | public static readonly GUIStyleState subFoldoutOnNormal= new GUIStyleState { textColor = Color.cyan }; 16 | 17 | public static GUIStyle CenteredTitleStyle => new GUIStyle(EditorStyles.largeLabel) 18 | { 19 | alignment = TextAnchor.UpperCenter, 20 | fontStyle = FontStyle.Bold, 21 | fontSize = 18, 22 | fixedHeight = 26 23 | }; 24 | 25 | public static GUIStyle CenteredLabelStyle => new GUIStyle(GUI.skin.label) 26 | { 27 | alignment = TextAnchor.UpperCenter, 28 | fontStyle = FontStyle.Bold, 29 | fontSize = 12 30 | }; 31 | 32 | public static GUIStyle FoldoutStyle => new GUIStyle(EditorStyles.foldout) 33 | { 34 | fontStyle = FontStyle.Bold, 35 | fontSize = 14, 36 | normal = foldoutNormal, 37 | onNormal = foldoutOnNormal, 38 | hover = foldoutOnNormal 39 | }; 40 | 41 | public static GUIStyle SubFoldoutStyle => new GUIStyle(EditorStyles.foldout) 42 | { 43 | fontStyle = FontStyle.Bold, 44 | fontSize = 12, 45 | normal = subFoldoutNormal, 46 | onNormal = subFoldoutOnNormal 47 | }; 48 | 49 | public static GUIStyle ReordableFoldoutStyle => new GUIStyle(GUI.skin.label) 50 | { 51 | fontStyle = FontStyle.Bold, 52 | fontSize = 12, 53 | normal = subFoldoutNormal, 54 | onNormal = subFoldoutOnNormal 55 | }; 56 | 57 | public static GUIStyle NotesLabel => new GUIStyle(GUI.skin.label) 58 | { 59 | fontStyle = FontStyle.Italic, 60 | fontSize = 10, 61 | alignment = TextAnchor.MiddleRight 62 | }; 63 | 64 | public static GUIStyle parentBox => new GUIStyle(GUI.skin.box) 65 | { padding = new RectOffset(15, 15, 15, 15) }; 66 | 67 | public static GUIStyle box => new GUIStyle(GUI.skin.box) 68 | { padding = new RectOffset(10, 10, 10, 10) }; 69 | } 70 | } -------------------------------------------------------------------------------- /Runtime/Mathx/MathUtil.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Unity.Mathematics; 3 | 4 | namespace Voxell.Mathx 5 | { 6 | public static class MathUtil 7 | { 8 | /// Calculate the least amount of groups needed based on thread count. 9 | /// total amount of size available 10 | /// maximum size of each divisions after the split 11 | /// Group count. 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | public static int CalculateGrids(int threadCount, int grpSize) => (threadCount + grpSize - 1) / grpSize; 14 | 15 | /// Calculate the least amount of groups needed based on thread count. 16 | /// total amount of size available 17 | /// maximum size of each divisions after the split 18 | /// Group count. 19 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 20 | public static int CalculateGrids(uint threadCount, uint grpSize) => (int)((threadCount + grpSize - 1) / grpSize); 21 | 22 | /// Convert float3 point location to int3 grid location. 23 | /// point 24 | /// unit size 25 | /// 26 | /// Point location should always be positive in all axis to obtain accurate grid location. 27 | /// 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | public static int3 PointToGrid(float3 p, float unitSize) => new int3(p / unitSize); 30 | 31 | /// 32 | /// Set all values in that array to the given value 33 | /// 34 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 35 | public static void SetArray(ref T[] array, T value) 36 | { for (int i=0; i < array.Length; i++) array[i] = value; } 37 | 38 | /// 39 | /// Generate an int array with sequence id as it's value 40 | /// (ex: [0, 1, 2, 3, 4] will be generated if `length` of 5 is being given) 41 | /// 42 | /// number of elements 43 | public static int[] GenerateSeqArray(int length) 44 | { 45 | int[] array = new int[length]; 46 | for (int i=0; i < length; i++) array[i] = i; 47 | return array; 48 | } 49 | 50 | /// Shuffles an array. 51 | public static void ShuffleArray(ref T[] decklist) 52 | { 53 | for (int i = 0; i < decklist.Length; i++) 54 | { 55 | int randomIdx = UnityEngine.Random.Range(0, decklist.Length); 56 | T tempItem = decklist[randomIdx]; 57 | decklist[randomIdx] = decklist[i]; 58 | decklist[i] = tempItem; 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Runtime/Graphics/ComputeShaderUtil.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Voxell.Graphics 4 | { 5 | using Mathx; 6 | 7 | public static class ComputeShaderUtil 8 | { 9 | public static ComputeShader cs_uint; 10 | public static ComputeShader cs_float3; 11 | 12 | private static int kn_CopyBuffer, kn_ZeroOut, kn_SetBufferAsThreadIdx; 13 | private static int kn_CopyBufferFloat3; 14 | 15 | /// 16 | /// copy a buffer to another buffer 17 | /// 18 | /// source buffer 19 | /// destination buffer 20 | /// buffer size 21 | public static void CopyBuffer(ref ComputeBuffer cb_in, ref ComputeBuffer cb_out, int dataSize) 22 | { 23 | int gridSize = MathUtil.CalculateGrids(dataSize, Graphics.L_BLOCK_SZ); 24 | cs_uint.SetInt(PropertyID.dataSize, dataSize); 25 | cs_uint.SetBuffer(kn_CopyBuffer, BufferID.cb_in, cb_in); 26 | cs_uint.SetBuffer(kn_CopyBuffer, BufferID.cb_out, cb_out); 27 | cs_uint.Dispatch(kn_CopyBuffer, gridSize, 1, 1); 28 | } 29 | 30 | public static void ZeroOut(ref ComputeBuffer cb_out, int dataSize) 31 | { 32 | int gridSize = MathUtil.CalculateGrids(dataSize, Graphics.L_BLOCK_SZ); 33 | cs_uint.SetInt(PropertyID.dataSize, dataSize); 34 | cs_uint.SetBuffer(kn_ZeroOut, BufferID.cb_out, cb_out); 35 | cs_uint.Dispatch(kn_ZeroOut, gridSize, 1, 1); 36 | } 37 | 38 | public static void SetBufferAsThreadIdx(ref ComputeBuffer cb_out, int dataSize) 39 | { 40 | int gridSize = MathUtil.CalculateGrids(dataSize, Graphics.L_BLOCK_SZ); 41 | cs_uint.SetInt(PropertyID.dataSize, dataSize); 42 | cs_uint.SetBuffer(kn_SetBufferAsThreadIdx, BufferID.cb_out, cb_out); 43 | cs_uint.Dispatch(kn_SetBufferAsThreadIdx, gridSize, 1, 1); 44 | } 45 | 46 | public static void CopyBufferFloat3(ref ComputeBuffer cb_in, ref ComputeBuffer cb_out, int dataSize) 47 | { 48 | int gridSize = MathUtil.CalculateGrids(dataSize, Graphics.L_BLOCK_SZ); 49 | cs_float3.SetInt(PropertyID.dataSize, dataSize); 50 | cs_float3.SetBuffer(kn_CopyBufferFloat3, BufferID.cb_in, cb_in); 51 | cs_float3.SetBuffer(kn_CopyBufferFloat3, BufferID.cb_out, cb_out); 52 | cs_float3.Dispatch(kn_CopyBufferFloat3, gridSize, 1, 1); 53 | } 54 | 55 | public static void InitKernels() 56 | { 57 | if (cs_uint != null) return; 58 | cs_uint = Resources.Load("Util/Util.UInt"); 59 | cs_float3 = Resources.Load("Util/Util.Float3"); 60 | 61 | kn_CopyBuffer = cs_uint.FindKernel("CopyBuffer"); 62 | kn_ZeroOut = cs_uint.FindKernel("ZeroOut"); 63 | kn_SetBufferAsThreadIdx = cs_uint.FindKernel("SetBufferAsThreadIdx"); 64 | 65 | kn_CopyBufferFloat3 = cs_float3.FindKernel("CopyBufferFloat3"); 66 | } 67 | 68 | private static class PropertyID 69 | { 70 | public static readonly int dataSize = Shader.PropertyToID("_dataSize"); 71 | } 72 | 73 | private static class BufferID 74 | { 75 | public static readonly int cb_in = Shader.PropertyToID("cb_in"); 76 | public static readonly int cb_out = Shader.PropertyToID("cb_out"); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /Runtime/Graphics/StrideSize.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using Unity.Mathematics; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Voxell.Graphics 6 | { 7 | public static class StrideSize 8 | { 9 | // ints 10 | public static readonly int s_int = Marshal.SizeOf(typeof(int)); 11 | public static readonly int s_int2 = Marshal.SizeOf(typeof(int2)); 12 | public static readonly int s_int3 = Marshal.SizeOf(typeof(int3)); 13 | public static readonly int s_int4 = Marshal.SizeOf(typeof(int4)); 14 | 15 | public static readonly int s_int2x2 = Marshal.SizeOf(typeof(int2x2)); 16 | public static readonly int s_int2x3 = Marshal.SizeOf(typeof(int2x3)); 17 | public static readonly int s_int2x4 = Marshal.SizeOf(typeof(int2x4)); 18 | 19 | public static readonly int s_int3x2 = Marshal.SizeOf(typeof(int3x2)); 20 | public static readonly int s_int3x3 = Marshal.SizeOf(typeof(int3x3)); 21 | public static readonly int s_int3x4 = Marshal.SizeOf(typeof(int3x4)); 22 | 23 | public static readonly int s_int4x2 = Marshal.SizeOf(typeof(int4x2)); 24 | public static readonly int s_int4x3 = Marshal.SizeOf(typeof(int4x3)); 25 | public static readonly int s_int4x4 = Marshal.SizeOf(typeof(int4x4)); 26 | 27 | // uints 28 | public static readonly int s_uint = Marshal.SizeOf(typeof(uint)); 29 | public static readonly int s_uint2 = Marshal.SizeOf(typeof(uint2)); 30 | public static readonly int s_uint3 = Marshal.SizeOf(typeof(uint3)); 31 | public static readonly int s_uint4 = Marshal.SizeOf(typeof(uint4)); 32 | 33 | public static readonly int s_uint2x2 = Marshal.SizeOf(typeof(uint2x2)); 34 | public static readonly int s_uint2x3 = Marshal.SizeOf(typeof(uint2x3)); 35 | public static readonly int s_uint2x4 = Marshal.SizeOf(typeof(uint2x4)); 36 | 37 | public static readonly int s_uint3x2 = Marshal.SizeOf(typeof(uint3x2)); 38 | public static readonly int s_uint3x3 = Marshal.SizeOf(typeof(uint3x3)); 39 | public static readonly int s_uint3x4 = Marshal.SizeOf(typeof(uint3x4)); 40 | 41 | public static readonly int s_uint4x2 = Marshal.SizeOf(typeof(uint4x2)); 42 | public static readonly int s_uint4x3 = Marshal.SizeOf(typeof(uint4x3)); 43 | public static readonly int s_uint4x4 = Marshal.SizeOf(typeof(uint4x4)); 44 | 45 | // floats 46 | public static readonly int s_float = Marshal.SizeOf(typeof(float)); 47 | public static readonly int s_float2 = Marshal.SizeOf(typeof(float2)); 48 | public static readonly int s_float3 = Marshal.SizeOf(typeof(float3)); 49 | public static readonly int s_float4 = Marshal.SizeOf(typeof(float4)); 50 | 51 | public static readonly int s_float2x2 = Marshal.SizeOf(typeof(float2x2)); 52 | public static readonly int s_float2x3 = Marshal.SizeOf(typeof(float2x3)); 53 | public static readonly int s_float2x4 = Marshal.SizeOf(typeof(float2x4)); 54 | 55 | public static readonly int s_float3x2 = Marshal.SizeOf(typeof(float3x2)); 56 | public static readonly int s_float3x3 = Marshal.SizeOf(typeof(float3x3)); 57 | public static readonly int s_float3x4 = Marshal.SizeOf(typeof(float3x4)); 58 | 59 | public static readonly int s_float4x2 = Marshal.SizeOf(typeof(float4x2)); 60 | public static readonly int s_float4x3 = Marshal.SizeOf(typeof(float4x3)); 61 | public static readonly int s_float4x4 = Marshal.SizeOf(typeof(float4x4)); 62 | 63 | public static readonly int s_boneWeight = Marshal.SizeOf(typeof(BoneWeight)); 64 | } 65 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Utilities 2 | 3 | This package is where all the utility functions as well as all the custom inspector drawer code lives. 4 | 5 | - [Unity Utilities](#unity-utilities) 6 | - [Installation](#installation) 7 | - [Custom Property Attribute](#custom-property-attribute) 8 | - [Utilities](#utilities) 9 | - [MathUtil](#mathutil) 10 | - [Under the hood](#under-the-hood) 11 | - [Support the project!](#support-the-project) 12 | - [Join the community!](#join-the-community) 13 | - [License](#license) 14 | - [References](#references) 15 | 16 | ## Installation 17 | 18 | There are no external dependencies for this package. 19 | 20 | 1. Clone this repository into your `Packages` folder. 21 | 2. And you are ready to go! 22 | 23 | ## Custom Property Attribute 24 | 25 | ```cs 26 | using UnityEngine; 27 | using Voxell.Inspector; 28 | 29 | public class CustomInspectorTest : MonoBehaviour 30 | { 31 | [Scene] 32 | public string testScene; 33 | [Scene] 34 | public string[] testSceneArray; 35 | [InspectOnly] 36 | public int inspectOnlyInt; 37 | 38 | [StreamingAssetFilePath] 39 | public string streamingAssetFilePath; 40 | [StreamingAssetFolderPath] 41 | public string streamingAssetFolderPath; 42 | 43 | [Button] 44 | void TestButton() => Debug.Log("TestButton function invoked!"); 45 | [Button("Super Button")] 46 | void AnotherTestButton() => Debug.Log("Button with Super Button name pressed!"); 47 | } 48 | ``` 49 | 50 | ![CustomPropertyAttribute](./Pictures~/CustomPropertyAttribute.png) 51 | 52 | ## Utilities 53 | 54 | ### MathUtil 55 | 56 | ```cs 57 | using UnityEngine; 58 | using Voxell.Mathx; 59 | 60 | // generate array [0, 1, 2, 3, 4] 61 | int[] shuffledArray = MathUtil.GenerateSeqArray(5); 62 | // shuffles array 63 | MathUtil.ShuffleArray(ref shuffledArray, 3); 64 | Debug.Log(shuffledArray); 65 | 66 | ``` 67 | ### Under the hood 68 | 69 | ```cs 70 | using Unity.Mathematics; 71 | 72 | // GenerateSeqArray method 73 | int length = 5; 74 | int[] shuffledArray = new int[length]; 75 | for (int i=0; i < length; i++) shuffledArray[i] = i; 76 | 77 | // ShuffleArray method 78 | for (int i = 0; i < shuffledArray.Length; i++) 79 | { 80 | int randomIdx = UnityEngine.Random.Range(0, shuffledArray.Length); 81 | int tempItem = shuffledArray[randomIdx]; 82 | shuffledArray[randomIdx] = shuffledArray[i]; 83 | shuffledArray[i] = tempItem; 84 | } 85 | 86 | Debug.Log(shuffledArray); 87 | ``` 88 | 89 | ## Support the project! 90 | 91 | 92 | patreon 93 | 94 | 95 | 96 | kofi 97 | 98 | 99 | ## Join the community! 100 | 101 | 102 | discord 103 | 104 | 105 | 106 | discord 107 | 108 | 109 | 110 | ## License 111 | 112 | This repository as a whole is licensed under the Apache License 2.0. Individual files may have a different, but compatible license. 113 | 114 | See [license file](./LICENSE) for details. 115 | 116 | ## References 117 | 118 | - https://github.com/dbrizov/NaughtyAttributes -------------------------------------------------------------------------------- /Editor/PropertyDrawers/StreamingAssetDrawer.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace Voxell.Inspector 5 | { 6 | [CustomPropertyDrawer(typeof(StreamingAssetFilePathAttribute))] 7 | public class StreamingAssetFilePathDrawer : PropertyDrawer 8 | { 9 | public override void OnGUI (Rect rect, SerializedProperty property, GUIContent label) 10 | { 11 | if (property.propertyType == SerializedPropertyType.String) 12 | { 13 | rect.size = new Vector2(rect.size.x, 20.0f); 14 | property.isExpanded = EditorGUI.Foldout(rect, property.isExpanded, label, true, VXEditorStyles.SubFoldoutStyle); 15 | if (property.isExpanded) 16 | { 17 | rect.y += 20.0f; 18 | if (GUI.Button(new Rect(rect.position, new Vector2(20.0f, 20.0f)), EditorGUIUtility.IconContent("Folder Icon").image)) 19 | { 20 | string filePath = EditorUtility.OpenFilePanel("Asset File", Application.streamingAssetsPath, ""); 21 | if (filePath != "") property.stringValue = filePath.Substring(Application.streamingAssetsPath.Length+1); 22 | property.serializedObject.ApplyModifiedProperties(); 23 | GUIUtility.ExitGUI(); 24 | } 25 | Rect assetLabelRect = new Rect(new Vector2(rect.x + 22.0f, rect.y), new Vector2(116.0f, rect.size.y)); 26 | EditorGUI.LabelField(assetLabelRect, "StreamingAssets/"); 27 | Rect filePathRect = new Rect(new Vector2(assetLabelRect.x + assetLabelRect.size.x, rect.y), new Vector2(rect.size.x - assetLabelRect.size.x - 22.0f, rect.size.y)); 28 | GUI.enabled = false; 29 | property.stringValue = EditorGUI.TextField(filePathRect, property.stringValue); 30 | GUI.enabled = true; 31 | } 32 | } 33 | else EditorGUI.LabelField(rect, label.text, "Use [StreamingAssetFilePath] with strings."); 34 | } 35 | 36 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label) 37 | => property.isExpanded ? 40.0f : 20.0f; 38 | } 39 | 40 | [CustomPropertyDrawer(typeof(StreamingAssetFolderPathAttribute))] 41 | public class StreamingAssetFolderPathPathDrawer : PropertyDrawer 42 | { 43 | public override void OnGUI (Rect rect, SerializedProperty property, GUIContent label) 44 | { 45 | if (property.propertyType == SerializedPropertyType.String) 46 | { 47 | rect.size = new Vector2(rect.size.x, 20.0f); 48 | property.isExpanded = EditorGUI.Foldout(rect, property.isExpanded, label, true, VXEditorStyles.SubFoldoutStyle); 49 | if (property.isExpanded) 50 | { 51 | rect.y += 20.0f; 52 | if (GUI.Button(new Rect(rect.position, new Vector2(20.0f, 20.0f)), EditorGUIUtility.IconContent("Folder Icon").image)) 53 | { 54 | string filePath = EditorUtility.OpenFolderPanel("Asset Folder", Application.streamingAssetsPath, ""); 55 | if (filePath != "") property.stringValue = filePath.Substring(Application.streamingAssetsPath.Length+1); 56 | property.serializedObject.ApplyModifiedProperties(); 57 | GUIUtility.ExitGUI(); 58 | } 59 | Rect assetLabelRect = new Rect(new Vector2(rect.x + 22.0f, rect.y), new Vector2(116.0f, rect.size.y)); 60 | EditorGUI.LabelField(assetLabelRect, "StreamingAssets/"); 61 | Rect filePathRect = new Rect(new Vector2(assetLabelRect.x + assetLabelRect.size.x, rect.y), new Vector2(rect.size.x - assetLabelRect.size.x - 22.0f, rect.size.y)); 62 | GUI.enabled = false; 63 | property.stringValue = EditorGUI.TextField(filePathRect, property.stringValue); 64 | GUI.enabled = true; 65 | } 66 | } 67 | else EditorGUI.LabelField(rect, label.text, "Use [StreamingAssetFilePath] with strings."); 68 | } 69 | 70 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label) 71 | => property.isExpanded ? 40.0f : 20.0f; 72 | } 73 | } -------------------------------------------------------------------------------- /Tests/Editor/JobxTests.cs: -------------------------------------------------------------------------------- 1 | using Unity.Mathematics; 2 | using Unity.Collections; 3 | using NUnit.Framework; 4 | using Random = UnityEngine.Random; 5 | 6 | namespace Voxell.Jobx 7 | { 8 | using Mathx; 9 | 10 | public class JobxTests 11 | { 12 | private const int ARRAY_COUNT = 2000; 13 | 14 | [Test] 15 | public void SumScanJobTest() 16 | { 17 | int[] array = new int[ARRAY_COUNT]; 18 | for (int i=0; i < ARRAY_COUNT; i++) array[i] = GenerateRandomInt(); 19 | 20 | NativeArray na_array = new NativeArray(array, Allocator.TempJob); 21 | SumScanJob sumScanJob = new SumScanJob(ref na_array); 22 | sumScanJob.InclusiveSumScan(); 23 | 24 | // using serial inclusive sum scan method to make sure that the parallel method works 25 | int sum = 0; 26 | for (int i=0; i < ARRAY_COUNT; i++) 27 | { 28 | sum += array[i]; 29 | Assert.AreEqual(sum, na_array[i]); 30 | } 31 | 32 | na_array.Dispose(); 33 | sumScanJob.Dispose(); 34 | } 35 | 36 | [Test] 37 | public void Float3MinScanJobTest() 38 | { 39 | float3[] array = new float3[ARRAY_COUNT]; 40 | for (int i=0; i < ARRAY_COUNT; i++) array[i] = GenerateRandomFloat3(); 41 | 42 | NativeArray na_array = new NativeArray(array, Allocator.TempJob); 43 | Float3MinScanJob float3MinScanJob = new Float3MinScanJob(ref na_array); 44 | float3MinScanJob.InclusiveMinScan(); 45 | 46 | // using serial inclusive min scan method to make sure that the parallel method works 47 | float3 float3Max = array[0]; 48 | for (int i=0; i < ARRAY_COUNT; i++) 49 | { 50 | float3Max = math.min(float3Max, array[i]); 51 | Assert.AreEqual(float3Max, na_array[i]); 52 | } 53 | 54 | na_array.Dispose(); 55 | float3MinScanJob.Dispose(); 56 | } 57 | 58 | [Test] 59 | public void Float3MaxScanJobTest() 60 | { 61 | float3[] array = new float3[ARRAY_COUNT]; 62 | for (int i=0; i < ARRAY_COUNT; i++) array[i] = GenerateRandomFloat3(); 63 | 64 | NativeArray na_array = new NativeArray(array, Allocator.TempJob); 65 | Float3MaxScanJob float3MaxScanJob = new Float3MaxScanJob(ref na_array); 66 | float3MaxScanJob.InclusiveMaxScan(); 67 | 68 | // using serial inclusive max scan method to make sure that the parallel method works 69 | float3 float3Max = array[0]; 70 | for (int i=0; i < ARRAY_COUNT; i++) 71 | { 72 | float3Max = math.max(float3Max, array[i]); 73 | Assert.AreEqual(float3Max, na_array[i]); 74 | } 75 | 76 | na_array.Dispose(); 77 | float3MaxScanJob.Dispose(); 78 | } 79 | 80 | [Test] 81 | public void RadixSortJobTest() 82 | { 83 | uint[] array = new uint[ARRAY_COUNT]; 84 | int[] indices = MathUtil.GenerateSeqArray(ARRAY_COUNT); 85 | for (uint i=0; i < ARRAY_COUNT; i++) array[i] = GenerateRandomUInt(); 86 | 87 | NativeArray na_values = new NativeArray(array, Allocator.TempJob); 88 | NativeArray na_indices = new NativeArray(indices, Allocator.TempJob); 89 | RadixSortJob radixSortJob = new RadixSortJob(ref na_values, ref na_indices); 90 | radixSortJob.Sort(); 91 | 92 | // check if sorting works 93 | for (int i=0; i < ARRAY_COUNT-1; i++) 94 | Assert.GreaterOrEqual(na_values[i+1], na_values[i]); 95 | // check if indices are sorted properly 96 | for (int i=0; i < ARRAY_COUNT; i++) 97 | Assert.AreEqual(array[na_indices[i]], na_values[i]); 98 | 99 | na_values.Dispose(); 100 | na_indices.Dispose(); 101 | radixSortJob.Dispose(); 102 | } 103 | 104 | private float3 GenerateRandomFloat3() => Random.insideUnitSphere * Random.Range(0.0f, (float)ARRAY_COUNT); 105 | private int GenerateRandomInt() => Random.Range(0, ARRAY_COUNT); 106 | private uint GenerateRandomUInt() => (uint)Random.Range(0, ARRAY_COUNT); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Pictures~/CustomPropertyAttribute.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: be43a69d8c7af284bb90b99466950f9f 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: 1 36 | aniso: 2 37 | mipBias: 0 38 | wrapU: 0 39 | wrapV: 0 40 | wrapW: 0 41 | nPOTScale: 1 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 0 54 | spriteTessellationDetail: -1 55 | textureType: 0 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 8192 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | - serializedVersion: 3 79 | buildTarget: Standalone 80 | maxTextureSize: 8192 81 | resizeAlgorithm: 0 82 | textureFormat: -1 83 | textureCompression: 1 84 | compressionQuality: 50 85 | crunchedCompression: 0 86 | allowsAlphaSplitting: 0 87 | overridden: 0 88 | androidETC2FallbackOverride: 0 89 | forceMaximumCompressionQuality_BC6H_BC7: 0 90 | - serializedVersion: 3 91 | buildTarget: iPhone 92 | maxTextureSize: 8192 93 | resizeAlgorithm: 0 94 | textureFormat: -1 95 | textureCompression: 1 96 | compressionQuality: 50 97 | crunchedCompression: 0 98 | allowsAlphaSplitting: 0 99 | overridden: 0 100 | androidETC2FallbackOverride: 0 101 | forceMaximumCompressionQuality_BC6H_BC7: 0 102 | - serializedVersion: 3 103 | buildTarget: Android 104 | maxTextureSize: 8192 105 | resizeAlgorithm: 0 106 | textureFormat: -1 107 | textureCompression: 1 108 | compressionQuality: 50 109 | crunchedCompression: 0 110 | allowsAlphaSplitting: 0 111 | overridden: 0 112 | androidETC2FallbackOverride: 0 113 | forceMaximumCompressionQuality_BC6H_BC7: 0 114 | - serializedVersion: 3 115 | buildTarget: Windows Store Apps 116 | maxTextureSize: 8192 117 | resizeAlgorithm: 0 118 | textureFormat: -1 119 | textureCompression: 1 120 | compressionQuality: 50 121 | crunchedCompression: 0 122 | allowsAlphaSplitting: 0 123 | overridden: 0 124 | androidETC2FallbackOverride: 0 125 | forceMaximumCompressionQuality_BC6H_BC7: 0 126 | spriteSheet: 127 | serializedVersion: 2 128 | sprites: [] 129 | outline: [] 130 | physicsShape: [] 131 | bones: [] 132 | spriteID: 133 | internalID: 0 134 | vertices: [] 135 | indices: 136 | edges: [] 137 | weights: [] 138 | secondaryTextures: [] 139 | spritePackingTag: 140 | pSDRemoveMatte: 0 141 | pSDShowRemoveMatteOption: 0 142 | userData: 143 | assetBundleName: 144 | assetBundleVariant: 145 | -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/Scan/BlellochSumScan.compute: -------------------------------------------------------------------------------- 1 | // blelloch exclusive sum scan 2 | 3 | #define M_BLOCK_SZ 64 4 | #define S_BLOCK_SZ 32 5 | #define NUM_BANKS 16 6 | #define LOG_NUM_BANKS 4 7 | 8 | // #define ZERO_BANK_CONFLICTS 9 | 10 | #ifdef ZERO_BANK_CONFLICTS 11 | #define CONFLICT_FREE_OFFSET(n) uint(n >> NUM_BANKS + n >> (2 * LOG_NUM_BANKS)) 12 | #else 13 | #define CONFLICT_FREE_OFFSET(n) uint(n >> LOG_NUM_BANKS) 14 | #endif 15 | 16 | StructuredBuffer cb_in; 17 | RWStructuredBuffer cb_out; 18 | RWStructuredBuffer cb_blockSums; 19 | 20 | uniform uint _len; 21 | 22 | groupshared uint s_out[M_BLOCK_SZ + (M_BLOCK_SZ >> LOG_NUM_BANKS)]; 23 | 24 | #pragma kernel PreSumScan 25 | [numthreads(S_BLOCK_SZ, 1, 1)] 26 | void PreSumScan( 27 | uint DTid : SV_DISPATCHTHREADID, 28 | uint Gidx : SV_GROUPINDEX, 29 | uint Gid : SV_GROUPID 30 | ) 31 | { 32 | int ai = Gidx; 33 | int bi = Gidx + S_BLOCK_SZ; 34 | 35 | // Zero out the shared memory 36 | // Helpful especially when input size is not power of two 37 | s_out[Gidx] = 0; 38 | s_out[Gidx + S_BLOCK_SZ] = 0; 39 | s_out[Gidx + S_BLOCK_SZ + (S_BLOCK_SZ >> LOG_NUM_BANKS) + 1] = 0; 40 | 41 | GroupMemoryBarrierWithGroupSync(); 42 | 43 | // Copy cb_in to shared memory 44 | // Note that cb_in's elements are scattered into shared memory in light of avoiding bank conflicts 45 | uint idx = M_BLOCK_SZ * Gid + Gidx; 46 | if (idx < _len) 47 | { 48 | s_out[ai + CONFLICT_FREE_OFFSET(ai)] = cb_in[idx]; 49 | if (idx + S_BLOCK_SZ < _len) 50 | s_out[bi + CONFLICT_FREE_OFFSET(bi)] = cb_in[idx + S_BLOCK_SZ]; 51 | } 52 | 53 | // For both upsweep and downsweep: 54 | // Sequential indices with conflict free padding 55 | // Amount of padding = target index / num banks 56 | // This "shifts" the target indices by one every multiple of the num banks 57 | // offset controls the stride and starting index of target elems at every iteration 58 | // d just controls which threads are active 59 | // Sweeps are pivoted on the last element of shared memory 60 | 61 | // Upsweep/Reduce step 62 | int offset = 1; 63 | for (uint u=S_BLOCK_SZ; u > 0; u >>= 1) 64 | { 65 | GroupMemoryBarrierWithGroupSync(); 66 | 67 | if (Gidx < u) 68 | { 69 | int ai = offset * ((Gidx << 1) + 1) - 1; 70 | int bi = offset * ((Gidx << 1) + 2) - 1; 71 | ai += CONFLICT_FREE_OFFSET(ai); 72 | bi += CONFLICT_FREE_OFFSET(bi); 73 | 74 | s_out[bi] += s_out[ai]; 75 | } 76 | offset <<= 1; 77 | } 78 | 79 | // Save the total sum on the global block sums array 80 | // Then clear the last element on the shared memory 81 | if (Gidx == 0) 82 | { 83 | cb_blockSums[Gid] = s_out[M_BLOCK_SZ - 1 + CONFLICT_FREE_OFFSET(M_BLOCK_SZ - 1)]; 84 | s_out[M_BLOCK_SZ - 1 + CONFLICT_FREE_OFFSET(M_BLOCK_SZ - 1)] = 0; 85 | } 86 | 87 | // Downsweep step 88 | for (uint d=1; d < M_BLOCK_SZ; d <<= 1) 89 | { 90 | offset >>= 1; 91 | GroupMemoryBarrierWithGroupSync(); 92 | 93 | if (Gidx < d) 94 | { 95 | int ai = offset * ((Gidx << 1) + 1) - 1; 96 | int bi = offset * ((Gidx << 1) + 2) - 1; 97 | ai += CONFLICT_FREE_OFFSET(ai); 98 | bi += CONFLICT_FREE_OFFSET(bi); 99 | 100 | uint temp = s_out[ai]; 101 | s_out[ai] = s_out[bi]; 102 | s_out[bi] += temp; 103 | } 104 | } 105 | GroupMemoryBarrierWithGroupSync(); 106 | 107 | // Copy contents of shared memory to global memory 108 | if (idx < _len) 109 | { 110 | cb_out[idx] = s_out[ai + CONFLICT_FREE_OFFSET(ai)]; 111 | if (idx + S_BLOCK_SZ < _len) 112 | cb_out[idx + S_BLOCK_SZ] = s_out[bi + CONFLICT_FREE_OFFSET(bi)]; 113 | } 114 | } 115 | 116 | #pragma kernel AddBlockSums 117 | [numthreads(S_BLOCK_SZ, 1, 1)] 118 | void AddBlockSums( 119 | uint Gidx : SV_GROUPINDEX, 120 | uint Gid : SV_GROUPID 121 | ) 122 | { 123 | uint d_block_sum_val = cb_blockSums[Gid]; 124 | 125 | uint idx = 2 * Gid * S_BLOCK_SZ + Gidx; 126 | if (idx < _len) 127 | { 128 | cb_out[idx] = cb_in[idx] + d_block_sum_val; 129 | if (idx + S_BLOCK_SZ < _len) 130 | cb_out[idx + S_BLOCK_SZ] = cb_in[idx + S_BLOCK_SZ] + d_block_sum_val; 131 | } 132 | } -------------------------------------------------------------------------------- /Editor/EditorList/EditorListUtil.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using UnityEditorInternal; 4 | 5 | namespace Voxell.Inspector.List 6 | { 7 | public static class EditorListUtil 8 | { 9 | public static ReorderableList CreateReorderableList( 10 | SerializedObject serializedObject, SerializedProperty property, EditorListConfig listConfig 11 | ) 12 | { 13 | ReorderableList list = new ReorderableList( 14 | serializedObject, property, 15 | listConfig.draggable, listConfig.displayHeader, 16 | listConfig.displayAddButton, listConfig.displayRemoveButton 17 | ); 18 | 19 | InitializeReorderableList(list, listConfig); 20 | 21 | return list; 22 | } 23 | 24 | public static void InitializeReorderableList(ReorderableList list, EditorListConfig listConfig) 25 | { 26 | list.multiSelect = listConfig.multiSelect; 27 | SetupDrawHeaderCallback(list, listConfig); 28 | SetupDrawElementCallback(list, listConfig); 29 | SetupElementHeightCallback(list); 30 | SetupDrawNoneCallback(list, listConfig); 31 | SetupDrawFooterCallback(list); 32 | } 33 | 34 | public static void SetupDrawHeaderCallback(ReorderableList list, EditorListConfig listConfig) 35 | { 36 | string header = string.IsNullOrEmpty(listConfig.header) 37 | ? list.serializedProperty.displayName : listConfig.header; 38 | 39 | list.drawHeaderCallback = (Rect rect) => 40 | { 41 | SerializedProperty property = list.serializedProperty; 42 | rect.height += 3.0f; 43 | EditorGUI.indentLevel += 1; 44 | 45 | property.isExpanded = EditorGUI.Foldout( 46 | rect, property.isExpanded, header, true, VXEditorStyles.ReordableFoldoutStyle 47 | ); 48 | list.draggable = property.isExpanded && listConfig.draggable; 49 | list.displayAdd = property.isExpanded && listConfig.displayAddButton; 50 | list.displayRemove = property.isExpanded && listConfig.displayRemoveButton; 51 | 52 | EditorGUI.indentLevel -= 1; 53 | }; 54 | } 55 | 56 | public static void SetupDrawElementCallback(ReorderableList list, EditorListConfig listConfig) 57 | { 58 | bool showPrefix = !string.IsNullOrEmpty(listConfig.prefix); 59 | 60 | list.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => 61 | { 62 | SerializedProperty property = list.serializedProperty; 63 | if (!property.isExpanded) return; 64 | 65 | SerializedProperty elemProperty = property.GetArrayElementAtIndex(index); 66 | bool isGeneric = elemProperty.propertyType == SerializedPropertyType.Generic; 67 | if (isGeneric) 68 | { 69 | rect.x += 10.0f; 70 | rect.width -= 10.0f; 71 | } 72 | 73 | EditorGUI.PropertyField( 74 | rect, elemProperty, 75 | new GUIContent(showPrefix ? $"{listConfig.prefix}{index}" : ""), true 76 | ); 77 | }; 78 | } 79 | 80 | public static void SetupElementHeightCallback(ReorderableList list) 81 | { 82 | list.elementHeightCallback = (int indexer) => 83 | { 84 | SerializedProperty property = list.serializedProperty; 85 | if (!property.isExpanded) return 0.0f; 86 | else 87 | { 88 | if (indexer < property.arraySize) 89 | return EditorGUI.GetPropertyHeight(property.GetArrayElementAtIndex(indexer)); 90 | 91 | return 0.0f; 92 | } 93 | }; 94 | } 95 | 96 | public static void SetupDrawNoneCallback(ReorderableList list, EditorListConfig listConfig) 97 | { 98 | string emptyMsg = !string.IsNullOrEmpty(listConfig.emptyMsg) ? listConfig.emptyMsg : "List is Empty"; 99 | 100 | list.drawNoneElementCallback = (Rect rect) => 101 | { 102 | SerializedProperty property = list.serializedProperty; 103 | if (property.isExpanded) 104 | { 105 | list.elementHeight = 22.0f; 106 | EditorGUI.LabelField(rect, emptyMsg); 107 | } else list.elementHeight = 0.0f; 108 | }; 109 | } 110 | 111 | public static void SetupDrawFooterCallback(ReorderableList list) 112 | { 113 | list.drawFooterCallback = (Rect rect) => 114 | { 115 | SerializedProperty property = list.serializedProperty; 116 | if (property.isExpanded) 117 | { 118 | list.footerHeight = 22.0f; 119 | ReorderableList.defaultBehaviours.DrawFooter(rect, list); 120 | } else list.footerHeight = 0.0f; 121 | }; 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /Runtime/FileUtilx.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | using UnityEngine; 4 | 5 | namespace Voxell 6 | { 7 | public static class FileUtilx 8 | { 9 | public static readonly string projectPath = Application.dataPath.Substring(0, Application.dataPath.Length-6); 10 | 11 | /// Get the path of the folder given a file path by excluding the filename 12 | /// full file path 13 | /// Folder path of the file 14 | public static string GetFolderPath(string assetPath) 15 | { 16 | string folder = ""; 17 | string[] paths = assetPath.Split(new char[]{'/', '\\'}); 18 | for (int p=0; p < paths.Length-1; p++) folder += paths[p] + '/'; 19 | return folder; 20 | } 21 | 22 | /// Get the path of the folder given a file path by excluding the filename 23 | /// full file path 24 | /// separator of each folder in the assetPath 25 | /// Folder path of the file 26 | public static string GetFolderPath(string assetPath, char[] separator) 27 | { 28 | string folder = ""; 29 | string[] paths = assetPath.Split(separator); 30 | for (int p=0; p < paths.Length-1; p++) folder += paths[p] + '/'; 31 | return folder; 32 | } 33 | 34 | /// Get the name of the file given the file path by excluding all of its folder paths 35 | /// full file path 36 | /// 37 | public static string GetFilename(string assetPath) 38 | { 39 | string[] paths = assetPath.Split(new char[]{'/', '\\'}); 40 | return paths[paths.Length-1]; 41 | } 42 | 43 | /// Get the name of the file given the file path by excluding all of its folder paths 44 | /// full file path 45 | /// separator of each folder in the assetPath 46 | /// 47 | public static string GetFilename(string assetPath, char[] separator) 48 | { 49 | string[] paths = assetPath.Split(separator); 50 | return paths[paths.Length-1]; 51 | } 52 | 53 | /// Return the full file path given an asset path 54 | /// Path that starts from the 'Assets/' folder 55 | public static string GetAssetFilePath(string assetPath) 56 | => Path.Combine(projectPath, assetPath); 57 | 58 | /// Return the full file path given a streaming asset path 59 | /// Path that is in the StreamingAssets/ folder 60 | public static string GetStreamingAssetFilePath(string streamingAssetPath) 61 | => Path.Combine(Application.streamingAssetsPath, streamingAssetPath); 62 | 63 | /// Read a streaming asset file and return raw bytes from the file 64 | /// file path starting from and excluding Application.streamingAssetsPath 65 | /// Raw bytes from the file 66 | public static byte[] ReadStreamingAssetFileByte(string path) 67 | => File.ReadAllBytes(GetStreamingAssetFilePath(path)); 68 | 69 | /// Read a streaming asset file and return raw string from the file 70 | /// file path starting excluding Application.streamingAssetsPath 71 | /// Raw string from the file 72 | public static string ReadStreamingAssetFileText(string path) 73 | => File.ReadAllText(GetStreamingAssetFilePath(path)); 74 | 75 | /// Write string contents to a streaming asset file 76 | /// file path starting excluding Application.streamingAssetsPath 77 | /// Raw string from the file 78 | public static void WriteStreamingAssetFileText(string path, string contents) 79 | => File.WriteAllText(GetStreamingAssetFilePath(path), contents); 80 | 81 | /// Write string contents to a streaming asset file 82 | /// file path starting excluding Application.streamingAssetsPath 83 | /// Raw string from the file 84 | public static void WriteStreamingAssetFileText(string path, string contents, Encoding encoding) 85 | => File.WriteAllText(GetStreamingAssetFilePath(path), contents, encoding); 86 | 87 | /// Write byte contents to a streaming asset file 88 | /// file path starting excluding Application.streamingAssetsPath 89 | /// Raw string from the file 90 | public static void WriteStreamingAssetFileByte(string path, byte[] bytes) 91 | => File.WriteAllBytes(GetStreamingAssetFilePath(path), bytes); 92 | 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Runtime/Graphics/RadixSort.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Profiling; 3 | 4 | namespace Voxell.Graphics 5 | { 6 | using Mathx; 7 | 8 | public sealed class RadixSort : System.IDisposable 9 | { 10 | private static ComputeShader cs_radixSort; 11 | private BlellochSumScan _blellochSumScan; 12 | private static int kn_radixSortLocal, kn_globalShuffle; 13 | 14 | private readonly int _sortGridSize, _blockSumsSize; 15 | private readonly int _dataSize; 16 | 17 | private ComputeBuffer cb_sortTemp, cb_indexTemp, cb_prefixSums; 18 | private ComputeBuffer cb_blockSums, cb_scanBlockSums; 19 | 20 | public RadixSort(int dataSize) 21 | { 22 | this._dataSize = dataSize; 23 | 24 | this._sortGridSize = MathUtil.CalculateGrids(_dataSize, Graphics.M_BLOCK_SZ); 25 | this._blockSumsSize = 4 * _sortGridSize; 26 | this._blellochSumScan = new BlellochSumScan(_blockSumsSize); 27 | 28 | this.cb_sortTemp = new ComputeBuffer(_dataSize, StrideSize.s_uint); 29 | this.cb_indexTemp = new ComputeBuffer(_dataSize, StrideSize.s_uint); 30 | this.cb_prefixSums = new ComputeBuffer(_dataSize, StrideSize.s_uint); 31 | this.cb_blockSums = new ComputeBuffer(_blockSumsSize, StrideSize.s_uint); 32 | this.cb_scanBlockSums = new ComputeBuffer(_blockSumsSize, StrideSize.s_uint); 33 | } 34 | 35 | public static void InitKernels() 36 | { 37 | if (cs_radixSort != null) return; 38 | cs_radixSort = Resources.Load("RadixSort"); 39 | kn_radixSortLocal = cs_radixSort.FindKernel("RadixSortLocal"); 40 | kn_globalShuffle = cs_radixSort.FindKernel("GlobalShuffle"); 41 | 42 | BlellochSumScan.InitKernels(); 43 | } 44 | 45 | /// Sorts an array of unsigned integers in parallel. 46 | public void Sort(int maxShiftWidth = 32) 47 | { 48 | Profiler.BeginSample("RadixSort"); 49 | ComputeShaderUtil.ZeroOut(ref cb_sortTemp, _dataSize); 50 | ComputeShaderUtil.ZeroOut(ref cb_indexTemp, _dataSize); 51 | ComputeShaderUtil.ZeroOut(ref cb_prefixSums, _dataSize); 52 | ComputeShaderUtil.ZeroOut(ref cb_blockSums, _blockSumsSize); 53 | ComputeShaderUtil.ZeroOut(ref cb_scanBlockSums, _blockSumsSize); 54 | 55 | // for every 2 bits from LSB to MSB: 56 | // block-wise radix sort (write blocks back to global memory) 57 | for (int shiftWidth=0; shiftWidth < maxShiftWidth; shiftWidth+=2) 58 | { 59 | cs_radixSort.SetInt(PropertyID.shiftWidth, shiftWidth); 60 | cs_radixSort.Dispatch(kn_radixSortLocal, _sortGridSize, 1, 1); 61 | 62 | // scan global block sum array 63 | ComputeShaderUtil.ZeroOut(ref cb_scanBlockSums, _blockSumsSize); 64 | _blellochSumScan.Scan(ref cb_blockSums, ref cb_scanBlockSums, _blockSumsSize); 65 | 66 | // scatter/shuffle block-wise sorted array to final positions 67 | cs_radixSort.Dispatch(kn_globalShuffle, _sortGridSize, 1, 1); 68 | } 69 | Profiler.EndSample(); 70 | } 71 | 72 | /// 73 | /// Sets up radix sort algorithm (call this function when you want to change the target buffers and/or data size) 74 | /// 75 | /// buffer of unsigned integers to be sorted 76 | /// buffer of indices for each unsigned integers 77 | /// total number of unsigned integers to sort 78 | /// number of bits to be sorted 79 | public void Setup(ref ComputeBuffer cb_sort, ref ComputeBuffer cb_indices) 80 | { 81 | cs_radixSort.SetInt(PropertyID.gridSize, _sortGridSize); 82 | cs_radixSort.SetInt(PropertyID.len, _dataSize); 83 | 84 | cs_radixSort.SetBuffer(kn_radixSortLocal, BufferID.cb_in, cb_sort); 85 | cs_radixSort.SetBuffer(kn_radixSortLocal, BufferID.cb_indices, cb_indices); 86 | 87 | cs_radixSort.SetBuffer(kn_globalShuffle, BufferID.cb_out, cb_sort); 88 | cs_radixSort.SetBuffer(kn_globalShuffle, BufferID.cb_indices, cb_indices); 89 | 90 | cs_radixSort.SetBuffer(kn_radixSortLocal, BufferID.cb_outSorted, cb_sortTemp); 91 | cs_radixSort.SetBuffer(kn_radixSortLocal, BufferID.cb_outIndex, cb_indexTemp); 92 | cs_radixSort.SetBuffer(kn_radixSortLocal, BufferID.cb_prefixSums, cb_prefixSums); 93 | cs_radixSort.SetBuffer(kn_radixSortLocal, BufferID.cb_blockSums, cb_blockSums); 94 | 95 | cs_radixSort.SetBuffer(kn_globalShuffle, BufferID.cb_outSorted, cb_sortTemp); 96 | cs_radixSort.SetBuffer(kn_globalShuffle, BufferID.cb_outIndex, cb_indexTemp); 97 | cs_radixSort.SetBuffer(kn_globalShuffle, BufferID.cb_prefixSums, cb_prefixSums); 98 | cs_radixSort.SetBuffer(kn_globalShuffle, BufferID.cb_scanBlockSums, cb_scanBlockSums); 99 | } 100 | 101 | public void Dispose() 102 | { 103 | cb_sortTemp?.Dispose(); 104 | cb_indexTemp?.Dispose(); 105 | cb_prefixSums?.Dispose(); 106 | cb_blockSums?.Dispose(); 107 | cb_scanBlockSums?.Dispose(); 108 | _blellochSumScan?.Dispose(); 109 | } 110 | 111 | private static class PropertyID 112 | { 113 | public static readonly int len = Shader.PropertyToID("_len"); 114 | public static readonly int gridSize = Shader.PropertyToID("_gridSize"); 115 | public static readonly int shiftWidth = Shader.PropertyToID("_shiftWidth"); 116 | } 117 | 118 | private static class BufferID 119 | { 120 | public static readonly int cb_in = Shader.PropertyToID("cb_in"); 121 | public static readonly int cb_out = Shader.PropertyToID("cb_out"); 122 | public static readonly int cb_outSorted = Shader.PropertyToID("cb_outSorted"); 123 | public static readonly int cb_prefixSums = Shader.PropertyToID("cb_prefixSums"); 124 | public static readonly int cb_blockSums = Shader.PropertyToID("cb_blockSums"); 125 | public static readonly int cb_scanBlockSums = Shader.PropertyToID("cb_scanBlockSums"); 126 | 127 | public static readonly int cb_outIndex = Shader.PropertyToID("cb_outIndex"); 128 | public static readonly int cb_indices = Shader.PropertyToID("cb_indices"); 129 | } 130 | } 131 | } -------------------------------------------------------------------------------- /Runtime/Graphics/Scan/BlellochSumScan.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using UnityEngine.Profiling; 4 | 5 | namespace Voxell.Graphics 6 | { 7 | using Mathx; 8 | 9 | /// Blelloch exclusive sum scan. 10 | public sealed class BlellochSumScan : AbstractScan 11 | { 12 | private static ComputeShader cs_blellochSumScan; 13 | private static int kn_preSumScan, kn_addBlockSums; 14 | 15 | private readonly int[] _gridSizes; 16 | 17 | private ComputeBuffer[] cb_sumScanBlockSums; 18 | private ComputeBuffer[] cb_preSumScanTemps; 19 | private ComputeBuffer[] cb_inBlockSums; 20 | private ComputeBuffer[] cb_addBlockSumsTemps; 21 | private ComputeBuffer cb_dummyGrpSums; 22 | 23 | public BlellochSumScan(int dataSize) 24 | { 25 | // generate all grid sizes for blelloch sum scan 26 | List blellochGridSizesList = new List(); 27 | int blellochGridSize = MathUtil.CalculateGrids(dataSize, Graphics.M_BLOCK_SZ); 28 | blellochGridSizesList.Add(blellochGridSize); 29 | while (blellochGridSize > Graphics.S_BLOCK_SZ) 30 | { 31 | blellochGridSize = MathUtil.CalculateGrids(blellochGridSize, Graphics.M_BLOCK_SZ); 32 | blellochGridSizesList.Add(blellochGridSize); 33 | } 34 | 35 | // store grid sizes as an array for performance 36 | this._gridSizes = blellochGridSizesList.ToArray(); 37 | // number of recursives needed 38 | int totalRecursives = _gridSizes.Length; 39 | 40 | // create static compute buffer arrays so that we do need to create them on the fly during runtime 41 | // prevent managed allocation and garbage collection spike 42 | this.cb_sumScanBlockSums = new ComputeBuffer[totalRecursives]; 43 | this.cb_preSumScanTemps = new ComputeBuffer[totalRecursives]; 44 | this.cb_inBlockSums = new ComputeBuffer[totalRecursives]; 45 | for (int b=0; b < totalRecursives; b++) 46 | { 47 | blellochGridSize = _gridSizes[b]; 48 | this.cb_sumScanBlockSums[b] = new ComputeBuffer(blellochGridSize, StrideSize.s_uint); 49 | this.cb_preSumScanTemps[b] = new ComputeBuffer(blellochGridSize, StrideSize.s_uint); 50 | this.cb_inBlockSums[b] = new ComputeBuffer(blellochGridSize, StrideSize.s_uint); 51 | } 52 | this.cb_dummyGrpSums = new ComputeBuffer(1, StrideSize.s_int); 53 | this.cb_addBlockSumsTemps = new ComputeBuffer[totalRecursives]; 54 | this.cb_addBlockSumsTemps[0] = new ComputeBuffer(dataSize, StrideSize.s_uint); 55 | for (int b=1; b < totalRecursives; b++) 56 | this.cb_addBlockSumsTemps[b] = new ComputeBuffer(_gridSizes[b-1], StrideSize.s_uint); 57 | } 58 | 59 | public static void InitKernels() 60 | { 61 | if (cs_blellochSumScan != null) return; 62 | cs_blellochSumScan = Resources.Load("Scan/BlellochSumScan"); 63 | kn_preSumScan = cs_blellochSumScan.FindKernel("PreSumScan"); 64 | kn_addBlockSums = cs_blellochSumScan.FindKernel("AddBlockSums"); 65 | } 66 | 67 | public void Scan( 68 | ref ComputeBuffer cb_in, ref ComputeBuffer cb_out, 69 | int dataSize, int recurseNum = 0 70 | ) 71 | { 72 | Profiler.BeginSample("BlellochSumScan"); 73 | int blellochGridSize = _gridSizes[recurseNum]; 74 | 75 | ComputeBuffer cb_sumScanBlockSum = cb_sumScanBlockSums[recurseNum]; 76 | ComputeShaderUtil.ZeroOut(ref cb_sumScanBlockSum, blellochGridSize); 77 | 78 | // sum scan data allocated to each block 79 | cs_blellochSumScan.SetInt(PropertyID.len, dataSize); 80 | cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_out, cb_out); 81 | cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_in, cb_in); 82 | cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_blockSums, cb_sumScanBlockSum); 83 | cs_blellochSumScan.Dispatch(kn_preSumScan, blellochGridSize, 1, 1); 84 | 85 | // sum scan total sums produced by each block 86 | // use basic implementation if number of total sums is <= 2 * Graphics.M_BLOCK_SZ 87 | // (this requires only one block to do the scan) 88 | if (blellochGridSize <= Graphics.S_BLOCK_SZ) 89 | { 90 | ComputeShaderUtil.ZeroOut(ref cb_dummyGrpSums, 1); 91 | 92 | ComputeBuffer cb_preSumScanTemp = cb_preSumScanTemps[recurseNum]; 93 | ComputeShaderUtil.CopyBuffer(ref cb_sumScanBlockSum, ref cb_preSumScanTemp, blellochGridSize); 94 | 95 | cs_blellochSumScan.SetInt(PropertyID.len, blellochGridSize); 96 | cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_out, cb_sumScanBlockSum); 97 | cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_in, cb_preSumScanTemp); 98 | cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_blockSums, cb_dummyGrpSums); 99 | cs_blellochSumScan.Dispatch(kn_preSumScan, 1, 1, 1); 100 | 101 | } else // else, recurse on this same function as you'll need the full-blown scan for the block sums 102 | { 103 | ComputeBuffer cb_inBlockSum = cb_inBlockSums[recurseNum]; 104 | ComputeShaderUtil.CopyBuffer(ref cb_sumScanBlockSum, ref cb_inBlockSum, blellochGridSize); 105 | Scan(ref cb_inBlockSum, ref cb_sumScanBlockSum, blellochGridSize, recurseNum + 1); 106 | } 107 | 108 | ComputeBuffer cb_addBlockSumsTemp = cb_addBlockSumsTemps[recurseNum]; 109 | ComputeShaderUtil.CopyBuffer(ref cb_out, ref cb_addBlockSumsTemp, dataSize); 110 | // add each block's total sum to its scan output in order to get the final, global scanned array 111 | cs_blellochSumScan.SetInt(PropertyID.len, dataSize); 112 | cs_blellochSumScan.SetBuffer(kn_addBlockSums, BufferID.cb_out, cb_out); 113 | cs_blellochSumScan.SetBuffer(kn_addBlockSums, BufferID.cb_in, cb_addBlockSumsTemp); 114 | cs_blellochSumScan.SetBuffer(kn_addBlockSums, BufferID.cb_blockSums, cb_sumScanBlockSum); 115 | cs_blellochSumScan.Dispatch(kn_addBlockSums, blellochGridSize, 1, 1); 116 | 117 | Profiler.EndSample(); 118 | } 119 | 120 | public override void Dispose() 121 | { 122 | for (int b=0, length=_gridSizes.Length; b < length; b++) 123 | { 124 | cb_sumScanBlockSums[b]?.Dispose(); 125 | cb_preSumScanTemps[b]?.Dispose(); 126 | cb_inBlockSums[b]?.Dispose(); 127 | cb_addBlockSumsTemps[b]?.Dispose(); 128 | } 129 | cb_dummyGrpSums?.Dispose(); 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /Tests/Editor/GraphicsTests.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using Unity.Mathematics; 3 | using NUnit.Framework; 4 | using Random = UnityEngine.Random; 5 | 6 | namespace Voxell.Graphics 7 | { 8 | using Mathx; 9 | 10 | public class GraphicsTests 11 | { 12 | private const int ARRAY_COUNT = 100000; 13 | 14 | [Test] 15 | public void HillisSteeleFloat3MinScanTest() 16 | { 17 | float3[] array = new float3[ARRAY_COUNT]; 18 | float3[] scannedArray = new float3[ARRAY_COUNT]; 19 | for (int i=0; i < ARRAY_COUNT; i++) array[i] = GenerateRandomFloat3(); 20 | 21 | ComputeBuffer cb_in = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_float3); 22 | 23 | ComputeShaderUtil.InitKernels(); 24 | HillisSteeleFloat3MinScan.InitKernels(); 25 | 26 | cb_in.SetData(array); 27 | 28 | HillisSteeleFloat3MinScan hillisSteeleFloat3MinScan = new HillisSteeleFloat3MinScan(ARRAY_COUNT); 29 | hillisSteeleFloat3MinScan.Scan(ref cb_in); 30 | 31 | cb_in.GetData(scannedArray); 32 | 33 | // using serial inclusive min scan method to make sure that the parallel method works 34 | float3 float3Max = array[0]; 35 | for (int i=0; i < ARRAY_COUNT; i++) 36 | { 37 | float3Max = math.min(float3Max, array[i]); 38 | Assert.AreEqual(float3Max, scannedArray[i]); 39 | } 40 | 41 | cb_in.Dispose(); 42 | hillisSteeleFloat3MinScan.Dispose(); 43 | } 44 | 45 | [Test] 46 | public void HillisSteeleFloat3MaxScanTest() 47 | { 48 | float3[] array = new float3[ARRAY_COUNT]; 49 | float3[] scannedArray = new float3[ARRAY_COUNT]; 50 | for (int i=0; i < ARRAY_COUNT; i++) array[i] = GenerateRandomFloat3(); 51 | 52 | ComputeBuffer cb_in = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_float3); 53 | 54 | ComputeShaderUtil.InitKernels(); 55 | HillisSteeleFloat3MaxScan.InitKernels(); 56 | 57 | cb_in.SetData(array); 58 | 59 | HillisSteeleFloat3MaxScan hillisSteeleFloat3MaxScan = new HillisSteeleFloat3MaxScan(ARRAY_COUNT); 60 | hillisSteeleFloat3MaxScan.Scan(ref cb_in); 61 | 62 | cb_in.GetData(scannedArray); 63 | 64 | // using serial inclusive min scan method to make sure that the parallel method works 65 | float3 float3Max = array[0]; 66 | for (int i=0; i < ARRAY_COUNT; i++) 67 | { 68 | float3Max = math.max(float3Max, array[i]); 69 | Assert.AreEqual(float3Max, scannedArray[i]); 70 | } 71 | 72 | cb_in.Dispose(); 73 | hillisSteeleFloat3MaxScan.Dispose(); 74 | } 75 | 76 | [Test] 77 | public void HillisSteeleSumScanTest() 78 | { 79 | uint[] array = new uint[ARRAY_COUNT]; 80 | uint[] scannedArray = new uint[ARRAY_COUNT]; 81 | for (int i=0; i < ARRAY_COUNT; i++) array[i] = GenerateRandomUInt(); 82 | 83 | ComputeBuffer cb_in = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_uint); 84 | 85 | ComputeShaderUtil.InitKernels(); 86 | HillisSteeleSumScan.InitKernels(); 87 | 88 | cb_in.SetData(array); 89 | 90 | HillisSteeleSumScan hillisSteeleSumScan = new HillisSteeleSumScan(ARRAY_COUNT); 91 | hillisSteeleSumScan.Scan(ref cb_in); 92 | 93 | cb_in.GetData(scannedArray); 94 | 95 | // using serial inclusive sum scan method to make sure that the parallel method works 96 | uint sum = 0; 97 | for (int i=0; i < ARRAY_COUNT; i++) 98 | { 99 | sum += array[i]; 100 | Assert.AreEqual(sum, scannedArray[i], i.ToString()); 101 | } 102 | 103 | cb_in.Dispose(); 104 | hillisSteeleSumScan.Dispose(); 105 | } 106 | 107 | [Test] 108 | public void BlellochSumScanTest() 109 | { 110 | uint[] array = new uint[ARRAY_COUNT]; 111 | uint[] scannedArray = new uint[ARRAY_COUNT]; 112 | for (int i=0; i < ARRAY_COUNT; i++) array[i] = GenerateRandomUInt(); 113 | 114 | ComputeBuffer cb_in = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_uint); 115 | ComputeBuffer cb_out = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_uint); 116 | 117 | ComputeShaderUtil.InitKernels(); 118 | BlellochSumScan.InitKernels(); 119 | 120 | cb_in.SetData(array); 121 | ComputeShaderUtil.ZeroOut(ref cb_out, ARRAY_COUNT); 122 | 123 | BlellochSumScan blellochSumScan = new BlellochSumScan(ARRAY_COUNT); 124 | blellochSumScan.Scan(ref cb_in, ref cb_out, ARRAY_COUNT); 125 | 126 | cb_out.GetData(scannedArray); 127 | 128 | // using serial exclusive sum scan method to make sure that the parallel method works 129 | uint sum = 0; 130 | for (int i=0; i < ARRAY_COUNT; i++) 131 | { 132 | Assert.AreEqual(sum, scannedArray[i]); 133 | sum += array[i]; 134 | } 135 | 136 | cb_in.Dispose(); 137 | cb_out.Dispose(); 138 | blellochSumScan.Dispose(); 139 | } 140 | 141 | [Test] 142 | public void RadixSortTest() 143 | { 144 | uint[] array = new uint[ARRAY_COUNT]; 145 | uint[] sortedArray = new uint[ARRAY_COUNT]; 146 | int[] indices = MathUtil.GenerateSeqArray(ARRAY_COUNT); 147 | for (uint i=0; i < ARRAY_COUNT; i++) array[i] = GenerateRandomUInt(); 148 | 149 | ComputeBuffer cb_sort = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_uint); 150 | ComputeBuffer cb_indices = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_int); 151 | 152 | ComputeShaderUtil.InitKernels(); 153 | RadixSort.InitKernels(); 154 | 155 | cb_sort.SetData(array); 156 | cb_indices.SetData(indices); 157 | 158 | RadixSort radixSort = new RadixSort(ARRAY_COUNT); 159 | radixSort.Setup(ref cb_sort, ref cb_indices); 160 | radixSort.Sort(); 161 | 162 | cb_sort.GetData(sortedArray); 163 | cb_indices.GetData(indices); 164 | 165 | // check if sorting works 166 | for (int i=0; i < ARRAY_COUNT-1; i++) 167 | Assert.GreaterOrEqual(sortedArray[i+1], sortedArray[i]); 168 | // check if indices are sorted properly 169 | for (int i=0; i < ARRAY_COUNT; i++) 170 | Assert.AreEqual(array[indices[i]], sortedArray[i]); 171 | 172 | cb_sort.Dispose(); 173 | cb_indices.Dispose(); 174 | radixSort.Dispose(); 175 | } 176 | 177 | private float3 GenerateRandomFloat3() => Random.insideUnitSphere * Random.Range(0.0f, (float)ARRAY_COUNT); 178 | private int GenerateRandomInt() => Random.Range(0, ARRAY_COUNT); 179 | private uint GenerateRandomUInt() => (uint)Random.Range(0, ARRAY_COUNT); 180 | } 181 | } -------------------------------------------------------------------------------- /Editor/Tools/ShowSelectedMeshInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEditor; 3 | using UnityEditorInternal; 4 | using UnityEngine; 5 | 6 | namespace Voxell.Inspector.Tools 7 | { 8 | public class ShowSelectedMeshInfo : EditorWindow 9 | { 10 | private bool selectionChanged = false; 11 | 12 | private int _totalMeshCount = 0; 13 | private int _totalVertexCount = 0; 14 | private int _totalSubMeshCount = 0; 15 | private uint _totalTriCount = 0; 16 | 17 | private MeshFilter[] _meshFilters; 18 | private SkinnedMeshRenderer[] _skinnedMeshRenderers; 19 | private List _meshes; 20 | private List _components; 21 | 22 | private int[] _vertexCounts; 23 | private int[] _subMeshCounts; 24 | private uint[][] _triCounts; 25 | 26 | private Vector2 scrollPos = Vector2.zero; 27 | 28 | [MenuItem("Tools/Voxell/Mesh Info")] 29 | public static void ShowWindow() 30 | { 31 | EditorWindow window = GetWindow(typeof(ShowSelectedMeshInfo)); 32 | window.titleContent = new GUIContent("Mesh Info"); 33 | } 34 | 35 | void OnEnable() => selectionChanged = true; 36 | 37 | void OnGUI() 38 | { 39 | GameObject[] selections = Selection.gameObjects; 40 | 41 | // if have selection 42 | if (selections.Length == 0) 43 | { 44 | EditorGUILayout.LabelField("Select gameobject from scene or hierarchy.."); 45 | } else 46 | { 47 | string selectedLabels = "["; 48 | for (int s=0; s < selections.Length-1; s++) 49 | selectedLabels += selections[s].name + ", "; 50 | selectedLabels += selections[selections.Length-1].name + "]"; 51 | 52 | EditorGUILayout.BeginHorizontal(); 53 | EditorGUILayout.LabelField("Selections: ", EditorStyles.boldLabel, GUILayout.Width(70.0f)); 54 | EditorGUILayout.LabelField(selectedLabels); 55 | EditorGUILayout.EndHorizontal(); 56 | 57 | // update mesh info only if selection changed 58 | if (selectionChanged) 59 | { 60 | selectionChanged = false; 61 | 62 | _totalMeshCount = 0; 63 | _totalVertexCount = 0; 64 | _totalSubMeshCount = 0; 65 | _totalTriCount = 0; 66 | 67 | _meshes = new List(); 68 | _components = new List(); 69 | 70 | for (int s=0; s < selections.Length; s++) 71 | { 72 | GameObject selection = selections[s]; 73 | // check all _meshFilters 74 | _meshFilters = selection.GetComponentsInChildren(); 75 | for (int mf=0, length=_meshFilters.Length; mf < length; mf++) 76 | { 77 | if (!_meshes.Contains(_meshFilters[mf].sharedMesh)) 78 | { 79 | _meshes.Add(_meshFilters[mf].sharedMesh); 80 | _components.Add(_meshFilters[mf]); 81 | } 82 | } 83 | 84 | // check all skinned mesh renderers 85 | _skinnedMeshRenderers = selection.GetComponentsInChildren(); 86 | for (int sm=0, length=_skinnedMeshRenderers.Length; sm < length; sm++) 87 | { 88 | if (!_meshes.Contains(_skinnedMeshRenderers[sm].sharedMesh)) 89 | { 90 | _meshes.Add(_skinnedMeshRenderers[sm].sharedMesh); 91 | _components.Add(_skinnedMeshRenderers[sm]); 92 | } 93 | } 94 | } 95 | 96 | _totalMeshCount = _meshes.Count; 97 | _vertexCounts = new int[_meshes.Count]; 98 | _subMeshCounts = new int[_meshes.Count]; 99 | _triCounts = new uint[_meshes.Count][]; 100 | for (int m=0; m < _totalMeshCount ; m++) 101 | { 102 | _vertexCounts[m] = _meshes[m].vertexCount; 103 | _subMeshCounts[m] = _meshes[m].subMeshCount; 104 | _triCounts[m] = new uint[_subMeshCounts[m]]; 105 | 106 | _totalVertexCount += _vertexCounts[m]; 107 | _totalSubMeshCount += _subMeshCounts[m]; 108 | for (int sub=0; sub < _subMeshCounts[m]; sub++) 109 | { 110 | _triCounts[m][sub] = _meshes[m].GetIndexCount(sub) / 3; 111 | _totalTriCount += _triCounts[m][sub]; 112 | } 113 | } 114 | } 115 | 116 | // display stats 117 | EditorGUILayout.LabelField($"Mesh Count: {_totalMeshCount}"); 118 | EditorGUILayout.LabelField($"Total Vertex Count: {_totalVertexCount}"); 119 | EditorGUILayout.LabelField($"Total Sub Mesh Count: {_totalSubMeshCount}"); 120 | EditorGUILayout.LabelField($"Total Triangle Count: {_totalTriCount}"); 121 | EditorGUILayout.Space(); 122 | 123 | scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Height(position.height - 5 * 22.0f)); 124 | for (int m=0; m < _totalMeshCount; m++) 125 | { 126 | EditorGUILayout.BeginVertical(VXEditorStyles.box); 127 | 128 | EditorGUILayout.BeginHorizontal(); 129 | 130 | // ping buttons 131 | if (GUILayout.Button(new GUIContent("M", "Ping Mesh in Project"), GUILayout.Width(22.0f))) 132 | EditorGUIUtility.PingObject(_meshes[m]); 133 | 134 | if (GUILayout.Button(new GUIContent("G", "Ping GameObject in Hierarchy"), GUILayout.Width(22.0f))) 135 | EditorGUIUtility.PingObject(_components[m]); 136 | 137 | EditorGUILayout.LabelField(_meshes[m].name, EditorStyles.boldLabel); 138 | EditorGUILayout.EndHorizontal(); 139 | 140 | EditorGUILayout.LabelField($"Vertex Count: {_vertexCounts[m]}"); 141 | EditorGUILayout.LabelField($"Sub Mesh Count: {_subMeshCounts[m]}"); 142 | ReorderableList triCountList = new ReorderableList(_triCounts[m], typeof(uint), true, true, false, false); 143 | triCountList.drawHeaderCallback = (Rect rect) => 144 | { 145 | EditorGUI.indentLevel += 1; 146 | EditorGUI.LabelField(rect, $"Triangle Counts"); 147 | EditorGUI.indentLevel -= 1; 148 | }; 149 | 150 | triCountList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => 151 | EditorGUI.LabelField(rect, $"Sub Mesh #{index}: {_triCounts[m][index]}"); 152 | 153 | triCountList.DoLayoutList(); 154 | 155 | EditorGUILayout.EndHorizontal(); 156 | } 157 | EditorGUILayout.EndScrollView(); 158 | } 159 | } 160 | 161 | void OnSelectionChange() 162 | { 163 | selectionChanged = true; 164 | // force redraw window 165 | Repaint(); 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /Runtime/Graphics/Resources/RadixSort.compute: -------------------------------------------------------------------------------- 1 | #define MAX_BLOCK_SZ 64 2 | #define LOG_MAX_BLOCK_SZ 6 3 | 4 | StructuredBuffer cb_in; 5 | RWStructuredBuffer cb_out; 6 | RWStructuredBuffer cb_outSorted; 7 | RWStructuredBuffer cb_prefixSums; 8 | RWStructuredBuffer cb_blockSums; 9 | RWStructuredBuffer cb_scanBlockSums; 10 | 11 | RWStructuredBuffer cb_outIndex; 12 | RWStructuredBuffer cb_indices; 13 | 14 | uniform uint _len; 15 | uniform uint _gridSize; 16 | uniform uint _shiftWidth; 17 | 18 | groupshared uint s_data[MAX_BLOCK_SZ]; 19 | groupshared uint s_index[MAX_BLOCK_SZ]; 20 | groupshared uint s_maskOut[MAX_BLOCK_SZ + 1]; 21 | groupshared uint s_mergedScanMaskOut[MAX_BLOCK_SZ]; 22 | groupshared uint s_maskOutSums[4]; 23 | groupshared uint s_scanMaskOutSums[4]; 24 | 25 | #pragma kernel RadixSortLocal 26 | [numthreads(MAX_BLOCK_SZ, 1, 1)] 27 | void RadixSortLocal( 28 | uint DTid : SV_DISPATCHTHREADID, 29 | uint Gidx : SV_GROUPINDEX, 30 | uint Gid : SV_GROUPID 31 | ) 32 | { 33 | // need shared memory array for: 34 | // - block's share of the input data (local sort will be put here too) 35 | // - mask outputs 36 | // - scanned mask outputs 37 | // - merged scaned mask outputs ("local prefix sum") 38 | // - local sums of scanned mask outputs 39 | // - scanned local sums of scanned mask outputs 40 | 41 | // for all radix combinations: 42 | // build mask output for current radix combination 43 | // scan mask ouput 44 | // store needed value from current prefix sum array to merged prefix sum array 45 | // store total sum of mask output (obtained from scan) to global block sum array 46 | // calculate local sorted address from local prefix sum and scanned mask output's total sums 47 | // shuffle input block according to calculated local sorted addresses 48 | // shuffle local prefix sums according to calculated local sorted addresses 49 | // copy locally sorted array back to global memory 50 | // copy local prefix sum array back to global memory 51 | 52 | // Copy block's portion of global input data to shared memory 53 | if (DTid < _len) 54 | { 55 | s_data[Gidx] = cb_in[DTid]; 56 | s_index[Gidx] = cb_indices[DTid]; 57 | } else 58 | { 59 | s_data[Gidx] = 0; 60 | s_index[Gidx] = 0; 61 | } 62 | 63 | GroupMemoryBarrierWithGroupSync(); 64 | 65 | // To extract the correct 2 bits, we first shift the number 66 | // to the right until the correct 2 bits are in the 2 LSBs, 67 | // then mask on the number with 11 (3) to remove the bits 68 | // on the left 69 | uint t_data = s_data[Gidx]; 70 | uint t_index = s_index[Gidx]; 71 | uint t_2bitExtract = (t_data >> _shiftWidth) & 3; 72 | 73 | [unroll] 74 | for (uint i = 0; i < 4; ++i) 75 | { 76 | // Zero out s_maskOut 77 | s_maskOut[Gidx] = 0; 78 | if (Gidx == 0) 79 | s_maskOut[MAX_BLOCK_SZ] = 0; 80 | 81 | GroupMemoryBarrierWithGroupSync(); 82 | 83 | // build bit mask output 84 | bool valEqualsi = false; 85 | if (DTid < _len) 86 | { 87 | valEqualsi = t_2bitExtract == i; 88 | s_maskOut[Gidx] = valEqualsi; 89 | } 90 | GroupMemoryBarrierWithGroupSync(); 91 | 92 | // Scan mask outputs (Hillis-Steele) 93 | int partner = 0; 94 | uint sum = 0; 95 | [unroll] 96 | for (uint d = 0; d < LOG_MAX_BLOCK_SZ; d++) { 97 | partner = Gidx - (1 << d); 98 | if (partner >= 0) 99 | sum = s_maskOut[Gidx] + s_maskOut[partner]; 100 | else 101 | sum = s_maskOut[Gidx]; 102 | 103 | GroupMemoryBarrierWithGroupSync(); 104 | s_maskOut[Gidx] = sum; 105 | GroupMemoryBarrierWithGroupSync(); 106 | } 107 | 108 | // Shift elements to produce the same effect as exclusive scan 109 | uint cpyVal = s_maskOut[Gidx]; 110 | GroupMemoryBarrierWithGroupSync(); 111 | s_maskOut[Gidx + 1] = cpyVal; 112 | GroupMemoryBarrierWithGroupSync(); 113 | 114 | if (Gidx == 0) 115 | { 116 | // Zero out first element to produce the same effect as exclusive scan 117 | s_maskOut[0] = 0; 118 | uint totalSum = s_maskOut[MAX_BLOCK_SZ]; 119 | s_maskOutSums[i] = totalSum; 120 | cb_blockSums[i * _gridSize + Gid] = totalSum; 121 | } 122 | GroupMemoryBarrierWithGroupSync(); 123 | 124 | if (valEqualsi && (DTid < _len)) 125 | { 126 | s_mergedScanMaskOut[Gidx] = s_maskOut[Gidx]; 127 | } 128 | 129 | GroupMemoryBarrierWithGroupSync(); 130 | } 131 | 132 | // Scan mask output sums 133 | // Just do a naive scan since the array is really small 134 | if (Gidx == 0) 135 | { 136 | uint run_sum = 0; 137 | for (uint i = 0; i < 4; ++i) 138 | { 139 | s_scanMaskOutSums[i] = run_sum; 140 | run_sum += s_maskOutSums[i]; 141 | } 142 | } 143 | 144 | uint newPos = 0; 145 | uint t_prefixSum = 0; 146 | 147 | GroupMemoryBarrierWithGroupSync(); 148 | 149 | if (DTid < _len) 150 | { 151 | // Calculate the new indices of the input elements for sorting 152 | t_prefixSum = s_mergedScanMaskOut[Gidx]; 153 | newPos = t_prefixSum + s_scanMaskOutSums[t_2bitExtract]; 154 | } 155 | 156 | GroupMemoryBarrierWithGroupSync(); 157 | 158 | if (DTid < _len) 159 | { 160 | // Shuffle the block's input elements to actually sort them 161 | // Do this step for greater global memory transfer coalescing 162 | // in next step 163 | s_data[newPos] = t_data; 164 | s_index[newPos] = t_index; 165 | s_mergedScanMaskOut[newPos] = t_prefixSum; 166 | } 167 | 168 | GroupMemoryBarrierWithGroupSync(); 169 | 170 | if (DTid < _len) 171 | { 172 | // Copy block - wise prefix sum results to global memory 173 | // Copy block-wise sort results to global 174 | cb_prefixSums[DTid] = s_mergedScanMaskOut[Gidx]; 175 | cb_outSorted[DTid] = s_data[Gidx]; 176 | cb_outIndex[DTid] = s_index[Gidx]; 177 | } 178 | } 179 | 180 | #pragma kernel GlobalShuffle 181 | [numthreads(MAX_BLOCK_SZ, 1, 1)] 182 | void GlobalShuffle( 183 | uint DTid : SV_DISPATCHTHREADID, 184 | uint Gidx : SV_GROUPINDEX, 185 | uint Gid : SV_GROUPID 186 | ) 187 | { 188 | // get d = digit 189 | // get n = blockIdx 190 | // get m = local prefix sum array value 191 | // calculate global position = P_d[n] + m 192 | // copy input element to final position in cb_out 193 | 194 | uint idx = MAX_BLOCK_SZ * Gid + Gidx; 195 | 196 | if (idx < _len) 197 | { 198 | uint t_data = cb_outSorted[idx]; 199 | uint t_index = cb_outIndex[idx]; 200 | uint t_2bitExtract = (t_data >> _shiftWidth) & 3; 201 | uint t_prefixSum = cb_prefixSums[idx]; 202 | uint globalPos = cb_scanBlockSums[t_2bitExtract * _gridSize + Gid] + t_prefixSum; 203 | GroupMemoryBarrierWithGroupSync(); 204 | cb_out[globalPos] = t_data; 205 | cb_indices[globalPos] = t_index; 206 | } 207 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.4.2] 2 | 3 | ### New Features 4 | 5 | - Added inverse lerp functions to support `float`, `float2`, and `float4` operations. 6 | - Added default fields to `VXEditorUtil`. 7 | - `CreateReorderableList` (formerly known as `FoldableReorderableList`): 8 | - Supports serialized structs/classes. 9 | - Element height now depends on serialized property height. 10 | - Added "empty message" to display when the list is empty. 11 | - Created `GroupableList` class for storing a group index for each reorderable list. 12 | - Created `EditorListConfig` struct to store `ReorderableList` related data. 13 | - Added `float3x.one` to `float3x.cs`. 14 | 15 | ### Changes 16 | 17 | - Removed `AbstractVXScriptableEditor`. 18 | - `serializedObject` now updates every frame in `OnInspectorGUI` (in `AbstractVXEditor`) to refresh `serializedObject` representation (especially in scriptable objects). 19 | - Removed unused functions from `VXEditorUtil`. 20 | - Renamed `FoldableReorderableList` to `CreateReorderableList`. 21 | - Added new `namespace` -> `Voxell.Inspector.List` for list specific classes/structs. 22 | - Moved `CreateReorderableList` to `EditorListUtil` file. 23 | - Bump `com.unity.jobs` package version to `0.50.0-preview.9`. 24 | - Bump `com.unity.mathematics` package version to `1.2.6`. 25 | - Updated `README.md` docs for `Mathx`. 26 | 27 | ### Bug Fixes 28 | 29 | - Fixed `InspectOnly` height problem. Previously, it can only handle properties with single line height, now it handles all properties with all kinds of height difference using `EditorGUI.GetPropertyHeight(property, true)`. 30 | 31 | ## [1.4.1] 32 | 33 | ### Changes 34 | 35 | - `FoldableReorderableList`: 36 | - Optional parameters for `draggable`, `displayHeader`, `displayAddButton`, `displayRemoveButton`, `multiSelect`, and `prefix`. 37 | - `multiSelect` is a newly added parameter. 38 | - Increase header rect by 3.0f to allow characters like 'g' and 'y' to be fully rendered. 39 | - Uses serialized property from the list instead of the cached serialized property taken in as the function's parameter. 40 | - Added parameter to change header string. 41 | - `spaceA` and `spaceB` changed to `SPACE_A` and `SPACE_B` respectively. 42 | - `InspectorView` returns `Editor` when initializing. 43 | - `OnChange` method implemented for abstract editors. This method will be called whenever there is any changes made to the editor. 44 | 45 | ## [1.4.0] 46 | 47 | ### New Features 48 | 49 | - Custom Editor Views for UIBuilder 50 | - Inspector View 51 | - Split View 52 | - Abstract Editor and Abstract Scriptable Editor. 53 | - Graphics 54 | - `Blelloch Sum Scan` compute shader. 55 | - `Hillis Steele Sum Scan` compute shader. 56 | - `AABB Scan` compute shader. 57 | - `Radix Sort` compute shader. 58 | - unit tests for each of them. 59 | - Added "writing" methods to streaming asset files in `FileUtilx`. 60 | 61 | ### Changes 62 | 63 | - Added `ReadOnly` and `WriteOnly` tags to native arrays on `Jobx` where neccessary. 64 | - Improved performance of `Min/Max/Sum Scan` by increasing the batch size. 65 | - Prevent the allocation of new array everytime a new scan/sort is needed by caching it during initialization. 66 | - Removed Logging class. 67 | - added NativeGetTangents method (MeshUtil). 68 | - Shuffle array method in MathUtil now uses UnityEngine.Random instead of Unity.Mathematics.Random for easier usage (no need to think about what seed to provide & since it is a serial method). 69 | - Renamed `Init()` method to `InitKernels()`. 70 | - `NativeContainers` completely removed. (this action has been made due to the additional complexitiy when using native containers on simple tasks like `Interlocked.Exchange` or `Interlocked.Increment`, these operations can be done quite easily using unsafe and pointers in a Job System) 71 | 72 | ## [1.3.0] 73 | 74 | ### New Features 75 | 76 | - Jobx (parallel computation primitives) 77 | - ReverseJob: Reverse native array in parallel. 78 | - Hillis Steele inclusive sum scan implementation. 79 | - Hillis Steele inclusive min/max scan implementation. 80 | - Radix Sort (LSB) implementation. 81 | - Native Containers 82 | - Native Increment (atomic incrementation of an int). 83 | - Native Add (atomic addition of an int). 84 | - Native Exchange (atomic exchange of an int). 85 | - mathx: 86 | - `approximately_zero` function. 87 | - lower case for `long_axis` function. 88 | - directional vectors added for `float2x` and `float3x` (e.g. up, down, forwad, etc.). 89 | - Created unit tests for `Jobx` and `NativeContainers`. 90 | 91 | ### Changes 92 | 93 | - Added package dependencies: 94 | - "com.unity.jobs": "0.11.0-preview.6" 95 | - "com.unity.burst": "1.5.5" 96 | - Fixed `StreamingAssetFilePath` and `StreamingAssetFolderPath` stack error when opening file explorer. 97 | - Renamed `float2_extension` and `float3_extension` to `float2x` and `float3x`. 98 | 99 | ### Bug Fixes 100 | 101 | - Fixed Bug: Mesh Info tool throws error when mesh filter or skinned mesh renderer has no mesh/missing mesh. 102 | - Hillis Steele inclusive sum scan does not include first element. 103 | 104 | ## [1.2.0] 105 | 106 | ### New Features 107 | 108 | - New tool: Mesh Info (EditorWindow) 109 | - Under *Tools/Voxell/Mesh Info* 110 | - Shows mesh stats based on the GameObject/Prefab you select. 111 | - Recursively search for children objects inside the GameObject/Prefab for MeshFilter and SkinnedMeshRenderer. 112 | - Stats include: 113 | - Vertex Count 114 | - Sub Mesh Count 115 | - Triangle Count 116 | - Ping functionality allows user to ping GameObject or Mesh location. 117 | - Multi select support. 118 | 119 | ### Changes 120 | 121 | - EditorStyles -> VXEditorStyles to prevent conflict with UnityEditor namespace 122 | - EditorUtil -> VXEditorUtil (match the above naming convention) 123 | - Moved NativeUtil from Voxell.Mathx to Voxell namespace 124 | 125 | ## [1.1.1] 126 | 127 | ### New Features 128 | 129 | - float2_extension 130 | - float2 perpendicular vector 131 | - angle between 2 float2 vectors 132 | - float3_extension 133 | - float3 LongAxis (select axis with the largest value) 134 | - mathx 135 | - approximately using Unity.Mathematics instead of Mathf. 136 | - Stride Size for all vector and matrix sizes 137 | 138 | ### Changes 139 | 140 | - GraphicsUtil 141 | - Generalize dispose buffers and destroy object array functions 142 | - NativeUtil 143 | - Inlining of array and list disposition functions 144 | - removed vector to float converter (since we can use NativeArray/NativeList.CopyFrom) 145 | 146 | - Removed 147 | - VectorUtil.cs (seems unnecessary) 148 | 149 | ## [1.1.0] 150 | 151 | ### New Features 152 | 153 | - Buffer Array disposing utilities in GraphicsUtil. 154 | - common stride sizes in a static class called StrideSize. 155 | - ComputeShaderUtil for handling simple parallel task. 156 | - Sequence array generator. 157 | 158 | ## [1.0.0] 159 | 160 | - Initial release. -------------------------------------------------------------------------------- /Runtime/Jobx/RadixSortJob.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.Profiling; 2 | using Unity.Collections; 3 | using Unity.Jobs; 4 | using Unity.Burst; 5 | 6 | namespace Voxell.Jobx 7 | { 8 | public sealed class RadixSortJob : System.IDisposable 9 | { 10 | public NativeArray na_values; 11 | public NativeArray na_indices; 12 | public NativeArray na_sortedValues; 13 | public NativeArray na_sortedIndices; 14 | 15 | private int _valueCount; 16 | private NativeArray na_bit; 17 | private NativeArray na_truePrefixSum; 18 | private NativeArray na_falsePrefixSum; 19 | 20 | private RadixBitCheckJob radixBitCheckJob; 21 | private RadixSortShuffleJob radixSortShuffleJob; 22 | private SumScanJob trueSumScanJob; 23 | private SumScanJob falseSumScanJob; 24 | 25 | public RadixSortJob(ref NativeArray na_values, ref NativeArray na_indices) 26 | { 27 | this._valueCount = na_values.Length; 28 | this.na_values = na_values; 29 | this.na_indices = na_indices; 30 | this.na_sortedValues = new NativeArray(na_values, Allocator.Persistent); 31 | this.na_sortedIndices = new NativeArray(na_indices, Allocator.Persistent); 32 | this.na_bit = new NativeArray(_valueCount, Allocator.Persistent); 33 | this.na_truePrefixSum = new NativeArray(_valueCount, Allocator.Persistent); 34 | this.na_falsePrefixSum = new NativeArray(_valueCount, Allocator.Persistent); 35 | 36 | this.radixBitCheckJob = new RadixBitCheckJob( 37 | ref na_values, ref na_bit, ref na_truePrefixSum, ref na_falsePrefixSum 38 | ); 39 | this.radixSortShuffleJob = new RadixSortShuffleJob( 40 | ref na_values, ref na_indices, ref na_sortedValues, ref na_sortedIndices, 41 | ref na_bit, ref na_truePrefixSum, ref na_falsePrefixSum 42 | ); 43 | 44 | this.trueSumScanJob = new SumScanJob(ref na_truePrefixSum); 45 | this.falseSumScanJob = new SumScanJob(ref na_falsePrefixSum); 46 | } 47 | 48 | /// Sort an array of unsigned integers. 49 | public void Sort(int maxShiftWidth = 32) 50 | { 51 | Profiler.BeginSample("RadixSort"); 52 | uint mask = 1; 53 | int valueCount = na_values.Length; 54 | JobHandle jobHandle; 55 | 56 | for (int m=0; m < maxShiftWidth; m++) 57 | { 58 | radixBitCheckJob.mask = mask; 59 | jobHandle = radixBitCheckJob.Schedule(valueCount, Jobx.XL_BATCH_SIZE); 60 | jobHandle.Complete(); 61 | 62 | trueSumScanJob.InclusiveSumScan(); 63 | falseSumScanJob.InclusiveSumScan(); 64 | radixSortShuffleJob.lastFalseIdx = na_falsePrefixSum[valueCount-1]; 65 | 66 | jobHandle = radixSortShuffleJob.Schedule(valueCount, Jobx.XL_BATCH_SIZE); 67 | jobHandle.Complete(); 68 | na_values.CopyFrom(na_sortedValues); 69 | na_indices.CopyFrom(na_sortedIndices); 70 | 71 | mask <<= 1; 72 | } 73 | Profiler.EndSample(); 74 | } 75 | 76 | [BurstCompile(CompileSynchronously = true)] 77 | private struct RadixBitCheckJob : IJobParallelFor 78 | { 79 | public uint mask; 80 | 81 | [ReadOnly] public NativeArray na_values; 82 | // true if current bit is 1 83 | [WriteOnly] public NativeArray na_bit; 84 | [WriteOnly] public NativeArray na_truePrefixSum; 85 | [WriteOnly] public NativeArray na_falsePrefixSum; 86 | 87 | public RadixBitCheckJob( 88 | ref NativeArray na_values, 89 | ref NativeArray na_bit, 90 | ref NativeArray na_truePrefixSum, 91 | ref NativeArray na_falsePrefixSum 92 | ) 93 | { 94 | this.na_values = na_values; 95 | this.na_bit = na_bit; 96 | this.na_truePrefixSum = na_truePrefixSum; 97 | this.na_falsePrefixSum = na_falsePrefixSum; 98 | this.mask = 1; 99 | } 100 | 101 | public void Execute(int index) 102 | { 103 | uint value = na_values[index]; 104 | bool bit = (value & mask) > 0; 105 | 106 | na_bit[index] = bit; 107 | if (bit) 108 | { 109 | na_truePrefixSum[index] = 1; 110 | na_falsePrefixSum[index] = 0; 111 | } else 112 | { 113 | na_truePrefixSum[index] = 0; 114 | na_falsePrefixSum[index] = 1; 115 | } 116 | } 117 | } 118 | 119 | [BurstCompile(CompileSynchronously = true)] 120 | private struct RadixSortShuffleJob : IJobParallelFor 121 | { 122 | public int lastFalseIdx; 123 | 124 | [ReadOnly] public NativeArray na_values; 125 | [ReadOnly] public NativeArray na_indices; 126 | [NativeDisableParallelForRestriction, WriteOnly] public NativeArray na_sortedValues; 127 | [NativeDisableParallelForRestriction, WriteOnly] public NativeArray na_sortedIndices; 128 | // true if current bit is 1 129 | [ReadOnly] public NativeArray na_bit; 130 | [ReadOnly] public NativeArray na_truePrefixSum; 131 | [ReadOnly] public NativeArray na_falsePrefixSum; 132 | 133 | public RadixSortShuffleJob( 134 | ref NativeArray na_values, 135 | ref NativeArray na_indices, 136 | ref NativeArray na_sortedValues, 137 | ref NativeArray na_sortedIndices, 138 | ref NativeArray na_bit, 139 | ref NativeArray na_truePrefixSum, 140 | ref NativeArray na_falsePrefixSum 141 | ) 142 | { 143 | this.na_values = na_values; 144 | this.na_indices = na_indices; 145 | this.na_sortedValues = na_sortedValues; 146 | this.na_sortedIndices = na_sortedIndices; 147 | this.na_bit = na_bit; 148 | this.na_truePrefixSum = na_truePrefixSum; 149 | this.na_falsePrefixSum = na_falsePrefixSum; 150 | 151 | lastFalseIdx = 0; 152 | } 153 | 154 | public void Execute(int index) 155 | { 156 | int sortIdx; 157 | if (na_bit[index]) 158 | { 159 | // minus one because we use inclusive sum scan 160 | sortIdx = na_truePrefixSum[index] - 1 + lastFalseIdx; 161 | na_sortedValues[sortIdx] = na_values[index]; 162 | na_sortedIndices[sortIdx] = na_indices[index]; 163 | } else 164 | { 165 | sortIdx = na_falsePrefixSum[index] - 1; 166 | na_sortedValues[sortIdx] = na_values[index]; 167 | na_sortedIndices[sortIdx] = na_indices[index]; 168 | } 169 | } 170 | } 171 | 172 | public void Dispose() 173 | { 174 | na_sortedValues.Dispose(); 175 | na_sortedIndices.Dispose(); 176 | na_bit.Dispose(); 177 | na_truePrefixSum.Dispose(); 178 | na_falsePrefixSum.Dispose(); 179 | trueSumScanJob.Dispose(); 180 | falseSumScanJob.Dispose(); 181 | } 182 | } 183 | } -------------------------------------------------------------------------------- /Runtime/MeshUtil.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using Unity.Collections; 3 | using Unity.Mathematics; 4 | 5 | namespace Voxell 6 | { 7 | public static class MeshUtil 8 | { 9 | /// Creates a deep copy of a mesh. 10 | /// source of mesh to copy from 11 | /// location of copied mesh 12 | public static void DeepCopyMesh(in Mesh originMesh, out Mesh newMesh) 13 | { 14 | newMesh = new Mesh(); 15 | newMesh.vertices = originMesh.vertices; 16 | newMesh.triangles = originMesh.triangles; 17 | newMesh.uv = originMesh.uv; 18 | newMesh.normals = originMesh.normals; 19 | newMesh.colors = originMesh.colors; 20 | newMesh.tangents = originMesh.tangents; 21 | 22 | int subMeshCount = originMesh.subMeshCount; 23 | newMesh.subMeshCount = subMeshCount; 24 | for (int s=0; s < subMeshCount; s++) 25 | newMesh.SetSubMesh(s, originMesh.GetSubMesh(s)); 26 | } 27 | 28 | /// Get native array of mesh vertices. 29 | /// mesh data 30 | /// allocation type 31 | public static void NativeGetVertices( 32 | in Mesh.MeshData meshData, 33 | out NativeArray na_vertices, Allocator allocator 34 | ) 35 | { 36 | int vertexCount = meshData.vertexCount; 37 | NativeArray na_verticesVec3 = new NativeArray(vertexCount, allocator); 38 | meshData.GetVertices(na_verticesVec3); 39 | na_vertices = na_verticesVec3.Reinterpret(); 40 | } 41 | 42 | /// Get native array of mesh normals. 43 | /// mesh data 44 | /// allocation type 45 | public static void NativeGetNormals( 46 | in Mesh.MeshData meshData, 47 | out NativeArray na_normals, Allocator allocator) 48 | { 49 | int indexCount = meshData.vertexCount; 50 | NativeArray na_normalsVec3 = new NativeArray(indexCount, allocator); 51 | meshData.GetNormals(na_normalsVec3); 52 | na_normals = na_normalsVec3.Reinterpret(); 53 | } 54 | 55 | /// Get native array of mesh normals. 56 | /// mesh data 57 | /// allocation type 58 | public static void NativeGetTangents( 59 | in Mesh.MeshData meshData, 60 | out NativeArray na_tangents, Allocator allocator) 61 | { 62 | int indexCount = meshData.vertexCount; 63 | NativeArray na_tangentsVec3 = new NativeArray(indexCount, allocator); 64 | meshData.GetTangents(na_tangentsVec3); 65 | na_tangents = na_tangentsVec3.Reinterpret(); 66 | } 67 | 68 | /// Get native array of uv coordinates. 69 | /// mesh data 70 | /// allocation type 71 | public static void NativeGetUVs( 72 | in Mesh.MeshData meshData, int channel, 73 | out NativeArray na_uvs, Allocator allocator 74 | ) 75 | { 76 | int vertexCount = meshData.vertexCount; 77 | NativeArray na_verticesVec2 = new NativeArray(vertexCount, allocator); 78 | meshData.GetUVs(channel, na_verticesVec2); 79 | na_uvs = na_verticesVec2.Reinterpret(); 80 | } 81 | 82 | /// Get native array of vertex colors. 83 | /// mesh data 84 | /// allocation type 85 | public static void NativeGetColors( 86 | in Mesh.MeshData meshData, 87 | out NativeArray na_colors, Allocator allocator) 88 | { 89 | int vertexCount = meshData.vertexCount; 90 | NativeArray na_colorsVec2 = new NativeArray(vertexCount, allocator); 91 | na_colors = new NativeArray(vertexCount, allocator); 92 | meshData.GetColors(na_colorsVec2); 93 | na_colors = na_colorsVec2.Reinterpret(); 94 | } 95 | 96 | /// Get native array of triangle indices. 97 | /// mesh data 98 | /// allocation type 99 | public static void NativeGetIndices( 100 | in Mesh.MeshData meshData, 101 | out NativeArray na_triangles, Allocator allocator, int submesh=0) 102 | { 103 | int indexCount = meshData.GetSubMesh(submesh).indexCount; 104 | na_triangles = new NativeArray(indexCount, allocator); 105 | meshData.GetIndices(na_triangles, submesh); 106 | } 107 | 108 | /// 109 | /// Reverse the triangle order of the mesh to flip the mesh 110 | /// 111 | /// mesh to be reversed 112 | public static void ReverseTriangleOrder(ref Mesh mesh) 113 | { 114 | for (int m = 0; m < mesh.subMeshCount; m++) 115 | { 116 | int[] triangles = mesh.GetTriangles(m); 117 | for (int t = 0; t < triangles.Length; t += 3) 118 | { 119 | int temp = triangles[t + 0]; 120 | triangles[t + 0] = triangles[t + 1]; 121 | triangles[t + 1] = temp; 122 | } 123 | mesh.SetTriangles(triangles, m); 124 | } 125 | 126 | Vector3[] normals = mesh.normals; 127 | for (int n=0; n < normals.Length; n++) normals[n] = -normals[n]; 128 | mesh.SetNormals(normals); 129 | } 130 | 131 | public static void SeparateTriangles( 132 | ref Vector3[] verts, 133 | ref ushort[] indices, 134 | ref Color[] colors, 135 | ref Vector2[] uvs, 136 | out Mesh mesh 137 | ) 138 | { 139 | int totalTris = indices.Length/3; 140 | Vector3[] newVerts = new Vector3[indices.Length]; 141 | ushort[] newIndices = new ushort[indices.Length]; 142 | Color[] newColors = new Color[indices.Length]; 143 | Vector2[] newUvs = new Vector2[indices.Length]; 144 | 145 | for (int t=0; t < totalTris; t++) 146 | { 147 | int t0 = indices[t*3]; 148 | int t1 = indices[t*3 + 1]; 149 | int t2 = indices[t*3 + 2]; 150 | 151 | newVerts[t*3] = verts[t0]; 152 | newVerts[t*3 + 1] = verts[t1]; 153 | newVerts[t*3 + 2] = verts[t2]; 154 | 155 | newColors[t*3] = colors[t0]; 156 | newColors[t*3 + 1] = colors[t1]; 157 | newColors[t*3 + 2] = colors[t2]; 158 | 159 | newUvs[t*3] = uvs[t0]; 160 | newUvs[t*3 + 1] = uvs[t1]; 161 | newUvs[t*3 + 2] = uvs[t2]; 162 | } 163 | 164 | for (ushort i=0; i < indices.Length; i++) newIndices[i] = i; 165 | 166 | mesh = new Mesh(); 167 | mesh.SetVertices(newVerts); 168 | mesh.SetIndices(newIndices, MeshTopology.Triangles, 0); 169 | mesh.SetColors(newColors); 170 | mesh.SetUVs(0, newUvs); 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 Voxell Technologies 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------