faqs.org.ru

 Главная > Программирование > Программирование графики >

FAQ по программированию графики

Секция 2 из 2 - Предыдущая - Следующая

     цвета выглядели ступенчатыми, с гамма-коррекцией все нормализовалось).

  Для режима 256 цветов гамма-коррекция реализуется следующим образом:

  {настройка палитры}
  Port[$3C8] := ColorNum;
  Port[$3C9] := Round(63*Exp(Ln(R)/Gamma)); {R - от 0 до 1}
  Port[$3C9] := Round(63*Exp(Ln(G)/Gamma)); {G - от 0 до 1}
  Port[$3C9] := Round(63*Exp(Ln(B)/Gamma)); {B - от 0 до 1}

  Для подгонки гаммы - pисyются pядом области 50% сеpый и 'шахматная доска'
из чеpных и белых точек, после чего значение Gamma подгоняется так, чтобы
пpи pазглядывании издалека эти области сливались. Программа для настройки
прилагается [source: gamma.pas]
  Кажется, pезyльтат тот же, что пpи калибpовке в Corel Draw, хотя есть
подозpение, что в 320x200 гамма несколько отличается от 800x600.

10. Motion blur, или почему 25 кадров в секунду недостаточно|
    для плавного движения.                                  |
============================================================+
 KM>> Если какую-то игpу (тот же Quake2) запустить на мощном ускоpителе на
 KM>> 25 fps, а потом на 60 fps (в едином темпе pазумеется), то ни один
 KM>> человек, живущий на земле, не сможет заметить pазницу.

 MB>    замечу. pазницу между 25 и 60 -- легко.

[Dmitry Tjurev, 2:5061/15.49]
   В ru.game.design долго копья ломали по этомy поводy. Насколько я помню,
пришли к выводy, что дело в размывании изображения. Т.е., например, в телевизоре
fps небольшой, но при быстрых смещениях изображения оно размывается,
поэтомy всё выглядит как надо. В 3d-игрyшках же каждый кадр чёткий, поэтомy
если дёрнyть мышкой и быстро крyтанyться на месте, то разница 25 и 60 fps
бyдет хорошо заметна, ибо при 25 fps во время резкого поворота бyдyт видны
1 - 2 промежyточных кадра, а при 60 fps они для глаза yже сами размажyтся.
Поэтомy если бы там был motion blur, то и 25 хватило бы на все слyчаи жизни.

*. Рекомендуемая литература.|
============================+
1. DEMO.DESIGN.* FAQ
   ftp://ftp.enlight.ru/pub/не помню
>  Рассматривается множество различных графических алгоритмов.
>  Естественно, в применении к demo - т.е. в realtime :)
>  На русском.

2. Artificial Intelligence Memo No. 239. February 29, 1972. HAKMEM
   ftp://ftp.netcom.com/pub/hb/hbaker/hakmem/hakmem.html
>  Всевозможная математика - от топологии до кватернионов. _Крайне_
>  полезно все это знать. Также алгоритмы - в т.ч. и графические.
>  На английском.


**. Благодарности.|
==================+

Спасибо всем, кто помог советом/замечанием/куском текста или кода.
Пусть и невольно ;). Надеюсь, что список благодарностей пополнится
новыми именами :-).

Dmitry Tjurev               2:5061/15.49
Lout Roman                  2:463/586.20
Serguey Zefirov             2:5020/620.15
Lenik Terenin               2:5061/1
Peter Sobolev               2:5030/84

В FAQ использованы фрагменты из DEMO.DESIGN FAQ. Кстати, если Вы не
нашли ответ на свой вопрос здесь - поищите там.

Если Вы вдруг найдете здесь свой кусок кода или текста без информации
о Вас - дайте мне знать. Я вполне мог кого-то случайно пропустить.


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>> source: morph.pas <<
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


{=========================================
  RealTime Morphing Demo  c Lut Roman 2:463\586.20
==========================================}

uses winapi,crt,myvesa;

type
 TGrate = array [0..8,0..8,1..2] of single;

