Needed:
lifetime integr.nb
geometry error.nb
inverserror.nb
texture.nb

Converting #polys and texsize to #bytes

Definitions

We have so many variables now, many of which are pseudo-constant, that we collect them in a list. This list will be filled with the constants as they are needed.This will be a list of rewrite rules. You can prepend a new value for a variable in the list, effectively overruling the default value.
This works as the Graphics Options construction, such as 'Frame->True'.

ConversionConstants  =  {};

WARNING. Setting one of the conversionconstants hard, for instance setting MaxPolygons=3, will override any value set in ConversionConstants!!!

required texture size

derived from r,d,max.distortion and lifetime

The following file defines a function
TexSize[r_,distance_,T_,Distortion_,MinDistance_,ObsSpeed_]
returning the number of pixels required

<< texture . nb

It's always a problem in Mathematica to localise the other files. Just evaluate it by hand if this fails...

ConversionConstants = 
      Join[ConversionConstants, {MPEG -> 75,  JPEG -> 20,  
          RGB -> 3,  RGBA -> 4,  RGBAD -> 5}]

Polygon size

<< "geometry error.nb"

This also defines plotcolors

<< inverserror.nb

This defines PolySimpN, VptDepSimpN and MeshedImposterN

ConversionConstants = 
      Join[ConversionConstants, {MinDistance -> 0.1, 
          VertexReuse -> 6, BitsPerVertex -> 30 + 12,  
          BitsPerFace -> 4, 
MaxPolygons -> 
            Infinity, ObsSpeed -> 1 }]

In a conventional mesh and assuming triangles, 
each vertex is corner of 6 triangles.
In a quadmesh this would be 4 but we assume triangles throughout.
MinDistance is the minimum distance that is accepted/corrected for (in meters).
In our current implementation prototype Mesa seems unable to handle indexedfacesets with texture properly. Thus we had to 'unfold' the indexedfaceset completely, giving VertexReuse=1.

BitsPerVertex is including the normals and texture coords.
So we have 3 coordinates for the position, 3 coordinates for the normal and 2 for the texture, or 8 coordinates in total.
[Pajarola] suggests that 4 to 6 bits are required for each coordinate, giving 48 bits per vertex .
Using compressed normals using a limited set of 4096 normal directions we need only 12 bits for the normal instead of 3*6=18[], giving 42 bits per vertex. 
When data is transmitted binary but not compressed, we need 4 bytes per coordinate = 32 bytes = 256 bits per vertex.
When data is transmitted ASCII, we have 10 bytes per coordinate = 80 bytes = 640 bits per vertex.

BitsPerFace is number of bits to store connectivity info. [Pajarola] comes to 3.7 bits per triangle. Without compression, 3 indices are required. Coding indices binary with 4byte integers, we get 4*3=12 bytes =   96 bits per face.Coding ASCII with 5 characters (4 digits and a space) or 40 bits per index, we have 120 bits per face.
With our prototype, the indexedfaceset mode does not work properly, giving VertexReuse=1 but no need for indices and therefore BitsPerFace=0.

We currently do not account for overhead when multiple objects are involved, transformation between objects, lighting etc.

SizeOf[Npolys_, NPixelBytes_, 
          CompressionRate_] := 
PolygonBytes[Npolys] + 
          NPixelBytes/CompressionRate;

VertexBytes[
          V_] := ((VertexReuse*V/3)*BitsPerFace  +  
              V*BitsPerVertex)/8;

Clear[PolygonBytes]

PolygonBytes[NPolys_] := 
        VertexBytes[((3 NPolys)/VertexReuse)];

Assuming triangle polygons..

PolygonBytes[
        NPolys_] :=  (NPolys*
              BitsPerFace   +  (3 NPolys / VertexReuse)*
              BitsPerVertex )/8

Simplify[PolygonBytes[npol] ] /. ConversionConstants

Check with real model

