JSFiddle - React, Tailwind, and code Playground

by Sergey khorev

HTML

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Чёрная дыра с вихрем</title>
    <style>
        body { margin: 0; height: 200vh; }
        canvas { width: 100%; height: 100vh; position: fixed; top: 0; left: 0; }
    </style>
</head>
<body>
    <canvas id="glCanvas"></canvas>
    <script src="shader.js"></script>
</body>
</html>

JavaScript

const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl');

// Устанавливаем размер канваса
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// Вершинный шейдер (без изменений)
const vertexShaderSource = `
    attribute vec2 a_position;
    void main() {
        gl_Position = vec4(a_position, 0.0, 1.0);
    }
`;

// Фрагментный шейдер с вращением внутри искажения
const fragmentShaderSource = `
    precision mediump float;
    uniform vec2 u_resolution;
    uniform float u_scroll;
    uniform float u_time;

    void main() {
        vec2 p = (gl_FragCoord.xy * 2.0 - u_resolution) / u_resolution.y;
        float radius = 0.5 + u_scroll * 0.2; // Эффект отдаления
        
        // Вращение искажения
        float angle = u_time * 2.0; // Скорость вращения
        float s = sin(angle);
        float c = cos(angle);
        vec2 rotatedP = vec2(
            p.x * c - p.y * s,
            p.x * s + p.y * c
        );
        float distortion = 0.01 / (rotatedP.x - rotatedP.y); // Вращаем только p.x - p.y
        
        // Оригинальная формула с вращением внутри
        float o = 0.0;
        o += 0.1 / abs(length(p) - radius + distortion);
        
        // Добавляем затемнение к центру для эффекта чёрной дыры
        float darkness = smoothstep(0.0, radius, length(p));
        gl_FragColor = vec4(vec3(o * darkness), 1.0);
    }
`;

// Функция создания шейдера (без изменений)
function createShader(gl, type, source) {
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        console.error(gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);
        return null;
    }
    return shader;
}

// Инициализация программы
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
const...