WebGL 2D: простой как Web

без GL

WebGL 2D:
простой как Web
без GL

Коротаев Александр

@mamu_eval
github.com/lekzd

  • Фронтенд разработчик в Tinkoff.ru
  • Spb-frontend
  • подкаст Drinkcast

web-standards-ru/cfp-list

Развитие за 9 лет

WebGL

  • версия 1
  • версия 2
  • WebGPU ?

Web Assembly

  • asm.js
  • wasm модули
  • сборщик мусора
  • компиляторы
  • webpack модули

API не из Web

            gl.activeTexture(gl.TEXTURE0)
            gl.bindTexture(gl.TEXTURE_2D, texture)
            gl.texImage2D(this.gl.TEXTURE_2D, ..., image)
            gl.uniform1i(gl.getUniformLocation('u_image'), 0);
        
https://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences

WebGL-2d

gameclosure/webgl-2d

Canvas API -> WebGL

Никто не должен понять WebGL

Пререндеринг
рисуем заранее

Как это выглядит

Демо
https://webglfundamentals.org/webgl/lessons/webgl-image-processing.html

Алгоритм

Самое важное

            const texture = gl.createTexture()
            const canvas = document.createElement('canvas')
             
            gl.activeTexture(gl.TEXTURE0)
            gl.bindTexture(gl.TEXTURE_2D, texture)
            gl.texImage2D(gl.TEXTURE_2D, ..., canvas)
        

Создание текстуры

            const texture = gl.createTexture()
            const canvas = document.createElement('canvas')
             
            gl.activeTexture(gl.TEXTURE0)
            gl.bindTexture(gl.TEXTURE_2D, texture)
            gl.texImage2D(gl.TEXTURE_2D, ..., canvas)
        

Canvas как текстура

            const texture = gl.createTexture()
            const canvas = document.createElement('canvas')
             
            gl.activeTexture(gl.TEXTURE0)
            gl.bindTexture(gl.TEXTURE_2D, texture)
            gl.texImage2D(gl.TEXTURE_2D, ..., canvas)
        

Первый шейдер

            uniform sampler2D u_background;
            varying vec2 v_texCoord;
             
            void main() {
              gl_FragColor = texture2D(u_background, v_texCoord);
            }
        

Больше картинок!

+ =

Уже знакомый код

            const texture = gl.createTexture()
            const canvas = document.createElement('canvas')
             
            gl.activeTexture(gl.TEXTURE0)
            gl.bindTexture(gl.TEXTURE_2D, texture)
            gl.texImage2D(gl.TEXTURE_2D, ..., canvas)
        
https://webglfundamentals.org/webgl/lessons/ru/webgl-2-textures.html

                // получаем ссылки на сэмплеры
                var u_image0 = gl.getUniformLocation(program, "u_image0")
                var u_image1 = gl.getUniformLocation(program, "u_image1")
                 
                // задаём, какой текстурный блок использовать при рендеринге
                gl.uniform1i(u_image0, 0)
                gl.uniform1i(u_image1, 1)
                 
                // привязываем текстуру к текстурному блоку
                gl.activeTexture(gl.TEXTURE0)
                gl.bindTexture(gl.TEXTURE_2D, textures[0])
                gl.activeTexture(gl.TEXTURE1)
                gl.bindTexture(gl.TEXTURE_2D, textures[1])
            

Создаем и храним ссылки на текстуры

            const textures = []
            function addTexture(canvas, name) {
              const texture = gl.createTexture()
              const location = gl.getUniformLocation(program, name)
              textures.push({texture, canvas, location})
            }
        

Обновляем текстуры

            textures.forEach(({texture, canvas, location}, i) => {
              gl.activeTexture(gl[`TEXTURE${i}`])
              gl.bindTexture(gl.TEXTURE_2D, texture)
              gl.texImage2D(this.gl.TEXTURE_2D, ..., canvas)
              gl.uniform1i(location, i);
            })
        

Активация текстурного блока

            textures.forEach(({texture, canvas, location}, i) => {
              gl.activeTexture(gl[`TEXTURE${i}`])
              gl.bindTexture(gl.TEXTURE_2D, texture)
              gl.texImage2D(this.gl.TEXTURE_2D, ..., canvas)
              gl.uniform1i(location, i);
            })
        

Передача Canvas

            textures.forEach(({texture, canvas, location}, i) => {
              gl.activeTexture(gl[`TEXTURE${i}`])
              gl.bindTexture(gl.TEXTURE_2D, texture)
              gl.texImage2D(this.gl.TEXTURE_2D, ..., canvas)
              gl.uniform1i(location, i);
            })
        

2 текстуры в шейдере

            uniform sampler2D u_background;
            uniform sampler2D u_foreground;
            varying vec2 v_texCoord;
            void main() {
              gl_FragColor = texture2D(u_background, v_texCoord)
                  + texture2D(u_foreground, v_texCoord);
            }
        
https://jsfiddle.net/dt6wfn10/

Шейдеры
Эффекты поверх canvas

Evil Glitch

Ссылка на игру

Про тег <script>

Но Webpack лучше

            rules: [
            ...
              {
                  test: /\.frag?$/,
                  use: 'raw-loader',
              }]
        

😍😍😍

            import * as fragmentShader from './shader.frag'
            import * as vertexShader from './shader.vert'
        

WebGL utils

https://webglfundamentals.org/docs/module-webgl-utils.html
            const shaders = [vertexShader, fragmentShader]
            const program = createProgramFromSources(gl, shaders)
        

Ссылки по шейдерам

Демо

React + WebGL
используем JSX

Что можно взять

Почему Pixi.js?





https://codesandbox.io/s/q7oj1p0jo6

Демо

React + Pixi.js?

            <Container>
                {state.enemies.map(enemy => (<Enemy {...enemy}/>))}
                {state.explosions.map(enemy => (<Explosion {...enemy}/>))}
                <Actor {...state.hero}/>
                <Header x={0} y={0} text={state.kills}/>
            <Container>
        

React + Pixi.js?

Выводы

Ускоряет отрисовку?

Эффекты?

Ссылки

???