Статья по теме:
Демо JavaScript:
<canvas id="canvas" width="500" height="500"></canvas> <!-- VERTEX SHADER --> <script type="shader" id="Vshader"> attribute vec2 vertexPosition; //атрибут вершин void main(){ gl_Position = vec4(vertexPosition, 0.0, 1.0);//строим вершинный шейдер } </script> <!-- FRAGMENT SHADER --> <script type="shader" id="Fshader"> precision mediump float; //устанавливаем точность для чисел с плавающей точкой uniform float u_time; //униформ переменная времени //функция генерации случайных чисел float random (in vec2 st) { //dot - скалярное произведение return fract(sin(dot(st.xy,vec2(12.9898,78.233)))* 43758.5453123); } //функция шума float noise (in vec2 st) { //in - квалификатор(переданная переменная предназначена //только для чтения) vec2 i = floor(st); //целая часть st vec2 f = fract(st); //дробная часть st float a = random(i + vec2(0.0, 0.0)); //нижний левый угол float b = random(i + vec2(1.0, 0.0)); //нижний правый угол float c = random(i + vec2(0.0, 1.0)); //верхний левый угол float d = random(i + vec2(1.0, 1.0)); //верхний правый угол //кубическая кривая vec2 u=smoothstep(0.0,1.0, f); return mix(a, b, u.x) + //интерполируем между четырмя случайными значениями (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } void main(){ vec2 st = gl_FragCoord.xy/vec2(500, 500);//нормализуем область vec2 pos = vec2(st*4.0); //масштабируем float n = noise(pos); //накладываем шум //капельки n+=smoothstep(.15,.2,noise(st*20.)); gl_FragColor = vec4(vec3(sin(n*u_time/5.),0.0,0.0), 1.0); //передаем цвет } </script> <script> function startWebGL() { //получаем исходники шейдеров var vertexShaderText = document.getElementById('Vshader').text; var fragmentShaderText = document.getElementById('Fshader').text; //получаем webgl context var canvas = document.getElementById('canvas'); var gl = canvas.getContext('webgl'); var vertexShader = gl.createShader(gl.VERTEX_SHADER); //создаем шейдеры var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(vertexShader, vertexShaderText); //передаем исходники gl.shaderSource(fragmentShader, fragmentShaderText); //компилируем. В случае неудачной компиляции выводим ошибку gl.compileShader(vertexShader); if(!gl.getShaderParameter(vertexShader,gl.COMPILE_STATUS)){ alert('ERROR COMPILING SHADER'); console.error('SHADER ERR: ',gl.getShaderInfoLog(vertexShader)); } gl.compileShader(fragmentShader); if(!gl.getShaderParameter(fragmentShader,gl.COMPILE_STATUS)){ alert('ERROR COMPILING SHADER'); console.error('SHADER ERR: ',gl.getShaderInfoLog(fragmentShader)); } var program = gl.createProgram(); //создаем программу gl.attachShader(program, vertexShader); //подключаем скомпилированные шейдеры gl.attachShader(program, fragmentShader); gl.linkProgram(program); //связываем var vertexBuffer = gl.createBuffer(); //создаем буфер вершин gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); //связываем var vertexArray = [ //массив вершин двух треугольников(из которых получена наша область работы) 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexArray), gl.STATIC_DRAW);//передаем данные нашего массива вершин в буфер вершин webgl //создаем атрибут, с помощью которого шейдер будет получать данные из буфера var positionAttribLocation = gl.getAttribLocation(program, 'vertexPosition'); gl.vertexAttribPointer( positionAttribLocation, // 2, // gl.FLOAT, // gl.FALSE, // 0, // 0 // ); gl.enableVertexAttribArray(positionAttribLocation); var timeLocation = gl.getUniformLocation(program, "u_time");//создаем униформ переменную времени function renderLoop(timeStamp) {//рекурсивная функция отрисовки gl.uniform1f(timeLocation, timeStamp/1000.0); //передаем время в униформ переменную gl.drawArrays(gl.TRIANGLES, 0, 6); //отрисовываем window.requestAnimationFrame(renderLoop); //вызываем функцию для зацикливания } gl.useProgram(program); window.requestAnimationFrame(renderLoop); } startWebGL(); </script>