Главная > Программирование > Программирование графики > |
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 - Предыдущая - Следующая
Вернуться в раздел "Программирование графики" - Обсудить эту статью на Форуме |
Главная - Поиск по сайту - О проекте - Форум - Обратная связь |