2D Бампмэппинг ( Bumpmapping )

Previous  Top  Next

    
 

2D Бампмэппинг ( Bumpmapping )

 

Чтобы сделать правильный 2d бампмэппинг надо посчитать нормаль для каждого пиксела в bumpmap (карте высот) и для вычисления цвета каждого пиксела использовать угол между источником света и данной нормалью.

Для бампмэппинга в нашем случае используется источник света, бесконечно близкий к освещаемой плоскости: координаты нормали nx и ny просто разность высот между соседними пикселaми в bumpmap по осям X и Y.

Так как нормаль - просто вектор направления, и ее длина равна единице, то nz=1-sqrt(nx2 + ny2).

 
 

1. Заранее вычисляем интенсивность света (light map) по вышеприведенной формуле. (Световое пятно с максимальной интенсивностью в центре). Полагаем как обычно, что интенсивность зависит от n_z. Пусть размер таблички будет для удобства 256x256.

2. Подбирая из lightmap интенсивность по формуле: outvalue = lightmap[n_x+128][n_y+128] (если использовать нормали в диапазоне -128...+127) мы получим корректную картину освещения для бесконечно близкого источника.

 
n_x = bumpmap[x+1][y] - bumpmap[x-1][y]
n_y = bumpmap[x][y+1] - bumpmap[x][y-1]
 
Конечный цвет определяется так:
outvalue:=lightmap[(n_x-(lightx-currentx))][(n_y-(lighty-currenty))].
Также нужно проверить, находимся ли мы внутри диапазона lightmap.
 
Вот пример:
 

Code:

Program Bumpy_Surface;

 

{Hичего не USES}

 

type Tscr=array[0..199,0..319] of byte;

 

    SegmentT = Array[0..65534] of byte;

 

    Virseg = ^SegmentT;

 

var

 

scr:Tscr absolute $A000:0000;

 

buf:Tscr;

 

ilx,ily:integer;

 

i,j,k,nx,ny,nz,rx,ry,x,y,lx,ly,x1,y1:integer;

 

tx,ty,tz:real;

 

var segm,offs:integer;

 

Segment : Virseg;

 

litemap : word;

 

Procedure SetUpSegment(VAR segname:virseg;VAR add : word);

 

begin GetMem (Segname,65534); add := seg (Segname^); end;

 

Procedure wait; assembler;

 

asm mov dx,3DAh;

 

@l1:in al,dx;and al,08h;jnz @l1;

 

@l2:in al,dx;and al,08h;jz @l2;end;

 

Procedure SetMode (Mode:word);assembler; asm mov ax,Mode; int 10h end;

 

Procedure FillBox(x,y,w,h:integer; color:byte);

 

var i,j,k:integer;

 

begin for i:=y to y+h-1 do for j:=x to x+w-1 do buf[i,j]:=color; end;

 

Procedure Print(x,y:integer; s:string; xs,ys:integer; color:byte);

 

var i,j,k,c,px,py:integer; b:byte;

 

begin px:=x;py:=y; for k:=1 to length(s) do begin c:=ord(s[k]);

 

for i:=0 to 7

do begin b:=mem[segm:offs+c*8+i]; for j:=0 to 7 do begin

 

if b shl j and 128<>0

    then FillBox(x,y,xs,ys,color); x:=x+xs; end;

 

x:=px; y:=y+ys; end; y:=py; px:=px+xs*8; x:=px; end;

 

end;

 

Procedure SetGradientPalette; var k,r,g,b:byte;

 

begin asm mov  dx,03c8h; xor al,al;out dx,al;end;

 

r:=0; g:=0; for k:=0 to 255 do begin b:=(k*63 div 255);

 

{r:=b; g:=b;{} if k>200 then begin r:=r+1;g:=g+1;end;

 

asm mov dx,03c9h; mov al,r;out dx,al;

 

mov al,g;out dx,al; mov al,b;out dx,al end;

 

end;end;

 

Procedure Blur;

 

var i,j,k:integer;

 

begin for i:=0 to 199 do for j:=0 to 319 do

 

buf[i,j]:=(buf[i-1,j]+buf[i+1,j]+buf[i,j-1]+buf[i,j+1]) div 4;

 

end;

 

Procedure ASMBumpmapping;assembler;

 

asm

 

{few times faster ;) }

 

   mov ax, seg buf

 

   mov es,ax

 

   mov ax, offset buf

 

   mov bx,320*3

 

   add ax,bx

 

   mov di,ax

 

   mov si,bx

 

   mov dx,199

 

   sub dx,5

 

