Реализация метода освещение по Фонгу Метод освещения по Фонгу сводит освещение к текстурированию по определенной текстуре. Для данного метода необходима константа, точечный источник, удаленный бесконечно далеко. В общем случае интенсивность освещения находится по формуле: intensity = ambient + amp * (N * L), где N - нормаль, L - непосредственный источник освещения Когда вектор L = (0,0,1). Общий случай сводится к упрощенному: intensity = ambient + amp * (N.x * L.x + N.y * L.y + N.z * L.z) = То есть интенсивность выражается через N.x, N.y, а эти величины меняются линейно. N.x и N.y - числа с плавающей запятой от -1 до 1 (т.к. длина вектора равна 1), интерполировать их - занятие медленное, да корень считать раз в пиксел тоже не хочется. Поэтому вместо интерполяции N.x и N.y обычно интерполируют, например, 128*(N.x+1) и 128*(N.y+1), причем уже в целых числах. Тогда все возможные значения таким образом отмасштабировнных N.x, N.y - это 0, 1, ..., 255. Поэтому можно заранее посчитать табличку значений intensity для каждой пары отмасштабировнных N.x, N.y. Линейно интерполируем 128*(N.x+1) и 128*(N.y+1) и по ним по таблице определяем интенсивность. Это и есть текстурирование, только в качестве текстуры используется таблица освещенности размером 256x256, а в качестве координат текстуры u, v для каждой вершины берутся отмасшатбированные координаты нормали в этой вершине. uses crt; const palwhite = 20; {Количество белых цветов} var phongmap : pointer; x,y : integer; c,i : byte; procedure setpal(c,r,g,b : byte);assembler; asm mov dx,3C8h;mov al,c;out dx,al;inc dx;mov al,r;out dx,al;mov al,g out dx,al;mov al,b;out dx,al;end; procedure makepal(objr,objg,objb : byte); begin {black to object color} for i := 0 to 127-palwhite do setpal(i,(objr*i) div (127-palwhite),(objg*i) div (127-palwhite), (objb*i) div (127-palwhite)); {object color to white} for i := 0 to palwhite do setpal(i+127-palwhite,objr+((63-objr)*i) div palwhite, objg+((63-objg)*i) div palwhite,objb+((63-objb)*i) div palwhite); end; function length(x1,y1,x2,y2 : longint) : word; begin length := round(sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))); end; begin getmem(phongmap,65535); for y := 0 to 127 do for x := 0 to 127 do begin c := length(x,y,128,128); {Задается длина} if c > 127 then c := 127; c := 127-c; {Реверс цвета, поэтому в центре н еполучается чёрный} mem[seg(phongmap^):y shl 8+x] := c; mem[seg(phongmap^):(255-y) shl 8+x] := c; mem[seg(phongmap^):y shl 8+(255-x)] := c; mem[seg(phongmap^):(255-y) shl 8+(255-x)] := c; end; asm mov ax,13h int 10h end; makepal(32,16,63); {Бирюзовый объект} {Прорисовка phongmap (в масштабе 1:2)} for y := 0 to 127 do for x := 0 to 127 do mem[$A000:x+y shl 8+y shl 6] := mem[seg(phongmap^):x shl 1+y shl 9]; repeat until keypressed; asm mov ax,3h int 10h end; end. {вычисление нормалей} const maxp = 900; {макс т.} maxpl = 900; var points : array[0..maxp,0..2] of integer; planes : array[0..maxpl,0..2] of word; pnormals : array[0..maxpl,0..2] of integer; {Нормали плоскости} normals : array[0..maxp,0..2] of integer; {Угловые нормали} maxpoint,maxpoint : word; {Фактическое число точек} i,a,n : word; rx1,ry1,rz1,rx2,ry2,rz2 : integer; rx,ry,rz,l : real; begin readobject; for i := 0 to maxplane do begin rx1 := points[planes[i,1],0]-points[planes[i,0],0]; ry1 := points[planes[i,1],1]-points[planes[i,0],1]; rz1 := points[planes[i,1],2]-points[planes[i,0],2]; rx2 := points[planes[i,2],0]-points[planes[i,0],0]; ry2 := points[planes[i,2],1]-points[planes[i,0],1]; rz2 := points[planes[i,2],2]-points[planes[i,0],2]; {Вычисление плоских нормалей} pnormals[i,0] := ry1*rz2-ry2*rz1;pnormals[i,1] := rz1*rx2-rz2*rx1; pnormals[i,2] := rx1*ry2-rx2*ry1; end; for i := 0 to maxpoint do begin {Reset all variabels} rx := 0;ry := 0;rz := 0;n := 0; for a := 0 to maxplane do {Check if point is in plane} if (planes[a,0] = i) or (planes[a,1] = i) or (planes[a,2] = i) then begin {К нормали плоскости прибавляется нормаль угла и края} rx := rx+pnormals[a,0];ry := ry+pnormals[a,1];rz := rz+pnormals[a,2]; {Increase numbers of planes} inc(n); end; if n > 0 then begin {n строго больше 0, иначе точка н еиспользуется} rx := rx/n;ry := ry/n;rz := rz/n; {Расчет средней нормали плоскости} l := sqrt(rx*rx+ry*ry+rz*rz); {Расчет длины нормали} if l = 0 then l := 1; {Для избежания деления на 0} {шкала нормалей} normals[i,0] := round(rx/l*120); normals[i,1] := round(ry/l*120); normals[i,2] := round(rz/l*120); end; end; end. begin { высчитывает phongmap, переходит в графический режим } repeat [Вращает точки и нормали, преобразовывает в 2d и сортирует] for i := 0 to maxplane do texture( {X и Y координаты для первого угла:} 160+newp[planes[pind[i],0],0],100+newp[planes[pind[i],0],1], {U и V координаты для первого угла} 128+newn[planes[pind[i],0],0],128+newn[planes[pind[i],0],1], {X и Y координаты для второго угла: и так далее} 160+newp[planes[pind[i],1],0],100+newp[planes[pind[i],1],1], 128+newn[planes[pind[i],1],0],128+newn[planes[pind[i],1],1], 160+newp[planes[pind[i],2],0],100+newp[planes[pind[i],2],1], 128+newn[planes[pind[i],2],0],128+newn[planes[pind[i],2],1]); {Восстанавливает в памяти, отображает картинку, очищает виртуальный экран} until keypressed; end;
Ключевые слова:
Освещение, интенсивность, диффузное, зеркальное, равномерное
|
|||||||