diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index b07d046c4262069cfec2b61c7bbf30a16fa8e11c..ae414406dbd568f6a3ac333e832b8c9c2dc778c9 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -714,23 +714,28 @@ a non-equal distribution of ore.
 
 ### `sheet`
 Creates a sheet of ore in a blob shape according to the 2D perlin noise
-described by `noise_params`. The relative height of the sheet can be
-controlled by the same perlin noise as well, by specifying a non-zero
-`scale` parameter in `noise_params`.
+described by `noise_params`. This is essentially an improved version of
+the so-called "stratus" ore seen in some unofficial mods.
 
-**IMPORTANT**: The noise is not transformed by `offset` or `scale` when comparing
-against the noise threshold, but scale is used to determine relative height.
-The height of the blob is randomly scattered, with a maximum height of `clust_size`.
+This sheet consists of vertical columns of uniform randomly distributed height,
+varying between the inclusive range `column_height_min` and `column_height_max`.
+If `column_height_min` is not specified, this parameter defaults to 1.
+If `column_height_max` is not specified, this parameter defaults to `clust_size`
+for reverse compatibility.  New code should prefer `column_height_max`.
 
-`clust_scarcity` and `clust_num_ores` are ignored.
+The `column_midpoint_factor` parameter controls the position of the column at which
+ore eminates from.  If 1, columns grow upward.  If 0, columns grow downward.  If 0.5,
+columns grow equally starting from each direction.  `column_midpoint_factor` is a
+decimal number ranging in value from 0 to 1.  If this parameter is not specified,
+the default is 0.5.
 
-This is essentially an improved version of the so-called "stratus" ore seen in
-some unofficial mods.
+The ore parameters `clust_scarcity` and `clust_num_ores` are ignored for this ore type.
 
 ### `blob`
 Creates a deformed sphere of ore according to 3d perlin noise described by
 `noise_params`.  The maximum size of the blob is `clust_size`, and
 `clust_scarcity` has the same meaning as with the `scatter` type.
+
 ### `vein
 Creates veins of ore varying in density by according to the intersection of two
 instances of 3d perlin noise with diffferent seeds, both described by
diff --git a/src/mg_ore.cpp b/src/mg_ore.cpp
index 0d0f74bf5996279f7dbe19cede28743b8137ec5f..f5d312ba273353474ea41c0acf754ccc3298e7ca 100644
--- a/src/mg_ore.cpp
+++ b/src/mg_ore.cpp
@@ -176,8 +176,8 @@ void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed,
 	PseudoRandom pr(blockseed + 4234);
 	MapNode n_ore(c_ore, 0, ore_param2);
 
-	int max_height = clust_size;
-	int y_start = pr.range(nmin.Y, nmax.Y - max_height);
+	u16 max_height = column_height_max;
+	int y_start = pr.range(nmin.Y + max_height, nmax.Y - max_height);
 
 	if (!noise) {
 		int sx = nmax.X - nmin.X + 1;
@@ -200,10 +200,12 @@ void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed,
 				continue;
 		}
 
-		int height = max_height * (1. / pr.range(1, 3));
-		int y0 = y_start + np.scale * noiseval; //pr.range(1, 3) - 1;
+		u16 height = pr.range(column_height_min, column_height_max);
+		int ymidpoint = y_start + noiseval;
+		int y0 = ymidpoint - height * (1 - column_midpoint_factor);
 		int y1 = y0 + height;
-		for (int y = y0; y != y1; y++) {
+
+		for (int y = y0; y < y1; y++) {
 			u32 i = vm->m_area.index(x, y, z);
 			if (!vm->m_area.contains(i))
 				continue;
diff --git a/src/mg_ore.h b/src/mg_ore.h
index ffe8cfe5081e7f19d7e1b80f5dd3fb5c7da6c5c7..db204437ebf5cc0c3d0bec0022e2cf20f6908516 100644
--- a/src/mg_ore.h
+++ b/src/mg_ore.h
@@ -87,6 +87,10 @@ class OreSheet : public Ore {
 public:
 	static const bool NEEDS_NOISE = true;
 
+	u16 column_height_min;
+	u16 column_height_max;
+	float column_midpoint_factor;
+
 	virtual void generate(MMVManip *vm, int mapseed, u32 blockseed,
 		v3s16 nmin, v3s16 nmax, u8 *biomemap);
 };
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index d30b680548e1bd9522d4f9d8625b1f2796266942..9050816bbcfa76277fe2585ff50b050e6f151f2a 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -937,8 +937,19 @@ int ModApiMapgen::l_register_ore(lua_State *L)
 	}
 	lua_pop(L, 1);
 
-	if (oretype == ORE_VEIN) {
+	//// Get type-specific parameters
+	if (oretype == ORE_SHEET) {
+		OreSheet *oresheet = (OreSheet *)ore;
+
+		oresheet->column_height_min = getintfield_default(L, index,
+			"column_height_min", 1);
+		oresheet->column_height_max = getintfield_default(L, index,
+			"column_height_max", ore->clust_size);
+		oresheet->column_midpoint_factor = getfloatfield_default(L, index,
+			"column_midpoint_factor", 0.5f);
+	} else if (oretype == ORE_VEIN) {
 		OreVein *orevein = (OreVein *)ore;
+
 		orevein->random_factor = getfloatfield_default(L, index,
 			"random_factor", 1.f);
 	}