§ Краткое описание программы
Я сделал вращение Земли, используя программу на Quick Basic 4.5.Программа довольно большая и состоит из следующих процедур:
- 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Качнуть файл