Something which only occurred to me recently when I read a bit about Java Mobile 3D was, that I generally ignored some of the abilities of the glNormal and glVertex functions: the ability to use integers. In mobile applications that is quite important, because most of the devices implementing the mobile 3D variant are lacking a floating point unit. So they have to emulate the FPU and that means, it is probably slower. So if possible you should use integers there.
That reminded me, that OpenGL also has that ability to use integers. I always considered it a remains of the early days (OpenGL is very old in IT terms). But I am no longer sure, if it isn't still quite useful.
In case you haven't used OpenGL, the basic operation of the old pipeline (there are newer ways, but they are compatible with the stuff I am about to explain) is the so called Begin/End-paradigm. You make a call to glBegin, send the coordinates of your face with glVertex and call glEnd. Additionally you can use glNormal to set the normal for all following coordinates. For a smooth surface you typically set a normal per vertex. The normal is used for smooth shading.
glVertex and glNormal are actually families of functions. You append the number of parameters and the type of the parameters to the base name. So you have glVertex2d or glVertex3f, the first sets the first two parameters of the vertex from floats (single precision floating point values), the second sets the first three parameters from doubles (double precision floating point values). A vertex in OpenGL always has four values for the three dimensions and a fourth one called w. The fourth coordiante is mostly set to 1, it is necessary because we work with homogeneous coordinates, but it is rarely set directly (I only used the variant with 3 values up to now, the two value variant is hardly useful in 3D and I never needed to set the 4. coordiante to anything but 1). There is only one use you see a bit more often, a value of 0 for w defines a direction, it can be useful for directional lights.
In addition to floating point values, there are also glVertex3s and glVertex3i (and glVertex2s, glVertex2i, glVertex4s and glVertex4i). The i stands for 32 bit integers, the s for 16 bit integers. I don't see many reasons for the 32 bit variants, floats are of the same size and you don't have to be careful to create the object properly scaled. But the s variants are interesting. As they only take up have as much memory, they might come in handy. The resolution isn't too bad if you always use the complete range they define, so for example defining a height map to use it should always be possible (I doubt you would use a bigger height field).
For normals there is even a variant called glNormal3b for byte. So they are only a fourth of the size of floats. I did a coarse error calculation and if I didn't make an error, the maximum difference between a normal defined in floats and bytes is guaranteed to be below 1.8°. So I seriously doubt that you would be able to spot an error if you don't have the same object with higher resolution right besides it.
So using them, I might be able to seriously cut down on the volume of data to be sent. I can get at least to half of it and when using bytes for the normals, even a bit lower. As I wrote in the beginning, you can also use these smaller values for more modern interfaces, i.e. vertex arrays and vertex buffer objects. And especially with VBOs it becomes very interesting. As VBOs are directly stored on the graphics card, you probably run out of memory earlier than you hope. When you can cut down one some object to half the memory (or alternatively load twice the amount of objects), it seems interesting to do that.
I especially would like to try it for the beach scene. One of the short comings is the rather deserted look. It would greatly benefit from some scattered stones and shells. And those objects seem like a perfect fit to these limitations. They are small, so the precision of shorts will suffice, the normal is not so important, so bytes should be ok and if you keep the number of vertices below 256 you can also use bytes for the element arrays further reducing memory. Additionally being able to use more than twice the amount will be very good, as it won't look as regular. And you fire them to the pipeline in high numbers.
The raytracer will obviously use the float variants. For it it would be terrible to use integers, as the necessary conversions would probably be quite expensive (most processors don't like to mix integers and floats). So for a raytracer you better have some memory.