Ничего не нашел лучше, чем посчитать карту теней статически, а потом загружать её вместе с уровнем.
Подсчет производить будем "в лоб": для каждого источника с координатами (x0, y0, z0) и для каждой точки на карте (x1, y1, z1) напишем уравнение луча, соединяющего их. Для координаты x:

Для остальных координат уравнение аналогичное. Теперь, двигаясь по лучу от источника освещения к точке на карте (в цикле по t от 0 до 1) делаем проверку
if (map[y][x]>z) установить_тень(x1,y1);
То есть, если на пути света стоит "гора" достаточной высоты, чтобы затмить свет, в точке, куда шел луч тень. Пока прикладываю программу по просчету теней и мира, так как чтобы это грамотно прорисовать нужно научится правильному смешению цветов и фильтрации. Об этом позже. Вот программа:
Открыть спойлер
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void filldata (int *hei)
{
int p = 0;
int x,y;
for (y=0; y<=63; y++)
{
for (x=0; x<=63; x++)
{
double x1 = x-32;
double y1 = y-32;
hei[p] = 60*sin(sqrt(x1*x1+y1*y1))/(1+sqrt(x1*x1+y1*y1));
p++;
}
}
}
void printmap (FILE *out, int *map)
{
int x,y;
for (y=0; y<=63; y++)
{
for (x=0; x<=63; x++)
{
fprintf (out, "%i %i %i\n", x, y, map[y*64+x]); // Код для gnuplot
// fprintf (out, "%i ", map[y*64+x]); // Код для программы
}
}
}
void fill_shadows (int *shadows, int *map, int x0, int y0, int z0)
{
float t;
float dt = 1.0/340;
int x1,y1,z1;
for (y1=0; y1<64; y1++)
{
for (x1=0; x1<64; x1++)
{
int idx1 = 64*y1+x1;
z1 = map[idx1];
for (t=0; t<1.0; t+=dt)
{
float x,y,z;
x = x0 + (x1-x0)*t;
y = y0 + (y1-y0)*t;
z = z0 + (z1-z0)*t;
int idx = 64*y+x;
if (map[idx]>z) {shadows[idx1] = 1; break;}
}
}
}
}
int main()
{
int hei[4096-1];
int shadows[4096-1];
filldata (hei);
memset (shadows, 0, sizeof(int));
// Print heightmap
FILE *out = fopen ("testhei.dat", "w");
printmap (out, hei);
fclose (out);
fill_shadows (shadows, hei, 32, 32, 500);
out = fopen ("testshadows.dat", "w");
printmap (out, shadows);
fclose (out);
return 0;
}
Комментариев нет:
Отправить комментарий