/// <summary> /// insert points into this node. Method does not check if these points belong here or not /// </summary> /// <param name="firstPointIndex">index of first point in source array in las file</param> /// <param name="source"></param> /// <param name="fromIdx"></param> /// <returns>next unused point or source.Length if all points were used</returns> internal int InsertPreliminary(uint firstPointIndex, Point3D[] source, int fromIdx, float selectionLOD) { findStepStopWatch.Start(); int toIndex = findEndWithStep(source, fromIdx, source.Length - 1); findStepStopWatch.Stop(); int sourcePtsLength = toIndex - fromIdx + 1; if (numberOfPoints == 0 && sourcePtsLength > 0) { LasMetrics.GetInstance().numberOfNonEmptyLeafs++; } numberOfPoints += sourcePtsLength; if (toIndex - fromIdx < 0) { numberOfSmallLists++; //do not add } else { this.SelectionLOD = selectionLOD; ListInfo listInfo = new ListInfo(); listInfo.numberOfPoints = (ushort)sourcePtsLength; listInfo.startingPointIndex = firstPointIndex + (uint)fromIdx; //have to add offset to get proper point ListInfos.Add(listInfo); } return(toIndex + 1); //should be pointing on next available point if any }
public static void ClearSecondPassQueue() { secondPassVBOs.Clear(); LasMetrics.GetInstance().pointsDrawn = pointsDrawnInPass; pointsDrawnInPass = 0; }
private void timer1_Tick(object sender, EventArgs e) { indexing.Text = LasMetrics.GetInstance().indexing.ToString(); indexingNoDisk.Text = LasMetrics.GetInstance().indexingNoDisk.ToString(); avgLoad.Text = LasMetrics.GetInstance().avgLoad.ToString(); avgLoadNoDisk.Text = LasMetrics.GetInstance().avgLoadNoDisk.ToString(); avgPPL.Text = LasMetrics.GetInstance().avgPointsPerLeaf.ToString(); avgPPLactual.Text = LasMetrics.GetInstance().avgPointsPerLeafActual.ToString(); numberOfNonEmptyLeafs.Text = LasMetrics.GetInstance().numberOfNonEmptyLeafs.ToString(); numberOfPoints.Text = LasMetrics.GetInstance().numberOfPoints.ToString(); lblNumPointsInVBOs.Text = LasMetrics.GetInstance().numberOfPointsLoadedIntoExistingVBOs.ToString(); lblNumVBOs.Text = LasMetrics.GetInstance().numberOfExistingVBOs.ToString(); lblPointsInsideView.Text = ((double)LasMetrics.GetInstance().pointsInsideViewMilis.TotalMilliseconds / LasMetrics.GetInstance().pointsInsideViewCounted).ToString(); if (RenderMetrics.getInstance() != null) { FPS.Text = RenderMetrics.getInstance().FPS.ToString(); frameDrawTime.Text = RenderMetrics.getInstance().frameRenderTime.ToString(); if (LasMetrics.GetInstance().pointsDrawn > 0) { pointsDrawn.Text = LasMetrics.GetInstance().pointsDrawn.ToString(); } double copiedToGPU = (double)LasMetrics.GetInstance().bytesTransferedToGPU / (1024.0 * 1024.0); lblRAM2GPU.Text = copiedToGPU.ToString(); } tabControl1.SelectedTab.Refresh(); }
private void PreprocessDataFromFile(QTreeWrapper qtreeWrapper) { Stopwatch initTimer = new Stopwatch(); initTimer.Start(); qtreeWrapper.lasFile.PositionAtStartOfPointData(); uint index = 0; uint numAllPoints = qtreeWrapper.lasFile.header.NumberOfPointRecords; Point3D[] lineOfPoints = null; int step = 100000; determineInitialSelectionLOD(); TimeSpan accReadTime = new TimeSpan(); while (index < numAllPoints) { if (loadingStatusEvent != null) { loadingStatusEvent("Indexing points..." + index + "/" + numAllPoints, (float)index / (float)numAllPoints); } TimeSpan before = initTimer.Elapsed; lineOfPoints = GetPoints(qtreeWrapper, index, step); accReadTime += (initTimer.Elapsed - before); if (lineOfPoints != null) { qtreeWrapper.qtree.Initialize(index, lineOfPoints, SelectionLOD); } index += (uint)lineOfPoints.Length; lineOfPoints = null; } initTimer.Stop(); LasMetrics.GetInstance().indexing = initTimer.ElapsedMilliseconds; LasMetrics.GetInstance().indexingNoDisk = (initTimer.Elapsed - accReadTime).TotalMilliseconds; LasMetrics.GetInstance().avgPointsPerLeafActual = (double)numAllPoints / LasMetrics.GetInstance().numberOfNonEmptyLeafs; LasMetrics.GetInstance().numberOfPoints += numAllPoints; Console.WriteLine("lasDataManager.Initialize() took {0} ms for {1} points", initTimer.ElapsedMilliseconds, numAllPoints); Console.WriteLine("reading from disk took {0} ms, indexing without reading from disk took {1} ms", accReadTime.TotalMilliseconds, LasMetrics.GetInstance().indexingNoDisk); Console.WriteLine("nr. of all points: {0}, avg. points per leaf: {1}, without empty: {2}", numAllPoints, numAllPoints / LasMetrics.GetInstance().numberOfLeafs, LasMetrics.GetInstance().avgPointsPerLeafActual); Console.WriteLine("QTreeLeaf.findEnd() took {0} ms", QTreeLeaf.findStepStopWatch.ElapsedMilliseconds); Console.WriteLine("array copying() took {0} ms", QTreeLeaf.arrayCompyTimer.ElapsedMilliseconds); Console.WriteLine("mem alocated: {0}kb", GC.GetTotalMemory(false) / 1024); }
private void btnLeafLoading_toggle_Click(object sender, EventArgs e) { if (btnLeafLoading_toggle.Text == "Start") { btnLeafLoading_toggle.Text = "Stop"; LasMetrics.GetInstance().leafLoadToggle = true; } else { LasMetrics.GetInstance().leafLoadToggle = false; btnLeafLoading_toggle.Text = "Start"; } }
private void OnPaint(object sender, PaintEventArgs e) { frameCounter++; watch.Stop(); base.OnPaint(e); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); RenderScene(); stopwatch.Stop(); //this.Text = "Frame rendered in " + stopwatch.ElapsedMilliseconds + " ms. Between frames: "+watch.ElapsedMilliseconds+", points: "+QTreeLeaf.total_drawn_points_in_pass; //Console.WriteLine("f#"+frameCounter+" rendered in " + stopwatch.ElapsedMilliseconds + "ms, between frames: " + watch.ElapsedMilliseconds + "ms, points: " + QTreeLeaf.total_drawn_points_in_pass); if (frameCounterStopwatch.ElapsedMilliseconds > fpsSampleIntervalMilis) { frameCounterStopwatch.Stop(); float fps = 1000.0f * (float)frameCounter / frameCounterStopwatch.ElapsedMilliseconds; float avgTime = (float)frameCounterStopwatch.ElapsedMilliseconds / frameCounter; Text = String.Format("FPS: {0}, points drawn: {1}", fps, LasMetrics.GetInstance().pointsDrawn); RenderMetrics.getInstance().FPS = fps; RenderMetrics.getInstance().frameRenderTime = avgTime; if (updateFormsEvent != null) { updateFormsEvent(); } frameCounter = 0; frameCounterStopwatch.Reset(); frameCounterStopwatch.Start(); } watch.Reset(); watch.Start(); }
public static void DeleteFromGPU(VBOStorageInformation serverBufferIds) { //free memory on server if (serverBufferIds.NumberOfPoints == 0) { return; } int[] buffersToDelete = new int[3]; buffersToDelete[0] = serverBufferIds.VertexVBO; buffersToDelete[1] = serverBufferIds.NormalVBO; buffersToDelete[2] = serverBufferIds.ColorVBO; Gl.glDeleteBuffers(buffersToDelete.Length, buffersToDelete); LasMetrics.GetInstance().bytesCurrentlyOnGPURAM -= serverBufferIds.NumberOfPoints * 3 * 4; //3=every point has color, position and normal; 4=every value has 4 bytes LasMetrics.GetInstance().numberOfExistingVBOs--; LasMetrics.GetInstance().numberOfPointsLoadedIntoExistingVBOs -= serverBufferIds.NumberOfPoints; serverBufferIds.ColorVBO = serverBufferIds.NormalVBO = serverBufferIds.VertexVBO = 0; serverBufferIds.NumberOfPoints = 0; }
/// <summary> /// copies points into the VBOs. returns number of points that were copied /// </summary> /// <param name="nbrPts"></param> /// <param name="vertices"></param> /// <param name="normals"></param> /// <param name="colors"></param> /// <param name="serverBufferIds"></param> /// <returns></returns> unsafe public static void CopyPointsToVBOs(float[] interleavedData, VBOStorageInformation serverBufferIds) { //create and initialize vertexbuffer Gl.glBindBuffer(Gl.GL_ARRAY_BUFFER, serverBufferIds.InterleavedVBO); VBOUtils.CheckGlError("Tried first binding of interleaved VBO during glBegin() and glEnd()"); long bytesCopied = 0; int size = 0; fixed(float *vptr = interleavedData) { size = (sizeof(float) * interleavedData.Length); bytesCopied += size; Gl.glBufferData(Gl.GL_ARRAY_BUFFER, (IntPtr)size, (IntPtr)vptr, Gl.GL_STATIC_DRAW); } VBOUtils.CheckGlError("Error copying interleaved data to VBO"); LasMetrics.GetInstance().bytesTransferedToGPU += bytesCopied; LasMetrics.GetInstance().numberOfPointsLoadedIntoExistingVBOs += serverBufferIds.NumberOfPoints; }
public static void RenderVBOsFastSecondPass() { if (LasMetrics.GetInstance().renderToggle == false || secondPassVBOs.Count == 0) { return; } int numVBOSIs = secondPassVBOs.Count; VBOStorageInformation vbo = null; int stride = 40; for (int i = 0; i < numVBOSIs; i++) { vbo = secondPassVBOs[i]; Gl.glBindBuffer(Gl.GL_ARRAY_BUFFER, vbo.InterleavedVBO); Gl.glInterleavedArrays(Gl.GL_C4F_N3F_V3F, stride, IntPtr.Zero); Gl.glDrawArrays(Gl.GL_POINTS, 0, vbo.NumberOfPoints); } }
public static void RenderVBO(VBOStorageInformation vbo) { if (LasMetrics.GetInstance().renderToggle == false) { return; } Gl.glBindBuffer(Gl.GL_ARRAY_BUFFER, vbo.InterleavedVBO); //array is interleaved like this: VVVNNNCCCC - this is 10*4 bytes. //try glInterleavedArrays instead of this three calls, should be faster Gl.glInterleavedArrays(Gl.GL_C4F_N3F_V3F, PointInformationSize, IntPtr.Zero); Gl.glDrawArrays(Gl.GL_POINTS, 0, vbo.NumberOfPoints); pointsDrawnInPass += vbo.NumberOfPoints; //add vbo for fast second pass rendering secondPassVBOs.Add(vbo); }
unsafe public static VBOStorageInformation GenerateVBOs(int numberOfPoints) { //generate free buffer names for 3 different buffers int bufferId = 0; Gl.glGenBuffers(1, out bufferId); VBOUtils.CheckGlError("Tried first binding of VBO during glBegin() and glEnd()"); if (bufferId == 0) { throw new ApplicationException("ID of VBO should be set but was not!!!"); } VBOStorageInformation vboSI = new VBOStorageInformation(); vboSI.InterleavedVBO = bufferId; vboSI.NumberOfPoints = numberOfPoints; LasMetrics.GetInstance().numberOfExistingVBOs++; return(vboSI); }
public QTreeLeaf(BoundingBox bb, Guid parentTreeID, QTreeNode parentNode) { ParentTreeID = parentTreeID; this.ParentNode = parentNode; QTreeWrapper parent = LasDataManager.GetInstance().GetQtreeByGuid(parentTreeID); parentVBOs = new Stack <VBOStorageInformation>(); //stored on this level ListInfos = new List <ListInfo>(); LasMetrics.GetInstance().numberOfLeafs++; boundingBox = bb; if (randArray == null) { randArray = new float[3000]; for (int i = 0; i < randArray.Length; i++) { randArray[i] = (float)rand.NextDouble(); } } }
/// <summary> /// leads leafs in a separate thread /// </summary> private void LeafLoader() { TimeSpan accLoadTime = new TimeSpan(); long loadCount = 0; TimeSpan accReadTime = new TimeSpan(); TimeSpan readTemp = new TimeSpan(); Stopwatch stopwatch = new Stopwatch(); long accPointsPerLeaf = 0; QTreeLeaf leaf = null; while (runLeafLoader) { if (LasMetrics.GetInstance().leafLoadToggle&& leafLoadRequestQueue.Count > 0) { leaf = leafLoadRequestQueue.Dequeue(); if (leaf == null) { continue; } if (leaf.State == LoadedState.REQUEST_LOAD) //if leaf still wants to be loaded { stopwatch.Start(); long readTicks = 0; for (int i = 0; i < leaf.ListInfos.Count; i++) { readTemp = stopwatch.Elapsed; Point3D[] pts = GetPoints(GetQtreeByGuid(leaf.ParentTreeID), leaf.ListInfos[i].startingPointIndex, leaf.ListInfos[i].numberOfPoints); readTicks = stopwatch.ElapsedTicks; accReadTime += (stopwatch.Elapsed - readTemp); leaf.InsertPoints(i, pts); } if (CALCULATE_NORMALS == true) { leaf.CalculateNormals(); } long loadTicks = stopwatch.ElapsedTicks; accLoadTime += stopwatch.Elapsed; stopwatch.Stop(); loadCount++; stopwatch.Reset(); leaf.State = LoadedState.BUFFERED_IN_RAM; if (loadCount > 0) { double avgLoadTime = accLoadTime.TotalMilliseconds / loadCount; double avgLoadTimeNoRead = (accLoadTime - accReadTime).TotalMilliseconds / loadCount; //Console.WriteLine("Avg. time from disk to GPU: {0} ms, without disk reads: {1} ms", avgLoadTime, avgLoadTimeNoRead); LasMetrics.GetInstance().avgLoad = avgLoadTime; LasMetrics.GetInstance().avgLoadNoDisk = avgLoadTimeNoRead; accPointsPerLeaf += leaf.NumberOfPoints; LasMetrics.GetInstance().avgPointsPerLeaf = (double)accPointsPerLeaf / loadCount; } } leaf = null; } else { Thread.Sleep(leafLoaderMSsleepInterval); } } }
/// <summary> /// rendering pass for a node /// </summary> /// <param name="FOV"></param> /// <param name="near"></param> /// <param name="far"></param> /// <param name="eyeVector"></param> /// <param name="position"></param> /// <param name="renderOverride">flag that prevents node to be rendered even if in view field, if its too far down the hierarchy</param> internal void RenderingPass(float FOV, float near, float far, Vector3f eyeVector, Point2f position, bool renderOverride) { //new algo: test if three points forming a view triangle lie within the box or only a part if current node pointsInsideFOV.Reset(); pointsInsideFOV.Start(); int pointsInside = NumberOfPointsInsideFOV(false, far, eyeVector, position); pointsInsideFOV.Stop(); LasMetrics.GetInstance().pointsInsideViewMilis += pointsInsideFOV.Elapsed; LasMetrics.GetInstance().pointsInsideViewCounted++; //if render override flag was not set to false, check if it can be set here //renderOverride set to false prevents node or leaf to be rendered if too far away, //although it can still be loaded into memory. This prevents far away regions to be //drawn in too much detail that isn't even visible if (QTreeNode.PerNodeLOD && renderOverride && !boundingBox.contains(position)) { float closestCorner = position.DistanceTo(boundingBox.Center); //check if nearest corner is close enough to warant rendering this level for (int i = 0; i < 4; i++) { float distToPosition = position.DistanceTo(boundingBox.Corners[i]); if (closestCorner > distToPosition) { closestCorner = distToPosition; } } //calculate distance relative to the far point. determines which nodes will be drawn and which not float relativeDistance = 1.0f - closestCorner / far; if (relativeDistance < nodeHierarchyLevel) { renderOverride = false; } } if (pointsInside == 3) { //all points are seen - contents of the node should immediately be drawn without further checks if (renderOverride) { RenderVisible(); } } else if (pointsInside > 0) { //if only some of the points are inside, checks should be performed in children if (renderOverride) { Render(); } if (leaf != null) { //if only a part is inside, render it anyway. leaf.Render(renderOverride); } else { //render also this node. parts of this node that are visible will be already loaded and therefore visible nodes[NE].RenderingPass(FOV, near, far, eyeVector, position, renderOverride); nodes[NW].RenderingPass(FOV, near, far, eyeVector, position, renderOverride); nodes[SE].RenderingPass(FOV, near, far, eyeVector, position, renderOverride); nodes[SW].RenderingPass(FOV, near, far, eyeVector, position, renderOverride); } } else { //no points are inside //count number of buffered corners. if: //- all buffered - place leaf in buffer // -some buffered - delve further //- none buffered - cascadeInvisibility //new values for buffered checks + values are modified with Buffered values int bufferedPointsInside = NumberOfPointsInsideFOV( true, far + LasDataManager.BufferedDistance, eyeVector, position - new Point2f(eyeVector.x, eyeVector.z) * LasDataManager.BufferedPositionRadius); if (bufferedPointsInside == 3) { //all points are within buffer range- buffer all lower nodes and leafs if (leaf != null) { leaf.BufferLeaf(); } else { CascadeBuffering(); } } else if (bufferedPointsInside > 0) { //if only some of the points are inside, checks should be performed in children if (leaf != null) { //if 2 or more points are inside buffered area buffer it anyways if (bufferedPointsInside > 1) { leaf.BufferLeaf(); } } else { nodes[NE].RenderingPass(FOV, near, far, eyeVector, position, renderOverride); nodes[NW].RenderingPass(FOV, near, far, eyeVector, position, renderOverride); nodes[SE].RenderingPass(FOV, near, far, eyeVector, position, renderOverride); nodes[SW].RenderingPass(FOV, near, far, eyeVector, position, renderOverride); } } else { //none are buffered - remove if in buffer CascadeInvisibility(); } } }