masterspammer (masterspammer) wrote,
masterspammer
masterspammer

(Пока ещё не одномерная) графика

 Жуки (см. ранее): пусть у нас есть поверхность (без внутренних полостей), высота в каждой точке которой известна z=f(x,y), или z[y][x] как это хранится внутри.

Рассмотрим, как осветить эту поверхность бесконечно удалённым источником света. Как известно (я не помню уже, откуда, но мне известно и эту формулу я примеряю уже не 10 лет), освещённость пропорциональна косинусу угла между вектором нормали и вектором направления на источник света - то есть если свет падает перпендикулярно, то векторы совпадают, угол равен нулю и освещённость максимальна.

(сейчас всё вычисляется для матовых поверхностей без учёта бликов - освещённость  блика же есть квадрат (думаю, что не только квадрат можно брать - зависит от материала) косинуса между вектором отражения и направлением на зрителя) 

в итоге у нас есть 3 вектора - (rx,ry,rz) - направление на источник света, (0,1,z[y+1,x]-z[y,x]) == (0,1,zy) и (1,0,z[y,x+1]-z[y,x]) == (1,0,zx), где zx и zy - перепады высот с соседними по x и y точками соответственно. Пусть вектор (rx,ry,rz) нормирован, найдём длины оставшихся: mx = 1+zx^2, my = 1+zy^2; тогда освещённость пропорциональна произведению 3х векторов (нормирование сделаю позже):

|rx, ry, rz|
|1,  0,  zx| = rz - rx*zx - ry*zy
|0,  1,  zy|


А после нормирования получим косинус равный (rz - rx*zx - ry*zy)/(mx*my); возьмём максимум значения косинуса и нуля (через песок свет не проходит и от того, что солнце светит снизу, толку нам немного, в отличии, например, от освещения плёнки или ткани) - получим освещённость от 0 до 1:

double find_cosinus(int zx,int zy){
    double dzx=zx/1.0,dzy=zy/1.0;
    double mx=sqrt(1+dzx*dzx);
    double my=sqrt(1+dzy*dzy);
    double r=rz-rx*dzx-ry*dzy;
    r/=mx*my;
    return r>0?(r>1?1:r):0;
}


Так как rx,ry и rz неизменны для каждого кадра (а по факту - не для одного, так как светило движется достаточно медленно), то имеет смысл оформить зависимость яркости от zx и zy как массив и вычислять его только когда светило изменяет свое положение на небосклоне:

static unsigned short int cosinuses[32][32];

void sh_init_cosinuses(){
    int i,j;
    for(j=0;j<32;j++){
        for(i=0;i<32;i++){
            cosinuses[j][i]=find_cosinus(i-16,j-16)*256;
        }
    }
}


(слишком большие перепады высот обрезаем)

И далее просто использовать результат, например так:

unsigned short int cosinus(int zx,int zy){
    return cosinuses[zy<-16?0:(zy>15?31:zy+16)][zx<-16?0:(zx>15?31:zx+16)];
}


...или так:

#define cosinus(zx,zy) cosinuses[zy<-16?0:(zy>15?31:zy+16)][zx<-16?0:(zx>15?31:zx+16)]

в зависимости от компилятора и чувства прекрасного.
Tags: xbugs
Subscribe

  • (no subject)

    Дети притащили из школы ротовирус - так-то это довольно регулярная болячка, хотя штаммами разнится как грипп - на этот раз досталось сыну и чуть…

  • Заскочил, значит, за проводочками...

    Хотел в гости зайти к знакомому дедушке/дядюшке, звоню, а он умер сегодня... P.S. Да, именно covid...

  • Стратегическая двуручная харкалка

    Харкалки в школьные годы не то, чтоб совсем мимо меня прошли, но всё же я был больше по брызгалкам. На втором месте были резинки и рогатки (в…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 6 comments