где бравый американский астронафт, ловко командует своим подчинённм турелькам голосом:
Не, ну на. В RPG режиме ты сидишь в командном центре, гоняя юнитов по карте и, при необходимости assuming direct control. Но если враги прорвались и your dungeon heart is under attack - теряешь всё управление базой, и отбиваешься от вторженцев от первого лица, в собственной хилой тушке. Или 
не такой хилой.
 ибо Z-buffer не нужен и всё решается порядком вывода спрайтов.
И тем не менее, запекалось в текстуру (при сбоях иногда появлялись чистые квадраты 256х256 пикселов).
Никакой z-buffer не имеет значения: запечёная текстура накладывается тем же проходом, у меша две развёртки и два набора текстурных координат.
Вы в курсе, что современная видеокарта практически обязана уметь читать из не менее 8 текстур одновременно? Из двух сразу умела ещё Voodoo2.
Но это - текстур. А уж выборок из них на пиксел можно делать хоть сорок - тут ограничение по нагрузке скорее насколько они далеко друг от друга.
В моём давишнем _test19 при увеличении QF врубается суперсемплинг. И сглаживание при выводе увеличенного рендербуфера на экран идёт за счёт N чтений из текстуры, вокруг заданной точки. Начинается с 5, расположенных крестом, но при росте разрешения они быстро выстраиваются концентрическими кольцами. 
См. мой угрёбищный хак, исходный код шейдера генерируется заново при изменении числа точек, а их координаты вшиваются в него как константы. И ведь работает, самка собаки. Моя Intel HD 3000 начинает дохнуть только точки с двадцатой. И это - на каждый пиксел!
- Код: Выделить всё
   procedure TMultisampleShader.GenerateShaderSource(var v, f: AnsiString);
  var
    sampler_code: AnsiString = '';
    hdr_mul: AnsiString;
    sampler_rx, sampler_ry, a, adelta, dx, dy, sr, srdelta: float;
    i, steps, step, ssum, perstep: integer;
    function csign(f: float): AnsiString;
    begin
      if f < 0 then Result:= '' else Result:= '+';
    end;
  begin
    //use default verter shader emulating ffp
    inherited GenerateShaderSource(v, f);
    hdr_mul:= '';
    if f_hdr > 1.0 then hdr_mul:=
      'vec4(' + FloatToStrF(f_hdr, ffExponent, 15, 1)
        + ','+ FloatToStrF(f_hdr, ffExponent, 15, 1)
        + ',' + FloatToStrF(f_hdr, ffExponent, 15, 1)
        + ',1.0) * ';
    steps:= 1 + ((f_samples - 1) div 8);
    ssum:= 1;
    for step:=1 to steps do begin
      perstep:= math.min(8, f_samples - ssum);
      adelta:= 3.1416 * 2 / perstep;
      a:= 3.1416 * 1.0; //0.75; //45 degrees
      sampler_rx:= 0.7 * ((1 + steps - step)/steps) * frw;
      sampler_ry:= 0.7 * ((1 + steps - step)/steps) * frh;
      for i:= 1 to perstep do begin
        dx:= sin(a) * sampler_rx;
        dy:= cos(a) * sampler_ry;
//addlog('step=%0, i=%1, a=%2, dx=%3, dy=%4, frw=%5, frh=%6',[step, i, a, dx, dy, frw, frh]);
        sampler_code+= 'sum += texture2D(u_texture, vec2(gl_TexCoord[0].x '
           + csign(dx) + ' ' + FloatToStrF(dx, ffExponent, 15, 1) + ', gl_TexCoord[0].y '
           + csign(dy) + ' ' + FloatToStrF(dy, ffExponent, 15, 1) + ')) * '
           + FloatToStrF(1 / f_samples, ffExponent, 15, 1) + '; ';
        a+= adelta;
      end;
      ssum+= perstep;
    end;
    //compose fragment shader
    f:=
       'uniform sampler2D u_texture;'
     + 'void main(void) {'
         + 'vec4 sum = vec4(0.0);'
         + 'sum += texture2D(u_texture, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y)) * '
         + FloatToStrF(1 / f_samples, ffExponent, 15, 1) + ';'
         + sampler_code
       //  + 'gl_FragColor = texture2D(u_texture, vec2(gl_TexCoord[0]));'
         + 'gl_FragColor = ' + hdr_mul + ' sum * gl_Color;'
     + '}';
  end; 
Добавлено спустя 9 минут 34 секунды:P.S. В итоге, меш ландшафта должен иметь три трёхкомпонентных и одну двухкомпонентный вектор текстурных координат на вершину. Трёхкомпонентные - для смешения до трёх базовых текстур на треугольник (s,t, индекс в атласе), а двухкомпонентный - развёртка персонализированной текстуры заляпов (которая тоже запихнута в какой-либо атлас, но её положение передаётся юниформами).