Image Synthesis Assignment 1: Heightfield Intersection
Due: February 8
For this assignment, you will improve pbrt's support for rendering terrain in scenes like landscapes and seascapes. Terrain is often represented as an elevation map, or what we will call a heightfield: a 2D table indicating the height of a surface above each point of a uniform grid. In other words, a heightfield is tabulated form of a height function z(x,y) stored in a 2D array.
pbrt has no native support for rendering directly from heightfield data. Instead, it converts heightfields into triangle meshes by connecting adjacent height values in the array. This approach is general but relatively inefficient; by converting to triangles we lose the orderly structure of the heightfield, which can be exploited to render more efficiently. Your assignment is to apply techniques similar to those used for grid-based acceleration structures to develop a fast intersection routine for heightfields.
I installed the heightfield plugin and rendered the tests scenes:
![]() |
![]() |
I implemented the simple list-type "accelerator". I only rendered one large scene with this structure as it took almost half an hour to render. It's curious that the hftest.pbrt scene actually outperforms the uniform grid accelerating structure.
| accelerator | hftest.pbrt | landsea-0.pbrt |
| slow-grid | 0.4 seconds (honestly) | 1753.1 seconds |
| uniform grid | 0.5 seconds | 7.8 seconds |
| k-D tree | 0.4 seconds | 6.6 seconds |
I modified the existing heightfield class to allow for faster intersections than by default. I was not able to outperform the built in triangle tessellation methods of pbrt however. This could be done with my existing code by exploiting maximum and minimum z-values to throw out bad candidates earlier. In the end, the time constraints of completing the assignment overuled this. I also implemented Phong interpolated normals by multiplying adjacent normals by the barycentric coordinates of a given triangle in the heightfield. In addition, I implemented (u,v) coordinates to allow texture mapping heightfields too.
| accelerator | texture.pbrt | landsea-0.pbrt |
| slow-grid | 159.0 seconds | 1753.1 seconds |
| uniform grid | 1.2 seconds | 7.8 seconds |
| k-D tree | 1.1 seconds | 6.6 seconds |
| height-grid (w/ Phong) : slow-grid | 5.5 seconds | 63.0 seconds |
| height-grid (w/ Phong) : uniform grid | 5.3 seconds | 62.5 seconds |
| height-grid (w/ Phong) : k-D tree | 5.3 seconds | 23.8 seconds |
Texture Mapped Phong Interpolated Griddy-McGridness

For some reason the water and land would not render together so I separated them to show that they are actually working independantly, but for whatever reason when they are overlapped the water becomes black...
![]() |
+ |
![]() |
≈ |
![]() |
Accidental Art
