├── LICENSE.txt ├── README.md ├── SimpleVDBLoader ├── DDAVolume.cs ├── FlyCamera.cs ├── OpenVDBReader.cs ├── Resources │ └── RenderVolume.compute ├── Vol.unity └── cloud_02_variant_0000.vdb ├── VolumeImages ├── 1.png └── 2.png └── VolumeLoader.unitypackage /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Payton Leather 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unofficial-Basic-Embergen-VDB-Loader-for-Unity 2 | # NOT OFFICIAL FROM EMBERGEN; just a utility I made to load them into unity and uploaded in case anyone else finds it useful 3 | ## If you like what I do and want to support me and this project(as this takes a LOT of my time), consider becoming a Github Sponsor! 4 |
5 | Basic VDB loader to load embergen vdb's into unity, paired with a basic small realtime volume renderer 6 |
7 | To load a single file, just drag it into the object field in the script of the MainCamera component 8 |
9 | To load multiple files to be animated, drag a folder with vdb's in it into the object field 10 |
11 | Press play and it will load and render the files(may take a bit) 12 |
13 | Uses a lot of memory 14 |
15 | Cannot load compressed files 16 | 17 | ## Example Images 18 | 19 | ![](/VolumeImages/1.png) 20 | ![](/VolumeImages/2.png) 21 | 22 | -------------------------------------------------------------------------------- /SimpleVDBLoader/DDAVolume.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.IO; 5 | using UnityEditor; 6 | using System.Threading.Tasks; 7 | using System.Threading; 8 | 9 | public class DDAVolume : MonoBehaviour 10 | { 11 | public Object FileIn; 12 | ComputeShader VolumeShader; 13 | ComputeBuffer ShadowBuffer; 14 | ComputeBuffer[] ValidVoxelSitesBuffer; 15 | ComputeBuffer UnityLightBuffer; 16 | RenderTexture MainTex; 17 | RenderTexture VolumeTex; 18 | Texture3D VolumeTex2; 19 | Vector4[] NonZeroVoxels; 20 | 21 | [Range(1, 10)] 22 | public int ShadowDistanceOffset = 1; 23 | [System.Serializable] 24 | public struct UnityLight { 25 | public Vector3 Position; 26 | public Vector3 Direction; 27 | public int Type; 28 | public Vector3 Col; 29 | } 30 | UnityLight[] UnityLightData; 31 | Light[] UnityLights; 32 | OpenVDBReader[] VDBFileArray; 33 | Vector3[] Sizes; 34 | 35 | 36 | private void CreateRenderTexture(ref RenderTexture ThisTex) 37 | { 38 | ThisTex = new RenderTexture(Screen.width, Screen.height, 0, 39 | RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.sRGB); 40 | ThisTex.enableRandomWrite = true; 41 | ThisTex.Create(); 42 | } 43 | void Start() 44 | { 45 | UnityLights = Object.FindObjectsOfType(); 46 | UnityLightData = new UnityLight[UnityLights.Length]; 47 | for(int i = 0; i < UnityLights.Length; i++) { 48 | Light ThisLight = UnityLights[i]; 49 | Color col = ThisLight.color; 50 | UnityLightData[i].Position = ThisLight.transform.position; 51 | UnityLightData[i].Direction = ThisLight.transform.forward; 52 | UnityLightData[i].Type = (ThisLight.type == LightType.Point) ? 0 : (ThisLight.type == LightType.Directional) ? 1 : (ThisLight.type == LightType.Spot) ? 2 : 3; 53 | UnityLightData[i].Col = new Vector3(col[0], col[1], col[2]) * ThisLight.intensity; 54 | } 55 | CreateRenderTexture(ref MainTex); 56 | string CachedString = AssetDatabase.GetAssetPath(FileIn); 57 | VolumeShader = Resources.Load("RenderVolume"); 58 | uint CurVox = 0; 59 | string[] Materials; 60 | if(CachedString.Contains(".vdb")) { 61 | Materials = new string[]{Application.dataPath + CachedString.Replace("Assets", "").Replace("/" + FileIn.name, "\\" + FileIn.name)}; 62 | } else { 63 | Materials = System.IO.Directory.GetFiles(Application.dataPath + CachedString.Replace("Assets", "")); 64 | } 65 | VDBFileArray = new OpenVDBReader[Materials.Length]; 66 | List Material3 = new List(); 67 | for(int i2 = 0; i2 < Materials.Length; i2++) { 68 | if(Materials[i2].Contains("meta")) continue; 69 | if(!Materials[i2].Contains("vdb")) continue; 70 | Material3.Add(Materials[i2]); 71 | } 72 | Materials = Material3.ToArray(); 73 | Sizes = new Vector3[Materials.Length]; 74 | ValidVoxelSitesBuffer = new ComputeBuffer[Materials.Length]; 75 | List RunningTasks = new List(); 76 | for(int i2 = 0; i2 < Materials.Length; i2++) { 77 | var A = i2; 78 | VDBFileArray[A] = new OpenVDBReader(); 79 | Task t1 = Task.Run(() => { VDBFileArray[A].ParseVDB(Materials[A], A);}); 80 | RunningTasks.Add(t1); 81 | } 82 | 83 | while(RunningTasks.Count != 0) { 84 | int TaskCount = RunningTasks.Count; 85 | for(int i = TaskCount - 1; i >= 0; i--) { 86 | if (RunningTasks[i].IsFaulted) { 87 | Debug.Log(RunningTasks[i].Exception); 88 | RunningTasks.RemoveAt(i); 89 | } else if(RunningTasks[i].Status == TaskStatus.RanToCompletion) { 90 | RunningTasks.RemoveAt(i); 91 | } 92 | } 93 | } 94 | 95 | int CurGrid = 0; 96 | for(int i2 = 0; i2 < Materials.Length; i2++) { 97 | OpenVDBReader VDBFile = VDBFileArray[i2]; 98 | Vector3 OrigionalSize = new Vector3(VDBFile.Grids[CurGrid].Size.x, VDBFile.Grids[CurGrid].Size.z, VDBFile.Grids[CurGrid].Size.y); 99 | NonZeroVoxels = new Vector4[VDBFile.Grids[CurGrid].Centers.Count]; 100 | VDBFile.Size = OrigionalSize; 101 | 102 | int RepCount = 0; 103 | OpenVDBReader.Node4 CurNode; 104 | OpenVDBReader.Node3 CurNode2; 105 | OpenVDBReader.Voxel Vox; 106 | Vector3Int ijk = new Vector3Int(0,0,0); 107 | Vector3 location2 = Vector3.zero; 108 | uint CurOffset = 0; 109 | for(int i = 0; i < VDBFile.Grids[CurGrid].Centers.Count; i++) { 110 | ulong BitIndex1 = (ulong)((((int)VDBFile.Grids[CurGrid].Centers[i].x & 4095) >> 7) | ((((int)VDBFile.Grids[CurGrid].Centers[i].y & 4095) >> 7) << 5) | ((((int)VDBFile.Grids[CurGrid].Centers[i].z & 4095) >> 7) << 10)); 111 | ulong BitIndex2 = (ulong)((((int)VDBFile.Grids[CurGrid].Centers[i].x & 127) >> 3) | ((((int)VDBFile.Grids[CurGrid].Centers[i].y & 127) >> 3) << 4) | ((((int)VDBFile.Grids[CurGrid].Centers[i].z & 127) >> 3) << 8)); 112 | ulong BitIndex3 = (ulong)((((int)VDBFile.Grids[CurGrid].Centers[i].x & 7) >> 0) | ((((int)VDBFile.Grids[CurGrid].Centers[i].y & 7) >> 0) << 3) | ((((int)VDBFile.Grids[CurGrid].Centers[i].z & 7) >> 0) << 6)); 113 | 114 | if(VDBFile.Grids[CurGrid].RootNode.Children.TryGetValue(BitIndex1, out CurNode)) { 115 | if(CurNode.Children.TryGetValue(BitIndex2, out CurNode2)) { 116 | if(CurNode2.Children.TryGetValue(BitIndex3, out Vox)) { 117 | location2 = new Vector3(VDBFile.Grids[CurGrid].Centers[i].z, VDBFile.Grids[CurGrid].Centers[i].x, VDBFile.Grids[CurGrid].Centers[i].y); 118 | float Val = System.BitConverter.ToSingle(System.BitConverter.GetBytes((uint)Vox.Density)) * 100000000000000000000000000000000000000.0f * 50.0f; 119 | if(Val > 0.01f) { 120 | NonZeroVoxels[CurOffset] = new Vector4(location2.x, location2.y, location2.z, Val); 121 | CurOffset++; 122 | } 123 | } 124 | } 125 | } 126 | } 127 | VDBFileArray[i2] = null; 128 | ValidVoxelSitesBuffer[i2] = new ComputeBuffer((int)CurOffset, 16); 129 | ValidVoxelSitesBuffer[i2].SetData(NonZeroVoxels); 130 | VolumeShader.SetVector("Size", VDBFile.Size); 131 | Sizes[i2] = VDBFile.Size; 132 | } 133 | VolumeTex2 = new Texture3D((int)Sizes[0].x, (int)Sizes[0].y, (int)Sizes[0].z, TextureFormat.RFloat, false); 134 | Debug.Log("Active Voxels: " + NonZeroVoxels.Length + ", Inactive Voxels: " + (VolumeTex2.width * VolumeTex2.height * VolumeTex2.depth - NonZeroVoxels.Length)); 135 | VolumeTex = new RenderTexture((int)Sizes[0].x, (int)Sizes[0].y, 0, RenderTextureFormat.RFloat, RenderTextureReadWrite.sRGB); 136 | VolumeTex.enableRandomWrite = true; 137 | VolumeTex.volumeDepth = (int)Sizes[0].z; 138 | VolumeTex.dimension = UnityEngine.Rendering.TextureDimension.Tex3D; 139 | VolumeTex.Create(); 140 | ShadowBuffer = new ComputeBuffer(VolumeTex2.width * VolumeTex2.height * VolumeTex2.depth, 8); 141 | UnityLightBuffer = new ComputeBuffer(UnityLights.Length, 40); 142 | VolumeShader.SetBuffer(2, "ShadowBuffer", ShadowBuffer); 143 | VolumeShader.SetBuffer(0, "ShadowBuffer", ShadowBuffer); 144 | VolumeShader.SetBuffer(1, "ShadowBuffer", ShadowBuffer); 145 | VolumeShader.SetBuffer(2, "UnityLights", UnityLightBuffer); 146 | VolumeShader.SetInt("ScreenWidth", Screen.width); 147 | VolumeShader.SetInt("ScreenHeight", Screen.height); 148 | } 149 | 150 | void OnApplicationQuit() 151 | { 152 | UnityLightBuffer.Release(); 153 | VolumeTex.Release(); 154 | if (ValidVoxelSitesBuffer != null) for(int i = 0; i < ValidVoxelSitesBuffer.Length; i++) ValidVoxelSitesBuffer[i].Release(); 155 | } 156 | float CurFrame = 0; 157 | private void OnRenderImage(RenderTexture source, RenderTexture destination) 158 | { 159 | VolumeShader.SetInt("CurFrame", (int)Mathf.Floor(CurFrame)); 160 | VolumeShader.SetInt("LightCount", UnityLights.Length); 161 | int i = (int)Mathf.Floor(CurFrame) % (ValidVoxelSitesBuffer.Length); 162 | bool HasChanged = false; 163 | for(int i2 = 0; i2 < UnityLights.Length; i2++) { 164 | Light ThisLight = UnityLights[i2]; 165 | Color col = ThisLight.color; 166 | if(ThisLight.transform.hasChanged) { 167 | HasChanged = true; 168 | ThisLight.transform.hasChanged = false; 169 | UnityLightData[i2].Position = ThisLight.transform.position; 170 | UnityLightData[i2].Direction = ThisLight.transform.forward; 171 | } 172 | int Type = (ThisLight.type == LightType.Point) ? 0 : (ThisLight.type == LightType.Directional) ? 1 : (ThisLight.type == LightType.Spot) ? 2 : 3; 173 | if(UnityLightData[i2].Type != Type) { 174 | HasChanged = true; 175 | UnityLightData[i2].Type = Type; 176 | } 177 | if(UnityLightData[i2].Type == 1) VolumeShader.SetVector("SunDir", UnityLightData[i2].Direction); 178 | Vector3 Col = new Vector3(col[0], col[1], col[2]) * ThisLight.intensity; 179 | if(!UnityLightData[i2].Col.Equals(Col)) { 180 | HasChanged = true; 181 | UnityLightData[i2].Col = Col; 182 | } 183 | } 184 | UnityLightBuffer.SetData(UnityLightData); 185 | 186 | if(Sizes.Length > 1 || CurFrame < 2) { 187 | VolumeShader.SetVector("Size", Sizes[(int)Mathf.Floor(CurFrame) % (ValidVoxelSitesBuffer.Length)]); 188 | VolumeShader.SetBuffer(1, "NonZeroVoxels", ValidVoxelSitesBuffer[i]); 189 | VolumeShader.SetTexture(1, "DDATextureWrite", VolumeTex); 190 | VolumeShader.SetTexture(3, "DDATextureWrite", VolumeTex); 191 | VolumeShader.Dispatch(3, Mathf.CeilToInt(Sizes[i].x / 8.0f), Mathf.CeilToInt(Sizes[i].y / 8.0f), Mathf.CeilToInt(Sizes[i].z / 8.0f)); 192 | 193 | VolumeShader.Dispatch(1, Mathf.CeilToInt(ValidVoxelSitesBuffer[i].count / 1023.0f), 1, 1); 194 | Graphics.CopyTexture(VolumeTex, VolumeTex2); 195 | } 196 | 197 | 198 | VolumeShader.SetTexture(0, "DDATexture", VolumeTex2); 199 | VolumeShader.SetTexture(2, "DDATexture", VolumeTex2); 200 | VolumeShader.SetBuffer(2, "NonZeroVoxels", ValidVoxelSitesBuffer[i]); 201 | 202 | VolumeShader.SetInt("ShadowDistanceOffset", ShadowDistanceOffset); 203 | 204 | if(CurFrame < 2 || HasChanged || Sizes.Length > 1) {VolumeShader.Dispatch(2, Mathf.CeilToInt(ValidVoxelSitesBuffer[i].count / 1023.0f), 1, 1);} 205 | 206 | 207 | VolumeShader.SetMatrix("_CameraInverseProjection", Camera.main.projectionMatrix.inverse); 208 | VolumeShader.SetMatrix("CameraToWorld", Camera.main.cameraToWorldMatrix); 209 | VolumeShader.SetTexture(0, "Result", MainTex); 210 | VolumeShader.Dispatch(0, Mathf.CeilToInt(Screen.width / 8.0f), Mathf.CeilToInt(Screen.height / 8.0f), 1); 211 | Graphics.Blit(MainTex, destination); 212 | CurFrame += 0.3f; 213 | } 214 | 215 | 216 | } 217 | -------------------------------------------------------------------------------- /SimpleVDBLoader/FlyCamera.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityPathtracer { 5 | public class FlyCamera : MonoBehaviour { 6 | 7 | /* 8 | Writen by Windexglow 11-13-10. Use it, edit it, steal it I don't care. 9 | Converted to C# 27-02-13 - no credit wanted. 10 | Simple flycam I made, since I couldn't find any others made public. 11 | Made simple to use (drag and drop, done) for regular keyboard layout 12 | wasd : basic movement 13 | shift : Makes camera accelerate 14 | space : Moves camera on X and Z axis only. So camera doesn't gain any height*/ 15 | 16 | //I made a small change so that I can turn off movement by pressing t 17 | float mainSpeed = 1.0f; //regular speed 18 | float shiftAdd = 25.0f; //multiplied by how long shift is held. Basically running 19 | float maxShift = 1000.0f; //Maximum speed when holdin gshift 20 | float camSens = 0.25f; //How sensitive it with mouse 21 | private Vector3 lastMouse = new Vector3(255, 255, 255); //kind of in the middle of the screen, rather than at the top (play) 22 | private float totalRun= 1.0f; 23 | private bool StopMovement = true; 24 | private bool IsPressingT = false; 25 | void Update () { 26 | bool PressedT = Input.GetKey(KeyCode.T); 27 | if(PressedT && !IsPressingT) { 28 | if(StopMovement) {StopMovement = false;} else {StopMovement = true;} 29 | } 30 | if(PressedT) { 31 | IsPressingT = true; 32 | } else {IsPressingT = false;} 33 | lastMouse = Input.mousePosition - lastMouse ; 34 | lastMouse = new Vector3(-lastMouse.y * camSens, lastMouse.x * camSens, 0 ); 35 | lastMouse = new Vector3(transform.eulerAngles.x + lastMouse.x , transform.eulerAngles.y + lastMouse.y, 0); 36 | if(!StopMovement) { 37 | transform.eulerAngles = lastMouse; 38 | //Mouse camera angle done. 39 | 40 | //Keyboard commands 41 | Vector3 p = GetBaseInput(); 42 | if (Input.GetKey (KeyCode.LeftShift)){ 43 | totalRun += Time.deltaTime; 44 | p = p * totalRun * shiftAdd; 45 | p.x = Mathf.Clamp(p.x, -maxShift, maxShift); 46 | p.y = Mathf.Clamp(p.y, -maxShift, maxShift); 47 | p.z = Mathf.Clamp(p.z, -maxShift, maxShift); 48 | } 49 | else{ 50 | totalRun = Mathf.Clamp(totalRun * 0.5f, 1f, 1000f); 51 | p = p * mainSpeed; 52 | } 53 | 54 | p = p * Time.deltaTime; 55 | Vector3 newPosition = transform.position; 56 | if (Input.GetKey(KeyCode.Space)){ //If player wants to move on X and Z axis only 57 | transform.Translate(p); 58 | newPosition.x = transform.position.x; 59 | newPosition.z = transform.position.z; 60 | transform.position = newPosition; 61 | } 62 | else{ 63 | transform.Translate(p); 64 | } 65 | } 66 | lastMouse = Input.mousePosition; 67 | 68 | } 69 | 70 | private Vector3 GetBaseInput() { //returns the basic values, if it's 0 than it's not active. 71 | Vector3 p_Velocity = new Vector3(); 72 | if (Input.GetKey (KeyCode.W)){ 73 | p_Velocity += new Vector3(0, 0 , 1); 74 | } 75 | if (Input.GetKey (KeyCode.S)){ 76 | p_Velocity += new Vector3(0, 0, -1); 77 | } 78 | if (Input.GetKey (KeyCode.A)){ 79 | p_Velocity += new Vector3(-1, 0, 0); 80 | } 81 | if (Input.GetKey (KeyCode.D)){ 82 | p_Velocity += new Vector3(1, 0, 0); 83 | } 84 | return p_Velocity; 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /SimpleVDBLoader/OpenVDBReader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.IO; 5 | using UnityEditor; 6 | 7 | public class OpenVDBReader 8 | { 9 | public Object FileIn; 10 | public int InstanceNumber; 11 | public OpenVDBReader() {} 12 | List Densitys; 13 | string ParsedString; 14 | public Vector3 Size; 15 | public Vector3 MinSize; 16 | public List Centers; 17 | 18 | public struct Grid { 19 | public Node5 RootNode; 20 | public string Name; 21 | public Vector3 Center; 22 | public Matrix4x4 VDBTransform; 23 | public Vector3 Size; 24 | public List Centers; 25 | 26 | } 27 | 28 | private Vector3 GetPosition(ulong Index, uint SizeIndex) 29 | { 30 | Vector3 location = new Vector3(); 31 | location.x = (Index % SizeIndex); 32 | location.y = (Index / SizeIndex) % SizeIndex; 33 | location.z = (Index / (SizeIndex * SizeIndex)); 34 | return location; 35 | } 36 | 37 | void ReadString(ref BinaryReader reader) { 38 | uint NameLength = System.BitConverter.ToUInt32(reader.ReadBytes(4)); 39 | byte[] Name = reader.ReadBytes((int)NameLength); 40 | ParsedString = System.Text.Encoding.ASCII.GetString(Name); 41 | } 42 | 43 | void ReadMetadata(ref BinaryReader reader, ref Grid grid) { 44 | uint MetaDataCount = System.BitConverter.ToUInt32(reader.ReadBytes(4)); 45 | for(uint i = 0; i < MetaDataCount; i++) { 46 | ReadString(ref reader); 47 | string Selection = ParsedString; 48 | ReadString(ref reader); 49 | if(ParsedString.Equals("string")) { 50 | ReadString(ref reader); 51 | } else if(ParsedString.Equals("bool")) { 52 | uint ByteCount = System.BitConverter.ToUInt32(reader.ReadBytes(4)); 53 | reader.ReadBytes(1); 54 | } else if(ParsedString.Equals("vec3i")) { 55 | reader.ReadBytes(4); 56 | if(Selection.Equals("file_bbox_max")) { 57 | MinSize = new Vector3((float)System.BitConverter.ToUInt32(reader.ReadBytes(4)), (float)System.BitConverter.ToUInt32(reader.ReadBytes(4)), (float)System.BitConverter.ToUInt32(reader.ReadBytes(4))); 58 | } else { 59 | Size = new Vector3((float)System.BitConverter.ToUInt32(reader.ReadBytes(4)), (float)System.BitConverter.ToUInt32(reader.ReadBytes(4)), (float)System.BitConverter.ToUInt32(reader.ReadBytes(4))); 60 | grid.Size = Size; 61 | } 62 | } else { 63 | reader.ReadBytes((int)System.BitConverter.ToUInt32(reader.ReadBytes(4))); 64 | } 65 | } 66 | } 67 | 68 | void ParseTransform(ref BinaryReader reader, ref Matrix4x4 VDBTransform) { 69 | for(int i = 0; i < 4; i++) { 70 | for(int j = 0; j < 4; j++) { 71 | VDBTransform[j,i] = (float)System.BitConverter.ToDouble(reader.ReadBytes(8)); 72 | 73 | } 74 | } 75 | } 76 | 77 | [System.Serializable] 78 | public struct Node5 { 79 | public Dictionary Children; 80 | public ulong[] Mask; 81 | public ulong[] ValueMask; 82 | public uint[] Values; 83 | } 84 | [System.Serializable] 85 | public struct Node4 { 86 | public int Offset; 87 | public Vector3 Center; 88 | public Dictionary Children; 89 | public ulong[] Mask; 90 | public ulong[] ValueMask; 91 | public uint[] Values; 92 | } 93 | [System.Serializable] 94 | public struct Node3 { 95 | public int Offset; 96 | public Vector3 Center; 97 | public Dictionary Children; 98 | public ulong[] Mask; 99 | } 100 | [System.Serializable] 101 | public struct Voxel { 102 | public ushort Density; 103 | } 104 | 105 | int BitCount(ulong A) { 106 | return (A == 0) ? 32 : (int) (31 - Mathf.Log((long)A & -(long)A, 2)); 107 | } 108 | 109 | public Grid[] Grids; 110 | 111 | void ReadGrid(ref BinaryReader reader, ref Grid grid) { 112 | ReadString(ref reader); 113 | grid.Name = ParsedString; 114 | 115 | ReadString(ref reader); 116 | reader.ReadBytes(28); 117 | uint Compresed = System.BitConverter.ToUInt32(reader.ReadBytes(4));//compression 118 | if(Compresed != 0) { 119 | Debug.Log("File needs to not be compressed"); 120 | return; 121 | } 122 | ReadMetadata(ref reader, ref grid); 123 | 124 | ReadString(ref reader); 125 | 126 | ParseTransform(ref reader, ref grid.VDBTransform); 127 | 128 | reader.ReadBytes(32); 129 | grid.Center = new Vector3((float)System.BitConverter.ToUInt32(reader.ReadBytes(4)), (float)System.BitConverter.ToUInt32(reader.ReadBytes(4)), (float)System.BitConverter.ToUInt32(reader.ReadBytes(4))); 130 | grid.RootNode = new Node5(); 131 | grid.RootNode.Mask = new ulong[512]; 132 | grid.RootNode.ValueMask = new ulong[512]; 133 | grid.RootNode.Values = new uint[32768]; 134 | grid.RootNode.Children = new Dictionary(); 135 | for(int i = 0; i < 512; i++) { 136 | grid.RootNode.Mask[i] = System.BitConverter.ToUInt64(reader.ReadBytes(8)); 137 | } 138 | for(int i = 0; i < 512; i++) { 139 | grid.RootNode.ValueMask[i] = System.BitConverter.ToUInt64(reader.ReadBytes(8)); 140 | } 141 | reader.ReadBytes(1); 142 | for(int i = 0; i < 32768; i++) { 143 | grid.RootNode.Values[i] = (uint)System.BitConverter.ToUInt16(reader.ReadBytes(2)); 144 | } 145 | uint IndexA = 0; 146 | 147 | Voxel CurNode3 = new Voxel(); 148 | Node4 CurNode; 149 | Node3 CurNode2; 150 | foreach(ulong A in grid.RootNode.Mask) { 151 | for(ulong A2 = A; A2 != 0; A2 &= A2 - 1) { 152 | ulong bit_index = (ulong)((ulong)((ulong)IndexA * (ulong)64) + (ulong)(31 - BitCount(A2))); 153 | CurNode = new Node4(); 154 | CurNode.Children = new Dictionary(); 155 | CurNode.Mask = new ulong[64]; 156 | CurNode.ValueMask = new ulong[64]; 157 | CurNode.Values = new uint[4096]; 158 | for(int i = 0; i < 64; i++) { 159 | CurNode.Mask[i] = System.BitConverter.ToUInt64(reader.ReadBytes(8)); 160 | } 161 | for(int i = 0; i < 64; i++) { 162 | CurNode.ValueMask[i] = System.BitConverter.ToUInt64(reader.ReadBytes(8)); 163 | } 164 | reader.ReadBytes(1); 165 | for(int i = 0; i < 4096; i++) { 166 | CurNode.Values[i] = (uint)System.BitConverter.ToUInt16(reader.ReadBytes(2)); 167 | } 168 | uint Index = 0; 169 | foreach(ulong B in CurNode.Mask) { 170 | for(ulong B2 = B; B2 != 0; B2 &= B2 - 1) { 171 | CurNode2 = new Node3(); 172 | CurNode2.Mask = new ulong[8]; 173 | CurNode2.Children = new Dictionary(); 174 | ulong bit_index2 = (ulong)((ulong)((ulong)Index * (ulong)64) + (ulong)(31 - BitCount(B2))); 175 | for(int i = 0; i < 8; i++) { 176 | CurNode2.Mask[i] = System.BitConverter.ToUInt64(reader.ReadBytes(8)); 177 | } 178 | CurNode.Children.Add(bit_index2, CurNode2); 179 | } 180 | Index++; 181 | } 182 | 183 | grid.RootNode.Children.Add(bit_index, CurNode); 184 | } 185 | IndexA++; 186 | } 187 | 188 | byte[] Buffer = new byte[1024]; 189 | IndexA = 0; 190 | grid.Centers = new List(); 191 | foreach(ulong A in grid.RootNode.Mask) { 192 | for(ulong A2 = A; A2 != 0; A2 &= A2 - 1) { 193 | ulong bit_index = (ulong)((ulong)((ulong)IndexA * (ulong)64) + (ulong)(31 - BitCount(A2))); 194 | if(grid.RootNode.Children.TryGetValue(bit_index, out CurNode)) { 195 | Vector3 RootNodePos = GetPosition(bit_index, 32) * 128.0f; 196 | uint Index = 0; 197 | foreach(ulong B in CurNode.Mask) { 198 | for(ulong B2 = B; B2 != 0; B2 &= B2 - 1) { 199 | ulong bit_index2 = (ulong)((ulong)((ulong)Index * (ulong)64) + (ulong)(31 - BitCount(B2))); 200 | Vector3 CurNodePos = GetPosition(bit_index2, 16) * 8; 201 | if(CurNode.Children.TryGetValue(bit_index2, out CurNode2)) { 202 | if((CurNodePos).z > Size.z) { 203 | reader.ReadBytes(1089); 204 | continue; 205 | } 206 | reader.ReadBytes(65); 207 | Buffer = reader.ReadBytes(1024); 208 | for(ulong i = 0; i < 512; i++) { 209 | CurNode3.Density = System.BitConverter.ToUInt16(Buffer, (int)i * 2); 210 | if(CurNode3.Density != 0) grid.Centers.Add(RootNodePos + CurNodePos + GetPosition((ulong)i, 8)); 211 | CurNode2.Children.Add(i, CurNode3); 212 | } 213 | } 214 | } 215 | Index++; 216 | } 217 | } 218 | 219 | } 220 | IndexA++; 221 | } 222 | } 223 | 224 | public async void ParseVDB(string CachedString, int InstanceNumber) 225 | { 226 | this.InstanceNumber = InstanceNumber; 227 | Centers = new List(); 228 | var reader = new BinaryReader(new MemoryStream(File.ReadAllBytes(CachedString))); 229 | reader.ReadBytes(57); 230 | uint MetaDataCount = System.BitConverter.ToUInt32(reader.ReadBytes(4)); 231 | byte[] MetaData = reader.ReadBytes((int)MetaDataCount); 232 | uint NumGrids = System.BitConverter.ToUInt32(reader.ReadBytes(4)); 233 | Grids = new Grid[NumGrids]; 234 | for(int i = 0; i < NumGrids; i++) { 235 | ReadGrid(ref reader, ref Grids[i]); 236 | } 237 | reader.Close(); 238 | } 239 | 240 | 241 | 242 | 243 | } 244 | -------------------------------------------------------------------------------- /SimpleVDBLoader/Resources/RenderVolume.compute: -------------------------------------------------------------------------------- 1 | // Each #kernel tells which function to compile; you can have many kernels 2 | #pragma use_dxc 3 | #include "UnityCG.cginc" 4 | #define PI 3.14159 5 | #pragma kernel CSMain 6 | 7 | 8 | 9 | 10 | RWStructuredBuffer ShadowBuffer; 11 | RWTexture2D Result; 12 | RWTexture3D DDATextureWrite; 13 | Texture3D DDATexture; 14 | float4x4 _CameraInverseProjection; 15 | float4x4 CameraToWorld; 16 | uint ScreenWidth; 17 | uint ScreenHeight; 18 | float3 Size; 19 | int LightCount; 20 | int CurFrame; 21 | 22 | struct UnityLight { 23 | float3 Pos; 24 | float3 Dir; 25 | int Type; 26 | float3 Col; 27 | }; 28 | StructuredBuffer UnityLights; 29 | 30 | 31 | struct Ray { 32 | float3 origin; 33 | float3 direction; 34 | }; 35 | Ray CreateRay(float3 A, float3 B) { 36 | Ray ray; 37 | ray.origin = A; 38 | ray.direction = B; 39 | return ray; 40 | } 41 | Ray CreateCameraRay(float2 uv) { 42 | // Transform the camera origin to world space 43 | float3 origin = mul(CameraToWorld, float4(0.0f, 0.0f, 0.0f, 1.0f)).xyz; 44 | 45 | // Invert the perspective projection of the view-space position 46 | float3 direction = mul(_CameraInverseProjection, float4(uv, 0.0f, 1.0f)).xyz; 47 | // Transform the direction from camera to world space and normalize 48 | direction = mul(CameraToWorld, float4(direction, 0.0f)).xyz; 49 | direction = normalize(direction); 50 | 51 | 52 | return CreateRay(origin, direction); 53 | } 54 | 55 | uint hash_with(uint seed, uint hash) { 56 | // Wang hash 57 | seed = (seed ^ 61) ^ hash; 58 | seed += seed << 3; 59 | seed ^= seed >> 4; 60 | seed *= 0x27d4eb2d; 61 | return seed; 62 | } 63 | uint pcg_hash(uint seed) { 64 | uint state = seed * 747796405u + 2891336453u; 65 | uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; 66 | return (word >> 22u) ^ word; 67 | } 68 | 69 | float2 random(uint samdim, uint pixel_index) { 70 | uint hash = pcg_hash((pixel_index * (uint)204 + samdim)); 71 | 72 | const static float one_over_max_unsigned = asfloat(0x2f7fffff); 73 | 74 | 75 | float x = hash_with(CurFrame, hash) * one_over_max_unsigned; 76 | float y = hash_with(CurFrame + 0xdeadbeef, hash) * one_over_max_unsigned; 77 | 78 | return float2(x, y); 79 | } 80 | 81 | uint packRGBE(float3 v) 82 | { 83 | float3 va = max(0, v); 84 | float max_abs = max(va.r, max(va.g, va.b)); 85 | if (max_abs == 0) 86 | return 0; 87 | 88 | float exponent = floor(log2(max_abs)); 89 | 90 | uint result; 91 | result = uint(clamp(exponent + 20, 0, 31)) << 27; 92 | 93 | float scale = pow(2, -exponent) * 256.0; 94 | uint3 vu = min(511, round(va * scale)); 95 | result |= vu.r; 96 | result |= vu.g << 9; 97 | result |= vu.b << 18; 98 | 99 | return result; 100 | } 101 | 102 | float3 unpackRGBE(uint x) 103 | { 104 | int exponent = int(x >> 27) - 20; 105 | float scale = pow(2, exponent) / 256.0; 106 | 107 | float3 v; 108 | v.r = float(x & 0x1ff) * scale; 109 | v.g = float((x >> 9) & 0x1ff) * scale; 110 | v.b = float((x >> 18) & 0x1ff) * scale; 111 | 112 | return v; 113 | } 114 | 115 | 116 | float HenyeyGreenstein(float g, float mu) { 117 | float gg = g * g; 118 | return (1.0 / (4.0 * PI)) * ((1.0 - gg) / pow(1.0 + gg - 2.0 * g * mu, 1.5)); 119 | } 120 | 121 | float DualHenyeyGreenstein(float g, float costh) { 122 | return lerp(HenyeyGreenstein(-g, costh), HenyeyGreenstein(g, costh), 0.7f); 123 | } 124 | 125 | float PhaseFunction(float g, float costh) { 126 | return DualHenyeyGreenstein(g, costh); 127 | } 128 | 129 | float3 MultipleOctaveScattering(float density, float mu) { 130 | float attenuation = 0.2; 131 | float contribution = 0.2; 132 | float phaseAttenuation = 0.5; 133 | 134 | float a = 1.0; 135 | float b = 1.0; 136 | float c = 1.0; 137 | float g = 0.85; 138 | const float scatteringOctaves = 4.0; 139 | 140 | float3 luminance = 0.0; 141 | 142 | for (float i = 0.0; i < scatteringOctaves; i++) { 143 | float phaseFunction = PhaseFunction(0.3 * c, mu); 144 | float3 beers = exp(-density * float3(0.8, 0.8, 1) * a); 145 | 146 | luminance += b * phaseFunction * beers; 147 | 148 | a *= attenuation; 149 | b *= contribution; 150 | c *= (1.0 - phaseAttenuation); 151 | } 152 | return luminance; 153 | } 154 | 155 | float inverseLerp(float minValue, float maxValue, float v) { 156 | return (v - minValue) / (maxValue - minValue); 157 | } 158 | 159 | float remap(float v, float inMin, float inMax, float outMin, float outMax) { 160 | float t = inverseLerp(inMin, inMax, v); 161 | return lerp(outMin, outMax, t); 162 | } 163 | 164 | int ShadowDistanceOffset; 165 | 166 | 167 | inline bool rayBoxIntersection(const float3 ray_orig, const float3 inv_dir, const float3 Min, const float3 Max, float tMax, inout float t0, inout float t1) { 168 | const float3 tmp_min = (Min - ray_orig) * inv_dir; 169 | const float3 tmp_max = (Max - ray_orig) * inv_dir; 170 | const float3 tmin = min(tmp_min, tmp_max); 171 | const float3 tmax = max(tmp_min, tmp_max); 172 | t0 = max(tmin.x, max(tmin.y, max(tmin.z, 0))); // Usually ray_tmin = 0 173 | t1 = min(tmax.x, min(tmax.y, min(tmax.z, tMax))); 174 | return (t0 <= t1); 175 | } 176 | 177 | inline float GetIndex(const int3 xyz) { 178 | return DDATexture[xyz]; 179 | } 180 | 181 | float3 SunDir; 182 | 183 | inline float MarchShadowDDA(int3 mapPos, const float3 rayDir, float MaxDist) { 184 | float Density = 0; 185 | float t0, t1; 186 | if(rayBoxIntersection(mapPos, rcp(rayDir), 0, Size, MaxDist, t0, t1)) { 187 | const float3 deltaDist = abs(rcp(rayDir)) * ShadowDistanceOffset; 188 | const int3 rayStep = sign(rayDir) * ShadowDistanceOffset; 189 | float3 sideDist = ((rayStep * 0.5) + 0.5) * deltaDist; 190 | 191 | float minDist = min(min(sideDist.x, sideDist.y), sideDist.z); 192 | bool3 mask; 193 | while (minDist < t1) { 194 | mask = (sideDist.xyz <= minDist); 195 | sideDist += mask * deltaDist; 196 | mapPos += mask * rayStep; 197 | Density += GetIndex(mapPos) * ShadowDistanceOffset; 198 | minDist = min(min(sideDist.x, sideDist.y), sideDist.z); 199 | if (Density >= 100) 200 | break; 201 | } 202 | } 203 | return Density; 204 | } 205 | 206 | 207 | inline float3 MarchDDA(Ray ray, inout float3 Luminance) { 208 | float t0, t1; 209 | float3 Transmission = 1; 210 | Luminance = 0; 211 | float mu = dot(-ray.direction, SunDir); 212 | if(rayBoxIntersection(ray.origin, rcp(ray.direction), 0, Size, 99999, t0, t1)) { 213 | ray.origin += ray.direction * t0; 214 | t1 = t1 - t0; 215 | int3 mapPos = int3(floor(ray.origin)); 216 | 217 | const float3 deltaDist = abs(rcp(ray.direction)); 218 | 219 | const int3 rayStep = int3(sign(ray.direction)); 220 | 221 | float3 sideDist = (rayStep * (mapPos - ray.origin) + (rayStep * 0.5) + 0.5) * deltaDist; 222 | 223 | bool3 mask; 224 | float minDist = min(min(sideDist.x, sideDist.y), sideDist.z); 225 | 226 | while(minDist < t1) { 227 | mask = (sideDist.xyz <= min(sideDist.yzx, sideDist.zxy)); 228 | sideDist += mask * deltaDist; 229 | minDist = min(min(sideDist.x, sideDist.y), sideDist.z); 230 | mapPos += mask * rayStep; 231 | float Density = GetIndex(mapPos); 232 | if(Density > 0.01f) { 233 | float LightDensity = asfloat(ShadowBuffer[mapPos.x + mapPos.y * Size.x + mapPos.z * Size.x * Size.y].x); 234 | float3 beerslaw = MultipleOctaveScattering(LightDensity, mu); 235 | float3 powder = 1.0f - exp(-LightDensity * 2 * float3(0.8, 0.8, 1)); 236 | // float3 transmittance = 0; 237 | // float3 Radiance = GetSkyRadiance(mapPos, -SunDir, 0, -SunDir, transmittance); 238 | float3 lum = unpackRGBE(ShadowBuffer[mapPos.x + mapPos.y * Size.x + mapPos.z * Size.x * Size.y].y) * beerslaw * lerp(2 * powder, 1, remap(mu, -1, 1, 0, 1));// * transmittance + Radiance; 239 | 240 | float3 transmittance2 = exp(-Density * float3(0.8, 0.8, 1)); 241 | float3 integscatter = (lum - lum * transmittance2); 242 | 243 | Luminance += integscatter * Transmission; 244 | Transmission *= transmittance2; 245 | if(Transmission.x < 0.01f) break; 246 | } 247 | } 248 | 249 | } 250 | return Transmission; 251 | } 252 | 253 | 254 | static const int2 PerFrameOffset[4] = { 255 | {int2(0,0), int2(1,0), int2(0,1), int2(1,1) } 256 | }; 257 | 258 | [numthreads(8,8,1)] 259 | void CSMain (uint3 id : SV_DispatchThreadID) 260 | { 261 | int2 ProperID = id.xy;/// * 2 + PerFrameOffset[CurFrame % 4]; 262 | float2 uv = float2((ProperID) / float2(ScreenWidth, ScreenHeight) * 2.0f - 1.0f); 263 | Ray ray = CreateCameraRay(uv); 264 | float3 Luminance; 265 | float3 Sun = 0;//(saturate(max(min(exp(-acos(max(dot(-SunDir, -ray.direction), 0.0f))* 60.0f),12.0f),0) * transmittance)); 266 | if (dot(ray.direction, -SunDir) > cos(0.0235f / 2.0f)) { 267 | Sun = saturate((1.5f / (PI * (0.0235f / 2.0f) * (0.0235f / 2.0f)))); 268 | } 269 | float3 Transmission = MarchDDA(ray, Luminance); 270 | Result[ProperID] = float4(0.1f * Transmission + Luminance + Sun * Transmission,1); 271 | } 272 | 273 | 274 | #pragma kernel CopyToTexture 275 | StructuredBuffer NonZeroVoxels; 276 | 277 | [numthreads(1023,1,1)] 278 | void CopyToTexture (uint3 id : SV_DispatchThreadID) 279 | { 280 | DDATextureWrite[NonZeroVoxels[id.x].xyz] = NonZeroVoxels[id.x].w; 281 | } 282 | 283 | #pragma kernel ShadeComputation 284 | [numthreads(1023,1,1)] 285 | void ShadeComputation (uint3 id : SV_DispatchThreadID) 286 | { 287 | int LightSelection = floor(random(23, id.x).x * (LightCount)); 288 | float3 Dir; 289 | float MaxDist; 290 | switch(UnityLights[LightSelection].Type) { 291 | case 0: 292 | Dir = UnityLights[LightSelection].Pos - NonZeroVoxels[id.x].xyz; 293 | MaxDist = length(Dir); 294 | Dir /= MaxDist; 295 | break; 296 | case 1: 297 | Dir = -UnityLights[LightSelection].Dir; 298 | MaxDist = 99999.0f; 299 | break; 300 | 301 | } 302 | ShadowBuffer[NonZeroVoxels[id.x].x + NonZeroVoxels[id.x].y * Size.x + NonZeroVoxels[id.x].z * Size.y * Size.x] = uint2(asuint(MarchShadowDDA(NonZeroVoxels[id.x].xyz, Dir, MaxDist)), packRGBE(UnityLights[LightSelection].Col)); 303 | 304 | } 305 | 306 | #pragma kernel TextureZero 307 | 308 | [numthreads(8,8,8)] 309 | void TextureZero (uint3 id : SV_DispatchThreadID) 310 | { 311 | DDATextureWrite[id.xyz] = 0; 312 | } -------------------------------------------------------------------------------- /SimpleVDBLoader/Vol.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 12 47 | m_GIWorkflowMode: 1 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 1 55 | m_EnableRealtimeLightmaps: 0 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 1 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 1 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 512 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 256 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 1 83 | m_PVRDenoiserTypeDirect: 1 84 | m_PVRDenoiserTypeIndirect: 1 85 | m_PVRDenoiserTypeAO: 1 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 1 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ExportTrainingData: 0 98 | m_TrainingDataDestination: TrainingData 99 | m_LightProbeSampleCountMultiplier: 4 100 | m_LightingDataAsset: {fileID: 0} 101 | m_LightingSettings: {fileID: 0} 102 | --- !u!196 &4 103 | NavMeshSettings: 104 | serializedVersion: 2 105 | m_ObjectHideFlags: 0 106 | m_BuildSettings: 107 | serializedVersion: 2 108 | agentTypeID: 0 109 | agentRadius: 0.5 110 | agentHeight: 2 111 | agentSlope: 45 112 | agentClimb: 0.4 113 | ledgeDropHeight: 0 114 | maxJumpAcrossDistance: 0 115 | minRegionArea: 2 116 | manualCellSize: 0 117 | cellSize: 0.16666667 118 | manualTileSize: 0 119 | tileSize: 256 120 | accuratePlacement: 0 121 | maxJobWorkers: 0 122 | preserveTilesOutsideBounds: 0 123 | debug: 124 | m_Flags: 0 125 | m_NavMeshData: {fileID: 0} 126 | --- !u!1 &132256877 127 | GameObject: 128 | m_ObjectHideFlags: 0 129 | m_CorrespondingSourceObject: {fileID: 0} 130 | m_PrefabInstance: {fileID: 0} 131 | m_PrefabAsset: {fileID: 0} 132 | serializedVersion: 6 133 | m_Component: 134 | - component: {fileID: 132256880} 135 | - component: {fileID: 132256879} 136 | - component: {fileID: 132256878} 137 | - component: {fileID: 132256882} 138 | - component: {fileID: 132256883} 139 | m_Layer: 0 140 | m_Name: Main Camera 141 | m_TagString: MainCamera 142 | m_Icon: {fileID: 0} 143 | m_NavMeshLayer: 0 144 | m_StaticEditorFlags: 0 145 | m_IsActive: 1 146 | --- !u!81 &132256878 147 | AudioListener: 148 | m_ObjectHideFlags: 0 149 | m_CorrespondingSourceObject: {fileID: 0} 150 | m_PrefabInstance: {fileID: 0} 151 | m_PrefabAsset: {fileID: 0} 152 | m_GameObject: {fileID: 132256877} 153 | m_Enabled: 1 154 | --- !u!20 &132256879 155 | Camera: 156 | m_ObjectHideFlags: 0 157 | m_CorrespondingSourceObject: {fileID: 0} 158 | m_PrefabInstance: {fileID: 0} 159 | m_PrefabAsset: {fileID: 0} 160 | m_GameObject: {fileID: 132256877} 161 | m_Enabled: 1 162 | serializedVersion: 2 163 | m_ClearFlags: 1 164 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} 165 | m_projectionMatrixMode: 1 166 | m_GateFitMode: 2 167 | m_FOVAxisMode: 0 168 | m_SensorSize: {x: 36, y: 24} 169 | m_LensShift: {x: 0, y: 0} 170 | m_FocalLength: 50 171 | m_NormalizedViewPortRect: 172 | serializedVersion: 2 173 | x: 0 174 | y: 0 175 | width: 1 176 | height: 1 177 | near clip plane: 0.3 178 | far clip plane: 1000 179 | field of view: 60 180 | orthographic: 0 181 | orthographic size: 5 182 | m_Depth: -1 183 | m_CullingMask: 184 | serializedVersion: 2 185 | m_Bits: 4294967295 186 | m_RenderingPath: -1 187 | m_TargetTexture: {fileID: 0} 188 | m_TargetDisplay: 0 189 | m_TargetEye: 3 190 | m_HDR: 1 191 | m_AllowMSAA: 1 192 | m_AllowDynamicResolution: 0 193 | m_ForceIntoRT: 0 194 | m_OcclusionCulling: 1 195 | m_StereoConvergence: 10 196 | m_StereoSeparation: 0.022 197 | --- !u!4 &132256880 198 | Transform: 199 | m_ObjectHideFlags: 0 200 | m_CorrespondingSourceObject: {fileID: 0} 201 | m_PrefabInstance: {fileID: 0} 202 | m_PrefabAsset: {fileID: 0} 203 | m_GameObject: {fileID: 132256877} 204 | m_LocalRotation: {x: -0.38129437, y: 0.46806362, z: -0.23420563, w: -0.7620228} 205 | m_LocalPosition: {x: 6.1373563, y: 0.999999, z: 126.966774} 206 | m_LocalScale: {x: 1, y: 1, z: 1} 207 | m_ConstrainProportionsScale: 0 208 | m_Children: [] 209 | m_Father: {fileID: 0} 210 | m_RootOrder: 0 211 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 212 | --- !u!114 &132256882 213 | MonoBehaviour: 214 | m_ObjectHideFlags: 0 215 | m_CorrespondingSourceObject: {fileID: 0} 216 | m_PrefabInstance: {fileID: 0} 217 | m_PrefabAsset: {fileID: 0} 218 | m_GameObject: {fileID: 132256877} 219 | m_Enabled: 1 220 | m_EditorHideFlags: 0 221 | m_Script: {fileID: 11500000, guid: 25708ab1647d3af43927c5c250594658, type: 3} 222 | m_Name: 223 | m_EditorClassIdentifier: 224 | --- !u!114 &132256883 225 | MonoBehaviour: 226 | m_ObjectHideFlags: 0 227 | m_CorrespondingSourceObject: {fileID: 0} 228 | m_PrefabInstance: {fileID: 0} 229 | m_PrefabAsset: {fileID: 0} 230 | m_GameObject: {fileID: 132256877} 231 | m_Enabled: 1 232 | m_EditorHideFlags: 0 233 | m_Script: {fileID: 11500000, guid: e3a0651dd9c8a1d478db944ccc39dddb, type: 3} 234 | m_Name: 235 | m_EditorClassIdentifier: 236 | FileIn: {fileID: 102900000, guid: 028ebc018dc17ed46a87c76ac71e40b1, type: 3} 237 | ShadowDistanceOffset: 1 238 | --- !u!1 &727784978 239 | GameObject: 240 | m_ObjectHideFlags: 0 241 | m_CorrespondingSourceObject: {fileID: 0} 242 | m_PrefabInstance: {fileID: 0} 243 | m_PrefabAsset: {fileID: 0} 244 | serializedVersion: 6 245 | m_Component: 246 | - component: {fileID: 727784979} 247 | m_Layer: 0 248 | m_Name: 55ms 249 | m_TagString: Untagged 250 | m_Icon: {fileID: 0} 251 | m_NavMeshLayer: 0 252 | m_StaticEditorFlags: 0 253 | m_IsActive: 1 254 | --- !u!4 &727784979 255 | Transform: 256 | m_ObjectHideFlags: 0 257 | m_CorrespondingSourceObject: {fileID: 0} 258 | m_PrefabInstance: {fileID: 0} 259 | m_PrefabAsset: {fileID: 0} 260 | m_GameObject: {fileID: 727784978} 261 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 262 | m_LocalPosition: {x: 0, y: 0, z: 0} 263 | m_LocalScale: {x: 1, y: 1, z: 1} 264 | m_ConstrainProportionsScale: 0 265 | m_Children: [] 266 | m_Father: {fileID: 0} 267 | m_RootOrder: 2 268 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 269 | --- !u!1 &747259822 270 | GameObject: 271 | m_ObjectHideFlags: 0 272 | m_CorrespondingSourceObject: {fileID: 0} 273 | m_PrefabInstance: {fileID: 0} 274 | m_PrefabAsset: {fileID: 0} 275 | serializedVersion: 6 276 | m_Component: 277 | - component: {fileID: 747259824} 278 | - component: {fileID: 747259823} 279 | m_Layer: 0 280 | m_Name: DL 281 | m_TagString: Untagged 282 | m_Icon: {fileID: 0} 283 | m_NavMeshLayer: 0 284 | m_StaticEditorFlags: 0 285 | m_IsActive: 1 286 | --- !u!108 &747259823 287 | Light: 288 | m_ObjectHideFlags: 0 289 | m_CorrespondingSourceObject: {fileID: 0} 290 | m_PrefabInstance: {fileID: 0} 291 | m_PrefabAsset: {fileID: 0} 292 | m_GameObject: {fileID: 747259822} 293 | m_Enabled: 1 294 | serializedVersion: 10 295 | m_Type: 1 296 | m_Shape: 0 297 | m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} 298 | m_Intensity: 12 299 | m_Range: 10 300 | m_SpotAngle: 30 301 | m_InnerSpotAngle: 21.80208 302 | m_CookieSize: 10 303 | m_Shadows: 304 | m_Type: 2 305 | m_Resolution: -1 306 | m_CustomResolution: -1 307 | m_Strength: 1 308 | m_Bias: 0.05 309 | m_NormalBias: 0.4 310 | m_NearPlane: 0.2 311 | m_CullingMatrixOverride: 312 | e00: 1 313 | e01: 0 314 | e02: 0 315 | e03: 0 316 | e10: 0 317 | e11: 1 318 | e12: 0 319 | e13: 0 320 | e20: 0 321 | e21: 0 322 | e22: 1 323 | e23: 0 324 | e30: 0 325 | e31: 0 326 | e32: 0 327 | e33: 1 328 | m_UseCullingMatrixOverride: 0 329 | m_Cookie: {fileID: 0} 330 | m_DrawHalo: 0 331 | m_Flare: {fileID: 0} 332 | m_RenderMode: 0 333 | m_CullingMask: 334 | serializedVersion: 2 335 | m_Bits: 4294967295 336 | m_RenderingLayerMask: 1 337 | m_Lightmapping: 4 338 | m_LightShadowCasterMode: 0 339 | m_AreaSize: {x: 1, y: 1} 340 | m_BounceIntensity: 1 341 | m_ColorTemperature: 6570 342 | m_UseColorTemperature: 0 343 | m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} 344 | m_UseBoundingSphereOverride: 0 345 | m_UseViewFrustumForShadowCasterCull: 1 346 | m_ShadowRadius: 0 347 | m_ShadowAngle: 0 348 | --- !u!4 &747259824 349 | Transform: 350 | m_ObjectHideFlags: 0 351 | m_CorrespondingSourceObject: {fileID: 0} 352 | m_PrefabInstance: {fileID: 0} 353 | m_PrefabAsset: {fileID: 0} 354 | m_GameObject: {fileID: 747259822} 355 | m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} 356 | m_LocalPosition: {x: 0, y: 3, z: 0} 357 | m_LocalScale: {x: 1, y: 1, z: 1} 358 | m_ConstrainProportionsScale: 0 359 | m_Children: [] 360 | m_Father: {fileID: 0} 361 | m_RootOrder: 1 362 | m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} 363 | -------------------------------------------------------------------------------- /SimpleVDBLoader/cloud_02_variant_0000.vdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pjbomb2/Unofficial-Basic-Embergen-VDB-Loader-for-Unity/42f4de413beee3061775f32785f70d8187e05ce6/SimpleVDBLoader/cloud_02_variant_0000.vdb -------------------------------------------------------------------------------- /VolumeImages/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pjbomb2/Unofficial-Basic-Embergen-VDB-Loader-for-Unity/42f4de413beee3061775f32785f70d8187e05ce6/VolumeImages/1.png -------------------------------------------------------------------------------- /VolumeImages/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pjbomb2/Unofficial-Basic-Embergen-VDB-Loader-for-Unity/42f4de413beee3061775f32785f70d8187e05ce6/VolumeImages/2.png -------------------------------------------------------------------------------- /VolumeLoader.unitypackage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pjbomb2/Unofficial-Basic-Embergen-VDB-Loader-for-Unity/42f4de413beee3061775f32785f70d8187e05ce6/VolumeLoader.unitypackage --------------------------------------------------------------------------------