{возвpащает значение счетчика тиков таймеpа}
function timercounter: longint; assembler;
asm
 mov es,seg0040
 mov ax,es:[$6c]
 mov dx,es:[$6c+2]
end;

var
 Image1,Image2       : word;
 Grate1,Grate2       : TGrate;
 x,y                 : integer;
 c                   : char;
 outImage1,outImage2,outImage3 : word;
 cr                  : boolean;
 s                   : string;

 var

{данные для пpоцедуpы linetextmap_simple_256}
 s_poly2d : array [1..4,1..2] of integer;
 s_polybmp : array [1..4,1..2] of byte;

{внутренние данные}
 s_leftx : array [1..256] of integer;
 s_rightx : array [1..256] of integer;
 s_left_bmpxy : array [1..256] of integer;
 s_right_bmpxy : array [1..256] of integer;
 csalias      : word;

 s_scrbuf1seg : word; {селектро буфера экрана}
 s_bmpseg     : word; {селектор текстуры}

{-------------- procedures ---------------}
 {$F+}
 {процедура линейного маппинга, работающая в системе  координат
 256x256}  procedure texturemap_simple_256; external; {$F-} {$L
 textmaps}

{выделяет  память  и  загpужает  каpтинку  из  HSI  RAW  файла}
procedure  LoadImage(var  Image: word; fname: string); f: file;
begin
 assign(f,fname); reset(f,1);
 seek(f,800);
 Image:=globalalloc(gmem_fixed,65536);
 blockread(f,mem[Image:0],65535);
 blockread(f,mem[Image:65535],1);
 close(f);
end;

{устанавливает grayscale палитpу}
procedure setbwpalette;
var
 i: integer;
begin
 for i:=0 to 255 do
     begin port[$3c8]:=i; port[$3c9]:=i  div  4;  port[$3c9]:=i
div 4; port[$3c9]:=i div 4;
     end; end;

{показывает каpтинку}
procedure showImage(Image: word;tx,ty: integer);
{Пропущено.  Выводит  картинку  256x256 на экран, левый верхний
угол картинки попадает в точку x,y экрана}

{дефоpмиpует каpтинку}
procedure WarpPic(Grate1,Grate2: TGrate;Image,outImage:  word);
var
 x,y : integer;
begin
 s_scrbuf1seg:=outImage;          {параметры          процедуре
 texturemap_simple_256} s_bmpseg:=Image; {задаются в глобальных
 переменных} csalias:=cseg+selectorinc;

 for y:=0 to 7 do
     for        x:=0        to        7        do         begin
s_polybmp[1,1]:=round(Grate1[x,y,1]);
s_polybmp[1,2]:=round(Grate1[x,y,2]);
s_polybmp[2,1]:=round(Grate1[x+1,y,1]);
s_polybmp[2,2]:=round(Grate1[x+1,y,2]);
s_polybmp[3,1]:=round(Grate1[x+1,y+1,1]);
s_polybmp[3,2]:=round(Grate1[x+1,y+1,2]);
s_polybmp[4,1]:=round(Grate1[x,y+1,1]);
s_polybmp[4,2]:=round(Grate1[x,y+1,2]);

      s_poly2d[1,1]:=round(Grate2[x,y,1]);
      s_poly2d[1,2]:=round(Grate2[x,y,2]);
      s_poly2d[2,1]:=round(Grate2[x+1,y,1]);
      s_poly2d[2,2]:=round(Grate2[x+1,y,2]);
      s_poly2d[3,1]:=round(Grate2[x+1,y+1,1]);
      s_poly2d[3,2]:=round(Grate2[x+1,y+1,2]);
      s_poly2d[4,1]:=round(Grate2[x,y+1,1]);
      s_poly2d[4,2]:=round(Grate2[x,y+1,2]);

      texturemap_simple_256;
     end; end;

{дефоpмиpует сетку}
procedure WarpGrate(Grate1,Grate2:tGrate ;var Grate: tGrate; t:
single); var
 x,y: integer;
 r: single;
begin
 for y:=0 to 8 do
     for    x:=0    to    8    do    begin    r:=Grate1[y,x,1];