Quick check, without compression. An SMF ASCII file of a cow takes 180kb for 2904 vertices and 5804 faces. 87kb is vertices, 92k is face-indices.This file has no texture and normal coordinates  estimation sould be larger than actual size. The actual vertexreuse factor in the cow is close to 6 (5804 triangles ~17412 corners / 2904 = 5.99

PolygonBytes[5804]  /.  {BitsPerFace -> 120,  
        BitsPerVertex -> 640, VertexReuse -> 6}

Check the composing parts

Connectivity estimation is exactly right (87k)

5804*BitsPerFace/8     /. {BitsPerFace -> 120,  
        BitsPerVertex -> 640, VertexReuse -> 6}

Vertex size is too large:

(3 5804 / VertexReuse)*BitsPerVertex /8    /. {BitsPerFace -> 120,  
        BitsPerVertex -> 640, VertexReuse -> 6}

Omitting per-vertex normal and uv coord, as is the case in our test file, saves 5 of the 8 values, so multiply by 3/8. Then the approximation is quite good (92k in our file):

3/8 (3 5804 / VertexReuse)*BitsPerVertex /8    /. {BitsPerFace -> 120,  
        BitsPerVertex -> 640, VertexReuse -> 6}

Combine texture and polygon sizes

The functions XXXsize[] defined below give the number of bytes required to reach target distortion, or INVALID if target distortion is not reachable anyway

<< "lifetime integr.nb"

Defines DandθAfterT[]

Simplified Polygon

PolygonSimpSize1[r_, d_, T_, DI_, TDI_, k_] := 
        Module[{d2, θ}, 
{d2, θ} = 
            DandθAfterT[d, r, T, ObsSpeed, 
              MinDistance]; 
If[
PolygonSimpErr[MaxPolygons, r, 
                d2, θ, k] <  DI, 
SizeOf[
              PolygonSimpN[r, d2, DI, θ, k], 
              RGB*TexSize[r, d, T, TDI, MinDistance, ObsSpeed], 
              JPEG], 
INVALID]
];

PolygonSimpSize[r_, d_, T_, DI_, TDI_, k_] := 
        PolygonSimpSize1[r, d, T, DI, TDI, k]  //.  
          ConversionConstants;

PolygonSimpSize[r_, d_, T_, DI_, TDI_, k_, options___] := 
        PolygonSimpSize1[r, d, T, DI, TDI, k]  //. 
          Flatten[Prepend[ConversionConstants, options]];

PolygonSimpSize[1, 5, 1, 0.01, 0.01, 30]

PolygonSimpSize[1, 1, 1, 0.001, 0.001, 30]

(3/500) ArcTan[(1/If)[0 > MinDistance, 1 - 1, MinDistance]]  /.  
      ConversionConstants

Vpt dependent simplified polygon

VptDepSimp's need full texture in order to be just as usable as normal simplified polygon objects.

VptDepSimpSize1[r_, d_, T_, DI_, TDI_, k_] := 
        Module[{d2, θ}, 
{d2, θ} = 
            DandθAfterT[d, r, T, ObsSpeed, 
              MinDistance]; 
If[
            VptDepSimpErr[MaxPolygons, r, d2, θ, k] < DI, 
            SizeOf[VptDepSimpN[r, d2, DI, θ, k], 
              RGB*TexSize[r, d, T, TDI, MinDistance, ObsSpeed], JPEG], 
            INVALID]
];

VptDepSimpSize[r_, d_, T_, DI_, TDI_, k_] := 
        VptDepSimpSize1[r, d, T, DI, TDI, k]  //.  
          ConversionConstants;

VptDepSimpSize[r_, d_, T_, DI_, TDI_, k_, options___] := 
        VptDepSimpSize1[r, d, T, DI, TDI, k]  //. 
          Flatten[Prepend[ConversionConstants, options]];

VptDepSimpSize[1, 5, 1, 0.01, 0.01, 30]

Incrementally coded polygon objs

We estimate this by taking the difference in size between the current position and the worst-case  reachable position after T.
Again, we assume textures are still required, and incremental transmission is assumed not very effective because of infrequent updates, so JPEG coding.
For the polygons we assume perfect incremental coding, so we use
 PolygonSimpN[r,d2,DI,θ,k] - PolygonSimpN[r,d,DI,θ,k]

IncrementalPolygonSize1[r_, d_, T_, DI_, TDI_, k_, options___] := 
        Module[{d2, θ}, 
{d2, θ} = 
            DandθAfterT[d, r, T, ObsSpeed, 
              MinDistance]; 
If[
PolygonSimpErr[MaxPolygons, r, 
                d2, θ, k] <  DI, 
SizeOf[
              PolygonSimpN[r, d2, DI, θ, k] - 
                PolygonSimpN[r, d, DI, θ, k], 
              RGB*TexSize[r, d, T, TDI, MinDistance, ObsSpeed], 
              JPEG], 
INVALID]
];

IncrementalPolygonSize[r_, d_, T_, DI_, TDI_, k_] := 
        IncrementalPolygonSize1[r, d, T, DI, TDI, k]  //.  
          ConversionConstants;

IncrementalPolygonSize[r_, d_, T_, DI_, TDI_, k_, options___] := 
        IncrementalPolygonSize1[r, d, T, DI, TDI, k]  //. 
          Flatten[Prepend[ConversionConstants, options]];

Simple imposters

Simple imposters are just single polygon, often refreshed with MPEG
Note that at close distances the texture would be both for front and back faces,
but imposters are not planned for near-distance use anyway.

SimpleImpSize1[r_, d_, T_, DI_, TDI_, k_] := 
        Module[{d2, θ}, 
{d2, θ} = 
            DandθAfterT[d, r, T, ObsSpeed, 
              MinDistance]; 
If [
            SimpleImposterErr[1, r, d2, θ, k] < 
              DI, 
SizeOf[1, 
              RGBA*TexSize[r, d, T,  TDI, MinDistance, ObsSpeed], 
              MPEG], 
INVALID
]
];

SimpleImpSize[r_, d_, T_, DI_, TDI_, k_] := 
        SimpleImpSize1[r, d, T, DI, TDI, k]  //.  
          ConversionConstants;

SimpleImpSize[r_, d_, T_, DI_, TDI_, k_, options___] := 
        SimpleImpSize1[r, d, T, DI, TDI, k]  //. 
          Flatten[Prepend[ConversionConstants, options]];

SimpleImpSize[1, 35, 1, 0.01, 0.01, 30]

Meshed imposters

Meshed imposters are to be refreshed quite often, so MPEG.

MeshedImpSize1[r_, d_, T_, DI_, TDI_, k_] := 
        Module[{d2, θ}, 
{d2, θ} = 
            DandθAfterT[d, r, T, ObsSpeed, 
              MinDistance]; 
If[
            0 < MeshedImposterErr[MaxPolygons, r, d2, θ, k] < 
              DI, 
SizeOf[
              MeshedImposterN[r, d2, DI, θ, k], 
              RGBA*TexSize[r, d, T, TDI, MinDistance, ObsSpeed], 
              MPEG], 
INVALID
]
];

MeshedImpSize[r_, d_, T_, DI_, TDI_, k_] := 
        MeshedImpSize1[r, d, T, DI, TDI, k]  //.  
          ConversionConstants;

MeshedImpSize[r_, d_, T_, DI_, TDI_, k_, options___] := 
        MeshedImpSize1[r, d, T, DI, TDI, k]  //. 
          Flatten[Prepend[ConversionConstants, options]];

MeshedImpSize[1, 35, 1, 0.01, 0.01, 30]

Image with depth

Image with depth is just 1 polygon, as a simple imposter, but it has RGBAD instead of RGBA.
Refresh quite often - no backside available! - therefore MPEG..

IwDSize1[r_, d_, T_, DI_, TDI_, k_] := 
        Module[{d2, θ}, 
{d2, θ} = 
            DandθAfterT[d, r, T, ObsSpeed, MinDistance];  
          If[IwDErr[MaxPolygons, r, d2, θ, k] < DI, 
            SizeOf[1, RGBAD*TexSize[r, d, T, TDI, MinDistance, ObsSpeed], 
              JPEG], INVALID
]
];

IwDSize[r_, d_, T_, DI_, TDI_, k_] := 
        IwDSize1[r, d, T, DI, TDI, k]  //.  
          ConversionConstants;

IwDSize[r_, d_, T_, DI_, TDI_, k_, options___] := 
        IwDSize1[r, d, T, DI, TDI, k]  //. 
          Flatten[Prepend[ConversionConstants, options]];

IwDSize[1, 35, 1, 0.01, 0.01, 30]

LDI

LDI has per viewing direction ("pixel") an extra byte holding amount of depth pixels in that direction.
Average LDI depth is 1.26  (literature) -> (1.26 + 1)TexSize[REF]
These pixels are RGBAD instead of RGBA
Currently I don't know about image compression possibilities. Assuming some JPEG-like ratio  is reachable.

ConversionConstants = 
      Join[ConversionConstants, {LDIDepth -> 1.24 }]

LDISize1[r_, d_, T_, DI_, TDI_, k_] := 
        Module[{d2, θ}, 
{d2, θ} = 
            DandθAfterT[d, r, T, ObsSpeed, MinDistance]; 
          If[LDIErr[MaxPolygons, r, d2, θ, k] < 
              DI, 
SizeOf[
              1, (1 + LDIDepth*RGBAD)*
                TexSize[r, d, T, TDI, MinDistance, ObsSpeed], JPEG],  
            INVALID]
];

LDISize[r_, d_, T_, DI_, TDI_, k_] := 
        LDISize1[r, d, T, DI, TDI, k]  //.  
          ConversionConstants;

LDISize[r_, d_, T_, DI_, TDI_, k_, options___] := 
        IwDSize1[r, d, T, DI, TDI, k]  //. 
          Flatten[Prepend[ConversionConstants, options]];

LDISize[1, 35, 1, 0.01, 0.01, 30]

Figures

byte size of simplified object, given object size and distance

Clear[n, r, d, θ, MaxPolygons, k, lifetime, 
        DI];
DI = 0.001;   
lifetime =  .1;   
neardist = -1;  fardist = 2; 
rmin = -1;  
    rmax = 1;   
k = 5;

SetOptions[Plot3D, 
        AxesLabel -> {"log object size", "log distance", "-Log \
size"}, ViewPoint -> {-1.661, -1.204, 0.947}, 
        PlotRange -> Automatic];

pa = 
        Plot3D[-Log[10, 
              PolygonSimpSize[(10^r), (10^d), lifetime, DI, DI, k]], {r, 
            rmin, rmax}, {d, neardist, fardist}];

pb = 
        Plot3D[-Log[10, 
              VptDepSimpSize[(10^r), (10^d), lifetime, DI, DI, k]], {r, rmin, 
            rmax}, {d, neardist, fardist}];

pi = 
        Plot3D[-Log[10, 
              SimpleImpSize[(10^r), (10^d), lifetime, DI, DI, k]], {r, rmin, 
            rmax}, {d, neardist, fardist}];

pc = 
        Plot3D[-Log[10, 
              MeshedImpSize[(10^r), (10^d), lifetime, DI, DI, k]], {r, rmin, 
            rmax}, {d, neardist, fardist}];

pd = 
        Plot3D[-Log[10, IwDSize[(10^r), (10^d), lifetime, DI, DI, k]], {r, 
            rmin, rmax}, {d, neardist, fardist}];

pe = 
        Plot3D[-Log[10, LDISize[(10^r), (10^d), lifetime, DI, DI, k]], {r, 
            rmin, rmax}, {d, neardist, fardist}];

pf = 
        Plot3D[-Log[10, 
              IncrementalPolygonSize[(10^r), (10^d), lifetime, DI, DI, 
                k]], {r, rmin, rmax}, {d, neardist, fardist}];

Show[Graphics3D[{
	PolygonColor,ConvertToMesh[pa],
	VptDepColor,ConvertToMesh[pb],
	SimpleImposterColor,ConvertToMesh[pi],
	MeshedImposterColor,ConvertToMesh[pc],
	IwDColor,ConvertToMesh[pd],
	LDIColor,ConvertToMesh[pe],
	IncrementalColor,ConvertToMesh[pf]

},
Lighting->False,AspectRatio->Automatic,
AxesLabel->{"log object size","log distance","-Log size"},
ViewPoint->{-2.456, -1.935, 1.294}
,PlotRange->{-2,-7},
Axes->True,BoxRatios->{1,1,.5}]]

byte size of simplified object, given lifetime and distance to object

Clear[n, r, d, θ, MaxPolygons, k, lifetime, 
        DI];
DI = 0.001;   
neardist = -1;  fardist = 2; 
tmin = -1;  
    tmax = 1;   
k = 5; r = 1;

SetOptions[Plot3D, 
        AxesLabel -> {"log lifetime(s)", "log distance", "-Log \
size"}, ViewPoint -> {-1.661, -1.204, 0.947}, 
        PlotRange -> All];

pa = 
        Plot3D[-Log[10, PolygonSimpSize[r, (10^d), (10^t), DI, DI, k]], {t, 
            tmin, tmax}, {d, neardist, fardist}];

pb = 
        Plot3D[-Log[10, VptDepSimpSize[r, (10^d), (10^t), DI, DI, k]], {t, 
            tmin, tmax}, {d, neardist, fardist}];

pi = 
        Plot3D[-Log[10, SimpleImpSize[r, (10^d), (10^t), DI, DI, k]], {t, 
            tmin, tmax}, {d, neardist, fardist}];

pc = 
        Plot3D[-Log[10, MeshedImpSize[r, (10^d), (10^t), DI, DI, k]], {t, 
            tmin, tmax}, {d, neardist, fardist}];

pd = 
        Plot3D[-Log[10, IwDSize[r, (10^d), (10^t), DI, DI, k]], {t, tmin, 
            tmax}, {d, neardist, fardist}];

pe = 
        Plot3D[-Log[10, LDISize[r, (10^d), (10^t), DI, DI, k]], {t, tmin, 
            tmax}, {d, neardist, fardist}];

pf = 
        Plot3D[-Log[10, 
              IncrementalPolygonSize[r, (10^d), (10^t), DI, DI, k]], {t, 
            tmin, tmax}, {d, neardist, fardist}];

Show[Graphics3D[{
	PolygonColor,ConvertToMesh[pa],
	VptDepColor,ConvertToMesh[pb],
	SimpleImposterColor,ConvertToMesh[pi],
	MeshedImposterColor,ConvertToMesh[pc],
	IwDColor,ConvertToMesh[pd],
	LDIColor,ConvertToMesh[pe],
	IncrementalColor,ConvertToMesh[pf]

},
Lighting->False,AspectRatio->Automatic,
AxesLabel->{"log lifetime(s)","log distance","-Log size"},ViewPoint->{-1.661,-1.204,
    0.947},
PlotRange->{-2,-9},
Axes->True,BoxRatios->{1,1,.5}]]

Incremental polygons do very well, so well that we cant see how the others behave.
    So lets turn it off and plot again.

Show[Graphics3D[{
	PolygonColor,ConvertToMesh[pa],
	VptDepColor,ConvertToMesh[pb],
	SimpleImposterColor,ConvertToMesh[pi],
	MeshedImposterColor,ConvertToMesh[pc],
	IwDColor,ConvertToMesh[pd],
	LDIColor,ConvertToMesh[pe]
},
Lighting->False,AspectRatio->Automatic,
AxesLabel->{"log lifetime(s)","log distance","-Log size"},ViewPoint->{-1.661,-1.204,
    0.947},
PlotRange->{-2,-9},
Axes->True,BoxRatios->{1,1,.5}]]