/// <summary> /// method for rendering threads management /// </summary> private void Render() { // create WaitCallBack instances with proper rendering methods var renderingCallBacks = new List <WaitCallback>(); foreach (var renderingJob in renderingJobs) { renderingCallBacks.Add(new WaitCallback(new RenderingThread().Render)); } var camera = Scene.Current.Camera; var frameTimer = new HighPerformanceTimer(); do { frameTimer.Start(); frameRedrawnEvent.Reset(); frameRenderedEvent.Reset(); // update camera view camera.Update(OutputBufferSize); // render all jobs for (var i = 0; i < renderingCallBacks.Count; i++) { ThreadPool.QueueUserWorkItem(renderingCallBacks[i], renderingJobs[i]); } // wait for end of rendering frameRenderedEvent.Wait(); FramesRendered++; if (framesToRender.HasValue && framesToRender.Value > 0) { framesToRender--; } frameTimer.Stop(); LastFrameDuration = frameTimer.Duration; RenderingDuration += LastFrameDuration; if (waitForOutputRedraw) { // wait while output window is redrawn frameRedrawnEvent.WaitOne(); } }while (!stopRendering && (!framesToRender.HasValue || framesToRender.Value > 0)); endOfRenderingEvent.Set(); }
/// <summary> /// /// </summary> private void LoadFromFile(string objFilename) { Filename = objFilename; // TODO read material file *.mtl var lines = File.ReadAllLines(objFilename); var timer = new HighPerformanceTimer(); timer.Start(); var min = new Vector3(float.MaxValue); var max = new Vector3(float.MinValue); for (var i = 0; i < lines.Length; i++) { var line = lines[i]; try { if (line.StartsWith("# object")) { if (string.IsNullOrEmpty(Name)) { Name = line.Substring("# object ".Length); } } // vertex else if (line.StartsWith("v ")) { var parts = line.Substring("v ".Length).Replace('.', ',').Split(' '); var vertex = new Vector3(float.Parse(parts[0], System.Globalization.NumberStyles.Float), float.Parse(parts[1]), float.Parse(parts[2])); if (vertex.X < min.X) { min.X = vertex.X; } if (vertex.Y < min.Y) { min.Y = vertex.Y; } if (vertex.Z < min.Z) { min.Z = vertex.Z; } if (vertex.X > max.X) { max.X = vertex.X; } if (vertex.Y > max.Y) { max.Y = vertex.Y; } if (vertex.Z > max.Z) { max.Z = vertex.Z; } Vertices.Add(vertex); } // vertex normal else if (line.StartsWith("vn ")) { var parts = line.Substring("vn ".Length).Replace('.', ',').Split(' '); Normals.Add(new Vector3(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]))); } // vertex texture coordinates else if (line.StartsWith("vt ")) { var parts = line.Substring("vt ".Length).Replace('.', ',').Split(' '); TextureCoords.Add(new Vector2(float.Parse(parts[0]), float.Parse(parts[1]))); } // face indices else if (line.StartsWith("f ")) { var parts = line.Substring("f ".Length).Split(' '); var v1Parts = parts[0].Split('/'); var v2Parts = parts[1].Split('/'); var v3Parts = parts[2].Split('/'); Faces.Add( new Face( this, int.Parse(v1Parts[0]) - 1, int.Parse(v2Parts[0]) - 1, int.Parse(v3Parts[0]) - 1, int.Parse(v1Parts[1]) - 1, int.Parse(v2Parts[1]) - 1, int.Parse(v3Parts[1]) - 1, int.Parse(v1Parts[2]) - 1, int.Parse(v2Parts[2]) - 1, int.Parse(v3Parts[2]) - 1 ) ); } } catch (Exception ex) { throw new Exception(string.Format("ObjImporter failed at line='{0}'", line), ex); } } BoundingBox = new AACell { Min = min, Max = max }; timer.Stop(); Log.Instance.AddMsg(LogLevel.Info, string.Format("WavefrontObjMesh '{0}' [vertices: {1}; faces: {2}; size: {3}] loaded in {4}", Name, Vertices.Count, Faces.Count, BoundingBox.Size.ToString(), FormatString.GetDuration((int)timer.Duration))); }
/// <summary> /// /// </summary> /// <param name="obj"></param> /// <param name="maxDepth"></param> /// <param name="voxelSizeThreshold"></param> /// <returns></returns> public static VoxelOctree Create(IVoxelizable obj, int maxDepth, float voxelSizeThreshold) { var octree = new VoxelOctree(maxDepth, voxelSizeThreshold); var timer = new HighPerformanceTimer(); timer.Start(); var cellSize = obj.BoundingBox.Size; var newCellSize = (cellSize.X > cellSize.Y ? (cellSize.X > cellSize.Z ? cellSize.X : cellSize.Z) : (cellSize.Y > cellSize.Z ? cellSize.Y : cellSize.Z)) * 0.5f; var generateNewOctree = true; if (obj is WavefrontObjMesh && File.Exists((obj as WavefrontObjMesh).Filename + ".octree")) { generateNewOctree = !octree.LoadFromFile((obj as WavefrontObjMesh).Filename + ".octree", maxDepth); } if (generateNewOctree) { #region calculate RootCell (equal edge sizes) var center = obj.BoundingBox.Center; octree.RootCell = new AACell { Min = new Vector3(center.X - newCellSize, center.Y - newCellSize, center.Z - newCellSize), Max = new Vector3(center.X + newCellSize, center.Y + newCellSize, center.Z + newCellSize) }; #endregion // create octree recursively octree.RootNode = new OctreeNode(); if (VoxelOctree.GenerateOnMultipleThreads) { Log.Instance.AddMsg(LogLevel.Info, string.Format("Generating VoxelOctree/MT [maxDepth: {0}; voxelSizeThreshold: {1}] ...", maxDepth, voxelSizeThreshold)); octree.ProcessNodeMultithreaded(obj, octree.RootCell, octree.RootNode); } else { Log.Instance.AddMsg(LogLevel.Info, string.Format("Generating VoxelOctree/ST [maxDepth: {0}; voxelSizeThreshold: {1}] ...", maxDepth, voxelSizeThreshold)); octree.ProcessNode(obj, octree.RootCell, octree.RootNode, 0); } } timer.Stop(); // count all nodes var nodeCount = CountNodesRecursive(octree.RootNode) + 1; // get actual tree depth octree.maxDepth = VoxelOctree.GetMaxDepth(octree.RootNode); #region calculate smallest voxel size var smallestVoxelSize = newCellSize * 2f; for (var i = 0; i < octree.maxDepth; i++) { smallestVoxelSize *= .5f; } #endregion Log.Instance.AddMsg(LogLevel.Info, string.Format("VoxelOctree [size: {0}; nodes: {1}; depth: {2}; voxelSize: {3}] generated in {4}", newCellSize * 2f, nodeCount, octree.maxDepth, smallestVoxelSize, FormatString.GetDuration((int)timer.Duration))); if (obj is WavefrontObjMesh && generateNewOctree) { octree.SaveToFile((obj as WavefrontObjMesh).Filename + ".octree"); } return(octree); }