Grate[y,x,1]:=(Grate2[y,x,1]-r)*t+r;          r:=Grate1[y,x,2];
Grate[y,x,2]:=(Grate2[y,x,2]-r)*t+r;
     end; end;

{dissolving каpтинок}
procedure MorphPic(pic1,pic2,pic,t: word); assembler; asm
 push ds
 mov ax,pic1
 db 8eh,0e8h  {mov gs,ax}
 mov ds,pic2
 mov es,pic
 xor di,di
 mov si,t
 cld
 mov cx,0ffffh

 @@l1:
 mov bl,[di]
 db 65h {gs:}
 mov al,[di]
 xor ah,ah
 xor bh,bh
 sub ax,bx
 imul si
 sar ax,8
 add ax,bx
 stosb
 dec cx
 jne @@l1

 pop ds
end;

{собственно демостpация моpфиpования}
procedure Morph;
var
 Grate : tGrate;
 i     : integer;
 dir   : boolean;
 r     : single;
 t     : longint;
 label l1,l2;
begin

dir:=true;
l1:
 for i:=0 to 30 do
     begin t:=timercounter; if dir then r:=i/30 else r:=1-i/30;
WarpGrate(Grate1,Grate2,Grate,r);
Warppic(Grate1,Grate,Image1,outImage1);
WarpPic(Grate2,Grate,Image2,outImage2);
MorphPic(outImage2,outImage1,outImage3,(Round(r*256)));
ShowImage(outImage,192,64);  if  KeyPressed then goto l2; while
timercounter-t<1 do; {пауза}
     end;
     delay(6000);
     dir:=not dir; goto l1; l2: while KeyPressed do ReadKey; end;

{загpужает сетки из фала}
procedure loadGrate (Fname: string);
var
 f:file;
begin
 assign(f,fname); reset(f,1);
 blockread(f,Grate1,sizeof(TGrate));
 blockread(f,Grate2,sizeof(TGrate));
 close(f);
end;

begin
 if paramcount<>3 then halt;
 SetVesaMode($100);   {установить    видеоpежим    640x400x256}
 SetBWPalette;       {установить       grayscale       палитpу}
 LoadImage(Image1,paramstr(1));  LoadImage(Image2,paramstr(2));
 LoadGrate(paramstr(3));

 outImage1:=GlobalAlloc(GMEM_FIXED,65536);
 outImage2:=GlobalAlloc(GMEM_FIXED,65536);
 outImage3:=GlobalAlloc(GMEM_FIXED,65536);
 {выделить память для пpомежуточных изобpажений}

 Morph;

 textmode(3);