@1: mov cx,320

 

@2: xor bh,bh; xor ah,ah;

 

   mov al, es:[di+1]

 

   mov bl, es:[di-1]

 

   sub ax,bx

 

   sub ax,320; add ax,cx; add ax,lx; add ax,128;

 

   cmp ax,255; jc @ok1; mov ax,255; @ok1:

 

   push ax

 

   xor ah,ah;

 

   mov al, es:[di+320]

 

   mov bl, es:[di-320]

 

   sub ax,bx

 

   sub ax,197; add ax,dx; add ax,ly; add ax,128;

 

   cmp ax,255; jc @ok2; mov ax,255; @ok2:

 

   pop bx

 

   mov bh,bl; mov bl,al

 

   push es

 

   mov ax, litemap

 

   mov es,ax

 

   and bx,0FFFEh

 

   mov bx,[es:bx]

 

   mov ax, 0A000h

 

   mov es,ax

 

   mov [es:si],bx

 

   pop es

 

   inc di

 

   inc si

 

   loop @2

 

   dec dx;

 

   jnz @1

 

   mov ax,$0a000

 

   mov es,ax

 

   xor ax,ax

 

   mov [es:si-1],ax

 

end;{asm Bumpmaping}

 

Procedure Bumpmapping;

 

begin

 

{Bumpmapping}

 

for y:=0+3 to 199-3 do begin

 

for x:=0 to 319 do begin

 

nx:=buf[y+1,x]-buf[y-1,x];

 

ny:=buf[y,x+1]-buf[y,x-1];

 

nx:=nx-x+lx;

 

ny:=ny-y+ly;

 

nx:=nx+128;

 

ny:=ny+128;

 

if (nx<0) or (nx>255) then nx:=0;

 

if (ny<0) or (ny>255) then ny:=0;

 

scr[y,x]:=mem[litemap:nX+nY*256]; end;

 

end;{ Bumpmapping }

 

end;

 

BEGIN

 

{Достанем адрес знакогенератора}

 

asm

mov ax,$1130;

mov bh,03h;

int 10h;

mov segm,es;

mov offs,bp;

end;

 

{установим режим и палитру}

 

setmode($13); setgradientpalette;

 

{Cгенерируем световое пятно}

 

SetUpSegment(Segment,litemap);

 

for y:=0 to 255 do for x:=0 to 255 do begin

 

tX:=(x-128)/128.0;

 

tY:=(y-128)/128.0;

 

tZ:=1-sqrt(tX*tX+tY*tY);

 

if (tZ<0) then tZ:=0; mem[litemap:x+y*256]:=round(tz*254); end;

 

{ Очистим буфер }

 

fillchar(buf,64000,0);

 

{набросаем точек}

 

for i:=0 to 10000 do fillbox(random(320),random(200),1,1,255);

 

{...и размоем их}

 

blur;

 

{Hапишем текст}

 

print(60,65,'BUMPY',5,5,255);

 

print(47,115,'SURFACE',4,4,255);

 

{...и опять размоем}

 

blur;blur;blur;

 

ilx:=5;ily:=5;

 

ly:=100;lx:=80;

 

REPEAT

 

{move(buf,scr,64000);}

 

wait;

 

{Bumpmapping;}

 

ASMBumpmapping;

 

lx:=lx+ilx;if (lx>320) or (lx<0) then ilx:=-ilx;

 

ly:=ly+ily;if (ly>200) or (ly<0) then ily:=-ily;

 

UNTIL port[$60]=1;{ESC}

 

{сбросим буфер клавиатуры}

 

memw[$000:$041a]:=memw[$000:$041c];

 

setmode($3);

END.

 

 

 

http://algolist.manual.ru

©Drkb::04121