где бравый американский астронафт, ловко командует своим подчинённм турелькам голосом:
Не, ну на. В 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, индекс в атласе), а двухкомпонентный - развёртка персонализированной текстуры заляпов (которая тоже запихнута в какой-либо атлас, но её положение передаётся юниформами).