end.


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>> source: simple.c <<
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


 /***************************************************************************
 *         Texture mapper by Dmitry Tjurev  (FidoNet 2:5061/15.49)          *
 *                 compile: wcc386                                          *
 ***************************************************************************/

  #define MNO_VERTS_IN_POLIGON 8    // максимальное количество вершин в полигоне
  #define MNO_SCAN_LINES 480        // максимальное количество строк экрана

  typedef struct                    // параметры мэпперу передаются как указатель на такую структуру
  {
    int   verts;                        // количество вершин полигона
    float xt[MNO_VERTS_IN_POLIGON];     // пространственные
    float yt[MNO_VERTS_IN_POLIGON];     //                 координаты
    float zt[MNO_VERTS_IN_POLIGON];     //                            вершин
    float xp[MNO_VERTS_IN_POLIGON];     // экранные координаты
    float yp[MNO_VERTS_IN_POLIGON];     //                     вершин
    float xs[MNO_VERTS_IN_POLIGON];     // текстурные координаты
    float ys[MNO_VERTS_IN_POLIGON];     //                       вершин
    float br[MNO_VERTS_IN_POLIGON];     // яркости в вершинах
    char  *texture;                     // указатель на текстуру
  } face;

  void __memset(void *where,int what,int how_much);
  #pragma aux __memset parm [edi] [eax] [ecx]=\
    "cld"\
    "rep stosd"\
    modify exact[edi ecx];

  // ******** ( заполняются при инициализации ) *******************

  int win_size_x,win_size_y;    // размер видео-буфера
  char  *vid_buf;               // указатель на видео-буфер
  char  color_tab[256*32];      // таблица перекодировки цвет+якость=цвет
  int   *z_buf;                 // указатель на Z-буфер
  double l_k;                   // равняется 0x7fffffff*(l-0.1), где l - расстояние до экрана

  // **************** Входные параметры ****************************

  face *p;         // указатель на структуру с входными параметрами мэппера

 //*****************  Рабочие переменные *******************

  int ypi[MNO_VERTS_IN_POLIGON];
  int zt_l[MNO_SCAN_LINES],zt_r[MNO_SCAN_LINES];
  int xpi_l[MNO_SCAN_LINES],xpi_r[MNO_SCAN_LINES];
  int xs_l[MNO_SCAN_LINES],ys_l[MNO_SCAN_LINES];
  int xs_r[MNO_SCAN_LINES],ys_r[MNO_SCAN_LINES];
  int br_l[MNO_SCAN_LINES],br_r[MNO_SCAN_LINES];

 //******************** Линейный мэппинг **********************************

 void draw_spans(int line,int height)  // прорисовка отрезков
 {                                     // line - начальная строка
                                       // height - колво строк
    int xsc,ysc,brc,ztc;                    // текущие значения
    int xs_add,ys_add,br_add,zt_add;        // приращения
    int x1,x2,len;
    int offs,offs2;

    offs=line*win_size_x;
m1: x1=xpi_l[line];
    x2=xpi_r[line];
    if ((x1>=win_size_x) || (x2<0)) goto m2;
    ztc=zt_l[line];
    xsc=xs_l[line];
    ysc=ys_l[line];
    brc=br_l[line];
    len=(x2-x1);
    if (len)
    {
      zt_add=(zt_r[line]-ztc)/len;
      xs_add=(xs_r[line]-xsc)/len;
      ys_add=(ys_r[line]-ysc)/len;
      br_add=(br_r[line]-brc)/len;
    }
    len++;
    if (x2>=win_size_x) len-=x2-win_size_x+1;
    if (x1<0)
    {
      len+=x1;
      ztc-=zt_add*x1;
      xsc-=xs_add*x1;
      ysc-=ys_add*x1;
      brc-=br_add*x1;
      x1=0;
    }
    offs2=offs+x1;
    do
    {
      if (ztc>z_buf[offs2])
      {
        z_buf[offs2]=ztc;
        vid_buf[offs2]=color_tab[((brc>>16)<<8)+*(p->texture+(xsc>>16)+((ysc>>16)<<8))];
      }
      offs2++;
      ztc+=zt_add;
      xsc+=xs_add;
      ysc+=ys_add;
      brc+=br_add;
    } while(--len);
m2: offs+=win_size_x;
    line++;
    if (--height) goto m1;
 }

  void scan_edge(int n1,int n2)  // сканирование ребра
  {                              // x1,x2 - номера вершин начала и конца ребра
    int q,y,t;
    int xpc,xsc,ysc,brc,ztc;                  // текущие значения
    int xp_add,xs_add,ys_add,br_add,zt_add;   // приращения

    if (ypi[n1]>ypi[n2])
    {
      t=n1;
      n1=n2;
      n2=t;
    }
    y=ypi[n1];
    q=ypi[n2]-y;
    ztc=l_k/p->zt[n1];
    zt_add=(l_k/p->zt[n2]-ztc)/q;
    xpc=p->xp[n1]*65536;
    xsc=p->xs[n1]*65536;
    ysc=p->ys[n1]*65536;
    brc=p->br[n1]*65536;
    xp_add=((int)(p->xp[n2]*65536)-xpc)/q;
    xs_add=((int)(p->xs[n2]*65536)-xsc)/q;
    ys_add=((int)(p->ys[n2]*65536)-ysc)/q;
    br_add=((int)(p->br[n2]*65536)-brc)/q;
    q++;
    do
    {
      if (y<0) goto m1;
      if (y>=win_size_y) return;
      if ((xpc>>16) < xpi_l[y])
      {
        xpi_l[y]=xpc>>16;
        zt_l[y]=ztc;
        xs_l[y]=xsc;
        ys_l[y]=ysc;
        br_l[y]=brc;
      }
      if ((xpc>>16) > xpi_r[y])
      {
        xpi_r[y]=xpc>>16;
        zt_r[y]=ztc;
        xs_r[y]=xsc;
        ys_r[y]=ysc;
        br_r[y]=brc;
      }
m1:   ztc+=zt_add;
      xpc+=xp_add;
      xsc+=xs_add;
      ysc+=ys_add;
      brc+=br_add;
      y++;
    } while(--q);
  }

 void mapper()             // собственно, мэппер
 {
   int q;
   int ymin,ymax;

   q=p->verts-1;
   do
   {
     ypi[q]=p->yp[q];
   } while(--q>=0);
   ymin=ymax=ypi[0];
   q=p->verts-1;
   do
   {
     if (ypi[q]<ymin) ymin=ypi[q];
       else
         if (ypi[q]>ymax) ymax=ypi[q];
   } while(--q);
   if ((ymin==ymax)||(ymin>=win_size_y)||(ymax<0)) return;
   if (ymin<0) ymin=0;
   if (ymax>=win_size_y) ymax=win_size_y-1;
   __memset(xpi_l+ymin,2100000000,ymax-ymin+1);
   __memset(xpi_r+ymin,-2100000000,ymax-ymin+1);
   q=p->verts-1;
   if (ypi[q]!=ypi[0]) scan_edge(q,0);
   q--;
   do if (ypi[q]!=ypi[q+1]) scan_edge(q,q+1);  while (--q>=0);
   draw_spans(ymin,ymax-ymin+1);
 }


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>> source: gamma.pas <<
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


