// /// <summary> // /// Normalizes all brick data // /// </summary> // public void FinalizeLeafVoxels() { // for ( int Z=0; Z < 2; Z++ ) // for ( int Y=0; Y < 2; Y++ ) // for ( int X=0; X < 2; X++ ) { // OctreeNode child = m_children[X,Y,Z]; // if ( child != null ) { // child.FinalizeLeafVoxels(); // } // } // // // Normalize brick data // m_brick.Normalize(); // } /// <summary> /// Builds all the mip at all levels /// </summary> public void BuildAllMips() { if (m_brick.accumulationCounter > 0) { // Already built! Just normalize... m_brick.Normalize(); return; } for (int Z = 0; Z < 2; Z++) { for (int Y = 0; Y < 2; Y++) { for (int X = 0; X < 2; X++) { OctreeNode child = m_children[X, Y, Z]; if (child == null) { continue; } // Make sure the child's brick data are built child.BuildAllMips(); // Accumulate from all valid children m_brick.Accumulate(ref child.m_brick); } } } // Normalize m_brick.accumulationCounter = 8; // We always assume all children contribute equally m_brick.Normalize(); }
public OctreeBuilder(Device _device, float3 _wsCornerMin, float _volumeSize, int _subdivisionsLevelsCount) { int subdivisionsCount = 1 << _subdivisionsLevelsCount; float voxelSize = _volumeSize / subdivisionsCount; #if LOAD_OCTREE // Load the octree OctreeNode root = null; using (System.IO.FileStream S = new System.IO.FileInfo("CornellBox_" + subdivisionsCount + ".octree").OpenRead()) using (System.IO.BinaryReader R = new System.IO.BinaryReader(S)) root = new OctreeNode(R); #else ////////////////////////////////////////////////////////////////////////// // 1] Generate a list of non-empty voxels // #if !LOAD_VOXELS // Start collecting all non-empty voxels float3 dV = voxelSize * float3.One; float3 wsVoxelMin = _wsCornerMin + 0.5f * dV; // Start voxel center float voxelDistance = (float)Math.Sqrt(dV.x * dV.x + dV.y * dV.y + dV.z * dV.z); List <Voxel> voxels = new List <Voxel>(10000000); // 10 million voxels DateTime buildStartTime = DateTime.Now; float3 voxelCenter = new float3(); voxelCenter.z = wsVoxelMin.z; for (uint Z = 0; Z < subdivisionsCount; Z++, voxelCenter.z += dV.z) { voxelCenter.y = wsVoxelMin.y; for (uint Y = 0; Y < subdivisionsCount; Y++, voxelCenter.y += dV.y) { voxelCenter.x = wsVoxelMin.x; for (uint X = 0; X < subdivisionsCount; X++, voxelCenter.x += dV.x) { float2 sceneDistance = Map(voxelCenter); if (sceneDistance.x > voxelDistance) { continue; // Scene is too far away } float3 sceneNormal = Normal(voxelCenter); float3 sceneAlbedo = Albedo(voxelCenter, sceneDistance.y); voxels.Add(new Voxel() { X = X, Y = Y, Z = Z, albedo = sceneAlbedo, normal = sceneNormal }); } } } DateTime buildEndTime = DateTime.Now; System.Diagnostics.Debug.WriteLine("Octree build time = " + (buildEndTime - buildStartTime).TotalSeconds + " seconds"); // Write to disk as it takes hell of a time to generate! using (System.IO.FileStream S = new System.IO.FileInfo("CornellBox_" + subdivisionsCount + ".voxels").Create()) using (System.IO.BinaryWriter W = new System.IO.BinaryWriter(S)) { W.Write(_wsCornerMin.x); W.Write(_wsCornerMin.y); W.Write(_wsCornerMin.z); W.Write(_volumeSize); W.Write(_subdivisionsLevelsCount); W.Write(voxels.Count); foreach (Voxel V in voxels) { W.Write(V.X); W.Write(V.Y); W.Write(V.Z); W.Write(V.albedo.x); W.Write(V.albedo.y); W.Write(V.albedo.z); W.Write(V.normal.x); W.Write(V.normal.y); W.Write(V.normal.z); } } #else // Read from disk as it takes hell of a time to generate! List <Voxel> voxels = null; using (System.IO.FileStream S = new System.IO.FileInfo("CornellBox_" + subdivisionsCount + ".voxels").OpenRead()) using (System.IO.BinaryReader R = new System.IO.BinaryReader(S)) { _wsCornerMin.x = R.ReadSingle(); _wsCornerMin.y = R.ReadSingle(); _wsCornerMin.z = R.ReadSingle(); _volumeSize = R.ReadSingle(); _subdivisionsLevelsCount = R.ReadInt32(); int voxelsCount = (int)R.ReadUInt32(); voxels = new List <Voxel>(voxelsCount); Voxel V = new Voxel(); for (int voxelIndex = 0; voxelIndex < voxelsCount; voxelIndex++) { V.X = R.ReadUInt32(); V.Y = R.ReadUInt32(); V.Z = R.ReadUInt32(); V.albedo.x = R.ReadSingle(); V.albedo.y = R.ReadSingle(); V.albedo.z = R.ReadSingle(); V.normal.x = R.ReadSingle(); V.normal.y = R.ReadSingle(); V.normal.z = R.ReadSingle(); voxels.Add(V); } } #endif ////////////////////////////////////////////////////////////////////////// // 2] Encode these voxels into an octree OctreeNode root = new OctreeNode(_wsCornerMin, _volumeSize, 0); float3 wsVoxelPosition = float3.Zero; // 2.1) Add each voxel individually foreach (Voxel V in voxels) { wsVoxelPosition.x = _wsCornerMin.x + (0.5f + V.X) * voxelSize; wsVoxelPosition.y = _wsCornerMin.y + (0.5f + V.Y) * voxelSize; wsVoxelPosition.z = _wsCornerMin.z + (0.5f + V.Z) * voxelSize; root.AddVoxel(ref wsVoxelPosition, V, _subdivisionsLevelsCount); } // // 2.2) Normalize existing voxels // root.FinalizeLeafVoxels(); // 2.3) Build mips at all levels root.BuildAllMips(); // Save the resulting octree using (System.IO.FileStream S = new System.IO.FileInfo("CornellBox_" + subdivisionsCount + ".octree").Create()) using (System.IO.BinaryWriter W = new System.IO.BinaryWriter(S)) root.SaveRoot(W); #endif }