§ Краткое описание программы

Я сделал вращение Земли, используя программу на Quick Basic 4.5.
record.gif
Программа довольно большая и состоит из следующих процедур:
  • rnd — генерация "случайного" значения по (x,y) координате
  • noise — создание интерполяционного по целочисленным значениям (x,y) и размытие между по дробным
  • fbm — многоуровневый фрактальный шум
  • normalize — просто нормализация вектора
  • sphere — определение точки пересечения со сферой
  • custompal — задание пользовательской палитры

§ Программный код

1#include <qb.h>
2
3float rot = 0;
4
5// -----------------------------------------------------------------------------
6
7// Псевдослучайный шум
8double rnd(double x, double y) {
9
10    double m = sin(x * 12.9898 + y * 78.233) * 43758.54531229988;
11    return m - floor(m);
12}
13
14// Просто шум в точке
15double noise(float x, float y) {
16
17    double ix = floor(x);
18    double iy = floor(y);
19    double fx = x - ix;
20    double fy = y - iy;
21
22    double a = rnd(ix,      iy);
23    double b = rnd(ix + 1., iy);
24    double c = rnd(ix,      iy + 1.);
25    double d = rnd(ix + 1., iy + 1.);
26
27    double ux = fx * fx * (3 - 2 * fx);
28    double uy = fy * fy * (3 - 2 * fy);
29
30    // a b Интерполяция по 4-м точкам
31    // c d Используя fx, fy в качестве позиции fx,fy=[0,1]
32    return a * (1 - ux) +
33           b * ux +
34           (c - a) * uy * (1 - ux) +
35           (d - b) * ux * uy;
36}
37
38// Фрактальный шум
39double fbm (double x, double y) {
40
41    double value  = 0;
42    double amp    = .5;
43    double freq   = 0;
44
45    for (int i = 0; i < 5; i++) {
46
47        value += amp * noise(x, y);
48        x = 2.*x;
49        y = 2.*y;
50        amp = amp * .5;
51    }
52
53    return value;
54}
55
56// -----------------------------------------------------------------------------
57
58// Нормализация вектора
59vec3 normalize (vec3 c) {
60
61    double d = sqrt(c.x*c.x + c.y*c.y + c.z*c.z);
62
63    d   = d ?: 1;
64    c.x = c.x / d;
65    c.y = c.y / d;
66    c.z = c.z / d;
67
68    return c;
69};
70
71// Вычисление пересечений луча D со сферой в точке O и радиусом R
72double sphere (vec3 d, vec3 o, double r) {
73
74    double sp = -1;
75
76    double a = d.x * d.x + d.y * d.y + d.z * d.z;
77    double b = -2 * (d.x * o.x + d.y * o.y + d.z * o.z);
78    double c = o.x * o.x + o.y * o.y + o.z * o.z - r;
79    double det = b*b - 4*a*c;
80
81    if (det >= 0) {
82
83        det = sqrt(det);
84        double x1 = (-b - det) / (2 * a);
85        double x2 = (-b + det) / (2 * a);
86
87        if (x1 < 0 && x2 < 0) sp = -1;
88        if (x1 < 0 && x2 > 0) sp = x2;
89        if (x1 > 0 && x2 < 0) sp = x1;
90        if (x1 > 0 && x2 > 0 && x1 < x2) sp = x1;
91        if (x1 > 0 && x2 > 0 && x1 >= x2) sp = x2;
92    }
93
94    return sp;
95}
96
97// Кастомная палитра
98void custompal() {
99
100    int i;
101
102    // Earth [0..63]
103    FOR(i,1,63) palette(   i, rgb(   i, 128 + i * 2, 4*i));
104
105    // Water [64..71]
106    FOR(i,0,7)  palette(64+i, rgb(i * 32, 32 + 24 * i, 255));
107
108    // Starfeld [72..135]
109    FOR(i,0,63) palette(72+i, rgb(4*i, 4*i, 4*i));
110}
111
112// -----------------------------------------------------------------------------
113
114program(13) custompal(); fps {
115
116    double u, v, m, dt = 8;
117    vec3 c, o = {0, 0, 1.5}, sun = normalize({1, 1, -.5});
118
119    srand(1);
120    FOR(i,0,320) pset(rand()%320, rand()%200, rand()%64+72);
121
122    FOR (y,-100,99) FOR (x,-160,159) {
123
124        c = {(float)x / 100, (float)y / 100, 1};
125
126        if ((m = sphere(c, o, 1)) > 0) {
127
128            // Точка пересечения
129            c.x = c.x * m - o.x;
130            c.y = c.y * m - o.y;
131            c.z = c.z * m - o.z;
132            c   = normalize(c);
133
134            // Вычислить UV
135            u = atan2(c.z, c.x);
136            v = atan2(c.z, c.y);
137            u = u + rot;
138
139            // Получение дробной части
140            u = u - floor(u);
141            v = v - floor(v);
142            m = fbm(dt * u, dt * v) * 63;
143
144            // Свет Солнца
145            int dl = 128*(c.x * sun.x + c.y * sun.y + c.z * sun.z);
146
147            // Дизеринг
148            dl = dl + lookupdith[x&7][y&7] - 64;
149
150            // Вода или поверхность?
151            m = (m <= 32) ? 64 : (2*m - 63);
152
153            // Использовать дизеринг для затененения
154            pset(160 + x, 100 - y, dl <= 0 ? 0 : m);
155        }
156    }
157
158    rot += 0.005;
159
160} end
Качнуть файл