Вдохновлён примерами из книги Рэнди Дж. Роста "Трехмерная графика и язык программирования шейдеров". На движке RBMK64 построена плоскость, на плоскость натянута текстура. Всё просто: Спойлер: Вершинный шейдер Код (C): #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; // unused by the fractal, kept for VAO compatibility layout (location = 2) in vec3 aColor; // tint for the fractal uniform mat4 uModel; uniform mat4 uView; uniform mat4 uProjection; out vec2 vFractalUV; out vec3 vColor; void main() { vFractalUV = aPos.xy; vColor = aColor; gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0); } Спойлер: Фрагментный шейдер Код (C): #version 330 core in vec2 vFractalUV; in vec3 vColor; uniform vec2 uCenter; uniform float uZoom; uniform float uAspect; out vec4 FragColor; // IQ cosine palette — bright and continuous vec3 palette(float t) { return 0.5 + 0.5 * cos(6.28318 * (vec3(1.0, 1.0, 1.0) * t + vec3(0.0, 0.33, 0.67))); } void main() { vec2 p = vec2(vFractalUV.x * uAspect, vFractalUV.y) * uZoom + uCenter; float logScale = log2(max(1.0 / max(uZoom, 1e-6), 1.0)); float posTerm = 0.5 * length(p - vec2(-0.75, 0.0)); int maxIter = int(64.0 + 32.0 * clamp(logScale + posTerm, 0.0, 12.0)); maxIter = min(maxIter, 512); vec2 z = vec2(0.0); int i = 0; for (; i < maxIter; ++i) { float zx2 = z.x * z.x; float zy2 = z.y * z.y; if (zx2 + zy2 > 4.0) break; z = vec2(zx2 - zy2 + p.x, 2.0 * z.x * z.y + p.y); } vec3 color; if (i == maxIter) { // Interior: very dark purple instead of pure black color = vec3(0.05, 0.0, 0.10); } else { float t = float(i) / float(maxIter); t = pow(t, 0.4); // log-ish spread: more range spent on small t color = palette(t); } FragColor = vec4(color * vColor, 1.0); } Все преимущества 3D-движка сохраняются (движение, вращение) Единственное, чего пока не сделал: фрактал - это самоподобие, для фрактала очень важен зум. нужен динамический пересчёт перспективы (near-far), ну и итеративный пересчёт геометрии, конечно. ...и для фракталов размер float - уже маловат. Но переписать движок ради фрактала я пока не готов.
Нафига? Мандельброт как раз тем и хорош, что у него каждая точка считается независимо. Он прям как будто предназначен, чтоб считать шейдером параллельно.
Да, LLM добавили итеративность. Я у себя тоже обязательно сделаю. Знаю, знаю. Но мне уже очень хотелось увидеть мой первый фрактал, построенный шейдером, поэтому сделал, как быстрее. Что дальше: 1) я убираю из движка всё, что касается 3D-матриц; 2) меняю размер на double; 3) вставляю 2D-геометрию (full-screen quad или surface в терминологии Vulkan и Direct3D); 4) получаю всё равно текстуру, натянутую на полигон (ну так это работает); 5) вместо движения камеры вперёд-назад делаю зум с расчётом нужной глубины итераций. Шаг зума - не линейный, как при движении камеры, а логарифмический, но это не точно.
Предлагаю сброситься, выкупить этот сайт и оживить его. Всё равно хозяева его забросили, может отдадут задешево, а то и вообще, бесплатно подарят. https://www.demoscene.ru/forum/
Действительно мертвый, в "музыке" ни одной моей биперной демки за этот год. Правда непонятно, какое это имеет отношение к названию этой темы? Насчет хозяев - с этого года делегирование доменов в зоне ру возможно только с подтверждением через Госуслуги.
Ну как же, а фракталы, а шейдеры. Мне раньше иногда казалось, что Битл кроме терминов: ассемблер и шейдеры - больше никаких терминов и не знает. Ну и термин фракталы, он иногда в своих комментариях использовал.