Here, we present a set of classes which allow researchers to compose a digital scene of 3D models and ”scan” the scene by finding the ray and scene intersections using techniques from ray tracing. This allows researchers to quickly and easily produce their own LiDAR data. The synthetic LiDAR scan data can also be used to produce datasets for which a ground truth is known. This is useful to ensure algorithms are behaving properly before moving to non-synthetic LiDAR scans. If more realistic data is required, noise can be added to the points to attempt to simulate a real LiDAR scan.
Scanner Model
We have based the synthetic scanner on the Leica HDS3000 LiDAR scanner. This scanner acquires points on a uniform angular grid. The first point acquired is in the lower left of the grid. The scanner proceeds bottom to top, left to right. The order of acquisition is usually not important, but the code could be easily changed to mimic a different scanner if desired.
Input Parameters
It is necessary to set several parameters before performing a synthetic scan. These parameters are:
Outputs
Two outputs are possible depending on the user’s requirements. The first is a PTX file. A PTX file implicitly maintains the structure of the scan. The scan points in the file are listed in the same order as they were acquired. This point list, together with the size of the scan grid, is sufficient to represent the grid of points acquired by the synthetic scanner.
The second type of output is simply an unorganized point cloud stored in a VTP file. This representation is useful for algorithms which do not assume any structure is known about the input.
New Classes
We introduce three new classes to implement a synthetic LiDAR scanner. The first two, vtkRay and vtkLidarPoint are supporting classes of vtkLidarScanner, which is the class that does the majority of the work.
vtkRay
This is a container class to hold a point (ray origin) and a vector (ray direction). It also contains functions to:
vtkLidarPoint
This class stores all of the information about the acquisition of a single LiDAR point. It stores:
vtkLidarScanner
This class does all the work of acquiring the synthetic scan.
Coordinate System
The default scanner is located at (0,0,0) with the following orientation:
Positioning (“aiming”) a vtkLidarScanner
A rigid transformation can be applied to the scanner via the SetTransform function which positions and orients the scanner relative to the scene.
Casting Rays
Rays cast by the scanner are relative to the scanner’s frame after the transformation is applied to the default frame.

Figure 1: 3D view of the scan.
To demonstrate the angles which must be specified, a (Φ = 5; θ = 4) scan of a flat surface was acquired, as shown in Figure 1. Throughout these examples the red sphere indicates the scanner location, cylinders represent the scan rays, and blue points represent scan points (intersections of the rays with the object/scene).
Order of Acquisition
The points were acquired in the order shown in Figure 2.

Figure 2: Scan points labeled in acquisition order.
Theta angle
The angle in the Forward-Right plane (a rotation around Up), measured from Forward. Its range is -
to
. –
is left,
is right.
Figure 3 shows a top view of the scan of a flat surface. The min and max θ angles are labeled.

Figure 3: Diagram of Theta angle settings.
Phi angle
The elevation angle, in the Forward-Up plane (a rotation around Right), measured from Forward. Its range is –
(down) to
(up). This is obtained by rotating around the “right” axis (AFTER the new right axis is obtained by setting Theta).
Figure 4 shows a side (left) view of the scan of a flat surface. The min and max Φ angles are labeled

Figure 4: Diagram of Phi angle settings.
Normals
Each LiDAR point stores the normal of the surface that it intersected. A scan of a sphere is shown in Figure 5 to demonstrate this. The normal vector coming from the scanner (red sphere) is the “up” direction of the scanner.
Outputs
vtkPolyData
A typical output from a VTK filter is a vtkPolyData. The vtkLidarScanner filter stores and returns the valid LiDAR returns in a vtkPolyData. If the CreateMesh flag is set to true, a Delaunay triangulation is performed to create a triangle mesh from the LiDAR points. vtkDelaunay2D is used to triangulate the 3D points utilizing the grid structure of the scan. Figure 6 shows the setup of a scan, the result with CreateMesh = false, and the result with CreateMesh = true.

Figure 5: Scene intersections and their normals
PTX file
All of the LiDAR ray returns, valid and invalid, are written to an ASCII PTX file. The PTX format implicitly maintains the order of point acquisition by recording the points in the same order in which they were acquired. A “miss” point is recorded as a row of zeros. Upon reading the PTX file (not covered by this set of classes), the best test to see if a row of the file is valid is checking if the intensity of the return is 0. This prevents corner cases, such as a valid return from (0;0;0), from creating a problem or confusion.
Scanner coordinate frame
Using void vtkLidarScanner::WriteScanner(const std::string &Filename) const, a VTP file of the scanner can be written. A coordinate frame indicates the location and orientation of the scanner. The green axis is “up”, the yellow axis is “forward” and the red axis is “right”. Figure 7 shows the synthetic scan of a sphere along with the scanner that was used to perform the scan.
Data Structure Speed Up
Instead of intersecting each ray with every triangle in the scene, this problem immediately lends itself to using a spatial data structure to achieve an enormous speedup. We originally tried an octree (vtkOBBTree), but we found that a modified BSP tree (vtkModifiedBSPTree) gives a 45x speedup, even over the octree! The current implementation includes this speed up and is therefore very fast.

Figure 6: Effect of CreateMesh flag.

Figure 7: Synthetic scan of a sphere with the scanner displayed
Noise Model
By default, a synthetic scan is “perfect” in the sense that the scan points actually lie on a surface of the 3D model as in Figure 8. In a real world scan, however, this is clearly not the case. To make the synthetic scans more realistic, we have modeled the noise in a LiDAR scan using two independent noise sources: line-of-sight and orthogonal.
Line-of-Sight (LOS) Noise
Line-of-Sight noise reads as an error in the distance measurement performed by the scanner. It is a vector parallel to the scanner ray whose length is chosen randomly from a Gaussian distribution. This distribution is zero mean and has a user specified variance (double LOSVariance). An example of a synthetic scan with LOS noise added is shown in Figure 9.The important note is that the orange (noisy) rays are exactly aligned with the gray (noiseless) rays.

Figure 8: A noiseless synthetic scan

Figure 9: A synthetic scan with line-of-sight noise added
Orthogonal Noise
Orthogonal noise models the angular error of the scanner. It is implemented by generating a vector orthogonal to the scanner ray whose length is chosen from a Gaussian distribution. This distribution is also zero mean and has a user specified variance (double OrthogonalVariance). An example of a synthetic scan with orthogonal noise added is shown in Figure 10. Note that the green (noisy) rays are not aligned with the gray (noiseless) rays, but they are the same length.
Combined Noise
A simple vector sum is used to combine the orthogonal noise vector with the LOS noise vector.

Figure 10: A synthetic scan with orthogonal noise added
Example Scene
As an example, a car model with 20k triangles was scanned with a 100x100 grid. On a P4 3GHz machine with 2GB of ram, the scan took 0.6 seconds. Figure 11 shows the model and the resulting synthetic scan.

Figure 11: A car model and the resulting synthetic scan.
Example Code
An example (TestScanner.cpp) is provided with the code zip file, but the basics are demonstrated here below with hard coded values:
David Doria is a PhD student in Electrical Engineering at Rensselaer Polytechnic Institute. He received his BS in EE in 2007 and his MS in EE in 2008, both from RPI. David is currently working on 3D object detection in LiDAR data. He is passionate about reducing the barrier of entry into 3D data processing. Find out more about David on his website rpi.edu/~doriad or email him at daviddoria@gmail.com.