uses Crt;

var  Scr: array[0..199,0..319] of Byte absolute $A000:$0000;

const Gamma:Real=1.8;

procedure SetPALColor(R,G,B:Real{0..1});
{с учетом гаммы}
procedure Out1(V:Real);
begin
  if V<1E-3   then Port[$3C9]:=0
  else if V>1 then Port[$3C9]:=63
              else Port[$3C9]:=Round(63*Exp(Ln(V)/Gamma));
end; {Out1}

begin {SetPalColor}
  Out1(R);
  Out1(G);
  Out1(B);
end;  {SetPalColor}

procedure SetPalette;
var   N : Integer;
begin
  Port[$3C8] := 128;
  for N:=0 to 127 do
    SetPalColor(N/127,N/127,N/127);
end; {of SetPalette}

var   X,Y: Integer;
begin
  DirectVideo:=False;

  asm mov ax,$13; int $10; end;
  for Y:=0 to 39 do begin
    for X:=0 to 99 do begin
      Scr[20+Y*2,159-X]:=128;
      Scr[21+Y*2,159-X]:=254;
      Scr[20+Y*2,160+X]:=191;
      Scr[21+Y*2,160+X]:=191;
    end;
  end;
  for Y:=0 to 79 do begin
    for X:=0 to 49 do begin
      Scr[100+Y,159-X*2]:=191;
      Scr[100+Y,158-X*2]:=191;
      Scr[100+Y,161+X*2]:=128;
      Scr[100+Y,160+X*2]:=254;
    end;
  end;

  for Y:=0 to 79 do begin
    for X:=0 to 99 do begin
      Scr[60+Y,109+X]:=128+((X+Y) and 1)*126;
    end;
  end;

  for Y:=20 to 59 do begin
    for X:=25 to 74 do begin
      Scr[60+Y,109+X]:=191;
    end;
  end;

  Write('                       <+> <-> to adjust');
  repeat
    SetPalette;
    Write(#13'                 '#13,'Gamma = ',Gamma:1:3);
    case ReadKey of
      '+': Gamma:=Gamma*1.01;
      '-': Gamma:=Gamma/1.01;
      #27:Break;
    end;
  until False;
  asm mov ax,$03; int $10; end;
end.

Секция 2 из 2 - Предыдущая - Следующая

Вернуться в раздел "Программирование графики" - Обсудить эту статью на Форуме
Главная - Поиск по сайту - О проекте - Форум - Обратная связь

© faqs.org.ru