├── Editor ├── MobileNeRFScene.cs ├── MobileNeRFImporter.cs ├── Doji.MobileNeRF.asmdef.meta ├── Mlp.cs.meta ├── ShaderTemplate.cs.meta ├── MobileNeRFImporter.cs.meta ├── MobileNeRFScene.cs.meta ├── ObjImportProcessor.cs.meta ├── PNGImportProcessor.cs.meta ├── WebRequestAsyncUtility.cs.meta ├── Doji.MobileNeRF.asmdef ├── Mlp.cs ├── PNGImportProcessor.cs ├── ObjImportProcessor.cs ├── ShaderTemplate.cs └── WebRequestAsyncUtility.cs ├── CHANGELOG.md.meta ├── LICENSE.txt.meta ├── readme.md.meta ├── package.json.meta ├── Editor.meta ├── Third Party Notices.txt.meta ├── package.json ├── CHANGELOG.md ├── Third Party Notices.txt ├── LICENSE.txt ├── .gitignore └── readme.md /Editor/MobileNeRFScene.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julienkay/MobileNeRF-Unity-Viewer/HEAD/Editor/MobileNeRFScene.cs -------------------------------------------------------------------------------- /Editor/MobileNeRFImporter.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julienkay/MobileNeRF-Unity-Viewer/HEAD/Editor/MobileNeRFImporter.cs -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a1cc125fe711e9e46850930d4711b9b2 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cc0c970179e4cd6438b134f015e67f3f 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /readme.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8c704b83110fb5349aed26629a4d15d7 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19b9c07104ad4374196c8eb43a1317c1 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1c7358ccaf80ed04482be4e74ea60702 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Third Party Notices.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 93c13af626350cf4792e0477a1d7c9df 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/Doji.MobileNeRF.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 648fc805c72ae7c49bf0e39c0e9f8195 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/Mlp.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4cbeaa8c68a3b834f88cabe1efecd6c3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/ShaderTemplate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1dc0edd415f24e747abc0bdc1c5a45a2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/MobileNeRFImporter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b10acd302c8803d48babe8c612d26f80 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/MobileNeRFScene.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a0d80641e9f59c94491d5bf137c38e5a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/ObjImportProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4129a0e7f3ee6484b8e9d548046015ae 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/PNGImportProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d5e5cd8c1458ed44aba0c9348b36861 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/WebRequestAsyncUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b257fece027b7a94a87a6ec25e32a6d6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.doji.mobilenerf", 3 | "version": "1.1.0", 4 | "displayName": "MobileNeRF", 5 | "description": "An unofficial Unity port of the MobileNeRF viewer.", 6 | "dependencies": 7 | { 8 | "com.unity.nuget.newtonsoft-json": "3.0.2" 9 | }, 10 | "author": 11 | { 12 | "name": "Doji Technologies", 13 | "email": "support@doji-tech.com", 14 | "url": "https://www.doji-tech.com/" 15 | } 16 | } -------------------------------------------------------------------------------- /Editor/Doji.MobileNeRF.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Doji.MobileNeRF", 3 | "rootNamespace": "", 4 | "references": [], 5 | "includePlatforms": [ 6 | "Editor" 7 | ], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [], 14 | "versionDefines": [], 15 | "noEngineReferences": false 16 | } -------------------------------------------------------------------------------- /Editor/Mlp.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | public partial class Mlp { 4 | [JsonProperty("0_weights")] 5 | public double[][] _0Weights; 6 | 7 | [JsonProperty("1_weights")] 8 | public double[][] _1Weights; 9 | 10 | [JsonProperty("2_weights")] 11 | public double[][] _2Weights; 12 | 13 | [JsonProperty("0_bias")] 14 | public double[] _0Bias; 15 | 16 | [JsonProperty("1_bias")] 17 | public double[] _1Bias; 18 | 19 | [JsonProperty("2_bias")] 20 | public double[] _2Bias; 21 | 22 | [JsonProperty("obj_num")] 23 | public int ObjNum; 24 | } -------------------------------------------------------------------------------- /Editor/PNGImportProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | /// 6 | /// Configures MobileNeRF feature textures to have the correct import settings. 7 | /// 8 | public class PNGImportProcessor : AssetPostprocessor { 9 | 10 | private void OnPreprocessTexture() { 11 | Regex featureTexturePattern = new Regex(@"shape[0-9].pngfeat[0-9]\.png"); 12 | if (featureTexturePattern.IsMatch(assetPath)) { 13 | TextureImporter textureImporter = assetImporter as TextureImporter; 14 | textureImporter.maxTextureSize = 4096; 15 | textureImporter.textureCompression = TextureImporterCompression.Uncompressed; 16 | textureImporter.sRGBTexture = false; 17 | textureImporter.filterMode = FilterMode.Point; 18 | textureImporter.mipmapEnabled = false; 19 | textureImporter.alphaIsTransparency = false; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.1.0] - 2023-05-28 9 | 10 | ### Changed 11 | 12 | - Optimized network evaluation shader code (thanks to [@mrxz](https://github.com/mrxz)) 13 | 14 | ## [1.0.1] - 2023-04-07 15 | 16 | ### Changed 17 | 18 | - Remove Unity version restriction from package 19 | 20 | ## [1.0.0] - 2023-04-07 21 | 22 | ### Added 23 | 24 | - Add support for 'Linear' color space 25 | 26 | ### Changed 27 | 28 | - Convert to package format 29 | 30 | ## [x.x.x] - 2022-09-01 31 | 32 | ### Added 33 | 34 | - Add support for importing your own trained datasets 35 | 36 | ## [x.x.x] - 2022-08-24 37 | 38 | ### Added 39 | 40 | - Add support for Single Pass Instanced rendering 41 | 42 | ## [x.x.x] - 2022-08-23 43 | 44 | ### Added 45 | 46 | - Add support for shadows 47 | 48 | ## [x.x.x] - 2022-08-07 49 | Initial Release -------------------------------------------------------------------------------- /Editor/ObjImportProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using UnityEditor; 3 | 4 | /// 5 | /// Custom import settings for MobileNeRF OBJs. 6 | /// 7 | public class ObjImportProcessor : AssetPostprocessor { 8 | private void OnPreprocessModel() { 9 | Regex objPattern = new Regex(@"shape.*\.obj"); 10 | 11 | if (objPattern.IsMatch(assetPath)) { 12 | ModelImporter modelImporter = assetImporter as ModelImporter; 13 | // MobileNeRFs don't use normals, so we disable trying to read them when importing .obj files 14 | // This is not strictly necessary, but prevents the warnings showing in the console. 15 | modelImporter.importTangents = ModelImporterTangents.None; 16 | modelImporter.importNormals = ModelImporterNormals.None; 17 | 18 | // one material per shape (each has individual feature textures) 19 | modelImporter.materialLocation = ModelImporterMaterialLocation.External; 20 | modelImporter.materialName = ModelImporterMaterialName.BasedOnModelNameAndMaterialName; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Third Party Notices.txt: -------------------------------------------------------------------------------- 1 | This project uses third-party libraries or other resources that may 2 | be distributed under licenses different than the project itself. 3 | 4 | In the event that we accidentally failed to list a required notice, 5 | please bring it to our attention. 6 | 7 | The attached notices are provided for information only. 8 | 9 | MobileNeRF: Exploiting the Polygon Rasterization Pipeline for Efficient Neural Field Rendering on Mobile Architectures 10 | --------------------------------------------------------------------------------------------------------------------- 11 | 12 | Licensed under the Apache License, Version 2.0 (the "License"); 13 | you may not use this file except in compliance with the License. 14 | You may obtain a copy of the License at 15 | 16 | http://www.apache.org/licenses/LICENSE-2.0 17 | 18 | Unless required by applicable law or agreed to in writing, software 19 | distributed under the License is distributed on an "AS IS" BASIS, 20 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | See the License for the specific language governing permissions and 22 | limitations under the License. -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Julien Kipp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Uu]ser[Ss]ettings/ 12 | 13 | # MemoryCaptures can get excessive in size. 14 | # They also could contain extremely sensitive data 15 | /[Mm]emoryCaptures/ 16 | 17 | # Asset meta data should only be ignored when the corresponding asset is also ignored 18 | !/[Aa]ssets/**/*.meta 19 | 20 | # Uncomment this line if you wish to ignore the asset store tools plugin 21 | # /[Aa]ssets/AssetStoreTools* 22 | 23 | # Autogenerated Jetbrains Rider plugin 24 | /[Aa]ssets/Plugins/Editor/JetBrains* 25 | 26 | # Visual Studio cache directory 27 | .vs/ 28 | 29 | # Gradle cache directory 30 | .gradle/ 31 | 32 | # Autogenerated VS/MD/Consulo solution and project files 33 | ExportedObj/ 34 | .consulo/ 35 | *.csproj 36 | *.unityproj 37 | *.sln 38 | *.suo 39 | *.tmp 40 | *.user 41 | *.userprefs 42 | *.pidb 43 | *.booproj 44 | *.svd 45 | *.pdb 46 | *.mdb 47 | *.opendb 48 | *.VC.db 49 | *.editorconfig 50 | *.vsconfig 51 | 52 | # Unity3D generated meta files 53 | *.pidb.meta 54 | *.pdb.meta 55 | *.mdb.meta 56 | 57 | # Unity3D generated file on crash reports 58 | sysinfo.txt 59 | 60 | # Builds 61 | *.apk 62 | *.aab 63 | *.unitypackage 64 | 65 | # Crashlytics generated file 66 | crashlytics-build.properties 67 | 68 | # Packed Addressables 69 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* 70 | 71 | # Temporary auto-generated Android Assets 72 | /[Aa]ssets/[Ss]treamingAssets/aa.meta 73 | /[Aa]ssets/[Ss]treamingAssets/aa/* 74 | 75 | 76 | ---------------------------------------------------- 77 | 78 | 79 | # ============ # 80 | # OS generated # 81 | # ============ # 82 | .DS_Store 83 | .DS_Store? 84 | ._* 85 | .Spotlight-V100 86 | .Trashes 87 | ehthumbs.db 88 | Thumbs.db 89 | 90 | 91 | # ====== # 92 | # custom # 93 | # ====== # 94 | /[Aa]ssets/[Mm]obileNeRF Data/ -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # MobileNeRF Unity Viewer 2 | 3 | ![MobileNeRF Unity Viewer](https://user-images.githubusercontent.com/26555424/230574173-4f6ed62e-2c58-4b90-a350-378df73b97c8.gif) 4 | 5 | This repository contains the source code for a Unity port of the web viewer from the paper [MobileNeRF: Exploiting the Polygon Rasterization Pipeline for Efficient Neural Field Rendering on Mobile Architectures](https://mobile-nerf.github.io/)[^1] 6 | 7 | *Please note, that this is an unofficial port. I am not affiliated with the original authors or their institution.* 8 | 9 | ## Usage 10 | 11 | ### Installation 12 | 13 | Go to the [releases section](https://github.com/julienkay/MobileNeRF-Unity-Viewer/releases/latest), download the Unity Package, and import it into any Unity project. This is a 'Hybrid Package' that will install into your project as a local package. 14 | 15 | ##### Alternatives 16 | 17 |
18 | UPM Package via OpenUPM 19 | 20 | In `Edit -> Project Settings -> Package Manager`, add a new scoped registry: 21 | 22 | Name: Doji 23 | URL: https://package.openupm.com 24 | Scope(s): com.doji 25 | 26 | In the Package Manager install 'com.doji.mobilenerf either by name or via `Package Manager -> My Registries` 27 |
28 | 29 |
30 | UPM Package via Git URL 31 | 32 | In `Package Manager -> Add package from git URL...` paste `https://github.com/julienkay/MobileNeRF-Unity-Viewer.git` [as described here](https://docs.unity3d.com/Manual/upm-ui-giturl) 33 |
34 | 35 | ### Importing sample scenes 36 | 37 | After succesful installation, you can use the menu `MobileNeRF -> Asset Downloads` to download any of the sample scenes available. 38 | In each scene folder there will be a convenient prefab, that you can then drag into the scene and you're good to go. 39 | 40 | ### Updating 41 | 42 | Since the initial release a small number of features have been added to the automatic shader generation code. 43 | That means, that if you have already downloaded some scenes before, you'll have to regenerate the source files by going to `MobileNeRF -> Asset Downloads` again. 44 | (This will not actually redownload Assets unless necessary, so this shouldn't take too long) 45 | 46 | ### Importing self-trained scenes 47 | 48 | If you have successfully trained your own MobileNeRF scenes using the [official code release](https://github.com/google-research/jax3d/tree/main/jax3d/projects/mobilenerf) and want to render them in Unity, you can use the menu *MobileNeRF -> Import from disk*. 49 | This lets you choose a folder that should contain all the output files of your training process. 50 | 51 | More specifically, the following assets are required: 52 | - multiple shapes as OBJ files with naming convention: shapeX.obj 53 | - multiple PNG files with naming convention: shapeX.pngfeatZ.png (where Z goes from 0 to 1, so 2 .pngs per shape) 54 | - The weights of the MLP in a file called mlp.json 55 | 56 | ## Details 57 | 58 | The project was created with Unity 2021.3 LTS using the Built-in Render Pipeline. 59 | 60 | The biggest deviation from the official viewer is, that this project doesn't use Deferred Rendering, but uses Forward Rendering instead. 61 | This has certain implications on performance. 62 | While the MobileNeRF representation itself greatly reduces the cost to render NeRFs, it still requires evaluating a small, view-dependent MLP (Multi Layer Perceptron) per fragment. Whenever the bottleneck is in the fragment shader, Deferred Rendering has obvious advantages, as each pixel only needs to run a single fragment shader. 63 | 64 | Forward Rendering however gives us MSAA, which is important for VR use cases. Additionally, in VR the image has to be rendered twice, once for each eye, with a fairly large resolution. The larger the G-buffer, the smaller the benefit of Deferred Rendering. Still, MobileNeRFs mesh representations have a fairly large poly count which works against us using Forward Rendering here. 65 | 66 | Some things to possibly look into: 67 | * Forward Rendering, but do a Depth Prepass to reduce overdraw (might require URP, see [here](https://forum.unity.com/threads/need-clarification-on-urps-use-of-the-depth-prepass.1004577/) and [here](https://gist.github.com/aras-p/5e3aa6f81c543ca74e3ae296c72ffcaf)) 68 | * Implement Deferred Rendering and compare performance in various scenarios 69 | 70 | ## Known Issues 71 | 72 | - Does not work well with MSAA. For now, I recommend turning MSAA off in `Project Settings -> Quality -> Anti Aliasing` 73 | 74 | ## References 75 | 76 | Thanks to 77 | 78 | - [@mrxz](https://github.com/mrxz) for providing some major performance optimizations as part of his [WebXR port](https://github.com/mrxz/mobilenerf-viewer-webxr) 79 | 80 | Other projects exploring NeRFs and related techniques in Unity: 81 | - [SNeRG (Sparse Neural Radiance Grids)](https://github.com/julienkay/SNeRG-Unity-Viewer) 82 | - [MERF (Memory Efficient Radiance Fields)](https://github.com/julienkay/MERF-Unity-Viewer) 83 | 84 | [^1]: [Zhiqin Chen and Thomas Funkhouser and Peter Hedman and Andrea Tagliasacchi. MobileNeRF: Exploiting the Polygon Rasterization Pipeline for Efficient Neural Field Rendering on Mobile Architectures. arXiv preprint arXiv:2208.00277, 2022](https://mobile-nerf.github.io/) 85 | -------------------------------------------------------------------------------- /Editor/ShaderTemplate.cs: -------------------------------------------------------------------------------- 1 | public static class ViewDependenceNetworkShader { 2 | public const string Template = @"Shader ""MobileNeRF/ViewDependenceNetworkShader/OBJECT_NAME"" { 3 | Properties { 4 | tDiffuse0x (""Diffuse Texture 0"", 2D) = ""white"" {} 5 | tDiffuse1x (""Diffuse Texture 1"", 2D) = ""white"" {} 6 | } 7 | 8 | CGINCLUDE 9 | #include ""UnityCG.cginc"" 10 | 11 | struct appdata { 12 | float4 vertex : POSITION; 13 | float2 uv : TEXCOORD0; 14 | UNITY_VERTEX_INPUT_INSTANCE_ID 15 | }; 16 | 17 | struct v2f { 18 | float2 uv : TEXCOORD0; 19 | float4 vertex : SV_POSITION; 20 | float3 rayDirection : TEXCOORD1; 21 | UNITY_VERTEX_OUTPUT_STEREO 22 | }; 23 | 24 | v2f vert(appdata v) { 25 | v2f o; 26 | 27 | UNITY_SETUP_INSTANCE_ID(v); 28 | UNITY_INITIALIZE_OUTPUT(v2f, o); 29 | UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); 30 | 31 | o.vertex = UnityObjectToClipPos(v.vertex); 32 | o.uv = v.uv; 33 | o.rayDirection = -WorldSpaceViewDir(v.vertex); 34 | AXIS_SWIZZLE 35 | 36 | return o; 37 | } 38 | 39 | sampler2D tDiffuse0x; 40 | sampler2D tDiffuse1x; 41 | 42 | half3 evaluateNetwork(fixed4 f0, fixed4 f1, fixed4 viewdir) { 43 | float4x4 intermediate_one = { BIAS_LIST_ZERO }; 44 | intermediate_one += f0.r * float4x4(__W0_0__) 45 | + f0.g * float4x4(__W0_1__) 46 | + f0.b * float4x4(__W0_2__) 47 | + f0.a * float4x4(__W0_3__) 48 | + f1.r * float4x4(__W0_4__) 49 | + f1.g * float4x4(__W0_5__) 50 | + f1.b * float4x4(__W0_6__) 51 | + f1.a * float4x4(__W0_7__) 52 | + viewdir.r * float4x4(__W0_8__) 53 | + viewdir.g * float4x4(__W0_9__) 54 | + viewdir.b * float4x4(__W0_10__); 55 | intermediate_one[0] = max(intermediate_one[0], 0.0); 56 | intermediate_one[1] = max(intermediate_one[1], 0.0); 57 | intermediate_one[2] = max(intermediate_one[2], 0.0); 58 | intermediate_one[3] = max(intermediate_one[3], 0.0); 59 | float4x4 intermediate_two = float4x4( 60 | BIAS_LIST_ONE 61 | ); 62 | intermediate_two += intermediate_one[0][0] * float4x4(__W1_0__) 63 | + intermediate_one[0][1] * float4x4(__W1_1__) 64 | + intermediate_one[0][2] * float4x4(__W1_2__) 65 | + intermediate_one[0][3] * float4x4(__W1_3__) 66 | + intermediate_one[1][0] * float4x4(__W1_4__) 67 | + intermediate_one[1][1] * float4x4(__W1_5__) 68 | + intermediate_one[1][2] * float4x4(__W1_6__) 69 | + intermediate_one[1][3] * float4x4(__W1_7__) 70 | + intermediate_one[2][0] * float4x4(__W1_8__) 71 | + intermediate_one[2][1] * float4x4(__W1_9__) 72 | + intermediate_one[2][2] * float4x4(__W1_10__) 73 | + intermediate_one[2][3] * float4x4(__W1_11__) 74 | + intermediate_one[3][0] * float4x4(__W1_12__) 75 | + intermediate_one[3][1] * float4x4(__W1_13__) 76 | + intermediate_one[3][2] * float4x4(__W1_14__) 77 | + intermediate_one[3][3] * float4x4(__W1_15__); 78 | intermediate_two[0] = max(intermediate_two[0], 0.0); 79 | intermediate_two[1] = max(intermediate_two[1], 0.0); 80 | intermediate_two[2] = max(intermediate_two[2], 0.0); 81 | intermediate_two[3] = max(intermediate_two[3], 0.0); 82 | float3 result = float3( 83 | BIAS_LIST_TWO 84 | ); 85 | result += intermediate_two[0][0] * float3(__W2_0__) 86 | + intermediate_two[0][1] * float3(__W2_1__) 87 | + intermediate_two[0][2] * float3(__W2_2__) 88 | + intermediate_two[0][3] * float3(__W2_3__) 89 | + intermediate_two[1][0] * float3(__W2_4__) 90 | + intermediate_two[1][1] * float3(__W2_5__) 91 | + intermediate_two[1][2] * float3(__W2_6__) 92 | + intermediate_two[1][3] * float3(__W2_7__) 93 | + intermediate_two[2][0] * float3(__W2_8__) 94 | + intermediate_two[2][1] * float3(__W2_9__) 95 | + intermediate_two[2][2] * float3(__W2_10__) 96 | + intermediate_two[2][3] * float3(__W2_11__) 97 | + intermediate_two[3][0] * float3(__W2_12__) 98 | + intermediate_two[3][1] * float3(__W2_13__) 99 | + intermediate_two[3][2] * float3(__W2_14__) 100 | + intermediate_two[3][3] * float3(__W2_15__); 101 | result = 1.0 / (1.0 + exp(-result)); 102 | return result*viewdir.a+(1.0-viewdir.a); 103 | } 104 | ENDCG 105 | 106 | SubShader { 107 | Cull Off 108 | ZTest LEqual 109 | 110 | Pass { 111 | CGPROGRAM 112 | 113 | #pragma vertex vert 114 | #pragma fragment frag 115 | 116 | fixed4 frag(v2f i) : SV_Target { 117 | fixed4 diffuse0 = tex2D( tDiffuse0x, i.uv ); 118 | if (diffuse0.r == 0.0) discard; 119 | fixed4 diffuse1 = tex2D( tDiffuse1x, i.uv ); 120 | fixed4 rayDir = fixed4(normalize(i.rayDirection), 1.0); 121 | 122 | // normalize range to [-1, 1] 123 | diffuse0.a = diffuse0.a * 2.0 - 1.0; 124 | diffuse1.a = diffuse1.a * 2.0 - 1.0; 125 | 126 | fixed4 fragColor; 127 | fragColor.rgb = evaluateNetwork(diffuse0,diffuse1,rayDir); 128 | fragColor.a = 1.0; 129 | 130 | #if(!UNITY_COLORSPACE_GAMMA) 131 | fragColor.rgb = GammaToLinearSpace(fragColor.rgb); 132 | #endif 133 | 134 | return fragColor; 135 | } 136 | ENDCG 137 | } 138 | 139 | // ------------------------------------------------------------------ 140 | // Shadow rendering pass 141 | Pass { 142 | Tags {""LightMode"" = ""ShadowCaster""} 143 | 144 | CGPROGRAM 145 | 146 | #pragma vertex vert 147 | #pragma fragment fragShadowCaster 148 | #pragma multi_compile_shadowcaster 149 | 150 | fixed4 fragShadowCaster(v2f i) : SV_Target{ 151 | fixed4 diffuse0 = tex2D(tDiffuse0x, i.uv); 152 | if (diffuse0.r == 0.0) discard; 153 | return 0; 154 | } 155 | ENDCG 156 | } 157 | } 158 | }"; 159 | } 160 | -------------------------------------------------------------------------------- /Editor/WebRequestAsyncUtility.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using Newtonsoft.Json; 3 | using UnityEngine.Networking; 4 | using System; 5 | using System.Threading.Tasks; 6 | using System.Text; 7 | 8 | public enum HTTPVerb { GET, POST }; 9 | 10 | public static class WebRequestAsyncUtility { 11 | 12 | public static class WebRequestAsync { 13 | 14 | /// 15 | /// Performs a WebRequest with the given URL. The response is expected to be a JSON serialized 16 | /// object of type and is automatically being deserialized and returned. 17 | /// 18 | /// the type that this web request returns. 19 | public static async Task SendWebRequestAsync(string url, HTTPVerb verb = HTTPVerb.GET, string postData = null, params Tuple[] requestHeaders) { 20 | UnityWebRequest wr = GetRequest(url, verb, postData, requestHeaders); 21 | if (wr == null) { 22 | return default; 23 | } 24 | 25 | try { 26 | var asyncOp = wr.SendWebRequest(); 27 | while (!asyncOp.webRequest.isDone) { 28 | await Task.Yield(); 29 | } 30 | 31 | switch (asyncOp.webRequest.result) { 32 | case UnityWebRequest.Result.InProgress: 33 | break; 34 | case UnityWebRequest.Result.Success: 35 | return JsonConvert.DeserializeObject(asyncOp.webRequest.downloadHandler.text); 36 | case UnityWebRequest.Result.ConnectionError: 37 | case UnityWebRequest.Result.ProtocolError: 38 | case UnityWebRequest.Result.DataProcessingError: 39 | Debug.LogError($"{asyncOp.webRequest.result}: {asyncOp.webRequest.error}\nURL: {asyncOp.webRequest.url}"); 40 | Debug.LogError($"{asyncOp.webRequest.downloadHandler.text}"); 41 | break; 42 | default: 43 | break; 44 | } 45 | 46 | } catch (Exception e) { 47 | Debug.LogError(e); 48 | } finally { 49 | wr.Dispose(); 50 | } 51 | return default; 52 | } 53 | } 54 | 55 | /// 56 | /// Simple WebRequest without JSON parsing. Returns plain text. 57 | /// 58 | public class WebRequestSimpleAsync { 59 | 60 | public static async Task SendWebRequestAsync(string url, HTTPVerb verb = HTTPVerb.GET, string postData = null, params Tuple[] requestHeaders) { 61 | UnityWebRequest wr = GetRequest(url, verb, postData, requestHeaders); 62 | if (wr == null) { 63 | return default; 64 | } 65 | 66 | try { 67 | var asyncOp = wr.SendWebRequest(); 68 | while (!asyncOp.webRequest.isDone) { 69 | await Task.Yield(); 70 | } 71 | 72 | switch (asyncOp.webRequest.result) { 73 | case UnityWebRequest.Result.InProgress: 74 | break; 75 | case UnityWebRequest.Result.Success: 76 | return asyncOp.webRequest.downloadHandler.text; 77 | case UnityWebRequest.Result.ConnectionError: 78 | case UnityWebRequest.Result.ProtocolError: 79 | case UnityWebRequest.Result.DataProcessingError: 80 | Debug.LogError($"{asyncOp.webRequest.result}: {asyncOp.webRequest.error}\nURL: {asyncOp.webRequest.url}"); 81 | Debug.LogError($"{asyncOp.webRequest.downloadHandler.text}"); 82 | break; 83 | default: 84 | break; 85 | } 86 | 87 | } catch (Exception e) { 88 | Debug.LogError(e); 89 | } finally { 90 | wr.Dispose(); 91 | } 92 | return default; 93 | } 94 | } 95 | 96 | /// 97 | /// WebRequest for binary data. 98 | /// 99 | public class WebRequestBinaryAsync { 100 | 101 | public static async Task SendWebRequestAsync(string url, HTTPVerb verb = HTTPVerb.GET, string postData = null, params Tuple[] requestHeaders) { 102 | UnityWebRequest wr = GetRequest(url, verb, postData, requestHeaders); 103 | if (wr == null) { 104 | return default; 105 | } 106 | 107 | try { 108 | var asyncOp = wr.SendWebRequest(); 109 | while (!asyncOp.webRequest.isDone) { 110 | await Task.Yield(); 111 | } 112 | 113 | switch (asyncOp.webRequest.result) { 114 | case UnityWebRequest.Result.InProgress: 115 | break; 116 | case UnityWebRequest.Result.Success: 117 | return asyncOp.webRequest.downloadHandler.data; 118 | case UnityWebRequest.Result.ConnectionError: 119 | case UnityWebRequest.Result.ProtocolError: 120 | case UnityWebRequest.Result.DataProcessingError: 121 | Debug.LogError($"{asyncOp.webRequest.result}: {asyncOp.webRequest.error}\nURL: {asyncOp.webRequest.url}"); 122 | Debug.LogError($"{asyncOp.webRequest.downloadHandler.text}"); 123 | break; 124 | default: 125 | break; 126 | } 127 | 128 | } catch (Exception e) { 129 | Debug.LogError(e); 130 | } finally { 131 | wr.Dispose(); 132 | } 133 | return default; 134 | } 135 | } 136 | 137 | private static UnityWebRequest GetRequest(string url, HTTPVerb verb, string postData, params Tuple[] requestHeaders) { 138 | UnityWebRequest webRequest; 139 | 140 | switch (verb) { 141 | case HTTPVerb.GET: 142 | webRequest = UnityWebRequest.Get(url); 143 | break; 144 | case HTTPVerb.POST: 145 | #if UNITY_2022_2_OR_NEWER 146 | webRequest = UnityWebRequest.PostWwwForm(url, postData); 147 | #else 148 | webRequest = UnityWebRequest.Post(url, postData); 149 | #endif 150 | byte[] rawBody = Encoding.UTF8.GetBytes(postData); 151 | webRequest.uploadHandler = new UploadHandlerRaw(rawBody); 152 | webRequest.downloadHandler = new DownloadHandlerBuffer(); 153 | webRequest.SetRequestHeader("Content-Type", "application/json"); 154 | break; 155 | default: 156 | Debug.LogError("Invalid HTTP request method."); 157 | return null; 158 | } 159 | 160 | // set optional headers 161 | if (requestHeaders != null) { 162 | foreach (var header in requestHeaders) { 163 | webRequest.SetRequestHeader(header.Item1, header.Item2); 164 | } 165 | } 166 | 167 | return webRequest; 168 | } 169 | } --------------------------------------------------------------------------------