A terrain M is the graph of a bivariate function. We assume that M is represented as a triangulated surface with N vertices. A contour (or isoline) of M is a connected component of a level set of M. Generically, each contour is a closed polygonal curve; at "critical" levels these curves may touch each other or collapse to a point. We present I/O efficient algorithms for the following two problems related to computing contours of M: (i) Given a sequence l_1 < ... < l_s of real numbers, we present an I/O-optimal algorithm that reports all contours of M at heights l_1 < ... < l_s, using O(sort(N) + T=B) I/Os, where T is the total number edges in the output contours, B is the "block size," and sort(N) is the number of I/Os needed to sort N elements. The algorithm uses O(N=B) disk blocks. Each contour is generated individually with its composing segments sorted in clockwise or counterclockwise order. Moreover, our algorithm generates information on how the contours are nested. (ii) We can preprocess M, using O(sort(N)) I/Os, into a linear-size data structure so that all contours at a given height can be reported using O(log_B N + T=B) I/Os, where T is the output size. Each contour is generated individually with its composing segments sorted in clockwise or counterclockwise order.